From 4029f51842656e7a1576dbe7c41aeea3eef83645 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 31 Oct 2014 20:28:10 +0000 Subject: [PATCH] stmhal: Fix UART so bits counts number of data bits, not incl parity. Addresses issue #950. --- docs/library/pyb.UART.rst | 38 +++++++++++++++++++---------- stmhal/uart.c | 51 +++++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/docs/library/pyb.UART.rst b/docs/library/pyb.UART.rst index c96810b639..f9760734bc 100644 --- a/docs/library/pyb.UART.rst +++ b/docs/library/pyb.UART.rst @@ -13,7 +13,10 @@ UART objects can be created and initialised using:: uart = UART(1, 9600) # init with given baudrate uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters -Bits can be 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2. +Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2. + +*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled, +only 7 and 8 bits are supported. A UART object acts like a stream object and reading and writing is done using the standard stream methods:: @@ -44,9 +47,9 @@ Constructors initialised (it has the settings from the last initialisation of the bus, if any). If extra arguments are given, the bus is initialised. See ``init`` for parameters of initialisation. - + The physical pins of the UART busses are: - + - ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)`` - ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)`` - ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)`` @@ -57,35 +60,44 @@ Constructors Methods ------- -.. method:: uart.any() - - Return ``True`` if any characters waiting, else ``False``. - -.. method:: uart.deinit() - - Turn off the UART bus. - .. method:: uart.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, timeout_char=0, read_buf_len=64) Initialise the UART bus with the given parameters: - + - ``baudrate`` is the clock rate. - - ``bits`` is the number of bits per byte, 8 or 9. + - ``bits`` is the number of bits per character, 7, 8 or 9. - ``parity`` is the parity, ``None``, 0 (even) or 1 (odd). - ``stop`` is the number of stop bits, 1 or 2. - ``timeout`` is the timeout in milliseconds to wait for the first character. - ``timeout_char`` is the timeout in milliseconds to wait between characters. - ``read_buf_len`` is the character length of the read buffer (0 to disable). + *Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled, + only 7 and 8 bits are supported. + +.. method:: uart.deinit() + + Turn off the UART bus. + +.. method:: uart.any() + + Return ``True`` if any characters waiting, else ``False``. + .. method:: uart.read([nbytes]) + Read characters. If ``nbytes`` is specified then read at most that many bytes. + + *Note:* for 9 bit characters each character takes 2 bytes, ``nbytes`` must be even, + and the number of characters is ``nbytes/2``. .. method:: uart.readall() + Read as much data as possible. .. method:: uart.readchar() Receive a single character on the bus. + Return value: The character read, as an integer. Returns -1 on timeout. .. method:: uart.readinto(buf[, nbytes]) diff --git a/stmhal/uart.c b/stmhal/uart.c index 8543740b37..f29ccfeb31 100644 --- a/stmhal/uart.c +++ b/stmhal/uart.c @@ -80,13 +80,14 @@ struct _pyb_uart_obj_t { mp_obj_base_t base; - pyb_uart_t uart_id; - bool is_enabled; - UART_HandleTypeDef uart; + UART_HandleTypeDef uart; // this is 17 words big IRQn_Type irqn; + pyb_uart_t uart_id : 8; + bool is_enabled : 1; + byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars + uint16_t char_mask; // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit uint16_t timeout; // timeout waiting for first char uint16_t timeout_char; // timeout waiting between chars - uint16_t char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars uint16_t read_buf_len; // len in chars; buf can hold len-1 chars volatile uint16_t read_buf_head; // indexes first empty slot uint16_t read_buf_tail; // indexes first full slot (not full if equals head) @@ -280,7 +281,7 @@ int uart_rx_char(pyb_uart_obj_t *self) { return data; } else { // no buffering - return self->uart.Instance->DR; + return self->uart.Instance->DR & self->char_mask; } } @@ -315,6 +316,7 @@ void uart_irq_handler(mp_uint_t uart_id) { if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) { int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE + data &= self->char_mask; if (self->read_buf_len != 0) { uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; if (next_head != self->read_buf_tail) { @@ -340,9 +342,12 @@ STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void if (!self->is_enabled) { print(env, "UART(%u)", self->uart_id); } else { + mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9); + if (self->uart.Init.Parity != UART_PARITY_NONE) { + bits -= 1; + } print(env, "UART(%u, baudrate=%u, bits=%u, parity=", - self->uart_id, self->uart.Init.BaudRate, - self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9); + self->uart_id, self->uart.Init.BaudRate, bits); if (self->uart.Init.Parity == UART_PARITY_NONE) { print(env, "None"); } else { @@ -359,7 +364,7 @@ STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void /// Initialise the UART bus with the given parameters: /// /// - `baudrate` is the clock rate. -/// - `bits` is the number of bits per byte, 8 or 9. +/// - `bits` is the number of bits per byte, 7, 8 or 9. /// - `parity` is the parity, `None`, 0 (even) or 1 (odd). /// - `stop` is the number of stop bits, 1 or 2. /// - `timeout` is the timeout in milliseconds to wait for the first character. @@ -384,20 +389,40 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, mp_uint_t n_args, con // set the UART configuration values memset(&self->uart, 0, sizeof(self->uart)); UART_InitTypeDef *init = &self->uart.Init; + + // baudrate init->BaudRate = args[0].u_int; - init->WordLength = args[1].u_int == 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B; + + // parity + mp_int_t bits = args[1].u_int; if (args[2].u_obj == mp_const_none) { init->Parity = UART_PARITY_NONE; } else { mp_int_t parity = mp_obj_get_int(args[2].u_obj); init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN; + bits += 1; // STs convention has bits including parity } + + // number of bits + if (bits == 8) { + init->WordLength = UART_WORDLENGTH_8B; + } else if (bits == 9) { + init->WordLength = UART_WORDLENGTH_9B; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unsupported combination of bits and parity")); + } + + // stop bits switch (args[3].u_int) { case 1: init->StopBits = UART_STOPBITS_1; break; default: init->StopBits = UART_STOPBITS_2; break; } - init->Mode = UART_MODE_TX_RX; + + // flow control init->HwFlowCtl = args[4].u_int; + + // extra config (not yet configurable) + init->Mode = UART_MODE_TX_RX; init->OverSampling = UART_OVERSAMPLING_16; // init UART (if it fails, it's because the port doesn't exist) @@ -412,8 +437,14 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, mp_uint_t n_args, con // setup the read buffer m_del(byte, self->read_buf, self->read_buf_len << self->char_width); if (init->WordLength == UART_WORDLENGTH_9B && init->Parity == UART_PARITY_NONE) { + self->char_mask = 0x1ff; self->char_width = CHAR_WIDTH_9BIT; } else { + if (init->WordLength == UART_WORDLENGTH_9B || init->Parity == UART_PARITY_NONE) { + self->char_mask = 0xff; + } else { + self->char_mask = 0x7f; + } self->char_width = CHAR_WIDTH_8BIT; } self->read_buf_head = 0;