RETRO ROBOT E

Dependents:   RETRO_ROBOT_SC16IS750E

Fork of SC16IS750 by Wim Huiskamp

Committer:
wim
Date:
Thu Feb 13 17:12:02 2014 +0000
Revision:
2:76cb93b511f2
Parent:
1:0440152c5387
Child:
3:9783b6bde958
Testversion 2

Who changed what in which revision?

UserRevisionLine numberNew contents of line
wim 0:d64854a60f95 1 /* SC16IS750 interface
wim 2:76cb93b511f2 2 * v0.1 WH, Nov 2013, Sparkfun Libs used as example. Added I2C I/F and many more methods.
wim 0:d64854a60f95 3 *
wim 0:d64854a60f95 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
wim 0:d64854a60f95 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
wim 0:d64854a60f95 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
wim 0:d64854a60f95 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
wim 0:d64854a60f95 8 * furnished to do so, subject to the following conditions:
wim 0:d64854a60f95 9 *
wim 0:d64854a60f95 10 * The above copyright notice and this permission notice shall be included in all copies or
wim 0:d64854a60f95 11 * substantial portions of the Software.
wim 0:d64854a60f95 12 *
wim 0:d64854a60f95 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
wim 0:d64854a60f95 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
wim 0:d64854a60f95 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
wim 0:d64854a60f95 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
wim 0:d64854a60f95 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
wim 0:d64854a60f95 18 */
wim 0:d64854a60f95 19 #include "mbed.h"
wim 0:d64854a60f95 20 #include "SC16IS750.h"
wim 0:d64854a60f95 21
wim 2:76cb93b511f2 22 #define ENABLE_BULK_TRANSFERS 0x01
wim 0:d64854a60f95 23
wim 0:d64854a60f95 24 /** Abstract class SC16IS750 for converter between either SPI or I2C and a Serial port
wim 1:0440152c5387 25 * Constructor for this Abstract Class is protected
wim 0:d64854a60f95 26 * Supports both SPI and I2C interfaces through derived classes
wim 0:d64854a60f95 27 *
wim 0:d64854a60f95 28 * @code
wim 0:d64854a60f95 29 *
wim 0:d64854a60f95 30 * @endcode
wim 0:d64854a60f95 31 */
wim 0:d64854a60f95 32 //SC16IS750::SC16IS750() : Serial(NC, NC) { //Fout ???
wim 0:d64854a60f95 33 SC16IS750::SC16IS750() {
wim 1:0440152c5387 34 // Dont call _init() here since the SPI or I2C port have not yet been configured...
wim 1:0440152c5387 35 //_init(); // initialise UART registers
wim 0:d64854a60f95 36 }
wim 0:d64854a60f95 37
wim 0:d64854a60f95 38
wim 0:d64854a60f95 39 /** Set baudrate of the serial port.
wim 0:d64854a60f95 40 * @param baud integer baudrate (4800, 9600 etc)
wim 0:d64854a60f95 41 * @return none
wim 0:d64854a60f95 42 */
wim 0:d64854a60f95 43 void SC16IS750::baud(int baudrate) {
wim 2:76cb93b511f2 44 unsigned long divisor = SC16IS750_BAUDRATE_DIVISOR(baudrate);
wim 0:d64854a60f95 45 char lcr_tmp;
wim 0:d64854a60f95 46
wim 0:d64854a60f95 47 _config.baudrate = baudrate; // Save baudrate
wim 0:d64854a60f95 48
wim 0:d64854a60f95 49 lcr_tmp = this->readRegister(LCR); // Read current LCR register
wim 1:0440152c5387 50 this->writeRegister(LCR, lcr_tmp | LCR_ENABLE_DIV); // Enable Divisor registers
wim 0:d64854a60f95 51 this->writeRegister(DLL, ( divisor & 0xFF)); // write divisor LSB
wim 0:d64854a60f95 52 this->writeRegister(DLH, ((divisor >> 8) & 0xFF)); // write divisor MSB
wim 0:d64854a60f95 53 this->writeRegister(LCR, lcr_tmp); // Restore LCR register, activate regular RBR, THR and IER registers
wim 1:0440152c5387 54
wim 0:d64854a60f95 55 }
wim 0:d64854a60f95 56
wim 0:d64854a60f95 57
wim 0:d64854a60f95 58 /** Set the transmission format used by the serial port.
wim 0:d64854a60f95 59 * @param bits The number of bits in a word (5-8; default = 8)
wim 0:d64854a60f95 60 * @param parity The parity used (Serial::None, Serial::Odd, Serial::Even, Serial::Forced1, Serial::Forced0; default = Serial::None)
wim 0:d64854a60f95 61 * @param stop_bits The number of stop bits (1 or 2; default = 1)
wim 2:76cb93b511f2 62 * @return none
wim 0:d64854a60f95 63 */
wim 0:d64854a60f95 64 void SC16IS750::format(int bits, Serial::Parity parity, int stop_bits) {
wim 0:d64854a60f95 65 char lcr_tmp = 0x00;
wim 0:d64854a60f95 66
wim 0:d64854a60f95 67 switch (bits) {
wim 0:d64854a60f95 68 case 5: lcr_tmp |= LCR_BITS5;
wim 0:d64854a60f95 69 break;
wim 0:d64854a60f95 70 case 6: lcr_tmp |= LCR_BITS6;
wim 0:d64854a60f95 71 break;
wim 0:d64854a60f95 72 case 7: lcr_tmp |= LCR_BITS7;
wim 0:d64854a60f95 73 break;
wim 0:d64854a60f95 74 case 8: lcr_tmp |= LCR_BITS8;
wim 0:d64854a60f95 75 break;
wim 0:d64854a60f95 76 default: lcr_tmp |= LCR_BITS8;
wim 0:d64854a60f95 77 }
wim 0:d64854a60f95 78
wim 0:d64854a60f95 79 switch (parity) {
wim 0:d64854a60f95 80 case Serial::None: lcr_tmp |= LCR_NONE;
wim 0:d64854a60f95 81 break;
wim 0:d64854a60f95 82 case Serial::Odd: lcr_tmp |= LCR_ODD;
wim 0:d64854a60f95 83 break;
wim 0:d64854a60f95 84 case Serial::Even: lcr_tmp |= LCR_EVEN;
wim 0:d64854a60f95 85 break;
wim 0:d64854a60f95 86 case Serial::Forced1: lcr_tmp |= LCR_FORCED1;
wim 0:d64854a60f95 87 break;
wim 0:d64854a60f95 88 case Serial::Forced0: lcr_tmp |= LCR_FORCED0;
wim 0:d64854a60f95 89 break;
wim 0:d64854a60f95 90 default: lcr_tmp |= LCR_NONE;
wim 0:d64854a60f95 91 }
wim 0:d64854a60f95 92
wim 0:d64854a60f95 93 switch (stop_bits) {
wim 0:d64854a60f95 94 case 1: lcr_tmp |= LCR_BITS1;
wim 0:d64854a60f95 95 break;
wim 0:d64854a60f95 96 case 2: lcr_tmp |= LCR_BITS2;
wim 0:d64854a60f95 97 break;
wim 0:d64854a60f95 98 default: lcr_tmp |= LCR_BITS1;
wim 0:d64854a60f95 99 }
wim 0:d64854a60f95 100
wim 0:d64854a60f95 101 _config.dataformat = lcr_tmp; // Save dataformat
wim 0:d64854a60f95 102
wim 0:d64854a60f95 103 this->writeRegister(LCR, lcr_tmp); // Set LCR register, activate regular RBR, THR and IER registers
wim 0:d64854a60f95 104
wim 0:d64854a60f95 105 };
wim 0:d64854a60f95 106
wim 1:0440152c5387 107 /** Generate a break condition on the serial line
wim 2:76cb93b511f2 108 * @return none
wim 1:0440152c5387 109 */
wim 1:0440152c5387 110 void SC16IS750::send_break() {
wim 1:0440152c5387 111 // Wait for 1.5 frames before clearing the break condition
wim 1:0440152c5387 112 // This will have different effects on our platforms, but should
wim 1:0440152c5387 113 // ensure that we keep the break active for at least one frame.
wim 1:0440152c5387 114 // We consider a full frame (1 start bit + 8 data bits bits +
wim 1:0440152c5387 115 // 1 parity bit + 2 stop bits = 12 bits) for computation.
wim 1:0440152c5387 116 // One bit time (in us) = 1000000/_baud
wim 1:0440152c5387 117 // Twelve bits: 12000000/baud delay
wim 1:0440152c5387 118 // 1.5 frames: 18000000/baud delay
wim 1:0440152c5387 119 set_break(true);
wim 1:0440152c5387 120 wait_us(18000000/_config.baudrate);
wim 1:0440152c5387 121 set_break(false);
wim 1:0440152c5387 122 };
wim 1:0440152c5387 123
wim 1:0440152c5387 124 /** Set a break condition on the serial line
wim 1:0440152c5387 125 * @param enable break condition
wim 2:76cb93b511f2 126 * @return none
wim 1:0440152c5387 127 */
wim 1:0440152c5387 128 void SC16IS750::set_break(bool enable) {
wim 0:d64854a60f95 129
wim 1:0440152c5387 130 if (enable) {
wim 1:0440152c5387 131 _config.dataformat |= LCR_BRK_ENA; // Save dataformat
wim 1:0440152c5387 132 }
wim 1:0440152c5387 133 else {
wim 1:0440152c5387 134 _config.dataformat &= ~LCR_BRK_ENA; // Save dataformat
wim 1:0440152c5387 135 }
wim 1:0440152c5387 136
wim 1:0440152c5387 137 this->writeRegister(LCR, _config.dataformat); // Set LCR register
wim 1:0440152c5387 138 }
wim 1:0440152c5387 139
wim 1:0440152c5387 140 /** Set the flow control type on the serial port
wim 1:0440152c5387 141 * Added for compatibility with Serial Class.
wim 1:0440152c5387 142 * SC16IS750 supports only Flow, Pins can not be selected.
wim 2:76cb93b511f2 143 * This method sets only hardware flow control. SC16IS750 supports XON/XOFF, but this is not implemented.
wim 0:d64854a60f95 144 *
wim 1:0440152c5387 145 * @param type the flow control type (Disabled, RTS, CTS, RTSCTS)
wim 2:76cb93b511f2 146 * @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS) - NOT USED
wim 2:76cb93b511f2 147 * @param flow2 the second flow control pin (CTS for RTSCTS) - NOT USED
wim 2:76cb93b511f2 148 * @return none
wim 0:d64854a60f95 149 */
wim 1:0440152c5387 150 void SC16IS750::set_flow_control(Flow type, PinName flow1, PinName flow2) {
wim 1:0440152c5387 151 char lcr_tmp;
wim 1:0440152c5387 152 char efr_tmp = 0x00;
wim 1:0440152c5387 153
wim 1:0440152c5387 154 // We need to enable flow control to prevent overflow of buffers and
wim 1:0440152c5387 155 // lose data when used with fast devices like the WiFly.
wim 1:0440152c5387 156
wim 1:0440152c5387 157 switch (type) {
wim 1:0440152c5387 158 case Disabled :
wim 1:0440152c5387 159 break;
wim 1:0440152c5387 160 case RTS: efr_tmp = EFR_ENABLE_RTS;
wim 1:0440152c5387 161 break;
wim 1:0440152c5387 162 case CTS: efr_tmp = EFR_ENABLE_CTS;
wim 1:0440152c5387 163 break;
wim 1:0440152c5387 164 case RTSCTS: efr_tmp = EFR_ENABLE_RTS | EFR_ENABLE_CTS;
wim 1:0440152c5387 165 break;
wim 1:0440152c5387 166 default: ;
wim 1:0440152c5387 167
wim 1:0440152c5387 168 }
wim 1:0440152c5387 169
wim 2:76cb93b511f2 170 //Save flowcontrol mode and enable enhanced functions
wim 2:76cb93b511f2 171 _config.flowctrl = efr_tmp | EFR_ENABLE_ENHANCED_FUNCTIONS;
wim 1:0440152c5387 172
wim 1:0440152c5387 173 lcr_tmp = this->readRegister(LCR); // save LRC register
wim 1:0440152c5387 174 this->writeRegister(LCR, LCR_ENABLE_ENHANCED_FUNCTIONS); // write magic number 0xBF to enable access to EFR register
wim 1:0440152c5387 175 this->writeRegister(EFR, _config.flowctrl); // set flow and enable enhanced functions
wim 1:0440152c5387 176 this->writeRegister(LCR, lcr_tmp); // restore LCR register
wim 1:0440152c5387 177 }
wim 2:76cb93b511f2 178
wim 2:76cb93b511f2 179 /** Set the RX FIFO flow control levels
wim 2:76cb93b511f2 180 * This method sets only hardware flow control levels. SC16IS750 supports XON/XOFF, but this is not implemented.
wim 2:76cb93b511f2 181 * Should be called BEFORE Auto RTS is enabled.
wim 2:76cb93b511f2 182 *
wim 2:76cb93b511f2 183 * @param resume trigger level to resume transmission (0..15, meaning 0-60 with a granularity of 4)
wim 2:76cb93b511f2 184 * @param halt trigger level to resume transmission (0..15, meaning 0-60 with granularity of 4)
wim 2:76cb93b511f2 185 * @return none
wim 2:76cb93b511f2 186 */
wim 2:76cb93b511f2 187 void SC16IS750::set_flow_triggers(int resume, int halt) {
wim 2:76cb93b511f2 188
wim 2:76cb93b511f2 189 // sanity checks
wim 2:76cb93b511f2 190 halt = halt & 0x0F;
wim 2:76cb93b511f2 191 resume = resume & 0x0F;
wim 2:76cb93b511f2 192 if (halt <= resume) {
wim 2:76cb93b511f2 193 halt = TCR_HALT_DEFAULT;
wim 2:76cb93b511f2 194 resume = TCR_RESUME_DEFAULT;
wim 2:76cb93b511f2 195 }
wim 2:76cb93b511f2 196
wim 2:76cb93b511f2 197 // Note: TCR accessible only when EFR[4]=1 and MCR[2]=1
wim 2:76cb93b511f2 198 this->writeRegister(TCR, (resume << 4) | halt); // set TCR register
wim 2:76cb93b511f2 199 }
wim 2:76cb93b511f2 200
wim 2:76cb93b511f2 201
wim 2:76cb93b511f2 202 /** Set the Modem Control register
wim 2:76cb93b511f2 203 * This method sets prescaler, enables TCR and TLR
wim 2:76cb93b511f2 204 *
wim 2:76cb93b511f2 205 * @param none
wim 2:76cb93b511f2 206 * @return none
wim 2:76cb93b511f2 207 */
wim 2:76cb93b511f2 208 void SC16IS750::set_modem_control() {
wim 2:76cb93b511f2 209
wim 2:76cb93b511f2 210 //Note MCR[7:4] and MCR[2] only accessible when EFR[4] is set
wim 2:76cb93b511f2 211 if (SC16IS750_PRESCALER == SC16IS750_PRESCALER_1) { // Default prescaler after reset
wim 2:76cb93b511f2 212 this->writeRegister(MCR, MCR_PRESCALE_1 | MCR_ENABLE_TCR_TLR);
wim 2:76cb93b511f2 213 }
wim 2:76cb93b511f2 214 else {
wim 2:76cb93b511f2 215 this->writeRegister(MCR, MCR_PRESCALE_4 | MCR_ENABLE_TCR_TLR);
wim 2:76cb93b511f2 216 }
wim 2:76cb93b511f2 217 }
wim 2:76cb93b511f2 218
wim 1:0440152c5387 219
wim 1:0440152c5387 220
wim 1:0440152c5387 221 /** Initialise internal registers
wim 1:0440152c5387 222 * Should be in protection section. Public for testing purposes
wim 1:0440152c5387 223 * If initialisation fails this method does not return.
wim 1:0440152c5387 224 * @param none
wim 1:0440152c5387 225 * @return none
wim 1:0440152c5387 226 */
wim 1:0440152c5387 227 void SC16IS750::_init() {
wim 0:d64854a60f95 228
wim 0:d64854a60f95 229 // Initialise SC16IS750
wim 0:d64854a60f95 230
wim 1:0440152c5387 231 // Software reset, assuming there is no access to the HW Reset pin
wim 1:0440152c5387 232 swReset();
wim 2:76cb93b511f2 233
wim 2:76cb93b511f2 234 // Set default baudrate (depends on prescaler) and save in _config
wim 2:76cb93b511f2 235 // DLL/DLH
wim 0:d64854a60f95 236 baud();
wim 0:d64854a60f95 237
wim 0:d64854a60f95 238 // Set default dataformat and save in _config
wim 1:0440152c5387 239 // LCR
wim 0:d64854a60f95 240 format();
wim 0:d64854a60f95 241
wim 2:76cb93b511f2 242 // Set dataflow mode and Enables enhanced functions
wim 2:76cb93b511f2 243 // Save in _config
wim 2:76cb93b511f2 244 // EFR
wim 2:76cb93b511f2 245 set_flow_control();
wim 2:76cb93b511f2 246
wim 2:76cb93b511f2 247
wim 2:76cb93b511f2 248 // FIFO control, sets TX and RX trigger levels and enables FIFO and save in _config
wim 2:76cb93b511f2 249 // Note FCR[5:4] only accessible when EFR[4] is set (enhanced functions enable)
wim 2:76cb93b511f2 250 // FCR, TLR
wim 2:76cb93b511f2 251 set_fifo_control();
wim 2:76cb93b511f2 252 flush();
wim 2:76cb93b511f2 253
wim 2:76cb93b511f2 254 // Modem control, sets prescaler, enable TCR and TLR
wim 2:76cb93b511f2 255 // Note MCR[7:4] and MCR[2] only accessible when EFR[4] is set (enhanced functions enable)
wim 2:76cb93b511f2 256 set_modem_control();
wim 2:76cb93b511f2 257
wim 2:76cb93b511f2 258 // Set RTS trigger levels
wim 2:76cb93b511f2 259 // Note TCR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set
wim 2:76cb93b511f2 260 set_flow_triggers();
wim 2:76cb93b511f2 261
wim 2:76cb93b511f2 262
wim 1:0440152c5387 263 // Set default break condition and save in _config
wim 1:0440152c5387 264 // LCR
wim 1:0440152c5387 265 //set_break();
wim 2:76cb93b511f2 266
wim 0:d64854a60f95 267 // The UART bridge should now be successfully initialised.
wim 0:d64854a60f95 268
wim 0:d64854a60f95 269 // Test if UART bridge is present and initialised
wim 0:d64854a60f95 270 if(!connected()){
wim 0:d64854a60f95 271 #if(0)
wim 0:d64854a60f95 272 // Lock up if we fail to initialise UART bridge.
wim 1:0440152c5387 273 while(1) {};
wim 0:d64854a60f95 274 #else
wim 0:d64854a60f95 275 printf("Failed to initialise UART bridge\r\n");
wim 1:0440152c5387 276 #endif
wim 1:0440152c5387 277 }
wim 1:0440152c5387 278 else {
wim 1:0440152c5387 279 printf("Initialised UART bridge!\r\n");
wim 1:0440152c5387 280 }
wim 1:0440152c5387 281
wim 1:0440152c5387 282 }
wim 1:0440152c5387 283
wim 2:76cb93b511f2 284
wim 2:76cb93b511f2 285 /** FIFO control, sets TX and RX trigger levels and enables FIFO and save in _config
wim 2:76cb93b511f2 286 * Note FCR[5:4] (=TX_IRQ_LVL) only accessible when EFR[4] is set (enhanced functions enable)
wim 2:76cb93b511f2 287 * Note TLR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set
wim 2:76cb93b511f2 288 * @param none
wim 2:76cb93b511f2 289 * @return none
wim 2:76cb93b511f2 290 */
wim 2:76cb93b511f2 291 void SC16IS750::set_fifo_control() {
wim 2:76cb93b511f2 292
wim 2:76cb93b511f2 293 // Set default fifoformat
wim 2:76cb93b511f2 294 // FCR
wim 2:76cb93b511f2 295 _config.fifoenable = true;
wim 2:76cb93b511f2 296
wim 2:76cb93b511f2 297 // Note FCR[5:4] (=TX_IRQ_LVL) only accessible when EFR[4] is set (enhanced functions enable)
wim 2:76cb93b511f2 298 // _config.fifoformat = FCR_RX_IRQ_8 | FCR_TX_IRQ_56;
wim 2:76cb93b511f2 299 _config.fifoformat = FCR_RX_IRQ_8 | FCR_TX_IRQ_8; //Default
wim 2:76cb93b511f2 300
wim 2:76cb93b511f2 301 if (_config.fifoenable)
wim 2:76cb93b511f2 302 // enable FIFO mode and set FIFO control values
wim 2:76cb93b511f2 303 this->writeRegister(FCR, _config.fifoformat | FCR_ENABLE_FIFO);
wim 2:76cb93b511f2 304 else
wim 2:76cb93b511f2 305 // disable FIFO mode and set FIFO control values
wim 2:76cb93b511f2 306 this->writeRegister(FCR, _config.fifoformat);
wim 2:76cb93b511f2 307
wim 2:76cb93b511f2 308 // Set Trigger level register TLR for RX and TX interrupt generation
wim 2:76cb93b511f2 309 // Note TLR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set
wim 2:76cb93b511f2 310 // TRL Trigger levels for RX and TX are 0..15, meaning 0-60 with a granularity of 4 chars
wim 2:76cb93b511f2 311 // When TLR for RX or TX are 'Zero' the corresponding values in FCR are used. The FCR settings
wim 2:76cb93b511f2 312 // have less resolution (only 4 levels) so TLR is considered an enhanced function.
wim 2:76cb93b511f2 313 this->writeRegister(TLR, 0x00); // Use FCR Levels
wim 2:76cb93b511f2 314 // this->writeRegister(TLR, (TLR_RX_DEFAULT << 4) | TLR_TX_DEFAULT); // Use Default enhanced levels
wim 2:76cb93b511f2 315
wim 2:76cb93b511f2 316 }
wim 2:76cb93b511f2 317
wim 2:76cb93b511f2 318
wim 1:0440152c5387 319 /**
wim 1:0440152c5387 320 * Flush the UART FIFOs while maintaining current FIFO mode.
wim 1:0440152c5387 321 * @param none
wim 1:0440152c5387 322 * @return none
wim 1:0440152c5387 323 */
wim 1:0440152c5387 324 void SC16IS750::flush() {
wim 2:76cb93b511f2 325 // FCR is Write Only, use saved _config
wim 1:0440152c5387 326
wim 1:0440152c5387 327 // reset TXFIFO, reset RXFIFO, non FIFO mode
wim 1:0440152c5387 328 this->writeRegister(FCR, FCR_TXFIFO_RST | FCR_RXFIFO_RST);
wim 1:0440152c5387 329
wim 1:0440152c5387 330 if (_config.fifoenable)
wim 1:0440152c5387 331 // enable FIFO mode and set FIFO control values
wim 1:0440152c5387 332 this->writeRegister(FCR, _config.fifoformat | FCR_ENABLE_FIFO);
wim 1:0440152c5387 333 else
wim 1:0440152c5387 334 // disable FIFO mode and set FIFO control values
wim 1:0440152c5387 335 this->writeRegister(FCR, _config.fifoformat);
wim 1:0440152c5387 336
wim 1:0440152c5387 337 #if(0)
wim 1:0440152c5387 338 //original
wim 1:0440152c5387 339 /*
wim 1:0440152c5387 340 * Flush characters from SC16IS750 receive buffer.
wim 1:0440152c5387 341 */
wim 1:0440152c5387 342
wim 1:0440152c5387 343 // Note: This may not be the most appropriate flush approach.
wim 1:0440152c5387 344 // It might be better to just flush the UART's buffer
wim 1:0440152c5387 345 // rather than the buffer of the connected device
wim 1:0440152c5387 346 // which is essentially what this does.
wim 1:0440152c5387 347 while(readable() > 0) {
wim 1:0440152c5387 348 getc();
wim 0:d64854a60f95 349 }
wim 0:d64854a60f95 350 #endif
wim 0:d64854a60f95 351
wim 0:d64854a60f95 352 }
wim 0:d64854a60f95 353
wim 0:d64854a60f95 354
wim 1:0440152c5387 355
wim 0:d64854a60f95 356 /**
wim 0:d64854a60f95 357 * Check that UART is connected and operational.
wim 0:d64854a60f95 358 * @param none
wim 0:d64854a60f95 359 * @return bool true when connected, false otherwise
wim 0:d64854a60f95 360 */
wim 0:d64854a60f95 361 bool SC16IS750::connected() {
wim 0:d64854a60f95 362 // Perform read/write test to check if UART is working
wim 0:d64854a60f95 363 const char TEST_CHARACTER = 'H';
wim 0:d64854a60f95 364
wim 0:d64854a60f95 365 this->writeRegister(SPR, TEST_CHARACTER);
wim 0:d64854a60f95 366
wim 0:d64854a60f95 367 return (this->readRegister(SPR) == TEST_CHARACTER);
wim 0:d64854a60f95 368 }
wim 0:d64854a60f95 369
wim 0:d64854a60f95 370
wim 0:d64854a60f95 371
wim 0:d64854a60f95 372 /** Determine if there is a character available to read.
wim 2:76cb93b511f2 373 * This is data that's already arrived and stored in the receive
wim 2:76cb93b511f2 374 * buffer (which holds 64 chars).
wim 2:76cb93b511f2 375 *
wim 0:d64854a60f95 376 * @return 1 if there is a character available to read, 0 otherwise
wim 0:d64854a60f95 377 */
wim 0:d64854a60f95 378 int SC16IS750::readable() {
wim 2:76cb93b511f2 379
wim 2:76cb93b511f2 380 // if (this->readableCount() > 0) { // Check count
wim 2:76cb93b511f2 381 if (this->readRegister(LSR) & LSR_DR) { // Data in Receiver Bit, at least one character waiting
wim 2:76cb93b511f2 382 return 1;
wim 2:76cb93b511f2 383 }
wim 2:76cb93b511f2 384 else {
wim 2:76cb93b511f2 385 return 0;
wim 2:76cb93b511f2 386 }
wim 2:76cb93b511f2 387
wim 0:d64854a60f95 388 }
wim 0:d64854a60f95 389
wim 1:0440152c5387 390 /** Determine how many characters are available to read.
wim 2:76cb93b511f2 391 * This is data that's already arrived and stored in the receive
wim 2:76cb93b511f2 392 * buffer (which holds 64 chars).
wim 2:76cb93b511f2 393 *
wim 0:d64854a60f95 394 * @return int Characters available to read
wim 0:d64854a60f95 395 */
wim 0:d64854a60f95 396 int SC16IS750::readableCount() {
wim 0:d64854a60f95 397
wim 0:d64854a60f95 398 return (this->readRegister(RXLVL));
wim 0:d64854a60f95 399 }
wim 0:d64854a60f95 400
wim 0:d64854a60f95 401 /** Determine if there is space available to write a character.
wim 0:d64854a60f95 402 * @return 1 if there is a space for a character to write, 0 otherwise
wim 0:d64854a60f95 403 */
wim 0:d64854a60f95 404 int SC16IS750::writable() {
wim 2:76cb93b511f2 405
wim 2:76cb93b511f2 406 // if ((this->writableCount() > 0) { // Check count
wim 2:76cb93b511f2 407 if (this->readRegister(LSR) & LSR_THRE) { // THR Empty, space for at least one character
wim 2:76cb93b511f2 408 return 1;
wim 2:76cb93b511f2 409 }
wim 2:76cb93b511f2 410 else {
wim 2:76cb93b511f2 411 return 0;
wim 2:76cb93b511f2 412 }
wim 0:d64854a60f95 413 }
wim 0:d64854a60f95 414
wim 1:0440152c5387 415 /** Determine how much space available for writing characters.
wim 2:76cb93b511f2 416 * This considers data that's already stored in the transmit
wim 2:76cb93b511f2 417 * buffer (which holds 64 chars).
wim 2:76cb93b511f2 418 *
wim 1:0440152c5387 419 * @return int character space available to write
wim 0:d64854a60f95 420 */
wim 0:d64854a60f95 421 int SC16IS750::writableCount() {
wim 0:d64854a60f95 422
wim 2:76cb93b511f2 423 return (this->readRegister(TXLVL)); // TX Level
wim 0:d64854a60f95 424 }
wim 0:d64854a60f95 425
wim 0:d64854a60f95 426
wim 1:0440152c5387 427 /**
wim 1:0440152c5387 428 * Read char from UART Bridge.
wim 1:0440152c5387 429 * Acts in the same manner as 'Serial.read()'.
wim 1:0440152c5387 430 * @param none
wim 1:0440152c5387 431 * @return char read or -1 if no data available.
wim 1:0440152c5387 432 */
wim 1:0440152c5387 433 int SC16IS750::getc() {
wim 0:d64854a60f95 434
wim 0:d64854a60f95 435 if (!readable()) {
wim 0:d64854a60f95 436 return -1;
wim 0:d64854a60f95 437 }
wim 0:d64854a60f95 438
wim 0:d64854a60f95 439 return this->readRegister(RHR);
wim 0:d64854a60f95 440 }
wim 0:d64854a60f95 441
wim 1:0440152c5387 442 /**
wim 1:0440152c5387 443 * Write char to UART Bridge. Blocking when no free space in FIFO
wim 1:0440152c5387 444 * @param value char to be written
wim 1:0440152c5387 445 * @return value written
wim 1:0440152c5387 446 */
wim 1:0440152c5387 447 int SC16IS750::putc(int value) {
wim 2:76cb93b511f2 448
wim 0:d64854a60f95 449 while (this->readRegister(TXLVL) == 0) {
wim 0:d64854a60f95 450 // Wait for space in TX buffer
wim 1:0440152c5387 451 wait_us(10);
wim 0:d64854a60f95 452 };
wim 0:d64854a60f95 453 this->writeRegister(THR, value);
wim 1:0440152c5387 454
wim 1:0440152c5387 455 return value;
wim 0:d64854a60f95 456 }
wim 0:d64854a60f95 457
wim 2:76cb93b511f2 458 /**
wim 2:76cb93b511f2 459 * Write char string to UART Bridge. Blocking when no free space in FIFO
wim 2:76cb93b511f2 460 * @param *str char string to be written
wim 2:76cb93b511f2 461 * @return none
wim 2:76cb93b511f2 462 */
wim 0:d64854a60f95 463 void SC16IS750::write(const char *str) {
wim 0:d64854a60f95 464
wim 0:d64854a60f95 465 #if ENABLE_BULK_TRANSFERS
wim 2:76cb93b511f2 466
wim 2:76cb93b511f2 467 #define BULK_BLOCK_LEN 16
wim 2:76cb93b511f2 468 int len, idx;
wim 0:d64854a60f95 469
wim 2:76cb93b511f2 470 len = strlen(str);
wim 0:d64854a60f95 471
wim 2:76cb93b511f2 472 // Write blocks of BULK_BLOCK_LEN
wim 2:76cb93b511f2 473 while (len > BULK_BLOCK_LEN) {
wim 2:76cb93b511f2 474 while(this->readRegister(TXLVL) < BULK_BLOCK_LEN) {
wim 2:76cb93b511f2 475 // Wait for space in TX buffer
wim 2:76cb93b511f2 476 wait_us(10);
wim 2:76cb93b511f2 477 };
wim 2:76cb93b511f2 478
wim 2:76cb93b511f2 479 // Write a block of BULK_BLOCK_LEN bytes
wim 2:76cb93b511f2 480 // Note: can be optimized by writing registeraddress once and then repeatedsly write the bytes.
wim 2:76cb93b511f2 481 for (idx=0; idx<BULK_BLOCK_LEN; idx++) {
wim 2:76cb93b511f2 482 this->writeRegister(THR, str[idx]);
wim 2:76cb93b511f2 483 };
wim 2:76cb93b511f2 484
wim 2:76cb93b511f2 485 len -= BULK_BLOCK_LEN;
wim 2:76cb93b511f2 486 str += BULK_BLOCK_LEN;
wim 0:d64854a60f95 487 }
wim 2:76cb93b511f2 488
wim 2:76cb93b511f2 489 // Write remaining bytes
wim 2:76cb93b511f2 490 for (idx=0; idx<len; idx++) {
wim 2:76cb93b511f2 491 while (this->readRegister(TXLVL) == 0) {
wim 2:76cb93b511f2 492 // Wait for space in TX buffer
wim 2:76cb93b511f2 493 wait_us(10);
wim 2:76cb93b511f2 494 };
wim 2:76cb93b511f2 495 this->writeRegister(THR, str[idx]);
wim 2:76cb93b511f2 496 }
wim 2:76cb93b511f2 497
wim 0:d64854a60f95 498
wim 2:76cb93b511f2 499 #else
wim 2:76cb93b511f2 500 int len, idx;
wim 2:76cb93b511f2 501
wim 2:76cb93b511f2 502 len = strlen(str);
wim 2:76cb93b511f2 503 for (idx=0; idx<len; idx++) {
wim 2:76cb93b511f2 504 while (this->readRegister(TXLVL) == 0) {
wim 2:76cb93b511f2 505 // Wait for space in TX buffer
wim 2:76cb93b511f2 506 wait_us(10);
wim 2:76cb93b511f2 507 };
wim 2:76cb93b511f2 508 this->writeRegister(THR, str[idx]);
wim 2:76cb93b511f2 509 }
wim 2:76cb93b511f2 510 #endif
wim 0:d64854a60f95 511 }
wim 2:76cb93b511f2 512
wim 2:76cb93b511f2 513
wim 0:d64854a60f95 514
wim 1:0440152c5387 515 /** Set direction of I/O port pins.
wim 1:0440152c5387 516 * This method is specific to the SPI-I2C UART and not found on the 16750
wim 1:0440152c5387 517 * @param bits Bitpattern for I/O (1=output, 0=input)
wim 1:0440152c5387 518 * @return none
wim 1:0440152c5387 519 */
wim 0:d64854a60f95 520 void SC16IS750::ioSetDirection(unsigned char bits) {
wim 0:d64854a60f95 521 this->writeRegister(IODIR, bits);
wim 0:d64854a60f95 522 }
wim 0:d64854a60f95 523
wim 1:0440152c5387 524 /** Set bits of I/O port pins.
wim 1:0440152c5387 525 * This method is specific to the SPI-I2C UART and not found on the 16750
wim 1:0440152c5387 526 * @param bits Bitpattern for I/O (1= set output bit, 0 = clear output bit)
wim 1:0440152c5387 527 * @return none
wim 1:0440152c5387 528 */
wim 0:d64854a60f95 529 void SC16IS750::ioSetState(unsigned char bits) {
wim 0:d64854a60f95 530 this->writeRegister(IOSTATE, bits);
wim 0:d64854a60f95 531 }
wim 0:d64854a60f95 532
wim 1:0440152c5387 533 /** Get bits of I/O port pins.
wim 1:0440152c5387 534 * This method is specific to the SPI-I2C UART and not found on the 16750
wim 1:0440152c5387 535 * @param none
wim 1:0440152c5387 536 * @return bits Bitpattern for I/O (1= bit set, 0 = bit cleared)
wim 1:0440152c5387 537 */
wim 1:0440152c5387 538 unsigned char SC16IS750::ioGetState() {
wim 1:0440152c5387 539 return this->readRegister(IOSTATE) ;
wim 1:0440152c5387 540 }
wim 0:d64854a60f95 541
wim 0:d64854a60f95 542
wim 1:0440152c5387 543 /** Software Reset SC16IS750 device.
wim 1:0440152c5387 544 * This method is specific to the SPI-I2C UART and not found on the 16750
wim 1:0440152c5387 545 * @param none
wim 1:0440152c5387 546 * @return none
wim 1:0440152c5387 547 */
wim 1:0440152c5387 548 void SC16IS750::swReset() {
wim 1:0440152c5387 549 this->writeRegister(IOCTRL, IOC_SW_RST);
wim 1:0440152c5387 550 }
wim 1:0440152c5387 551
wim 1:0440152c5387 552
wim 1:0440152c5387 553 //
wim 1:0440152c5387 554 // End Abstract Class Implementation
wim 0:d64854a60f95 555 //
wim 0:d64854a60f95 556
wim 1:0440152c5387 557
wim 1:0440152c5387 558
wim 0:d64854a60f95 559 /** Class SC16IS750_SPI for a converter between SPI and a Serial port
wim 0:d64854a60f95 560 *
wim 1:0440152c5387 561 * @code
wim 1:0440152c5387 562 *
wim 1:0440152c5387 563 * @endcode
wim 1:0440152c5387 564 *
wim 0:d64854a60f95 565 */
wim 0:d64854a60f95 566 SC16IS750_SPI::SC16IS750_SPI (SPI *spi, PinName cs) : _spi(spi), _cs(cs) {
wim 0:d64854a60f95 567 _cs = 1; // deselect
wim 0:d64854a60f95 568
wim 0:d64854a60f95 569 _spi->format(8, 0);
wim 0:d64854a60f95 570 _spi->frequency(1000000);
wim 1:0440152c5387 571 // _spi->frequency(100000); //test
wim 1:0440152c5387 572
wim 1:0440152c5387 573 // Dont call _init() until SPI port has been configured.
wim 1:0440152c5387 574 // That is why _init() is not called in parent Constructor
wim 1:0440152c5387 575 _init();
wim 1:0440152c5387 576
wim 0:d64854a60f95 577 };
wim 0:d64854a60f95 578
wim 0:d64854a60f95 579 /** Write value to internal register.
wim 0:d64854a60f95 580 * Pure virtual, must be declared in derived class.
wim 1:0440152c5387 581 * @param registerAddress The address of the Register (enum RegisterName)
wim 0:d64854a60f95 582 * @param data The 8bit value to write
wim 0:d64854a60f95 583 * @return none
wim 0:d64854a60f95 584 */
wim 0:d64854a60f95 585 void SC16IS750_SPI::writeRegister(RegisterName registerAddress, char data) {
wim 0:d64854a60f95 586
wim 0:d64854a60f95 587 _cs = 0; // select;
wim 0:d64854a60f95 588 _spi->write(registerAddress);
wim 0:d64854a60f95 589 _spi->write(data);
wim 0:d64854a60f95 590 _cs = 1; // deselect;
wim 1:0440152c5387 591
wim 1:0440152c5387 592 #if(0)
wim 0:d64854a60f95 593 //Test only
wim 0:d64854a60f95 594 DigitalOut myled2(LED_GREEN);
wim 0:d64854a60f95 595 myled2 = 0; //LED On
wim 0:d64854a60f95 596 wait(0.2);
wim 0:d64854a60f95 597 myled2 = 1; //LED Off
wim 0:d64854a60f95 598 wait(0.6);
wim 1:0440152c5387 599 #endif
wim 0:d64854a60f95 600 }
wim 0:d64854a60f95 601
wim 0:d64854a60f95 602
wim 0:d64854a60f95 603 /** Read value from internal register.
wim 1:0440152c5387 604 * @param registerAddress The address of the Register (enum RegisterName)
wim 0:d64854a60f95 605 * @return char The 8bit value read from the register
wim 0:d64854a60f95 606 */
wim 0:d64854a60f95 607 char SC16IS750_SPI::readRegister(RegisterName registerAddress) {
wim 0:d64854a60f95 608
wim 0:d64854a60f95 609 // Used in SPI read operations to flush slave's shift register
wim 1:0440152c5387 610 const char SPI_DUMMY_CHAR = 0xFF;
wim 0:d64854a60f95 611
wim 0:d64854a60f95 612 char result;
wim 0:d64854a60f95 613
wim 0:d64854a60f95 614 _cs = 0; // select;
wim 0:d64854a60f95 615 _spi->write(SPI_READ_MODE_FLAG | registerAddress);
wim 1:0440152c5387 616 result = _spi->write(SPI_DUMMY_CHAR);
wim 0:d64854a60f95 617 _cs = 1; // deselect;
wim 0:d64854a60f95 618
wim 0:d64854a60f95 619 return result;
wim 0:d64854a60f95 620 }
wim 0:d64854a60f95 621
wim 0:d64854a60f95 622 //
wim 0:d64854a60f95 623 // End SPI Implementation
wim 1:0440152c5387 624 //
wim 0:d64854a60f95 625
wim 0:d64854a60f95 626
wim 0:d64854a60f95 627 /** Class SC16IS750_I2C for a converter between I2C and a Serial port
wim 0:d64854a60f95 628 *
wim 1:0440152c5387 629 * @code
wim 1:0440152c5387 630 *
wim 1:0440152c5387 631 * @endcode
wim 1:0440152c5387 632 *
wim 0:d64854a60f95 633 */
wim 0:d64854a60f95 634 SC16IS750_I2C::SC16IS750_I2C(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c), _slaveAddress(deviceAddress) {
wim 0:d64854a60f95 635
wim 1:0440152c5387 636 _i2c->frequency(400000);
wim 0:d64854a60f95 637
wim 1:0440152c5387 638 // Dont call _init() until I2C port has been configured.
wim 1:0440152c5387 639 // That is why _init() is not called in parent Constructor
wim 1:0440152c5387 640 _init();
wim 0:d64854a60f95 641 }
wim 0:d64854a60f95 642
wim 0:d64854a60f95 643
wim 0:d64854a60f95 644 /** Write value to internal register.
wim 1:0440152c5387 645 * @param registerAddress The address of the Register (enum RegisterName)
wim 0:d64854a60f95 646 * @param data The 8bit value to write
wim 0:d64854a60f95 647 * @return none
wim 0:d64854a60f95 648 */
wim 0:d64854a60f95 649 void SC16IS750_I2C::writeRegister(RegisterName registerAddress, char data) {
wim 0:d64854a60f95 650 char w[2];
wim 0:d64854a60f95 651
wim 0:d64854a60f95 652 w[0] = registerAddress;
wim 0:d64854a60f95 653 w[1] = data;
wim 0:d64854a60f95 654
wim 0:d64854a60f95 655 _i2c->write( _slaveAddress, w, 2 );
wim 0:d64854a60f95 656 }
wim 0:d64854a60f95 657
wim 0:d64854a60f95 658
wim 0:d64854a60f95 659 /** Read value from internal register.
wim 1:0440152c5387 660 * @param registerAddress The address of the Register (enum RegisterName)
wim 0:d64854a60f95 661 * @return char The 8bit value read from the register
wim 0:d64854a60f95 662 */
wim 0:d64854a60f95 663 char SC16IS750_I2C::readRegister(RegisterName registerAddress) {
wim 0:d64854a60f95 664 /*
wim 0:d64854a60f95 665 * Read char from SC16IS750 register at <registerAddress>.
wim 0:d64854a60f95 666 */
wim 0:d64854a60f95 667 char w[1];
wim 0:d64854a60f95 668 char r[1];
wim 0:d64854a60f95 669
wim 0:d64854a60f95 670 w[0] = registerAddress;
wim 0:d64854a60f95 671
wim 0:d64854a60f95 672 _i2c->write( _slaveAddress, w, 1 );
wim 0:d64854a60f95 673 _i2c->read( _slaveAddress, r, 1 );
wim 0:d64854a60f95 674
wim 0:d64854a60f95 675 return ( r[0] );
wim 0:d64854a60f95 676 }
wim 0:d64854a60f95 677
wim 0:d64854a60f95 678
wim 0:d64854a60f95 679 //
wim 1:0440152c5387 680 // End I2C Implementation
wim 1:0440152c5387 681 //