summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/alif/main.c2
-rw-r--r--ports/alif/mpconfigport.h2
-rw-r--r--ports/alif/mphalport.c2
-rw-r--r--ports/alif/mpuart.c294
-rw-r--r--ports/alif/mpuart.h17
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