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 Helmut Schmücker

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;
 }