This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] EK-TM4C129EXL:使用 I2C 和 ROM 引导加载程序更新固件-成功完成 COMMAND_GET_STATUS 后挂起

Guru**** 2618835 points

Other Parts Discussed in Thread: EK-TM4C129EXL, EK-TM4C1294XL

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status

器件型号:EK-TM4C129EXL
Thread 中讨论的其他器件: EK-TM4C1294XL

工具与软件:

您好!我有 EK-TM4C129EXL 和 EK-TM4C1294XL。  我将使用  EK-TM4C129EXL 使用 ROM 引导加载程序通过 I2C 更新 EK-TM4C1294XL 上的固件。

我已经过多次阅读《TivaWare 引导加载程序用户指南》(SPMU301E)、相信我已经正确完成了所有内容。  例如:

  • 我 在 禁用中断和调用 ROM_UpdateI2C ()之前、在 EK-TM4C1294XL 上以从模式设置 I2C。
  • 我在  EK-TM4C129EXL 上以100kbps 的速率在主模式下设置 I2C、并确保 EK-TM4C1294XL  在尝试发送命令之前已调用 ROM_UpdateI2C ()。

我将 在 EK-TM4C129EXL 上执行的 将固件发送到 EK-TM4C1294XL 的步骤如下所示。  首先、我按照以下步骤发送 COMMAND_DOWNLOAD 命令:

  1. 发送 COMMAND_DOWNLOAD 命令适当地打包。 (我将固件写入地址0x00000000、因为我没有自己的引导加载程序、新固件的大小为0x9A8)
  2. 请检查 COMMAND_DOWNLOAD 命令的 ACK  
  3. 发送 COMMAND_GET_STATUS 适当的封包化。
  4. 检查 COMMAND_GET_STATUS 命令的 ACK  
  5. 确保  COMMAND_GET_STATUS 中的返回代码为 COMMAND_RET_SUCCESS。

以下是 逻辑分析仪的图像、其中显示了上述步骤的成功通信。  首先调用 command_download、然后开始读取 ACK。。。

...然后是 ACK 响应和状态:

一切看起来都很好。

然后、我等待10秒(是的、10完整秒)、因为我知道 COMMAND_DOWNLOAD 步骤需要擦除 EK-TM4C1294XL 上的整个闪存部分。

然后、我从 COMMAND_SEND_DATA 命令开始:

  1. 发送 COMMAND_SEND_DATA 命令以进行适当的封包化。
  2. 检查 COMMAND_SEND_DATA  命令的 ACK  
  3. 发送 COMMAND_GET_STATUS  命令进行适当的封包化。
  4. 检查  COMMAND_GET_STATUS 命令的 ACK  
  5. 确保  COMMAND_GET_STATUS 中的返回代码为 COMMAND_RET_SUCCESS。

在执行  第一条 COMMAND_SEND_DATA 命令时、它在步骤2中无限期挂起。   无论我等待多长时间、引导加载程序都不会发回 ACK。  这里是我的逻辑分析仪输出:

现在、我们来讨论一下有趣的事情:如果我  在执行 COMMAND_DOWNLOAD 和 COMMAND_SEND_DATA 命令时省略了 COMMAND_GET_STATUS、则一切都正常工作。   新固件的整个0x9A8字节将成功 从 EK-TM4C129EXL 发送到 EK-TM4C1294XL、并写入 EK-TM4C1294XL 上的闪存 。   重新启动时、它会成功运行新固件。

所以,我对 两点感到困惑,希望有人有一些建议:

  • 为什么 I2C 通信在第一个 COMMAND_SEND_DATA 命令之后挂起。
  • 为什么在 删除 COMMAND_GET_STATUS 命令时一切都正常?

欢迎提出任何建议。  谢谢。

-Terence

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Terence、

    [报价用户 id="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status "]

    然后、我从 COMMAND_SEND_DATA 命令开始:

    1. 发送 COMMAND_SEND_DATA 命令以进行适当的封包化。
    2. 检查 COMMAND_SEND_DATA  命令的 ACK  
    3. 发送 COMMAND_GET_STATUS  命令进行适当的封包化。
    4. 检查  COMMAND_GET_STATUS 命令的 ACK  
    5. 确保  COMMAND_GET_STATUS 中的返回代码为 COMMAND_RET_SUCCESS。

    在执行  第一条 COMMAND_SEND_DATA 命令时、它在步骤2中无限期挂起。   无论我等待多长时间、引导加载程序都不会发回 ACK。  这里是我的逻辑分析仪输出:

    [报价]

    通常、如果从器件引导加载程序未发送 ACK、则可能意味着要编程的起始地址不是有效的32字地址、或者映像大小可能已超过可用闪存大小。 校验和也可能不匹配、因此会响应 NAK。 让我们分析一下您的波形。

    [报价用户 id="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status "]

    [报价]

    从上面的波形可以看出、您发送的是:

    -字节长度: 8

    -校验和: 0x8C,您能确认0x8C 是否正确吗?

    -命令: 0x24 (发送数据)

    -数据:1 0x20000200

    - Data2: 0x0000073F

    在发送 SEND_DATA 后、您可以尝试读取响应。 以"R 0x42"开头。 不过、我看不到更多的数据正在传输。 与工作波形相比、可以看到"R 0x42"->"0x00"->"0xCC"、非工作波形不符合0x00。 我对第二个字节0x00的使用感到有点困惑。 我认为这应该来自从器件、因为主器件发出了 I2C 读取命令。 我不知道为什么从器件不响应。 您是否可以发出 ping 命令以查看从器件是否处于引导加载程序模式?

    [编辑]我认为主器件仍必须生成 SCL 时钟、以便从器件在 I2C 读取模式下返回数据。 您可能需要检查主器件侧为什么它不会在"R 0x42"之后生成时钟。

    您能否请参阅此串行引导加载程序应用手册。 不确定在 I2C 主端开发串行编程器时是否参考了此应用手册。   

    https://www.ti.com/lit/an/spma074a/spma074a.pdf

    [报价用户 id="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status "]

    现在、我们来讨论一下有趣的事情:如果我  在执行 COMMAND_DOWNLOAD 和 COMMAND_SEND_DATA 命令时省略了 COMMAND_GET_STATUS、则一切都正常工作。   新固件的整个0x9A8字节将成功 从 EK-TM4C129EXL 发送到 EK-TM4C1294XL、并写入 EK-TM4C1294XL 上的闪存 。   重新启动时、它会成功运行新固件。

    所以,我对 两点感到困惑,希望有人有一些建议:

    • 为什么 I2C 通信在第一个 COMMAND_SEND_DATA 命令之后挂起。
    • 为什么在 删除 COMMAND_GET_STATUS 命令时一切都正常?
    [报价]

     这是一个有趣的观察、我还没有答案。 在这里、我有点困惑。 您之前说过、I2C 从器件通过 ACK 响应检查挂起。 在这里、您似乎提示挂起是由于 GET_STATUS。 有两种类型的响应:1类(ACK 或 NAK 响应)和2类(GET_STATUS)。 哪一个正在挂起?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Charles、感谢您的详细答复。  解决您的以下问题:

    [报价 userid="93620" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586093 #5586093"]

    校验和:0x8C、您能否确认0x8C 是否正确?

    [报价]

    我认为校验和正确。   通过使用以下数据来计算校验和:0x24 + 0x00 + 0x02 + 0x20 + 0x3F + 0x07 + 0x00 + 0x00。  这会指向0x8C。

    [报价 userid="93620" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586093 #5586093"]与工作波形相比、我看到"R 0x42"->"0x00"->"0xCC"、非工作波形不跟在0x00之后。 我对第二个字节0x00的使用感到有点困惑。 我认为这应该来自从器件、因为主器件发出了 I2C 读取命令。[/QUOT]

    是的、我同意第二个(以及第三个)字节应该来自从器件。  这是发生故障的地方、我不再收到从器件的响应。  为了进一步说明:我对默认引导加载程序工作原理的理解是、当主器件发送有效命令时、引导加载程序将以 ACK 进行响应。  该 ACK 包含两个字节(0x00、后跟0xCC)。  如果存在某些问题、引导加载程序将使用 NACK (0x33而不是0xCC)进行响应。  当然、要获得 ACK 或 NACK、主器件必须进行读取。  当您看到主器件发送"R 0x42"时会发生这种情况-它在启动对 ACK/NACK 的读取。  您是对的、问题的第一个迹象是当主器件发送"R 0x42"而什么都不回来...  此时一切都发生故障、我不再从从器件(即目标)获取任何响应。

    您可以发出 ping 命令来查看从设备是否处于引导加载程序模式吗?

    是的、我添加了代码、因此、主器件首先发出 ping 以确保其可以与目标的引导加载程序通信。  逻辑分析仪的以下图像显示了 ping 命令、ACK、后跟"get status"命令、相应 ACK 以及成功状态-一切看起来都正常。  我不得不稍微分解图像、因为它太长、无法全部垂直显示:

    实际上、我可以 继续执行此操作、以展示我遇到的问题。  ping 后、我发送"download"命令。  它是:

    然后、我去读取"download"命令的 ACK、就像我最初帖子中的示例一样、引导加载程序没有响应。  SCL 线无限期保持低电平:

    仔细观察一下、我最初以为从器件(引导加载程序)将时钟线保持在低电平、但我不确定是否确实是如此。  我想知道主器件是否 需要做的都是发送更多时钟信号以从引导加载程序获得响应。  我将对此进行调查。

    [报价 userid="93620" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586093 #5586093"]

    您能否请参阅此串行引导加载程序应用手册。 不确定在 I2C 主端开发串行编程器时是否参考了此应用手册。   

    https://www.ti.com/lit/an/spma074a/spma074a.pdf

    [报价]

    谢谢、我不知道这个应用手册。  我使用 SPMU301E (TivaWare 引导加载程序用户指南)和 TivaWare 引导加载程序代码来 创建代码。  我还将回顾 SPMA074A。

    在这里、我有点困惑。 您之前说过、I2C 从器件通过 ACK 响应检查挂起。 在这里、您似乎提示挂起是由于 GET_STATUS。 有两种类型的响应:1类(ACK 或 NAK 响应)和2类(GET_STATUS)。 哪一个正在挂起?

    为困惑道歉。  为清楚起见、当我删除 get_status 调用并在 ACK 读取中保留时、一切都会正常运行。  ping 命令有效、下载命令有效、many send data 命令以及 reset 命令有效(在我的 send data 命令完成后、目标板成功地使用新固件进行了更新)。

    现在、如上面的 ping 示例所示、只要我添加 get_status 命令、*Following*命令上的*ACK*就会挂起。  

    这种描述是否合理?  我知道,这是奇怪的,我现在不能理解它。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    只是一个跟进这一点:

    在深入了解此事时、我最初以为从设备(引导加载程序)将时钟线保持在低电平、但我不确定情况是否属实。  我想知道主器件是否 需要做的都是发送更多时钟信号以从引导加载程序获得响应。  我将对此进行调查。

    它 由于在启动读取操作后主总线处于忙状态而挂起、如下所示:

    总线无限期地保持忙状态:

    这是我用于执行所有其他 I2C 读取的相同函数、并且没有遇到任何问题。。  我不确定为什么总线繁忙位无限期地保持设置...   

    此外、查看 SPMA074A 似乎表明、ACK/NACK 只应为引导加载程序返回的单个字节、而不是我通常接收的两个字节(如我在上一篇文章中的 ping 示例所示)。

    不知道为什么我要接收两个字节而不是一个字节吗?  我原本以为 ACK 应该有两个字节、因为在写入我自己的更新程序固件之前 、我使用 Total Phase Aardvark 发送 ping 命令、然后读回 ACK 的数据、并接收到两个字节(0x00、然后是0xCC)。

    此外、如果需要帮助的话、我可以附上我在两个评估板上使用的代码。  这些是基本的 CCS 项目。  代码具有良好的注释、应非常易于阅读。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    非常抱歉布置过度、但在查看引导加载程序代码时、我看到 ACK 实际上是一个0x00、后跟0xCC。  从 TivaWare 2.2.0.295引导加载程序中的 bl_packet.c:

    //*****************************************************************************
    //
    // The packet that is sent to acknowledge a received packet.
    //
    //*****************************************************************************
    static const uint8_t g_pui8ACK[2] = { 0, COMMAND_ACK };

    ...然后进一步下去:

    //*****************************************************************************
    //
    //! Sends an Acknowledge packet.
    //!
    //! This function is called to acknowledge that a packet has been received by
    //! the microcontroller.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    AckPacket(void)
    {
        //
        // ACK/NAK packets are the only ones with no size.
        //
        SendData(g_pui8ACK, 2);
    }
    

    我仍然非常开放的想法,在我的 I2CReadData 函数中有什么问题。  它是:

    #define I2C_DELAY                 2000     // Wait this many ticks between I2C actions
    
    void I2CReadData(uint8_t* outputBuffer, const uint32_t bytesToRead)
    {
        // Make sure the bus isn't busy before trying to start the transaction
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Set the slave address for receiving
        MAP_I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, true);
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Start receiving data in burst mode
        MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
        MAP_SysCtlDelay(I2C_DELAY);
        while(I2CMasterBusy(I2C0_BASE));
    
        // Get the first byte
        outputBuffer[0] = MAP_I2CMasterDataGet(I2C0_BASE);
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Read the remaining data
        uint32_t i = 1;
        for(; i < bytesToRead; ++i)
        {
            // If we're not yet at the last byte, send a continue, otherwise, send a finish
            if(i < (bytesToRead - 1))
            {
                MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
            }
            else
            {
                MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
            }
    
            MAP_SysCtlDelay(I2C_DELAY);
            while(MAP_I2CMasterBusy(I2C0_BASE));
    
            // Get the current byte of data
            outputBuffer[i] = (uint8_t)MAP_I2CMasterDataGet(I2C0_BASE);
            MAP_SysCtlDelay(I2C_DELAY);
            while(MAP_I2CMasterBusy(I2C0_BASE));
        }
    }
    

    我将对此进行返工。  与   突发模式相比、可能执行两次单次读取会效果更好。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    为了更详细地解释:我对默认引导加载程序工作原理的理解是主设备发送有效命令时引导加载程序将用 ACK 进行响应。  该 ACK 包含两个字节(0x00、后跟0xCC)。  如果存在某些问题、引导加载程序将使用 NACK (0x33而不是0xCC)进行响应。  [报价]

    正确。  

    [报价 userid="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586220 #5586220"]当然、要获得 ACK 或 NACK、主控方必须进行读取。  当您看到主器件发送"R 0x42"时会发生这种情况-它在启动对 ACK/NACK 的读取。  您是对的、问题的第一个迹象是当主器件发送"R 0x42"而什么都不回来...  此时一切都失败、我不再从从器件(即目标)获取任何响应。

    [报价]

    我修改了我原来的答复,而你发送了你的答复。 在我修改后的答复中、我提到了主器件仍然必须为从器件生成时钟才能返回数据。 但是、仔细观察您的上面的波形、在我看来、SCL 为低电平。 这可能意味着两件事、但我不知道是哪个。 第一种可能性是主器件不输出时钟、或者在第二种情况下、从器件拉伸时钟、以根据 I2C 协议将主器件保持在等待状态。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [报价用户 id="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586304 #5586304"]

    但查看引导加载程序代码、我看到 ACK 实际上是一个0x00、后跟0xCC。  从 TivaWare 2.2.0.295引导加载程序中的 bl_packet.c:

    全屏
    1.
    2.
    3.
    4.
    5.
    6.
    //
    //
    //为了确认接收到的数据包而发送的数据包。
    //
    //
    静态 const uint8_t g_pui8ACK[2]={0、COMMAND_ACK};
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    ...然后进一步下去:

    全屏
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    10.
    11.
    12.
    13.
    14.
    15.
    16.
    17.
    18.
    //
    //
    //! 发送确认数据包。
    //!
    //! 调用此函数以确认已接收到数据包
    //! 微控制器供电。
    //!
    //! \返回无。
    //
    //
    空洞
    AckPacket (空)
    //
    // ACK/NAK 数据包是唯一没有大小的数据包。
    //
    SendData (g_pui8ACK、2);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    [报价]

    是、响应为两个字节、其中0x00、0xCC 用于 ACK。  

    我将对此进行修改。  可能执行 两次 单次读取 而不是突发模式将效果更好。

    如果这会产生什么影响、请告诉我。 还要检查从器件是否正在延展时钟。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的、谢谢、Charles。  我将突发读取替换为两个 I2C_MASTER_CMD_SINGLE_RECEIVE、但仍获得相同的结果。  我还将 I2C_DELAY 延长到了6000个周期、以便为接收器提供更多的时间、同时也获得相同的结果。

    下面是我的新 I2CRead 函数:

    #define I2C_DELAY                 6000     // Wait this many ticks between I2C actions
    
    void I2CReadDataACK(uint8_t* outputBuffer)
    {
        // Make sure the bus isn't busy before trying to start the transaction
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Set the slave address for receiving
        MAP_I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, true);
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Request to receive the single byte
        MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Read the first byte of data
        outputBuffer[0] = I2CMasterDataGet(I2C0_BASE);
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Request to receive the single byte
        MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    
        // Read the second byte of data
        outputBuffer[1] = I2CMasterDataGet(I2C0_BASE);
        MAP_SysCtlDelay(I2C_DELAY);
        while(MAP_I2CMasterBusy(I2C0_BASE));
    }

    与我旧的 I2CRead 函数类似、它无限期地停留在这里:

    总线无限期地处于繁忙状态、在读取尝试之后 SCL 保持低电平:

    缩小显示 它无限期挂起:

    利用时钟延展、应该由 I2C 从器件在某个时候释放 SCL、对吗?

    此外、我认为是目标器件(I2C 从器件)将 SCL 保持在低电平、因为如果我仅复位该板而不接触其他板(主器件)、SCL 线会恢复到高电平。

    我很难 相信这是 ROM 引导加载程序中的错误、因为我想它的用途非常广泛、但我 不确定还有什么。

    有什么想法吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [报价用户 id="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586369 #5586369"]此外、我认为是目标器件(I2C 从设备)将 SCL 保持在低电平、因为如果我只复位了那个板而又未接触其它板(主设备)、SCL 线又恢复高电平。

    您好、Terence、

     您可以通过设置时钟低电平超时来仔细检查主器件侧吗? 如果您看到超时标志或中断、则可确认从器件确实占用了总线。 至于从器件侧 ROM 引导加载程序保留总线的原因、我真的不知道。 事实上、我不记得 e2e 上基于 ROM 的 I2C 引导加载程序问题。 您可能是第一个、也可能是其中很少的一个。 大多数人使用 UART、以太网和 USB、而有些人使用 SPI 和 CAN。 由于您使用 ROM 引导加载程序、因此与基于闪存的引导加载程序不同、对其正在执行的操作的可见性和调试在某种程度上受到限制。 当从器件延长时钟时、这意味着它未准备好获取数据。 如果在 send_data 命令中一次发送的只是4个字节或更少、而不是8个字节、该怎么办? 这会产生影响吗? 我首先会一次仅发送一个字节、以查看引导加载程序是如何响应并逐渐增加字节计数的。  

    18.3.1.6时钟低电平超时(CLTO)
    I2C 从器件可以通过将时钟周期性地拉低以创建慢速位来扩展事务
    传输速率。 I2C 模块有一个12位可编程计数器、可以用来跟踪的时长
    时钟已经被保持在低电平。 计数值的高8位可通过进行软件编程
    I2C 主机时钟低电平超时计数寄存器(I2CMCLKOCNT)。 低四位没有
    用户可见、为0x0。 写入 I2CMCLKOCNT 寄存器中 CNTL 的值必须为
    大于0x01。 应用程序可将计数器的8个最高有效位编程到
    反映事务中可接受的累计低电平时间。 计数在开始时加载
    条件、并且在主机内部总线时钟的每个下降沿倒计时。 请注意
    为该计数器生成的内部总线时钟能够以编程的 I2C 速度继续运行
    在总线上产生最低的延迟。 在达到终端计数时、主状态机强制中止
    在 SCL 和 SDA 释放时发出一个停止条件来释放总线上的所有数据。
    例如、如果一个 I2C 模块正以100kHz 的速度运行、那么就需要对 I2CMCLKOCNT 编程
    寄存器0xDA 将转换为值0xDA0、因为低四位设置为0x0。 减少
    换言之、也就是3488个时钟周期、即34.88ms 时钟低电平累计时间
    100kHz。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好查尔斯,谢谢你的答复。   是的、我可以理解、使用 I2C 与引导加载程序通信并不是常用或优选的方法。  我们遇到这样的情况:我们使用的是 TM4C123 (因此没有以太网)、而我们没有使用 USB、 UART0不可用于引导加载程序通信。   不过、我们在同一电路板上有一个独立的处理器、能够通过 I2C 与 I2C0上的 TM4C123通信。  这个单独的处理器可以与外界通信。   所以,它(不幸?) 它最适合用于更新固件。

    我添加了您建议的时钟低电平超时。  如 TivaWare 文档所述:

    "……要将20ms 的超时编程为100kHz SCL 频率、ui32Value 为0x7d"

    我认为20ms 会足够长、因此我使用0x7D 作为超时。  以下是初始化 I2C 主器件的代码:

    void SetupI2C(uint32_t sysClock)
    {
        // Enable the GPIO peripheral
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));
    
        // Enable the I2C peripheral
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0));
    
        // Set the pin multiplexors
        MAP_GPIOPinConfigure(GPIO_PB2_I2C0SCL);
        MAP_GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    
        // Assign pins to SCL and SDA
        MAP_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
        MAP_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    
        // Set the I2C clock
        MAP_I2CMasterInitExpClk(I2C0_BASE, sysClock, false);  // Set speed to 100 kbps
    
        MAP_I2CMasterTimeoutSet(I2C0_BASE, 0x7D);
    }

    ^该代码与之前的代码相同,只是我 在底部添加了 I2CMasterTimeoutSet()。

    重新运行与之前完全相同的测试时、现在显示了以前不存在时钟超时错误:

    似乎是 ROM 引导加载程序导致问题的额外指示。

    如果在 send_data 命令中一次只发送4个字节或更少的数据、而不是8个字节、该怎么办? 这会产生什么影响吗?

    好主意!  但这让我想尝试其他东西: 每 50毫秒不停地发送 ping (只有一个数据字节)一次、看看它是否可以处理该问题。  遗憾的是、同样的问题:

    然后、 第二个 ping 的 ACK 读取失败、SCL 像往常一样卡在低电平:


    尽管如此,我认为这不是一个摊牌。  正如我前面提到的、如果我没有发送"get status"命令、固件更新每次都成功完成。  我已经测试了很多次、没有失败。  是的、状态最好是*但是*我至少要为我发出的每个命令提供 ACK。

    我会与团队中的其他人讨论此事、但我认为这是可以接受的。

    我非常感谢你在这方面提供的所有帮助。

    -Terence

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [报价用户 id="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586511 #5586511"]

    重新运行与之前完全相同的测试时、现在显示了以前不存在时钟超时错误:

    似乎是 ROM 引导加载程序导致问题的额外指示。

    [报价]

    您好、Terence、

     感谢您的确认。 从机确实是因为我没有解释的原因而扣留了总线。  

    [报价用户 id="467243" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456117/ek-tm4c129exl-updating-firmware-using-i2c-with-the-rom-bootloader---hanging-after-successful-command_get_status/5586511 #5586511"]

    好主意!  但这让我想尝试其他东西: 每 50毫秒不停地发送 ping (只有一个数据字节)一次、看看它是否可以处理该问题。  遗憾的是、同样的问题:

    然后、 第二个 ping 的 ACK 读取失败、SCL 像往常一样卡在低电平:

    [报价]

    好的、我看到了。 可能基于 ROM 的 I2C 引导加载程序存在一些未知问题。 由于引导加载程序存储在 ROM 中、因此如果没有无法得到的器件响应、就无法对其进行修补。  

    尽管如此,我不认为这是一个摊牌。  正如我前面提到的、如果我没有发送"get status"命令、固件更新每次都成功完成。  我已经测试了很多次、没有失败。  是的,最好有状态*但是*我至少要有我发出的每个命令的 ACK。

    很高兴您已经测试了权变措施(不发送 GET_STATUS 命令)而未失败。 我一定会注意到这一点并将此帖子加入书签、以便社区中的任何人都可以从您的变通办法中受益(如果我被要求)。 非常感谢!