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 I2cRtosDriver by
I2CDriver.cpp@4:eafa7efcd771, 2013-04-20 (annotated)
- Committer:
- humlet
- Date:
- Sat Apr 20 09:52:09 2013 +0000
- Revision:
- 4:eafa7efcd771
- Parent:
- 3:967dde37e712
- Child:
- 5:8a418c89e515
running
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
humlet | 0:13c962fecb13 | 1 | #include "I2CDriver.h" |
humlet | 3:967dde37e712 | 2 | #include "i2c_api.h" |
humlet | 0:13c962fecb13 | 3 | #include "error.h" |
humlet | 0:13c962fecb13 | 4 | |
humlet | 1:90455d5bdd8c | 5 | using namespace mbed; |
humlet | 1:90455d5bdd8c | 6 | using namespace rtos; |
humlet | 0:13c962fecb13 | 7 | |
humlet | 2:514105beb343 | 8 | #define I2C_ISR_DRV_SIG (1<<7) |
humlet | 1:90455d5bdd8c | 9 | #define DRV_USR_SIG (1<<6) |
humlet | 1:90455d5bdd8c | 10 | |
humlet | 1:90455d5bdd8c | 11 | const PinName I2CDriver::c_sdas[] = {p9,p28}; |
humlet | 1:90455d5bdd8c | 12 | const PinName I2CDriver::c_scls[] = {p10,p27}; |
humlet | 1:90455d5bdd8c | 13 | |
humlet | 1:90455d5bdd8c | 14 | I2CDriver::Channel* I2CDriver::s_channels[2] = {0,0}; |
humlet | 0:13c962fecb13 | 15 | |
humlet | 0:13c962fecb13 | 16 | |
humlet | 0:13c962fecb13 | 17 | void I2CDriver::channel_0_ISR() |
humlet | 0:13c962fecb13 | 18 | { |
humlet | 2:514105beb343 | 19 | osSignalSet( s_channels[0]->driver, I2C_ISR_DRV_SIG); |
humlet | 1:90455d5bdd8c | 20 | NVIC_DisableIRQ(I2C1_IRQn); |
humlet | 0:13c962fecb13 | 21 | } |
humlet | 0:13c962fecb13 | 22 | |
humlet | 0:13c962fecb13 | 23 | |
humlet | 0:13c962fecb13 | 24 | void I2CDriver::channel_1_ISR() |
humlet | 0:13c962fecb13 | 25 | { |
humlet | 2:514105beb343 | 26 | osSignalSet( s_channels[1]->driver, I2C_ISR_DRV_SIG); |
humlet | 1:90455d5bdd8c | 27 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 1:90455d5bdd8c | 28 | NVIC_DisableIRQ(I2C2_IRQn); |
humlet | 1:90455d5bdd8c | 29 | #elif defined(TARGET_LPC11U24) |
humlet | 1:90455d5bdd8c | 30 | NVIC_DisableIRQ(I2C_IRQn); |
humlet | 1:90455d5bdd8c | 31 | #endif |
humlet | 0:13c962fecb13 | 32 | } |
humlet | 0:13c962fecb13 | 33 | |
humlet | 0:13c962fecb13 | 34 | |
humlet | 3:967dde37e712 | 35 | I2CDriver::I2CDriver(PinName sda, PinName scl, int hz, int slaveAdr):m_freq(hz),m_slaveAdr(slaveAdr) |
humlet | 3:967dde37e712 | 36 | { |
humlet | 3:967dde37e712 | 37 | // check pins and determine i2c channel |
humlet | 3:967dde37e712 | 38 | int channel=0; |
humlet | 3:967dde37e712 | 39 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 3:967dde37e712 | 40 | if(sda==c_sdas[0] && scl==c_scls[0]) channel=0; // I2C_1 |
humlet | 3:967dde37e712 | 41 | else |
humlet | 3:967dde37e712 | 42 | #endif |
humlet | 3:967dde37e712 | 43 | if (sda==c_sdas[1] && scl==c_scls[1]) channel=1; //I2C_2 or I2C |
humlet | 3:967dde37e712 | 44 | else error("I2CDriver: Invalid I2C pinns selected"); |
humlet | 3:967dde37e712 | 45 | |
humlet | 3:967dde37e712 | 46 | if(s_channels[channel]==0) |
humlet | 3:967dde37e712 | 47 | new Thread(threadFun,(void *)channel,osPriorityRealtime,512); |
humlet | 3:967dde37e712 | 48 | m_channel = s_channels[channel]; |
humlet | 3:967dde37e712 | 49 | } |
humlet | 3:967dde37e712 | 50 | |
humlet | 3:967dde37e712 | 51 | |
humlet | 1:90455d5bdd8c | 52 | void I2CDriver::threadFun(void const *args) |
humlet | 0:13c962fecb13 | 53 | { |
humlet | 0:13c962fecb13 | 54 | int channelIdx = (int)args; |
humlet | 0:13c962fecb13 | 55 | Channel channel; |
humlet | 0:13c962fecb13 | 56 | s_channels[channelIdx] = &channel; |
humlet | 2:514105beb343 | 57 | channel.driver = Thread::gettid(); |
humlet | 0:13c962fecb13 | 58 | |
humlet | 1:90455d5bdd8c | 59 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 0:13c962fecb13 | 60 | if(channelIdx==0)NVIC_SetVector(I2C1_IRQn, (uint32_t)I2CDriver::channel_0_ISR); |
humlet | 0:13c962fecb13 | 61 | if(channelIdx==1)NVIC_SetVector(I2C2_IRQn, (uint32_t)I2CDriver::channel_1_ISR); |
humlet | 1:90455d5bdd8c | 62 | #elif defined(TARGET_LPC11U24) |
humlet | 1:90455d5bdd8c | 63 | NVIC_SetVector(I2C_IRQn, (uint32_t)I2CDriver::channel_1_ISR); |
humlet | 1:90455d5bdd8c | 64 | #endif |
humlet | 2:514105beb343 | 65 | |
humlet | 3:967dde37e712 | 66 | int freq = 0; |
humlet | 3:967dde37e712 | 67 | int adrSlave = 0; |
humlet | 3:967dde37e712 | 68 | int modeSlave = 0; |
humlet | 3:967dde37e712 | 69 | i2c_t i2c; |
humlet | 3:967dde37e712 | 70 | i2c_init(&i2c, c_sdas[channelIdx], c_scls[channelIdx]); |
humlet | 2:514105beb343 | 71 | |
humlet | 1:90455d5bdd8c | 72 | volatile Transfer& tr = channel.transfer; |
humlet | 0:13c962fecb13 | 73 | while(1) { |
humlet | 1:90455d5bdd8c | 74 | // wait for requests |
humlet | 1:90455d5bdd8c | 75 | osSignalWait(DRV_USR_SIG,osWaitForever); |
humlet | 3:967dde37e712 | 76 | |
humlet | 1:90455d5bdd8c | 77 | // check and adapt frequency |
humlet | 3:967dde37e712 | 78 | if(freq != tr.freq) { |
humlet | 3:967dde37e712 | 79 | freq = tr.freq; |
humlet | 3:967dde37e712 | 80 | i2c_frequency(&i2c, tr.freq); |
humlet | 1:90455d5bdd8c | 81 | } |
humlet | 3:967dde37e712 | 82 | |
humlet | 3:967dde37e712 | 83 | // check and adapt slave/master mode |
humlet | 3:967dde37e712 | 84 | if(modeSlave != tr.slv) { |
humlet | 3:967dde37e712 | 85 | modeSlave = tr.slv; |
humlet | 3:967dde37e712 | 86 | i2c_slave_mode(&i2c, tr.slv); |
humlet | 3:967dde37e712 | 87 | } |
humlet | 3:967dde37e712 | 88 | |
humlet | 3:967dde37e712 | 89 | // check and adapt slave address |
humlet | 3:967dde37e712 | 90 | int adr = (tr.adr & 0xFF) | 1; |
humlet | 3:967dde37e712 | 91 | if(tr.slv && adrSlave != adr) { |
humlet | 3:967dde37e712 | 92 | adrSlave = adr; |
humlet | 3:967dde37e712 | 93 | i2c_slave_address(&i2c, 0, adr, 0); |
humlet | 3:967dde37e712 | 94 | } |
humlet | 3:967dde37e712 | 95 | |
humlet | 1:90455d5bdd8c | 96 | // just doit |
humlet | 1:90455d5bdd8c | 97 | switch(tr.cmd) { |
humlet | 0:13c962fecb13 | 98 | case START: |
humlet | 3:967dde37e712 | 99 | i2c_start(&i2c); |
humlet | 0:13c962fecb13 | 100 | break; |
humlet | 0:13c962fecb13 | 101 | case STOP: |
humlet | 3:967dde37e712 | 102 | i2c_stop(&i2c); |
humlet | 0:13c962fecb13 | 103 | break; |
humlet | 3:967dde37e712 | 104 | case READ_MST: |
humlet | 3:967dde37e712 | 105 | tr.ret = i2c_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); |
humlet | 1:90455d5bdd8c | 106 | break; |
humlet | 3:967dde37e712 | 107 | case READ_MST_REG: |
humlet | 3:967dde37e712 | 108 | tr.ret = i2c_write(&i2c, tr.adr,(const char*)&(tr.reg), 1, 0); |
humlet | 1:90455d5bdd8c | 109 | if(tr.ret)break; // error => bail out |
humlet | 3:967dde37e712 | 110 | tr.ret = i2c_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); |
humlet | 3:967dde37e712 | 111 | break; |
humlet | 3:967dde37e712 | 112 | case READ_SLV: |
humlet | 3:967dde37e712 | 113 | tr.ret = i2c_slave_read(&i2c, tr.dta, tr.len); |
humlet | 1:90455d5bdd8c | 114 | break; |
humlet | 1:90455d5bdd8c | 115 | case READ_BYTE: |
humlet | 3:967dde37e712 | 116 | tr.ret = i2c_byte_read(&i2c, (tr.ack?0:1)); |
humlet | 1:90455d5bdd8c | 117 | break; |
humlet | 3:967dde37e712 | 118 | case WRITE_MST: |
humlet | 3:967dde37e712 | 119 | tr.ret = i2c_write(&i2c, tr.adr, tr.wdta, tr.len, (tr.rep?0:1)); |
humlet | 3:967dde37e712 | 120 | break; |
humlet | 3:967dde37e712 | 121 | case WRITE_SLV: |
humlet | 3:967dde37e712 | 122 | tr.ret = i2c_slave_write(&i2c, tr.wdta, tr.len); |
humlet | 1:90455d5bdd8c | 123 | break; |
humlet | 1:90455d5bdd8c | 124 | case WRITE_BYTE: |
humlet | 3:967dde37e712 | 125 | tr.ret = i2c_byte_write(&i2c, tr.ack); |
humlet | 1:90455d5bdd8c | 126 | break; |
humlet | 3:967dde37e712 | 127 | case RECEIVE: |
humlet | 3:967dde37e712 | 128 | tr.ret = i2c_slave_receive_rtos(&i2c, tr.tmout); |
humlet | 4:eafa7efcd771 | 129 | break; |
humlet | 1:90455d5bdd8c | 130 | default: |
humlet | 4:eafa7efcd771 | 131 | error("call 911\n"); |
humlet | 0:13c962fecb13 | 132 | } |
humlet | 1:90455d5bdd8c | 133 | // inform the caller |
humlet | 1:90455d5bdd8c | 134 | osSignalSet( channel.transfer.caller, DRV_USR_SIG); |
humlet | 0:13c962fecb13 | 135 | } |
humlet | 0:13c962fecb13 | 136 | } |
humlet | 0:13c962fecb13 | 137 | |
humlet | 3:967dde37e712 | 138 | int I2CDriver::sendNwait() |
humlet | 0:13c962fecb13 | 139 | { |
humlet | 3:967dde37e712 | 140 | m_channel->transfer.freq = m_freq; |
humlet | 1:90455d5bdd8c | 141 | m_channel->transfer.caller = Thread::gettid(); |
humlet | 1:90455d5bdd8c | 142 | osSignalSet( m_channel->driver, DRV_USR_SIG); |
humlet | 0:13c962fecb13 | 143 | osSignalWait(DRV_USR_SIG,osWaitForever); |
humlet | 1:90455d5bdd8c | 144 | int ret = m_channel->transfer.ret; |
humlet | 1:90455d5bdd8c | 145 | unlock(); |
humlet | 1:90455d5bdd8c | 146 | return ret; |
humlet | 0:13c962fecb13 | 147 | } |
humlet | 0:13c962fecb13 | 148 | |
humlet | 3:967dde37e712 | 149 | int I2CDriver::readMaster(int address, char *data, int length, bool repeated) |
humlet | 1:90455d5bdd8c | 150 | { |
humlet | 1:90455d5bdd8c | 151 | lock(); |
humlet | 3:967dde37e712 | 152 | m_channel->transfer.cmd = READ_MST; |
humlet | 3:967dde37e712 | 153 | m_channel->transfer.slv = false; |
humlet | 1:90455d5bdd8c | 154 | m_channel->transfer.adr = address; |
humlet | 1:90455d5bdd8c | 155 | m_channel->transfer.dta = data; |
humlet | 1:90455d5bdd8c | 156 | m_channel->transfer.len = length; |
humlet | 1:90455d5bdd8c | 157 | m_channel->transfer.rep = repeated; |
humlet | 3:967dde37e712 | 158 | return sendNwait(); |
humlet | 1:90455d5bdd8c | 159 | } |
humlet | 1:90455d5bdd8c | 160 | |
humlet | 3:967dde37e712 | 161 | int I2CDriver::readMaster(int address, uint8_t _register, char *data, int length, bool repeated) |
humlet | 3:967dde37e712 | 162 | { |
humlet | 3:967dde37e712 | 163 | lock(); |
humlet | 3:967dde37e712 | 164 | m_channel->transfer.cmd = READ_MST_REG; |
humlet | 3:967dde37e712 | 165 | m_channel->transfer.slv = false; |
humlet | 3:967dde37e712 | 166 | m_channel->transfer.adr = address; |
humlet | 3:967dde37e712 | 167 | m_channel->transfer.reg = _register; |
humlet | 3:967dde37e712 | 168 | m_channel->transfer.dta = data; |
humlet | 3:967dde37e712 | 169 | m_channel->transfer.len = length; |
humlet | 3:967dde37e712 | 170 | m_channel->transfer.rep = repeated; |
humlet | 3:967dde37e712 | 171 | return sendNwait(); |
humlet | 3:967dde37e712 | 172 | } |
humlet | 3:967dde37e712 | 173 | |
humlet | 3:967dde37e712 | 174 | int I2CDriver::readMaster(int ack) |
humlet | 1:90455d5bdd8c | 175 | { |
humlet | 1:90455d5bdd8c | 176 | lock(); |
humlet | 1:90455d5bdd8c | 177 | m_channel->transfer.cmd = READ_BYTE; |
humlet | 3:967dde37e712 | 178 | m_channel->transfer.slv = false; |
humlet | 1:90455d5bdd8c | 179 | m_channel->transfer.ack = ack; |
humlet | 3:967dde37e712 | 180 | return sendNwait(); |
humlet | 1:90455d5bdd8c | 181 | } |
humlet | 1:90455d5bdd8c | 182 | |
humlet | 3:967dde37e712 | 183 | int I2CDriver::writeMaster(int address, const char *data, int length, bool repeated) |
humlet | 1:90455d5bdd8c | 184 | { |
humlet | 0:13c962fecb13 | 185 | lock(); |
humlet | 3:967dde37e712 | 186 | m_channel->transfer.cmd = WRITE_MST; |
humlet | 3:967dde37e712 | 187 | m_channel->transfer.slv = false; |
humlet | 1:90455d5bdd8c | 188 | m_channel->transfer.adr = address; |
humlet | 1:90455d5bdd8c | 189 | m_channel->transfer.wdta = data; |
humlet | 1:90455d5bdd8c | 190 | m_channel->transfer.len = length; |
humlet | 1:90455d5bdd8c | 191 | m_channel->transfer.rep = repeated; |
humlet | 3:967dde37e712 | 192 | return sendNwait(); |
humlet | 1:90455d5bdd8c | 193 | } |
humlet | 1:90455d5bdd8c | 194 | |
humlet | 3:967dde37e712 | 195 | int I2CDriver::writeMaster(int data) |
humlet | 1:90455d5bdd8c | 196 | { |
humlet | 1:90455d5bdd8c | 197 | lock(); |
humlet | 1:90455d5bdd8c | 198 | m_channel->transfer.cmd = WRITE_BYTE; |
humlet | 3:967dde37e712 | 199 | m_channel->transfer.slv = false; |
humlet | 1:90455d5bdd8c | 200 | m_channel->transfer.ack = data; |
humlet | 3:967dde37e712 | 201 | return sendNwait(); |
humlet | 0:13c962fecb13 | 202 | } |
humlet | 1:90455d5bdd8c | 203 | |
humlet | 3:967dde37e712 | 204 | void I2CDriver::startMaster(void) |
humlet | 1:90455d5bdd8c | 205 | { |
humlet | 1:90455d5bdd8c | 206 | lock(); |
humlet | 1:90455d5bdd8c | 207 | m_channel->transfer.cmd = START; |
humlet | 3:967dde37e712 | 208 | m_channel->transfer.slv = false; |
humlet | 1:90455d5bdd8c | 209 | sendNwait(); |
humlet | 3:967dde37e712 | 210 | } |
humlet | 3:967dde37e712 | 211 | |
humlet | 3:967dde37e712 | 212 | void I2CDriver::stopMaster(void) |
humlet | 3:967dde37e712 | 213 | { |
humlet | 3:967dde37e712 | 214 | lock(); |
humlet | 3:967dde37e712 | 215 | m_channel->transfer.cmd = STOP; |
humlet | 3:967dde37e712 | 216 | m_channel->transfer.slv = false; |
humlet | 3:967dde37e712 | 217 | sendNwait(); |
humlet | 3:967dde37e712 | 218 | } |
humlet | 3:967dde37e712 | 219 | |
humlet | 3:967dde37e712 | 220 | void I2CDriver::stopSlave(void) |
humlet | 3:967dde37e712 | 221 | { |
humlet | 3:967dde37e712 | 222 | lock(); |
humlet | 3:967dde37e712 | 223 | m_channel->transfer.cmd = STOP; |
humlet | 3:967dde37e712 | 224 | m_channel->transfer.slv = true; |
humlet | 3:967dde37e712 | 225 | m_channel->transfer.adr = m_slaveAdr; |
humlet | 3:967dde37e712 | 226 | sendNwait(); |
humlet | 3:967dde37e712 | 227 | } |
humlet | 3:967dde37e712 | 228 | |
humlet | 3:967dde37e712 | 229 | int I2CDriver::receiveSlave(uint32_t timeout_ms) |
humlet | 3:967dde37e712 | 230 | { |
humlet | 3:967dde37e712 | 231 | lock(); |
humlet | 3:967dde37e712 | 232 | m_channel->transfer.cmd = RECEIVE; |
humlet | 3:967dde37e712 | 233 | m_channel->transfer.slv = true; |
humlet | 3:967dde37e712 | 234 | m_channel->transfer.adr = m_slaveAdr; |
humlet | 3:967dde37e712 | 235 | m_channel->transfer.tmout = timeout_ms; |
humlet | 3:967dde37e712 | 236 | return sendNwait(); |
humlet | 3:967dde37e712 | 237 | } |
humlet | 3:967dde37e712 | 238 | |
humlet | 3:967dde37e712 | 239 | int I2CDriver::readSlave(char* data, int length) |
humlet | 3:967dde37e712 | 240 | { |
humlet | 3:967dde37e712 | 241 | lock(); |
humlet | 3:967dde37e712 | 242 | m_channel->transfer.cmd = READ_SLV; |
humlet | 3:967dde37e712 | 243 | m_channel->transfer.slv = true; |
humlet | 3:967dde37e712 | 244 | m_channel->transfer.adr = m_slaveAdr; |
humlet | 3:967dde37e712 | 245 | m_channel->transfer.dta = data; |
humlet | 3:967dde37e712 | 246 | m_channel->transfer.len = length; |
humlet | 3:967dde37e712 | 247 | return sendNwait(); |
humlet | 3:967dde37e712 | 248 | } |
humlet | 3:967dde37e712 | 249 | |
humlet | 3:967dde37e712 | 250 | int I2CDriver::readSlave(void) |
humlet | 3:967dde37e712 | 251 | { |
humlet | 3:967dde37e712 | 252 | lock(); |
humlet | 3:967dde37e712 | 253 | m_channel->transfer.cmd = READ_BYTE; |
humlet | 3:967dde37e712 | 254 | m_channel->transfer.slv = true; |
humlet | 3:967dde37e712 | 255 | m_channel->transfer.adr = m_slaveAdr; |
humlet | 3:967dde37e712 | 256 | m_channel->transfer.ack = 1; |
humlet | 3:967dde37e712 | 257 | return sendNwait(); |
humlet | 3:967dde37e712 | 258 | } |
humlet | 3:967dde37e712 | 259 | |
humlet | 3:967dde37e712 | 260 | int I2CDriver::writeSlave(const char *data, int length) |
humlet | 3:967dde37e712 | 261 | { |
humlet | 3:967dde37e712 | 262 | lock(); |
humlet | 3:967dde37e712 | 263 | m_channel->transfer.cmd = WRITE_SLV; |
humlet | 3:967dde37e712 | 264 | m_channel->transfer.slv = true; |
humlet | 3:967dde37e712 | 265 | m_channel->transfer.adr = m_slaveAdr; |
humlet | 3:967dde37e712 | 266 | m_channel->transfer.wdta = data; |
humlet | 3:967dde37e712 | 267 | m_channel->transfer.len = length; |
humlet | 3:967dde37e712 | 268 | return sendNwait(); |
humlet | 3:967dde37e712 | 269 | } |
humlet | 3:967dde37e712 | 270 | |
humlet | 3:967dde37e712 | 271 | int I2CDriver::writeSlave(int data) |
humlet | 3:967dde37e712 | 272 | { |
humlet | 3:967dde37e712 | 273 | lock(); |
humlet | 3:967dde37e712 | 274 | m_channel->transfer.cmd = WRITE_BYTE; |
humlet | 3:967dde37e712 | 275 | m_channel->transfer.slv = true; |
humlet | 3:967dde37e712 | 276 | m_channel->transfer.adr = m_slaveAdr; |
humlet | 3:967dde37e712 | 277 | m_channel->transfer.ack = data; |
humlet | 3:967dde37e712 | 278 | return sendNwait(); |
humlet | 1:90455d5bdd8c | 279 | } |
humlet | 1:90455d5bdd8c | 280 | |
humlet | 1:90455d5bdd8c | 281 | |
humlet | 3:967dde37e712 | 282 | |
humlet | 3:967dde37e712 | 283 |