标签:
有关的例程,请参考如下:
#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);
标签:
原文地址:http://blog.csdn.net/efm32/article/details/43530253