SPI or I2C to UART Bridge

Dependents:   SC16IS750_Test mbed_SC16IS750 Xadow_SC16IS750_Test Xadow_MPU9150AHRS

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SC16IS750.cpp Source File

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