MAX3100, an external serial device to add additional serial ports via SPI

Dependents:   FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM

Committer:
AjK
Date:
Sun Jan 16 18:27:44 2011 +0000
Revision:
0:055897ab699b
Child:
1:46c8c60e744a
1.0 Initial release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AjK 0:055897ab699b 1 /*
AjK 0:055897ab699b 2 Copyright (c) 2011 Andy Kirkham
AjK 0:055897ab699b 3
AjK 0:055897ab699b 4 Permission is hereby granted, free of charge, to any person obtaining a copy
AjK 0:055897ab699b 5 of this software and associated documentation files (the "Software"), to deal
AjK 0:055897ab699b 6 in the Software without restriction, including without limitation the rights
AjK 0:055897ab699b 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
AjK 0:055897ab699b 8 copies of the Software, and to permit persons to whom the Software is
AjK 0:055897ab699b 9 furnished to do so, subject to the following conditions:
AjK 0:055897ab699b 10
AjK 0:055897ab699b 11 The above copyright notice and this permission notice shall be included in
AjK 0:055897ab699b 12 all copies or substantial portions of the Software.
AjK 0:055897ab699b 13
AjK 0:055897ab699b 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
AjK 0:055897ab699b 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
AjK 0:055897ab699b 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AjK 0:055897ab699b 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
AjK 0:055897ab699b 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
AjK 0:055897ab699b 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
AjK 0:055897ab699b 20 THE SOFTWARE.
AjK 0:055897ab699b 21 */
AjK 0:055897ab699b 22
AjK 0:055897ab699b 23 #include "MAX3100.h"
AjK 0:055897ab699b 24
AjK 0:055897ab699b 25 namespace AjK {
AjK 0:055897ab699b 26
AjK 0:055897ab699b 27 void
AjK 0:055897ab699b 28 MAX3100::init(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, SPI *spi)
AjK 0:055897ab699b 29 {
AjK 0:055897ab699b 30 config = 0;
AjK 0:055897ab699b 31 flushTxBuffer();
AjK 0:055897ab699b 32 flushRxBuffer();
AjK 0:055897ab699b 33
AjK 0:055897ab699b 34 _parity = 0;
AjK 0:055897ab699b 35
AjK 0:055897ab699b 36 _cs_function = NULL;
AjK 0:055897ab699b 37 _cs_obj = NULL;
AjK 0:055897ab699b 38 _cs_method = NULL;
AjK 0:055897ab699b 39
AjK 0:055897ab699b 40 if (cs != NC) {
AjK 0:055897ab699b 41 _cs = new DigitalOut(cs);
AjK 0:055897ab699b 42 _cs->write( 1 );
AjK 0:055897ab699b 43 }
AjK 0:055897ab699b 44 else _cs = (DigitalOut *)NULL;
AjK 0:055897ab699b 45
AjK 0:055897ab699b 46 if (spi) {
AjK 0:055897ab699b 47 _spi = spi;
AjK 0:055897ab699b 48 }
AjK 0:055897ab699b 49 else {
AjK 0:055897ab699b 50 _spi = new SPI(mosi, miso, sclk);
AjK 0:055897ab699b 51 _spi->format(16, 0);
AjK 0:055897ab699b 52 _spi->frequency(MAX3100_SPI_FREQ);
AjK 0:055897ab699b 53 }
AjK 0:055897ab699b 54
AjK 0:055897ab699b 55 if (irq != NC) {
AjK 0:055897ab699b 56 _irq = new InterruptIn(irq);
AjK 0:055897ab699b 57 _irq->mode(PullUp);
AjK 0:055897ab699b 58 topic_1498(irq);
AjK 0:055897ab699b 59 _irq->fall(this, &MAX3100::isr);
AjK 0:055897ab699b 60 }
AjK 0:055897ab699b 61 else { _irq = (InterruptIn *)NULL; }
AjK 0:055897ab699b 62
AjK 0:055897ab699b 63 baud(10); // 9600baud by default.
AjK 0:055897ab699b 64 }
AjK 0:055897ab699b 65
AjK 0:055897ab699b 66 void
AjK 0:055897ab699b 67 MAX3100::cs_value(int i)
AjK 0:055897ab699b 68 {
AjK 0:055897ab699b 69 if (_cs != (DigitalOut *)NULL) _cs->write(i & 1);
AjK 0:055897ab699b 70 else {
AjK 0:055897ab699b 71 if (_cs_function != NULL) (*_cs_function)(_device, i & 1);
AjK 0:055897ab699b 72 else {
AjK 0:055897ab699b 73 if (_cs_obj && _cs_method) (_cs_obj->*_cs_method)(_device, i & 1);
AjK 0:055897ab699b 74 }
AjK 0:055897ab699b 75 }
AjK 0:055897ab699b 76 }
AjK 0:055897ab699b 77
AjK 0:055897ab699b 78 uint16_t
AjK 0:055897ab699b 79 MAX3100::spiwrite(uint16_t val)
AjK 0:055897ab699b 80 {
AjK 0:055897ab699b 81 cs_value(0);
AjK 0:055897ab699b 82 uint16_t r = _spi->write(val);
AjK 0:055897ab699b 83 cs_value(1);
AjK 0:055897ab699b 84 return r;
AjK 0:055897ab699b 85 }
AjK 0:055897ab699b 86
AjK 0:055897ab699b 87 uint16_t
AjK 0:055897ab699b 88 MAX3100::config_write(uint16_t val)
AjK 0:055897ab699b 89 {
AjK 0:055897ab699b 90 return spiwrite(MAX3100_CONF_WR | val);
AjK 0:055897ab699b 91 }
AjK 0:055897ab699b 92
AjK 0:055897ab699b 93 uint16_t
AjK 0:055897ab699b 94 MAX3100::config_read(void)
AjK 0:055897ab699b 95 {
AjK 0:055897ab699b 96 return spiwrite(MAX3100_CONF_RD);
AjK 0:055897ab699b 97 }
AjK 0:055897ab699b 98
AjK 0:055897ab699b 99
AjK 0:055897ab699b 100 void
AjK 0:055897ab699b 101 MAX3100::baud(int baudrate)
AjK 0:055897ab699b 102 {
AjK 0:055897ab699b 103 __disable_irq();
AjK 0:055897ab699b 104 config &= ~(0xf);
AjK 0:055897ab699b 105 config |= (baudrate & 0xf);
AjK 0:055897ab699b 106 config_write(config);
AjK 0:055897ab699b 107 __enable_irq();
AjK 0:055897ab699b 108 }
AjK 0:055897ab699b 109
AjK 0:055897ab699b 110 void
AjK 0:055897ab699b 111 MAX3100::enableRxIrq(void)
AjK 0:055897ab699b 112 {
AjK 0:055897ab699b 113 __disable_irq();
AjK 0:055897ab699b 114 config &= ~MAX3100_RM(1);
AjK 0:055897ab699b 115 config |= MAX3100_RM(1);
AjK 0:055897ab699b 116 config_write(config);
AjK 0:055897ab699b 117 __enable_irq();
AjK 0:055897ab699b 118 }
AjK 0:055897ab699b 119
AjK 0:055897ab699b 120 void
AjK 0:055897ab699b 121 MAX3100::disableRxIrq(void)
AjK 0:055897ab699b 122 {
AjK 0:055897ab699b 123 __disable_irq();
AjK 0:055897ab699b 124 config &= ~MAX3100_RM(1);
AjK 0:055897ab699b 125 config_write(config);
AjK 0:055897ab699b 126 __enable_irq();
AjK 0:055897ab699b 127 }
AjK 0:055897ab699b 128
AjK 0:055897ab699b 129 void
AjK 0:055897ab699b 130 MAX3100::enableTxIrq(void)
AjK 0:055897ab699b 131 {
AjK 0:055897ab699b 132 __disable_irq();
AjK 0:055897ab699b 133 config &= ~MAX3100_TM(1);
AjK 0:055897ab699b 134 config |= MAX3100_TM(1);
AjK 0:055897ab699b 135 config_write(config);
AjK 0:055897ab699b 136 __enable_irq();
AjK 0:055897ab699b 137 }
AjK 0:055897ab699b 138
AjK 0:055897ab699b 139 void
AjK 0:055897ab699b 140 MAX3100::disableTxIrq(void)
AjK 0:055897ab699b 141 {
AjK 0:055897ab699b 142 __disable_irq();
AjK 0:055897ab699b 143 config &= ~MAX3100_TM(1);
AjK 0:055897ab699b 144 config_write(config);
AjK 0:055897ab699b 145 __enable_irq();
AjK 0:055897ab699b 146 }
AjK 0:055897ab699b 147
AjK 0:055897ab699b 148 int
AjK 0:055897ab699b 149 MAX3100::putc(int c)
AjK 0:055897ab699b 150 {
AjK 0:055897ab699b 151 uint16_t data, conf;
AjK 0:055897ab699b 152
AjK 0:055897ab699b 153 // If no space return -1 as an error code.
AjK 0:055897ab699b 154 if (tx_buffer_full) return -1;
AjK 0:055897ab699b 155
AjK 0:055897ab699b 156 if (_parity) {
AjK 0:055897ab699b 157 int pBit = parityCal(c & 0xFF);
AjK 0:055897ab699b 158 if (_parity == Even && pBit == 0) { c |= (1 << 8); }
AjK 0:055897ab699b 159 if (_parity == Odd && pBit == 1) { c |= (1 << 8); }
AjK 0:055897ab699b 160 }
AjK 0:055897ab699b 161 else { c &= 0xFF; }
AjK 0:055897ab699b 162
AjK 0:055897ab699b 163 // Function is non-interruptable by the MAX3100 class
AjK 0:055897ab699b 164 // to avoid SPI bus contention between writing a byte
AjK 0:055897ab699b 165 // in user context (here) and IRQ context.
AjK 0:055897ab699b 166 __disable_irq();
AjK 0:055897ab699b 167
AjK 0:055897ab699b 168 conf = config_read();
AjK 0:055897ab699b 169
AjK 0:055897ab699b 170 if (tx_buffer_in == tx_buffer_out && conf & MAX3100_CONF_T) {
AjK 0:055897ab699b 171 data = spiwrite(MAX3100_DATA_WR | (c & 0x1FF));
AjK 0:055897ab699b 172 // In case we get a byte while writing store it away.
AjK 0:055897ab699b 173 if (!rx_buffer_full && data & MAX3100_CONF_R) {
AjK 0:055897ab699b 174 rx_buffer[rx_buffer_in++] = (uint16_t)(data & 0xFF);
AjK 0:055897ab699b 175 if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0;
AjK 0:055897ab699b 176 if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true;
AjK 0:055897ab699b 177 }
AjK 0:055897ab699b 178 }
AjK 0:055897ab699b 179 else {
AjK 0:055897ab699b 180 tx_buffer[tx_buffer_in++] = (char)(c & 0xFF);
AjK 0:055897ab699b 181 if (tx_buffer_in >= MAX3100_TX_BUFFER_SIZE) {
AjK 0:055897ab699b 182 tx_buffer_in = 0;
AjK 0:055897ab699b 183 }
AjK 0:055897ab699b 184 if (tx_buffer_in == tx_buffer_out) tx_buffer_full = true;
AjK 0:055897ab699b 185 }
AjK 0:055897ab699b 186
AjK 0:055897ab699b 187 __enable_irq();
AjK 0:055897ab699b 188
AjK 0:055897ab699b 189 return 1;
AjK 0:055897ab699b 190 }
AjK 0:055897ab699b 191
AjK 0:055897ab699b 192 void
AjK 0:055897ab699b 193 MAX3100::puts(char *s) {
AjK 0:055897ab699b 194 char *q = s;
AjK 0:055897ab699b 195 while(*(q)) {
AjK 0:055897ab699b 196 if (putc((int)(*(q))) == -1) return;
AjK 0:055897ab699b 197 q++;
AjK 0:055897ab699b 198 }
AjK 0:055897ab699b 199 }
AjK 0:055897ab699b 200
AjK 0:055897ab699b 201 int
AjK 0:055897ab699b 202 MAX3100::getc(void) {
AjK 0:055897ab699b 203 if (!rx_buffer_full && rx_buffer_in == rx_buffer_out) return -1;
AjK 0:055897ab699b 204 int c = (int)((unsigned char)rx_buffer[rx_buffer_out++]);
AjK 0:055897ab699b 205 if (rx_buffer_out >= MAX3100_RX_BUFFER_SIZE) rx_buffer_out = 0;
AjK 0:055897ab699b 206 rx_buffer_full = false;
AjK 0:055897ab699b 207 return c;
AjK 0:055897ab699b 208 }
AjK 0:055897ab699b 209
AjK 0:055897ab699b 210 char *
AjK 0:055897ab699b 211 MAX3100::gets(char *s, int size)
AjK 0:055897ab699b 212 {
AjK 0:055897ab699b 213 int i;
AjK 0:055897ab699b 214 char *q = s;
AjK 0:055897ab699b 215 while(size) {
AjK 0:055897ab699b 216 do { i = getc(); } while (i == -1); // Blocks!
AjK 0:055897ab699b 217 *(q) = (char)i; size--;
AjK 0:055897ab699b 218 }
AjK 0:055897ab699b 219 return s;
AjK 0:055897ab699b 220 }
AjK 0:055897ab699b 221
AjK 0:055897ab699b 222 int
AjK 0:055897ab699b 223 MAX3100::peek(void) {
AjK 0:055897ab699b 224 if (!rx_buffer_full && rx_buffer_in == rx_buffer_out) return -1;
AjK 0:055897ab699b 225 return (int)((unsigned char)rx_buffer[rx_buffer_out]);
AjK 0:055897ab699b 226 }
AjK 0:055897ab699b 227
AjK 0:055897ab699b 228 void
AjK 0:055897ab699b 229 MAX3100::isr(void) {
AjK 0:055897ab699b 230 uint16_t data = spiwrite(MAX3100_DATA_RD);
AjK 0:055897ab699b 231 bool tx_ready = data & MAX3100_CONF_T ? true : false;
AjK 0:055897ab699b 232
AjK 0:055897ab699b 233 // The MAX3100 does have an RX fifo. So attempt to empty it into the RX buffer.
AjK 0:055897ab699b 234 do {
AjK 0:055897ab699b 235 if (!rx_buffer_full && data & MAX3100_CONF_R) {
AjK 0:055897ab699b 236 rx_buffer[rx_buffer_in++] = (char)(data & 0xFF);
AjK 0:055897ab699b 237 if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0;
AjK 0:055897ab699b 238 if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true;
AjK 0:055897ab699b 239 }
AjK 0:055897ab699b 240 }
AjK 0:055897ab699b 241 while ((data = spiwrite(MAX3100_DATA_RD)) & MAX3100_CONF_R);
AjK 0:055897ab699b 242
AjK 0:055897ab699b 243 // The MAX3100 doesn't have a hardware TX fifo, so just test to see if it's TX buffer
AjK 0:055897ab699b 244 // is empty. If it is and we have bytes in the TX buffer then send one now.
AjK 0:055897ab699b 245 if (tx_ready && (tx_buffer_full || tx_buffer_in != tx_buffer_out)) {
AjK 0:055897ab699b 246 data = spiwrite(MAX3100_DATA_WR | (tx_buffer[tx_buffer_out++] & 0x1FF));
AjK 0:055897ab699b 247 if (tx_buffer_out >= MAX3100_TX_BUFFER_SIZE) tx_buffer_out = 0;
AjK 0:055897ab699b 248 tx_buffer_full = false;
AjK 0:055897ab699b 249 }
AjK 0:055897ab699b 250
AjK 0:055897ab699b 251 // In case we get a byte while sending then store it.
AjK 0:055897ab699b 252 if (!rx_buffer_full && data & MAX3100_CONF_R) {
AjK 0:055897ab699b 253 rx_buffer[rx_buffer_in++] = (char)(data & 0xFF);
AjK 0:055897ab699b 254 if (rx_buffer_in >= MAX3100_RX_BUFFER_SIZE) rx_buffer_in = 0;
AjK 0:055897ab699b 255 if (rx_buffer_in == rx_buffer_out) rx_buffer_full = true;
AjK 0:055897ab699b 256 }
AjK 0:055897ab699b 257 }
AjK 0:055897ab699b 258
AjK 0:055897ab699b 259 void
AjK 0:055897ab699b 260 MAX3100::setStopBits(int i)
AjK 0:055897ab699b 261 {
AjK 0:055897ab699b 262 switch(i) {
AjK 0:055897ab699b 263 case 1:
AjK 0:055897ab699b 264 __disable_irq();
AjK 0:055897ab699b 265 config &= ~(1 << 6);
AjK 0:055897ab699b 266 config_write(config);
AjK 0:055897ab699b 267 __enable_irq();
AjK 0:055897ab699b 268 break;
AjK 0:055897ab699b 269 case 2:
AjK 0:055897ab699b 270 __disable_irq();
AjK 0:055897ab699b 271 config |= (1 << 6);
AjK 0:055897ab699b 272 config_write(config);
AjK 0:055897ab699b 273 __enable_irq();
AjK 0:055897ab699b 274 break;
AjK 0:055897ab699b 275 }
AjK 0:055897ab699b 276 }
AjK 0:055897ab699b 277
AjK 0:055897ab699b 278 int
AjK 0:055897ab699b 279 MAX3100::parityCal(uint8_t c)
AjK 0:055897ab699b 280 {
AjK 0:055897ab699b 281 int count = 0;
AjK 0:055897ab699b 282 for (int mask = 1, i = 0; i < 8; i++, mask = mask << 1) {
AjK 0:055897ab699b 283 if (c & mask) count++;
AjK 0:055897ab699b 284 }
AjK 0:055897ab699b 285 return count & 1;
AjK 0:055897ab699b 286 }
AjK 0:055897ab699b 287
AjK 0:055897ab699b 288 void
AjK 0:055897ab699b 289 MAX3100::topic_1498(PinName p) {
AjK 0:055897ab699b 290 // http://mbed.org/forum/bugs-suggestions/topic/1498
AjK 0:055897ab699b 291 uint32_t clr0 = 0, clr2 = 0;
AjK 0:055897ab699b 292
AjK 0:055897ab699b 293 switch( p ) {
AjK 0:055897ab699b 294 case p5: clr0 = (1UL << 9); break;
AjK 0:055897ab699b 295 case p6: clr0 = (1UL << 8); break;
AjK 0:055897ab699b 296 case p7: clr0 = (1UL << 7); break;
AjK 0:055897ab699b 297 case p8: clr0 = (1UL << 6); break;
AjK 0:055897ab699b 298 case p9: clr0 = (1UL << 0); break;
AjK 0:055897ab699b 299 case p10: clr0 = (1UL << 1); break;
AjK 0:055897ab699b 300 case p11: clr0 = (1UL << 18); break;
AjK 0:055897ab699b 301 case p12: clr0 = (1UL << 17); break;
AjK 0:055897ab699b 302 case p13: clr0 = (1UL << 15); break;
AjK 0:055897ab699b 303 case p14: clr0 = (1UL << 16); break;
AjK 0:055897ab699b 304 case p15: clr0 = (1UL << 23); break;
AjK 0:055897ab699b 305 case p16: clr0 = (1UL << 24); break;
AjK 0:055897ab699b 306 case p17: clr0 = (1UL << 25); break;
AjK 0:055897ab699b 307 case p18: clr0 = (1UL << 26); break;
AjK 0:055897ab699b 308 case p21: clr2 = (1UL << 5); break;
AjK 0:055897ab699b 309 case p22: clr2 = (1UL << 4); break;
AjK 0:055897ab699b 310 case p23: clr2 = (1UL << 3); break;
AjK 0:055897ab699b 311 case p24: clr2 = (1UL << 2); break;
AjK 0:055897ab699b 312 case p25: clr2 = (1UL << 1); break;
AjK 0:055897ab699b 313 case p26: clr2 = (1UL << 0); break;
AjK 0:055897ab699b 314 case p27: clr0 = (1UL << 11); break;
AjK 0:055897ab699b 315 case p28: clr0 = (1UL << 10); break;
AjK 0:055897ab699b 316 case p29: clr0 = (1UL << 5); break;
AjK 0:055897ab699b 317 case p30: clr0 = (1UL << 4); break;
AjK 0:055897ab699b 318 }
AjK 0:055897ab699b 319
AjK 0:055897ab699b 320 if (clr0) LPC_GPIOINT->IO0IntClr = clr0;
AjK 0:055897ab699b 321 if (clr2) LPC_GPIOINT->IO2IntClr = clr2;
AjK 0:055897ab699b 322 }
AjK 0:055897ab699b 323
AjK 0:055897ab699b 324 }; // namespace AjK ends