I2CRTOS Driver by Helmut Schmücker. Removed included mbed-rtos library to prevent multiple definition. Make sure to include mbed-rtos library in your program!
Fork of I2cRtosDriver by
Revision 9:65aae53a34de, committed 2013-05-04
- Comitter:
- humlet
- Date:
- Sat May 04 16:47:56 2013 +0000
- Parent:
- 8:5be85bd4c5ba
- Child:
- 10:e3d6c92ff222
- Commit message:
- at least it compiles
Changed in this revision
--- a/I2CDriver.cpp Tue Apr 30 19:12:57 2013 +0000 +++ b/I2CDriver.cpp Sat May 04 16:47:56 2013 +0000 @@ -1,17 +1,10 @@ #include "I2CDriver.h" -#include "i2c_api.h" +#include "i2cRtos_api.h" #include "error.h" using namespace mbed; using namespace rtos; -extern "C"{ -osSemaphoreId i2cIsrDrvSem_1; -osSemaphoreDef(i2cIsrDrvSem_1); -osSemaphoreId i2cIsrDrvSem_2; -osSemaphoreDef(i2cIsrDrvSem_2); -} - #define DRV_USR_SIG (1<<6) const PinName I2CDriver::c_sdas[] = {p9,p28}; @@ -19,25 +12,6 @@ I2CDriver::Channel* I2CDriver::s_channels[2] = {0,0}; -#if defined(TARGET_LPC1768) -void I2CDriver::channel_0_ISR() -{ - osSemaphoreRelease(i2cIsrDrvSem_1); - NVIC_DisableIRQ(I2C1_IRQn); -} -#endif - -void I2CDriver::channel_1_ISR() -{ - osSemaphoreRelease(i2cIsrDrvSem_2); -#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) - NVIC_DisableIRQ(I2C2_IRQn); -#elif defined(TARGET_LPC11U24) - NVIC_DisableIRQ(I2C_IRQn); -#endif -} - - I2CDriver::I2CDriver(PinName sda, PinName scl, int hz, int slaveAdr):m_freq(hz),m_slaveAdr(slaveAdr) { // check pins and determine i2c channel @@ -47,17 +21,10 @@ else #endif if (sda==c_sdas[1] && scl==c_scls[1]) channel=1; //I2C_2 or I2C - else error("I2CDriver: Invalid I2C pinns selected"); + else error("I2CDriver: Invalid I2C pins selected\n"); - if(s_channels[channel]==0){ - new Thread(threadFun,(void *)channel,osPriorityRealtime,256); - if(channel==0){ - i2cIsrDrvSem_1 = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_1), 1); - osSemaphoreWait(i2cIsrDrvSem_1,osWaitForever); - }else{ - i2cIsrDrvSem_2 = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_2), 1); - osSemaphoreWait(i2cIsrDrvSem_2,osWaitForever); - } + if(s_channels[channel]==0) { + new Thread(threadFun,(void *)channel,osPriorityRealtime,512); // evillive } m_channel = s_channels[channel]; } @@ -70,18 +37,11 @@ s_channels[channelIdx] = &channel; channel.driver = Thread::gettid(); -#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) - if(channelIdx==0)NVIC_SetVector(I2C1_IRQn, (uint32_t)I2CDriver::channel_0_ISR); - if(channelIdx==1)NVIC_SetVector(I2C2_IRQn, (uint32_t)I2CDriver::channel_1_ISR); -#elif defined(TARGET_LPC11U24) - NVIC_SetVector(I2C_IRQn, (uint32_t)I2CDriver::channel_1_ISR); -#endif - int freq = 0; int adrSlave = 0; int modeSlave = 0; i2c_t i2c; - i2c_init(&i2c, c_sdas[channelIdx], c_scls[channelIdx]); + i2cRtos_init(&i2c, c_sdas[channelIdx], c_scls[channelIdx]); volatile Transfer& tr = channel.transfer; while(1) { @@ -116,31 +76,31 @@ i2c_stop(&i2c); break; case READ_MST: - tr.ret = i2c_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); + tr.ret = i2cRtos_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); break; case READ_MST_REG: //printf("Disco\n"); - tr.ret = i2c_write(&i2c, tr.adr,(const char*)&(tr.reg), 1, 0); + tr.ret = i2cRtos_write(&i2c, tr.adr,(const char*)&(tr.reg), 1, 0); if(tr.ret)break; // error => bail out - tr.ret = i2c_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); + tr.ret = i2cRtos_read(&i2c, tr.adr, tr.dta, tr.len, (tr.rep?0:1)); break; case READ_SLV: - tr.ret = i2c_slave_read(&i2c, tr.dta, tr.len); + tr.ret = i2cRtos_slave_read(&i2c, tr.dta, tr.len); break; case READ_BYTE: - tr.ret = i2c_byte_read(&i2c, (tr.ack?0:1)); + tr.ret = i2cRtos_byte_read(&i2c, (tr.ack?0:1)); break; case WRITE_MST: - tr.ret = i2c_write(&i2c, tr.adr, tr.wdta, tr.len, (tr.rep?0:1)); + tr.ret = i2cRtos_write(&i2c, tr.adr, tr.wdta, tr.len, (tr.rep?0:1)); break; case WRITE_SLV: - tr.ret = i2c_slave_write(&i2c, tr.wdta, tr.len); + tr.ret = i2cRtos_slave_write(&i2c, tr.wdta, tr.len); break; case WRITE_BYTE: - tr.ret = i2c_byte_write(&i2c, tr.ack); + tr.ret = i2cRtos_byte_write(&i2c, tr.ack); break; case RECEIVE: - tr.ret = i2c_slave_receive_rtos(&i2c, tr.tmout); + tr.ret = i2cRtos_slave_receive(&i2c, tr.tmout); break; default: error("call 911\n");
--- a/I2CDriver.h Tue Apr 30 19:12:57 2013 +0000 +++ b/I2CDriver.h Sat May 04 16:47:56 2013 +0000 @@ -249,10 +249,6 @@ /// to one of the entries in s_channels Channel* m_channel; - // ISRs - static void channel_0_ISR(); - static void channel_1_ISR(); - // the driver thread function static void threadFun(void const *args);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2cRtos_api.c Sat May 04 16:47:56 2013 +0000 @@ -0,0 +1,350 @@ +#include "i2cRtos_api.h" + +#if DEVICE_I2C + +#include "cmsis_os.h" +#include "error.h" + +#define I2C_CONSET(x) (x->i2c->I2CONSET) +#define I2C_CONCLR(x) (x->i2c->I2CONCLR) +#define I2C_STAT(x) (x->i2c->I2STAT) +#define I2C_DAT(x) (x->i2c->I2DAT) + +enum I2cIsrCmd { + readMst, + writeMst, + readSlv, + writeSlv, + waitSI +}; +struct I2cIsrTransfer { + i2c_t* obj; + enum I2cIsrCmd cmd; + int adr; + int len; + int cnt; + int stat; + char* rData; + const char* wData; +}; +volatile static struct I2cIsrTransfer i2c_transfer[2]; // evillive: dare to get rid of volatile? + + +struct IsrIrqSem { + IRQn_Type irq; + uint32_t isr; + osSemaphoreId sem; +}; +static struct IsrIrqSem isrIrqSem[2]; + + +// little helpers cloned from official i2c api +static inline void i2c_conclr(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) +{ + I2C_CONCLR(obj) = (start << 5) + | (stop << 4) + | (interrupt << 3) + | (acknowledge << 2); +} +static inline void i2c_conset(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) +{ + I2C_CONSET(obj) = (start << 5) + | (stop << 4) + | (interrupt << 3) + | (acknowledge << 2); +} +static inline void i2c_clear_SI(i2c_t *obj) +{ + i2c_conclr(obj, 0, 0, 1, 0); +} +static inline int i2c_status(i2c_t *obj) +{ + return I2C_STAT(obj); +} + + +// ISR stuff +static inline void i2cRtos_isr(uint32_t ch) +{ + volatile struct I2cIsrTransfer* tr=&(i2c_transfer[ch]); + + if(tr->cmd==waitSI) { + osSemaphoreRelease(isrIrqSem[ch].sem); + NVIC_DisableIRQ(isrIrqSem[ch].irq); + return; + } + + int stat=i2c_status(tr->obj); + int stay = 0; + + switch(tr->cmd) { + case readMst: { + int cnt = (tr->cnt)++; + if(cnt==-1) { + if(stat==0x40) { + i2c_conset(tr->obj, 0, 0, 0, 1); + stay = 1; + } + } else if(cnt < tr->len-1) { + if(stat==0x50) { + (tr->rData)[cnt] = (char)(I2C_DAT(tr->obj) & 0xff); + if(cnt != tr->len-2) { + i2c_conset(tr->obj, 0, 0, 0, 1); + } else { + i2c_conclr(tr->obj, 0, 0, 0, 1); + } + stay = 1; + } + } else { + if(stat==0x58) { + (tr->rData)[cnt] = (char)(I2C_DAT(tr->obj) & 0xff); + stat = 0; + } + } + break; + } + case writeMst: { + int cnt = ++(tr->cnt); + if(cnt==0) { + if(stat==0x18) { + I2C_DAT(tr->obj) = (tr->wData)[cnt]; + stay = 1; + } + } else if(cnt < tr->len) { + if(stat==0x28) { + I2C_DAT(tr->obj) = (tr->wData)[cnt]; + stay = 1; + } + } else { + if(stat==0x28) { + stat = 0; + } + } + break; + } + case readSlv: { + int cnt = ++(tr->cnt); + if(stat==0x80 || stat==0x90) + (tr->rData)[cnt] = I2C_DAT(tr->obj) & 0xFF; + stay = (stat==0x80 || stat==0x90 || stat==0x060 || stat==0x70) && (cnt < tr->len-1); + break; + } + case writeSlv: { + int cnt = ++(tr->cnt); + stay = cnt<tr->len && stat==0xb8; + if(stay) + I2C_DAT(tr->obj) = tr->wData[cnt]; + break; + } + default: + error("Dial911 i2cRtos_isr\n"); + } + if(stay) { + i2c_clear_SI(tr->obj); + } else { + tr->stat = stat; + osSemaphoreRelease(isrIrqSem[ch].sem); + NVIC_DisableIRQ(isrIrqSem[ch].irq); + } +} +static inline void i2cRtos_isr_ch0() +{ + i2cRtos_isr(0); +} +static inline void i2cRtos_isr_ch1() +{ + i2cRtos_isr(1); +} + + +// determine channel +static inline uint32_t i2c_get_channel(i2c_t *obj) +{ +#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) + switch((I2CName)(obj->i2c)) { + case I2C_1: + return 0; + case I2C_2: + return 1; + default: + error("Dial911 i2c_get_channel: Invaid I2CName \n"); + } +#elif defined(TARGET_LPC11U24) + return 1; +#else + #error "Dial911 i2c_get_channel: Unsupported HW" +#endif +return 1; +} + + +// wait for ISR finished +static inline void i2cRtos_wait_and_see(i2c_t *obj, int channel, uint32_t tmOut) +{ + struct IsrIrqSem* iis = &(isrIrqSem[channel]); + //NVIC_ClearPendingIRQ(iis->irq); // evillive + i2c_clear_SI(obj); + NVIC_EnableIRQ(iis->irq); + if(osSemaphoreWait(iis->sem, tmOut)!=1) NVIC_DisableIRQ(iis->irq); +} + + +// setup semaphores and hook in ISRs +void i2cRtos_init(i2c_t *obj, PinName sda, PinName scl) +{ + i2c_init(obj,sda,scl); + uint32_t ch = i2c_get_channel(obj); +#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) + static osSemaphoreDef(i2cIsrDrvSem_ch0); + static osSemaphoreDef(i2cIsrDrvSem_ch1); + switch(ch) { + case 0: + isrIrqSem[ch].irq = I2C1_IRQn; + isrIrqSem[ch].isr = (uint32_t)i2cRtos_isr_ch0; + isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch0), 1); + osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever); + break; + case 1: + isrIrqSem[ch].irq = I2C2_IRQn; + isrIrqSem[ch].isr = (uint32_t)i2cRtos_isr_ch1; + isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1); + osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever); + break; + } +#elif defined(TARGET_LPC11U24) + static osSemaphoreDef(i2cIsrDrvSem_ch1); + isrIrqSem[ch].irq = I2C_IRQn; + isrIrqSem[ch].isr = (uint32_t)i2cRtos_isr_ch1; + isrIrqSem[1].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1); + osSemaphoreWait(isrIrqSem[0].sem, osWaitForever); +#else + #error "Dial911 i2cRtos_init: Unsupported HW" +#endif +} + +int i2cRtos_read(i2c_t *obj, int address, char *data, int length, int stop) +{ + int status = i2c_start(obj); + if ((status != 0x10) && (status != 0x08)) { + i2c_stop(obj); + return status; + } + int ch = i2c_get_channel(obj); + volatile struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? + tr->obj=obj; + tr->cmd=readMst; + tr->len=length; + tr->cnt=-1; + tr->rData=data; + I2C_DAT(obj) = address | 0x01; + i2cRtos_wait_and_see(obj, ch, 1+(length>>2)); // timeout (1+len/4)ms + status = tr->stat; + if(status || stop) i2c_stop(obj); + return status; +} + +int i2cRtos_write(i2c_t *obj, int address, const char *data, int length, int stop) +{ + int status = i2c_start(obj); + if ((status != 0x10) && (status != 0x08)) { + i2c_stop(obj); + return status; + } + int ch = i2c_get_channel(obj); + volatile struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? + tr->obj=obj; + tr->cmd=writeMst; + tr->len=length; + tr->cnt=-1; + tr->wData=data; + I2C_DAT(obj) = address & 0xfe; + i2cRtos_wait_and_see(obj, ch, 1+(length>>2)); // timeout (1+len/4)ms + i2c_clear_SI(obj); // ... why? Also in official lib + status = tr->stat; + if(status || stop) i2c_stop(obj); + return status; +} + +int i2cRtos_byte_read(i2c_t *obj, int last) +{ + if(last) { + i2c_conclr(obj, 0, 0, 0, 1); // send a NOT ACK + } else { + i2c_conset(obj, 0, 0, 0, 1); // send a ACK + } + int ch = i2c_get_channel(obj); + i2c_transfer[ch].cmd = waitSI; + i2cRtos_wait_and_see(obj, ch, 1); + return (I2C_DAT(obj) & 0xff); + +} + +int i2cRtos_byte_write(i2c_t *obj, int data) +{ + I2C_DAT(obj) = (data & 0xff); + int ch = i2c_get_channel(obj); + i2c_transfer[ch].cmd = waitSI; + i2cRtos_wait_and_see(obj, ch, 1); + int stat=i2c_status(obj); + return (stat==0x18 || stat==0x28 || stat==0x40 || stat==0xb8); +} + + +#if DEVICE_I2CSLAVE + + +int i2cRtos_slave_receive(i2c_t *obj, uint32_t tmOut) +{ + int retval = i2c_slave_receive(obj); + //check for pending requests + if(retval)return retval; // there is one => bail out + + // No request? Wait for it! + int ch = i2c_get_channel(obj); + i2c_transfer[ch].cmd = waitSI; + i2cRtos_wait_and_see(obj, ch, tmOut); + // check again for pending requests + return i2c_slave_receive(obj); +} + +int i2cRtos_slave_read(i2c_t *obj, char *data, int length) +{ + int ch = i2c_get_channel(obj); + volatile struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? + tr->obj=obj; + tr->cmd=readSlv; + tr->len=length; + tr->cnt=-1; + tr->rData=data; + i2cRtos_wait_and_see(obj, ch, 1+(length>>2)); // timeout (1+len/4)ms + if(tr->stat != 0xa0) { + i2c_stop(obj); + } + i2c_clear_SI(obj); // ... why? Also in official lib + return tr->cnt; // same weird return as in official lib +} + +int i2cRtos_slave_write(i2c_t *obj, const char *data, int length) +{ + if(length <= 0) { + return(0); + } + int ch = i2c_get_channel(obj); + volatile struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? + tr->obj=obj; + tr->cmd=writeSlv; + tr->len=length; + tr->cnt=0; + tr->wData=data; + I2C_DAT(obj) = data[0]; + i2cRtos_wait_and_see(obj, ch, 1+(length>>2)); // timeout (1+len/4)ms + int status = tr->stat; + if(status!=0xC0 && status!=0xC8) { + i2c_stop(obj); + } + i2c_clear_SI(obj); // ... why? Also in official lib + return tr->cnt; +} + +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2cRtos_api.h Sat May 04 16:47:56 2013 +0000 @@ -0,0 +1,45 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_I2CRTOS_API_H +#define MBED_I2CRTOS_API_H + +#include "i2c_api.h" + +#if DEVICE_I2C + +#ifdef __cplusplus +extern "C" { +#endif + void i2cRtos_init(i2c_t *obj, PinName sda, PinName scl); + + int i2cRtos_read(i2c_t *obj, int address, char *data, int length, int stop); + int i2cRtos_write(i2c_t *obj, int address, const char *data, int length, int stop); + int i2cRtos_byte_read(i2c_t *obj, int last); + int i2cRtos_byte_write(i2c_t *obj, int data); + +#if DEVICE_I2CSLAVE + int i2cRtos_slave_receive(i2c_t *obj, uint32_t tmOut); + int i2cRtos_slave_read(i2c_t *obj, char *data, int length); + int i2cRtos_slave_write(i2c_t *obj, const char *data, int length); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif