diff options
| author | Damien George <damien@micropython.org> | 2025-03-17 13:19:07 +1100 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2025-04-09 00:22:32 +1000 |
| commit | 293e8db9d739c4e32420a48304ac9d2251e63570 (patch) | |
| tree | 7917735972ee4072db69f7054691deb9e2cce6b0 | |
| parent | 19a4689c6b0b652f8d50be6b658adc649649d5d1 (diff) | |
alif/mpuart: Enhance UART to support bits/parity/stop and more IRQs.
Signed-off-by: Damien George <damien@micropython.org>
| -rw-r--r-- | ports/alif/mpbthciport.c | 10 | ||||
| -rw-r--r-- | ports/alif/mpuart.c | 85 | ||||
| -rw-r--r-- | ports/alif/mpuart.h | 14 |
3 files changed, 92 insertions, 17 deletions
diff --git a/ports/alif/mpbthciport.c b/ports/alif/mpbthciport.c index a37c96215..10a0505fe 100644 --- a/ports/alif/mpbthciport.c +++ b/ports/alif/mpbthciport.c @@ -89,14 +89,20 @@ static ringbuf_t hci_rx_ringbuf = { .iput = 0, }; +static void mp_bluetooth_hci_uart_irq_callback(unsigned int uart_id, unsigned int trigger) { + if (trigger == MP_UART_IRQ_RXIDLE) { + mp_bluetooth_hci_poll_now(); + } +} + int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { hci_uart_id = port; hci_uart_first_char = true; // Initialise the UART. - mp_uart_init(hci_uart_id, baudrate, pin_BT_UART_TX, pin_BT_UART_RX, &hci_rx_ringbuf); + mp_uart_init(hci_uart_id, baudrate, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1, pin_BT_UART_TX, pin_BT_UART_RX, &hci_rx_ringbuf); mp_uart_set_flow(hci_uart_id, pin_BT_UART_RTS, pin_BT_UART_CTS); - mp_uart_set_irq_callback(hci_uart_id, mp_bluetooth_hci_poll_now); + mp_uart_set_irq_callback(hci_uart_id, MP_UART_IRQ_RXIDLE, mp_bluetooth_hci_uart_irq_callback); // Start the HCI polling to process any initial events/packets. mp_bluetooth_hci_start_polling(); diff --git a/ports/alif/mpuart.c b/ports/alif/mpuart.c index 7f14ff544..4fe82ce12 100644 --- a/ports/alif/mpuart.c +++ b/ports/alif/mpuart.c @@ -26,20 +26,28 @@ #include "py/mphal.h" #include "py/runtime.h" +#include "shared/runtime/softtimer.h" #include "mpuart.h" - #include "sys_ctrl_uart.h" -#include "uart.h" -#define UART_MAX (8) +#define mp_container_of(ptr, structure, member) (void *)((uintptr_t)(ptr) - offsetof(structure, member)) + +#define UART_LSR_TEMT_Pos (6) #define SYST_PCLK (100000000) +#define CALCULATE_BITS_PER_CHAR(data_bits, parity, stop_bits) \ + (1 + ((data_bits) + 5) + ((parity) != UART_PARITY_NONE) + ((stop_bits) + 1)) + typedef struct _uart_state_t { UART_TRANSFER_STATUS status; + uint32_t baudrate; + uint32_t bits_per_char; ringbuf_t *rx_ringbuf; const uint8_t *tx_src; const uint8_t *tx_src_max; - void (*irq_callback)(void); + soft_timer_entry_t rx_idle_timer; + unsigned int irq_trigger; + void (*irq_callback)(unsigned int uart_id, unsigned int trigger); } uart_state_t; static const uint8_t uart_irqn[UART_MAX] = { @@ -66,7 +74,19 @@ static UART_Type *const uart_periph[UART_MAX] = { static uart_state_t uart_state[UART_MAX]; -void mp_uart_init(unsigned int uart_id, uint32_t baudrate, mp_hal_pin_obj_t tx, mp_hal_pin_obj_t rx, ringbuf_t *rx_ringbuf) { +// This is called by soft_timer and executes at IRQ_PRI_PENDSV. +static void rx_idle_timer_callback(soft_timer_entry_t *self) { + uart_state_t *state = mp_container_of(self, uart_state_t, rx_idle_timer); + if (state->irq_callback != NULL && state->irq_trigger & MP_UART_IRQ_RXIDLE) { + unsigned int uart_id = state - &uart_state[0]; + state->irq_callback(uart_id, MP_UART_IRQ_RXIDLE); + } +} + +void mp_uart_init(unsigned int uart_id, uint32_t baudrate, + UART_DATA_BITS data_bits, UART_PARITY parity, UART_STOP_BITS stop_bits, + mp_hal_pin_obj_t tx, mp_hal_pin_obj_t rx, ringbuf_t *rx_ringbuf) { + UART_Type *uart = uart_periph[uart_id]; uart_state_t *state = &uart_state[uart_id]; @@ -82,17 +102,20 @@ void mp_uart_init(unsigned int uart_id, uint32_t baudrate, mp_hal_pin_obj_t tx, uart_disable_tx_irq(uart); uart_disable_rx_irq(uart); uart_set_baudrate(uart, SYST_PCLK, baudrate); - uart_set_data_parity_stop_bits(uart, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1); + uart_set_data_parity_stop_bits(uart, data_bits, parity, stop_bits); uart_set_flow_control(uart, UART_FLOW_CONTROL_NONE); uart->UART_FCR |= UART_FCR_RCVR_FIFO_RESET; uart_set_tx_trigger(uart, UART_TX_FIFO_EMPTY); - uart_set_rx_trigger(uart, UART_RX_ONE_CHAR_IN_FIFO); + uart_set_rx_trigger(uart, UART_RX_FIFO_QUARTER_FULL); // Initialise the state. state->status = UART_TRANSFER_STATUS_NONE; + state->baudrate = baudrate; + state->bits_per_char = CALCULATE_BITS_PER_CHAR(data_bits, parity, stop_bits); state->rx_ringbuf = rx_ringbuf; state->tx_src = NULL; state->tx_src_max = NULL; + state->irq_trigger = 0; state->irq_callback = NULL; // Enable interrupts. @@ -100,6 +123,8 @@ void mp_uart_init(unsigned int uart_id, uint32_t baudrate, mp_hal_pin_obj_t tx, NVIC_SetPriority(uart_irqn[uart_id], IRQ_PRI_UART_REPL); NVIC_EnableIRQ(uart_irqn[uart_id]); uart_enable_rx_irq(uart); + + soft_timer_static_init(&state->rx_idle_timer, SOFT_TIMER_MODE_ONE_SHOT, 0, rx_idle_timer_callback); } void mp_uart_deinit(unsigned int uart_id) { @@ -109,9 +134,16 @@ void mp_uart_deinit(unsigned int uart_id) { NVIC_DisableIRQ(uart_irqn[uart_id]); } -void mp_uart_set_irq_callback(unsigned int uart_id, void (*callback)(void)) { +void mp_uart_set_irq_callback(unsigned int uart_id, unsigned int trigger, void (*callback)(unsigned int uart_id, unsigned int trigger)) { + UART_Type *uart = uart_periph[uart_id]; uart_state_t *state = &uart_state[uart_id]; + state->irq_trigger = trigger; state->irq_callback = callback; + if (trigger & MP_UART_IRQ_RX) { + uart_set_rx_trigger(uart, UART_RX_ONE_CHAR_IN_FIFO); + } else { + uart_set_rx_trigger(uart, UART_RX_FIFO_QUARTER_FULL); + } } void mp_uart_set_flow(unsigned int uart_id, mp_hal_pin_obj_t rts, mp_hal_pin_obj_t cts) { @@ -131,10 +163,20 @@ void mp_uart_set_flow(unsigned int uart_id, mp_hal_pin_obj_t rts, mp_hal_pin_obj void mp_uart_set_baudrate(unsigned int uart_id, uint32_t baudrate) { UART_Type *uart = uart_periph[uart_id]; + uart_state_t *state = &uart_state[uart_id]; + state->baudrate = baudrate; uart_set_baudrate(uart, SYST_PCLK, baudrate); } +void mp_uart_set_bits_parity_stop(unsigned int uart_id, UART_DATA_BITS data_bits, UART_PARITY parity, UART_STOP_BITS stop_bits) { + UART_Type *uart = uart_periph[uart_id]; + uart_state_t *state = &uart_state[uart_id]; + + state->bits_per_char = CALCULATE_BITS_PER_CHAR(data_bits, parity, stop_bits); + uart_set_data_parity_stop_bits(uart, data_bits, parity, stop_bits); +} + size_t mp_uart_rx_any(unsigned int uart_id) { uart_state_t *state = &uart_state[uart_id]; if (state->rx_ringbuf != NULL) { @@ -143,6 +185,11 @@ size_t mp_uart_rx_any(unsigned int uart_id) { return 0; } +size_t mp_uart_tx_any(unsigned int uart_id) { + UART_Type *uart = uart_periph[uart_id]; + return uart->UART_TFL + !((uart->UART_LSR >> UART_LSR_TEMT_Pos) & 1); +} + int mp_uart_rx_char(unsigned int uart_id) { uart_state_t *state = &uart_state[uart_id]; if (state->rx_ringbuf != NULL && ringbuf_avail(state->rx_ringbuf)) { @@ -208,9 +255,11 @@ static void mp_uart_irq_handler(unsigned int uart_id) { } case UART_IIR_RECEIVED_DATA_AVAILABLE: - case UART_IIR_CHARACTER_TIMEOUT: + case UART_IIR_CHARACTER_TIMEOUT: { + bool had_char = false; while (uart->UART_USR & UART_USR_RECEIVE_FIFO_NOT_EMPTY) { for (uint32_t rfl = uart->UART_RFL; rfl; --rfl) { + had_char = true; int c = uart->UART_RBR; #if MICROPY_HW_ENABLE_UART_REPL && MICROPY_KBD_EXCEPTION if (uart_id == MICROPY_HW_UART_REPL) { @@ -226,13 +275,18 @@ static void mp_uart_irq_handler(unsigned int uart_id) { } } - if (iir == UART_IIR_CHARACTER_TIMEOUT) { - if (state->irq_callback != NULL) { - state->irq_callback(); + if (had_char) { + if (state->irq_callback != NULL && state->irq_trigger & MP_UART_IRQ_RX) { + state->irq_callback(uart_id, MP_UART_IRQ_RX); } } + if (state->irq_trigger & MP_UART_IRQ_RXIDLE) { + // Wait for 2 characters worth of time before triggering the RXIDLE event. + soft_timer_reinsert(&state->rx_idle_timer, 2000 * state->bits_per_char / state->baudrate + 1); + } break; + } case UART_IIR_TRANSMIT_HOLDING_REG_EMPTY: while (uart->UART_USR & UART_USR_TRANSMIT_FIFO_NOT_FULL) { @@ -241,6 +295,9 @@ static void mp_uart_irq_handler(unsigned int uart_id) { } else { uart_disable_tx_irq(uart); state->status = UART_TRANSFER_STATUS_SEND_COMPLETE; + if (state->irq_callback != NULL && state->irq_trigger & MP_UART_IRQ_TXIDLE) { + state->irq_callback(uart_id, MP_UART_IRQ_TXIDLE); + } break; } } @@ -273,7 +330,9 @@ DEFINE_IRQ_HANDLER(7) #define REPL_BAUDRATE (115200) void mp_uart_init_repl(void) { - mp_uart_init(MICROPY_HW_UART_REPL, REPL_BAUDRATE, pin_REPL_UART_TX, pin_REPL_UART_RX, &stdin_ringbuf); + mp_uart_init(MICROPY_HW_UART_REPL, + REPL_BAUDRATE, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1, + pin_REPL_UART_TX, pin_REPL_UART_RX, &stdin_ringbuf); } void mp_uart_write_strn_repl(const char *str, size_t len) { diff --git a/ports/alif/mpuart.h b/ports/alif/mpuart.h index 1c28da462..76dadaab3 100644 --- a/ports/alif/mpuart.h +++ b/ports/alif/mpuart.h @@ -27,15 +27,25 @@ #define MICROPY_INCLUDED_ALIF2_UART_H #include "py/ringbuf.h" +#include "uart.h" -void mp_uart_init(unsigned int uart_id, uint32_t baudrate, mp_hal_pin_obj_t tx, mp_hal_pin_obj_t rx, ringbuf_t *rx_ringbuf); +#define UART_MAX (8) +#define MP_UART_IRQ_RX (1) +#define MP_UART_IRQ_RXIDLE (2) +#define MP_UART_IRQ_TXIDLE (4) + +void mp_uart_init(unsigned int uart_id, uint32_t baudrate, + UART_DATA_BITS data_bits, UART_PARITY parity, UART_STOP_BITS stop_bits, + mp_hal_pin_obj_t tx, mp_hal_pin_obj_t rx, ringbuf_t *rx_ringbuf); void mp_uart_deinit(unsigned int uart_id); -void mp_uart_set_irq_callback(unsigned int uart_id, void (*callback)(void)); +void mp_uart_set_irq_callback(unsigned int uart_id, unsigned int trigger, void (*callback)(unsigned int uart_id, unsigned int trigger)); void mp_uart_set_flow(unsigned int uart_id, mp_hal_pin_obj_t rts, mp_hal_pin_obj_t cts); void mp_uart_set_baudrate(unsigned int uart_id, uint32_t baudrate); +void mp_uart_set_bits_parity_stop(unsigned int uart_id, UART_DATA_BITS data_bits, UART_PARITY parity, UART_STOP_BITS stop_bits); size_t mp_uart_rx_any(unsigned int uart_id); +size_t mp_uart_tx_any(unsigned int uart_id); int mp_uart_rx_char(unsigned int uart_id); void mp_uart_tx_data(unsigned int uart_id, const uint8_t *src, size_t len); |
