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 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
