STM32 L4 低级 I2C 主机,第一次写入是 ACK,第二次写入是 ACK,但在代码中始终是 NACK

STM32 L4 Low Level I2C Master, first write is ACK, second write is ACK but always NACK in code

提问人:Paris Molver 提问时间:10/2/2023 更新时间:10/2/2023 访问量:80

问:

我已经在这个问题上工作了几个小时。我有代码可以将移动的 LED 推过几个 I2C GPIO 扩展器PCA9555。我什至可以阅读,但是当我在这里和那里修复一些错误时,我发现 I2C 的可用性越来越低。当我启动程序时,它需要将端口设置为输出,以便前几次写入相同的PCA9555。

第一次写入是成功的。

第一次写入

第二次写入始终是 NACK 指令,尽管示波器显示 0100 0000 0 位流

第二次写入

我也以 10Khz 的速度运行它,所以这个速度应该足够慢,以避免在我开发软件时出现噪音失真。

我的旧代码将继续编写移动的 LED 图案。如果它被锁定,它将重新启动,因为“if (I2CTimeout-- == 0)”将环绕并触发看门狗。但是,它运行了相当长一段时间。

I2C_Error_t driver_I2C_Write(I2C_TypeDef *_I2C, uint8_t devAddr, uint8_t* buffer, uint16_t len)
{
    I2C_Error_t result = I2C_ERROR_UNKNOWN;
    int counter = 0;
    uint32_t I2CTimeout;
    uint8_t *pTransmitBuffer = buffer;
    uint8_t read_write = 0;

    taskENTER_CRITICAL();

    I2CTimeout = _I2C_LONG_TIMEOUT;
    while (LL_I2C_IsActiveFlag_BUSY(_I2C))
    {
        if (LL_SYSTICK_IsActiveCounterFlag())
        {
            if (I2CTimeout-- == 0)
            {
                result = I2C_ERROR_BUSY;
                LL_I2C_TransmitData8(_I2C, 0);
                LL_I2C_TransmitData8(_I2C, 0);
                goto EXIT;
            }
        }
        vTaskDelay(1);
    }

    // HandleTransfer will preload the registers with the address, the R/W bit
    // It generates the start condition and sends the address + R/W bits.
    LL_I2C_SetMasterAddressingMode(_I2C, LL_I2C_ADDRESSING_MODE_7BIT);
    LL_I2C_SetSlaveAddr(_I2C, devAddr);
    LL_I2C_SetTransferRequest(_I2C, LL_I2C_REQUEST_WRITE);
    LL_I2C_DisableAutoEndMode(_I2C);
    LL_I2C_SetTransferSize(_I2C, len);

    LL_I2C_GenerateStartCondition(_I2C);

    if(!LL_I2C_IsActiveFlag_TXIS(_I2C))
    {
        result = I2C_ERROR_ADD_NACK;
        // Handle Transfer will not generate the stop condition?
        // LL_I2C_GenerateStopCondition(_I2C);
    }

    // Now that the start condition is active, we can transmit until
    // N_Bytes are sent and the stop condition is automatically generated
    I2CTimeout = _I2C_TXIS_TIMEOUT;
    while (!LL_I2C_IsActiveFlag_TC(_I2C))
    {
        // TXIS is set every time a sent byte is acknowledged.
        if (LL_I2C_IsActiveFlag_TXIS(_I2C))
        {
            counter++;
            LL_I2C_TransmitData8(_I2C, (*pTransmitBuffer++));
            I2CTimeout = _I2C_TXIS_TIMEOUT;
            result = I2C_ERROR_PARTIAL;
        } else
        // If not TXIS, then the byte is delayed or was not acknowledged.
        if (I2CTimeout-- == 0)
        {
            // TODO LOG I2C Timeout failure.
            result = I2C_ERROR_TIMEOUT;
        }
    }


    if (counter == len)
        result = I2C_SUCCESS;

    EXIT:
    LL_I2C_GenerateStopCondition(_I2C);
    LL_I2C_ClearFlag_STOP(_I2C);
    taskEXIT_CRITICAL();

    return result;
}

一旦我修复了超时错误,一切都变成了废话。如果出现单个传输错误,则 I2C 总线停止,看起来像第一张图片 (ACK + DATA) 并变为 (ACK + STOP)。ACK 之后的停止是我试图编写的东西,但似乎它已经融入了 STM32 I2C 外设,因此很明显外设正在起作用。我已经检查了第一个 TX 和第二个 TX 的 SFR,在这两种情况下,I2C 外设的设置相同。

我的解释是,在使用 LL_I2C_HandleTransfer() 之后,代码的所有其他部分都无关紧要,因为停止条件是作为地址传输的一部分触发的。我已经能够使用显示的代码来一致地发送消息,但是微小的更改(例如实现超时)不应像现在这样影响地址确认。

我试着查找答案,但找不到任何东西。我试过降低时钟速度,分享了示波器结果,但仍然没有运气。

任何反馈将不胜感激!

已确认 I2C 总线上的确认。

确认的代码在某种程度上起作用。

STM32 I2C 低电平

评论


答: 暂无答案