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@14:352609d395c1, 2013-05-19 (annotated)
- Committer:
- humlet
- Date:
- Sun May 19 11:21:16 2013 +0000
- Revision:
- 14:352609d395c1
- Parent:
- 13:530968937ccb
almost beta?; ***refactored (removed mbed-NXP and mbed-src hacks/dependencies) ; *** bugs fixed; *** performance improved (read/write sequence now handled in ISR);
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
humlet | 0:13c962fecb13 | 1 | #include "I2CDriver.h" |
humlet | 9:65aae53a34de | 2 | #include "i2cRtos_api.h" |
humlet | 14:352609d395c1 | 3 | //#include "rt_System.h" |
humlet | 0:13c962fecb13 | 4 | #include "error.h" |
humlet | 0:13c962fecb13 | 5 | |
humlet | 1:90455d5bdd8c | 6 | using namespace mbed; |
humlet | 1:90455d5bdd8c | 7 | using namespace rtos; |
humlet | 0:13c962fecb13 | 8 | |
humlet | 14:352609d395c1 | 9 | //DigitalOut I2CDriver::osci2(p7); |
humlet | 14:352609d395c1 | 10 | |
humlet | 14:352609d395c1 | 11 | #define PREFIX i2cRtos |
humlet | 14:352609d395c1 | 12 | //#define PREFIX i2c // fallback to offical busy wait i2c c-api for performance testing |
humlet | 13:530968937ccb | 13 | #define PASTER(x,y) x ## _ ## y |
humlet | 13:530968937ccb | 14 | #define EVALUATOR(x,y) PASTER(x,y) |
humlet | 13:530968937ccb | 15 | #define FUNCTION(fun) EVALUATOR(PREFIX, fun) |
humlet | 1:90455d5bdd8c | 16 | |
humlet | 1:90455d5bdd8c | 17 | const PinName I2CDriver::c_sdas[] = {p9,p28}; |
humlet | 1:90455d5bdd8c | 18 | const PinName I2CDriver::c_scls[] = {p10,p27}; |
humlet | 1:90455d5bdd8c | 19 | |
humlet | 1:90455d5bdd8c | 20 | I2CDriver::Channel* I2CDriver::s_channels[2] = {0,0}; |
humlet | 0:13c962fecb13 | 21 | |
humlet | 3:967dde37e712 | 22 | I2CDriver::I2CDriver(PinName sda, PinName scl, int hz, int slaveAdr):m_freq(hz),m_slaveAdr(slaveAdr) |
humlet | 3:967dde37e712 | 23 | { |
humlet | 14:352609d395c1 | 24 | // ensure exclusive access for initialization |
humlet | 14:352609d395c1 | 25 | static Mutex mtx; |
humlet | 14:352609d395c1 | 26 | bool locked = false; |
humlet | 14:352609d395c1 | 27 | if(osKernelRunning()) { // but don't try to lock if rtos kernel is not running yet. (global/static definition) |
humlet | 14:352609d395c1 | 28 | mtx.lock(); |
humlet | 14:352609d395c1 | 29 | locked = true; |
humlet | 14:352609d395c1 | 30 | } |
humlet | 14:352609d395c1 | 31 | |
humlet | 3:967dde37e712 | 32 | // check pins and determine i2c channel |
humlet | 3:967dde37e712 | 33 | int channel=0; |
humlet | 3:967dde37e712 | 34 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 3:967dde37e712 | 35 | if(sda==c_sdas[0] && scl==c_scls[0]) channel=0; // I2C_1 |
humlet | 3:967dde37e712 | 36 | else |
humlet | 3:967dde37e712 | 37 | #endif |
humlet | 3:967dde37e712 | 38 | if (sda==c_sdas[1] && scl==c_scls[1]) channel=1; //I2C_2 or I2C |
humlet | 9:65aae53a34de | 39 | else error("I2CDriver: Invalid I2C pins selected\n"); |
humlet | 14:352609d395c1 | 40 | |
humlet | 14:352609d395c1 | 41 | // initialize the selected i2c channel |
humlet | 9:65aae53a34de | 42 | if(s_channels[channel]==0) { |
humlet | 13:530968937ccb | 43 | s_channels[channel] = new I2CDriver::Channel; |
humlet | 13:530968937ccb | 44 | m_channel = s_channels[channel]; |
humlet | 13:530968937ccb | 45 | m_channel->freq = 0; |
humlet | 13:530968937ccb | 46 | m_channel->slaveAdr = 0; |
humlet | 13:530968937ccb | 47 | m_channel->modeSlave = 0; |
humlet | 14:352609d395c1 | 48 | m_channel->initialized=false; // defer i2c initialization util we are sure the rtos kernel is running (config() function) |
humlet | 8:5be85bd4c5ba | 49 | } |
humlet | 3:967dde37e712 | 50 | m_channel = s_channels[channel]; |
humlet | 14:352609d395c1 | 51 | if(locked) mtx.unlock(); |
humlet | 0:13c962fecb13 | 52 | } |
humlet | 0:13c962fecb13 | 53 | |
humlet | 6:5b98c902a659 | 54 | void I2CDriver::lock() |
humlet | 6:5b98c902a659 | 55 | { |
humlet | 14:352609d395c1 | 56 | //osci2.write(1); |
humlet | 6:5b98c902a659 | 57 | // One and the same thread can lock twice, but then it needs also to unlock twice. |
humlet | 6:5b98c902a659 | 58 | // exactly what we need here |
humlet | 6:5b98c902a659 | 59 | m_channel->mutex.lock(osWaitForever); |
humlet | 14:352609d395c1 | 60 | m_channel->callerID = osThreadGetId(); |
humlet | 14:352609d395c1 | 61 | m_channel->callerPrio = osThreadGetPriority(m_channel->callerID); |
humlet | 13:530968937ccb | 62 | // maximize thread prio |
humlet | 14:352609d395c1 | 63 | osThreadSetPriority(m_channel->callerID, c_drvPrio); // hopefully not interrupted since the lock in the line above |
humlet | 13:530968937ccb | 64 | // mutex code looks like that waiting threads are priority ordered |
humlet | 13:530968937ccb | 65 | // also priority inheritance seems to be provided |
humlet | 14:352609d395c1 | 66 | //osci2.write(0); |
humlet | 6:5b98c902a659 | 67 | } |
humlet | 6:5b98c902a659 | 68 | |
humlet | 6:5b98c902a659 | 69 | void I2CDriver::unlock() |
humlet | 6:5b98c902a659 | 70 | { |
humlet | 14:352609d395c1 | 71 | //osci2.write(1); |
humlet | 13:530968937ccb | 72 | // free the mutex and restore original prio |
humlet | 14:352609d395c1 | 73 | //rt_tsk_lock(); // just prevent beeing preempted after restoring prio before freeing the mutex |
humlet | 14:352609d395c1 | 74 | osThreadSetPriority(m_channel->callerID, m_channel->callerPrio); |
humlet | 14:352609d395c1 | 75 | m_channel->mutex.unlock(); |
humlet | 14:352609d395c1 | 76 | //rt_tsk_unlock(); |
humlet | 14:352609d395c1 | 77 | //osci2.write(0); |
humlet | 6:5b98c902a659 | 78 | } |
humlet | 6:5b98c902a659 | 79 | |
humlet | 13:530968937ccb | 80 | void I2CDriver::config() |
humlet | 0:13c962fecb13 | 81 | { |
humlet | 14:352609d395c1 | 82 | //osci2.write(1); |
humlet | 14:352609d395c1 | 83 | // check and initialize driver |
humlet | 14:352609d395c1 | 84 | if(!m_channel->initialized) { |
humlet | 14:352609d395c1 | 85 | int channel = m_channel==s_channels[0] ? 0 : 1; // ...ugly |
humlet | 14:352609d395c1 | 86 | FUNCTION(init)(&m_channel->i2c, c_sdas[channel], c_scls[channel]); |
humlet | 14:352609d395c1 | 87 | m_channel->initialized=true; |
humlet | 14:352609d395c1 | 88 | } |
humlet | 13:530968937ccb | 89 | // check and update frequency |
humlet | 13:530968937ccb | 90 | if(m_freq != m_channel->freq) { |
humlet | 13:530968937ccb | 91 | m_channel->freq = m_freq; |
humlet | 13:530968937ccb | 92 | i2c_frequency(&m_channel->i2c, m_freq); |
humlet | 13:530968937ccb | 93 | } |
humlet | 13:530968937ccb | 94 | // check and update slave/master mode |
humlet | 13:530968937ccb | 95 | if(m_modeSlave != m_channel->modeSlave) { |
humlet | 13:530968937ccb | 96 | m_channel->modeSlave = m_modeSlave; |
humlet | 13:530968937ccb | 97 | i2c_slave_mode(&m_channel->i2c, m_modeSlave); |
humlet | 13:530968937ccb | 98 | } |
humlet | 13:530968937ccb | 99 | // check and update slave address |
humlet | 13:530968937ccb | 100 | if(m_modeSlave && m_slaveAdr != m_channel->slaveAdr) { |
humlet | 13:530968937ccb | 101 | m_channel->slaveAdr = m_slaveAdr; |
humlet | 13:530968937ccb | 102 | i2c_slave_address(&m_channel->i2c, 0, m_slaveAdr, 0); |
humlet | 13:530968937ccb | 103 | } |
humlet | 14:352609d395c1 | 104 | //osci2.write(0); |
humlet | 0:13c962fecb13 | 105 | } |
humlet | 0:13c962fecb13 | 106 | |
humlet | 3:967dde37e712 | 107 | int I2CDriver::readMaster(int address, char *data, int length, bool repeated) |
humlet | 1:90455d5bdd8c | 108 | { |
humlet | 13:530968937ccb | 109 | m_modeSlave = false; |
humlet | 13:530968937ccb | 110 | lockNconfig(); |
humlet | 13:530968937ccb | 111 | int ret = FUNCTION(read)(&m_channel->i2c, address, data, length, (repeated?0:1)); |
humlet | 13:530968937ccb | 112 | unlock(); |
humlet | 13:530968937ccb | 113 | return ret; |
humlet | 1:90455d5bdd8c | 114 | } |
humlet | 3:967dde37e712 | 115 | int I2CDriver::readMaster(int address, uint8_t _register, char *data, int length, bool repeated) |
humlet | 3:967dde37e712 | 116 | { |
humlet | 13:530968937ccb | 117 | m_modeSlave = false; |
humlet | 13:530968937ccb | 118 | lockNconfig(); |
humlet | 13:530968937ccb | 119 | int ret = FUNCTION(write)(&m_channel->i2c, address,(const char*)&_register, 1, 0); |
humlet | 13:530968937ccb | 120 | if(!ret) ret = FUNCTION(read)(&m_channel->i2c, address, data, length, (repeated?0:1)); |
humlet | 13:530968937ccb | 121 | unlock(); |
humlet | 13:530968937ccb | 122 | return ret; |
humlet | 3:967dde37e712 | 123 | } |
humlet | 3:967dde37e712 | 124 | int I2CDriver::readMaster(int ack) |
humlet | 1:90455d5bdd8c | 125 | { |
humlet | 13:530968937ccb | 126 | m_modeSlave = false; |
humlet | 13:530968937ccb | 127 | lockNconfig(); |
humlet | 13:530968937ccb | 128 | int ret = i2cRtos_byte_read(&m_channel->i2c, (ack?0:1)); |
humlet | 13:530968937ccb | 129 | unlock(); |
humlet | 13:530968937ccb | 130 | return ret; |
humlet | 1:90455d5bdd8c | 131 | } |
humlet | 3:967dde37e712 | 132 | int I2CDriver::writeMaster(int address, const char *data, int length, bool repeated) |
humlet | 1:90455d5bdd8c | 133 | { |
humlet | 13:530968937ccb | 134 | m_modeSlave = false; |
humlet | 13:530968937ccb | 135 | lockNconfig(); |
humlet | 13:530968937ccb | 136 | int ret = FUNCTION(write)(&m_channel->i2c, address, data, length, (repeated?0:1)); |
humlet | 13:530968937ccb | 137 | unlock(); |
humlet | 13:530968937ccb | 138 | return ret; |
humlet | 1:90455d5bdd8c | 139 | } |
humlet | 3:967dde37e712 | 140 | int I2CDriver::writeMaster(int data) |
humlet | 1:90455d5bdd8c | 141 | { |
humlet | 13:530968937ccb | 142 | m_modeSlave = false; |
humlet | 13:530968937ccb | 143 | lockNconfig(); |
humlet | 13:530968937ccb | 144 | int ret = i2cRtos_byte_write(&m_channel->i2c, data); |
humlet | 13:530968937ccb | 145 | unlock(); |
humlet | 13:530968937ccb | 146 | return ret; |
humlet | 0:13c962fecb13 | 147 | } |
humlet | 3:967dde37e712 | 148 | void I2CDriver::startMaster(void) |
humlet | 1:90455d5bdd8c | 149 | { |
humlet | 13:530968937ccb | 150 | m_modeSlave = false; |
humlet | 13:530968937ccb | 151 | lockNconfig(); |
humlet | 13:530968937ccb | 152 | i2c_start(&m_channel->i2c); |
humlet | 13:530968937ccb | 153 | unlock(); |
humlet | 3:967dde37e712 | 154 | } |
humlet | 13:530968937ccb | 155 | bool I2CDriver::stopMaster(void) |
humlet | 3:967dde37e712 | 156 | { |
humlet | 13:530968937ccb | 157 | m_modeSlave = false; |
humlet | 13:530968937ccb | 158 | lockNconfig(); |
humlet | 13:530968937ccb | 159 | bool ret=i2cRtos_stop(&m_channel->i2c); |
humlet | 13:530968937ccb | 160 | unlock(); |
humlet | 13:530968937ccb | 161 | return ret; |
humlet | 3:967dde37e712 | 162 | } |
humlet | 3:967dde37e712 | 163 | void I2CDriver::stopSlave(void) |
humlet | 3:967dde37e712 | 164 | { |
humlet | 13:530968937ccb | 165 | m_modeSlave = true; |
humlet | 13:530968937ccb | 166 | lockNconfig(); |
humlet | 13:530968937ccb | 167 | i2c_stop(&m_channel->i2c); |
humlet | 13:530968937ccb | 168 | unlock(); |
humlet | 3:967dde37e712 | 169 | } |
humlet | 3:967dde37e712 | 170 | int I2CDriver::receiveSlave(uint32_t timeout_ms) |
humlet | 3:967dde37e712 | 171 | { |
humlet | 13:530968937ccb | 172 | m_modeSlave = true; |
humlet | 13:530968937ccb | 173 | lockNconfig(); |
humlet | 13:530968937ccb | 174 | int ret = i2cRtos_slave_receive(&m_channel->i2c, timeout_ms); |
humlet | 13:530968937ccb | 175 | unlock(); |
humlet | 13:530968937ccb | 176 | return ret; |
humlet | 3:967dde37e712 | 177 | } |
humlet | 3:967dde37e712 | 178 | int I2CDriver::readSlave(char* data, int length) |
humlet | 3:967dde37e712 | 179 | { |
humlet | 13:530968937ccb | 180 | m_modeSlave = true; |
humlet | 13:530968937ccb | 181 | lockNconfig(); |
humlet | 13:530968937ccb | 182 | int ret = i2cRtos_slave_read(&m_channel->i2c, data, length); |
humlet | 13:530968937ccb | 183 | unlock(); |
humlet | 13:530968937ccb | 184 | return ret; |
humlet | 3:967dde37e712 | 185 | } |
humlet | 3:967dde37e712 | 186 | int I2CDriver::readSlave(void) |
humlet | 3:967dde37e712 | 187 | { |
humlet | 13:530968937ccb | 188 | m_modeSlave = true; |
humlet | 13:530968937ccb | 189 | lockNconfig(); |
humlet | 13:530968937ccb | 190 | int ret = i2cRtos_byte_read(&m_channel->i2c, 0); |
humlet | 13:530968937ccb | 191 | unlock(); |
humlet | 13:530968937ccb | 192 | return ret; |
humlet | 3:967dde37e712 | 193 | } |
humlet | 3:967dde37e712 | 194 | int I2CDriver::writeSlave(const char *data, int length) |
humlet | 3:967dde37e712 | 195 | { |
humlet | 13:530968937ccb | 196 | m_modeSlave = true; |
humlet | 13:530968937ccb | 197 | lockNconfig(); |
humlet | 13:530968937ccb | 198 | int ret = i2cRtos_slave_write(&m_channel->i2c, data, length); |
humlet | 13:530968937ccb | 199 | unlock(); |
humlet | 13:530968937ccb | 200 | return ret; |
humlet | 3:967dde37e712 | 201 | } |
humlet | 3:967dde37e712 | 202 | int I2CDriver::writeSlave(int data) |
humlet | 3:967dde37e712 | 203 | { |
humlet | 13:530968937ccb | 204 | m_modeSlave = true; |
humlet | 13:530968937ccb | 205 | lockNconfig(); |
humlet | 13:530968937ccb | 206 | int ret = i2cRtos_byte_write(&m_channel->i2c, data); |
humlet | 13:530968937ccb | 207 | unlock(); |
humlet | 13:530968937ccb | 208 | return ret; |
humlet | 1:90455d5bdd8c | 209 | } |
humlet | 1:90455d5bdd8c | 210 | |
humlet | 1:90455d5bdd8c | 211 | |
humlet | 3:967dde37e712 | 212 | |
humlet | 3:967dde37e712 | 213 |