在stm32f103上解决硬件I2C总是busy的问题
问题
在使用stm32f103的硬件I2C的时候,读写I2C总线总是busy,即下面的代码总是无法退出:
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))
{
;
}
解决方法
在将io管脚复用成I2C之前,先作为输出GPIO管脚,然后拉高,即下面代码里的i2c_pin_init
,并且在每次读写的时候都调用一次i2c_pin_init
,代码如下:
#include "stm32f10x.h"
#include <stdint.h>
#include <stdio.h>
#define I2C1_ADDR 0x74
#define I2C_OK 0
#define I2C_FAIL -1
/* Maximum Timeout values for flags and events waiting loops. These timeouts are
not based on accurate values, they just guarantee that the application will
not remain stuck if the I2C communication is corrupted.
You may modify these timeout values depending on CPU frequency and application
conditions (interrupts routines ...). */
#define I2C_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2C_LONG_TIMEOUT ((uint32_t)(10 * I2C_FLAG_TIMEOUT))
static i2c_pin_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
/*!< Configure pins: SCL/SDL */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void i2c_Init(void)
{
I2C_InitTypeDef I2C_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
i2c_pin_init();
I2C_DeInit(I2C1);
/*!< I2C1 Init */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C1_ADDR<<1;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
/*!< I2C1 Init */
I2C_Cmd(I2C1, ENABLE);
}
int8_t i2c_read(uint8_t devaddr, uint8_t RegName, uint8_t *buf, uint8_t len)
{
uint16_t tmp = 0;
uint32_t i2c_timeout;
uint8_t loop;
int8_t ret;
devaddr <<= 1;
i2c_pin_init();
/* Test on BUSY Flag */
i2c_timeout = I2C_LONG_TIMEOUT;
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))
{
if((i2c_timeout--) == 0) return -1;
}
/* Enable the I2C peripheral */
I2C_GenerateSTART(I2C1, ENABLE);
/* EV5 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
{
if((i2c_timeout--) == 0)
{
ret = -2;
goto I2CR_ERR;
}
}
/* Transmit the slave address and enable writing operation */
I2C_Send7bitAddress(I2C1, devaddr, I2C_Direction_Transmitter);
/* EV6 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((i2c_timeout--) == 0)
{
ret = -3;
goto I2CR_ERR;
}
}
/* Transmit the register address */
I2C_SendData(I2C1, RegName);
/* EV8 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
{
if((i2c_timeout--) == 0)
{
ret = -4;
goto I2CR_ERR;
}
}
/* Enable the I2C peripheral */
I2C_GenerateSTART(I2C1, ENABLE);
/* EV5 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
{
if((i2c_timeout--) == 0)
{
ret = -5;
goto I2CR_ERR;
}
}
/* Send address for read */
I2C_Send7bitAddress(I2C1, devaddr, I2C_Direction_Receiver);
/* EV6 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if((i2c_timeout--) == 0)
{
ret = -6;
goto I2CR_ERR;
}
}
for (loop=0; loop<len; loop++)
{
if (loop == (len-1))
{
I2C_AcknowledgeConfig(I2C1, DISABLE);
/* Send STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
{
if((i2c_timeout--) == 0)
{
ret = -7;
goto I2CR_ERR;
}
}
buf[loop] = I2C_ReceiveData(I2C1);
}
I2C_AcknowledgeConfig(I2C1, ENABLE);
/* return a Reg value */
return I2C_OK;
I2CR_ERR:
I2C_GenerateSTOP(I2C1, ENABLE);
return ret;
}
int8_t i2c_write(uint8_t devaddr, uint8_t RegName, uint8_t *buf, uint8_t len)
{
uint32_t i2c_timeout;
uint8_t loop;
int8_t ret = I2C_OK;
devaddr <<= 1;
i2c_pin_init();
/* Test on BUSY Flag */
i2c_timeout = I2C_LONG_TIMEOUT;
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))
{
if((i2c_timeout--) == 0) return -1;
}
/* Enable the I2C peripheral */
I2C_GenerateSTART(I2C1, ENABLE);
/* EV5 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
{
if((i2c_timeout--) == 0)
{
ret = -2;
goto I2CW_ERR;
}
}
/* Transmit the slave address and enable writing operation */
I2C_Send7bitAddress(I2C1, devaddr, I2C_Direction_Transmitter);
/* EV6 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if((i2c_timeout--) == 0)
{
ret = -3;
goto I2CW_ERR;
}
}
/* Transmit the register address for r/w operations */
I2C_SendData(I2C1, RegName);
i2c_timeout = I2C_FLAG_TIMEOUT;
/* EV8 */
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
{
if((i2c_timeout--) == 0)
{
ret = -4;
goto I2CW_ERR;
}
}
for (loop=0; loop<len-1; loop++)
{
I2C_SendData(I2C1, buf[loop]);
/* EV8 */
i2c_timeout = I2C_FLAG_TIMEOUT;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
{
if((i2c_timeout--) == 0)
{
ret = -5;
goto I2CW_ERR;
}
}
}
I2C_SendData(I2C1, buf[loop]);
i2c_timeout = I2C_FLAG_TIMEOUT;
/* EV8-2 */
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if((i2c_timeout--) == 0)
{
ret = -6;
goto I2CW_ERR;
}
}
I2CW_ERR:
/* Send STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
return ret;
}