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

I2CDriver.cpp

Committer:
humlet
Date:
2013-04-14
Revision:
1:90455d5bdd8c
Parent:
0:13c962fecb13
Child:
2:514105beb343

File content as of revision 1:90455d5bdd8c:

#include "I2CDriver.h"
#include "error.h"

using namespace mbed;
using namespace rtos;

#define ISR2DRV_SIG (1<<7)
#define DRV_USR_SIG (1<<6)

const PinName I2CDriver::c_sdas[] = {p9,p28};
const PinName I2CDriver::c_scls[] = {p10,p27};

I2CDriver::Channel* I2CDriver::s_channels[2] = {0,0};


void I2CDriver::channel_0_ISR()
{
    osSignalSet( s_channels[0]->driver, ISR2DRV_SIG);
    NVIC_DisableIRQ(I2C1_IRQn);
}


void I2CDriver::channel_1_ISR()
{
    osSignalSet( s_channels[1]->driver, ISR2DRV_SIG);
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    NVIC_DisableIRQ(I2C2_IRQn);
#elif defined(TARGET_LPC11U24)
    NVIC_DisableIRQ(I2C_IRQn);
#endif
}


void I2CDriver::threadFun(void const *args)
{
    int channelIdx = (int)args;
    Channel channel;
    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
    I2C i2c(c_sdas[channelIdx], c_scls[channelIdx]);
    volatile Transfer& tr = channel.transfer;
    while(1) {
        // wait for requests
        osSignalWait(DRV_USR_SIG,osWaitForever);
        // check and adapt frequency
        if(channel.freq != tr.freq) {
            channel.freq = tr.freq;
            i2c.frequency(tr.freq);
        }
        // just doit
        switch(tr.cmd) {
            case START:
                i2c.start();
                break;
            case STOP:
                i2c.stop();
                break;
            case READ:
                tr.ret = i2c.read(tr.adr, tr.dta, tr.len, tr.rep);
                break;
            case READ_FROM_REGISTER:
                tr.ret = i2c.write(tr.adr,(const char*)&(tr.reg), 1, true);
                if(tr.ret)break; // error => bail out
                tr.ret = i2c.read(tr.adr, tr.dta, tr.len, tr.rep);
                break;
            case READ_BYTE:
                tr.ret = i2c.read(tr.ack);
                break;
            case WRITE:
                tr.ret = i2c.write(tr.adr, tr.wdta, tr.len, tr.rep);
                break;
            case WRITE_BYTE:
                tr.ret = i2c.write(tr.ack);
                break;
            default:
                error("call 911");
        }
        // inform the caller
        osSignalSet( channel.transfer.caller, DRV_USR_SIG);
    }
}


I2CDriver::I2CDriver(PinName sda, PinName scl):I2C(sda,scl)
{
    // check pins and determine i2c channel
    int channel=0;
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    if(sda==c_sdas[0] && scl==c_scls[0]) channel=0; // I2C_1
    else
#endif
        if (sda==c_sdas[1] && scl==c_scls[1]) channel=1; //I2C_2 or I2C
        else error("I2CDriver: Invalid I2C pinns selected");
    if(s_channels[channel]==0)
        new Thread(threadFun,(void *)channel,osPriorityRealtime);
    m_channel = s_channels[channel];
}


void I2CDriver::sendNwait()
{
    m_channel->transfer.freq = _hz;
    m_channel->transfer.caller = Thread::gettid();
    osSignalSet( m_channel->driver, DRV_USR_SIG);
    osSignalWait(DRV_USR_SIG,osWaitForever);
}


int I2CDriver::read(int address, char *data, int length, bool repeated)
{
    lock();
    m_channel->transfer.cmd = READ;
    m_channel->transfer.adr = address;
    m_channel->transfer.dta = data;
    m_channel->transfer.len = length;
    m_channel->transfer.rep = repeated;
    sendNwait();
    int ret = m_channel->transfer.ret;
    unlock();
    return ret;
}


int I2CDriver::read(int address, uint8_t regist, char *data, int length, bool repeated)
{
    lock();
    m_channel->transfer.cmd = READ_FROM_REGISTER;
    m_channel->transfer.adr = address;
    m_channel->transfer.reg = regist;
    m_channel->transfer.dta = data;
    m_channel->transfer.len = length;
    m_channel->transfer.rep = repeated;
    sendNwait();
    int ret = m_channel->transfer.ret;
    unlock();
    return ret;
}

int I2CDriver::read(int ack)
{
    lock();
    m_channel->transfer.cmd = READ_BYTE;
    m_channel->transfer.ack = ack;
    sendNwait();
    int ret = m_channel->transfer.ret;
    unlock();
    return ret;
}

int I2CDriver::write(int address, const char *data, int length, bool repeated)
{
    lock();
    m_channel->transfer.cmd = WRITE;
    m_channel->transfer.adr = address;
    m_channel->transfer.wdta = data;
    m_channel->transfer.len = length;
    m_channel->transfer.rep = repeated;
    sendNwait();
    int ret = m_channel->transfer.ret;
    unlock();
    return ret;
}

int I2CDriver::write(int data)
{
    lock();
    m_channel->transfer.cmd = WRITE_BYTE;
    m_channel->transfer.ack = data;
    sendNwait();
    int ret = m_channel->transfer.ret;
    unlock();
    return ret;
}

void I2CDriver::start(void)
{
    lock();
    m_channel->transfer.cmd = START;
    sendNwait();
    unlock();
}


void I2CDriver::stop(void)
{
    lock();
    m_channel->transfer.cmd = STOP;
    sendNwait();
    unlock();
}