diff options
| -rw-r--r-- | ports/alif/main.c | 2 | ||||
| -rw-r--r-- | ports/alif/mpconfigport.h | 2 | ||||
| -rw-r--r-- | ports/alif/mphalport.c | 2 | ||||
| -rw-r--r-- | ports/alif/mpuart.c | 294 | ||||
| -rw-r--r-- | ports/alif/mpuart.h | 17 |
5 files changed, 251 insertions, 66 deletions
diff --git a/ports/alif/main.c b/ports/alif/main.c index 793425fff..77e413e1e 100644 --- a/ports/alif/main.c +++ b/ports/alif/main.c @@ -66,7 +66,7 @@ int main(void) { MICROPY_BOARD_EARLY_INIT(); #if MICROPY_HW_ENABLE_UART_REPL - mp_uart_init(); + mp_uart_init_repl(); #endif #if MICROPY_HW_ENABLE_OSPI if (ospi_flash_init() != 0) { diff --git a/ports/alif/mpconfigport.h b/ports/alif/mpconfigport.h index 33f300641..a5fd4f6db 100644 --- a/ports/alif/mpconfigport.h +++ b/ports/alif/mpconfigport.h @@ -73,7 +73,7 @@ #define MICROPY_HW_USB_PID (0x9802) // interface has CDC only #endif #ifndef MICROPY_HW_ENABLE_UART_REPL -#define MICROPY_HW_ENABLE_UART_REPL (CORE_M55_HP) // useful if there is no USB +#define MICROPY_HW_ENABLE_UART_REPL (0) #endif #define MICROPY_HW_FLASH_BLOCK_SIZE_BYTES (4096) diff --git a/ports/alif/mphalport.c b/ports/alif/mphalport.c index 1a6136c31..8f7780bb8 100644 --- a/ports/alif/mphalport.c +++ b/ports/alif/mphalport.c @@ -91,7 +91,7 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) { #endif #if MICROPY_HW_ENABLE_UART_REPL - mp_uart_write_strn(str, len); + mp_uart_write_strn_repl(str, len); did_write = true; #endif diff --git a/ports/alif/mpuart.c b/ports/alif/mpuart.c index 69734659a..7f14ff544 100644 --- a/ports/alif/mpuart.c +++ b/ports/alif/mpuart.c @@ -24,88 +24,260 @@ * THE SOFTWARE. */ -#include <string.h> -#include "py/runtime.h" #include "py/mphal.h" +#include "py/runtime.h" #include "mpuart.h" -#if MICROPY_HW_ENABLE_UART_REPL - -#include "pinconf.h" #include "sys_ctrl_uart.h" #include "uart.h" -#define TX_PIN pin_P12_2 -#define RX_PIN pin_P12_1 -#define UART_ID 4 -#define UART_IRQN UART4_IRQ_IRQn -#define UART_PTR ((UART_Type *)UART4_BASE) -#define BAUDRATE 115200 -#define SYST_PCLK 100000000 - -static UART_TRANSFER transfer; - -void mp_uart_init(void) { - mp_hal_pin_config(TX_PIN, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_LOW, MP_HAL_PIN_DRIVE_12MA, MP_HAL_PIN_ALT_UART, false); - mp_hal_pin_config(RX_PIN, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_LOW, MP_HAL_PIN_DRIVE_12MA, MP_HAL_PIN_ALT_UART, true); - select_uart_clock_syst_pclk(UART_ID); - enable_uart_clock(UART_ID); - uart_software_reset(UART_PTR); - uart_enable_fifo(UART_PTR); - uart_disable_tx_irq(UART_PTR); - uart_disable_rx_irq(UART_PTR); - uart_set_baudrate(UART_PTR, SYST_PCLK, BAUDRATE); - uart_set_data_parity_stop_bits(UART_PTR, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1); - uart_set_flow_control(UART_PTR, UART_FLOW_CONTROL_NONE); - NVIC_ClearPendingIRQ(UART_IRQN); - NVIC_SetPriority(UART_IRQN, IRQ_PRI_UART_REPL); - NVIC_EnableIRQ(UART_IRQN); - uart_set_tx_trigger(UART_PTR, UART_TX_FIFO_EMPTY); - uart_set_rx_trigger(UART_PTR, UART_RX_ONE_CHAR_IN_FIFO); - uart_enable_rx_irq(UART_PTR); +#define UART_MAX (8) +#define SYST_PCLK (100000000) + +typedef struct _uart_state_t { + UART_TRANSFER_STATUS status; + ringbuf_t *rx_ringbuf; + const uint8_t *tx_src; + const uint8_t *tx_src_max; + void (*irq_callback)(void); +} uart_state_t; + +static const uint8_t uart_irqn[UART_MAX] = { + UART0_IRQ_IRQn, + UART1_IRQ_IRQn, + UART2_IRQ_IRQn, + UART3_IRQ_IRQn, + UART4_IRQ_IRQn, + UART5_IRQ_IRQn, + UART6_IRQ_IRQn, + UART7_IRQ_IRQn, +}; + +static UART_Type *const uart_periph[UART_MAX] = { + (UART_Type *)UART0_BASE, + (UART_Type *)UART1_BASE, + (UART_Type *)UART2_BASE, + (UART_Type *)UART3_BASE, + (UART_Type *)UART4_BASE, + (UART_Type *)UART5_BASE, + (UART_Type *)UART6_BASE, + (UART_Type *)UART7_BASE, +}; + +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) { + UART_Type *uart = uart_periph[uart_id]; + uart_state_t *state = &uart_state[uart_id]; + + // Configure TX/RX pins. + mp_hal_pin_config(tx, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_HIGH, MP_HAL_PIN_DRIVE_8MA, MP_HAL_PIN_ALT_UART, false); + mp_hal_pin_config(rx, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_HIGH, MP_HAL_PIN_DRIVE_8MA, MP_HAL_PIN_ALT_UART, true); + + // Configure the UART peripheral. + select_uart_clock_syst_pclk(uart_id); + enable_uart_clock(uart_id); + uart_software_reset(uart); + uart_enable_fifo(uart); + 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_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); + + // Initialise the state. + state->status = UART_TRANSFER_STATUS_NONE; + state->rx_ringbuf = rx_ringbuf; + state->tx_src = NULL; + state->tx_src_max = NULL; + state->irq_callback = NULL; + + // Enable interrupts. + NVIC_ClearPendingIRQ(uart_irqn[uart_id]); + NVIC_SetPriority(uart_irqn[uart_id], IRQ_PRI_UART_REPL); + NVIC_EnableIRQ(uart_irqn[uart_id]); + uart_enable_rx_irq(uart); +} + +void mp_uart_deinit(unsigned int uart_id) { + UART_Type *uart = uart_periph[uart_id]; + + uart_disable_rx_irq(uart); + NVIC_DisableIRQ(uart_irqn[uart_id]); +} + +void mp_uart_set_irq_callback(unsigned int uart_id, void (*callback)(void)) { + uart_state_t *state = &uart_state[uart_id]; + state->irq_callback = callback; } -void mp_uart_write_strn(const char *str, size_t len) { - memset(&transfer, 0, sizeof(transfer)); - transfer.tx_buf = (uint8_t *)str; - transfer.tx_total_num = len; - transfer.tx_curr_cnt = 0U; - transfer.status = UART_TRANSFER_STATUS_NONE; +void mp_uart_set_flow(unsigned int uart_id, mp_hal_pin_obj_t rts, mp_hal_pin_obj_t cts) { + UART_Type *uart = uart_periph[uart_id]; - uart_enable_tx_irq(UART_PTR); + unsigned int flow = UART_FLOW_CONTROL_NONE; + if (rts != NULL) { + flow |= UART_FLOW_CONTROL_RTS; + mp_hal_pin_config(rts, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_HIGH, MP_HAL_PIN_DRIVE_8MA, MP_HAL_PIN_ALT_UART, false); + } + if (cts != NULL) { + flow |= UART_FLOW_CONTROL_CTS; + mp_hal_pin_config(cts, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_HIGH, MP_HAL_PIN_DRIVE_8MA, MP_HAL_PIN_ALT_UART, true); + } + uart_set_flow_control(uart, flow); +} + +void mp_uart_set_baudrate(unsigned int uart_id, uint32_t baudrate) { + UART_Type *uart = uart_periph[uart_id]; + + uart_set_baudrate(uart, SYST_PCLK, baudrate); +} + +size_t mp_uart_rx_any(unsigned int uart_id) { + uart_state_t *state = &uart_state[uart_id]; + if (state->rx_ringbuf != NULL) { + return ringbuf_avail(state->rx_ringbuf); + } + return 0; +} +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)) { + return ringbuf_get(state->rx_ringbuf); + } + return -1; +} + +void mp_uart_tx_data_blocking(unsigned int uart_id, const uint8_t *src, size_t len) { + UART_Type *uart = uart_periph[uart_id]; + + for (size_t i = 0; i < len; ++i) { + for (;;) { + size_t tx_avail = UART_FIFO_DEPTH - uart->UART_TFL; + if (tx_avail > 0) { + break; + } + mp_event_handle_nowait(); + } + uart->UART_THR = src[i]; + } +} + +void mp_uart_tx_data(unsigned int uart_id, const uint8_t *src, size_t len) { + UART_Type *uart = uart_periph[uart_id]; + + // Configure transmission, to be handled by IRQ. + uart_state_t *state = &uart_state[uart_id]; + state->status = UART_TRANSFER_STATUS_NONE; + state->tx_src = src; + state->tx_src_max = src + len; + + // Enable TX IRQ to start transmission. + uart_enable_tx_irq(uart); + + // Wait for transfer to complete. + const uint32_t total_timeout_ms = 100 * len; uint32_t start = mp_hal_ticks_ms(); - while (transfer.status == UART_TRANSFER_STATUS_NONE) { - if (mp_hal_ticks_ms() - start > 10 * len) { + while (state->status == UART_TRANSFER_STATUS_NONE) { + if (mp_hal_ticks_ms() - start > total_timeout_ms) { break; } - __WFE(); + mp_event_wait_indefinite(); } - uart_disable_tx_irq(UART_PTR); + + // Disable TX IRQ. + uart_disable_tx_irq(uart); } -void UART4_IRQHandler(void) { - if (UART_PTR->UART_RFL) { - for (;;) { - uint32_t rx_fifo_available_cnt = UART_PTR->UART_RFL; - if (rx_fifo_available_cnt == 0) { - break; +static void mp_uart_irq_handler(unsigned int uart_id) { + UART_Type *uart = uart_periph[uart_id]; + uart_state_t *state = &uart_state[uart_id]; + + // Process pending interrupt (below is order of highest to lowest priority). + uint32_t iir = uart->UART_IIR & UART_IIR_INTERRUPT_ID_MASK; + switch (iir) { + case UART_IIR_RECEIVER_LINE_STATUS: { + uint32_t lsr = uart->UART_LSR; + if (lsr & (UART_LSR_RECEIVER_FIFO_ERR | UART_LSR_OVERRUN_ERR)) { + state->status = UART_TRANSFER_STATUS_ERROR; } - for (uint32_t i = 0; i < rx_fifo_available_cnt; ++i) { - int c = UART_PTR->UART_RBR; - #if MICROPY_KBD_EXCEPTION - if (c == mp_interrupt_char) { - mp_sched_keyboard_interrupt(); - continue; + break; + } + + case UART_IIR_RECEIVED_DATA_AVAILABLE: + case UART_IIR_CHARACTER_TIMEOUT: + while (uart->UART_USR & UART_USR_RECEIVE_FIFO_NOT_EMPTY) { + for (uint32_t rfl = uart->UART_RFL; rfl; --rfl) { + int c = uart->UART_RBR; + #if MICROPY_HW_ENABLE_UART_REPL && MICROPY_KBD_EXCEPTION + if (uart_id == MICROPY_HW_UART_REPL) { + if (c == mp_interrupt_char) { + mp_sched_keyboard_interrupt(); + continue; + } + } + #endif + if (state->rx_ringbuf != NULL) { + ringbuf_put(state->rx_ringbuf, c); + } } - #endif - ringbuf_put(&stdin_ringbuf, c); } - } - } else { - uart_irq_handler(UART_PTR, &transfer); + + if (iir == UART_IIR_CHARACTER_TIMEOUT) { + if (state->irq_callback != NULL) { + state->irq_callback(); + } + } + + break; + + case UART_IIR_TRANSMIT_HOLDING_REG_EMPTY: + while (uart->UART_USR & UART_USR_TRANSMIT_FIFO_NOT_FULL) { + if (state->tx_src < state->tx_src_max) { + uart->UART_THR = *state->tx_src++; + } else { + uart_disable_tx_irq(uart); + state->status = UART_TRANSFER_STATUS_SEND_COMPLETE; + break; + } + } + break; + + case UART_IIR_MODEM_STATUS: + (void)uart->UART_MSR; + break; } + __SEV(); } +#define DEFINE_IRQ_HANDLER(id) \ + void UART##id##_IRQHandler(void) { \ + mp_uart_irq_handler(id); \ + } + +DEFINE_IRQ_HANDLER(0) +DEFINE_IRQ_HANDLER(1) +DEFINE_IRQ_HANDLER(2) +DEFINE_IRQ_HANDLER(3) +DEFINE_IRQ_HANDLER(4) +DEFINE_IRQ_HANDLER(5) +DEFINE_IRQ_HANDLER(6) +DEFINE_IRQ_HANDLER(7) + +#if MICROPY_HW_ENABLE_UART_REPL + +#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); +} + +void mp_uart_write_strn_repl(const char *str, size_t len) { + mp_uart_tx_data(MICROPY_HW_UART_REPL, (const uint8_t *)str, len); +} + #endif diff --git a/ports/alif/mpuart.h b/ports/alif/mpuart.h index 0c2e510a9..1c28da462 100644 --- a/ports/alif/mpuart.h +++ b/ports/alif/mpuart.h @@ -26,7 +26,20 @@ #ifndef MICROPY_INCLUDED_ALIF2_UART_H #define MICROPY_INCLUDED_ALIF2_UART_H -void mp_uart_init(void); -void mp_uart_write_strn(const char *str, size_t len); +#include "py/ringbuf.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); +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_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); + +size_t mp_uart_rx_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); + +void mp_uart_init_repl(void); +void mp_uart_write_strn_repl(const char *str, size_t len); #endif // MICROPY_INCLUDED_ALIF2_UART_H |
