MAX3100, an external serial device to add additional serial ports via SPI
Dependents: FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM
MAX3100.cpp
00001 /* 00002 Copyright (c) 2011 Andy Kirkham 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy 00005 of this software and associated documentation files (the "Software"), to deal 00006 in the Software without restriction, including without limitation the rights 00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 copies of the Software, and to permit persons to whom the Software is 00009 furnished to do so, subject to the following conditions: 00010 00011 The above copyright notice and this permission notice shall be included in 00012 all copies or substantial portions of the Software. 00013 00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00020 THE SOFTWARE. 00021 */ 00022 00023 #include "MAX3100.h" 00024 00025 namespace AjK { 00026 00027 void 00028 MAX3100::init(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, SPI *spi) 00029 { 00030 config = 0; 00031 flushTxBuffer(); 00032 flushRxBuffer(); 00033 00034 _parity = 0; 00035 00036 _cs_function = NULL; 00037 _cs_obj = NULL; 00038 _cs_method = NULL; 00039 00040 _isr_user_function = NULL; 00041 _isr_user_obj = NULL; 00042 _isr_user_method = NULL; 00043 00044 if (cs != NC) { 00045 _cs = new DigitalOut(cs); 00046 _cs->write( 1 ); 00047 } 00048 else _cs = (DigitalOut *)NULL; 00049 00050 if (spi) { 00051 _spi = spi; 00052 } 00053 else { 00054 _spi = new SPI(mosi, miso, sclk); 00055 _spi->format(16, 0); 00056 _spi->frequency(MAX3100_SPI_FREQ); 00057 } 00058 00059 if (irq != NC) { 00060 irqMask(irq); 00061 _irq = new InterruptIn(irq); 00062 _irq->mode(PullUp); 00063 topic_1498(irq); 00064 _irq->fall(this, &MAX3100::isr); 00065 } 00066 else { _irq = (InterruptIn *)NULL; } 00067 00068 baud(10); // 9600baud by default. 00069 } 00070 00071 void 00072 MAX3100::cs_value(int i) 00073 { 00074 if (_cs != (DigitalOut *)NULL) _cs->write(i & 1); 00075 else { 00076 if (_cs_function != NULL) (*_cs_function)(_device, i & 1); 00077 else { 00078 if (_cs_obj && _cs_method) (_cs_obj->*_cs_method)(_device, i & 1); 00079 } 00080 } 00081 } 00082 00083 uint16_t 00084 MAX3100::spiwrite(uint16_t val) 00085 { 00086 cs_value(0); 00087 uint16_t r = _spi->write(val); 00088 cs_value(1); 00089 return r; 00090 } 00091 00092 uint16_t 00093 MAX3100::config_write(uint16_t val) 00094 { 00095 return spiwrite(MAX3100_CONF_WR | val); 00096 } 00097 00098 uint16_t 00099 MAX3100::config_read(void) 00100 { 00101 return spiwrite(MAX3100_CONF_RD); 00102 } 00103 00104 00105 void 00106 MAX3100::baud(int baudrate) 00107 { 00108 irqDisable(); 00109 config &= ~(0xf); 00110 config |= (baudrate & 0xf); 00111 config_write(config); 00112 irqEnable(); 00113 } 00114 00115 void 00116 MAX3100::enableRxIrq(void) 00117 { 00118 irqDisable(); 00119 config &= ~MAX3100_RM(1); 00120 config |= MAX3100_RM(1); 00121 config_write(config); 00122 irqEnable(); 00123 } 00124 00125 void 00126 MAX3100::disableRxIrq(void) 00127 { 00128 irqDisable(); 00129 config &= ~MAX3100_RM(1); 00130 config_write(config); 00131 irqEnable(); 00132 } 00133 00134 void 00135 MAX3100::enableTxIrq(void) 00136 { 00137 irqDisable(); 00138 config &= ~MAX3100_TM(1); 00139 config |= MAX3100_TM(1); 00140 config_write(config); 00141 irqEnable(); 00142 } 00143 00144 void 00145 MAX3100::disableTxIrq(void) 00146 { 00147 irqDisable(); 00148 config &= ~MAX3100_TM(1); 00149 config_write(config); 00150 irqEnable(); 00151 } 00152 00153 int 00154 MAX3100::putc(int c) 00155 { 00156 uint16_t data, conf; 00157 00158 // If no space return -1 as an error code. 00159 if (tx_buffer_full) return -1; 00160 00161 if (_parity) { 00162 int pBit = parityCal(c & 0xFF); 00163 if (_parity == Even && pBit == 0) { c |= (1 << 8); } 00164 if (_parity == Odd && pBit == 1) { c |= (1 << 8); } 00165 } 00166 else { c &= 0xFF; } 00167 00168 // Function is non-interruptable by the MAX3100 class 00169 // to avoid SPI bus contention between writing a byte 00170 // in user context (here) and IRQ context. 00171 irqDisable(); 00172 00173 conf = config_read(); 00174 00175 if (tx_buffer_in == tx_buffer_out && conf & MAX3100_CONF_T) { 00176 data = spiwrite(MAX3100_DATA_WR | (c & 0x1FF)); 00177 // In case we get a byte while writing store it away. 00178 if (!rx_buffer_full && data & MAX3100_CONF_R) { 00179 rx_buffer[rx_buffer_in++] = (uint16_t)(data & 0xFF); 00180 if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0; 00181 if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true; 00182 } 00183 } 00184 else { 00185 tx_buffer[tx_buffer_in++] = (char)(c & 0xFF); 00186 if (tx_buffer_in >= MAX3100_TX_BUFFER_SIZE) { 00187 tx_buffer_in = 0; 00188 } 00189 if (tx_buffer_in == tx_buffer_out) tx_buffer_full = true; 00190 } 00191 00192 irqEnable(); 00193 00194 return 1; 00195 } 00196 00197 void 00198 MAX3100::puts(char *s) { 00199 char *q = s; 00200 while(*(q)) { 00201 if (putc((int)(*(q))) == -1) return; 00202 q++; 00203 } 00204 } 00205 00206 int 00207 MAX3100::getc(void) { 00208 if (!rx_buffer_full && rx_buffer_in == rx_buffer_out) return -1; 00209 int c = (int)((unsigned char)rx_buffer[rx_buffer_out++]); 00210 if (rx_buffer_out >= MAX3100_RX_BUFFER_SIZE) rx_buffer_out = 0; 00211 rx_buffer_full = false; 00212 return c; 00213 } 00214 00215 char * 00216 MAX3100::gets(char *s, int size) 00217 { 00218 int i; 00219 char *q = s; 00220 while(size) { 00221 do { i = getc(); } while (i == -1); // Blocks! 00222 *(q) = (char)i; size--; 00223 } 00224 return s; 00225 } 00226 00227 int 00228 MAX3100::peek(void) { 00229 if (!rx_buffer_full && rx_buffer_in == rx_buffer_out) return -1; 00230 return (int)((unsigned char)rx_buffer[rx_buffer_out]); 00231 } 00232 00233 void 00234 MAX3100::isr(void) { 00235 uint16_t data = spiwrite(MAX3100_DATA_RD); 00236 bool tx_ready = data & MAX3100_CONF_T ? true : false; 00237 00238 // The MAX3100 does have an RX fifo. So attempt to empty it into the RX buffer. 00239 do { 00240 if (!rx_buffer_full && data & MAX3100_CONF_R) { 00241 rx_buffer[rx_buffer_in++] = (char)(data & 0xFF); 00242 if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0; 00243 if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true; 00244 } 00245 } 00246 while ((data = spiwrite(MAX3100_DATA_RD)) & MAX3100_CONF_R); 00247 00248 // The MAX3100 doesn't have a hardware TX fifo, so just test to see if it's TX buffer 00249 // is empty. If it is and we have bytes in the TX buffer then send one now. 00250 if (tx_ready && (tx_buffer_full || tx_buffer_in != tx_buffer_out)) { 00251 data = spiwrite(MAX3100_DATA_WR | (tx_buffer[tx_buffer_out++] & 0x1FF)); 00252 if (tx_buffer_out >= MAX3100_TX_BUFFER_SIZE) tx_buffer_out = 0; 00253 tx_buffer_full = false; 00254 } 00255 00256 // In case we get a byte while sending then store it. 00257 if (!rx_buffer_full && data & MAX3100_CONF_R) { 00258 rx_buffer[rx_buffer_in++] = (char)(data & 0xFF); 00259 if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0; 00260 if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true; 00261 } 00262 00263 int isrType = MAX3100::ISR; 00264 00265 if ( data & MAX3100_CONF_R ) { 00266 isrType |= MAX3100::ISR_RX; 00267 } 00268 00269 if ( tx_ready ) { 00270 isrType |= MAX3100::ISR_TX; 00271 } 00272 00273 00274 if (_isr_user_function != NULL) (*_isr_user_function)( isrType ); 00275 else { 00276 if (_isr_user_obj && _isr_user_method) (_isr_user_obj->*_isr_user_method)( isrType ); 00277 } 00278 } 00279 00280 void 00281 MAX3100::setStopBits(int i) 00282 { 00283 switch(i) { 00284 case 1: 00285 irqDisable(); 00286 config &= ~(1 << 6); 00287 config_write(config); 00288 irqEnable(); 00289 break; 00290 case 2: 00291 irqDisable(); 00292 config |= (1 << 6); 00293 config_write(config); 00294 irqEnable(); 00295 break; 00296 } 00297 } 00298 00299 int 00300 MAX3100::parityCal(uint8_t c) 00301 { 00302 int count = 0; 00303 for (int mask = 1, i = 0; i < 8; i++, mask = mask << 1) { 00304 if (c & mask) count++; 00305 } 00306 return count & 1; 00307 } 00308 00309 void 00310 MAX3100::irqDisable(void) 00311 { 00312 if (_irqMask0) LPC_GPIOINT->IO0IntEnF &= ~_irqMask0; 00313 if (_irqMask2) LPC_GPIOINT->IO2IntEnF &= ~_irqMask2; 00314 } 00315 00316 void 00317 MAX3100::irqEnable(void) 00318 { 00319 if (_irqMask0) LPC_GPIOINT->IO0IntEnF |= _irqMask0; 00320 if (_irqMask2) LPC_GPIOINT->IO2IntEnF |= _irqMask2; 00321 } 00322 00323 void 00324 MAX3100::irqMask(PinName p) 00325 { 00326 _irqMask0 = _irqMask2 = 0; 00327 00328 switch( p ) { 00329 case p5: _irqMask0 = (1UL << 9); break; 00330 case p6: _irqMask0 = (1UL << 8); break; 00331 case p7: _irqMask0 = (1UL << 7); break; 00332 case p8: _irqMask0 = (1UL << 6); break; 00333 case p9: _irqMask0 = (1UL << 0); break; 00334 case p10: _irqMask0 = (1UL << 1); break; 00335 case p11: _irqMask0 = (1UL << 18); break; 00336 case p12: _irqMask0 = (1UL << 17); break; 00337 case p13: _irqMask0 = (1UL << 15); break; 00338 case p14: _irqMask0 = (1UL << 16); break; 00339 case p15: _irqMask0 = (1UL << 23); break; 00340 case p16: _irqMask0 = (1UL << 24); break; 00341 case p17: _irqMask0 = (1UL << 25); break; 00342 case p18: _irqMask0 = (1UL << 26); break; 00343 case p21: _irqMask2 = (1UL << 5); break; 00344 case p22: _irqMask2 = (1UL << 4); break; 00345 case p23: _irqMask2 = (1UL << 3); break; 00346 case p24: _irqMask2 = (1UL << 2); break; 00347 case p25: _irqMask2 = (1UL << 1); break; 00348 case p26: _irqMask2 = (1UL << 0); break; 00349 case p27: _irqMask0 = (1UL << 11); break; 00350 case p28: _irqMask0 = (1UL << 10); break; 00351 case p29: _irqMask0 = (1UL << 5); break; 00352 case p30: _irqMask0 = (1UL << 4); break; 00353 } 00354 } 00355 00356 void 00357 MAX3100::topic_1498(PinName p) { 00358 // http://mbed.org/forum/bugs-suggestions/topic/1498 00359 uint32_t clr0 = 0, clr2 = 0; 00360 00361 switch( p ) { 00362 case p5: clr0 = (1UL << 9); break; 00363 case p6: clr0 = (1UL << 8); break; 00364 case p7: clr0 = (1UL << 7); break; 00365 case p8: clr0 = (1UL << 6); break; 00366 case p9: clr0 = (1UL << 0); break; 00367 case p10: clr0 = (1UL << 1); break; 00368 case p11: clr0 = (1UL << 18); break; 00369 case p12: clr0 = (1UL << 17); break; 00370 case p13: clr0 = (1UL << 15); break; 00371 case p14: clr0 = (1UL << 16); break; 00372 case p15: clr0 = (1UL << 23); break; 00373 case p16: clr0 = (1UL << 24); break; 00374 case p17: clr0 = (1UL << 25); break; 00375 case p18: clr0 = (1UL << 26); break; 00376 case p21: clr2 = (1UL << 5); break; 00377 case p22: clr2 = (1UL << 4); break; 00378 case p23: clr2 = (1UL << 3); break; 00379 case p24: clr2 = (1UL << 2); break; 00380 case p25: clr2 = (1UL << 1); break; 00381 case p26: clr2 = (1UL << 0); break; 00382 case p27: clr0 = (1UL << 11); break; 00383 case p28: clr0 = (1UL << 10); break; 00384 case p29: clr0 = (1UL << 5); break; 00385 case p30: clr0 = (1UL << 4); break; 00386 } 00387 00388 if (clr0) LPC_GPIOINT->IO0IntClr = clr0; 00389 if (clr2) LPC_GPIOINT->IO2IntClr = clr2; 00390 } 00391 00392 }; // namespace AjK ends
Generated on Wed Jul 13 2022 13:30:40 by 1.7.2