本帖最后由 l00140627 于 2024-5-25 09:50 编辑
项目中用到gd32F103C8T6做主控单元,I2C总线挂了多个外设,如下:- I2C0:从设备是一个英飞凌mx38740电压管理芯片,走PMBus。PB8,PB9是SCL和SDA
- I2C1:从设备是一个TCA9548 I2C Switch芯片; Switch上外挂一个风扇芯片31760,一个TMP112温度芯片,走普通的I2C协议。 PB10是SCL, PB11是SDA
- 用官方硬件I2C API操作
问题:
- I2C1读取31760正常;
- I2C0读取38740失败, 逻辑分析仪时序如图1
图1 硬件API读取I2C0时序
3 软件模拟,读取I2C0也失败,逻辑分析仪时序如图2
图2 软件模拟I2C0时序
硬件I2C关键代码如下:
1) I2C初始化
/* 描述:IIC0控制器初始化
* 参数:use_remap 是否使用GPIO remep, 0 不启用, 其他 启用
speed I2C速率
i2c_address I2C地址
address_mode 地址模式(7bit或10bit)
* 返回值:无*/
void i2c0_init_ex(uint32_t speed, uint32_t i2c_address)
{
// 1 使能GPIOB端口的外设时钟
rcu_periph_clock_enable(RCU_GPIOB);
// 2 使能映射功能的时钟
rcu_periph_clock_enable(RCU_AF);
// 3 设置AFIO_PCF0寄存器的I2C0_REMAP=1;
gpio_pin_remap_config(GPIO_I2C0_REMAP,ENABLE);
// 4 I2C0_SCL映射到PB8引脚,I2C0_SDA映射到PB9引脚;
gpio_init(GPIOB,GPIO_MODE_AF_OD,GPIO_OSPEED_50MHZ,GPIO_PIN_8|GPIO_PIN_9);
// 5 使能RCU_I2C0时钟
rcu_periph_clock_enable(RCU_I2C0);
// 6 I2C0_SPEED=400000位/秒,配置I2C为快速模式,Tlow/Thigh=2;
i2c_clock_config(I2C0,speed,I2C_DTCY_2);
// 7 配置为I2C模式,I2C从机设备使用7位地址为I2C0_SLAVE_ADDRESS7(0xA0)
i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,i2c_address);
// 8 使能I2C外设
i2c_enable(I2C0);
// 9 I2C_ACK_ENABLE:ACKEN=1,允许发送ACK应答
i2c_ack_config(I2C0,I2C_ACK_ENABLE);
}
static uint8_t check_process(uint32_t i2c,i2c_flag_enum flag,uint8_t max_try, uint8_t step)
{
uint8_t count = 0;
while (!i2c_flag_get(i2c,flag))
{
count++;
if (count >= max_try)
{
return step;
}
}
return 0;
}
/* 描述:指定地址读出一个字节的数据
* 参数:ReadAddr: 需要读出数据的地址
* ReadByte: 读出的数据值的存放指针
* 返回值:0:读取成功 其他:读取错误*/
uint8_t i2c_read_byte(uint32_t i2c,uint8_t slave_addr,uint16_t ReadAddr, uint8_t addr_len,uint8_t *ReadByte)
{
uint8_t err = 0;
uint16_t count = 0;
uint8_t check_busy = 0;
int max_try = 100;
//PROCESS(i2c_flag_get(i2c, I2C_FLAG_I2CBSY),count,1);
while (i2c_flag_get(i2c,I2C_FLAG_I2CBSY))
{
count++;
if (count >= max_try)
{
i2c_deinit(i2c);
// return 1;
}
}
/* 1 发送一个起始位到I2C总线 */
i2c_start_on_bus(i2c);
if (err = check_process(i2c, I2C_FLAG_SBSEND,max_try,2)) return err;
/* 2 等待起始位发送完成 */
// while(!i2c_flag_get(i2c, I2C_FLAG_SBSEND));
/* 3 发送器件地址,写数据 */
i2c_master_addressing(i2c, slave_addr<<1, I2C_TRANSMITTER);
/* 4 等待从机地址发送完成 */
count = 0;
if (err = check_process(i2c, I2C_FLAG_ADDSEND, max_try,3)) return err;
// while(!i2c_flag_get(i2c, I2C_FLAG_ADDSEND));
/* 5 清除从机地址发送完成标志位 */
i2c_flag_clear(i2c, I2C_FLAG_ADDSEND);
/* 6 等待IIC发送区为空 */
count = 0;
if (err = check_process(i2c, I2C_FLAG_TBE, max_try,4)) return err;
// while(!i2c_flag_get(i2c, I2C_FLAG_TBE));
/* 7 IIC发送数据,AT24C02需要读出数据的地址*/
uint8_t high = (ReadAddr >> 8) & 0xFF;
uint8_t low = ReadAddr & 0xFF;
if (addr_len == 1)
{
i2c_data_transmit(i2c, low);
}
else
{
i2c_data_transmit(i2c, high);
// while(!i2c_flag_get(i2c, I2C_FLAG_TBE));
count = 0;
if (err = check_process(i2c, I2C_FLAG_TBE, max_try,5)) return err;
i2c_data_transmit(i2c, low);
}
/* 8 等待IIC发送区为空,即发送完成 */
// while(!i2c_flag_get(i2c, I2C_FLAG_TBE));
count = 0;
if (err = check_process(i2c, I2C_FLAG_TBE, max_try,6)) return err;
/* 9 再次发送一个起始位到I2C总线 */
i2c_start_on_bus(i2c);
/* 10 等待起始位发送完成 */
// while(!i2c_flag_get(i2c, I2C_FLAG_SBSEND));
count = 0;
if (err = check_process(i2c, I2C_FLAG_SBSEND, max_try,7)) return err;
/* 11 发送器件地址,读数据 */
i2c_master_addressing(i2c, slave_addr<<1, I2C_RECEIVER);
/* 12 等待从机地址发送完成 */
// while(!i2c_flag_get(i2c, I2C_FLAG_ADDSEND));
count = 0;
if (err = check_process(i2c, I2C_FLAG_ADDSEND,max_try,8)) return err;
/* 13 设置为非应答 NACK, 要在清除FLAG_ADDSEND前*/
i2c_ack_config(i2c, I2C_ACK_DISABLE);
/* 114 清除从机地址发送完成标志位 */
i2c_flag_clear(i2c, I2C_FLAG_ADDSEND);
/* 15 发送一个停止位到I2C总线 */
i2c_stop_on_bus(i2c);
/* 16 等待数据寄存器可读 */
// while(!i2c_flag_get(i2c, I2C_FLAG_RBNE));
count = 0;
if (err = check_process(i2c, I2C_FLAG_RBNE,max_try,9)) return err;
/* 17 读出接收到的数据 */
*ReadByte = i2c_data_receive(i2c);
/* 18 使能应答 ACK, */
i2c_ack_config(i2c, I2C_ACK_ENABLE);
err = 0;
return err;
}
|
|