Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-RtosI2cDriver 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 |
