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 <noreply@anthropic.com>
This commit is contained in:
sl-controls 2026-03-06 23:02:01 -05:00
parent e28f1549cb
commit b128e164e7
2 changed files with 26 additions and 3 deletions

View File

@ -154,7 +154,8 @@
// --- SaltyLab Assignments --- // --- SaltyLab Assignments ---
// Hoverboard ESC: USART2 (PA2=TX, PA3=RX) or USART3 // Hoverboard ESC: USART2 (PA2=TX, PA3=RX) or USART3
// ELRS Receiver: UART4 (PA0=TX, PA1=RX) — CRSF 420000 baud // 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) // Debug: UART5 (PC12=TX, PD2=RX)
// --- ESC Backend Selection (Issue #388) --- // --- ESC Backend Selection (Issue #388) ---

View File

@ -13,6 +13,28 @@ static uint32_t s_rx_tail = 0; /* consumer index (byte already processed) */
static UART_HandleTypeDef s_uart; static UART_HandleTypeDef s_uart;
static DMA_HandleTypeDef s_dma_rx; 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 state ---- */
volatile JLinkState jlink_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 + 1] = (uint8_t)(crc & 0xFFu);
frame[3 + plen + 2] = JLINK_ETX; 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() ---- */ /* ---- 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 + 1] = (uint8_t)(crc & 0xFFu);
frame[3 + plen + 2] = JLINK_ETX; frame[3 + plen + 2] = JLINK_ETX;
HAL_UART_Transmit(&s_uart, frame, sizeof(frame), 5u); jlink_tx_locked(frame, sizeof(frame));
} }