MAX3100, an external serial device to add additional serial ports via SPI
Dependents: FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM
Revision 0:055897ab699b, committed 2011-01-16
- Comitter:
- AjK
- Date:
- Sun Jan 16 18:27:44 2011 +0000
- Child:
- 1:46c8c60e744a
- Commit message:
- 1.0 Initial release
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX3100.cpp Sun Jan 16 18:27:44 2011 +0000 @@ -0,0 +1,324 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "MAX3100.h" + +namespace AjK { + +void +MAX3100::init(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, SPI *spi) +{ + config = 0; + flushTxBuffer(); + flushRxBuffer(); + + _parity = 0; + + _cs_function = NULL; + _cs_obj = NULL; + _cs_method = NULL; + + if (cs != NC) { + _cs = new DigitalOut(cs); + _cs->write( 1 ); + } + else _cs = (DigitalOut *)NULL; + + if (spi) { + _spi = spi; + } + else { + _spi = new SPI(mosi, miso, sclk); + _spi->format(16, 0); + _spi->frequency(MAX3100_SPI_FREQ); + } + + if (irq != NC) { + _irq = new InterruptIn(irq); + _irq->mode(PullUp); + topic_1498(irq); + _irq->fall(this, &MAX3100::isr); + } + else { _irq = (InterruptIn *)NULL; } + + baud(10); // 9600baud by default. +} + +void +MAX3100::cs_value(int i) +{ + if (_cs != (DigitalOut *)NULL) _cs->write(i & 1); + else { + if (_cs_function != NULL) (*_cs_function)(_device, i & 1); + else { + if (_cs_obj && _cs_method) (_cs_obj->*_cs_method)(_device, i & 1); + } + } +} + +uint16_t +MAX3100::spiwrite(uint16_t val) +{ + cs_value(0); + uint16_t r = _spi->write(val); + cs_value(1); + return r; +} + +uint16_t +MAX3100::config_write(uint16_t val) +{ + return spiwrite(MAX3100_CONF_WR | val); +} + +uint16_t +MAX3100::config_read(void) +{ + return spiwrite(MAX3100_CONF_RD); +} + + +void +MAX3100::baud(int baudrate) +{ + __disable_irq(); + config &= ~(0xf); + config |= (baudrate & 0xf); + config_write(config); + __enable_irq(); +} + +void +MAX3100::enableRxIrq(void) +{ + __disable_irq(); + config &= ~MAX3100_RM(1); + config |= MAX3100_RM(1); + config_write(config); + __enable_irq(); +} + +void +MAX3100::disableRxIrq(void) +{ + __disable_irq(); + config &= ~MAX3100_RM(1); + config_write(config); + __enable_irq(); +} + +void +MAX3100::enableTxIrq(void) +{ + __disable_irq(); + config &= ~MAX3100_TM(1); + config |= MAX3100_TM(1); + config_write(config); + __enable_irq(); +} + +void +MAX3100::disableTxIrq(void) +{ + __disable_irq(); + config &= ~MAX3100_TM(1); + config_write(config); + __enable_irq(); +} + +int +MAX3100::putc(int c) +{ + uint16_t data, conf; + + // If no space return -1 as an error code. + if (tx_buffer_full) return -1; + + if (_parity) { + int pBit = parityCal(c & 0xFF); + if (_parity == Even && pBit == 0) { c |= (1 << 8); } + if (_parity == Odd && pBit == 1) { c |= (1 << 8); } + } + else { c &= 0xFF; } + + // Function is non-interruptable by the MAX3100 class + // to avoid SPI bus contention between writing a byte + // in user context (here) and IRQ context. + __disable_irq(); + + conf = config_read(); + + if (tx_buffer_in == tx_buffer_out && conf & MAX3100_CONF_T) { + data = spiwrite(MAX3100_DATA_WR | (c & 0x1FF)); + // In case we get a byte while writing store it away. + if (!rx_buffer_full && data & MAX3100_CONF_R) { + rx_buffer[rx_buffer_in++] = (uint16_t)(data & 0xFF); + if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0; + if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true; + } + } + else { + tx_buffer[tx_buffer_in++] = (char)(c & 0xFF); + if (tx_buffer_in >= MAX3100_TX_BUFFER_SIZE) { + tx_buffer_in = 0; + } + if (tx_buffer_in == tx_buffer_out) tx_buffer_full = true; + } + + __enable_irq(); + + return 1; +} + +void +MAX3100::puts(char *s) { + char *q = s; + while(*(q)) { + if (putc((int)(*(q))) == -1) return; + q++; + } +} + +int +MAX3100::getc(void) { + if (!rx_buffer_full && rx_buffer_in == rx_buffer_out) return -1; + int c = (int)((unsigned char)rx_buffer[rx_buffer_out++]); + if (rx_buffer_out >= MAX3100_RX_BUFFER_SIZE) rx_buffer_out = 0; + rx_buffer_full = false; + return c; +} + +char * +MAX3100::gets(char *s, int size) +{ + int i; + char *q = s; + while(size) { + do { i = getc(); } while (i == -1); // Blocks! + *(q) = (char)i; size--; + } + return s; +} + +int +MAX3100::peek(void) { + if (!rx_buffer_full && rx_buffer_in == rx_buffer_out) return -1; + return (int)((unsigned char)rx_buffer[rx_buffer_out]); +} + +void +MAX3100::isr(void) { + uint16_t data = spiwrite(MAX3100_DATA_RD); + bool tx_ready = data & MAX3100_CONF_T ? true : false; + + // The MAX3100 does have an RX fifo. So attempt to empty it into the RX buffer. + do { + if (!rx_buffer_full && data & MAX3100_CONF_R) { + rx_buffer[rx_buffer_in++] = (char)(data & 0xFF); + if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0; + if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true; + } + } + while ((data = spiwrite(MAX3100_DATA_RD)) & MAX3100_CONF_R); + + // The MAX3100 doesn't have a hardware TX fifo, so just test to see if it's TX buffer + // is empty. If it is and we have bytes in the TX buffer then send one now. + if (tx_ready && (tx_buffer_full || tx_buffer_in != tx_buffer_out)) { + data = spiwrite(MAX3100_DATA_WR | (tx_buffer[tx_buffer_out++] & 0x1FF)); + if (tx_buffer_out >= MAX3100_TX_BUFFER_SIZE) tx_buffer_out = 0; + tx_buffer_full = false; + } + + // In case we get a byte while sending then store it. + if (!rx_buffer_full && data & MAX3100_CONF_R) { + rx_buffer[rx_buffer_in++] = (char)(data & 0xFF); + if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0; + if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true; + } +} + +void +MAX3100::setStopBits(int i) +{ + switch(i) { + case 1: + __disable_irq(); + config &= ~(1 << 6); + config_write(config); + __enable_irq(); + break; + case 2: + __disable_irq(); + config |= (1 << 6); + config_write(config); + __enable_irq(); + break; + } +} + +int +MAX3100::parityCal(uint8_t c) +{ + int count = 0; + for (int mask = 1, i = 0; i < 8; i++, mask = mask << 1) { + if (c & mask) count++; + } + return count & 1; +} + +void +MAX3100::topic_1498(PinName p) { + // http://mbed.org/forum/bugs-suggestions/topic/1498 + uint32_t clr0 = 0, clr2 = 0; + + switch( p ) { + case p5: clr0 = (1UL << 9); break; + case p6: clr0 = (1UL << 8); break; + case p7: clr0 = (1UL << 7); break; + case p8: clr0 = (1UL << 6); break; + case p9: clr0 = (1UL << 0); break; + case p10: clr0 = (1UL << 1); break; + case p11: clr0 = (1UL << 18); break; + case p12: clr0 = (1UL << 17); break; + case p13: clr0 = (1UL << 15); break; + case p14: clr0 = (1UL << 16); break; + case p15: clr0 = (1UL << 23); break; + case p16: clr0 = (1UL << 24); break; + case p17: clr0 = (1UL << 25); break; + case p18: clr0 = (1UL << 26); break; + case p21: clr2 = (1UL << 5); break; + case p22: clr2 = (1UL << 4); break; + case p23: clr2 = (1UL << 3); break; + case p24: clr2 = (1UL << 2); break; + case p25: clr2 = (1UL << 1); break; + case p26: clr2 = (1UL << 0); break; + case p27: clr0 = (1UL << 11); break; + case p28: clr0 = (1UL << 10); break; + case p29: clr0 = (1UL << 5); break; + case p30: clr0 = (1UL << 4); break; + } + + if (clr0) LPC_GPIOINT->IO0IntClr = clr0; + if (clr2) LPC_GPIOINT->IO2IntClr = clr2; +} + +}; // namespace AjK ends
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX3100.h Sun Jan 16 18:27:44 2011 +0000 @@ -0,0 +1,314 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + + +#ifndef AJK_MAX31000_H +#define AJK_MAX31000_H + +#ifndef MBED_H +#include "mbed.h" +#endif + +#ifndef MAX3100_TX_BUFFER_SIZE +#define MAX3100_TX_BUFFER_SIZE 32 +#endif + +#ifndef MAX3100_RX_BUFFER_SIZE +#define MAX3100_RX_BUFFER_SIZE 32 +#endif + +#ifndef MAX3100_SPI_FREQ +#define MAX3100_SPI_FREQ 5000000 +#endif + +#define MAX3100_CONF_WR (3U << 14) +#define MAX3100_CONF_RD (1U << 14) +#define MAX3100_CONF_T (1U << 14) +#define MAX3100_CONF_R (1U << 15) +#define MAX3100_FEN(x) (x << 13) +#define MAX3100_SHDNi(x) (x << 12) +#define MAX3100_TM(x) (x << 11) +#define MAX3100_RM(x) (x << 10) +#define MAX3100_PM(x) (x << 9) +#define MAX3100_RAM(x) (x << 8) +#define MAX3100_IR(x) (x << 7) +#define MAX3100_ST(x) (x << 6) +#define MAX3100_PE(x) (x << 5) +#define MAX3100_L(x) (x << 4) +#define MAX3100_BAUD(x) (x << 0) + +#define MAX3100_DATA_WR (2U << 14) +#define MAX3100_DATA_RD (0) +#define MAX3100_TE(x) (x << 10) +#define MAX3100_RAFE(x) (x << 10) +#define MAX3100_RTS(x) (x << 9) +#define MAX3100_CTS(x) (x << 9) +#define MAX3100_PT(x) (x << 8) +#define MAX3100_PR(x) (x << 8) + +namespace AjK { + +class MAX3100Dummy; + +/** MAX3100 An external serial IO device. + * + * The MAX3100 librray is designed to allow the easy attachment of additional + * serial ports to the Mbed. We all know that the Mbed already has 3 potential + * serial ports. But maybe you need more ports or maybe you need to use the Mbed + * pins for an alternative function. The MAX3100 may well be able to help in + * situations like these. + * + * Each MAX3100 device you create in is TX/RX buffered with 32 characters in a circular + * buffer system. + * + * The MAX3100 uses at least one Mbed SPI port and additional DigitalOut and InterruptIn + * pins to work. However, you can attach multiple MAX3100 devices to a single SPI "bus". + * + * For more information on attaching multiple devices see all the examples listed below. + * + * @see example1.h + * @see example2.h + * @see example3.h + * @see http://pdfserv.maxim-ic.com/en/ds/MAX3100.pdf + */ +class MAX3100 : public Stream { + +protected: + + SPI *_spi; + DigitalOut *_cs; + InterruptIn *_irq; + + uint16_t tx_buffer[MAX3100_TX_BUFFER_SIZE]; + int tx_buffer_in; + int tx_buffer_out; + bool tx_buffer_full; + + uint16_t rx_buffer[MAX3100_RX_BUFFER_SIZE]; + int rx_buffer_in; + int rx_buffer_out; + bool rx_buffer_full; + + uint16_t config; + int _device; + int _parity; + + virtual int _putc(int c) { return putc(c); } + virtual int _getc() { return getc(); } + + /** init + * + * Initialise the device. + * @param PinName SPI mosi + * @param PinName SPI miso + * @param PinName SPI sclk + * @param PinName DigitalOut cs + * @param PinName InterruptIn irq + * @param SPI * A pointer to a shared SPI bus + */ + void init(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, SPI *spi = (SPI *)NULL); + + uint16_t spiwrite(uint16_t val); + uint16_t config_write(uint16_t val); + uint16_t config_read(void); + + // C style callback function pointer for external CS control. + void (*_cs_function)(int, int); + + // C++ style callback method pointer for external CS control + MAX3100Dummy *_cs_obj; + void (MAX3100Dummy::*_cs_method)(int, int); + + // Internal CS control. + void cs_value(int); + + // calculate byte parity. + int parityCal(uint8_t c); + + // http://mbed.org/forum/bugs-suggestions/topic/1498 + void topic_1498(PinName p); + +public: + + /** Constructor + */ + MAX3100() { error( "No pins supplied to constructor" ); } + + /** Constructor + */ + MAX3100(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, int device = 0) { + _device = device; + init( mosi, miso, sclk, cs, irq); + } + + /** Constructor + */ + MAX3100(SPI *spi, PinName cs, PinName irq, int device = 0) { + _device = device; + init( NC, NC, NC, cs, irq, spi); + } + + /** Destructor + */ + virtual ~MAX3100() { + if ( _spi ) delete( _spi ); + if ( _irq ) delete( _irq ); + if ( _cs ) delete( _cs ); + } + + enum Parity { + None = 0 + , Odd + , Even + , Forced1 + , Forced0 + }; + + /** setParity + * + * Set the parity of the system. Default is None. + * + * @param Parity None, Odd, Even + */ + void setParity(int p) { _parity = p; } + + /** setStopBits + * + * Set the number of stop bits. Default is One. + * + * @param int 1 or 2 + */ + void setStopBits(int i); + + /** System interrupt service routine. + */ + void isr(void); + + /** baud + * Set the system baud. Default is "10" (9600). Note, + * this is not like Mbed's Serial where you pass the + * baud rate you want. The MAX3100 has 16 possible + * preset prescalers you can choose from. See the datasheet + * for more info. + * + * @see http://pdfserv.maxim-ic.com/en/ds/MAX3100.pdf + * @param int A number from 0 to 15 indicating which prescaler to use. + */ + void baud(int baudrate); + + /** enableRxIrq + */ + void enableRxIrq(void); + + /** disableRxIrq + */ + void disableRxIrq(void); + + /** enableTxIrq + */ + void enableTxIrq(void); + + /** disableTxIrq + */ + void disableTxIrq(void); + + /** putc + * @param int c The byte to write. + */ + int putc(int c); + + /** puts + * @param char * The string to print. + */ + void puts(char *s); + + /** getc + * @return int c The byte read or -1 if no bytes to read. + */ + int getc(void); + + /** gets + * Get a string. Note, this method blocks until size bytes are read. + * @param char *s where to place the incoming bytes. + * @param int size How many bytes to read. + * @return char * The value of *s passed in. + */ + char *gets(char *s, int size); + + /** peek + * like getc() but does NOT remove the byte from the buffer. + * @see getc*( + */ + int peek(void); + + /** readable + * Are any byte(s) available in the RX buffer? + * @return 0 if none, 1 otherwise. + */ + int readable(void) { return (rx_buffer_in != rx_buffer_out || rx_buffer_full) ? 1 : 0; } + + /** writable + * Can we write a byte to teh serial stream? + * @return non-zero if we can, zero otherwise. + */ + int writable(void) { return tx_buffer_full ? 0 : 1; } + + /** setDevice + * Give this device an "address". + * @param int i An address to use in callbacks. + */ + void setDevice(int i) { _device = i; } + + /** flushTxBuffer + * + * Flush the TX buffer. + */ + void flushTxBuffer(void) { tx_buffer_in = tx_buffer_out = 0; tx_buffer_full = false; } + + /** flushRxBuffer + * + * Flush the RX buffer. + */ + void flushRxBuffer(void) { rx_buffer_in = rx_buffer_out = 0; rx_buffer_full = false; } + + /** attach_cs + * Attach a C style callback function pointer. Used if an external function + * is controlling the chip CS line. + * @param function A C function pointer + */ + void attach_cs(void (*function)(int, int) = 0) { _cs_function = function; } + + /** attach_cs + * Attach a C++ object/method pointer. Used if an external function + * @param object An object that conatins the callback method. + * @param method The method within the object to call. + */ + template<class T> + void attach_cs(T* item, void (T::*method)(int, int)) { _cs_obj = (MAX3100Dummy *)item; _cs_method = (void (MAX3100Dummy::*)(int, int))method; } + +}; + +}; // namespace AjK ends. + +using namespace AjK; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example1.h Sun Jan 16 18:27:44 2011 +0000 @@ -0,0 +1,72 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifdef MAX3100_EXAMPLE_COMPILE + +/* + * Connecting up the MAX3100 for this test program. Note, to form a "loopback" + * the MAX3100 TX pin (13) is connected to the RX pin (12). Don't forget thwe Xtal + * and power pins that are not shown here. Although I do PullUp mode on the IRQ pin + * I still needed a real external pull up resistor on the IRQ line. You may need one + * also. + * ____________ + * / \ + * Mbed MOSI p5 |-----------------> 1| Din TX | 13 ------\ + * MISO p6 |-----------------> 2| Dout | | + * SCLK p7 |-----------------> 3| Sclk RX | 12 ------/ + * p8 |-----------------> 4| CS | + * p9 |-----------------> 5| IRQ | MAX3100 + * +5v ------> 6| SHTD | Xtal and PWR not shown. + * \____________/ + */ + +#include "mbed.h" +#include "MAX3100.h" + +Serial pc(USBTX, USBRX); +MAX3100 max(p5, p6, p7, p8, p9); + +int main() { + + // Set the PC USB serial baud rate. + pc.baud(115200); + + max.enableRxIrq(); + max.enableTxIrq(); + + max.printf("\nHello World.\n"); + + // Any byte received on the "USB serial port" is sent to the MAX3100 device. + // Any byte received by the MAX3100 device is sent to the "USB serial port". + while (1) { + if (pc.readable()) { + int c = pc.getc(); + while (!max.writable()); + max.putc(c); + } + if (max.readable()) { + pc.putc( max.getc() ); + } + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example2.h Sun Jan 16 18:27:44 2011 +0000 @@ -0,0 +1,103 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifdef MAX3100_EXAMPLE_COMPILE + +/* + * Connecting up the MAX3100 for this test program. Note, to form a "loopback" + * the MAX3100 TX pin (13) is connected to the RX pin (12). Don't forget thwe Xtal + * and power pins that are not shown here. Although I do PullUp mode on the IRQ pin + * I still needed a real external pull up resistor on the IRQ lines. You may need to + * add two pullups to teh two interrupt lines at p9 and p11. + * ____________ + * / \ U1 + * Mbed MOSI p5 |-------*---------------> 1| Din TX | 13 ------\ + * MISO p6 |-----*-|---------------> 2| Dout | | + * SCLK p7 |---*-|-|---------------> 3| Sclk RX | 12 ------/ + * p8 |---|-|-|---------------> 4| CS | + * p9 |---|-|-|---------------> 5| IRQ | MAX3100 + * | | | +5v ---> 6| SHTD | Xtal and PWR not shown. + * | | | \____________/ + * | | | ____________ + * | | | / \ U2 + * | | \---------------> 1| Din TX | 13 ------\ + * | \-----------------> 2| Dout | | + * \-------------------> 3| Sclk RX | 12 ------/ + * p10 |-----------------------> 4| CS | + * p11 |-----------------------> 5| IRQ | MAX3100 + * +5v ---> 6| SHTD | Xtal and PWR not shown. + * \____________/ + * + * This example shows two MAX3100 sharing a single SPI bus. Each device, however, + * still has it's own CS and IRQ signals. + */ + +#include "mbed.h" +#include "MAX3100.h" + +Serial pc(USBTX, USBRX); +SPI spi(p5, p6, p7); +MAX3100 *max1; +MAX3100 *max2; + +int main() { + + // Set the PC USB serial baud rate. + pc.baud(115200); + + // Format the SPI interface. + spi.format(16, 0); + spi.frequency(MAX3100_SPI_FREQ); + + // Create the two MAX3100 objects which share the SPI bus. + max1 = new MAX3100(&spi, p8, p9); + max2 = new MAX3100(&spi, p10, p11); + + // Enable the interrupts. + max1->enableRxIrq(); + max1->enableTxIrq(); + max2->enableRxIrq(); + max2->enableTxIrq(); + + max1->printf("\nHello World.\n"); + max2->printf("\nHello World.\n"); + + // Any byte received on the "USB serial port" is sent to both MAX3100 devices. + // Any byte received by a MAX3100 device is sent to the "USB serial port". + while (1) { + if (pc.readable()) { + int c = pc.getc(); + while (!max1->writable()); + max1->putc(c); + while (!max2->writable()); + max2->putc(c); + } + if (max1->readable()) { + pc.putc( max1->getc() ); + } + if (max2->readable()) { + pc.putc( max2->getc() ); + } + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example3.h Sun Jan 16 18:27:44 2011 +0000 @@ -0,0 +1,153 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifdef MAX3100_EXAMPLE_COMPILE + +/* + * NOTE! Unlike examples 1 & 2 (which are tested in the real world) this example + * is theoretical only as I have not tested it. It should work but if you try it + * and it doesn't work let me know! It's shown here as a starting point to demo + * how to share multiple MAX3100 interrupts and address multiple chips using + * external hardware to manage each MAX3100's CS signal. + * + * Connecting up the MAX3100 for this test program. Note, to form a "loopback" + * the MAX3100 TX pin (13) is connected to the RX pin (12). Don't forget thwe Xtal + * and power pins that are not shown here. Although I do PullUp mode on the IRQ pin + * I still needed a real external pull up resistor on the IRQ line. You may need one + * also. + * + * __________ + * / \ + * Mbed p8 |---> 1| A0 Y0 | 15 -----> MAX0 + * p9 |---> 2| A1 Y1 | 14 -----> MAX1 + * p10 |---> 3| A2 Y2 | 13 -----> MAX2 + * p11 |---> 5| CS3 Y3 | 12 -----> MAX3 (and on to MAX7) + * \__________/ TTL138 (Tie CS1 to +ve and CS2 to 0v) + * + * ____________ + * / \ U1 + * Mbed MOSI p5 |-------*---------------> 1| Din TX | 13 ------\ + * MISO p6 |-----*-|---------------> 2| Dout | | + * SCLK p7 |---*-|-|---------------> 3| Sclk RX | 12 ------/ + * | | | MAX0 --> 4| CS | + * p12 |-*-|-|-|---------------> 5| IRQ | MAX3100 + * | | | | +5v ---> 6| SHTD | Xtal and PWR not shown. + * | | | | \____________/ + * | | | | ____________ + * | | | | / \ U2 + * | | | *---------------> 1| Din TX | 13 ------\ + * | | *-|---------------> 2| Dout | | + * | *-|-|---------------> 3| Sclk RX | 12 ------/ + * | | | | MAX1 --> 4| CS | + * *-|-|-|---------------> 5| IRQ | MAX3100 + * | | | | +5v ---> 6| SHTD | Xtal and PWR not shown. + * | | | | \____________/ + * | | | | ____________ + * | | | | / \ U3 + * | | | \---------------> 1| Din TX | 13 ------\ + * | | \-----------------> 2| Dout | | + * | \-------------------> 3| Sclk RX | 12 ------/ + * | MAX2 --> 4| CS | + * \---------------------> 5| IRQ | MAX3100 + * +5v ---> 6| SHTD | Xtal and PWR not shown. + * \____________/ + * + * Assume a further 5 MAX3100 devices connected to the bus in the same way + * to make a total of 8 MAX3100 serial devices connected to a single SPI bus. + * Additionally, they all share the same interrupt signal. This is possible + * because the MAX3100 IRQ output is open drain. So you will need an external 1k + * pull up resistor on the IRQ signal. + */ + +#include "mbed.h" +#include "MAX3100.h" + +Serial pc(USBTX, USBRX); +SPI spi(p5, p6, p7); +BusOut addr(p8, p9, p10); +DigitalOut cs(p11); +InterruptIn irq(p12); +MAX3100 *max[8]; + +// Class used to decode the address and handle shared interrupts. +class MAX3100_Addr { +public: + void cs_select(int device, int val) { + addr = device & 0x7; // Select device. + cs.write(val & 1); // Assert/deassert chip CS. + } + void isr(void) { + for (int i = 0; i < 8; i++) { + if (max[i] != (MAX3100 *)NULL) max[i]->isr(); + } + } +}; + +MAX3100_Addr address; + +int main() { + int index; + + cs = 1; + + // Set the PC USB serial baud rate. + pc.baud(115200); + + // Format the SPI interface. + spi.format(16, 0); + spi.frequency(MAX3100_SPI_FREQ); + + // Create the 8 devices and set them up. + for (int index = 0; index < 8; index++) { + max[index] = new MAX3100(&spi, NC, NC); + max[index]->setDevice(index); + max[index]->enableRxIrq(); + max[index]->enableTxIrq(); + max[index]->attach_cs(&address, &MAX3100_Addr::cs_select); + } + + // Connect the interrupt signal. + irq.fall(&address, &MAX3100_Addr::isr); + + // Any byte received on the "USB serial port" is sent to all MAX3100 devices. + // Any byte received by a MAX3100 device is sent to the "USB serial port". + while (1) { + if (pc.readable()) { + int c = pc.getc(); + for (index = 0; index < 8; index++) { + if (max[index] != (MAX3100 *)NULL) { + while (!max[index]->writable()); + max[index]->putc(c); + } + } + } + for (index = 0; index < 8; index++) { + if (max[index] != (MAX3100 *)NULL) { + if (max[index]->readable()) { + pc.putc(max[index]->getc()); + } + } + } + } +} + +#endif