@@ -107,10 +107,17 @@ static const char *_parity_name[] = {"None", "", "0", "1"}; // Is defined as 0,
107107
108108// take all bytes from the fifo and store them in the buffer
109109static void uart_drain_rx_fifo (machine_uart_obj_t * self , Sercom * uart ) {
110+ uint8_t bits = self -> bits ;
110111 while (uart -> USART .INTFLAG .bit .RXC != 0 ) {
111- if (ringbuf_free (& self -> read_buffer ) > 0 ) {
112- // get a byte from uart and put into the buffer
113- ringbuf_put (& (self -> read_buffer ), uart -> USART .DATA .bit .DATA );
112+ if (ringbuf_free (& self -> read_buffer ) >= (bits <= 8 ? 1 : 2 )) {
113+ // get a word from uart and put into the buffer
114+ if (bits <= 8 ) {
115+ ringbuf_put (& (self -> read_buffer ), uart -> USART .DATA .bit .DATA );
116+ } else {
117+ uint16_t data = uart -> USART .DATA .bit .DATA ;
118+ ringbuf_put (& (self -> read_buffer ), data );
119+ ringbuf_put (& (self -> read_buffer ), data >> 8 );
120+ }
114121 } else {
115122 // if the buffer is full, disable the RX interrupt
116123 // allowing RTS to come up. It will be re-enabled by the next read
@@ -150,7 +157,12 @@ void common_uart_irq_handler(int uart_id) {
150157 #if MICROPY_HW_UART_TXBUF
151158 // handle the outgoing data
152159 if (ringbuf_avail (& self -> write_buffer ) > 0 ) {
153- uart -> USART .DATA .bit .DATA = ringbuf_get (& self -> write_buffer );
160+ if (self -> bits <= 8 ) {
161+ uart -> USART .DATA .bit .DATA = ringbuf_get (& self -> write_buffer );
162+ } else {
163+ uart -> USART .DATA .bit .DATA =
164+ ringbuf_get (& self -> write_buffer ) | (ringbuf_get (& self -> write_buffer ) << 8 );
165+ }
154166 } else {
155167 #if MICROPY_PY_MACHINE_UART_IRQ
156168 // Set the TXIDLE flag
@@ -274,6 +286,17 @@ void machine_uart_set_baudrate(mp_obj_t self_in, uint32_t baudrate) {
274286
275287static void mp_machine_uart_print (const mp_print_t * print , mp_obj_t self_in , mp_print_kind_t kind ) {
276288 machine_uart_obj_t * self = MP_OBJ_TO_PTR (self_in );
289+ size_t rxbuf_len = self -> read_buffer .size - 1 ;
290+ #if MICROPY_HW_UART_TXBUF
291+ size_t txbuf_len = self -> write_buffer .size - 1 ;
292+ #endif
293+ if (self -> bits > 8 ) {
294+ rxbuf_len /= 2 ;
295+ #if MICROPY_HW_UART_TXBUF
296+ txbuf_len /= 2 ;
297+ #endif
298+ }
299+
277300 mp_printf (print , "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, "
278301 "timeout=%u, timeout_char=%u, rxbuf=%d"
279302 #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_
287310 #endif
288311 ")" ,
289312 self -> id , self -> baudrate , self -> bits , _parity_name [self -> parity ],
290- self -> stop + 1 , self -> timeout , self -> timeout_char , self -> read_buffer . size - 1
313+ self -> stop + 1 , self -> timeout , self -> timeout_char , rxbuf_len
291314 #if MICROPY_HW_UART_TXBUF
292- , self -> write_buffer . size - 1
315+ , txbuf_len
293316 #endif
294317 #if MICROPY_HW_UART_RTSCTS
295318 , 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,
411434 }
412435 }
413436 #endif
437+
438+ // Double the buffer lengths for 9 bit transfer
439+ if (self -> bits > 8 ) {
440+ rxbuf_len *= 2 ;
441+ #if MICROPY_HW_UART_TXBUF
442+ txbuf_len *= 2 ;
443+ #endif
444+ }
414445 // Initialise the UART peripheral if any arguments given, or it was not initialised previously.
415446 if (n_args > 0 || kw_args -> used > 0 || self -> new ) {
416447 self -> new = false;
@@ -619,7 +650,12 @@ static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t
619650 uint64_t timeout_char = self -> timeout_char ;
620651 uint8_t * dest = buf_in ;
621652
622- for (size_t i = 0 ; i < size ; i ++ ) {
653+ // Check that size is even for 9 bit transfers.
654+ if ((self -> bits >= 9 ) && (size & 1 )) {
655+ * errcode = MP_EIO ;
656+ return MP_STREAM_ERROR ;
657+ }
658+ for (size_t i = 0 ; i < size ;) {
623659 // Wait for the first/next character
624660 while (ringbuf_avail (& self -> read_buffer ) == 0 ) {
625661 if (mp_hal_ticks_ms_64 () > t ) { // timed out
@@ -633,6 +669,11 @@ static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t
633669 MICROPY_EVENT_POLL_HOOK
634670 }
635671 * dest ++ = ringbuf_get (& (self -> read_buffer ));
672+ i ++ ;
673+ if (self -> bits >= 9 && i < size ) {
674+ * dest ++ = ringbuf_get (& (self -> read_buffer ));
675+ i ++ ;
676+ }
636677 t = mp_hal_ticks_ms_64 () + timeout_char ;
637678 // (Re-)Enable RXC interrupt
638679 if ((uart -> USART .INTENSET .reg & SERCOM_USART_INTENSET_RXC ) == 0 ) {
@@ -647,12 +688,19 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_
647688 size_t i = 0 ;
648689 const uint8_t * src = buf_in ;
649690 Sercom * uart = sercom_instance [self -> id ];
650-
651691 uint64_t t = mp_hal_ticks_ms_64 () + self -> timeout ;
692+ uint8_t bits = self -> bits ;
693+ // Check that size is even for 9 bit transfers.
694+ if ((bits >= 9 ) && (size & 1 )) {
695+ * errcode = MP_EIO ;
696+ return MP_STREAM_ERROR ;
697+ }
698+
652699 #if MICROPY_HW_UART_TXBUF
653700
654701 #if MICROPY_PY_MACHINE_UART_IRQ
655702 // Prefill the FIFO to get rid of the initial IRQ_TXIDLE event
703+ // Do not care for 9 Bit transfer here since the UART is not yet started.
656704 while (i < size && ringbuf_free (& (self -> write_buffer )) > 0 ) {
657705 ringbuf_put (& (self -> write_buffer ), * src ++ );
658706 i ++ ;
@@ -672,8 +720,16 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_
672720 }
673721 MICROPY_EVENT_POLL_HOOK
674722 }
675- ringbuf_put (& (self -> write_buffer ), * src ++ );
676- i ++ ;
723+ if (bits >= 9 ) {
724+ mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION ();
725+ ringbuf_put (& (self -> write_buffer ), * src ++ );
726+ ringbuf_put (& (self -> write_buffer ), * src ++ );
727+ i += 2 ;
728+ MICROPY_END_ATOMIC_SECTION (atomic_state );
729+ } else {
730+ ringbuf_put (& (self -> write_buffer ), * src ++ );
731+ i += 1 ;
732+ }
677733 uart -> USART .INTENSET .reg = SERCOM_USART_INTENSET_DRE ; // kick off the IRQ
678734 }
679735
@@ -691,7 +747,13 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_
691747 }
692748 MICROPY_EVENT_POLL_HOOK
693749 }
694- uart -> USART .DATA .bit .DATA = * src ++ ;
750+ if (self -> bits > 8 && i < (size - 1 )) {
751+ uart -> USART .DATA .bit .DATA = * (uint16_t * )src ;
752+ i ++ ;
753+ src += 2 ;
754+ } else {
755+ uart -> USART .DATA .bit .DATA = * src ++ ;
756+ }
695757 i ++ ;
696758 }
697759 #endif
0 commit comments