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 I2cRtosDriver by
i2cRtos_api.c
- Committer:
- humlet
- Date:
- 2013-05-04
- Revision:
- 9:65aae53a34de
- Child:
- 10:e3d6c92ff222
File content as of revision 9:65aae53a34de:
#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
