fix(balance): TWAI bus-off detection, auto-recovery, console off UART0
- vesc_can: poll twai_get_status_info() every 500ms; auto-recover from bus-off (twai_initiate_recovery) and stopped state (twai_start) - vesc_can: expose g_twai_bus_off / g_twai_tx_err_count / g_twai_rx_err_count - main: set flags bit2 when TWAI is bus-off (visible in TELEM_STATUS) - sdkconfig: switch console from UART0 (conflicts with binary protocol at 460800) to USB serial JTAG — eliminates log corruption on Orin Flags byte: bit0=estop, bit1=hb_timeout, bit2=twai_bus_off Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b830420efc
commit
4335d71187
@ -41,9 +41,10 @@ static void telem_task(void *arg)
|
|||||||
state = BAL_ARMED;
|
state = BAL_ARMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* flags: bit0=estop_active, bit1=heartbeat_timeout */
|
/* flags: bit0=estop_active, bit1=heartbeat_timeout, bit2=twai_bus_off */
|
||||||
uint8_t flags = (g_orin_ctrl.estop ? 0x01u : 0x00u) |
|
uint8_t flags = (g_orin_ctrl.estop ? 0x01u : 0x00u) |
|
||||||
(hb_timeout ? 0x02u : 0x00u);
|
(hb_timeout ? 0x02u : 0x00u) |
|
||||||
|
(g_twai_bus_off ? 0x04u : 0x00u);
|
||||||
|
|
||||||
/* Battery voltage from VESC_ID_A STATUS_5 (V×10 → mV) */
|
/* Battery voltage from VESC_ID_A STATUS_5 (V×10 → mV) */
|
||||||
uint16_t vbat_mv = (uint16_t)((int32_t)g_vesc[0].voltage_x10 * 100);
|
uint16_t vbat_mv = (uint16_t)((int32_t)g_vesc[0].voltage_x10 * 100);
|
||||||
@ -96,8 +97,9 @@ void app_main(void)
|
|||||||
s_orin_tx_q = xQueueCreate(ORIN_TX_QUEUE_DEPTH, sizeof(orin_tx_frame_t));
|
s_orin_tx_q = xQueueCreate(ORIN_TX_QUEUE_DEPTH, sizeof(orin_tx_frame_t));
|
||||||
configASSERT(s_orin_tx_q);
|
configASSERT(s_orin_tx_q);
|
||||||
|
|
||||||
/* Seed heartbeat timer so we don't immediately timeout */
|
/* Seed timers so we don't immediately trip hb_timeout or drive_stale */
|
||||||
g_orin_ctrl.hb_last_ms = (uint32_t)(esp_timer_get_time() / 1000LL);
|
g_orin_ctrl.hb_last_ms = (uint32_t)(esp_timer_get_time() / 1000LL);
|
||||||
|
g_orin_drive.updated_ms = g_orin_ctrl.hb_last_ms;
|
||||||
|
|
||||||
/* Create tasks */
|
/* Create tasks */
|
||||||
xTaskCreate(orin_serial_rx_task, "orin_rx", 4096, s_orin_tx_q, 10, NULL);
|
xTaskCreate(orin_serial_rx_task, "orin_rx", 4096, s_orin_tx_q, 10, NULL);
|
||||||
|
|||||||
@ -17,6 +17,9 @@
|
|||||||
static const char *TAG = "vesc_can";
|
static const char *TAG = "vesc_can";
|
||||||
|
|
||||||
vesc_state_t g_vesc[2] = {0};
|
vesc_state_t g_vesc[2] = {0};
|
||||||
|
volatile bool g_twai_bus_off = false;
|
||||||
|
volatile uint32_t g_twai_tx_err_count = 0;
|
||||||
|
volatile uint32_t g_twai_rx_err_count = 0;
|
||||||
|
|
||||||
/* Index for a given VESC node ID: 0=VESC_ID_A, 1=VESC_ID_B */
|
/* Index for a given VESC node ID: 0=VESC_ID_A, 1=VESC_ID_B */
|
||||||
static int vesc_idx(uint8_t id)
|
static int vesc_idx(uint8_t id)
|
||||||
@ -55,15 +58,46 @@ void vesc_can_send_rpm(uint8_t vesc_id, int32_t erpm)
|
|||||||
msg.data[1] = (uint8_t)(u >> 16u);
|
msg.data[1] = (uint8_t)(u >> 16u);
|
||||||
msg.data[2] = (uint8_t)(u >> 8u);
|
msg.data[2] = (uint8_t)(u >> 8u);
|
||||||
msg.data[3] = (uint8_t)(u);
|
msg.data[3] = (uint8_t)(u);
|
||||||
twai_transmit(&msg, pdMS_TO_TICKS(5));
|
esp_err_t ret = twai_transmit(&msg, pdMS_TO_TICKS(5));
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "twai_transmit vesc_id=%u erpm=%ld: %s",
|
||||||
|
vesc_id, (long)erpm, esp_err_to_name(ret));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vesc_can_rx_task(void *arg)
|
void vesc_can_rx_task(void *arg)
|
||||||
{
|
{
|
||||||
QueueHandle_t tx_q = (QueueHandle_t)arg;
|
QueueHandle_t tx_q = (QueueHandle_t)arg;
|
||||||
twai_message_t msg;
|
twai_message_t msg;
|
||||||
|
uint32_t status_tick = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
/* Poll TWAI health every 500 ms and recover from bus-off */
|
||||||
|
uint32_t now_ms = (uint32_t)(esp_timer_get_time() / 1000LL);
|
||||||
|
if ((now_ms - status_tick) >= 500u) {
|
||||||
|
status_tick = now_ms;
|
||||||
|
twai_status_info_t si;
|
||||||
|
if (twai_get_status_info(&si) == ESP_OK) {
|
||||||
|
g_twai_bus_off = (si.state == TWAI_STATE_BUS_OFF);
|
||||||
|
g_twai_tx_err_count = si.tx_error_counter;
|
||||||
|
g_twai_rx_err_count = si.rx_error_counter;
|
||||||
|
if (si.state == TWAI_STATE_BUS_OFF) {
|
||||||
|
ESP_LOGW(TAG, "TWAI bus-off — initiating recovery");
|
||||||
|
twai_initiate_recovery();
|
||||||
|
} else if (si.state == TWAI_STATE_STOPPED) {
|
||||||
|
ESP_LOGW(TAG, "TWAI stopped — restarting");
|
||||||
|
twai_start();
|
||||||
|
}
|
||||||
|
if (si.tx_error_counter > 0 || si.rx_error_counter > 0) {
|
||||||
|
ESP_LOGW(TAG, "TWAI errs tx=%lu rx=%lu msgs_tx=%lu msgs_rx=%lu",
|
||||||
|
(unsigned long)si.tx_error_counter,
|
||||||
|
(unsigned long)si.rx_error_counter,
|
||||||
|
(unsigned long)si.msgs_to_tx,
|
||||||
|
(unsigned long)si.msgs_to_rx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (twai_receive(&msg, pdMS_TO_TICKS(50)) != ESP_OK) {
|
if (twai_receive(&msg, pdMS_TO_TICKS(50)) != ESP_OK) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,11 @@ typedef struct {
|
|||||||
/* ── Globals (two VESC nodes: index 0 = VESC_ID_A=56, 1 = VESC_ID_B=68) ── */
|
/* ── Globals (two VESC nodes: index 0 = VESC_ID_A=56, 1 = VESC_ID_B=68) ── */
|
||||||
extern vesc_state_t g_vesc[2];
|
extern vesc_state_t g_vesc[2];
|
||||||
|
|
||||||
|
/* TWAI bus health — set by vesc_can_rx_task, read by telem_task for flags bit2 */
|
||||||
|
extern volatile bool g_twai_bus_off;
|
||||||
|
extern volatile uint32_t g_twai_tx_err_count;
|
||||||
|
extern volatile uint32_t g_twai_rx_err_count;
|
||||||
|
|
||||||
/* ── API ── */
|
/* ── API ── */
|
||||||
void vesc_can_init(void);
|
void vesc_can_init(void);
|
||||||
void vesc_can_send_rpm(uint8_t vesc_id, int32_t erpm);
|
void vesc_can_send_rpm(uint8_t vesc_id, int32_t erpm);
|
||||||
|
|||||||
@ -5,7 +5,5 @@ CONFIG_ESP_TASK_WDT_EN=y
|
|||||||
CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
|
CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
|
||||||
CONFIG_TWAI_ISR_IN_IRAM=y
|
CONFIG_TWAI_ISR_IN_IRAM=y
|
||||||
CONFIG_UART_ISR_IN_IRAM=y
|
CONFIG_UART_ISR_IN_IRAM=y
|
||||||
CONFIG_ESP_CONSOLE_UART_DEFAULT=y
|
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
|
||||||
CONFIG_ESP_CONSOLE_UART_NUM=0
|
|
||||||
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
|
|
||||||
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user