Andy K / MAX3100

Dependents:   FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM

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