esp32/machine_uart: Improve sendbreak so it doesn't reconfig the UART.

Currently, `UART.sendbreak()` on esp32 will reconfigure the UART to a
slower baudrate and send out a null byte, to synthesise a break condition.
That's not great because it changes the baudrate of the RX path as well,
which could miss incoming bytes while sending the break.

This commit changes the sendbreak implementation to just reconfigure the TX
pin as GPIO in output mode, and hold the pin low for the required duration.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2025-07-17 16:49:26 +10:00
parent 941b7e35ac
commit 79b2d4ff22

View file

@ -508,20 +508,21 @@ static bool mp_machine_uart_txdone(machine_uart_obj_t *self) {
}
static void mp_machine_uart_sendbreak(machine_uart_obj_t *self) {
// Save settings
// Calculate the length of the break, as 13 bits.
uint32_t baudrate;
check_esp_err(uart_get_baudrate(self->uart_num, &baudrate));
uint32_t break_delay_us = 13000000 / baudrate;
// Synthesise the break condition by reducing the baud rate,
// and cater for the worst case of 5 data bits, no parity.
check_esp_err(uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000)));
check_esp_err(uart_set_baudrate(self->uart_num, baudrate * 6 / 15));
char buf[1] = {0};
uart_write_bytes(self->uart_num, buf, 1);
// Wait for any outstanding data to be transmitted.
check_esp_err(uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000)));
// Restore original setting
check_esp_err(uart_set_baudrate(self->uart_num, baudrate));
// Set the TX pin to output, pull it low, and wait for the break period.
mp_hal_pin_output(self->tx);
mp_hal_pin_write(self->tx, 0);
mp_hal_delay_us(break_delay_us);
// Restore original UART pin settings.
check_esp_err(uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts));
}
// Configure the timer used for IRQ_RXIDLE