mimxrt/machine_uart: Fix and complete UART.deinit and uart_deinit_all.

The code did not check at deinit whether a UART was initialized.  That did
not matter for all MCU's except MIMXRT1176, which crashes at the second
soft reset in a row.

But since it is a general problem to use UART methods of a UART which has
been deinitialized, checks were added to all applicable methods for a clear
response instead of e.g. a crash.

Deinitialize UART using software reset.  It resets the UART but keeps it
accessible for software, avoiding an exception when UART registers are
accessed after a DeInit.

Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
robert-hh 2023-08-16 16:00:43 +02:00 committed by Damien George
parent 3f5976e14a
commit ce38784fa8
1 changed files with 17 additions and 4 deletions

View File

@ -146,6 +146,12 @@ void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t st
} }
} }
static void machine_uart_ensure_active(machine_uart_obj_t *uart) {
if (uart->lpuart->CTRL == 0) {
mp_raise_OSError(EIO);
}
}
STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, flow=%s, " mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, flow=%s, "
@ -351,13 +357,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);
// uart.deinit() // uart.deinit()
STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) { STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
LPUART_Deinit(self->lpuart); LPUART_SoftwareReset(self->lpuart);
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit); STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit);
STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
machine_uart_ensure_active(self);
size_t count = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle); size_t count = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle);
return MP_OBJ_NEW_SMALL_INT(count); return MP_OBJ_NEW_SMALL_INT(count);
} }
@ -365,6 +372,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
STATIC mp_obj_t machine_uart_sendbreak(mp_obj_t self_in) { STATIC mp_obj_t machine_uart_sendbreak(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
machine_uart_ensure_active(self);
self->lpuart->CTRL |= 1 << LPUART_CTRL_SBK_SHIFT; // Set SBK bit self->lpuart->CTRL |= 1 << LPUART_CTRL_SBK_SHIFT; // Set SBK bit
self->lpuart->CTRL &= ~LPUART_CTRL_SBK_MASK; // Clear SBK bit self->lpuart->CTRL &= ~LPUART_CTRL_SBK_MASK; // Clear SBK bit
return mp_const_none; return mp_const_none;
@ -382,11 +390,11 @@ STATIC mp_obj_t machine_uart_txdone(mp_obj_t self_in) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone); STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone);
// Deinitialize all defined UARTs // Reset all defined UARTs
void machine_uart_deinit_all(void) { void machine_uart_deinit_all(void) {
for (int i = 0; i < sizeof(uart_index_table); i++) { for (int i = 0; i < MICROPY_HW_UART_NUM; i++) {
if (uart_index_table[i] != 0) { if (uart_index_table[i] != 0) {
LPUART_Deinit(uart_base_ptr_table[uart_index_table[i]]); LPUART_SoftwareReset(uart_base_ptr_table[uart_index_table[i]]);
} }
} }
} }
@ -424,6 +432,8 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz
size_t avail; size_t avail;
size_t nget; size_t nget;
machine_uart_ensure_active(self);
for (size_t received = 0; received < size;) { for (size_t received = 0; received < size;) {
// Wait for the first/next character. // Wait for the first/next character.
while ((avail = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle)) <= 0) { while ((avail = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle)) <= 0) {
@ -456,6 +466,8 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin
size_t offset = 0; size_t offset = 0;
uint8_t fifo_size = FSL_FEATURE_LPUART_FIFO_SIZEn(0); uint8_t fifo_size = FSL_FEATURE_LPUART_FIFO_SIZEn(0);
machine_uart_ensure_active(self);
// First check if a previous transfer is still ongoing, // First check if a previous transfer is still ongoing,
// then wait at least the number of remaining character times. // then wait at least the number of remaining character times.
t = ticks_us64() + (uint64_t)(self->handle.txDataSize + fifo_size) * (13000000 / self->config.baudRate_Bps + 1000); t = ticks_us64() + (uint64_t)(self->handle.txDataSize + fifo_size) * (13000000 / self->config.baudRate_Bps + 1000);
@ -510,6 +522,7 @@ STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint
machine_uart_obj_t *self = self_in; machine_uart_obj_t *self = self_in;
mp_uint_t ret; mp_uint_t ret;
if (request == MP_STREAM_POLL) { if (request == MP_STREAM_POLL) {
machine_uart_ensure_active(self);
uintptr_t flags = arg; uintptr_t flags = arg;
ret = 0; ret = 0;
if (flags & MP_STREAM_POLL_RD) { if (flags & MP_STREAM_POLL_RD) {