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
I2CDriver.cpp
- Committer:
- humlet
- Date:
- 2013-05-09
- Revision:
- 11:8c1d44595620
- Parent:
- 10:e3d6c92ff222
- Child:
- 13:530968937ccb
File content as of revision 11:8c1d44595620:
#include "I2CDriver.h" #include "i2cRtos_api.h" #include "error.h" using namespace mbed; using namespace rtos; #define DRV_USR_SIG (1<<6) const PinName I2CDriver::c_sdas[] = {p9,p28}; const PinName I2CDriver::c_scls[] = {p10,p27}; I2CDriver::Channel* I2CDriver::s_channels[2] = {0,0}; I2CDriver::I2CDriver(PinName sda, PinName scl, int hz, int slaveAdr):m_freq(hz),m_slaveAdr(slaveAdr) { // check pins and determine i2c channel int channel=0; #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) if(sda==c_sdas[0] && scl==c_scls[0]) channel=0; // I2C_1 else #endif if (sda==c_sdas[1] && scl==c_scls[1]) channel=1; //I2C_2 or I2C else error("I2CDriver: Invalid I2C pins selected\n"); if(s_channels[channel]==0) { new Thread(threadFun,(void *)channel,osPriorityRealtime,1024); // evillive } 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); } } void I2CDriver::lock() { // One and the same thread can lock twice, but then it needs also to unlock twice. // exactly what we need here 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 } void I2CDriver::unlock() { // free the mtex and restore original prio m_channel->mutex.unlock(); osThreadSetPriority(m_callerID, m_callerPrio); } int I2CDriver::sendNwait() { 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; } 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(); } 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(); } int I2CDriver::readMaster(int ack) { lock(); m_channel->transfer.cmd = READ_BYTE; m_channel->transfer.slv = false; m_channel->transfer.ack = ack; return sendNwait(); } 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(); } int I2CDriver::writeMaster(int data) { lock(); m_channel->transfer.cmd = WRITE_BYTE; m_channel->transfer.slv = false; m_channel->transfer.ack = data; return sendNwait(); } void I2CDriver::startMaster(void) { lock(); m_channel->transfer.cmd = START; m_channel->transfer.slv = false; sendNwait(); } void I2CDriver::stopMaster(void) { lock(); m_channel->transfer.cmd = STOP; m_channel->transfer.slv = false; sendNwait(); } void I2CDriver::stopSlave(void) { lock(); m_channel->transfer.cmd = STOP; m_channel->transfer.slv = true; m_channel->transfer.adr = m_slaveAdr; sendNwait(); } 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(); } 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(); } 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(); } 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(); } 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(); }