• ESP32在CAN(TWAI)波特率不同时收发数据,导致总线错误无法恢复


    问题描述:

    总线上有两个设备,主机:100ms周期发送数据。从机:以不同波特率发送数据,再把从机波特率调节至主机波特率一致无法通信。

    环境:VSCODE + IDF-v5.0

    问题分析:

    我们先看下ESP32技术参考手册中TWAI中对错误状态计数器的描述。当TEC>255时,说明总线发生严重错误,此时ESP32的机制会关闭总线进入离线状态。这也是导致我们无法通信的原因。

    问题解决方法:

    在ESP32的技术参考手册上也描述了怎么恢复离线状态。

    首先我们需要知道CAN(TWAI)的总线状态。这个我们可以通过IDF的API函数来获取中线的各种状态。

    代码如下:

    1. /**
    2. * @brief Structure to store status information of TWAI driver
    3. */
    4. typedef struct {
    5. twai_state_t state; /**< Current state of TWAI controller (Stopped/Running/Bus-Off/Recovery) */
    6. uint32_t msgs_to_tx; /**< Number of messages queued for transmission or awaiting transmission completion */
    7. uint32_t msgs_to_rx; /**< Number of messages in RX queue waiting to be read */
    8. uint32_t tx_error_counter; /**< Current value of Transmit Error Counter */
    9. uint32_t rx_error_counter; /**< Current value of Receive Error Counter */
    10. uint32_t tx_failed_count; /**< Number of messages that failed transmissions */
    11. uint32_t rx_missed_count; /**< Number of messages that were lost due to a full RX queue (or errata workaround if enabled) */
    12. uint32_t rx_overrun_count; /**< Number of messages that were lost due to a RX FIFO overrun */
    13. uint32_t arb_lost_count; /**< Number of instances arbitration was lost */
    14. uint32_t bus_error_count; /**< Number of instances a bus error has occurred */
    15. } twai_status_info_t;
    16. /**
    17. * @brief Get current status information of the TWAI driver
    18. *
    19. * @param[out] status_info Status information
    20. *
    21. * @return
    22. * - ESP_OK: Status information retrieved
    23. * - ESP_ERR_INVALID_ARG: Arguments are invalid
    24. * - ESP_ERR_INVALID_STATE: TWAI driver is not installed
    25. */
    26. esp_err_t twai_get_status_info(twai_status_info_t *status_info)

    同时CAN(TWAI)总线的状态有以下几种状态。

    1. /**
    2. * @brief TWAI driver states
    3. */
    4. typedef enum {
    5. TWAI_STATE_STOPPED, /**< Stopped state. The TWAI controller will not participate in any TWAI bus activities */
    6. TWAI_STATE_RUNNING, /**< Running state. The TWAI controller can transmit and receive messages */
    7. TWAI_STATE_BUS_OFF, /**< Bus-off state. The TWAI controller cannot participate in bus activities until it has recovered */
    8. TWAI_STATE_RECOVERING, /**< Recovering state. The TWAI controller is undergoing bus recovery */
    9. } twai_state_t;

    当我们获取到现在的总线状态为OFF时,我们就可以知道我们的CAN(TWAI)中线已经离线,我们要开始进入恢复流程,我们直接调用IDF的API进入恢复流程,我们可以通过以下代码来实现。

    1. /**
    2. * @brief Start the bus recovery process
    3. *
    4. * This function initiates the bus recovery process when the TWAI driver is in
    5. * the bus-off state. Once initiated, the TWAI driver will enter the recovering
    6. * state and wait for 128 occurrences of the bus-free signal on the TWAI bus
    7. * before returning to the stopped state. This function will reset the TX queue,
    8. * clearing any messages pending transmission.
    9. *
    10. * @note The BUS_RECOVERED alert can be enabled to alert the application when
    11. * the bus recovery process completes.
    12. *
    13. * @return
    14. * - ESP_OK: Bus recovery started
    15. * - ESP_ERR_INVALID_STATE: TWAI driver is not in the bus-off state, or is not installed
    16. */
    17. esp_err_t twai_initiate_recovery(void);
    18. twai_status_info_t twai_status_info;
    19. twai_get_status_info(&twai_status_info);
    20. // 总线关闭
    21. if(twai_status_info.state == TWAI_STATE_BUS_OFF)
    22. {
    23. // 总线复位
    24. twai_initiate_recovery();
    25. }

    当我们执行完twai_initiate_recovery();函数之后CAN(TWAI)总线会清空所有错误计数,但是此时总线还不能直接收发数据,因为此时我们的总线状态为TWAI_STATE_STOPPED状态,我们此时需要切换到TWAI_STATE_RUNNING状态我们才能正常收发数据,这个状态的切换我们也是通过API函数来切换。代码如下:

    twai_start();

    问题总结:解决这个问题只需要在收发任务中加入以下代码就可以对总线状态进行监控。进入恢复流程。

    1. // 读取总线状态
    2. twai_status_info_t twai_status_info;
    3. twai_get_status_info(&twai_status_info);
    4. // 总线关闭
    5. if(twai_status_info.state == TWAI_STATE_BUS_OFF)
    6. {
    7. twai_initiate_recovery();
    8. }
    9. // 总线停止
    10. else if(twai_status_info.state == TWAI_STATE_STOPPED)
    11. {
    12. twai_start();
    13. }

    如果帮到了你,请给我一个关注😍。

  • 相关阅读:
    (其他) 剑指 Offer 61. 扑克牌中的顺子 ——【Leetcode每日一题】
    技术分享 | MySQL 存储过程中的只读语句超时怎么办?
    能够1年涨薪2次的软件测试工程师,他到底强在哪里?
    【图论】【Matlab】最小生成树之Kruskal算法【贪心思想超详细详解Kruskal算法并应用】
    (附源码)ssm人才市场招聘信息系统 毕业设计 271621
    Flink之SQL查询操作
    uniapp 微信小程序登录 新手专用 引入即可
    2023USNews美国加州系大学排名
    springcloud微服务(一)(了解微服务、eureka注册中心、Ribbon负载均衡)
    七大排序--万字详解
  • 原文地址:https://blog.csdn.net/qq_44744444/article/details/133275057