summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2025-03-17 13:19:07 +1100
committerDamien George <damien@micropython.org>2025-04-09 00:22:32 +1000
commit293e8db9d739c4e32420a48304ac9d2251e63570 (patch)
tree7917735972ee4072db69f7054691deb9e2cce6b0
parent19a4689c6b0b652f8d50be6b658adc649649d5d1 (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.c10
-rw-r--r--ports/alif/mpuart.c85
-rw-r--r--ports/alif/mpuart.h14
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);