EFM32 硬件I2C操作

来源:互联网 发布:网络诗选 编辑:程序博客网 时间:2024/04/29 03:28

有关的例程,请参考如下:

#include "efm32.h"#include "em_chip.h"#include "em_cmu.h"#include "em_emu.h"#include "em_gpio.h"#include "em_i2c.h"#include "I2C_hw.h"unsigned long i2c_error = 0;void I2C_WaitForAck(void);void I2C_Buslock_Process(void);void I2C_IO_Initial(void){    i2c_error = 0;        /* Enabling clock to the I2C, GPIO*/    CMU_ClockEnable(cmuClock_GPIO, true);    CMU_ClockEnable(cmuClock_I2C0, true);        /* Using PC6 (SDA) and PC7 (SCL) */    GPIO_PinModeSet(gpioPortD, 6, gpioModeWiredAndPullUpFilter, 1);    GPIO_PinModeSet(gpioPortD, 7, gpioModeWiredAndPullUpFilter, 1);          /* Enable pins at location 2 */    I2C0->ROUTE = (I2C_ROUTE_SDAPEN |I2C_ROUTE_SCLPEN |I2C_ROUTE_LOCATION_LOC1);        I2C0->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX | I2C_CMD_ABORT;        I2C0->CTRL &= ~_I2C_CTRL_MASK;    /* Set the CLHR (clock low to high ratio). */    I2C0->CTRL |= i2cClockHLRStandard <<_I2C_CTRL_CLHR_SHIFT;    // Set SCK clock low timeout and bus idle timeout    I2C0->CTRL |= I2C_CTRL_CLTO_1024PPC | I2C_CTRL_GIBITO | I2C_CTRL_BITO_160PCC;    // Set auto STOP when NACK    I2C0->CTRL |= I2C_CTRL_AUTOSN;        /* Frequency is given by fSCL = fHFPERCLK/((Nlow + Nhigh)(DIV + 1) + 4), thus */    /* DIV = ((fHFPERCLK - 4fSCL)/((Nlow + Nhigh)fSCL)) - 1 */    //Assume system clock = 1000000, i2c clock = 30kHz;    //div = (1000000 - (4 * 30000)) / (8 * 30000) = 3.67 = 4;    //CLKDIV = div - 1;    I2C0->CLKDIV = 16;        NVIC_ClearPendingIRQ(I2C0_IRQn);    I2C0->IFC = _I2C_IFC_MASK;        //I2C0->IEN = I2C_IEN_ARBLOST | I2C_IEN_CLTO | I2C_IEN_BITO | I2C_IEN_NACK | I2C_IEN_BUSERR;    //NVIC_EnableIRQ(I2C0_IRQn);        BITBAND_Peripheral(&(I2C0->CTRL),_I2C_CTRL_EN_SHIFT,true);}unsigned char I2C_SentData(unsigned char Address, unsigned short Offset, unsigned char Data){    //Perpare for a new transmit    I2C0->CMD = I2C_CMD_ABORT;    I2C0->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;        //Clear all the flags    I2C0->IFC = _I2C_IFC_MASK;        //Begin to transmit    I2C0->CMD = I2C_CMD_START;                   //Start    I2C0->TXDATA = Address | I2C_WRITE_COMMAND;  //I2C hardware address    I2C_WaitForAck();                                    I2C0->TXDATA  = Offset;                      //I2C internal address    I2C_WaitForAck();        I2C0->TXDATA = Data;                         //I2C data     I2C_WaitForAck();        I2C0->CMD = I2C_CMD_STOP;                    //Stop        unsigned char Result = i2c_error;    i2c_error = 0;    return Result;}unsigned char I2C_ReadData(unsigned char Address, unsigned short Offset, unsigned char *Rx){    //Perpare for a new transmit    I2C0->CMD = I2C_CMD_ABORT;    I2C0->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;      //Clear all the flags    I2C0->IFC = _I2C_IFC_MASK;        //Begin to transmit    I2C0->CMD = I2C_CMD_START;                   //S    I2C0->TXDATA = Address | I2C_WRITE_COMMAND;  //AD+W hardware address    I2C_WaitForAck();        I2C0->TXDATA  = Offset;                      //internal register address    I2C_WaitForAck();        I2C0->CMD = I2C_CMD_START;                   //S    I2C0->TXDATA = Address | I2C_READ_COMMAND;   //AD+R internal register address    I2C_WaitForAck();        while(!((I2C0->IF) & I2C_IF_RXDATAV));    *Rx = (unsigned char)(I2C0->RXDATA);    I2C0->CMD = I2C_CMD_NACK;                     //NACK    I2C0->CMD = I2C_CMD_STOP;                     //P        unsigned char Result = i2c_error;    i2c_error = 0;     return Result;}void I2C_WaitForAck(void){    while(!((I2C0->IF) & I2C_IF_ACK))    {        //STOP auto send        if(i2c_error)        {            break;        }    }    I2C0->IFC = _I2C_IFC_MASK;}void I2C0_IRQHandler(void){    static unsigned char Arblost = 0;    unsigned long Flag = I2C0->IF;    if(Flag & I2C_IF_NACK)    {        //auto STOP send        i2c_error = 1;    }    if(Flag & I2C_IF_BUSERR)    {        I2C0->CMD = I2C_CMD_ABORT;        I2C0->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;        i2c_error = 1;    }        if(Flag & I2C_IF_ARBLOST)    {        //arbitration losses, maybe SDA is stuck        if(Arblost++ > 5)        {            Arblost = 0;            I2C_Buslock_Process();        }        i2c_error = 1;    }    if((Flag & I2C_IF_CLTO) || (Flag & I2C_IF_BITO))    {        I2C_Buslock_Process();        i2c_error = 1;    }        I2C0->IFC = Flag;}void I2C_Buslock_Process(void){    unsigned long Delay = 1000;        //Disable I2C module, and clearing the route register    BITBAND_Peripheral(&(I2C0->CTRL),_I2C_CTRL_EN_SHIFT,false);    I2C0->ROUTE = 0;    //Set as pushpull mode    GPIO_PinModeSet(gpioPortD, 6, gpioModePushPull, 1);//SDA    GPIO_PinModeSet(gpioPortD, 7, gpioModePushPull, 1);//SCL        //send 9 clock of SCL    for(unsigned char i = 0; i < 9; i++)    {        Delay = 3000;        GPIO_PinOutClear(gpioPortD, 7);        while(Delay--);        Delay = 3000;        GPIO_PinOutSet(gpioPortD, 7);        while(Delay--);    }        /* Using PD6 (SDA) and PD7 (SCL) */    GPIO_PinModeSet(gpioPortD, 7, gpioModeWiredAndPullUpFilter, 1);    GPIO_PinModeSet(gpioPortD, 6, gpioModeWiredAndPullUpFilter, 1);          /* Enable pins at location 2 */    I2C0->ROUTE = (I2C_ROUTE_SDAPEN |I2C_ROUTE_SCLPEN |I2C_ROUTE_LOCATION_LOC1);    //enable again    BITBAND_Peripheral(&(I2C0->CTRL),_I2C_CTRL_EN_SHIFT,true);   }

在以上代码中,并没有使能硬件I2C的中断,因此也不会调用I2C_Buslock_Process()函数。另外,针对该函数,目前也还没有做过功能验证,我只能通过短接SCL和SDA来测试。

I2C_Buslock_Process()原意是当I2C总线死锁的时候,控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情况),这样I2C从设备就可以完成被挂起的读操作,从死锁状态中恢复过来。

在主函数中的调用方式如下:

I2C_SentData(SLAVE_ADDRESS, PWR_MGMT_1,   0x00);
I2C_ReadData(Address, RegAddress+1, &L);



2 0