Skip to content

Commit 4029f51

Browse files
committed
stmhal: Fix UART so bits counts number of data bits, not incl parity.
Addresses issue adafruit#950.
1 parent 1559a97 commit 4029f51

2 files changed

Lines changed: 66 additions & 23 deletions

File tree

docs/library/pyb.UART.rst

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ UART objects can be created and initialised using::
1313
uart = UART(1, 9600) # init with given baudrate
1414
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
1515

16-
Bits can be 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
16+
Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
17+
18+
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
19+
only 7 and 8 bits are supported.
1720

1821
A UART object acts like a stream object and reading and writing is done
1922
using the standard stream methods::
@@ -44,9 +47,9 @@ Constructors
4447
initialised (it has the settings from the last initialisation of
4548
the bus, if any). If extra arguments are given, the bus is initialised.
4649
See ``init`` for parameters of initialisation.
47-
50+
4851
The physical pins of the UART busses are:
49-
52+
5053
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
5154
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
5255
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
@@ -57,35 +60,44 @@ Constructors
5760
Methods
5861
-------
5962

60-
.. method:: uart.any()
61-
62-
Return ``True`` if any characters waiting, else ``False``.
63-
64-
.. method:: uart.deinit()
65-
66-
Turn off the UART bus.
67-
6863
.. method:: uart.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, timeout_char=0, read_buf_len=64)
6964

7065
Initialise the UART bus with the given parameters:
71-
66+
7267
- ``baudrate`` is the clock rate.
73-
- ``bits`` is the number of bits per byte, 8 or 9.
68+
- ``bits`` is the number of bits per character, 7, 8 or 9.
7469
- ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
7570
- ``stop`` is the number of stop bits, 1 or 2.
7671
- ``timeout`` is the timeout in milliseconds to wait for the first character.
7772
- ``timeout_char`` is the timeout in milliseconds to wait between characters.
7873
- ``read_buf_len`` is the character length of the read buffer (0 to disable).
7974

75+
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
76+
only 7 and 8 bits are supported.
77+
78+
.. method:: uart.deinit()
79+
80+
Turn off the UART bus.
81+
82+
.. method:: uart.any()
83+
84+
Return ``True`` if any characters waiting, else ``False``.
85+
8086
.. method:: uart.read([nbytes])
8187

88+
Read characters. If ``nbytes`` is specified then read at most that many bytes.
89+
90+
*Note:* for 9 bit characters each character takes 2 bytes, ``nbytes`` must be even,
91+
and the number of characters is ``nbytes/2``.
8292

8393
.. method:: uart.readall()
8494

95+
Read as much data as possible.
8596

8697
.. method:: uart.readchar()
8798

8899
Receive a single character on the bus.
100+
89101
Return value: The character read, as an integer. Returns -1 on timeout.
90102

91103
.. method:: uart.readinto(buf[, nbytes])

stmhal/uart.c

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,14 @@
8080

8181
struct _pyb_uart_obj_t {
8282
mp_obj_base_t base;
83-
pyb_uart_t uart_id;
84-
bool is_enabled;
85-
UART_HandleTypeDef uart;
83+
UART_HandleTypeDef uart; // this is 17 words big
8684
IRQn_Type irqn;
85+
pyb_uart_t uart_id : 8;
86+
bool is_enabled : 1;
87+
byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars
88+
uint16_t char_mask; // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit
8789
uint16_t timeout; // timeout waiting for first char
8890
uint16_t timeout_char; // timeout waiting between chars
89-
uint16_t char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars
9091
uint16_t read_buf_len; // len in chars; buf can hold len-1 chars
9192
volatile uint16_t read_buf_head; // indexes first empty slot
9293
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) {
280281
return data;
281282
} else {
282283
// no buffering
283-
return self->uart.Instance->DR;
284+
return self->uart.Instance->DR & self->char_mask;
284285
}
285286
}
286287

@@ -315,6 +316,7 @@ void uart_irq_handler(mp_uint_t uart_id) {
315316

316317
if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) {
317318
int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE
319+
data &= self->char_mask;
318320
if (self->read_buf_len != 0) {
319321
uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
320322
if (next_head != self->read_buf_tail) {
@@ -340,9 +342,12 @@ STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void
340342
if (!self->is_enabled) {
341343
print(env, "UART(%u)", self->uart_id);
342344
} else {
345+
mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9);
346+
if (self->uart.Init.Parity != UART_PARITY_NONE) {
347+
bits -= 1;
348+
}
343349
print(env, "UART(%u, baudrate=%u, bits=%u, parity=",
344-
self->uart_id, self->uart.Init.BaudRate,
345-
self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9);
350+
self->uart_id, self->uart.Init.BaudRate, bits);
346351
if (self->uart.Init.Parity == UART_PARITY_NONE) {
347352
print(env, "None");
348353
} else {
@@ -359,7 +364,7 @@ STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void
359364
/// Initialise the UART bus with the given parameters:
360365
///
361366
/// - `baudrate` is the clock rate.
362-
/// - `bits` is the number of bits per byte, 8 or 9.
367+
/// - `bits` is the number of bits per byte, 7, 8 or 9.
363368
/// - `parity` is the parity, `None`, 0 (even) or 1 (odd).
364369
/// - `stop` is the number of stop bits, 1 or 2.
365370
/// - `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
384389
// set the UART configuration values
385390
memset(&self->uart, 0, sizeof(self->uart));
386391
UART_InitTypeDef *init = &self->uart.Init;
392+
393+
// baudrate
387394
init->BaudRate = args[0].u_int;
388-
init->WordLength = args[1].u_int == 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B;
395+
396+
// parity
397+
mp_int_t bits = args[1].u_int;
389398
if (args[2].u_obj == mp_const_none) {
390399
init->Parity = UART_PARITY_NONE;
391400
} else {
392401
mp_int_t parity = mp_obj_get_int(args[2].u_obj);
393402
init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN;
403+
bits += 1; // STs convention has bits including parity
394404
}
405+
406+
// number of bits
407+
if (bits == 8) {
408+
init->WordLength = UART_WORDLENGTH_8B;
409+
} else if (bits == 9) {
410+
init->WordLength = UART_WORDLENGTH_9B;
411+
} else {
412+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unsupported combination of bits and parity"));
413+
}
414+
415+
// stop bits
395416
switch (args[3].u_int) {
396417
case 1: init->StopBits = UART_STOPBITS_1; break;
397418
default: init->StopBits = UART_STOPBITS_2; break;
398419
}
399-
init->Mode = UART_MODE_TX_RX;
420+
421+
// flow control
400422
init->HwFlowCtl = args[4].u_int;
423+
424+
// extra config (not yet configurable)
425+
init->Mode = UART_MODE_TX_RX;
401426
init->OverSampling = UART_OVERSAMPLING_16;
402427

403428
// 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
412437
// setup the read buffer
413438
m_del(byte, self->read_buf, self->read_buf_len << self->char_width);
414439
if (init->WordLength == UART_WORDLENGTH_9B && init->Parity == UART_PARITY_NONE) {
440+
self->char_mask = 0x1ff;
415441
self->char_width = CHAR_WIDTH_9BIT;
416442
} else {
443+
if (init->WordLength == UART_WORDLENGTH_9B || init->Parity == UART_PARITY_NONE) {
444+
self->char_mask = 0xff;
445+
} else {
446+
self->char_mask = 0x7f;
447+
}
417448
self->char_width = CHAR_WIDTH_8BIT;
418449
}
419450
self->read_buf_head = 0;

0 commit comments

Comments
 (0)