本帖最后由 fox1 于 2024-12-4 21:28 编辑
大佬们,在做一个MEMS芯片的驱动移植,他的i2c read时序比较奇怪,是先1 START -> 2 SLA+W 【收ACK】->3 发读取的寄存器地址【收ACK】->4 START -> 5 SLA+R 【收ACK】->接收数据 -> END 最后发STOP
我看cw32l010的用户手册
状态间没有切换的,如果我第3步发完寄存器收完ACK后,直接重新发送起始信号,会报错吗?
根据时序图写的代码这样子:
----------------已经解决了,正确代码-------------------
I2C_ErrorDef I2C_QMA6100P_SEQ_READ(I2C_TypeDef *I2Cx, uint8_t regAddr, uint8_t *pu8Data, uint32_t u32Len)
{
uint8_t u8i = 0, u8State;
// 是否已发送 寄存器地址
uint8_t flag = 0;
uint8_t Qma6100PAddr = 0x24;
uint32_t timeout = I2C_TIMEOUT;
I2C_ClearIrq(I2Cx);
I2C_GenerateSTART(I2Cx, ENABLE);
while (timeout--)
{
while (timeout)
{
timeout--;
if (I2C_GetIrq(I2Cx))
{
break;
}
}
u8State = I2C_GetState(I2Cx);
switch (u8State)
{
case 0x08: // 1 发送完START信号 发送SLA+W
I2Cx->DR_f.DR = Qma6100PAddr & 0xfe;
I2Cx->CR_f.STA = 0;
I2Cx->CR_f.SI = 0;
timeout = I2C_TIMEOUT;
break;
case 0x10: // 已发送重复起始信号
// 发送完restart信号,发送SLA+R
if (flag == 1)
{
I2Cx->DR = Qma6100PAddr | 0x01;
I2Cx->CR_f.STA = 0;
I2Cx->CR_f.SI = 0;
}
timeout = I2C_TIMEOUT;
flag = 0;
break;
case 0x18: // 2.SLA+W 后收到 从机ACK,发第一个寄存器地址
// printf("I2C SLA+W ACK \r\n");
I2Cx->DR = regAddr;
I2Cx->CR_f.SI = 0;
flag = 1;
timeout = I2C_TIMEOUT;
break;
case 0x28:
// 3 发送寄存器地址,并收到ACK 发送Restart
if (flag == 1)
{
I2Cx->CR_f.STA = 0;
I2Cx->CR_f.STA = 1;
timeout = I2C_TIMEOUT;
break;
}
break;
case 0x40: // 发送完SLA+R信号,开始接收数据
if (u32Len == 1)
{
I2Cx->CR_f.AA = 0;
}
else
{
I2Cx->CR_f.AA = 1;
}
I2Cx->CR_f.SI = 0;
timeout = I2C_TIMEOUT;
break;
case 0x50: // 接收完一字节数据,在接收最后1字节数据之前设置AA=0;
pu8Data[u8i = (uint8_t)I2Cx->DR;
// pass 0x40已经过滤了U32LEN = 1 的情况
if (u8i == u32Len - 1)
{
I2Cx->CR_f.AA = 0;
}
printf("I2C 0x50 \r\n");
printf("pu8Data[%d] = %x \r\n", u8i, pu8Data[u8i - 1]);
timeout = I2C_TIMEOUT;
break;
case 0x58: // 接收到一个数据字节,且NACK已回应
pu8Data[u8i = (uint8_t)I2Cx->DR;
printf("I2C 0x58 \r\n");
printf("pu8Data[%d] = %x \r\n", u8i, pu8Data[u8i - 1]);
if (u32Len == 1 || u8i == u32Len)
{
I2C_GenerateSTOP(I2Cx);
I2C_ClearIrq(I2Cx);
return I2C_NO_ERROR;
}
I2C_GenerateSTOP(I2Cx);
I2C_ClearIrq(I2Cx);
return I2C_MR_DATA_NACK;
case 0x38: // 主机在发送 SLA+W 阶段或者发送数据阶段丢失仲载 或者 主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
I2C_GenerateSTOP(I2Cx);
I2C_ClearIrq(I2Cx);
return I2C_MR_ARBITRATION_LOST;
case 0x48: // 发送完SLA+R后从机返回NACK
I2C_GenerateSTOP(I2Cx);
I2C_ClearIrq(I2Cx);
return I2C_MR_ADDR_NACK;
default:
break;
}
I2C_ClearIrq(I2Cx);
}
}
|