本次研究了一下APM32F411的I2C接口功能。看了一下官方例子是使用的中断模式,感觉不太方便。这里我就不使用中断模式操作I2C接口。
首先初始化I2C接口IO和外设:使用PB8和PB9的I2C1外设。
void drv_i2c_gpio_init( void )
{
GPIO_Config_T gpioConfigStruct;
/* Enable I2C related Clock */
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOB);
#ifdef I2C_USE_GPIO
#else
I2C_Config_T i2cConfigStruct;
gpioConfigStruct.mode = GPIO_MODE_AF;
gpioConfigStruct.speed = GPIO_SPEED_50MHz;
gpioConfigStruct.pin = GPIO_PIN_8 | GPIO_PIN_9;
gpioConfigStruct.otype = GPIO_OTYPE_OD;
gpioConfigStruct.pupd = GPIO_PUPD_UP;
GPIO_Config(GPIOB, &gpioConfigStruct);
/* Free I2C_SCL and I2C_SDA */
GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_8, GPIO_AF_I2C1);
GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_9, GPIO_AF_I2C1);
/* Config I2C1 */
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_I2C1);
I2C_Reset(I2C1);
i2cConfigStruct.mode = I2C_MODE_I2C;
i2cConfigStruct.dutyCycle = I2C_DUTYCYCLE_2;
i2cConfigStruct.ackAddress = I2C_ACK_ADDRESS_7BIT;
i2cConfigStruct.ownAddress1 = 0XA0;
i2cConfigStruct.ack = I2C_ACK_DISABLE;
i2cConfigStruct.clockSpeed = 100000;
I2C_Config(I2C1, &i2cConfigStruct);
I2C_DisableDualAddress(I2C1);
/* Enable I2Cx */
I2C_Enable(I2C1);
#endif
}
下面就是我的I2C读写接口:
static int __CheckErrFlag(I2C_T* i2c)
{
int bflag;
bflag = 0;
if(I2C_ReadStatusFlag(i2c, I2C_FLAG_BERR)) //
{
bflag =1;
I2C_ClearStatusFlag(i2c, I2C_FLAG_BERR); //
}
if(I2C_ReadStatusFlag(i2c, I2C_FLAG_AL)) //
{
bflag =2;
I2C_ClearStatusFlag(i2c, I2C_FLAG_AL); //
}
if(I2C_ReadStatusFlag(i2c, I2C_FLAG_AE)) //
{
bflag =3;
I2C_ClearStatusFlag(i2c, I2C_FLAG_AE); //
}
if(I2C_ReadStatusFlag(i2c, I2C_FLAG_OVRUR)) //
{
bflag =4;
I2C_ClearStatusFlag(i2c, I2C_FLAG_OVRUR); //
}
if(I2C_ReadStatusFlag(i2c, I2C_FLAG_PECE)) //
{
bflag =5;
I2C_ClearStatusFlag(i2c, I2C_FLAG_PECE); //
}
if(I2C_ReadStatusFlag(i2c, I2C_FLAG_TTE)) //
{
bflag =6;
I2C_ClearStatusFlag(i2c, I2C_FLAG_TTE); //
}
if(I2C_ReadStatusFlag(i2c, I2C_FLAG_SMBALT)) //
{
bflag =7;
I2C_ClearStatusFlag(i2c, I2C_FLAG_SMBALT); //
}
return bflag;
}
static int __WaitEvtTimeout(I2C_T* i2c, I2C_EVENT_T evt)
{
volatile uint32_t timeout;
timeout = 10000;
while (!I2C_ReadEventStatus(i2c, evt))
{
timeout--;
if(timeout == 0)
{
return -1;
}
if(__CheckErrFlag(i2c))
{
return 1;
}
}
return 0;
}
uint8_t I2C_WriteByte(uint8_t index,uint32_t dev_addr, uint32_t addr,uint8_t Byte)
{
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET) //bus busy
{
I2C_EnableGenerateStop(I2C1);
delay_us(15);
break;
}
/* Send START condition */
I2C_EnableGenerateStart(I2C1);
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //wait flag
/* Send address for write */
I2C_Tx7BitAddress(I2C1, dev_addr << 1, I2C_DIRECTION_TX);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //wait flag
/* Send the current byte */
I2C_TxData(I2C1,addr &0xff);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
/* Send the current byte */
I2C_TxData(I2C1,Byte);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
I2C_EnableGenerateStop(I2C1);
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET);
return 0;
}
uint8_t I2C_ReadByte (uint8_t index,uint32_t dev_addr, uint32_t addr)
{
uint8_t buff;
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET) //bus busy
{
I2C_EnableGenerateStop(I2C1);
delay_us(15);
break;
}
/* Send START condition */
I2C_EnableGenerateStart(I2C1);
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //wait flag
/* Send address for write */
I2C_Tx7BitAddress(I2C1, dev_addr << 1, I2C_DIRECTION_TX);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //wait flag
/* Send the current byte */
I2C_TxData(I2C1,addr &0xff);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
/* Send START condition */
I2C_EnableGenerateStart(I2C1);
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //wait flag
/* Send address for write */
I2C_Tx7BitAddress(I2C1, dev_addr << 1, I2C_DIRECTION_RX);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //wait flag
I2C_DisableAcknowledge(I2C1);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED);
/* Recv the current byte */
buff = I2C_RxData(I2C1);
I2C_EnableGenerateStop(I2C1);
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET);
return buff;
}
uint8_t I2C_PageWrite(uint8_t index,uint32_t dev_addr, uint32_t addr,uint8_t *str,uint32_t num)
{
uint32_t i;
if((num == 0)||(str==NULL)) return 1;
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET) //bus busy
{
I2C_EnableGenerateStop(I2C1);
delay_us(15);
break;
}
/* Send START condition */
I2C_EnableGenerateStart(I2C1);
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //wait flag
/* Send address for write */
I2C_Tx7BitAddress(I2C1, dev_addr << 1, I2C_DIRECTION_TX);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //wait flag
/* Send the current byte */
I2C_TxData(I2C1,addr &0xff);
for(i=num;i>0;i--)
{
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
/* Send the current byte */
I2C_TxData(I2C1,*str++);
}
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
I2C_EnableGenerateStop(I2C1);
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET);
return 0;
}
uint8_t I2C_PageRead (uint8_t index,uint32_t dev_addr, uint32_t addr,uint8_t *str,uint32_t num)
{
uint32_t i;
if((num == 0)||(str==NULL)) return 1;
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET) //bus busy
{
I2C_EnableGenerateStop(I2C1);
delay_us(15);
break;
}
/* Send START condition */
I2C_EnableGenerateStart(I2C1);
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //wait flag
/* Send address for write */
I2C_Tx7BitAddress(I2C1, dev_addr << 1, I2C_DIRECTION_TX);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //wait flag
/* Send the current byte */
I2C_TxData(I2C1,addr &0xff);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
/* Send START condition */
I2C_EnableGenerateStart(I2C1);
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //wait flag
/* Send address for write */
I2C_Tx7BitAddress(I2C1, dev_addr << 1, I2C_DIRECTION_RX);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //wait flag
for(i=num-1;i>0;i--)
{
I2C_EnableAcknowledge(I2C1);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED);
/* Recv the current byte */
*str++ = I2C_RxData(I2C1);
}
I2C_DisableAcknowledge(I2C1);
__WaitEvtTimeout(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED);
/* Recv the current byte */
*str++ = I2C_RxData(I2C1);
I2C_EnableGenerateStop(I2C1);
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET);
return 0;
}
调试这个I2C花了不少时间,主要是这个时序状态。我这里是用逻辑分析仪一步步慢慢调试出来的。
下面是一个检测I2C设备地址的函数,检测总线上设备。通过shell来检查地址状态。
static int __AddrDetect(uint8_t addr)
{
uint32_t bflag;
while (I2C_ReadStatusFlag(I2C1, I2C_FLAG_BUSBSY) == SET) //bus busy
{
I2C_EnableGenerateStop(I2C1);
delay_us(15);
break;
}
/* Send START condition */
I2C_EnableGenerateStart(I2C1);
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //wait flag
/* Send address for write */
I2C_Tx7BitAddress(I2C1, addr << 1, I2C_DIRECTION_TX);
bflag = 0;
while (! I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
delay_us(25);
bflag = __CheckErrFlag(I2C1);
if(bflag) break;
}
delay_us(10);
I2C_EnableGenerateStop(I2C1);
return bflag;
}
#if UART_SHELL == 2
#include "nr_micro_shell.h"
void I2C_AddrDetect(char argc, char *argv)
{
int i,j;
printf("Detect I2C addr:\r\n");
for(i=0;i<8;i++)
{
for(j=0;j<16;j++)
{
if(__AddrDetect(j + i*16) == 0) printf("%02X ",j + i*16);
else printf("-- ");
delay_ms(1);
}
printf("\r\n");
}
printf("\r\nDetect I2C addr over.\r\n");
}
NR_SHELL_CMD_EXPORT(i2c_detect, I2C_AddrDetect, "I2C detect device address");
#endif
这里我板子上接了4个I2C设备。分别是光照的RPR0521RS,3轴加速度BM1422,气压BM1383,和温湿度SHTC3。
接下来我们看看设备检测效果:
可以看到检测了4个地址设备了。
设备驱动都写好了测试成功,也可以通过shell读取数据了:
|
共1人点赞
|