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:
Thu May 09 20:52:07 2013 +0000
Revision:
11:8c1d44595620
Parent:
10:e3d6c92ff222
Child:
12:6ddadcbbdca2
seem to work without  tweaked mbed lib

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