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:
- 14:352609d395c1
- Parent:
- 13:530968937ccb
--- a/I2CDriver.cpp Fri May 10 20:38:35 2013 +0000 +++ b/I2CDriver.cpp Sun May 19 11:21:16 2013 +0000 @@ -1,11 +1,15 @@ #include "I2CDriver.h" #include "i2cRtos_api.h" +//#include "rt_System.h" #include "error.h" using namespace mbed; using namespace rtos; -#define PREFIX i2c +//DigitalOut I2CDriver::osci2(p7); + +#define PREFIX i2cRtos +//#define PREFIX i2c // fallback to offical busy wait i2c c-api for performance testing #define PASTER(x,y) x ## _ ## y #define EVALUATOR(x,y) PASTER(x,y) #define FUNCTION(fun) EVALUATOR(PREFIX, fun) @@ -17,8 +21,14 @@ I2CDriver::I2CDriver(PinName sda, PinName scl, int hz, int slaveAdr):m_freq(hz),m_slaveAdr(slaveAdr) { - static Mutex mutex; - mutex.lock(); + // ensure exclusive access for initialization + static Mutex mtx; + bool locked = false; + if(osKernelRunning()) { // but don't try to lock if rtos kernel is not running yet. (global/static definition) + mtx.lock(); + locked = true; + } + // check pins and determine i2c channel int channel=0; #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) @@ -27,41 +37,55 @@ #endif if (sda==c_sdas[1] && scl==c_scls[1]) channel=1; //I2C_2 or I2C else error("I2CDriver: Invalid I2C pins selected\n"); - + + // initialize the selected i2c channel if(s_channels[channel]==0) { 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->initialized=false; // defer i2c initialization util we are sure the rtos kernel is running (config() function) } m_channel = s_channels[channel]; - mutex.unlock(); + if(locked) mtx.unlock(); } void I2CDriver::lock() { + //osci2.write(1); // 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); + m_channel->callerID = osThreadGetId(); + m_channel->callerPrio = osThreadGetPriority(m_channel->callerID); // maximize thread prio - osThreadSetPriority(m_callerID, c_drvPrio); // hopefully not interrupted since the lock in the line above + osThreadSetPriority(m_channel->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 + //osci2.write(0); } void I2CDriver::unlock() { + //osci2.write(1); // free the mutex and restore original prio - m_channel->mutex.unlock(); - osThreadSetPriority(m_callerID, m_callerPrio); + //rt_tsk_lock(); // just prevent beeing preempted after restoring prio before freeing the mutex + osThreadSetPriority(m_channel->callerID, m_channel->callerPrio); + m_channel->mutex.unlock(); + //rt_tsk_unlock(); + //osci2.write(0); } void I2CDriver::config() { + //osci2.write(1); + // check and initialize driver + if(!m_channel->initialized) { + int channel = m_channel==s_channels[0] ? 0 : 1; // ...ugly + FUNCTION(init)(&m_channel->i2c, c_sdas[channel], c_scls[channel]); + m_channel->initialized=true; + } // check and update frequency if(m_freq != m_channel->freq) { m_channel->freq = m_freq; @@ -77,6 +101,7 @@ m_channel->slaveAdr = m_slaveAdr; i2c_slave_address(&m_channel->i2c, 0, m_slaveAdr, 0); } + //osci2.write(0); } int I2CDriver::readMaster(int address, char *data, int length, bool repeated)