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 Helmut Schmücker

Files at this revision

API Documentation at this revision

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

I2CDriver.cpp Show annotated file Show diff for this revision Revisions of this file
I2CDriver.h Show annotated file Show diff for this revision Revisions of this file
i2cRtos_api.c Show annotated file Show diff for this revision Revisions of this file
i2cRtos_api.h Show annotated file Show diff for this revision Revisions of this file
--- 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