alif/mpuart: Enhance UART to support bits/parity/stop and more IRQs.
Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
@@ -89,14 +89,20 @@ static ringbuf_t hci_rx_ringbuf = {
|
|||||||
.iput = 0,
|
.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) {
|
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
|
||||||
hci_uart_id = port;
|
hci_uart_id = port;
|
||||||
hci_uart_first_char = true;
|
hci_uart_first_char = true;
|
||||||
|
|
||||||
// Initialise the UART.
|
// 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_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.
|
// Start the HCI polling to process any initial events/packets.
|
||||||
mp_bluetooth_hci_start_polling();
|
mp_bluetooth_hci_start_polling();
|
||||||
|
|||||||
@@ -26,20 +26,28 @@
|
|||||||
|
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
#include "shared/runtime/softtimer.h"
|
||||||
#include "mpuart.h"
|
#include "mpuart.h"
|
||||||
|
|
||||||
#include "sys_ctrl_uart.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 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 {
|
typedef struct _uart_state_t {
|
||||||
UART_TRANSFER_STATUS status;
|
UART_TRANSFER_STATUS status;
|
||||||
|
uint32_t baudrate;
|
||||||
|
uint32_t bits_per_char;
|
||||||
ringbuf_t *rx_ringbuf;
|
ringbuf_t *rx_ringbuf;
|
||||||
const uint8_t *tx_src;
|
const uint8_t *tx_src;
|
||||||
const uint8_t *tx_src_max;
|
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;
|
} uart_state_t;
|
||||||
|
|
||||||
static const uint8_t uart_irqn[UART_MAX] = {
|
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];
|
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_Type *uart = uart_periph[uart_id];
|
||||||
uart_state_t *state = &uart_state[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_tx_irq(uart);
|
||||||
uart_disable_rx_irq(uart);
|
uart_disable_rx_irq(uart);
|
||||||
uart_set_baudrate(uart, SYST_PCLK, baudrate);
|
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_set_flow_control(uart, UART_FLOW_CONTROL_NONE);
|
||||||
uart->UART_FCR |= UART_FCR_RCVR_FIFO_RESET;
|
uart->UART_FCR |= UART_FCR_RCVR_FIFO_RESET;
|
||||||
uart_set_tx_trigger(uart, UART_TX_FIFO_EMPTY);
|
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.
|
// Initialise the state.
|
||||||
state->status = UART_TRANSFER_STATUS_NONE;
|
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->rx_ringbuf = rx_ringbuf;
|
||||||
state->tx_src = NULL;
|
state->tx_src = NULL;
|
||||||
state->tx_src_max = NULL;
|
state->tx_src_max = NULL;
|
||||||
|
state->irq_trigger = 0;
|
||||||
state->irq_callback = NULL;
|
state->irq_callback = NULL;
|
||||||
|
|
||||||
// Enable interrupts.
|
// 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_SetPriority(uart_irqn[uart_id], IRQ_PRI_UART_REPL);
|
||||||
NVIC_EnableIRQ(uart_irqn[uart_id]);
|
NVIC_EnableIRQ(uart_irqn[uart_id]);
|
||||||
uart_enable_rx_irq(uart);
|
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) {
|
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]);
|
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];
|
uart_state_t *state = &uart_state[uart_id];
|
||||||
|
state->irq_trigger = trigger;
|
||||||
state->irq_callback = callback;
|
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) {
|
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) {
|
void mp_uart_set_baudrate(unsigned int uart_id, uint32_t baudrate) {
|
||||||
UART_Type *uart = uart_periph[uart_id];
|
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);
|
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) {
|
size_t mp_uart_rx_any(unsigned int uart_id) {
|
||||||
uart_state_t *state = &uart_state[uart_id];
|
uart_state_t *state = &uart_state[uart_id];
|
||||||
if (state->rx_ringbuf != NULL) {
|
if (state->rx_ringbuf != NULL) {
|
||||||
@@ -143,6 +185,11 @@ size_t mp_uart_rx_any(unsigned int uart_id) {
|
|||||||
return 0;
|
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) {
|
int mp_uart_rx_char(unsigned int uart_id) {
|
||||||
uart_state_t *state = &uart_state[uart_id];
|
uart_state_t *state = &uart_state[uart_id];
|
||||||
if (state->rx_ringbuf != NULL && ringbuf_avail(state->rx_ringbuf)) {
|
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_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) {
|
while (uart->UART_USR & UART_USR_RECEIVE_FIFO_NOT_EMPTY) {
|
||||||
for (uint32_t rfl = uart->UART_RFL; rfl; --rfl) {
|
for (uint32_t rfl = uart->UART_RFL; rfl; --rfl) {
|
||||||
|
had_char = true;
|
||||||
int c = uart->UART_RBR;
|
int c = uart->UART_RBR;
|
||||||
#if MICROPY_HW_ENABLE_UART_REPL && MICROPY_KBD_EXCEPTION
|
#if MICROPY_HW_ENABLE_UART_REPL && MICROPY_KBD_EXCEPTION
|
||||||
if (uart_id == MICROPY_HW_UART_REPL) {
|
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 (had_char) {
|
||||||
if (state->irq_callback != NULL) {
|
if (state->irq_callback != NULL && state->irq_trigger & MP_UART_IRQ_RX) {
|
||||||
state->irq_callback();
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case UART_IIR_TRANSMIT_HOLDING_REG_EMPTY:
|
case UART_IIR_TRANSMIT_HOLDING_REG_EMPTY:
|
||||||
while (uart->UART_USR & UART_USR_TRANSMIT_FIFO_NOT_FULL) {
|
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 {
|
} else {
|
||||||
uart_disable_tx_irq(uart);
|
uart_disable_tx_irq(uart);
|
||||||
state->status = UART_TRANSFER_STATUS_SEND_COMPLETE;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,7 +330,9 @@ DEFINE_IRQ_HANDLER(7)
|
|||||||
#define REPL_BAUDRATE (115200)
|
#define REPL_BAUDRATE (115200)
|
||||||
|
|
||||||
void mp_uart_init_repl(void) {
|
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) {
|
void mp_uart_write_strn_repl(const char *str, size_t len) {
|
||||||
|
|||||||
@@ -27,15 +27,25 @@
|
|||||||
#define MICROPY_INCLUDED_ALIF2_UART_H
|
#define MICROPY_INCLUDED_ALIF2_UART_H
|
||||||
|
|
||||||
#include "py/ringbuf.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_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_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_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_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);
|
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);
|
void mp_uart_tx_data(unsigned int uart_id, const uint8_t *src, size_t len);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user