SPI or I2C to UART Bridge
Dependents: SC16IS750_Test mbed_SC16IS750 Xadow_SC16IS750_Test Xadow_MPU9150AHRS
SC16IS750.cpp
00001 /* SC16IS750 I2C or SPI to UART bridge 00002 * v0.1 WH, Nov 2013, Sparkfun WiFly Shield code library alpha 0 used as example, Added I2C I/F and many more methods. 00003 * https://forum.sparkfun.com/viewtopic.php?f=13&t=21846 00004 * v0.2 WH, Feb 2014, Added Doxygen Documentation, Added Hardware Reset pin methods. 00005 * v0.3 WH, Dec 2014, Added support for SC16IS752 dual UART. 00006 * v0.4 WH, Dec 2014, Added Repeated Start for I2C readRegister(). Set I2C clock at 100kb/s. Fixed and added some comments. 00007 * 00008 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00009 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00010 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00011 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00012 * furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included in all copies or 00015 * substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00018 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00020 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00022 */ 00023 #include "mbed.h" 00024 #include "SC16IS750.h" 00025 00026 #define ENABLE_BULK_TRANSFERS 1 00027 #define BULK_BLOCK_LEN 16 00028 00029 /** Abstract class SC16IS750 for converter between either SPI or I2C and a Serial port 00030 * Constructor for this Abstract Class is protected 00031 * Supports both SPI and I2C interfaces through derived classes 00032 * 00033 * @code 00034 * 00035 * @endcode 00036 */ 00037 SC16IS750::SC16IS750() { 00038 //SC16IS750::SC16IS750() : Serial(NC, NC) { //Fout, mag geen NC zijn 00039 //SC16IS750::SC16IS750() : SerialBase(NC, NC) { //Fout, mag geen NC zijn 00040 // Dont call _init() here since the SPI or I2C port have not yet been configured... 00041 //_init(); // initialise UART registers 00042 } 00043 00044 00045 /** Set baudrate of the serial port. 00046 * @param baud integer baudrate (4800, 9600 etc) 00047 * @return none 00048 */ 00049 void SC16IS750::baud(int baudrate) { 00050 unsigned long divisor = SC16IS750_BAUDRATE_DIVISOR(baudrate); 00051 char lcr_tmp; 00052 00053 _config.baudrate = baudrate; // Save baudrate 00054 00055 lcr_tmp = this->readRegister(LCR); // Read current LCR register 00056 this->writeRegister(LCR, lcr_tmp | LCR_ENABLE_DIV); // Enable Divisor registers 00057 this->writeRegister(DLL, ( divisor & 0xFF)); // write divisor LSB 00058 this->writeRegister(DLH, ((divisor >> 8) & 0xFF)); // write divisor MSB 00059 this->writeRegister(LCR, lcr_tmp); // Restore LCR register, activate regular RBR, THR and IER registers 00060 00061 } 00062 00063 00064 /** Set the transmission format used by the serial port. 00065 * @param bits The number of bits in a word (5-8; default = 8) 00066 * @param parity The parity used (Serial::None, Serial::Odd, Serial::Even, Serial::Forced1, Serial::Forced0; default = Serial::None) 00067 * @param stop_bits The number of stop bits (1 or 2; default = 1) 00068 * @return none 00069 */ 00070 void SC16IS750::format(int bits, Serial::Parity parity, int stop_bits) { 00071 char lcr_tmp = 0x00; 00072 00073 switch (bits) { 00074 case 5: lcr_tmp |= LCR_BITS5; 00075 break; 00076 case 6: lcr_tmp |= LCR_BITS6; 00077 break; 00078 case 7: lcr_tmp |= LCR_BITS7; 00079 break; 00080 case 8: lcr_tmp |= LCR_BITS8; 00081 break; 00082 default: lcr_tmp |= LCR_BITS8; 00083 } 00084 00085 switch (parity) { 00086 case Serial::None: lcr_tmp |= LCR_NONE; 00087 break; 00088 case Serial::Odd: lcr_tmp |= LCR_ODD; 00089 break; 00090 case Serial::Even: lcr_tmp |= LCR_EVEN; 00091 break; 00092 case Serial::Forced1: lcr_tmp |= LCR_FORCED1; 00093 break; 00094 case Serial::Forced0: lcr_tmp |= LCR_FORCED0; 00095 break; 00096 default: lcr_tmp |= LCR_NONE; 00097 } 00098 00099 switch (stop_bits) { 00100 case 1: lcr_tmp |= LCR_BITS1; 00101 break; 00102 case 2: lcr_tmp |= LCR_BITS2; 00103 break; 00104 default: lcr_tmp |= LCR_BITS1; 00105 } 00106 00107 _config.dataformat = lcr_tmp; // Save dataformat 00108 00109 this->writeRegister(LCR, lcr_tmp); // Set LCR register, activate regular RBR, THR and IER registers 00110 00111 }; 00112 00113 /** Generate a break condition on the serial line 00114 * @return none 00115 */ 00116 void SC16IS750::send_break() { 00117 // Wait for 1.5 frames before clearing the break condition 00118 // This will have different effects on our platforms, but should 00119 // ensure that we keep the break active for at least one frame. 00120 // We consider a full frame (1 start bit + 8 data bits bits + 00121 // 1 parity bit + 2 stop bits = 12 bits) for computation. 00122 // One bit time (in us) = 1000000/_baud 00123 // Twelve bits: 12000000/baud delay 00124 // 1.5 frames: 18000000/baud delay 00125 set_break(true); 00126 wait_us(18000000/_config.baudrate); 00127 set_break(false); 00128 }; 00129 00130 /** Set a break condition on the serial line 00131 * @param enable break condition 00132 * @return none 00133 */ 00134 void SC16IS750::set_break(bool enable) { 00135 00136 if (enable) { 00137 _config.dataformat |= LCR_BRK_ENA; // Save dataformat 00138 } 00139 else { 00140 _config.dataformat &= ~LCR_BRK_ENA; // Save dataformat 00141 } 00142 00143 this->writeRegister(LCR, _config.dataformat); // Set LCR register 00144 } 00145 00146 /** Set the flow control type on the serial port 00147 * Added for compatibility with Serial Class. 00148 * SC16IS750 supports only Flow, Pins can not be selected. 00149 * This method sets hardware flow control. SC16IS750 supports XON/XOFF, but this is not implemented. 00150 * 00151 * @param type the flow control type (Disabled, RTS, CTS, RTSCTS) 00152 * @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS) - NOT USED 00153 * @param flow2 the second flow control pin (CTS for RTSCTS) - NOT USED 00154 * @return none 00155 */ 00156 void SC16IS750::set_flow_control(Flow type, PinName flow1, PinName flow2) { 00157 char lcr_tmp; 00158 char efr_tmp = 0x00; 00159 00160 // We need to enable flow control to prevent overflow of buffers and 00161 // lose data when used with fast devices like the WiFly. 00162 00163 switch (type) { 00164 case Disabled : 00165 break; 00166 case RTS: efr_tmp = EFR_ENABLE_RTS; 00167 break; 00168 case CTS: efr_tmp = EFR_ENABLE_CTS; 00169 break; 00170 case RTSCTS: efr_tmp = EFR_ENABLE_RTS | EFR_ENABLE_CTS; 00171 break; 00172 default: ; 00173 00174 } 00175 00176 //Save flowcontrol mode and enable enhanced functions 00177 _config.flowctrl = efr_tmp | EFR_ENABLE_ENHANCED_FUNCTIONS; 00178 00179 lcr_tmp = this->readRegister(LCR); // save LRC register 00180 this->writeRegister(LCR, LCR_ENABLE_ENHANCED_FUNCTIONS); // write magic number 0xBF to enable access to EFR register 00181 this->writeRegister(EFR, _config.flowctrl); // set flow and enable enhanced functions 00182 this->writeRegister(LCR, lcr_tmp); // restore LCR register 00183 } 00184 00185 /** Set the RX FIFO flow control levels 00186 * This method sets hardware flow control levels. SC16IS750 supports XON/XOFF, but this is not implemented. 00187 * Should be called BEFORE Auto RTS is enabled. 00188 * 00189 * @param resume trigger level to resume transmission (0..15, meaning 0-60 with a granularity of 4) 00190 * @param halt trigger level to resume transmission (0..15, meaning 0-60 with granularity of 4) 00191 * @return none 00192 */ 00193 void SC16IS750::set_flow_triggers(int resume, int halt) { 00194 00195 // sanity checks 00196 halt = halt & 0x0F; 00197 resume = resume & 0x0F; 00198 if (halt <= resume) { 00199 halt = TCR_HALT_DEFAULT; 00200 resume = TCR_RESUME_DEFAULT; 00201 } 00202 00203 // Note: TCR accessible only when EFR[4]=1 and MCR[2]=1 00204 this->writeRegister(TCR, (resume << 4) | halt); // set TCR register 00205 } 00206 00207 00208 /** Set the Modem Control register 00209 * This method sets prescaler, enables TCR and TLR 00210 * 00211 * @param none 00212 * @return none 00213 */ 00214 void SC16IS750::set_modem_control() { 00215 00216 //Note MCR[7:4] and MCR[2] only accessible when EFR[4] is set 00217 if (SC16IS750_PRESCALER == SC16IS750_PRESCALER_1) { // Default prescaler after reset 00218 this->writeRegister(MCR, MCR_PRESCALE_1 | MCR_ENABLE_TCR_TLR); 00219 } 00220 else { 00221 this->writeRegister(MCR, MCR_PRESCALE_4 | MCR_ENABLE_TCR_TLR); 00222 } 00223 } 00224 00225 00226 00227 /** Initialise internal registers 00228 * Should be in protection section. Public for testing purposes 00229 * If initialisation fails this method does not return. 00230 * @param none 00231 * @return none 00232 */ 00233 void SC16IS750::_init() { 00234 00235 // Initialise SC16IS750 00236 00237 // Hardware reset, assuming there is a HW Reset pin 00238 // this->hwReset(); 00239 00240 // Software reset, assuming there is no access to the HW Reset pin 00241 swReset(); 00242 00243 // Set default baudrate (depends on prescaler) and save in _config 00244 // DLL/DLH 00245 baud(); 00246 00247 // Set default dataformat and save in _config 00248 // LCR 00249 format(); 00250 00251 // Set dataflow mode and Enables enhanced functions 00252 // Save in _config 00253 // EFR 00254 set_flow_control(); 00255 00256 00257 // FIFO control, sets TX and RX IRQ trigger levels and enables FIFO and save in _config 00258 // Note FCR[5:4] only accessible when EFR[4] is set (enhanced functions enable) 00259 // FCR, TLR 00260 set_fifo_control(); 00261 flush(); 00262 00263 // Modem control, sets prescaler, enable TCR and TLR 00264 // Note MCR[7:4] and MCR[2] only accessible when EFR[4] is set (enhanced functions enable) 00265 set_modem_control(); 00266 00267 // Set RTS trigger levels 00268 // Note TCR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set 00269 set_flow_triggers(); 00270 00271 00272 // Set default break condition and save in _config 00273 // LCR 00274 //set_break(); 00275 00276 // The UART bridge should now be successfully initialised. 00277 00278 // Test if UART bridge is present and initialised 00279 if(!connected()){ 00280 #if(0) 00281 // Lock up if we fail to initialise UART bridge. 00282 while(1) {}; 00283 #else 00284 printf("Failed to initialise UART bridge\r\n"); 00285 #endif 00286 } 00287 else { 00288 printf("Initialised UART bridge!\r\n"); 00289 } 00290 00291 } 00292 00293 00294 /** FIFO control, sets TX and RX trigger levels and enables FIFO and save in _config 00295 * Note FCR[5:4] (=TX_IRQ_LVL) only accessible when EFR[4] is set (enhanced functions enable) 00296 * Note TLR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set 00297 * @param none 00298 * @return none 00299 */ 00300 void SC16IS750::set_fifo_control() { 00301 00302 // Set default fifoformat 00303 // FCR 00304 _config.fifoenable = true; 00305 00306 // Note FCR[5:4] (=TX_IRQ_LVL) only accessible when EFR[4] is set (enhanced functions enable) 00307 // _config.fifoformat = FCR_RX_IRQ_8 | FCR_TX_IRQ_56; 00308 _config.fifoformat = FCR_RX_IRQ_8 | FCR_TX_IRQ_8; //Default 00309 00310 if (_config.fifoenable) 00311 // enable FIFO mode and set FIFO control values 00312 this->writeRegister(FCR, _config.fifoformat | FCR_ENABLE_FIFO); 00313 else 00314 // disable FIFO mode and set FIFO control values 00315 this->writeRegister(FCR, _config.fifoformat); 00316 00317 // Set Trigger level register TLR for RX and TX interrupt generation 00318 // Note TLR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set 00319 // TRL Trigger levels for RX and TX are 0..15, meaning 0-60 with a granularity of 4 chars 00320 // When TLR for RX or TX are 'Zero' the corresponding values in FCR are used. The FCR settings 00321 // have less resolution (only 4 levels) so TLR is considered an enhanced function. 00322 this->writeRegister(TLR, 0x00); // Use FCR Levels 00323 // this->writeRegister(TLR, (TLR_RX_DEFAULT << 4) | TLR_TX_DEFAULT); // Use Default enhanced levels 00324 00325 } 00326 00327 00328 /** 00329 * Flush the UART FIFOs while maintaining current FIFO mode. 00330 * @param none 00331 * @return none 00332 */ 00333 void SC16IS750::flush() { 00334 // FCR is Write Only, use saved _config 00335 00336 // reset TXFIFO, reset RXFIFO, non FIFO mode 00337 this->writeRegister(FCR, FCR_TX_FIFO_RST | FCR_RX_FIFO_RST); 00338 00339 if (_config.fifoenable) 00340 // enable FIFO mode and set FIFO control values 00341 this->writeRegister(FCR, _config.fifoformat | FCR_ENABLE_FIFO); 00342 else 00343 // disable FIFO mode and set FIFO control values 00344 this->writeRegister(FCR, _config.fifoformat); 00345 00346 #if(0) 00347 //original 00348 /* 00349 * Flush characters from SC16IS750 receive buffer. 00350 */ 00351 00352 // Note: This may not be the most appropriate flush approach. 00353 // It might be better to just flush the UART's buffer 00354 // rather than the buffer of the connected device 00355 // which is essentially what this does. 00356 while(readable() > 0) { 00357 getc(); 00358 } 00359 #endif 00360 00361 } 00362 00363 00364 /** 00365 * Check that UART is connected and operational. 00366 * @param none 00367 * @return bool true when connected, false otherwise 00368 */ 00369 bool SC16IS750::connected() { 00370 // Perform read/write test to check if UART is working 00371 const char TEST_CHARACTER = 'H'; 00372 00373 this->writeRegister(SPR, TEST_CHARACTER); 00374 00375 return (this->readRegister(SPR) == TEST_CHARACTER); 00376 } 00377 00378 00379 /** Determine if there is a character available to read. 00380 * This is data that's already arrived and stored in the receive 00381 * buffer (which holds 64 chars). 00382 * 00383 * @return 1 if there is a character available to read, 0 otherwise 00384 */ 00385 int SC16IS750::readable() { 00386 00387 // if (this->readableCount() > 0) { // Check count 00388 if (this->readRegister(LSR) & LSR_DR) { // Data in Receiver Bit, at least one character waiting 00389 return 1; 00390 } 00391 else { 00392 return 0; 00393 } 00394 } 00395 00396 /** Determine how many characters are available to read. 00397 * This is data that's already arrived and stored in the receive 00398 * buffer (which holds 64 chars). 00399 * 00400 * @return int Characters available to read 00401 */ 00402 int SC16IS750::readableCount() { 00403 00404 return (this->readRegister(RXLVL)); 00405 } 00406 00407 /** Determine if there is space available to write a character. 00408 * @return 1 if there is a space for a character to write, 0 otherwise 00409 */ 00410 int SC16IS750::writable() { 00411 00412 // if ((this->writableCount() > 0) { // Check count 00413 if (this->readRegister(LSR) & LSR_THRE) { // THR Empty, space for at least one character 00414 return 1; 00415 } 00416 else { 00417 return 0; 00418 } 00419 } 00420 00421 /** Determine how much space available for writing characters. 00422 * This considers data that's already stored in the transmit 00423 * buffer (which holds 64 chars). 00424 * 00425 * @return int character space available to write 00426 */ 00427 int SC16IS750::writableCount() { 00428 00429 return (this->readRegister(TXLVL)); // TX Level 00430 } 00431 00432 00433 /** 00434 * Read char from UART Bridge. 00435 * Acts in the same manner as 'Serial.read()'. 00436 * @param none 00437 * @return char read or -1 if no data available. 00438 */ 00439 int SC16IS750::getc() { 00440 00441 if (!readable()) { 00442 return -1; 00443 } 00444 00445 return this->readRegister(RHR); 00446 } 00447 00448 00449 /** 00450 * Write char to UART Bridge. Blocking when no free space in FIFO 00451 * @param value char to be written 00452 * @return value written 00453 */ 00454 int SC16IS750::putc(int value) { 00455 00456 while (this->readRegister(TXLVL) == 0) { 00457 // Wait for space in TX buffer 00458 wait_us(10); 00459 }; 00460 this->writeRegister(THR, value); 00461 00462 return value; 00463 } 00464 00465 00466 /** 00467 * Write char string to UART Bridge. Blocking when no free space in FIFO 00468 * @param *str char string to be written 00469 * @return none 00470 */ 00471 void SC16IS750::writeString(const char *str) { 00472 00473 #if ENABLE_BULK_TRANSFERS 00474 int len, idx; 00475 00476 len = strlen(str); 00477 00478 // Write blocks of BULK_BLOCK_LEN 00479 while (len > BULK_BLOCK_LEN) { 00480 while(this->readRegister(TXLVL) < BULK_BLOCK_LEN) { 00481 // Wait for space in TX buffer 00482 wait_us(10); 00483 }; 00484 00485 // Write a block of BULK_BLOCK_LEN bytes 00486 #if (0) 00487 // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes. 00488 for (idx=0; idx<BULK_BLOCK_LEN; idx++) { 00489 this->writeRegister(THR, str[idx]); 00490 }; 00491 #else 00492 // optimized 00493 this->writeDataBlock(str, BULK_BLOCK_LEN); 00494 #endif 00495 00496 len -= BULK_BLOCK_LEN; 00497 str += BULK_BLOCK_LEN; 00498 } 00499 00500 // Write remaining bytes 00501 // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes. 00502 for (idx=0; idx<len; idx++) { 00503 while (this->readRegister(TXLVL) == 0) { 00504 // Wait for space in TX buffer 00505 wait_us(10); 00506 }; 00507 this->writeRegister(THR, str[idx]); 00508 } 00509 00510 00511 #else 00512 // Single writes instead of bulktransfer 00513 int len, idx; 00514 00515 len = strlen(str); 00516 for (idx=0; idx<len; idx++) { 00517 while (this->readRegister(TXLVL) == 0) { 00518 // Wait for space in TX buffer 00519 wait_us(10); 00520 }; 00521 this->writeRegister(THR, str[idx]); 00522 } 00523 #endif 00524 } 00525 00526 00527 /** 00528 * Write byte array to UART Bridge. Blocking when no free space in FIFO 00529 * @param *data byte array to be written 00530 * @param len number of bytes to write 00531 * @return none 00532 */ 00533 void SC16IS750::writeBytes(const char *data, int len) { 00534 00535 #if ENABLE_BULK_TRANSFERS 00536 int idx; 00537 00538 // Write blocks of BULK_BLOCK_LEN 00539 while (len > BULK_BLOCK_LEN) { 00540 while(this->readRegister(TXLVL) < BULK_BLOCK_LEN) { 00541 // Wait for space in TX buffer 00542 wait_us(10); 00543 }; 00544 00545 // Write a block of BULK_BLOCK_LEN bytes 00546 #if (0) 00547 // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes. 00548 for (idx=0; idx<BULK_BLOCK_LEN; idx++) { 00549 this->writeRegister(THR, data[idx]); 00550 }; 00551 #else 00552 // optimized 00553 this->writeDataBlock(data, BULK_BLOCK_LEN); 00554 #endif 00555 00556 len -= BULK_BLOCK_LEN; 00557 data += BULK_BLOCK_LEN; 00558 } 00559 00560 // Write remaining bytes 00561 // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes. 00562 for (idx=0; idx<len; idx++) { 00563 while (this->readRegister(TXLVL) == 0) { 00564 // Wait for space in TX buffer 00565 wait_us(10); 00566 }; 00567 this->writeRegister(THR, data[idx]); 00568 } 00569 00570 00571 #else 00572 // Single writes instead of bulktransfer 00573 int idx; 00574 00575 for (idx=0; idx<len; idx++) { 00576 while (this->readRegister(TXLVL) == 0) { 00577 // Wait for space in TX buffer 00578 wait_us(10); 00579 }; 00580 this->writeRegister(THR, str[idx]); 00581 } 00582 #endif 00583 } 00584 00585 00586 /** Set direction of I/O port pins. 00587 * This method is specific to the SPI-I2C UART and not found on the 16750 00588 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. 00589 * @param bits Bitpattern for I/O (1=output, 0=input) 00590 * @return none 00591 */ 00592 void SC16IS750::ioSetDirection(unsigned char bits) { 00593 this->writeRegister(IODIR, bits); 00594 } 00595 00596 /** Set bits of I/O port pins. 00597 * This method is specific to the SPI-I2C UART and not found on the 16750 00598 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. 00599 * @param bits Bitpattern for I/O (1= set output bit, 0 = clear output bit) 00600 * @return none 00601 */ 00602 void SC16IS750::ioSetState(unsigned char bits) { 00603 this->writeRegister(IOSTATE, bits); 00604 } 00605 00606 /** Get bits of I/O port pins. 00607 * This method is specific to the SPI-I2C UART and not found on the 16750 00608 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. 00609 * @param none 00610 * @return bits Bitpattern for I/O (1= bit set, 0 = bit cleared) 00611 */ 00612 unsigned char SC16IS750::ioGetState() { 00613 return this->readRegister(IOSTATE) ; 00614 } 00615 00616 00617 /** Software Reset SC16IS750 device. 00618 * This method is specific to the SPI-I2C UART and not found on the 16750 00619 * Note: The SC16IS752 does not have separate Reset for Channel_A and Channel_B. 00620 * @param none 00621 * @return none 00622 */ 00623 void SC16IS750::swReset() { 00624 this->writeRegister(IOCTRL, IOC_SW_RST); 00625 } 00626 00627 00628 // 00629 // End Abstract Class Implementation 00630 // 00631 00632 00633 00634 // 00635 // Begin SPI Class Implementation 00636 // 00637 00638 00639 /** Create an SC16IS750_SPI object using a specified SPI bus and CS 00640 * 00641 * @param SPI &spi the SPI port to connect to 00642 * @param cs Pinname of the CS pin (active low) 00643 * @param rst Pinname for Reset pin (active low) Optional, Default = NC 00644 */ 00645 SC16IS750_SPI::SC16IS750_SPI (SPI *spi, PinName cs, PinName rst) : _spi(spi), _cs(cs) { 00646 _cs = 1; // deselect 00647 00648 _spi->format(8, 0); 00649 _spi->frequency(1000000); 00650 00651 // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. 00652 if (rst != NC) { 00653 _reset = new DigitalOut(rst); //Construct new pin 00654 _reset->write(1); //Deactivate 00655 } 00656 else { 00657 // No Hardware Reset pin 00658 _reset = NULL; //Construct dummy pin 00659 } 00660 00661 00662 // Dont call _init() until SPI port has been configured. 00663 // That is why _init() is not called in parent Constructor 00664 _init(); 00665 00666 }; 00667 00668 00669 /** Destruct SC16IS750_SPI bridge object 00670 * 00671 * @param none 00672 * @return none 00673 */ 00674 SC16IS750_SPI::~SC16IS750_SPI() { 00675 if (_reset != NULL) {delete _reset;} // Reset pin 00676 } 00677 00678 /** Write value to internal register. 00679 * Pure virtual, must be declared in derived class. 00680 * @param registerAddress The address of the Register (enum RegisterName) 00681 * @param data The 8bit value to write 00682 * @return none 00683 */ 00684 void SC16IS750_SPI::writeRegister(RegisterName registerAddress, char data) { 00685 00686 _cs = 0; // select; 00687 _spi->write(registerAddress); 00688 _spi->write(data); 00689 _cs = 1; // deselect; 00690 00691 } 00692 00693 00694 /** Read value from internal register. 00695 * @param registerAddress The address of the Register (enum RegisterName) 00696 * @return char The 8bit value read from the register 00697 */ 00698 char SC16IS750_SPI::readRegister(RegisterName registerAddress) { 00699 00700 // Used in SPI read operations to flush slave's shift register 00701 const char SPI_DUMMY_CHAR = 0xFF; 00702 00703 char result; 00704 00705 _cs = 0; // select; 00706 _spi->write(SPI_READ_MODE_FLAG | registerAddress); 00707 result = _spi->write(SPI_DUMMY_CHAR); 00708 _cs = 1; // deselect; 00709 00710 return result; 00711 } 00712 00713 00714 /** Write multiple datavalues to Transmitregister. 00715 * More Efficient implementation than writing individual bytes 00716 * Assume that previous check confirmed that the FIFO has sufficient free space to store the data 00717 * Pure virtual, must be declared in derived class. 00718 * @param char* databytes The pointer to the block of data 00719 * @param len The number of bytes to write 00720 * @return none 00721 */ 00722 void SC16IS750_SPI::writeDataBlock (const char *data, int len) { 00723 int i; 00724 00725 _cs = 0; // select; 00726 00727 // Select the Transmit Holding Register 00728 // Assume that previous check confirmed that the FIFO has sufficient free space to store the data 00729 _spi->write(THR); 00730 00731 for (i=0; i<len; i++, data++) 00732 _spi->write(*data); 00733 00734 _cs = 1; // deselect; 00735 } 00736 00737 00738 /** Hardware Reset SC16IS750 device. 00739 * This method is only available when the Reset pin has been declared and is also connected 00740 * @param none 00741 * @return none 00742 */ 00743 void SC16IS750_SPI::hwReset() { 00744 00745 if (_reset != NULL){ 00746 _reset->write(0); //activate 00747 // wait_ms(100); 00748 wait_ms(1000); //test only 00749 _reset->write(1); //deactivate 00750 } 00751 else { 00752 printf("Hardware Reset pin is not available...\n\r"); 00753 } 00754 00755 } 00756 00757 // 00758 // End SPI Implementation 00759 // 00760 00761 00762 00763 // 00764 // Begin I2C Implementation 00765 // 00766 00767 /** Create a SC16IS750_I2C object for a bridge between I2C and a Serial port 00768 * 00769 * @param I2C &i2c the I2C port to connect to 00770 * @param char deviceAddress the I2C slave address of the SC16IS750 00771 * @param rst Pinname for Reset pin (active low) Optional, Default = NC 00772 * 00773 */ 00774 SC16IS750_I2C::SC16IS750_I2C(I2C *i2c, uint8_t deviceAddress, PinName rst) : _i2c(i2c), _slaveAddress(deviceAddress & 0xFE) { 00775 00776 // _i2c->frequency(400000); 00777 _i2c->frequency(100000); 00778 00779 // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. 00780 if (rst != NC) { 00781 _reset = new DigitalOut(rst); //Construct new pin 00782 _reset->write(1); //Deactivate 00783 } 00784 else { 00785 // No Hardware Reset pin 00786 _reset = NULL; //Construct dummy pin 00787 } 00788 00789 // Dont call _init() until I2C port has been configured. 00790 // That is why _init() is not called in parent Constructor 00791 _init(); 00792 } 00793 00794 00795 /** Destruct SC16IS750_I2C bridge object 00796 * 00797 * @param none 00798 * @return none 00799 */ 00800 SC16IS750_I2C::~SC16IS750_I2C() { 00801 if (_reset != NULL) {delete _reset;} // Reset pin 00802 } 00803 00804 00805 /** Write value to internal register. 00806 * @param registerAddress The address of the Register (enum RegisterName) 00807 * @param data The 8bit value to write 00808 * @return none 00809 */ 00810 void SC16IS750_I2C::writeRegister(RegisterName registerAddress, char data) { 00811 char w[2]; 00812 00813 w[0] = registerAddress; 00814 w[1] = data; 00815 00816 _i2c->write( _slaveAddress, w, 2 ); 00817 } 00818 00819 00820 /** Read value from internal register. 00821 * @param registerAddress The address of the Register (enum RegisterName) 00822 * @return char The 8bit value read from the register 00823 */ 00824 char SC16IS750_I2C::readRegister(RegisterName registerAddress) { 00825 /* 00826 * Read char from SC16IS750 register at <registerAddress>. 00827 */ 00828 char w[1]; 00829 char r[1]; 00830 00831 w[0] = registerAddress; 00832 00833 // _i2c->write( _slaveAddress, w, 1 ); 00834 _i2c->write(_slaveAddress, w, 1, true); //Repeated Start 00835 _i2c->read( _slaveAddress, r, 1 ); 00836 00837 return ( r[0] ); 00838 } 00839 00840 00841 /** Write multiple datavalues to Transmitregister. 00842 * More Efficient implementation than writing individual bytes 00843 * Assume that previous check confirmed that the FIFO has sufficient free space to store the data 00844 * Pure virtual, must be declared in derived class. 00845 * @param char* databytes The pointer to the block of data 00846 * @param len The number of bytes to write 00847 * @return none 00848 */ 00849 void SC16IS750_I2C::writeDataBlock (const char *data, int len) { 00850 00851 #if(0) 00852 int i; 00853 char w[BULK_BLOCK_LEN]; 00854 00855 // Select the Transmit Holding Register 00856 // Assume that previous check confirmed that the FIFO has sufficient free space to store the data 00857 w[0] = THR; 00858 00859 // copy the data.. 00860 for (i=0; i<len; i++) 00861 w[i+1] = data[i]; 00862 00863 _i2c->write( _slaveAddress, w, len + 1); 00864 #else 00865 int i; 00866 00867 _i2c->start(); 00868 _i2c->write(_slaveAddress); 00869 00870 // Select the Transmit Holding Register 00871 // Assume that previous check confirmed that the FIFO has sufficient free space to store the data 00872 _i2c->write(THR); 00873 00874 // send the data.. 00875 for (i=0; i<len; i++) 00876 _i2c->write(data[i]); 00877 00878 _i2c->stop(); 00879 #endif 00880 } 00881 00882 00883 /** Hardware Reset SC16IS750 device. 00884 * This method is only available when the Reset pin has been declared and is also connected 00885 * @param none 00886 * @return none 00887 */ 00888 void SC16IS750_I2C::hwReset() { 00889 00890 if (_reset != NULL){ 00891 _reset->write(0); //activate 00892 // wait_ms(100); 00893 wait_ms(1000); //test only 00894 _reset->write(1); //deactivate 00895 } 00896 else { 00897 printf("Hardware Reset pin is not available...\n\r"); 00898 } 00899 } 00900 00901 00902 // 00903 // End I2C Implementation 00904 // 00905 00906 00907 00908 // 00909 // Begin SPI Class Implementation for 16SCIS752 dual UART 00910 // 00911 00912 00913 /** Create an SC16IS752_SPI object using a specified SPI bus and CS 00914 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. 00915 * Note: The SC16IS752 does not have separate Reset for Channel_A and Channel_B. 00916 * 00917 * @param SPI &spi the SPI port to connect to 00918 * @param cs Pinname of the CS pin (active low) 00919 * @param rst Pinname for Reset pin (active low) Optional, Default = NC 00920 * @param channel UART ChannelName, Default = Channel_A 00921 */ 00922 SC16IS752_SPI::SC16IS752_SPI (SPI *spi, PinName cs, PinName rst, ChannelName channel) : _spi(spi), _cs(cs), _channel(channel) { 00923 _cs = 1; // deselect 00924 00925 _spi->format(8, 0); 00926 _spi->frequency(1000000); 00927 00928 // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. 00929 if (rst != NC) { 00930 _reset = new DigitalOut(rst); //Construct new pin 00931 _reset->write(1); //Deactivate 00932 } 00933 else { 00934 // No Hardware Reset pin 00935 _reset = NULL; //Construct dummy pin 00936 } 00937 00938 00939 // Dont call _init() until SPI port has been configured. 00940 // That is why _init() is not called in parent Constructor 00941 _init(); 00942 00943 }; 00944 00945 00946 /** Destruct SC16IS750_SPI bridge object 00947 * 00948 * @param none 00949 * @return none 00950 */ 00951 SC16IS752_SPI::~SC16IS752_SPI() { 00952 if (_reset != NULL) {delete _reset;} // Reset pin 00953 } 00954 00955 00956 /** Write value to internal register. 00957 * Pure virtual, must be declared in derived class. 00958 * @param registerAddress The address of the Register (enum RegisterName) 00959 * @param data The 8bit value to write 00960 * @return none 00961 */ 00962 void SC16IS752_SPI::writeRegister(RegisterName registerAddress, char data) { 00963 00964 _cs = 0; // select; 00965 _spi->write(registerAddress | _channel); 00966 _spi->write(data); 00967 _cs = 1; // deselect; 00968 00969 } 00970 00971 00972 /** Read value from internal register. 00973 * @param registerAddress The address of the Register (enum RegisterName) 00974 * @return char The 8bit value read from the register 00975 */ 00976 char SC16IS752_SPI::readRegister(RegisterName registerAddress) { 00977 00978 // Used in SPI read operations to flush slave's shift register 00979 const char SPI_DUMMY_CHAR = 0xFF; 00980 00981 char result; 00982 00983 _cs = 0; // select; 00984 _spi->write(SPI_READ_MODE_FLAG | registerAddress | _channel); 00985 result = _spi->write(SPI_DUMMY_CHAR); 00986 _cs = 1; // deselect; 00987 00988 return result; 00989 } 00990 00991 00992 /** Write multiple datavalues to Transmitregister. 00993 * More Efficient implementation than writing individual bytes 00994 * Assume that previous check confirmed that the FIFO has sufficient free space to store the data 00995 * Pure virtual, must be declared in derived class. 00996 * @param char* databytes The pointer to the block of data 00997 * @param len The number of bytes to write 00998 * @return none 00999 */ 01000 void SC16IS752_SPI::writeDataBlock (const char *data, int len) { 01001 int i; 01002 01003 _cs = 0; // select; 01004 01005 // Select the Transmit Holding Register 01006 // Assume that previous check confirmed that the FIFO has sufficient free space to store the data 01007 _spi->write(THR | _channel); 01008 01009 for (i=0; i<len; i++, data++) 01010 _spi->write(*data); 01011 01012 _cs = 1; // deselect; 01013 } 01014 01015 01016 /** Hardware Reset SC16IS752 device. 01017 * This method is only available when the Reset pin has been declared and is also connected 01018 * @param none 01019 * @return none 01020 */ 01021 void SC16IS752_SPI::hwReset() { 01022 01023 if (_reset != NULL){ 01024 _reset->write(0); //activate 01025 // wait_ms(100); 01026 wait_ms(1000); //test only 01027 _reset->write(1); //deactivate 01028 } 01029 else { 01030 printf("Hardware Reset pin is not available...\n\r"); 01031 } 01032 01033 } 01034 01035 // 01036 // End SPI Implementation 01037 // 01038 01039 01040 01041 // 01042 // Begin I2C Implementation for 16SCIS752 dual UART 01043 // 01044 01045 /** Create a SC16IS752_I2C object for a bridge between I2C and a Serial port 01046 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. 01047 * Note: The SC16IS752 does not have separate Reset for Channel_A and Channel_B. 01048 * 01049 * @param I2C &i2c the I2C port to connect to 01050 * @param char deviceAddress the I2C slave address of the SC16IS750 01051 * @param rst Pinname for Reset pin (active low) Optional, Default = NC 01052 * @param channel UART Channel, Default = Channel_A 01053 */ 01054 SC16IS752_I2C::SC16IS752_I2C(I2C *i2c, uint8_t deviceAddress, PinName rst, ChannelName channel) : _i2c(i2c), _slaveAddress(deviceAddress & 0xFE), _channel(channel) { 01055 01056 // _i2c->frequency(400000); 01057 _i2c->frequency(100000); 01058 01059 // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. 01060 if (rst != NC) { 01061 _reset = new DigitalOut(rst); //Construct new pin 01062 _reset->write(1); //Deactivate 01063 } 01064 else { 01065 // No Hardware Reset pin 01066 _reset = NULL; //Construct dummy pin 01067 } 01068 01069 // Dont call _init() until I2C port has been configured. 01070 // That is why _init() is not called in parent Constructor 01071 _init(); 01072 } 01073 01074 01075 /** Destruct SC16IS752_I2C bridge object 01076 * 01077 * @param none 01078 * @return none 01079 */ 01080 SC16IS752_I2C::~SC16IS752_I2C() { 01081 if (_reset != NULL) {delete _reset;} // Reset pin 01082 } 01083 01084 01085 /** Write value to internal register. 01086 * @param registerAddress The address of the Register (enum RegisterName) 01087 * @param data The 8bit value to write 01088 * @return none 01089 */ 01090 void SC16IS752_I2C::writeRegister(RegisterName registerAddress, char data) { 01091 char w[2]; 01092 01093 w[0] = registerAddress | _channel; 01094 w[1] = data; 01095 01096 _i2c->write( _slaveAddress, w, 2 ); 01097 } 01098 01099 01100 /** Read value from internal register. 01101 * @param registerAddress The address of the Register (enum RegisterName) 01102 * @return char The 8bit value read from the register 01103 */ 01104 char SC16IS752_I2C::readRegister(RegisterName registerAddress) { 01105 /* 01106 * Read char from SC16IS752 register at <registerAddress>. 01107 */ 01108 char w[1]; 01109 char r[1]; 01110 01111 w[0] = registerAddress | _channel; 01112 01113 // _i2c->write( _slaveAddress, w, 1 ); 01114 _i2c->write(_slaveAddress, w, 1, true); //Repeated Start 01115 _i2c->read(_slaveAddress, r, 1 ); 01116 01117 return ( r[0] ); 01118 } 01119 01120 01121 /** Write multiple datavalues to Transmitregister. 01122 * More Efficient implementation than writing individual bytes 01123 * Assume that previous check confirmed that the FIFO has sufficient free space to store the data 01124 * Pure virtual, must be declared in derived class. 01125 * @param char* databytes The pointer to the block of data 01126 * @param len The number of bytes to write 01127 * @return none 01128 */ 01129 void SC16IS752_I2C::writeDataBlock (const char *data, int len) { 01130 01131 #if(0) 01132 int i; 01133 char w[BULK_BLOCK_LEN]; 01134 01135 // Select the Transmit Holding Register 01136 // Assume that previous check confirmed that the FIFO has sufficient free space to store the data 01137 w[0] = THR | _channel; 01138 01139 // copy the data.. 01140 for (i=0; i<len; i++) 01141 w[i+1] = data[i]; 01142 01143 _i2c->write( _slaveAddress, w, len + 1); 01144 #else 01145 int i; 01146 01147 _i2c->start(); 01148 _i2c->write(_slaveAddress); 01149 01150 // Select the Transmit Holding Register 01151 // Assume that previous check confirmed that the FIFO has sufficient free space to store the data 01152 _i2c->write(THR | _channel); 01153 01154 // send the data.. 01155 for (i=0; i<len; i++) 01156 _i2c->write(data[i]); 01157 01158 _i2c->stop(); 01159 #endif 01160 } 01161 01162 01163 /** Hardware Reset SC16IS752 device. 01164 * This method is only available when the Reset pin has been declared and is also connected 01165 * @param none 01166 * @return none 01167 */ 01168 void SC16IS752_I2C::hwReset() { 01169 01170 if (_reset != NULL){ 01171 _reset->write(0); //activate 01172 // wait_ms(100); 01173 wait_ms(1000); //test only 01174 _reset->write(1); //deactivate 01175 } 01176 else { 01177 printf("Hardware Reset pin is not available...\n\r"); 01178 } 01179 } 01180 01181 01182 // 01183 // End I2C Implementation 01184 // 01185 01186 01187
Generated on Wed Jul 13 2022 00:35:37 by 1.7.2