**
解决 realtek 库函数方式实现出现的 iic clock strech 时钟拉伸问题
**
很多小伙伴应该都用过 iic 但是接触过时钟拉伸这个细节的估计不多
简单的说就是通信过程中主机每次控制时钟线的电平需要判断从机是否准备好
在拉高时钟脚时需先切换成输入状态判断从机是否拉低时钟脚
如果从机拉住时钟脚 说明从机没有准备就绪 主机不能强行拉高 需等待从机释放
用realtek当主控和某器件通信 发现偶现一些不正常的现象 抓取逻辑分析仪看数据有时钟脉冲不均匀的情况
于是用示波器抓取发现有时钟线半高的电平
realtek的初始化函数并没有一个给用户设置时钟拉伸最大等待从机就绪超时的地方
但是 iic 写函数和读函数都包含了一个变量I2C_TimeOut 从代码看就是起这个作用的
/*** \brief Send data in master mode through the I2Cx peripheral.* \param I2Cx: Select the I2C peripheral. \ref I2C_Declaration* \param pBuf: Byte to be transmitted.* \param len: Data length to send.* \return I2C_Status: The status of I2Cx. \ref I2C_Status*/
I2C_Status I2C_MasterWrite(I2C_TypeDef *I2Cx, uint8_t *pBuf, uint16_t len)
{uint16_t cnt = 0;uint32_t time_out = I2C_TimeOut;I2C_Status abort_status = I2C_Success;/* Check the parameters */assert_param(IS_I2C_ALL_PERIPH(I2Cx));/* Write in the DR register the data to be sent */for (cnt = 0; cnt < len; cnt++){if (cnt >= len - 1){/*generate stop signal*/I2Cx->IC_DATA_CMD = (*pBuf++) | I2C_0X10_STOP;}else{I2Cx->IC_DATA_CMD = *pBuf++;}/* wait for flag of I2C_FLAG_TFNF */time_out = I2C_TimeOut;while (((I2Cx->IC_STATUS & I2C_FLAG_TFNF) == 0) && (time_out != 0)){/* Check abort status */abort_status = I2C_CheckAbortStatus(I2Cx);if (abort_status != I2C_Success){return abort_status;}time_out--;if (time_out == 0){return I2C_ERR_TIMEOUT;}}/* Check abort status */abort_status = I2C_CheckAbortStatus(I2Cx);if (abort_status != I2C_Success){return abort_status;}}while (((I2C_GetFlagState(I2Cx, I2C_FLAG_ACTIVITY) == SET) || \(I2C_GetFlagState(I2Cx, I2C_FLAG_TFE) != SET)) && (time_out != 0)){abort_status = I2C_CheckAbortStatus(I2Cx);if (abort_status != I2C_Success){return abort_status;}time_out--;if (time_out == 0){return I2C_ERR_TIMEOUT;}}return abort_status;
}
I2C_Status I2C_RepeatRead(I2C_TypeDef *I2Cx, uint8_t *pWriteBuf, uint16_t Writelen,uint8_t *pReadBuf, uint16_t Readlen)
{uint16_t cnt = 0;uint32_t reg_value = 0;uint32_t time_out = I2C_TimeOut;I2C_Status abort_status = I2C_Success;/* Check the parameters */assert_param(IS_I2C_ALL_PERIPH(I2Cx));/*------------------------------ write data section ------------------------------*//* write data in the IC_DATA_CMD register */for (cnt = 0; cnt < Writelen; cnt++){I2Cx->IC_DATA_CMD = *pWriteBuf++;/*wait for I2C_FLAG_TFNF flag that Tx FIFO is not full*/time_out = I2C_TimeOut;while (((I2Cx->IC_STATUS & I2C_FLAG_TFNF) == 0) && (time_out != 0)){/* Check abort status */abort_status = I2C_CheckAbortStatus(I2Cx);if (abort_status != I2C_Success){return abort_status;}time_out--;if (time_out == 0){return I2C_ERR_TIMEOUT;}}/* Check abort status */abort_status = I2C_CheckAbortStatus(I2Cx);if (abort_status != I2C_Success){return abort_status;}}/*------------------------------ read data section ------------------------------*/for (cnt = 0; cnt < Readlen; cnt++){if (cnt >= Readlen - 1){/*generate stop singal in last byte which to be sent*/I2Cx->IC_DATA_CMD = reg_value | I2C_0X10_CMD | I2C_0X10_STOP;}else{I2Cx->IC_DATA_CMD = reg_value | I2C_0X10_CMD;}/*wait for I2C_FLAG_RFNE flag*/time_out = I2C_TimeOut;while (((I2Cx->IC_STATUS & I2C_FLAG_RFNE) == 0) && (time_out != 0)){/* Check abort status */abort_status = I2C_CheckAbortStatus(I2Cx);if (abort_status != I2C_Success){return abort_status;}time_out--;if (time_out == 0){return I2C_ERR_TIMEOUT;}}*pReadBuf++ = (uint8_t)I2Cx->IC_DATA_CMD;}return abort_status;
}
realtek官方原生的 iic 库默认写的0xFFFFF 我们加一个 f 改成6个f 验证正常