RTOS enabled i2c-driver based on the official i2c-C-api.

Dependencies:   mbed-rtos

Fork of mbed-RtosI2cDriver by Helmut Schmücker

I2cRtosDriver

Overview

  • Based on RTOS
    • Less busy wait waste of CPU cycles
    • ... but some waste of CPU cycles by context switches
    • Frees up to 80% of CPU resources
  • Fixes the bug described in https://mbed.org/forum/bugs-suggestions/topic/4128/
  • Spends minimal time in interrupt context
  • Supports I2C Master and Slave mode
  • Interface compatible to official I2C lib
  • Supports LPC1768 and LPC11U24.
  • Reuses parts of the official I2C implementation
  • The test and example programs work quite well and the results look promising. But this is by no means a thoroughly regression tested library. There might be some surprises left.
  • If you want to avoid the RTOS overhead MODI2C might be a better choice.

Usage

  • In existing projects simply replace in the I2C interface class declaration the official type by one of the adapters I2CMasterRtos or I2CSlaveRtos described below. The behavior should be the same.
  • You can also use the I2CDriver interface directly.
  • You can create several instances of I2CMasterRtos, I2CSlaveRtos and I2CDriver. The interface classes are lightweight and work in parallel.
  • See also the tests/examples in I2CDriverTest01.h - I2CDriverTest05.h
  • The I2CDriver class is the central interface
    • I2CDriver provides a "fat" API for I2C master and slave access
    • It supports on the fly changes between master and slave mode.
    • All requests are blocking. Other threads might do their work while the calling thread waits for the i2c requests to be completed.
    • It ensures mutual exclusive access to the I2C HW.
      • This is realized by a static RTOS mutex for each I2C channel. The mutex is taken by the calling thread on any call of an I2CDriver-function.
      • Thus accesses are prioritized automatically by the priority of the calling user threads.
      • Once having access to the interface the requests are performed with high priority and cannot be interrupted by other threads.
      • Optionally the interface can be locked manually. Useful if one wants to perform a sequence of commands without interruption.
  • I2CMasterRtos and I2CSlaveRtos provide an interface compatible to the official mbed I2C interface. Additionally
    • the constructors provide parameters for defining the frequency and the slave address
    • I2CMasterRtos provides a function to read data from a given slave register
    • In contrast to the original interface the I2CSlaveRtos::receive() function is blocking, i.e it returns, when the master sends a request to the listening slave. There is no need to poll the receive status in a loop. Optionally a timeout value can be passed to the function.
    • The stop function provides a timeout mechanism and returns the status. Thus if someone on the bus inhibits the creation of a stop condition by keeping the scl or the sda line low the mbed master won't get freezed.
    • The interface adapters are implemented as object adapters, i.e they hold an I2CDriver-instance, to which they forward the user requests by simple inline functions. The overhead is negligible.

Design

The i2c read and write sequences have been realized in an interrupt service routine. The communicaton between the calling thread and the ISR is realized by a simple static transfer struct and a semaphore ... see i2cRtos_api.c
The start and stop functions still use the busy wait approach. They are not entered that frequently and usually they take less than 12µs at 100kHz bus speed. At 400kHz even less time is consumed. Thus there wouldn't be much benefit if one triggers the whole interrupt/task wait/switch sequence for that short period of time.

Performance

The following performance data have been measured with the small test applications in I2CDriverTest01.h and I2CDriverTest04.h . In these applications a high priority thread, triggered at a rate of 1kHz, reads on each trigger a data packet of given size with given I2C bus speed from a SRF08 ultra sonic ranger or a MPU6050 accelerometer/gyro. At the same time the main thread - running at a lower priority - counts in an endless loop adjacent increments of the mbed's µs-ticker API and calculates a duty cycle from this. These duty cycle measurements are shown in the table below together with the time measured for one read sequence (write address+register; write address and read x byte of data). The measurements have been performed with the ISR/RTOS approach used by this driver and with the busy wait approach used by the official mbed I2C implementation. The i2c implementation can be selected via #define PREFIX in I2CDriver.cpp.

  • The time for one read cycle is almost the same for both approaches
  • At full load the duty cycle of the low priority thread drops almost to zero for the busy wait approach, whereas with the RTOS/ISR enabled driver it stays at 80%-90% on the LPC1768 and above 65% on the LPC11U24.
  • => Especially at low bus speeds and/or high data transfer loads the driver is able to free a significant amount of CPU time.
LPC17681byte/ms4byte/ms6byte/ms1byte/ms6byte/ms12byte/ms25byte/ms
SRF08@ 100kHz@ 100kHz@ 100kHz@ 400kHz@ 400kHz@ 400kHz@ 400kHz
rtos/ISRDC[%]91.791.090.593.391.990.386.8
t[µs]421714910141314518961
busy waitDC[%]57.127.78.185.868.748.23.8
t[µs]415710907128299503949
LPC17681byte/ms4byte/ms7byte/ms1byte/ms6byte/ms12byte/ms36byte/ms
MPU6050@ 100kHz@ 100kHz@ 100kHz@ 400kHz@ 400kHz@ 400kHz@ 400kHz
rtos/ISRDC[%]91.590.789.393.091.690.084.2
t[µs]415687959133254398977
busy waitDC[%]57.730.53.386.574.359.71.2
t[µs]408681953121243392974
LPC11U241byte/ms6byte/ms1byte/ms6byte/ms23byte/ms
SRF08@ 100kHz@ 100kHz@ 400kHz@ 400kHz@ 400kHz
rtos/ISRDC[%]79.277.581.178.771.4
t[µs]474975199374978
busy waitDC[%]51.82.480.5633.3
t[µs]442937156332928
LPC11U241byte/ms6byte/ms1byte/ms6byte/ms32byte/ms
MPU6050@ 100kHz@ 100kHz@ 400kHz@ 400kHz@ 400kHz
rtos/ISRDC[%]79.176.881.078.667.1
t[µs]466922188316985
busy waitDC[%]52.87.281.769.87.4
t[µs]433893143268895
Committer:
humlet
Date:
Fri May 10 20:38:35 2013 +0000
Revision:
13:530968937ccb
Parent:
12:6ddadcbbdca2
Child:
14:352609d395c1
happyhappyjoyjoy

Who changed what in which revision?

UserRevisionLine numberNew contents of line
humlet 9:65aae53a34de 1 #include "i2cRtos_api.h"
humlet 9:65aae53a34de 2
humlet 9:65aae53a34de 3 #if DEVICE_I2C
humlet 9:65aae53a34de 4
humlet 13:530968937ccb 5 #include "us_ticker_api.h"
humlet 9:65aae53a34de 6 #include "cmsis_os.h"
humlet 9:65aae53a34de 7 #include "error.h"
humlet 9:65aae53a34de 8
humlet 13:530968937ccb 9 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
humlet 9:65aae53a34de 10 #define I2C_CONSET(x) (x->i2c->I2CONSET)
humlet 9:65aae53a34de 11 #define I2C_CONCLR(x) (x->i2c->I2CONCLR)
humlet 9:65aae53a34de 12 #define I2C_STAT(x) (x->i2c->I2STAT)
humlet 9:65aae53a34de 13 #define I2C_DAT(x) (x->i2c->I2DAT)
humlet 13:530968937ccb 14 #elif defined(TARGET_LPC11U24)
humlet 13:530968937ccb 15 #define I2C_CONSET(x) (x->i2c->CONSET)
humlet 13:530968937ccb 16 #define I2C_CONCLR(x) (x->i2c->CONCLR)
humlet 13:530968937ccb 17 #define I2C_STAT(x) (x->i2c->STAT)
humlet 13:530968937ccb 18 #define I2C_DAT(x) (x->i2c->DAT)
humlet 13:530968937ccb 19 #endif
humlet 9:65aae53a34de 20
humlet 13:530968937ccb 21 #include "gpio_api.h"
humlet 13:530968937ccb 22 static gpio_t gpio[2]; // evillive
humlet 10:e3d6c92ff222 23
humlet 9:65aae53a34de 24 enum I2cIsrCmd {
humlet 9:65aae53a34de 25 readMst,
humlet 9:65aae53a34de 26 writeMst,
humlet 9:65aae53a34de 27 readSlv,
humlet 9:65aae53a34de 28 writeSlv,
humlet 9:65aae53a34de 29 waitSI
humlet 9:65aae53a34de 30 };
humlet 9:65aae53a34de 31 struct I2cIsrTransfer {
humlet 9:65aae53a34de 32 i2c_t* obj;
humlet 9:65aae53a34de 33 enum I2cIsrCmd cmd;
humlet 9:65aae53a34de 34 int len;
humlet 9:65aae53a34de 35 int cnt;
humlet 9:65aae53a34de 36 int stat;
humlet 9:65aae53a34de 37 char* rData;
humlet 9:65aae53a34de 38 const char* wData;
humlet 9:65aae53a34de 39 };
humlet 10:e3d6c92ff222 40 static struct I2cIsrTransfer i2c_transfer[2]; // evillive: dare to get rid of volatile?
humlet 9:65aae53a34de 41
humlet 9:65aae53a34de 42
humlet 9:65aae53a34de 43 struct IsrIrqSem {
humlet 9:65aae53a34de 44 IRQn_Type irq;
humlet 9:65aae53a34de 45 osSemaphoreId sem;
humlet 9:65aae53a34de 46 };
humlet 9:65aae53a34de 47 static struct IsrIrqSem isrIrqSem[2];
humlet 9:65aae53a34de 48
humlet 9:65aae53a34de 49
humlet 9:65aae53a34de 50 // little helpers cloned from official i2c api
humlet 9:65aae53a34de 51 static inline void i2c_conclr(i2c_t *obj, int start, int stop, int interrupt, int acknowledge)
humlet 9:65aae53a34de 52 {
humlet 9:65aae53a34de 53 I2C_CONCLR(obj) = (start << 5)
humlet 9:65aae53a34de 54 | (stop << 4)
humlet 9:65aae53a34de 55 | (interrupt << 3)
humlet 9:65aae53a34de 56 | (acknowledge << 2);
humlet 9:65aae53a34de 57 }
humlet 9:65aae53a34de 58 static inline void i2c_conset(i2c_t *obj, int start, int stop, int interrupt, int acknowledge)
humlet 9:65aae53a34de 59 {
humlet 9:65aae53a34de 60 I2C_CONSET(obj) = (start << 5)
humlet 9:65aae53a34de 61 | (stop << 4)
humlet 9:65aae53a34de 62 | (interrupt << 3)
humlet 9:65aae53a34de 63 | (acknowledge << 2);
humlet 9:65aae53a34de 64 }
humlet 9:65aae53a34de 65 static inline void i2c_clear_SI(i2c_t *obj)
humlet 9:65aae53a34de 66 {
humlet 9:65aae53a34de 67 i2c_conclr(obj, 0, 0, 1, 0);
humlet 9:65aae53a34de 68 }
humlet 9:65aae53a34de 69 static inline int i2c_status(i2c_t *obj)
humlet 9:65aae53a34de 70 {
humlet 9:65aae53a34de 71 return I2C_STAT(obj);
humlet 9:65aae53a34de 72 }
humlet 9:65aae53a34de 73
humlet 9:65aae53a34de 74 // ISR stuff
humlet 10:e3d6c92ff222 75 static void i2cRtos_isr(uint32_t ch)
humlet 9:65aae53a34de 76 {
humlet 11:8c1d44595620 77 struct I2cIsrTransfer* tr=&(i2c_transfer[ch]);
humlet 12:6ddadcbbdca2 78 if(tr->cmd==waitSI) {
humlet 9:65aae53a34de 79 osSemaphoreRelease(isrIrqSem[ch].sem);
humlet 9:65aae53a34de 80 NVIC_DisableIRQ(isrIrqSem[ch].irq);
humlet 9:65aae53a34de 81 return;
humlet 9:65aae53a34de 82 }
humlet 9:65aae53a34de 83 int stat=i2c_status(tr->obj);
humlet 9:65aae53a34de 84 int stay = 0;
humlet 9:65aae53a34de 85 switch(tr->cmd) {
humlet 11:8c1d44595620 86 case readMst:
humlet 11:8c1d44595620 87 switch(stat) {
humlet 11:8c1d44595620 88 case 0x50:
humlet 11:8c1d44595620 89 (tr->rData)[tr->cnt] = (char)(I2C_DAT(tr->obj) & 0xff);
humlet 11:8c1d44595620 90 case 0x40:
humlet 11:8c1d44595620 91 ++(tr->cnt);
humlet 11:8c1d44595620 92 if(tr->cnt != tr->len-1)
humlet 10:e3d6c92ff222 93 i2c_conset(tr->obj, 0, 0, 0, 1);
humlet 11:8c1d44595620 94 else
humlet 10:e3d6c92ff222 95 i2c_conclr(tr->obj, 0, 0, 0, 1);
humlet 9:65aae53a34de 96 stay = 1;
humlet 11:8c1d44595620 97 break;
humlet 11:8c1d44595620 98 case 0x58:
humlet 11:8c1d44595620 99 (tr->rData)[tr->cnt] = (char)(I2C_DAT(tr->obj) & 0xff);
humlet 11:8c1d44595620 100 stat=0;
humlet 11:8c1d44595620 101 break;
humlet 9:65aae53a34de 102 }
humlet 9:65aae53a34de 103 break;
humlet 11:8c1d44595620 104 case writeMst:
humlet 11:8c1d44595620 105 switch(stat) {
humlet 11:8c1d44595620 106 case 0x18:
humlet 11:8c1d44595620 107 case 0x28:
humlet 11:8c1d44595620 108 if(++(tr->cnt)!=tr->len) { // evillive
humlet 11:8c1d44595620 109 I2C_DAT(tr->obj) = (tr->wData)[tr->cnt];
humlet 11:8c1d44595620 110 stay=1;
humlet 11:8c1d44595620 111 } else {
humlet 11:8c1d44595620 112 stat=0;
humlet 11:8c1d44595620 113 }
humlet 9:65aae53a34de 114 }
humlet 9:65aae53a34de 115 break;
humlet 11:8c1d44595620 116 case readSlv:
humlet 11:8c1d44595620 117 ++(tr->cnt);
humlet 9:65aae53a34de 118 if(stat==0x80 || stat==0x90)
humlet 11:8c1d44595620 119 (tr->rData)[tr->cnt] = I2C_DAT(tr->obj) & 0xFF;
humlet 11:8c1d44595620 120 stay = (stat==0x80 || stat==0x90 || stat==0x060 || stat==0x70) && (tr->cnt < tr->len-1);
humlet 9:65aae53a34de 121 break;
humlet 11:8c1d44595620 122 case writeSlv:
humlet 11:8c1d44595620 123 ++(tr->cnt);
humlet 11:8c1d44595620 124 stay = tr->cnt<tr->len && stat==0xb8;
humlet 9:65aae53a34de 125 if(stay)
humlet 11:8c1d44595620 126 I2C_DAT(tr->obj) = tr->wData[tr->cnt];
humlet 9:65aae53a34de 127 break;
humlet 9:65aae53a34de 128 }
humlet 9:65aae53a34de 129 if(stay) {
humlet 9:65aae53a34de 130 i2c_clear_SI(tr->obj);
humlet 9:65aae53a34de 131 } else {
humlet 9:65aae53a34de 132 tr->stat = stat;
humlet 9:65aae53a34de 133 osSemaphoreRelease(isrIrqSem[ch].sem);
humlet 9:65aae53a34de 134 NVIC_DisableIRQ(isrIrqSem[ch].irq);
humlet 9:65aae53a34de 135 }
humlet 9:65aae53a34de 136 }
humlet 13:530968937ccb 137 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
humlet 11:8c1d44595620 138 static void i2cRtos_isr_ch0()
humlet 9:65aae53a34de 139 {
humlet 11:8c1d44595620 140 //gpio_write(&gpio[0], 1);
humlet 9:65aae53a34de 141 i2cRtos_isr(0);
humlet 11:8c1d44595620 142 //gpio_write(&gpio[0], 0);
humlet 9:65aae53a34de 143 }
humlet 13:530968937ccb 144 #endif
humlet 11:8c1d44595620 145 static void i2cRtos_isr_ch1()
humlet 9:65aae53a34de 146 {
humlet 11:8c1d44595620 147 //gpio_write(&gpio[1], 1);
humlet 9:65aae53a34de 148 i2cRtos_isr(1);
humlet 11:8c1d44595620 149 //gpio_write(&gpio[1], 0);
humlet 9:65aae53a34de 150 }
humlet 9:65aae53a34de 151
humlet 9:65aae53a34de 152
humlet 9:65aae53a34de 153 // determine channel
humlet 11:8c1d44595620 154 static inline uint32_t i2c_get_channel(const i2c_t *obj)
humlet 9:65aae53a34de 155 {
humlet 9:65aae53a34de 156 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
humlet 9:65aae53a34de 157 switch((I2CName)(obj->i2c)) {
humlet 9:65aae53a34de 158 case I2C_1:
humlet 9:65aae53a34de 159 return 0;
humlet 9:65aae53a34de 160 case I2C_2:
humlet 9:65aae53a34de 161 return 1;
humlet 9:65aae53a34de 162 default:
humlet 9:65aae53a34de 163 error("Dial911 i2c_get_channel: Invaid I2CName \n");
humlet 9:65aae53a34de 164 }
humlet 9:65aae53a34de 165 #endif
humlet 10:e3d6c92ff222 166 return 1;
humlet 9:65aae53a34de 167 }
humlet 9:65aae53a34de 168
humlet 9:65aae53a34de 169
humlet 9:65aae53a34de 170 // wait for ISR finished
humlet 12:6ddadcbbdca2 171 static inline void i2cRtos_wait_and_see(i2c_t *obj, int ch, uint32_t tmOut) //evillive
humlet 9:65aae53a34de 172 {
humlet 11:8c1d44595620 173 struct IsrIrqSem* iis = &(isrIrqSem[ch]);
humlet 10:e3d6c92ff222 174 __disable_irq();
humlet 9:65aae53a34de 175 i2c_clear_SI(obj);
humlet 11:8c1d44595620 176 NVIC_ClearPendingIRQ(iis->irq);
humlet 9:65aae53a34de 177 NVIC_EnableIRQ(iis->irq);
humlet 10:e3d6c92ff222 178 __enable_irq();
humlet 11:8c1d44595620 179 if(osSemaphoreWait(iis->sem, tmOut)!=1) NVIC_DisableIRQ(iis->irq);
humlet 11:8c1d44595620 180 }
humlet 11:8c1d44595620 181
humlet 12:6ddadcbbdca2 182 static inline void i2cRtos_waitSI(i2c_t *obj, uint32_t tmOut)
humlet 12:6ddadcbbdca2 183 {
humlet 11:8c1d44595620 184 int ch = i2c_get_channel(obj);
humlet 11:8c1d44595620 185 i2c_transfer[ch].cmd = waitSI;
humlet 11:8c1d44595620 186 i2cRtos_wait_and_see(obj, ch, tmOut);
humlet 9:65aae53a34de 187 }
humlet 9:65aae53a34de 188
humlet 9:65aae53a34de 189
humlet 9:65aae53a34de 190 int i2cRtos_read(i2c_t *obj, int address, char *data, int length, int stop)
humlet 9:65aae53a34de 191 {
humlet 12:6ddadcbbdca2 192 //gpio_write(&gpio[1], 1);
humlet 11:8c1d44595620 193 int stat = i2c_start(obj);
humlet 11:8c1d44595620 194 if ((stat != 0x10) && (stat != 0x08)) {
humlet 9:65aae53a34de 195 i2c_stop(obj);
humlet 11:8c1d44595620 196 return stat;
humlet 9:65aae53a34de 197 }
humlet 12:6ddadcbbdca2 198 //gpio_write(&gpio[1], 0);
humlet 9:65aae53a34de 199 int ch = i2c_get_channel(obj);
humlet 12:6ddadcbbdca2 200 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem?
humlet 9:65aae53a34de 201 tr->obj=obj;
humlet 9:65aae53a34de 202 tr->cmd=readMst;
humlet 9:65aae53a34de 203 tr->len=length;
humlet 9:65aae53a34de 204 tr->cnt=-1;
humlet 9:65aae53a34de 205 tr->rData=data;
humlet 9:65aae53a34de 206 I2C_DAT(obj) = address | 0x01;
humlet 11:8c1d44595620 207 i2cRtos_wait_and_see(obj, ch,2+(length>>2)); // timeout (2+len/4)ms
humlet 11:8c1d44595620 208 stat = tr->stat;
humlet 12:6ddadcbbdca2 209 //gpio_write(&gpio[1], 1);
humlet 11:8c1d44595620 210 if(stat || stop) i2c_stop(obj);
humlet 12:6ddadcbbdca2 211 //gpio_write(&gpio[1], 0);
humlet 11:8c1d44595620 212 return stat;
humlet 9:65aae53a34de 213 }
humlet 9:65aae53a34de 214
humlet 9:65aae53a34de 215 int i2cRtos_write(i2c_t *obj, int address, const char *data, int length, int stop)
humlet 9:65aae53a34de 216 {
humlet 12:6ddadcbbdca2 217 //gpio_write(&gpio[1], 1);
humlet 9:65aae53a34de 218 int status = i2c_start(obj);
humlet 9:65aae53a34de 219 if ((status != 0x10) && (status != 0x08)) {
humlet 9:65aae53a34de 220 i2c_stop(obj);
humlet 9:65aae53a34de 221 return status;
humlet 9:65aae53a34de 222 }
humlet 12:6ddadcbbdca2 223 //gpio_write(&gpio[1], 0);
humlet 12:6ddadcbbdca2 224
humlet 9:65aae53a34de 225 int ch = i2c_get_channel(obj);
humlet 12:6ddadcbbdca2 226 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem?
humlet 12:6ddadcbbdca2 227 tr->obj = obj;
humlet 12:6ddadcbbdca2 228 tr->cmd = writeMst;
humlet 12:6ddadcbbdca2 229 tr->len = length;
humlet 12:6ddadcbbdca2 230 tr->cnt = -1;
humlet 12:6ddadcbbdca2 231 tr->wData = data;
humlet 9:65aae53a34de 232 I2C_DAT(obj) = address & 0xfe;
humlet 11:8c1d44595620 233 i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (2+len/4)ms
humlet 12:6ddadcbbdca2 234 //i2c_clear_SI(obj); // ... why? Also in official lib ... I guess this is the "write instead of start" bug
humlet 9:65aae53a34de 235 status = tr->stat;
humlet 12:6ddadcbbdca2 236 //gpio_write(&gpio[1], 1);
humlet 9:65aae53a34de 237 if(status || stop) i2c_stop(obj);
humlet 12:6ddadcbbdca2 238 //gpio_write(&gpio[1], 0);
humlet 9:65aae53a34de 239 return status;
humlet 9:65aae53a34de 240 }
humlet 9:65aae53a34de 241
humlet 9:65aae53a34de 242 int i2cRtos_byte_read(i2c_t *obj, int last)
humlet 9:65aae53a34de 243 {
humlet 9:65aae53a34de 244 if(last) {
humlet 9:65aae53a34de 245 i2c_conclr(obj, 0, 0, 0, 1); // send a NOT ACK
humlet 9:65aae53a34de 246 } else {
humlet 9:65aae53a34de 247 i2c_conset(obj, 0, 0, 0, 1); // send a ACK
humlet 9:65aae53a34de 248 }
humlet 11:8c1d44595620 249 i2cRtos_waitSI(obj, 2);
humlet 9:65aae53a34de 250 return (I2C_DAT(obj) & 0xff);
humlet 9:65aae53a34de 251 }
humlet 9:65aae53a34de 252
humlet 9:65aae53a34de 253 int i2cRtos_byte_write(i2c_t *obj, int data)
humlet 9:65aae53a34de 254 {
humlet 9:65aae53a34de 255 I2C_DAT(obj) = (data & 0xff);
humlet 11:8c1d44595620 256 i2cRtos_waitSI(obj, 2);
humlet 9:65aae53a34de 257 int stat=i2c_status(obj);
humlet 9:65aae53a34de 258 return (stat==0x18 || stat==0x28 || stat==0x40 || stat==0xb8);
humlet 9:65aae53a34de 259 }
humlet 9:65aae53a34de 260
humlet 9:65aae53a34de 261
humlet 13:530968937ccb 262 inline int i2cRtos_stop(i2c_t *obj) {
humlet 13:530968937ccb 263 i2c_conset(obj, 0, 1, 0, 0);
humlet 13:530968937ccb 264 i2c_clear_SI(obj);
humlet 13:530968937ccb 265
humlet 13:530968937ccb 266 uint32_t t0=us_ticker_read();
humlet 13:530968937ccb 267 uint32_t dt=0;
humlet 13:530968937ccb 268 while((I2C_CONSET(obj) & (1 << 4)) && dt<23){
humlet 13:530968937ccb 269 dt = us_ticker_read() - t0;
humlet 13:530968937ccb 270 }
humlet 13:530968937ccb 271 return dt<23;
humlet 13:530968937ccb 272 }
humlet 13:530968937ccb 273
humlet 13:530968937ccb 274
humlet 9:65aae53a34de 275 #if DEVICE_I2CSLAVE
humlet 9:65aae53a34de 276
humlet 9:65aae53a34de 277
humlet 9:65aae53a34de 278 int i2cRtos_slave_receive(i2c_t *obj, uint32_t tmOut)
humlet 9:65aae53a34de 279 {
humlet 9:65aae53a34de 280 int retval = i2c_slave_receive(obj);
humlet 9:65aae53a34de 281 //check for pending requests
humlet 9:65aae53a34de 282 if(retval)return retval; // there is one => bail out
humlet 9:65aae53a34de 283 // No request? Wait for it!
humlet 11:8c1d44595620 284 i2cRtos_waitSI(obj, tmOut);
humlet 9:65aae53a34de 285 // check again for pending requests
humlet 9:65aae53a34de 286 return i2c_slave_receive(obj);
humlet 9:65aae53a34de 287 }
humlet 9:65aae53a34de 288
humlet 9:65aae53a34de 289 int i2cRtos_slave_read(i2c_t *obj, char *data, int length)
humlet 9:65aae53a34de 290 {
humlet 9:65aae53a34de 291 int ch = i2c_get_channel(obj);
humlet 12:6ddadcbbdca2 292 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem?
humlet 9:65aae53a34de 293 tr->obj=obj;
humlet 9:65aae53a34de 294 tr->cmd=readSlv;
humlet 9:65aae53a34de 295 tr->len=length;
humlet 9:65aae53a34de 296 tr->cnt=-1;
humlet 9:65aae53a34de 297 tr->rData=data;
humlet 10:e3d6c92ff222 298 i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (1+len/4)ms
humlet 9:65aae53a34de 299 if(tr->stat != 0xa0) {
humlet 9:65aae53a34de 300 i2c_stop(obj);
humlet 9:65aae53a34de 301 }
humlet 11:8c1d44595620 302 i2c_clear_SI(obj); // ... why? Also in official lib ... stops keeping scl low
humlet 9:65aae53a34de 303 return tr->cnt; // same weird return as in official lib
humlet 9:65aae53a34de 304 }
humlet 9:65aae53a34de 305
humlet 9:65aae53a34de 306 int i2cRtos_slave_write(i2c_t *obj, const char *data, int length)
humlet 9:65aae53a34de 307 {
humlet 9:65aae53a34de 308 if(length <= 0) {
humlet 9:65aae53a34de 309 return(0);
humlet 9:65aae53a34de 310 }
humlet 9:65aae53a34de 311 int ch = i2c_get_channel(obj);
humlet 12:6ddadcbbdca2 312 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem?
humlet 9:65aae53a34de 313 tr->obj=obj;
humlet 9:65aae53a34de 314 tr->cmd=writeSlv;
humlet 9:65aae53a34de 315 tr->len=length;
humlet 9:65aae53a34de 316 tr->cnt=0;
humlet 9:65aae53a34de 317 tr->wData=data;
humlet 9:65aae53a34de 318 I2C_DAT(obj) = data[0];
humlet 11:8c1d44595620 319 i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (1+len/4)ms
humlet 9:65aae53a34de 320 int status = tr->stat;
humlet 9:65aae53a34de 321 if(status!=0xC0 && status!=0xC8) {
humlet 9:65aae53a34de 322 i2c_stop(obj);
humlet 9:65aae53a34de 323 }
humlet 11:8c1d44595620 324 i2c_clear_SI(obj); // ... why? Also in official lib ... stops keeping scl low
humlet 9:65aae53a34de 325 return tr->cnt;
humlet 9:65aae53a34de 326 }
humlet 9:65aae53a34de 327
humlet 11:8c1d44595620 328
humlet 11:8c1d44595620 329 // setup semaphores and hook in ISRs
humlet 11:8c1d44595620 330 void i2cRtos_init(i2c_t *obj, PinName sda, PinName scl)
humlet 11:8c1d44595620 331 {
humlet 13:530968937ccb 332
humlet 11:8c1d44595620 333 static int called=0;
humlet 11:8c1d44595620 334 if(!called) {
humlet 11:8c1d44595620 335 gpio_init(&gpio[0], p15, PIN_OUTPUT);
humlet 11:8c1d44595620 336 gpio_init(&gpio[1], p16, PIN_OUTPUT);
humlet 11:8c1d44595620 337 }
humlet 11:8c1d44595620 338 called = 1;
humlet 11:8c1d44595620 339 gpio_write(&gpio[0], 0);
humlet 11:8c1d44595620 340 gpio_write(&gpio[1], 0);
humlet 13:530968937ccb 341
humlet 11:8c1d44595620 342 i2c_init(obj,sda,scl);
humlet 11:8c1d44595620 343 uint32_t ch = i2c_get_channel(obj);
humlet 11:8c1d44595620 344 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
humlet 11:8c1d44595620 345 static osSemaphoreDef(i2cIsrDrvSem_ch0);
humlet 11:8c1d44595620 346 static osSemaphoreDef(i2cIsrDrvSem_ch1);
humlet 11:8c1d44595620 347 switch(ch) {
humlet 11:8c1d44595620 348 case 0:
humlet 11:8c1d44595620 349 isrIrqSem[ch].irq = I2C1_IRQn;
humlet 11:8c1d44595620 350 NVIC_SetVector(I2C1_IRQn, (uint32_t)i2cRtos_isr_ch0);
humlet 11:8c1d44595620 351 isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch0), 1);
humlet 11:8c1d44595620 352 break;
humlet 11:8c1d44595620 353 case 1:
humlet 11:8c1d44595620 354 isrIrqSem[ch].irq = I2C2_IRQn;
humlet 11:8c1d44595620 355 NVIC_SetVector(I2C2_IRQn, (uint32_t)i2cRtos_isr_ch1);
humlet 11:8c1d44595620 356 isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1);
humlet 11:8c1d44595620 357 break;
humlet 11:8c1d44595620 358 }
humlet 11:8c1d44595620 359 osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever);
humlet 11:8c1d44595620 360 #elif defined(TARGET_LPC11U24)
humlet 11:8c1d44595620 361 static osSemaphoreDef(i2cIsrDrvSem_ch1);
humlet 11:8c1d44595620 362 isrIrqSem[ch].irq = I2C_IRQn;
humlet 11:8c1d44595620 363 NVIC_SetVector(I2C_IRQn, (uint32_t)i2cRtos_isr_ch1);
humlet 11:8c1d44595620 364 isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1);
humlet 11:8c1d44595620 365 osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever);
humlet 11:8c1d44595620 366 #else
humlet 11:8c1d44595620 367 #error "Dial911 i2cRtos_init: Unsupported HW"
humlet 11:8c1d44595620 368 #endif
humlet 11:8c1d44595620 369 }
humlet 9:65aae53a34de 370 #endif
humlet 9:65aae53a34de 371 #endif