Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM
Diff: MAX3100.cpp
- Revision:
- 0:055897ab699b
- Child:
- 1:46c8c60e744a
--- /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