SPI or I2C to UART Bridge

Dependents:   SC16IS750_Test mbed_SC16IS750 Xadow_SC16IS750_Test Xadow_MPU9150AHRS

Revision:
3:9783b6bde958
Parent:
2:76cb93b511f2
Child:
4:12446ee9f9c8
--- a/SC16IS750.cpp	Thu Feb 13 17:12:02 2014 +0000
+++ b/SC16IS750.cpp	Thu Feb 20 19:37:55 2014 +0000
@@ -1,5 +1,6 @@
-/* SC16IS750 interface 
- *   v0.1 WH, Nov 2013, Sparkfun Libs used as example. Added I2C I/F and many more methods. 
+/* SC16IS750 I2C or SPI to UART bridge 
+ *   v0.1 WH, Nov 2013, Sparkfun WiFly Shield code library alpha 0 used as example, Added I2C I/F and many more methods.
+ *                      https://forum.sparkfun.com/viewtopic.php?f=13&t=21846
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  * and associated documentation files (the "Software"), to deal in the Software without restriction,
@@ -19,7 +20,8 @@
 #include    "mbed.h"
 #include    "SC16IS750.h"
 
-#define ENABLE_BULK_TRANSFERS          0x01
+#define ENABLE_BULK_TRANSFERS             1
+#define BULK_BLOCK_LEN                   16
 
 /** Abstract class SC16IS750 for converter between either SPI or I2C and a Serial port
   * Constructor for this Abstract Class is protected  
@@ -29,8 +31,9 @@
   *
   * @endcode
   */
-//SC16IS750::SC16IS750() : Serial(NC, NC) {   //Fout ???
-SC16IS750::SC16IS750() {  
+SC16IS750::SC16IS750() { 
+//SC16IS750::SC16IS750() : Serial(NC, NC) {   //Fout, mag geen NC zijn
+//SC16IS750::SC16IS750() : SerialBase(NC, NC) { //Fout, mag geen NC zijn
 // Dont call _init() here since the SPI or I2C port have not yet been configured...
   //_init();  // initialise UART registers
 }
@@ -140,7 +143,7 @@
 /** Set the flow control type on the serial port
   *  Added for compatibility with Serial Class.
   *  SC16IS750 supports only Flow, Pins can not be selected.
-  *  This method sets only hardware flow control. SC16IS750 supports XON/XOFF, but this is not implemented.  
+  *  This method sets hardware flow control. SC16IS750 supports XON/XOFF, but this is not implemented.  
   *
   *  @param type the flow control type (Disabled, RTS, CTS, RTSCTS)     
   *  @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS) - NOT USED
@@ -177,7 +180,7 @@
 }  
 
 /** Set the RX FIFO flow control levels
-  *  This method sets only hardware flow control levels. SC16IS750 supports XON/XOFF, but this is not implemented.
+  *  This method sets hardware flow control levels. SC16IS750 supports XON/XOFF, but this is not implemented.
   *  Should be called BEFORE Auto RTS is enabled.  
   *
   *  @param resume trigger level to resume transmission (0..15, meaning 0-60 with a granularity of 4)     
@@ -245,7 +248,7 @@
   set_flow_control(); 
   
 
-  // FIFO control, sets TX and RX trigger levels and enables FIFO and save in _config
+  // FIFO control, sets TX and RX IRQ trigger levels and enables FIFO and save in _config
   // Note FCR[5:4] only accessible when EFR[4] is set (enhanced functions enable)
   // FCR, TLR
   set_fifo_control();
@@ -325,7 +328,7 @@
   // FCR is Write Only, use saved _config
 
   // reset TXFIFO, reset RXFIFO, non FIFO mode  
-  this->writeRegister(FCR, FCR_TXFIFO_RST | FCR_RXFIFO_RST);
+  this->writeRegister(FCR, FCR_TX_FIFO_RST | FCR_RX_FIFO_RST);
   
   if (_config.fifoenable)
     // enable FIFO mode and set FIFO control values  
@@ -439,6 +442,7 @@
   return this->readRegister(RHR);
 }
 
+
 /**
   * Write char to UART Bridge. Blocking when no free space in FIFO
   *   @param value char to be written    
@@ -455,16 +459,15 @@
   return value;
 }
 
+
 /**
   * Write char string to UART Bridge. Blocking when no free space in FIFO
   *   @param *str char string to be written    
   *   @return none  
   */
-void SC16IS750::write(const char *str) {
+void SC16IS750::writeString(const char *str) {
 
 #if ENABLE_BULK_TRANSFERS
-
-  #define BULK_BLOCK_LEN  16
   int len, idx;
   
   len = strlen(str);  
@@ -477,16 +480,22 @@
     };  
   
     // Write a block of BULK_BLOCK_LEN bytes
-    // Note: can be optimized by writing registeraddress once and then repeatedsly write the bytes.
+#if (0)    
+    // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes.
     for (idx=0; idx<BULK_BLOCK_LEN; idx++) {
       this->writeRegister(THR, str[idx]);
     };
-        
+#else
+    // optimized
+    this->writeDataBlock(str, BULK_BLOCK_LEN);    
+#endif
+              
     len -= BULK_BLOCK_LEN;
     str += BULK_BLOCK_LEN;
   }
   
   // Write remaining bytes 
+  // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes.  
   for (idx=0; idx<len; idx++) {
     while (this->readRegister(TXLVL) == 0) {
       // Wait for space in TX buffer
@@ -497,6 +506,7 @@
 
 
 #else
+  // Single writes instead of bulktransfer
   int len, idx;
   
   len = strlen(str);
@@ -511,6 +521,66 @@
 }
 
 
+/**
+  * Write byte array to UART Bridge. Blocking when no free space in FIFO
+  *   @param *data byte array to be written    
+  *   @param len   number of bytes to write  
+  *   @return none  
+  */
+void SC16IS750::writeBytes(const char *data, int len) {
+
+#if ENABLE_BULK_TRANSFERS
+  int idx;
+  
+  // Write blocks of BULK_BLOCK_LEN  
+  while (len > BULK_BLOCK_LEN) {
+    while(this->readRegister(TXLVL) < BULK_BLOCK_LEN) {
+      // Wait for space in TX buffer
+      wait_us(10);
+    };  
+  
+    // Write a block of BULK_BLOCK_LEN bytes
+#if (0)    
+    // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes.
+    for (idx=0; idx<BULK_BLOCK_LEN; idx++) {
+      this->writeRegister(THR, data[idx]);
+    };
+#else
+    // optimized
+    this->writeDataBlock(data, BULK_BLOCK_LEN);    
+#endif
+              
+    len  -= BULK_BLOCK_LEN;
+    data += BULK_BLOCK_LEN;
+  }
+  
+  // Write remaining bytes 
+  // Note: can be optimized by writing registeraddress once and then repeatedly write the bytes.  
+  for (idx=0; idx<len; idx++) {
+    while (this->readRegister(TXLVL) == 0) {
+      // Wait for space in TX buffer
+      wait_us(10);
+    };
+    this->writeRegister(THR, data[idx]);
+  }  
+
+
+#else
+  // Single writes instead of bulktransfer
+  int idx;
+  
+  for (idx=0; idx<len; idx++) {
+    while (this->readRegister(TXLVL) == 0) {
+      // Wait for space in TX buffer
+      wait_us(10);
+    };
+    this->writeRegister(THR, str[idx]);
+  }  
+#endif  
+}
+
+
+
 
 /** Set direction of I/O port pins.
   * This method is specific to the SPI-I2C UART and not found on the 16750
@@ -589,14 +659,7 @@
   _spi->write(data);
   _cs = 1; //  deselect;
 
-#if(0)  
-//Test only  
-  DigitalOut myled2(LED_GREEN);  
-  myled2 = 0; //LED On
-  wait(0.2);
-  myled2 = 1; //LED Off
-  wait(0.6);  
-#endif  
+
 }
 
 
@@ -619,6 +682,30 @@
   return result;  
 }
 
+
+/** Write multiple datavalues to Transmitregister.
+  * More Efficient implementation than writing individual bytes
+  * Assume that previous check confirmed that the FIFO has sufficient free space to store the data  
+  * Pure virtual, must be declared in derived class.   
+  *   @param char* databytes   The pointer to the block of data
+  *   @param len               The number of bytes to write
+  *   @return none 
+  */
+void SC16IS750_SPI::writeDataBlock (const char *data, int len) {
+  int i;
+  
+  _cs = 0; //  select;
+  
+  // Select the Transmit Holding Register
+  // Assume that previous check confirmed that the FIFO has sufficient free space to store the data
+  _spi->write(THR);
+  
+  for (i=0; i<len; i++, data++)
+    _spi->write(*data);
+    
+  _cs = 1; //  deselect;
+}
+
 //
 // End SPI Implementation
 //
@@ -631,7 +718,7 @@
   * @endcode
   *
   */
-SC16IS750_I2C::SC16IS750_I2C(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c), _slaveAddress(deviceAddress) {
+SC16IS750_I2C::SC16IS750_I2C(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c), _slaveAddress(deviceAddress & 0xFE) {
 
   _i2c->frequency(400000);
 
@@ -676,6 +763,48 @@
 }
 
 
+/** Write multiple datavalues to Transmitregister.
+  * More Efficient implementation than writing individual bytes
+  * Assume that previous check confirmed that the FIFO has sufficient free space to store the data
+  * Pure virtual, must be declared in derived class.   
+  *   @param char* databytes   The pointer to the block of data
+  *   @param len               The number of bytes to write
+  *   @return none 
+  */
+void SC16IS750_I2C::writeDataBlock (const char *data, int len) {
+  
+#if(0)  
+  int i;
+  char w[BULK_BLOCK_LEN];
+  
+  // Select the Transmit Holding Register
+  // Assume that previous check confirmed that the FIFO has sufficient free space to store the data
+  w[0] = THR;
+
+  // copy the data..
+  for (i=0; i<len; i++)
+    w[i+1] = data[i];
+    
+  _i2c->write( _slaveAddress, w, len + 1);  
+#else
+  int i;
+  
+  _i2c->start();
+  _i2c->write(_slaveAddress); 
+
+  // Select the Transmit Holding Register
+  // Assume that previous check confirmed that the FIFO has sufficient free space to store the data
+  _i2c->write(THR);
+
+  // send the data..
+  for (i=0; i<len; i++)
+    _i2c->write(data[i]);
+    
+  _i2c->stop();  
+#endif
+}
+
+
 //
 // End I2C Implementation
 //
\ No newline at end of file