mimxrt/machine_uart: Fix rx/tx buffer allocation bug.

The buffer would be reset on every call to `uart.init()`.  If no sizes were
given, the buffer would be set to the default size 256.  That made problems
e.g. with PPP.  Also, the RX buffer was not stored at the UART object and
not visible to GC as being in use.  Then a `gc.collect()` would eventually
free the buffer.

This commit fixes those issues, keeping the buffer size if not deliberately
changed and allocating new buffers only if the size was changed.

Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
robert-hh
2025-03-09 09:08:01 +01:00
committed by Damien George
parent 1398e7fd20
commit b85ad4bd41

View File

@@ -66,6 +66,8 @@ typedef struct _machine_uart_obj_t {
uint16_t tx_status;
uint8_t *txbuf;
uint16_t txbuf_len;
uint8_t *rxbuf;
uint16_t rxbuf_len;
bool new;
uint16_t mp_irq_trigger; // user IRQ trigger mask
uint16_t mp_irq_flags; // user IRQ active IRQ flags
@@ -197,7 +199,7 @@ static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_
self->id, self->config.baudRate_Bps, 8 - self->config.dataBitsCount,
_parity_name[self->config.parityMode], self->config.stopBitCount + 1,
_flow_name[(self->config.enableTxCTS << 1) | self->config.enableRxRTS],
self->handle.rxRingBufferSize, self->txbuf_len, self->timeout, self->timeout_char,
self->rxbuf_len, self->txbuf_len, self->timeout, self->timeout_char,
_invert_name[self->invert], self->mp_irq_trigger);
}
@@ -291,25 +293,33 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args,
self->config.enableRx = true;
// Set the RX buffer size if configured.
size_t rxbuf_len = DEFAULT_BUFFER_SIZE;
if (args[ARG_rxbuf].u_int > 0) {
rxbuf_len = args[ARG_rxbuf].u_int;
size_t rxbuf_len = args[ARG_rxbuf].u_int;
if (rxbuf_len < MIN_BUFFER_SIZE) {
rxbuf_len = MIN_BUFFER_SIZE;
} else if (rxbuf_len > MAX_BUFFER_SIZE) {
mp_raise_ValueError(MP_ERROR_TEXT("rxbuf too large"));
}
// Force re-allocting of the buffer if the size changed
if (rxbuf_len != self->rxbuf_len) {
self->rxbuf = NULL;
self->rxbuf_len = rxbuf_len;
}
}
// Set the TX buffer size if configured.
size_t txbuf_len = DEFAULT_BUFFER_SIZE;
if (args[ARG_txbuf].u_int > 0) {
txbuf_len = args[ARG_txbuf].u_int;
size_t txbuf_len = args[ARG_txbuf].u_int;
if (txbuf_len < MIN_BUFFER_SIZE) {
txbuf_len = MIN_BUFFER_SIZE;
} else if (txbuf_len > MAX_BUFFER_SIZE) {
mp_raise_ValueError(MP_ERROR_TEXT("txbuf too large"));
}
// Force re-allocting of the buffer if the size is changed
if (txbuf_len != self->txbuf_len) {
self->txbuf = NULL;
self->txbuf_len = txbuf_len;
}
}
// Initialise the UART peripheral if any arguments given, or it was not initialised previously.
@@ -335,10 +345,13 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args,
LPUART_Init(self->lpuart, &self->config, CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot));
#endif
LPUART_TransferCreateHandle(self->lpuart, &self->handle, LPUART_UserCallback, self);
uint8_t *buffer = m_new(uint8_t, rxbuf_len + 1);
LPUART_TransferStartRingBuffer(self->lpuart, &self->handle, buffer, rxbuf_len);
self->txbuf = m_new(uint8_t, txbuf_len); // Allocate the TX buffer.
self->txbuf_len = txbuf_len;
if (self->rxbuf == NULL) {
self->rxbuf = m_new(uint8_t, self->rxbuf_len + 1);
}
LPUART_TransferStartRingBuffer(self->lpuart, &self->handle, self->rxbuf, self->rxbuf_len);
if (self->txbuf == NULL) {
self->txbuf = m_new(uint8_t, self->txbuf_len); // Allocate the TX buffer.
}
#if MICROPY_PY_MACHINE_UART_IRQ
LPUART_EnableInterrupts(self->lpuart, kLPUART_IdleLineInterruptEnable);
@@ -380,6 +393,10 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
self->invert = false;
self->timeout = 1;
self->timeout_char = 1;
self->rxbuf = NULL;
self->rxbuf_len = DEFAULT_BUFFER_SIZE;
self->txbuf = NULL;
self->txbuf_len = DEFAULT_BUFFER_SIZE;
self->new = true;
self->mp_irq_obj = NULL;
self->mp_irq_trigger = 0;