From b128e164e76179cdb34981bdabafc6975059cc51 Mon Sep 17 00:00:00 2001 From: sl-controls Date: Fri, 6 Mar 2026 23:02:01 -0500 Subject: [PATCH] fix: USART6 TX mutex to prevent truncated output (Issue #522) USART1 IDLE interrupt (DMA circular RX) was calling HAL_UART_IRQHandler mid-frame during polling HAL_UART_Transmit, resetting gState and causing leading nulls / truncated frames on the Jetson telemetry link at 921600 baud. Fix: introduce jlink_tx_locked() which disables USART1_IRQn around every blocking HAL_UART_Transmit call, preventing IRQHandler from corrupting gState while the TX loop is running. A s_tx_busy flag drops any re-entrant caller (ESC debug, future USART6/VESC paths). Both jlink_send_telemetry (50 Hz) and jlink_send_power_telemetry (1 Hz) now use jlink_tx_locked(). Also correct the stale config.h comment that misidentified the Jetson link as USART6 (it moved to USART1 in Issue #120). Co-Authored-By: Claude Sonnet 4.6 --- include/config.h | 3 ++- src/jlink.c | 26 ++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/config.h b/include/config.h index c3bb117..fa1e4e3 100644 --- a/include/config.h +++ b/include/config.h @@ -154,7 +154,8 @@ // --- SaltyLab Assignments --- // Hoverboard ESC: USART2 (PA2=TX, PA3=RX) or USART3 // ELRS Receiver: UART4 (PA0=TX, PA1=RX) — CRSF 420000 baud -// Jetson: USART6 (PC6=TX, PC7=RX) +// Jetson (JLink binary protocol, Issue #120): USART1 (PB6=TX, PB7=RX) @ 921600 +// USART6 (PC6=TX, PC7=RX): legacy Jetson CDC path — reserved for VESC (Issue #383) // Debug: UART5 (PC12=TX, PD2=RX) // --- ESC Backend Selection (Issue #388) --- diff --git a/src/jlink.c b/src/jlink.c index c9a94f3..dba55ec 100644 --- a/src/jlink.c +++ b/src/jlink.c @@ -13,6 +13,28 @@ static uint32_t s_rx_tail = 0; /* consumer index (byte already processed) */ static UART_HandleTypeDef s_uart; static DMA_HandleTypeDef s_dma_rx; +/* ---- TX mutex ---- */ +/* + * Issue #522: USART1 IDLE interrupt (DMA RX) fires via HAL_UART_IRQHandler + * mid-frame during polling HAL_UART_Transmit, resetting gState and causing + * truncated/null-prefixed frames on the Jetson link. + * + * Fix: disable USART1_IRQn around every blocking TX so HAL_UART_IRQHandler + * cannot modify gState while HAL_UART_Transmit is looping. s_tx_busy guards + * against any re-entrant caller (ESC debug, future paths). + */ +static volatile uint8_t s_tx_busy = 0; + +static void jlink_tx_locked(uint8_t *buf, uint16_t len) +{ + if (s_tx_busy) return; /* drop if already transmitting */ + s_tx_busy = 1u; + HAL_NVIC_DisableIRQ(USART1_IRQn); + HAL_UART_Transmit(&s_uart, buf, len, 5u); + HAL_NVIC_EnableIRQ(USART1_IRQn); + s_tx_busy = 0u; +} + /* ---- Volatile state ---- */ volatile JLinkState jlink_state; @@ -293,7 +315,7 @@ void jlink_send_telemetry(const jlink_tlm_status_t *status) frame[3 + plen + 1] = (uint8_t)(crc & 0xFFu); frame[3 + plen + 2] = JLINK_ETX; - HAL_UART_Transmit(&s_uart, frame, sizeof(frame), 5u); + jlink_tx_locked(frame, sizeof(frame)); } /* ---- jlink_send_power_telemetry() ---- */ @@ -318,5 +340,5 @@ void jlink_send_power_telemetry(const jlink_tlm_power_t *power) frame[3 + plen + 1] = (uint8_t)(crc & 0xFFu); frame[3 + plen + 2] = JLINK_ETX; - HAL_UART_Transmit(&s_uart, frame, sizeof(frame), 5u); + jlink_tx_locked(frame, sizeof(frame)); }