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:
Wed May 08 19:22:45 2013 +0000
Revision:
10:e3d6c92ff222
Parent:
9:65aae53a34de
Child:
11:8c1d44595620
less smoke, actually it seems to work

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