Skip to content

Commit e1b4e9b

Browse files
committed
UART: Always allocate UART objects in the long-lived pool
Particularly when they have buffers that are written via IRQ or DMA, UART objects do not relocate gracefully. If such an object is relocated to the long-lived pool after its original creation, the IRQ or DMA will write to an unexpected location within the Python heap, leading to a variety of symptoms. The most frequent symptom is inability to read from the UART. Consider the particular case of atmel-samd: usart_uart_obj_t contains a usart_async_descriptor contains a _usart_async_device. In _sercom_init_irq_param the address of this contained _usart_async_device is assigned to a global array sercom_to_sercom_dev which is later used from the interrupt context _sercom_usart_interrupt_handler to store the received data in the right ring buffer. When the UART object is relocated to the long-lived heap, there's no mechanism to re-point these internal pointers, so instead take the cowardly way and allocate the UART object as long-lived. Happily, almost all UART objects are likely to be long-lived, so this is unlikely to have a negative effect on memory usage or heap fragmentation. Closes: adafruit#1056
1 parent 2e80f37 commit e1b4e9b

File tree

1 file changed

+5
-1
lines changed

1 file changed

+5
-1
lines changed

shared-bindings/busio/UART.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ extern const busio_uart_parity_obj_t busio_uart_parity_odd_obj;
6666

6767
STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
6868
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
69-
busio_uart_obj_t *self = m_new_obj(busio_uart_obj_t);
69+
// Always initially allocate the UART object within the long-lived heap.
70+
// This is needed to avoid crashes with certain UART implementations which
71+
// cannot accomodate being moved after creation. (See
72+
// https://github.com/adafruit/circuitpython/issues/1056)
73+
busio_uart_obj_t *self = m_new_ll_obj(busio_uart_obj_t);
7074
self->base.type = &busio_uart_type;
7175
mp_map_t kw_args;
7276
mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);

0 commit comments

Comments
 (0)