1 背景
基于 GD32F470ZGT6 进行 SHT31-DIS 模块移植时,I2C通信失败。进行调试后,发现当代码执行完 i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER) 语句后,I2C_FLAG_ADDSEND 始终为 0,关键代码如下:
#define I2C0_SLAVE_ADDRESS7 0x44
……
// wait until I2C bus is idle
while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) == SET);
// transmit start signal
i2c_start_on_bus(I2C0);
// wait until SBSEND flag = 1
while(i2c_flag_get(I2C0, I2C_FLAG_SBSEND) == RESET);
// transmit header
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
// wait until ADDSEND flag = 1
while(i2c_flag_get(I2C0, I2C_FLAG_ADDSEND) == RESET);
……
查看 SHT31-DIS 数据手册可知,其默认 I2C 地址为 0x44,故进行上述宏定义 #define I2C0_SLAVE_ADDRESS7 0x44。

2 问题排查
查看官方固件库 gd32f4xx_i2c.c 中 i2c_master_addressing(uint32_t i2c_periph, uint32_t addr, uint32_t trandirection) 函数定义,代码如下:
/*!
\brief master sends slave address
\param[in] i2c_periph: I2Cx(x=0,1,2)
\param[in] addr: slave address
\param[in] trandirection: transmitter or receiver
only one parameter can be selected which is shown as below:
\arg I2C_TRANSMITTER: transmitter
\arg I2C_RECEIVER: receiver
\param[out] none
\retval none
*/
void i2c_master_addressing(uint32_t i2c_periph, uint32_t addr, uint32_t trandirection)
{
/* master is a transmitter or a receiver */
if(I2C_TRANSMITTER == trandirection) {
addr = addr & I2C_TRANSMITTER;
} else {
addr = addr | I2C_RECEIVER;
}
/* send slave address */
I2C_DATA(i2c_periph) = addr;
}
可知:如果形参 trandirection 传入 I2C_TRANSMITTER((uint32_t)0xFFFFFFFEU),则将 addr(7位 I2C 地址) 最低位置 0;如果形参 trandirection 传入 I2C_RECEIVER((uint32_t)0x00000001U),则将 addr(7位 I2C 地址) 最低位置 1。
而 SHT31-DIS 数据手册给出的 I2C 通信示例是在 7 位 I2C 地址后添加一位 0/1 形成形成一个字节的 I2C write/read header,如下所示:

3 解决办法
将宏定义 #define I2C0_SLAVE_ADDRESS7 0x44 改写为 #define I2C0_SLAVE_ADDRESS7 (0x44 << 1)。