From 6d56c05e1e939dcd80f243c0b4e6882530fc3ee1 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Mon, 2 Sep 2024 16:24:46 +0200 Subject: [PATCH] samd/machine_uart.c: Add full support for 9bit data. 9 bit data has to be provided with uart.write() and uart.read() as two bytes, low order byte first. Signed-off-by: robert-hh --- ports/samd/machine_uart.c | 62 ++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/ports/samd/machine_uart.c b/ports/samd/machine_uart.c index b0dc4c5768d13..87137f86fff32 100644 --- a/ports/samd/machine_uart.c +++ b/ports/samd/machine_uart.c @@ -108,9 +108,15 @@ static const char *_parity_name[] = {"None", "", "0", "1"}; // Is defined as 0, // take all bytes from the fifo and store them in the buffer static void uart_drain_rx_fifo(machine_uart_obj_t *self, Sercom *uart) { while (uart->USART.INTFLAG.bit.RXC != 0) { - if (ringbuf_free(&self->read_buffer) > 0) { + if (ringbuf_free(&self->read_buffer) > 1) { // get a byte from uart and put into the buffer - ringbuf_put(&(self->read_buffer), uart->USART.DATA.bit.DATA); + if (self->bits <= 8) { + ringbuf_put(&(self->read_buffer), uart->USART.DATA.bit.DATA); + } else { + uint16_t data = uart->USART.DATA.bit.DATA; + ringbuf_put(&(self->read_buffer), data); + ringbuf_put(&(self->read_buffer), data >> 8); + } } else { // if the buffer is full, disable the RX interrupt // allowing RTS to come up. It will be re-enabled by the next read @@ -148,9 +154,15 @@ void common_uart_irq_handler(int uart_id) { #endif } else if (uart->USART.INTFLAG.bit.DRE != 0) { #if MICROPY_HW_UART_TXBUF + uint16_t min_data = self->bits <= 8 ? 1 : 2; // handle the outgoing data - if (ringbuf_avail(&self->write_buffer) > 0) { - uart->USART.DATA.bit.DATA = ringbuf_get(&self->write_buffer); + if (ringbuf_avail(&self->write_buffer) >= min_data) { + if (self->bits <= 8) { + uart->USART.DATA.bit.DATA = ringbuf_get(&self->write_buffer); + } else { + uart->USART.DATA.bit.DATA = + ringbuf_get(&self->write_buffer) | (ringbuf_get(&self->write_buffer) << 8); + } } else { #if MICROPY_PY_MACHINE_UART_IRQ // Set the TXIDLE flag @@ -274,6 +286,17 @@ void machine_uart_set_baudrate(mp_obj_t self_in, uint32_t baudrate) { static void mp_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); + size_t rxbuf_len = self->read_buffer.size - 1; + #if MICROPY_HW_UART_TXBUF + size_t txbuf_len = self->write_buffer.size - 1; + #endif + if (self->bits > 8) { + rxbuf_len /= 2; + #if MICROPY_HW_UART_TXBUF + txbuf_len /= 2; + #endif + } + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, " "timeout=%u, timeout_char=%u, rxbuf=%d" #if MICROPY_HW_UART_TXBUF @@ -287,9 +310,9 @@ static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_ #endif ")", self->id, self->baudrate, self->bits, _parity_name[self->parity], - self->stop + 1, self->timeout, self->timeout_char, self->read_buffer.size - 1 + self->stop + 1, self->timeout, self->timeout_char, rxbuf_len #if MICROPY_HW_UART_TXBUF - , self->write_buffer.size - 1 + , txbuf_len #endif #if MICROPY_HW_UART_RTSCTS , self->rts != 0xff ? pin_find_by_id(self->rts)->name : MP_QSTR_None @@ -411,6 +434,14 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, } } #endif + + // Double the buffer lengts for 9 bit transfer + if (self->bits > 8) { + rxbuf_len *= 2; + #if MICROPY_HW_UART_TXBUF + txbuf_len *= 2; + #endif + } // Initialise the UART peripheral if any arguments given, or it was not initialised previously. if (n_args > 0 || kw_args->used > 0 || self->new) { self->new = false; @@ -619,7 +650,7 @@ static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t uint64_t timeout_char = self->timeout_char; uint8_t *dest = buf_in; - for (size_t i = 0; i < size; i++) { + for (size_t i = 0; i < size;) { // Wait for the first/next character while (ringbuf_avail(&self->read_buffer) == 0) { if (mp_hal_ticks_ms_64() > t) { // timed out @@ -633,6 +664,11 @@ static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t MICROPY_EVENT_POLL_HOOK } *dest++ = ringbuf_get(&(self->read_buffer)); + i++; + if (self->bits >= 8 && i < size) { + *dest++ = ringbuf_get(&(self->read_buffer)); + i++; + } t = mp_hal_ticks_ms_64() + timeout_char; // (Re-)Enable RXC interrupt if ((uart->USART.INTENSET.reg & SERCOM_USART_INTENSET_RXC) == 0) { @@ -674,6 +710,10 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_ } ringbuf_put(&(self->write_buffer), *src++); i++; + if (self->bits > 8 && i < size) { + ringbuf_put(&(self->write_buffer), *src++); + i++; + } uart->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE; // kick off the IRQ } @@ -691,7 +731,13 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_ } MICROPY_EVENT_POLL_HOOK } - uart->USART.DATA.bit.DATA = *src++; + if (self->bits > 8 && i < (size - 1)) { + uart->USART.DATA.bit.DATA = *(uint16_t *)src; + i++; + src += 2; + } else { + uart->USART.DATA.bit.DATA = *src++; + } i++; } #endif