RTOS enabled i2c-driver based on the official i2c-C-api.
Fork of mbed-RtosI2cDriver by
i2cRtos_api.c
00001 #include "i2cRtos_api.h" 00002 00003 #if DEVICE_I2C 00004 00005 #include "us_ticker_api.h" 00006 #include "cmsis_os.h" 00007 #include "error.h" 00008 00009 // little helpers cloned from official i2c api 00010 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00011 #define I2C_CONSET(x) (x->i2c->I2CONSET) 00012 #define I2C_CONCLR(x) (x->i2c->I2CONCLR) 00013 #define I2C_STAT(x) (x->i2c->I2STAT) 00014 #define I2C_DAT(x) (x->i2c->I2DAT) 00015 #elif defined(TARGET_LPC11U24) 00016 #define I2C_CONSET(x) (x->i2c->CONSET) 00017 #define I2C_CONCLR(x) (x->i2c->CONCLR) 00018 #define I2C_STAT(x) (x->i2c->STAT) 00019 #define I2C_DAT(x) (x->i2c->DAT) 00020 #endif 00021 00022 //#include "gpio_api.h" 00023 //static gpio_t gpio[2]; // evillive 00024 00025 // isr/thread data transfer struct 00026 enum I2cIsrCmd { 00027 readMst, 00028 writeMst, 00029 readSlv, 00030 writeSlv, 00031 waitSI 00032 }; 00033 struct I2cIsrTransfer { 00034 i2c_t* obj; 00035 enum I2cIsrCmd cmd; 00036 int len; 00037 int cnt; 00038 int stat; 00039 char* rData; 00040 const char* wData; 00041 }; 00042 // one for each channel 00043 // "volatile" has been omitted since ISR and thread do not run simultaneously, hopefully ok 00044 static struct I2cIsrTransfer i2c_transfer[2]; 00045 00046 // struct holding IRQ and semaphore ID 00047 // needed for thread<->isr communication/activation 00048 struct IsrIrqSem { 00049 IRQn_Type irq; 00050 osSemaphoreId sem; 00051 }; 00052 static struct IsrIrqSem isrIrqSem[2]; // one for each channel 00053 00054 00055 // little helpers cloned from official i2c api 00056 static inline void i2c_conclr(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) 00057 { 00058 I2C_CONCLR(obj) = (start << 5) 00059 | (stop << 4) 00060 | (interrupt << 3) 00061 | (acknowledge << 2); 00062 } 00063 static inline void i2c_conset(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) 00064 { 00065 I2C_CONSET(obj) = (start << 5) 00066 | (stop << 4) 00067 | (interrupt << 3) 00068 | (acknowledge << 2); 00069 } 00070 static inline void i2c_clear_SI(i2c_t *obj) 00071 { 00072 i2c_conclr(obj, 0, 0, 1, 0); 00073 } 00074 static inline int i2c_status(i2c_t *obj) 00075 { 00076 return I2C_STAT(obj); 00077 } 00078 00079 // ISR routines 00080 // implements the same read/write sequences as the official i2c lib 00081 static void i2cRtos_isr(uint32_t ch) 00082 { 00083 struct I2cIsrTransfer* tr=&(i2c_transfer[ch]); 00084 if(tr->cmd==waitSI) { 00085 // just waiting for an interrupt after a byte read/write or slave receive call 00086 osSemaphoreRelease(isrIrqSem[ch].sem); 00087 NVIC_DisableIRQ(isrIrqSem[ch].irq); 00088 return; 00089 } 00090 int stat=i2c_status(tr->obj); 00091 int stay = 0; 00092 switch(tr->cmd) { 00093 case readMst: 00094 switch(stat) { 00095 case 0x50: // Data byte has been received; ACK has been returned. 00096 (tr->rData)[tr->cnt] = (char)(I2C_DAT(tr->obj) & 0xff); 00097 case 0x40: // SLA+R has been transmitted; ACK has been received. 00098 ++(tr->cnt); 00099 if(tr->cnt != tr->len-1) 00100 i2c_conset(tr->obj, 0, 0, 0, 1); 00101 else 00102 i2c_conclr(tr->obj, 0, 0, 0, 1); // do not ack the last byte read 00103 stay = 1; 00104 break; 00105 case 0x58: // Data byte has been received; NOT ACK has been returned. 00106 (tr->rData)[tr->cnt] = (char)(I2C_DAT(tr->obj) & 0xff); 00107 stat=0; 00108 break; 00109 } 00110 break; 00111 case writeMst: 00112 switch(stat) { 00113 case 0x18: // SLA+W has been transmitted; ACK has been received. 00114 case 0x28: // SLA+W has been transmitted; NOT ACK has been received. 00115 if(++(tr->cnt)!=tr->len) { 00116 I2C_DAT(tr->obj) = (tr->wData)[tr->cnt]; 00117 stay=1; 00118 } else { 00119 stat=0; 00120 } 00121 } 00122 break; 00123 case readSlv: 00124 ++(tr->cnt); 00125 if(stat==0x80 || stat==0x90) // Previously addressed with own SLA address(0x80) or geberal call (0x90); DATA has been received; ACK has been returned. 00126 (tr->rData)[tr->cnt] = I2C_DAT(tr->obj) & 0xFF; 00127 stay = (stat==0x80 || stat==0x90 || stat==0x060 || stat==0x70) && (tr->cnt < tr->len-1); 00128 // 60: Own SLA+W has been received; ACK has been returned. ... SLV+W??? 00129 // 70: General Call address (0x00) has been received; ACK has been returned. 00130 break; 00131 case writeSlv: 00132 ++(tr->cnt); 00133 stay = tr->cnt<tr->len && stat==0xb8; // Data byte in I2DAT has been transmitted; ACK has been received. 00134 if(stay) I2C_DAT(tr->obj) = tr->wData[tr->cnt]; 00135 break; 00136 } 00137 if(stay) { 00138 // sequence not finished => stay in ISR mode and trigger next i2c by clearing he SI bit 00139 i2c_clear_SI(tr->obj); 00140 } else { 00141 // sequence finished or unexpected state has been reported 00142 // => bail out of isr mode and return last status received 00143 tr->stat = stat; 00144 osSemaphoreRelease(isrIrqSem[ch].sem); 00145 NVIC_DisableIRQ(isrIrqSem[ch].irq); 00146 } 00147 } 00148 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00149 static void i2cRtos_isr_ch0() 00150 { 00151 //gpio_write(&gpio[0], 1); 00152 i2cRtos_isr(0); 00153 //gpio_write(&gpio[0], 0); 00154 } 00155 #endif 00156 static void i2cRtos_isr_ch1() 00157 { 00158 //gpio_write(&gpio[1], 1); 00159 i2cRtos_isr(1); 00160 //gpio_write(&gpio[1], 0); 00161 } 00162 00163 00164 // determine channel 00165 static inline uint32_t i2c_get_channel(const i2c_t *obj) 00166 { 00167 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00168 switch((I2CName)(obj->i2c)) { 00169 case I2C_1: 00170 return 0; 00171 case I2C_2: 00172 return 1; 00173 default: 00174 error("Dial911 i2c_get_channel: Invaid I2CName \n"); 00175 } 00176 #endif 00177 return 1; 00178 } 00179 00180 00181 // Enable IRQ and wait for ISR sequence to be finished 00182 static inline void i2cRtos_wait_and_see(i2c_t *obj, int ch, uint32_t tmOut) //evillive 00183 { 00184 struct IsrIrqSem* iis = &(isrIrqSem[ch]); 00185 __disable_irq(); // evil, but don't want the next three lines to be interrupted 00186 i2c_clear_SI(obj); 00187 NVIC_ClearPendingIRQ(iis->irq); 00188 NVIC_EnableIRQ(iis->irq); 00189 __enable_irq(); 00190 if(osSemaphoreWait(iis->sem, tmOut)!=1) NVIC_DisableIRQ(iis->irq); // time out => diable the IRQ 00191 } 00192 00193 // just wait for a generic i2c interrupt 00194 static inline void i2cRtos_waitSI(i2c_t *obj, uint32_t tmOut) 00195 { 00196 int ch = i2c_get_channel(obj); 00197 i2c_transfer[ch].cmd = waitSI; 00198 i2cRtos_wait_and_see(obj, ch, tmOut); 00199 } 00200 00201 // master mode read sequence 00202 int i2cRtos_read(i2c_t *obj, int address, char *data, int length, int stop) 00203 { 00204 //gpio_write(&gpio[1], 1); 00205 int stat = i2c_start(obj); 00206 if ((stat != 0x10) && (stat != 0x08)) { 00207 i2cRtos_stop(obj); // use freeze free stop if the start has failed 00208 return stat; 00209 } 00210 //gpio_write(&gpio[1], 0); 00211 int ch = i2c_get_channel(obj); 00212 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); 00213 tr->obj=obj; 00214 tr->cmd=readMst; 00215 tr->len=length; 00216 tr->cnt=-1; 00217 tr->rData=data; 00218 I2C_DAT(obj) = address | 0x01; // initiate address+R write and enter isr mode 00219 i2cRtos_wait_and_see(obj, ch,2+(length>>2)); // timeout (2+len/4)ms 00220 stat = tr->stat; 00221 //gpio_write(&gpio[1], 1); 00222 if(stat || stop) i2cRtos_stop(obj); 00223 //gpio_write(&gpio[1], 0); 00224 return stat; 00225 } 00226 00227 // master mode write sequence 00228 int i2cRtos_write(i2c_t *obj, int address, const char *data, int length, int stop) 00229 { 00230 //gpio_write(&gpio[1], 1); 00231 int status = i2c_start(obj); 00232 if ((status != 0x10) && (status != 0x08)) { 00233 i2cRtos_stop(obj); // use freeze free stop if the start has failed 00234 return status; 00235 } 00236 //gpio_write(&gpio[1], 0); 00237 int ch = i2c_get_channel(obj); 00238 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? 00239 tr->obj = obj; 00240 tr->cmd = writeMst; 00241 tr->len = length; 00242 tr->cnt = -1; 00243 tr->wData = data; 00244 I2C_DAT(obj) = address & 0xfe; // initiate address+W write and enter isr mode 00245 i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (2+len/4)ms 00246 //i2c_clear_SI(obj); // ... why? Also in official lib ... I guess this is the "write instead of start" bug 00247 status = tr->stat; 00248 //gpio_write(&gpio[1], 1); 00249 if(status || stop) i2cRtos_stop(obj); 00250 //gpio_write(&gpio[1], 0); 00251 return status; 00252 } 00253 00254 // read single byte from bus (master/slave) 00255 int i2cRtos_byte_read(i2c_t *obj, int last) 00256 { 00257 if(last) { 00258 i2c_conclr(obj, 0, 0, 0, 1); // send a NOT ACK 00259 } else { 00260 i2c_conset(obj, 0, 0, 0, 1); // send a ACK 00261 } 00262 i2cRtos_waitSI(obj, 2); 00263 return (I2C_DAT(obj) & 0xff); 00264 } 00265 00266 // write single byte to bus (master/slave) 00267 int i2cRtos_byte_write(i2c_t *obj, int data) 00268 { 00269 I2C_DAT(obj) = (data & 0xff); 00270 i2cRtos_waitSI(obj, 2); 00271 int stat=i2c_status(obj); 00272 return (stat==0x18 || stat==0x28 || stat==0x40 || stat==0xb8); 00273 } 00274 00275 // freeze free i2c stop 00276 // the busy wait without timeout of the official i2c lib 00277 // might freeze the mbed if someone on the bus keeps the clock down 00278 // and prevents LPC's i2c controller to create a stop condition 00279 int i2cRtos_stop(i2c_t *obj) 00280 { 00281 i2c_conset(obj, 0, 1, 0, 0); 00282 i2c_clear_SI(obj); 00283 uint32_t t0=us_ticker_read(); 00284 uint32_t dt=0; 00285 while((I2C_CONSET(obj) & (1 << 4)) && dt<23) { 00286 dt = us_ticker_read() - t0; 00287 } 00288 return dt<23; 00289 } 00290 00291 00292 #if DEVICE_I2CSLAVE 00293 00294 // determine slave's receive mode. Blocking with timeout 00295 int i2cRtos_slave_receive(i2c_t *obj, uint32_t tmOut) 00296 { 00297 int retval = i2c_slave_receive(obj); 00298 //check for pending requests 00299 if(retval)return retval; // there is one => bail out 00300 // No request? Wait for it! ... with time out 00301 i2cRtos_waitSI(obj, tmOut); 00302 // check again for pending requests 00303 return i2c_slave_receive(obj); 00304 } 00305 00306 // slave mode read sequence 00307 int i2cRtos_slave_read(i2c_t *obj, char *data, int length) 00308 { 00309 int ch = i2c_get_channel(obj); 00310 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? 00311 tr->obj=obj; 00312 tr->cmd=readSlv; 00313 tr->len=length; 00314 tr->cnt=-1; 00315 tr->rData=data; 00316 i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (1+len/4)ms 00317 if(tr->stat != 0xa0) { 00318 i2cRtos_stop(obj); 00319 } 00320 i2c_clear_SI(obj); // stop keeping scl low 00321 return tr->cnt; // same weird return as in official lib 00322 } 00323 00324 // slave mode write sequence 00325 int i2cRtos_slave_write(i2c_t *obj, const char *data, int length) 00326 { 00327 if(length <= 0) { 00328 return(0); 00329 } 00330 int ch = i2c_get_channel(obj); 00331 struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? 00332 tr->obj=obj; 00333 tr->cmd=writeSlv; 00334 tr->len=length; 00335 tr->cnt=0; 00336 tr->wData=data; 00337 I2C_DAT(obj) = data[0]; 00338 i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (1+len/4)ms 00339 int status = tr->stat; 00340 if(status!=0xC0 && status!=0xC8) { 00341 i2cRtos_stop(obj); 00342 } 00343 i2c_clear_SI(obj); // stops keeping scl low 00344 return tr->cnt; 00345 } 00346 #endif 00347 00348 // setup semaphores and hook in ISRs 00349 void i2cRtos_init(i2c_t *obj, PinName sda, PinName scl) 00350 { 00351 /*static int called=0; 00352 if(!called) { 00353 gpio_init(&gpio[0], p15, PIN_OUTPUT); 00354 gpio_init(&gpio[1], p16, PIN_OUTPUT); 00355 } 00356 called = 1; 00357 gpio_write(&gpio[0], 0); 00358 gpio_write(&gpio[1], 0);*/ 00359 00360 i2c_init(obj,sda,scl); 00361 uint32_t ch = i2c_get_channel(obj); 00362 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00363 static osSemaphoreDef(i2cIsrDrvSem_ch0); 00364 static osSemaphoreDef(i2cIsrDrvSem_ch1); 00365 switch(ch) { 00366 case 0: 00367 isrIrqSem[ch].irq = I2C1_IRQn; 00368 NVIC_SetVector(I2C1_IRQn, (uint32_t)i2cRtos_isr_ch0); 00369 isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch0), 1); 00370 break; 00371 case 1: 00372 isrIrqSem[ch].irq = I2C2_IRQn; 00373 NVIC_SetVector(I2C2_IRQn, (uint32_t)i2cRtos_isr_ch1); 00374 isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1); 00375 break; 00376 } 00377 osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever); 00378 #elif defined(TARGET_LPC11U24) 00379 static osSemaphoreDef(i2cIsrDrvSem_ch1); 00380 isrIrqSem[ch].irq = I2C_IRQn; 00381 NVIC_SetVector(I2C_IRQn, (uint32_t)i2cRtos_isr_ch1); 00382 isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1); 00383 osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever); 00384 #else 00385 #error "Dial911 i2cRtos_init: Unsupported HW" 00386 #endif 00387 } 00388 #endif
Generated on Wed Jul 13 2022 17:20:05 by 1.7.2