I2CRTOS Driver by Helmut Schmücker. Removed included mbed-rtos library to prevent multiple definition. Make sure to include mbed-rtos library in your program!
Fork of I2cRtosDriver by
Diff: I2CDriver.cpp
- Revision:
- 13:530968937ccb
- Parent:
- 11:8c1d44595620
- Child:
- 14:352609d395c1
--- a/I2CDriver.cpp Fri May 10 07:34:24 2013 +0000 +++ b/I2CDriver.cpp Fri May 10 20:38:35 2013 +0000 @@ -5,7 +5,10 @@ using namespace mbed; using namespace rtos; -#define DRV_USR_SIG (1<<6) +#define PREFIX i2c +#define PASTER(x,y) x ## _ ## y +#define EVALUATOR(x,y) PASTER(x,y) +#define FUNCTION(fun) EVALUATOR(PREFIX, fun) const PinName I2CDriver::c_sdas[] = {p9,p28}; const PinName I2CDriver::c_scls[] = {p10,p27}; @@ -14,6 +17,8 @@ I2CDriver::I2CDriver(PinName sda, PinName scl, int hz, int slaveAdr):m_freq(hz),m_slaveAdr(slaveAdr) { + static Mutex mutex; + mutex.lock(); // check pins and determine i2c channel int channel=0; #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) @@ -24,89 +29,15 @@ else error("I2CDriver: Invalid I2C pins selected\n"); if(s_channels[channel]==0) { - new Thread(threadFun,(void *)channel,osPriorityRealtime,1024); // evillive + s_channels[channel] = new I2CDriver::Channel; + m_channel = s_channels[channel]; + m_channel->freq = 0; + m_channel->slaveAdr = 0; + m_channel->modeSlave = 0; + FUNCTION(init)(&m_channel->i2c, c_sdas[channel], c_scls[channel]); } m_channel = s_channels[channel]; -} - - -void I2CDriver::threadFun(void const *args) -{ - int channelIdx = (int)args; - Channel channel; - s_channels[channelIdx] = &channel; - channel.driver = Thread::gettid(); - - int freq = 0; - int adrSlave = 0; - int modeSlave = 0; - i2c_t i2c; - i2cRtos_init(&i2c, c_sdas[channelIdx], c_scls[channelIdx]); - - volatile Transfer& tr = channel.transfer; - while(1) { - // wait for requests - osSignalWait(DRV_USR_SIG,osWaitForever); - - // check and adapt frequency - if(freq != tr.freq) { - freq = tr.freq; - i2c_frequency(&i2c, tr.freq); - } - - // check and adapt slave/master mode - if(modeSlave != tr.slv) { - modeSlave = tr.slv; - i2c_slave_mode(&i2c, tr.slv); - } - - // check and adapt slave address - int adr = (tr.adr & 0xFF) | 1; - if(tr.slv && adrSlave != adr) { - adrSlave = adr; - i2c_slave_address(&i2c, 0, adr, 0); - } - - // just doit - switch(tr.cmd) { - case START: - i2c_start(&i2c); - break; - case STOP: - i2c_stop(&i2c); - break; - case READ_MST: - tr.ret = i2cRtos_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); - break; - case READ_MST_REG: - tr.ret = i2cRtos_write(&i2c, tr.adr,(const char*)&(tr.reg), 1, 0); - if(tr.ret)break; // error => bail out - tr.ret = i2cRtos_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); - break; - case READ_SLV: - tr.ret = i2cRtos_slave_read(&i2c, tr.dta, tr.len); - break; - case READ_BYTE: - tr.ret = i2cRtos_byte_read(&i2c, (tr.ack?0:1)); - break; - case WRITE_MST: - tr.ret = i2cRtos_write(&i2c, tr.adr, tr.wdta, tr.len, (tr.rep?0:1)); - break; - case WRITE_SLV: - tr.ret = i2cRtos_slave_write(&i2c, tr.wdta, tr.len); - break; - case WRITE_BYTE: - tr.ret = i2cRtos_byte_write(&i2c, tr.ack); - break; - case RECEIVE: - tr.ret = i2cRtos_slave_receive(&i2c, tr.tmout); - break; - default: - error("call 911\n"); - } - // inform the caller - osSignalSet( channel.transfer.caller, DRV_USR_SIG); - } + mutex.unlock(); } void I2CDriver::lock() @@ -116,157 +47,140 @@ m_callerID = osThreadGetId(); m_callerPrio = osThreadGetPriority(m_callerID); m_channel->mutex.lock(osWaitForever); - osThreadSetPriority(m_callerID, c_drvPrio); // evillive hopefully not interrupted since the lock + // maximize thread prio + osThreadSetPriority(m_callerID, c_drvPrio); // hopefully not interrupted since the lock in the line above + // mutex code looks like that waiting threads are priority ordered + // also priority inheritance seems to be provided } void I2CDriver::unlock() { - // free the mtex and restore original prio + // free the mutex and restore original prio m_channel->mutex.unlock(); osThreadSetPriority(m_callerID, m_callerPrio); } -int I2CDriver::sendNwait() +void I2CDriver::config() { - m_channel->transfer.freq = m_freq; - m_channel->transfer.caller = Thread::gettid(); - osSignalSet( m_channel->driver, DRV_USR_SIG); - osSignalWait(DRV_USR_SIG,osWaitForever); - int ret = m_channel->transfer.ret; - unlock(); - return ret; + // check and update frequency + if(m_freq != m_channel->freq) { + m_channel->freq = m_freq; + i2c_frequency(&m_channel->i2c, m_freq); + } + // check and update slave/master mode + if(m_modeSlave != m_channel->modeSlave) { + m_channel->modeSlave = m_modeSlave; + i2c_slave_mode(&m_channel->i2c, m_modeSlave); + } + // check and update slave address + if(m_modeSlave && m_slaveAdr != m_channel->slaveAdr) { + m_channel->slaveAdr = m_slaveAdr; + i2c_slave_address(&m_channel->i2c, 0, m_slaveAdr, 0); + } } int I2CDriver::readMaster(int address, char *data, int length, bool repeated) { - lock(); - m_channel->transfer.cmd = READ_MST; - m_channel->transfer.slv = false; - m_channel->transfer.adr = address; - m_channel->transfer.dta = data; - m_channel->transfer.len = length; - m_channel->transfer.rep = repeated; - return sendNwait(); + m_modeSlave = false; + lockNconfig(); + int ret = FUNCTION(read)(&m_channel->i2c, address, data, length, (repeated?0:1)); + unlock(); + return ret; } - int I2CDriver::readMaster(int address, uint8_t _register, char *data, int length, bool repeated) { - lock(); - m_channel->transfer.cmd = READ_MST_REG; - m_channel->transfer.slv = false; - m_channel->transfer.adr = address; - m_channel->transfer.reg = _register; - m_channel->transfer.dta = data; - m_channel->transfer.len = length; - m_channel->transfer.rep = repeated; - return sendNwait(); + m_modeSlave = false; + lockNconfig(); + int ret = FUNCTION(write)(&m_channel->i2c, address,(const char*)&_register, 1, 0); + if(!ret) ret = FUNCTION(read)(&m_channel->i2c, address, data, length, (repeated?0:1)); + unlock(); + return ret; } - int I2CDriver::readMaster(int ack) { - lock(); - m_channel->transfer.cmd = READ_BYTE; - m_channel->transfer.slv = false; - m_channel->transfer.ack = ack; - return sendNwait(); + m_modeSlave = false; + lockNconfig(); + int ret = i2cRtos_byte_read(&m_channel->i2c, (ack?0:1)); + unlock(); + return ret; } - int I2CDriver::writeMaster(int address, const char *data, int length, bool repeated) { - lock(); - m_channel->transfer.cmd = WRITE_MST; - m_channel->transfer.slv = false; - m_channel->transfer.adr = address; - m_channel->transfer.wdta = data; - m_channel->transfer.len = length; - m_channel->transfer.rep = repeated; - return sendNwait(); + m_modeSlave = false; + lockNconfig(); + int ret = FUNCTION(write)(&m_channel->i2c, address, data, length, (repeated?0:1)); + unlock(); + return ret; } - int I2CDriver::writeMaster(int data) { - lock(); - m_channel->transfer.cmd = WRITE_BYTE; - m_channel->transfer.slv = false; - m_channel->transfer.ack = data; - return sendNwait(); + m_modeSlave = false; + lockNconfig(); + int ret = i2cRtos_byte_write(&m_channel->i2c, data); + unlock(); + return ret; } - void I2CDriver::startMaster(void) { - lock(); - m_channel->transfer.cmd = START; - m_channel->transfer.slv = false; - sendNwait(); + m_modeSlave = false; + lockNconfig(); + i2c_start(&m_channel->i2c); + unlock(); } - -void I2CDriver::stopMaster(void) +bool I2CDriver::stopMaster(void) { - lock(); - m_channel->transfer.cmd = STOP; - m_channel->transfer.slv = false; - sendNwait(); + m_modeSlave = false; + lockNconfig(); + bool ret=i2cRtos_stop(&m_channel->i2c); + unlock(); + return ret; } - void I2CDriver::stopSlave(void) { - lock(); - m_channel->transfer.cmd = STOP; - m_channel->transfer.slv = true; - m_channel->transfer.adr = m_slaveAdr; - sendNwait(); + m_modeSlave = true; + lockNconfig(); + i2c_stop(&m_channel->i2c); + unlock(); } - int I2CDriver::receiveSlave(uint32_t timeout_ms) { - lock(); - m_channel->transfer.cmd = RECEIVE; - m_channel->transfer.slv = true; - m_channel->transfer.adr = m_slaveAdr; - m_channel->transfer.tmout = timeout_ms; - return sendNwait(); + m_modeSlave = true; + lockNconfig(); + int ret = i2cRtos_slave_receive(&m_channel->i2c, timeout_ms); + unlock(); + return ret; } - int I2CDriver::readSlave(char* data, int length) { - lock(); - m_channel->transfer.cmd = READ_SLV; - m_channel->transfer.slv = true; - m_channel->transfer.adr = m_slaveAdr; - m_channel->transfer.dta = data; - m_channel->transfer.len = length; - return sendNwait(); + m_modeSlave = true; + lockNconfig(); + int ret = i2cRtos_slave_read(&m_channel->i2c, data, length); + unlock(); + return ret; } - int I2CDriver::readSlave(void) { - lock(); - m_channel->transfer.cmd = READ_BYTE; - m_channel->transfer.slv = true; - m_channel->transfer.adr = m_slaveAdr; - m_channel->transfer.ack = 1; - return sendNwait(); + m_modeSlave = true; + lockNconfig(); + int ret = i2cRtos_byte_read(&m_channel->i2c, 0); + unlock(); + return ret; } - int I2CDriver::writeSlave(const char *data, int length) { - lock(); - m_channel->transfer.cmd = WRITE_SLV; - m_channel->transfer.slv = true; - m_channel->transfer.adr = m_slaveAdr; - m_channel->transfer.wdta = data; - m_channel->transfer.len = length; - return sendNwait(); + m_modeSlave = true; + lockNconfig(); + int ret = i2cRtos_slave_write(&m_channel->i2c, data, length); + unlock(); + return ret; } - int I2CDriver::writeSlave(int data) { - lock(); - m_channel->transfer.cmd = WRITE_BYTE; - m_channel->transfer.slv = true; - m_channel->transfer.adr = m_slaveAdr; - m_channel->transfer.ack = data; - return sendNwait(); + m_modeSlave = true; + lockNconfig(); + int ret = i2cRtos_byte_write(&m_channel->i2c, data); + unlock(); + return ret; }