alif/mpuart: Generalise UART driver to suppot all UART instances.
Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
@@ -66,7 +66,7 @@ int main(void) {
|
|||||||
MICROPY_BOARD_EARLY_INIT();
|
MICROPY_BOARD_EARLY_INIT();
|
||||||
|
|
||||||
#if MICROPY_HW_ENABLE_UART_REPL
|
#if MICROPY_HW_ENABLE_UART_REPL
|
||||||
mp_uart_init();
|
mp_uart_init_repl();
|
||||||
#endif
|
#endif
|
||||||
#if MICROPY_HW_ENABLE_OSPI
|
#if MICROPY_HW_ENABLE_OSPI
|
||||||
if (ospi_flash_init() != 0) {
|
if (ospi_flash_init() != 0) {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
#define MICROPY_HW_USB_PID (0x9802) // interface has CDC only
|
#define MICROPY_HW_USB_PID (0x9802) // interface has CDC only
|
||||||
#endif
|
#endif
|
||||||
#ifndef MICROPY_HW_ENABLE_UART_REPL
|
#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
|
#endif
|
||||||
#define MICROPY_HW_FLASH_BLOCK_SIZE_BYTES (4096)
|
#define MICROPY_HW_FLASH_BLOCK_SIZE_BYTES (4096)
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MICROPY_HW_ENABLE_UART_REPL
|
#if MICROPY_HW_ENABLE_UART_REPL
|
||||||
mp_uart_write_strn(str, len);
|
mp_uart_write_strn_repl(str, len);
|
||||||
did_write = true;
|
did_write = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -24,88 +24,260 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "py/runtime.h"
|
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
|
#include "py/runtime.h"
|
||||||
#include "mpuart.h"
|
#include "mpuart.h"
|
||||||
|
|
||||||
#if MICROPY_HW_ENABLE_UART_REPL
|
|
||||||
|
|
||||||
#include "pinconf.h"
|
|
||||||
#include "sys_ctrl_uart.h"
|
#include "sys_ctrl_uart.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
|
||||||
#define TX_PIN pin_P12_2
|
#define UART_MAX (8)
|
||||||
#define RX_PIN pin_P12_1
|
#define SYST_PCLK (100000000)
|
||||||
#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;
|
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;
|
||||||
|
|
||||||
void mp_uart_init(void) {
|
static const uint8_t uart_irqn[UART_MAX] = {
|
||||||
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);
|
UART0_IRQ_IRQn,
|
||||||
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);
|
UART1_IRQ_IRQn,
|
||||||
select_uart_clock_syst_pclk(UART_ID);
|
UART2_IRQ_IRQn,
|
||||||
enable_uart_clock(UART_ID);
|
UART3_IRQ_IRQn,
|
||||||
uart_software_reset(UART_PTR);
|
UART4_IRQ_IRQn,
|
||||||
uart_enable_fifo(UART_PTR);
|
UART5_IRQ_IRQn,
|
||||||
uart_disable_tx_irq(UART_PTR);
|
UART6_IRQ_IRQn,
|
||||||
uart_disable_rx_irq(UART_PTR);
|
UART7_IRQ_IRQn,
|
||||||
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);
|
static UART_Type *const uart_periph[UART_MAX] = {
|
||||||
NVIC_ClearPendingIRQ(UART_IRQN);
|
(UART_Type *)UART0_BASE,
|
||||||
NVIC_SetPriority(UART_IRQN, IRQ_PRI_UART_REPL);
|
(UART_Type *)UART1_BASE,
|
||||||
NVIC_EnableIRQ(UART_IRQN);
|
(UART_Type *)UART2_BASE,
|
||||||
uart_set_tx_trigger(UART_PTR, UART_TX_FIFO_EMPTY);
|
(UART_Type *)UART3_BASE,
|
||||||
uart_set_rx_trigger(UART_PTR, UART_RX_ONE_CHAR_IN_FIFO);
|
(UART_Type *)UART4_BASE,
|
||||||
uart_enable_rx_irq(UART_PTR);
|
(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_write_strn(const char *str, size_t len) {
|
void mp_uart_deinit(unsigned int uart_id) {
|
||||||
memset(&transfer, 0, sizeof(transfer));
|
UART_Type *uart = uart_periph[uart_id];
|
||||||
transfer.tx_buf = (uint8_t *)str;
|
|
||||||
transfer.tx_total_num = len;
|
|
||||||
transfer.tx_curr_cnt = 0U;
|
|
||||||
transfer.status = UART_TRANSFER_STATUS_NONE;
|
|
||||||
|
|
||||||
uart_enable_tx_irq(UART_PTR);
|
uart_disable_rx_irq(uart);
|
||||||
|
NVIC_DisableIRQ(uart_irqn[uart_id]);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t start = mp_hal_ticks_ms();
|
void mp_uart_set_irq_callback(unsigned int uart_id, void (*callback)(void)) {
|
||||||
while (transfer.status == UART_TRANSFER_STATUS_NONE) {
|
uart_state_t *state = &uart_state[uart_id];
|
||||||
if (mp_hal_ticks_ms() - start > 10 * len) {
|
state->irq_callback = callback;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
__WFE();
|
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];
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
uart_disable_tx_irq(UART_PTR);
|
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 UART4_IRQHandler(void) {
|
void mp_uart_set_baudrate(unsigned int uart_id, uint32_t baudrate) {
|
||||||
if (UART_PTR->UART_RFL) {
|
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 (;;) {
|
for (;;) {
|
||||||
uint32_t rx_fifo_available_cnt = UART_PTR->UART_RFL;
|
size_t tx_avail = UART_FIFO_DEPTH - uart->UART_TFL;
|
||||||
if (rx_fifo_available_cnt == 0) {
|
if (tx_avail > 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < rx_fifo_available_cnt; ++i) {
|
mp_event_handle_nowait();
|
||||||
int c = UART_PTR->UART_RBR;
|
|
||||||
#if MICROPY_KBD_EXCEPTION
|
|
||||||
if (c == mp_interrupt_char) {
|
|
||||||
mp_sched_keyboard_interrupt();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ringbuf_put(&stdin_ringbuf, c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
uart->UART_THR = src[i];
|
||||||
uart_irq_handler(UART_PTR, &transfer);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (state->status == UART_TRANSFER_STATUS_NONE) {
|
||||||
|
if (mp_hal_ticks_ms() - start > total_timeout_ms) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mp_event_wait_indefinite();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable TX IRQ.
|
||||||
|
uart_disable_tx_irq(uart);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
__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
|
#endif
|
||||||
|
|||||||
@@ -26,7 +26,20 @@
|
|||||||
#ifndef MICROPY_INCLUDED_ALIF2_UART_H
|
#ifndef MICROPY_INCLUDED_ALIF2_UART_H
|
||||||
#define MICROPY_INCLUDED_ALIF2_UART_H
|
#define MICROPY_INCLUDED_ALIF2_UART_H
|
||||||
|
|
||||||
void mp_uart_init(void);
|
#include "py/ringbuf.h"
|
||||||
void mp_uart_write_strn(const char *str, size_t len);
|
|
||||||
|
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
|
#endif // MICROPY_INCLUDED_ALIF2_UART_H
|
||||||
|
|||||||
Reference in New Issue
Block a user