RETRO ROBOT E
Dependents: RETRO_ROBOT_SC16IS750E
Fork of SC16IS750 by
SC16IS750.cpp
- Committer:
- RLRiedinger
- Date:
- 2015-03-02
- Revision:
- 6:b57b71c0879a
- Parent:
- 5:ff3e57bebb6a
File content as of revision 6:b57b71c0879a:
/* * 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 * v0.2 WH, Feb 2014, Added Doxygen Documentation, Added Hardware Reset pin methods. * v0.3 WH, Dec 2014, Added support for SC16IS752 dual UART. * v0.4 WH, Dec 2014, Added Repeated Start for I2C readRegister(). Set I2C clock at 100kb/s. Fixed and added some comments. * * 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, * including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mbed.h" #include "SC16IS750.h" #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 * Supports both SPI and I2C interfaces through derived classes * * @code * * @endcode */ 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(); // initialize UART registers } /* * Set baudrate of the serial port. * @param baud integer baudrate (4800, 9600 etc) * @return none */ void SC16IS750::baud(unsigned long SC16IS750_XTAL_FREQ, int baudrate) { /* #define SC16IS750_XTAL_FREQ 14745600UL // On-board crystal (New mid-2010 Version) #define SC16IS750_XTAL_FREQ 12288000UL // On-board crystal (New mid-2010 Version) #define SC16IS750_BAUDRATE_DIVISOR(baud) ((SC16IS750_XTAL_FREQ / SC16IS750_PRESCALER)/(baud * 16UL)) */ unsigned long divisor = (SC16IS750_XTAL_FREQ / SC16IS750_PRESCALER) / (baudrate * 16UL); char lcr_tmp; _config.baudrate = baudrate; // Save baudrate lcr_tmp = this->readRegister(LCR); // Read current LCR register this->writeRegister(LCR, lcr_tmp | LCR_ENABLE_DIV); // Enable Divisor registers this->writeRegister(DLL, ( divisor & 0xFF)); // write divisor LSB this->writeRegister(DLH, ((divisor >> 8) & 0xFF)); // write divisor MSB this->writeRegister(LCR, lcr_tmp); // Restore LCR register, activate regular RBR, THR and IER registers } /* * Set the transmission format used by the serial port. * @param bits The number of bits in a word (5-8; default = 8) * @param parity The parity used (Serial::None, Serial::Odd, Serial::Even, Serial::Forced1, Serial::Forced0; default = Serial::None) * @param stop_bits The number of stop bits (1 or 2; default = 1) * @return none */ void SC16IS750::format(int bits, Serial::Parity parity, int stop_bits) { char lcr_tmp = 0x00; switch (bits) { case 5: lcr_tmp |= LCR_BITS5; break; case 6: lcr_tmp |= LCR_BITS6; break; case 7: lcr_tmp |= LCR_BITS7; break; case 8: lcr_tmp |= LCR_BITS8; break; default: lcr_tmp |= LCR_BITS8; break; } switch (parity) { case Serial::None: lcr_tmp |= LCR_NONE; break; case Serial::Odd: lcr_tmp |= LCR_ODD; break; case Serial::Even: lcr_tmp |= LCR_EVEN; break; case Serial::Forced1: lcr_tmp |= LCR_FORCED1; break; case Serial::Forced0: lcr_tmp |= LCR_FORCED0; break; default: lcr_tmp |= LCR_NONE; break; } switch (stop_bits) { case 1: lcr_tmp |= LCR_BITS1; break; case 2: lcr_tmp |= LCR_BITS2; break; default: lcr_tmp |= LCR_BITS1; break; } _config.dataformat = lcr_tmp; // Save dataformat this->writeRegister(LCR, lcr_tmp); // Set LCR register, activate regular RBR, THR and IER registers }; /* * Generate a break condition on the serial line * @param none * @return none */ void SC16IS750::send_break() { // Wait for 1.5 frames before clearing the break condition // This will have different effects on our platforms, but should // ensure that we keep the break active for at least one frame. // We consider a full frame (1 start bit + 8 data bits bits + // 1 parity bit + 2 stop bits = 12 bits) for computation. // One bit time (in us) = 1000000/_baud // Twelve bits: 12000000 / baud delay // 1.5 frames: 18000000 / baud delay set_break(true); wait_us(18000000 / _config.baudrate); set_break(false); } /* * Set a break condition on the serial line * @param enable break condition * @return none */ void SC16IS750::set_break(bool enable) { if (enable) { _config.dataformat |= LCR_BRK_ENA; // Save dataformat } else { _config.dataformat &= ~LCR_BRK_ENA; // Save dataformat } this->writeRegister(LCR, _config.dataformat); // Set LCR register } /* * 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 hardware flow control levels. 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) * @param flow2 the second flow control pin (CTS for RTSCTS) * @return none */ void SC16IS750::set_flow_control(Flow type, PinName flow1, PinName flow2) { char lcr_tmp; char efr_tmp = 0x00; // We need to enable flow control to prevent overflow of buffers and // lose data when used with fast devices like the WiFly. switch (type) { case Disabled: break; case RTS: efr_tmp = EFR_ENABLE_RTS; break; case CTS: efr_tmp = EFR_ENABLE_CTS; break; case RTSCTS: efr_tmp = EFR_ENABLE_RTS | EFR_ENABLE_CTS; break; default: break; } //Save flowcontrol mode and enable enhanced functions _config.flowctrl = efr_tmp | EFR_ENABLE_ENHANCED_FUNCTIONS; lcr_tmp = this->readRegister(LCR); // save LRC register this->writeRegister(LCR, LCR_ENABLE_ENHANCED_FUNCTIONS); // write magic number 0xBF to enable access to EFR register this->writeRegister(EFR, _config.flowctrl); // set flow and enable enhanced functions this->writeRegister(LCR, lcr_tmp); // restore LCR register } /* * Set the RX FIFO flow control levels * 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) * @param halt trigger level to resume transmission (0..15, meaning 0-60 with granularity of 4) * @return none */ void SC16IS750::set_flow_triggers(int resume, int halt) { // sanity checks halt = halt & 0x0F; resume = resume & 0x0F; if (halt <= resume) { halt = TCR_HALT_DEFAULT; resume = TCR_RESUME_DEFAULT; } // Note: TCR accessible only when EFR[4] = 1 and MCR[2] = 1 this->writeRegister(TCR, (resume << 4) | halt); // set TCR register } /* * Set the Modem Control register * This method sets prescaler, enables TCR and TLR * * @param none * @return none */ void SC16IS750::set_modem_control() { // Note MCR[7:4] and MCR[2] only accessible when EFR[4] is set if (SC16IS750_PRESCALER == SC16IS750_PRESCALER_1) { // Default prescaler after reset this->writeRegister(MCR, MCR_PRESCALE_1 | MCR_ENABLE_TCR_TLR); } else { this->writeRegister(MCR, MCR_PRESCALE_4 | MCR_ENABLE_TCR_TLR); } } /** Initialize internal registers * Should be in protection section. Public for testing purposes * If initialisation fails this method does not return. * @param none * @return none */ void SC16IS750::_init() { // Initialize SC16IS750 // Hardware reset, assuming there is a HW Reset pin this->hwReset(); // Software reset, assuming there is no access to the HW Reset pin swReset(); // Set default baudrate (depends on prescaler) and save in _config DLL / DLH baud(); // Set default dataformat and save in _config LCR format(); // Set dataflow mode and Enables enhanced functions. Save in _config EFR set_flow_control(); // 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(); flush(); // Modem control, sets prescaler, enable TCR and TLR // Note MCR[7:4] and MCR[2] only accessible when EFR[4] is set (enhanced functions enable) set_modem_control(); // Set RTS trigger levels // Note TCR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set set_flow_triggers(); // Set default break condition and save in _config LCR // set_break(); // The UART bridge should now be successfully initialized. // Test if UART bridge is present and initialized if (!connected()) { #if (0) // Lock up if we fail to initialize UART bridge. while(1){}; #else // printf("Failed to initialize UART bridge\r\n"); #endif } else { // printf("Initialized UART bridge!\r\n"); } } /* * FIFO control, sets TX and RX IRQ trigger levels and enables FIFO and save in _config * Note FCR[5:4] (=TX_IRQ_LVL) only accessible when EFR[4] is set (enhanced functions enable) * Note TLR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set * @param none * @return none */ void SC16IS750::set_fifo_control() { // Set default fifoformat FCR _config.fifoenable = true; // Note FCR[5:4] (=TX_IRQ_LVL) only accessible when EFR[4] is set (enhanced functions enable) // _config.fifoformat = FCR_RX_IRQ_8 | FCR_TX_IRQ_56; _config.fifoformat = FCR_RX_IRQ_8 | FCR_TX_IRQ_8; // Default if (_config.fifoenable) { // Enable FIFO mode and set FIFO control values this->writeRegister(FCR, _config.fifoformat | FCR_ENABLE_FIFO); } else { // Disable FIFO mode and set FIFO control values this->writeRegister(FCR, _config.fifoformat); } // Set Trigger level register TLR for RX and TX interrupt generation // Note TLR only accessible when EFR[4] is set (enhanced functions enable) and MCR[2] is set // TRL Trigger levels for RX and TX are 0..15, meaning 0-60 with a granularity of 4 chars // When TLR for RX or TX are 'Zero' the corresponding values in FCR are used. The FCR settings // have less resolution (only 4 levels) so TLR is considered an enhanced function. this->writeRegister(TLR, 0x00); // Use FCR Levels // this->writeRegister(TLR, (TLR_RX_DEFAULT << 4) | TLR_TX_DEFAULT); // Use Default enhanced levels } /* * Flush the UART FIFOs while maintaining current FIFO mode. * @param none * @return none */ void SC16IS750::flush() { // FCR is Write Only, use saved _config // Reset TXFIFO, reset RXFIFO, non FIFO mode this->writeRegister(FCR, FCR_TX_FIFO_RST | FCR_RX_FIFO_RST); if (_config.fifoenable) { // Enable FIFO mode and set FIFO control values this->writeRegister(FCR, _config.fifoformat | FCR_ENABLE_FIFO); } else { // Disable FIFO mode and set FIFO control values this->writeRegister(FCR, _config.fifoformat); } #if (0) // original /* * Flush characters from SC16IS750 receive buffer. */ // Note: This may not be the most appropriate flush approach. // It might be better to just flush the UART's buffer // rather than the buffer of the connected device // which is essentially what this does. while(readable() > 0) { getc(); } #endif } /* * * Check that UART is connected and operational. * @param none * @return bool true when connected, false otherwise */ bool SC16IS750::connected() { // Perform read/write test to check if UART is working const char TEST_CHARACTER = 'H'; this->writeRegister(SPR, TEST_CHARACTER); return (this->readRegister(SPR) == TEST_CHARACTER); } /* * Determine if there is a character available to read. * This is data that's already arrived and stored in the receive * buffer (which holds 64 chars). * * @return 1 if there is a character available to read, 0 otherwise */ int SC16IS750::readable() { // if (this->readableCount() > 0) { // Check count if (this->readRegister(LSR) & LSR_DR) { // Data in Receiver Bit, at least one character waiting return 1; } else { return 0; } } /* * Determine how many characters are available to read. * This is data that's already arrived and stored in the receive * buffer (which holds 64 chars). * * @return int Characters available to read */ int SC16IS750::readableCount() { return (this->readRegister(RXLVL)); } /* * Determine if there is space available to write a character. * @return 1 if there is a space for a character to write, 0 otherwise */ int SC16IS750::writable() { // if ((this->writableCount() > 0) { // Check count if (this->readRegister(LSR) & LSR_THRE) { // THR Empty, space for at least one character return 1; } else { return 0; } } /* * Determine how much space available for writing characters. * This considers data that's already stored in the transmit * buffer (which holds 64 chars). * * @return int character space available to write */ int SC16IS750::writableCount() { return (this->readRegister(TXLVL)); // TX Level } /* * Read char from UART Bridge. * Acts in the same manner as 'Serial.read()'. * @param none * @return char read or -1 if no data available. */ int SC16IS750::getc() { if (!readable()) { return -1; } else { return this->readRegister(RHR); } } /* * * Write char to UART Bridge. Blocking when no free space in FIFO * @param value char to be written * @return value written */ int SC16IS750::putc(int value) { while (this->readRegister(TXLVL) == 0) { // Wait for space in TX buffer wait_us(10); } this->writeRegister(THR, value); 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::writeString(const char *str) { #if ENABLE_BULK_TRANSFERS int len, idx; len = strlen(str); // 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, 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 wait_us(10); } this->writeRegister(THR, str[idx]); } #else // Single writes instead of bulktransfer int len, idx; len = strlen(str); 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 } /* * * 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 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. * @param bits Bitpattern for I/O (1=output, 0=input) * @return none */ void SC16IS750::ioSetDirection(unsigned char bits) { this->writeRegister(IODIR, bits); } /* * Set bits of I/O port pins. * This method is specific to the SPI-I2C UART and not found on the 16750 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. * @param bits Bitpattern for I/O (1= set output bit, 0 = clear output bit) * @return none */ void SC16IS750::ioSetState(unsigned char bits) { this->writeRegister(IOSTATE, bits); } /* * Get bits of I/O port pins. * This method is specific to the SPI-I2C UART and not found on the 16750 * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. * @param none * @return bits Bitpattern for I/O (1= bit set, 0 = bit cleared) */ unsigned char SC16IS750::ioGetState() { return this->readRegister(IOSTATE) ; } /* * Software Reset SC16IS750 device. * This method is specific to the SPI-I2C UART and not found on the 16750 * Note: The SC16IS752 does not have separate Reset for Channel_A and Channel_B. * @param none * @return none */ void SC16IS750::swReset() { this->writeRegister(IOCTRL, IOC_SW_RST); } // // End Abstract Class Implementation // // // Begin SPI Class Implementation // /* * Create an SC16IS750_SPI object using a specified SPI bus and CS * * @param SPI &spi the SPI port to connect to * @param cs Pinname of the CS pin (active low) * @param rst Pinname for Reset pin (active low) Optional, Default = NC */ SC16IS750_SPI::SC16IS750_SPI(SPI *spi, PinName cs, PinName rst) : _spi(spi), _cs(cs) { _cs = 1; // Deselect _spi->format(8, 0); _spi->frequency(1000000); //_spi->frequency(100000); // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. if (rst != NC) { _reset = new DigitalOut(rst); // Construct new pin _reset->write(1); // Deactivate } else { // No Hardware Reset pin _reset = NULL; // Construct dummy pin } // Dont call _init() until SPI port has been configured. // That is why _init() is not called in parent Constructor _init(); } /* * Destruct SC16IS750_SPI bridge object * * @param none * @return none */ SC16IS750_SPI::~SC16IS750_SPI() { if (_reset != NULL) { delete _reset; } // Reset pin } /* * Write value to internal register. * @param registerAddress The address of the Register (enum RegisterName) * @param data The 8bit value to write * @return none */ void SC16IS750_SPI::writeRegister(RegisterName registerAddress, char data) { _cs = 0; // Select; _spi->write(registerAddress); _spi->write(data); _cs = 1; // Deselect; } /* * Read value from internal register. * @param registerAddress The address of the Register (enum RegisterName) * @return char The 8bit value read from the register */ char SC16IS750_SPI::readRegister(RegisterName registerAddress) { // Used in SPI read operations to flush slave's shift register const char SPI_DUMMY_CHAR = 0xFF; char result; _cs = 0; // Select; _spi->write(SPI_READ_MODE_FLAG | registerAddress); result = _spi->write(SPI_DUMMY_CHAR); _cs = 1; // Deselect; 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 * * @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; } /* * Hardware Reset SC16IS750 device. * This method is only functional when the Reset pin has been declared and is also connected * @param none * @return none */ void SC16IS750_SPI::hwReset() { if (_reset != NULL) { _reset->write(0); // Activate // wait_ms(100); wait_ms(1000); //Test only _reset->write(1); // Deactivate } else { printf("Hardware Reset pin is not available...\n\r"); } } // // End SPI Implementation // // // Begin I2C Implementation // /* * Create a SC16IS750_I2C object for a bridge between I2C and a Serial port * * @param I2C &i2c the I2C port to connect to * @param char deviceAddress the I2C slave address of the SC16IS750 * @param rst Pinname for Reset pin (active low) Optional, Default = NC * */ SC16IS750_I2C::SC16IS750_I2C(I2C *i2c, uint8_t deviceAddress, PinName rst) : _i2c(i2c), _slaveAddress(deviceAddress & 0xFE) { //_i2c->frequency(400000); _i2c->frequency(400000); // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. if (rst != NC) { _reset = new DigitalOut(rst); // Construct new pin _reset->write(1); // Deactivate } else { // No Hardware Reset pin _reset = NULL; // Construct dummy pin } // Dont call _init() until I2C port has been configured. // That is why _init() is not called in parent Constructor _init(); } /* * Destruct SC16IS750_I2C bridge object * * @param none * @return none */ SC16IS750_I2C::~SC16IS750_I2C() { if (_reset != NULL) { delete _reset; // Reset pin } } /* * Write value to internal register. * @param registerAddress The address of the Register (enum RegisterName) * @param data The 8bit value to write * @return none */ void SC16IS750_I2C::writeRegister(RegisterName registerAddress, char data) { char w[2]; w[0] = registerAddress; w[1] = data; _i2c->write(_slaveAddress, w, 2); } /* * Read value from internal register. * @param registerAddress The address of the Register (enum RegisterName) * @return char The 8bit value read from the register */ char SC16IS750_I2C::readRegister(RegisterName registerAddress) { /* * Read char from SC16IS750 register at <registerAddress>. */ char w[1]; char r[1]; w[0] = registerAddress; // _i2c->write(_slaveAddress, w, 1 ); _i2c->write(_slaveAddress, w, 1, true); // Repeated Start _i2c->read(_slaveAddress, r, 1); return (r[0]); } /* * 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 } /* * Hardware Reset SC16IS750 device. * This method is only available when the Reset pin has been declared and is also connected * @param none * @return none */ void SC16IS750_I2C::hwReset() { if (_reset != NULL) { _reset->write(0); // Activate // wait_ms(100); wait_ms(1000); // Test only _reset->write(1); // Deactivate } else { printf("Hardware Reset pin is not available ...\n\r"); } } // // End I2C Implementation // // // Begin SPI Class Implementation for 16SCIS752 dual UART // /* * Create an SC16IS752_SPI object using a specified SPI bus and CS * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. * Note: The SC16IS752 does not have separate Reset for Channel_A and Channel_B. * * @param SPI &spi the SPI port to connect to * @param cs Pinname of the CS pin (active low) * @param rst Pinname for Reset pin (active low) Optional, Default = NC * @param channel UART ChannelName, Default = Channel_A */ SC16IS752_SPI::SC16IS752_SPI (SPI *spi, PinName cs, PinName rst, ChannelName channel) : _spi(spi), _cs(cs), _channel(channel) { _cs = 1; // Deselect _spi->format(8, 0); _spi->frequency(1000000); // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. if (rst != NC) { _reset = new DigitalOut(rst); // Construct new pin _reset->write(1); // Deactivate } else { // No Hardware Reset pin _reset = NULL; // Construct dummy pin } // Dont call _init() until SPI port has been configured. // That is why _init() is not called in parent Constructor _init(); } /* * Destruct SC16IS750_SPI bridge object * * @param none * @return none */ SC16IS752_SPI::~SC16IS752_SPI() { if (_reset != NULL) { delete _reset; // Reset pin } } /* * Write value to internal register. * Pure virtual, must be declared in derived class. * @param registerAddress The address of the Register (enum RegisterName) * @param data The 8bit value to write * @return none */ void SC16IS752_SPI::writeRegister(RegisterName registerAddress, char data) { _cs = 0; // Select; _spi->write(registerAddress | _channel); _spi->write(data); _cs = 1; // Deselect; } /* * Read value from internal register. * @param registerAddress The address of the Register (enum RegisterName) * @return char The 8bit value read from the register */ char SC16IS752_SPI::readRegister(RegisterName registerAddress) { // Used in SPI read operations to flush slave's shift register const char SPI_DUMMY_CHAR = 0xFF; char result; _cs = 0; // Select; _spi->write(SPI_READ_MODE_FLAG | registerAddress | _channel); result = _spi->write(SPI_DUMMY_CHAR); _cs = 1; // Deselect; 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 SC16IS752_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 | _channel); for (i = 0; i < len; i++, data++) { _spi->write(*data); } _cs = 1; // Deselect; } /* * Hardware Reset SC16IS752 device. * This method is only available when the Reset pin has been declared and is also connected * @param none * @return none */ void SC16IS752_SPI::hwReset() { if (_reset != NULL) { _reset->write(0); // Activate // wait_ms(100); wait_ms(1000); // Test only _reset->write(1); // Deactivate } else { printf("Hardware Reset pin is not available ...\n\r"); } } // // End SPI Implementation // // // Begin I2C Implementation for 16SCIS752 dual UART // /* * Create a SC16IS752_I2C object for a bridge between I2C and a Serial port * Note: The SC16IS752 does not have separate GPIOs for Channel_A and Channel_B. * Note: The SC16IS752 does not have separate Reset for Channel_A and Channel_B. * * @param I2C &i2c the I2C port to connect to * @param char deviceAddress the I2C slave address of the SC16IS750 * @param rst Pinname for Reset pin (active low) Optional, Default = NC * @param channel UART Channel, Default = Channel_A */ SC16IS752_I2C::SC16IS752_I2C(I2C *i2c, uint8_t deviceAddress, PinName rst, ChannelName channel) : _i2c(i2c), _slaveAddress(deviceAddress & 0xFE), _channel(channel) { // _i2c->frequency(400000); _i2c->frequency(100000); // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access. if (rst != NC) { _reset = new DigitalOut(rst); // Construct new pin _reset->write(1); // Deactivate } else { // No Hardware Reset pin _reset = NULL; // Construct dummy pin } // Dont call _init() until I2C port has been configured. // That is why _init() is not called in parent Constructor _init(); } /* * Destruct SC16IS752_I2C bridge object * * @param none * @return none */ SC16IS752_I2C::~SC16IS752_I2C() { if (_reset != NULL) {delete _reset;} // Reset pin } /* * Write value to internal register. * @param registerAddress The address of the Register (enum RegisterName) * @param data The 8bit value to write * @return none */ void SC16IS752_I2C::writeRegister(RegisterName registerAddress, char data) { char w[2]; w[0] = registerAddress | _channel; w[1] = data; _i2c->write( _slaveAddress, w, 2 ); } /* * Read value from internal register. * @param registerAddress The address of the Register (enum RegisterName) * @return char The 8bit value read from the register */ char SC16IS752_I2C::readRegister(RegisterName registerAddress) { /* * Read char from SC16IS752 register at <registerAddress>. */ char w[1]; char r[1]; w[0] = registerAddress | _channel; // _i2c->write( _slaveAddress, w, 1); _i2c->write(_slaveAddress, w, 1, true); // Repeated Start _i2c->read(_slaveAddress, r, 1); return (r[0]); } /* * 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 SC16IS752_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 | _channel; // 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 | _channel); // Send the data ... for (i = 0; i < len; i++) { _i2c->write(data[i]); } _i2c->stop(); #endif } /* * Hardware Reset SC16IS752 device. * This method is only available when the Reset pin has been declared and is also connected * @param none * @return none */ void SC16IS752_I2C::hwReset() { if (_reset != NULL){ _reset->write(0); //activate // wait_ms(100); wait_ms(1000); //test only _reset->write(1); //deactivate } else { printf("Hardware Reset pin is not available...\n\r"); } } // // End I2C Implementation //