Browse Source

stmhal: Fix UART so bits counts number of data bits, not incl parity.

Addresses issue #950.
pull/954/head
Damien George 10 years ago
parent
commit
4029f51842
  1. 38
      docs/library/pyb.UART.rst
  2. 51
      stmhal/uart.c

38
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 = UART(1, 9600) # init with given baudrate
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters 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 A UART object acts like a stream object and reading and writing is done
using the standard stream methods:: using the standard stream methods::
@ -44,9 +47,9 @@ Constructors
initialised (it has the settings from the last initialisation of initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised. the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation. See ``init`` for parameters of initialisation.
The physical pins of the UART busses are: The physical pins of the UART busses are:
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)`` - ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)`` - ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)`` - ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
@ -57,35 +60,44 @@ Constructors
Methods 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) .. 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: Initialise the UART bus with the given parameters:
- ``baudrate`` is the clock rate. - ``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). - ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
- ``stop`` is the number of stop bits, 1 or 2. - ``stop`` is the number of stop bits, 1 or 2.
- ``timeout`` is the timeout in milliseconds to wait for the first character. - ``timeout`` is the timeout in milliseconds to wait for the first character.
- ``timeout_char`` is the timeout in milliseconds to wait between characters. - ``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). - ``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]) .. 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() .. method:: uart.readall()
Read as much data as possible.
.. method:: uart.readchar() .. method:: uart.readchar()
Receive a single character on the bus. Receive a single character on the bus.
Return value: The character read, as an integer. Returns -1 on timeout. Return value: The character read, as an integer. Returns -1 on timeout.
.. method:: uart.readinto(buf[, nbytes]) .. method:: uart.readinto(buf[, nbytes])

51
stmhal/uart.c

@ -80,13 +80,14 @@
struct _pyb_uart_obj_t { struct _pyb_uart_obj_t {
mp_obj_base_t base; mp_obj_base_t base;
pyb_uart_t uart_id; UART_HandleTypeDef uart; // this is 17 words big
bool is_enabled;
UART_HandleTypeDef uart;
IRQn_Type irqn; 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; // timeout waiting for first char
uint16_t timeout_char; // timeout waiting between chars 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 uint16_t read_buf_len; // len in chars; buf can hold len-1 chars
volatile uint16_t read_buf_head; // indexes first empty slot volatile uint16_t read_buf_head; // indexes first empty slot
uint16_t read_buf_tail; // indexes first full slot (not full if equals head) 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; return data;
} else { } else {
// no buffering // 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) { if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) {
int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE
data &= self->char_mask;
if (self->read_buf_len != 0) { if (self->read_buf_len != 0) {
uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
if (next_head != self->read_buf_tail) { 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) { if (!self->is_enabled) {
print(env, "UART(%u)", self->uart_id); print(env, "UART(%u)", self->uart_id);
} else { } 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=", print(env, "UART(%u, baudrate=%u, bits=%u, parity=",
self->uart_id, self->uart.Init.BaudRate, self->uart_id, self->uart.Init.BaudRate, bits);
self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9);
if (self->uart.Init.Parity == UART_PARITY_NONE) { if (self->uart.Init.Parity == UART_PARITY_NONE) {
print(env, "None"); print(env, "None");
} else { } 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: /// Initialise the UART bus with the given parameters:
/// ///
/// - `baudrate` is the clock rate. /// - `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). /// - `parity` is the parity, `None`, 0 (even) or 1 (odd).
/// - `stop` is the number of stop bits, 1 or 2. /// - `stop` is the number of stop bits, 1 or 2.
/// - `timeout` is the timeout in milliseconds to wait for the first character. /// - `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 // set the UART configuration values
memset(&self->uart, 0, sizeof(self->uart)); memset(&self->uart, 0, sizeof(self->uart));
UART_InitTypeDef *init = &self->uart.Init; UART_InitTypeDef *init = &self->uart.Init;
// baudrate
init->BaudRate = args[0].u_int; 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) { if (args[2].u_obj == mp_const_none) {
init->Parity = UART_PARITY_NONE; init->Parity = UART_PARITY_NONE;
} else { } else {
mp_int_t parity = mp_obj_get_int(args[2].u_obj); mp_int_t parity = mp_obj_get_int(args[2].u_obj);
init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN; 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) { switch (args[3].u_int) {
case 1: init->StopBits = UART_STOPBITS_1; break; case 1: init->StopBits = UART_STOPBITS_1; break;
default: init->StopBits = UART_STOPBITS_2; break; default: init->StopBits = UART_STOPBITS_2; break;
} }
init->Mode = UART_MODE_TX_RX;
// flow control
init->HwFlowCtl = args[4].u_int; init->HwFlowCtl = args[4].u_int;
// extra config (not yet configurable)
init->Mode = UART_MODE_TX_RX;
init->OverSampling = UART_OVERSAMPLING_16; init->OverSampling = UART_OVERSAMPLING_16;
// init UART (if it fails, it's because the port doesn't exist) // 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 // setup the read buffer
m_del(byte, self->read_buf, self->read_buf_len << self->char_width); m_del(byte, self->read_buf, self->read_buf_len << self->char_width);
if (init->WordLength == UART_WORDLENGTH_9B && init->Parity == UART_PARITY_NONE) { if (init->WordLength == UART_WORDLENGTH_9B && init->Parity == UART_PARITY_NONE) {
self->char_mask = 0x1ff;
self->char_width = CHAR_WIDTH_9BIT; self->char_width = CHAR_WIDTH_9BIT;
} else { } 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->char_width = CHAR_WIDTH_8BIT;
} }
self->read_buf_head = 0; self->read_buf_head = 0;

Loading…
Cancel
Save