Skip to content

Commit 411146b

Browse files
committed
alif/mpuart: Generalise UART driver to suppot all UART instances.
Signed-off-by: Damien George <damien@micropython.org>
1 parent 4f2a8bd commit 411146b

File tree

5 files changed

+251
-66
lines changed

5 files changed

+251
-66
lines changed

ports/alif/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ int main(void) {
6666
MICROPY_BOARD_EARLY_INIT();
6767

6868
#if MICROPY_HW_ENABLE_UART_REPL
69-
mp_uart_init();
69+
mp_uart_init_repl();
7070
#endif
7171
#if MICROPY_HW_ENABLE_OSPI
7272
if (ospi_flash_init() != 0) {

ports/alif/mpconfigport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
#define MICROPY_HW_USB_PID (0x9802) // interface has CDC only
7474
#endif
7575
#ifndef MICROPY_HW_ENABLE_UART_REPL
76-
#define MICROPY_HW_ENABLE_UART_REPL (CORE_M55_HP) // useful if there is no USB
76+
#define MICROPY_HW_ENABLE_UART_REPL (0)
7777
#endif
7878
#define MICROPY_HW_FLASH_BLOCK_SIZE_BYTES (4096)
7979

ports/alif/mphalport.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
9191
#endif
9292

9393
#if MICROPY_HW_ENABLE_UART_REPL
94-
mp_uart_write_strn(str, len);
94+
mp_uart_write_strn_repl(str, len);
9595
did_write = true;
9696
#endif
9797

ports/alif/mpuart.c

Lines changed: 233 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -24,88 +24,260 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
#include <string.h>
28-
#include "py/runtime.h"
2927
#include "py/mphal.h"
28+
#include "py/runtime.h"
3029
#include "mpuart.h"
3130

32-
#if MICROPY_HW_ENABLE_UART_REPL
33-
34-
#include "pinconf.h"
3531
#include "sys_ctrl_uart.h"
3632
#include "uart.h"
3733

38-
#define TX_PIN pin_P12_2
39-
#define RX_PIN pin_P12_1
40-
#define UART_ID 4
41-
#define UART_IRQN UART4_IRQ_IRQn
42-
#define UART_PTR ((UART_Type *)UART4_BASE)
43-
#define BAUDRATE 115200
44-
#define SYST_PCLK 100000000
45-
46-
static UART_TRANSFER transfer;
47-
48-
void mp_uart_init(void) {
49-
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);
50-
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);
51-
select_uart_clock_syst_pclk(UART_ID);
52-
enable_uart_clock(UART_ID);
53-
uart_software_reset(UART_PTR);
54-
uart_enable_fifo(UART_PTR);
55-
uart_disable_tx_irq(UART_PTR);
56-
uart_disable_rx_irq(UART_PTR);
57-
uart_set_baudrate(UART_PTR, SYST_PCLK, BAUDRATE);
58-
uart_set_data_parity_stop_bits(UART_PTR, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1);
59-
uart_set_flow_control(UART_PTR, UART_FLOW_CONTROL_NONE);
60-
NVIC_ClearPendingIRQ(UART_IRQN);
61-
NVIC_SetPriority(UART_IRQN, IRQ_PRI_UART_REPL);
62-
NVIC_EnableIRQ(UART_IRQN);
63-
uart_set_tx_trigger(UART_PTR, UART_TX_FIFO_EMPTY);
64-
uart_set_rx_trigger(UART_PTR, UART_RX_ONE_CHAR_IN_FIFO);
65-
uart_enable_rx_irq(UART_PTR);
34+
#define UART_MAX (8)
35+
#define SYST_PCLK (100000000)
36+
37+
typedef struct _uart_state_t {
38+
UART_TRANSFER_STATUS status;
39+
ringbuf_t *rx_ringbuf;
40+
const uint8_t *tx_src;
41+
const uint8_t *tx_src_max;
42+
void (*irq_callback)(void);
43+
} uart_state_t;
44+
45+
static const uint8_t uart_irqn[UART_MAX] = {
46+
UART0_IRQ_IRQn,
47+
UART1_IRQ_IRQn,
48+
UART2_IRQ_IRQn,
49+
UART3_IRQ_IRQn,
50+
UART4_IRQ_IRQn,
51+
UART5_IRQ_IRQn,
52+
UART6_IRQ_IRQn,
53+
UART7_IRQ_IRQn,
54+
};
55+
56+
static UART_Type *const uart_periph[UART_MAX] = {
57+
(UART_Type *)UART0_BASE,
58+
(UART_Type *)UART1_BASE,
59+
(UART_Type *)UART2_BASE,
60+
(UART_Type *)UART3_BASE,
61+
(UART_Type *)UART4_BASE,
62+
(UART_Type *)UART5_BASE,
63+
(UART_Type *)UART6_BASE,
64+
(UART_Type *)UART7_BASE,
65+
};
66+
67+
static uart_state_t uart_state[UART_MAX];
68+
69+
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) {
70+
UART_Type *uart = uart_periph[uart_id];
71+
uart_state_t *state = &uart_state[uart_id];
72+
73+
// Configure TX/RX pins.
74+
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);
75+
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);
76+
77+
// Configure the UART peripheral.
78+
select_uart_clock_syst_pclk(uart_id);
79+
enable_uart_clock(uart_id);
80+
uart_software_reset(uart);
81+
uart_enable_fifo(uart);
82+
uart_disable_tx_irq(uart);
83+
uart_disable_rx_irq(uart);
84+
uart_set_baudrate(uart, SYST_PCLK, baudrate);
85+
uart_set_data_parity_stop_bits(uart, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1);
86+
uart_set_flow_control(uart, UART_FLOW_CONTROL_NONE);
87+
uart->UART_FCR |= UART_FCR_RCVR_FIFO_RESET;
88+
uart_set_tx_trigger(uart, UART_TX_FIFO_EMPTY);
89+
uart_set_rx_trigger(uart, UART_RX_ONE_CHAR_IN_FIFO);
90+
91+
// Initialise the state.
92+
state->status = UART_TRANSFER_STATUS_NONE;
93+
state->rx_ringbuf = rx_ringbuf;
94+
state->tx_src = NULL;
95+
state->tx_src_max = NULL;
96+
state->irq_callback = NULL;
97+
98+
// Enable interrupts.
99+
NVIC_ClearPendingIRQ(uart_irqn[uart_id]);
100+
NVIC_SetPriority(uart_irqn[uart_id], IRQ_PRI_UART_REPL);
101+
NVIC_EnableIRQ(uart_irqn[uart_id]);
102+
uart_enable_rx_irq(uart);
103+
}
104+
105+
void mp_uart_deinit(unsigned int uart_id) {
106+
UART_Type *uart = uart_periph[uart_id];
107+
108+
uart_disable_rx_irq(uart);
109+
NVIC_DisableIRQ(uart_irqn[uart_id]);
110+
}
111+
112+
void mp_uart_set_irq_callback(unsigned int uart_id, void (*callback)(void)) {
113+
uart_state_t *state = &uart_state[uart_id];
114+
state->irq_callback = callback;
66115
}
67116

68-
void mp_uart_write_strn(const char *str, size_t len) {
69-
memset(&transfer, 0, sizeof(transfer));
70-
transfer.tx_buf = (uint8_t *)str;
71-
transfer.tx_total_num = len;
72-
transfer.tx_curr_cnt = 0U;
73-
transfer.status = UART_TRANSFER_STATUS_NONE;
117+
void mp_uart_set_flow(unsigned int uart_id, mp_hal_pin_obj_t rts, mp_hal_pin_obj_t cts) {
118+
UART_Type *uart = uart_periph[uart_id];
74119

75-
uart_enable_tx_irq(UART_PTR);
120+
unsigned int flow = UART_FLOW_CONTROL_NONE;
121+
if (rts != NULL) {
122+
flow |= UART_FLOW_CONTROL_RTS;
123+
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);
124+
}
125+
if (cts != NULL) {
126+
flow |= UART_FLOW_CONTROL_CTS;
127+
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);
128+
}
129+
uart_set_flow_control(uart, flow);
130+
}
131+
132+
void mp_uart_set_baudrate(unsigned int uart_id, uint32_t baudrate) {
133+
UART_Type *uart = uart_periph[uart_id];
134+
135+
uart_set_baudrate(uart, SYST_PCLK, baudrate);
136+
}
137+
138+
size_t mp_uart_rx_any(unsigned int uart_id) {
139+
uart_state_t *state = &uart_state[uart_id];
140+
if (state->rx_ringbuf != NULL) {
141+
return ringbuf_avail(state->rx_ringbuf);
142+
}
143+
return 0;
144+
}
76145

146+
int mp_uart_rx_char(unsigned int uart_id) {
147+
uart_state_t *state = &uart_state[uart_id];
148+
if (state->rx_ringbuf != NULL && ringbuf_avail(state->rx_ringbuf)) {
149+
return ringbuf_get(state->rx_ringbuf);
150+
}
151+
return -1;
152+
}
153+
154+
void mp_uart_tx_data_blocking(unsigned int uart_id, const uint8_t *src, size_t len) {
155+
UART_Type *uart = uart_periph[uart_id];
156+
157+
for (size_t i = 0; i < len; ++i) {
158+
for (;;) {
159+
size_t tx_avail = UART_FIFO_DEPTH - uart->UART_TFL;
160+
if (tx_avail > 0) {
161+
break;
162+
}
163+
mp_event_handle_nowait();
164+
}
165+
uart->UART_THR = src[i];
166+
}
167+
}
168+
169+
void mp_uart_tx_data(unsigned int uart_id, const uint8_t *src, size_t len) {
170+
UART_Type *uart = uart_periph[uart_id];
171+
172+
// Configure transmission, to be handled by IRQ.
173+
uart_state_t *state = &uart_state[uart_id];
174+
state->status = UART_TRANSFER_STATUS_NONE;
175+
state->tx_src = src;
176+
state->tx_src_max = src + len;
177+
178+
// Enable TX IRQ to start transmission.
179+
uart_enable_tx_irq(uart);
180+
181+
// Wait for transfer to complete.
182+
const uint32_t total_timeout_ms = 100 * len;
77183
uint32_t start = mp_hal_ticks_ms();
78-
while (transfer.status == UART_TRANSFER_STATUS_NONE) {
79-
if (mp_hal_ticks_ms() - start > 10 * len) {
184+
while (state->status == UART_TRANSFER_STATUS_NONE) {
185+
if (mp_hal_ticks_ms() - start > total_timeout_ms) {
80186
break;
81187
}
82-
__WFE();
188+
mp_event_wait_indefinite();
83189
}
84-
uart_disable_tx_irq(UART_PTR);
190+
191+
// Disable TX IRQ.
192+
uart_disable_tx_irq(uart);
85193
}
86194

87-
void UART4_IRQHandler(void) {
88-
if (UART_PTR->UART_RFL) {
89-
for (;;) {
90-
uint32_t rx_fifo_available_cnt = UART_PTR->UART_RFL;
91-
if (rx_fifo_available_cnt == 0) {
92-
break;
195+
static void mp_uart_irq_handler(unsigned int uart_id) {
196+
UART_Type *uart = uart_periph[uart_id];
197+
uart_state_t *state = &uart_state[uart_id];
198+
199+
// Process pending interrupt (below is order of highest to lowest priority).
200+
uint32_t iir = uart->UART_IIR & UART_IIR_INTERRUPT_ID_MASK;
201+
switch (iir) {
202+
case UART_IIR_RECEIVER_LINE_STATUS: {
203+
uint32_t lsr = uart->UART_LSR;
204+
if (lsr & (UART_LSR_RECEIVER_FIFO_ERR | UART_LSR_OVERRUN_ERR)) {
205+
state->status = UART_TRANSFER_STATUS_ERROR;
93206
}
94-
for (uint32_t i = 0; i < rx_fifo_available_cnt; ++i) {
95-
int c = UART_PTR->UART_RBR;
96-
#if MICROPY_KBD_EXCEPTION
97-
if (c == mp_interrupt_char) {
98-
mp_sched_keyboard_interrupt();
99-
continue;
207+
break;
208+
}
209+
210+
case UART_IIR_RECEIVED_DATA_AVAILABLE:
211+
case UART_IIR_CHARACTER_TIMEOUT:
212+
while (uart->UART_USR & UART_USR_RECEIVE_FIFO_NOT_EMPTY) {
213+
for (uint32_t rfl = uart->UART_RFL; rfl; --rfl) {
214+
int c = uart->UART_RBR;
215+
#if MICROPY_HW_ENABLE_UART_REPL && MICROPY_KBD_EXCEPTION
216+
if (uart_id == MICROPY_HW_UART_REPL) {
217+
if (c == mp_interrupt_char) {
218+
mp_sched_keyboard_interrupt();
219+
continue;
220+
}
221+
}
222+
#endif
223+
if (state->rx_ringbuf != NULL) {
224+
ringbuf_put(state->rx_ringbuf, c);
225+
}
100226
}
101-
#endif
102-
ringbuf_put(&stdin_ringbuf, c);
103227
}
104-
}
105-
} else {
106-
uart_irq_handler(UART_PTR, &transfer);
228+
229+
if (iir == UART_IIR_CHARACTER_TIMEOUT) {
230+
if (state->irq_callback != NULL) {
231+
state->irq_callback();
232+
}
233+
}
234+
235+
break;
236+
237+
case UART_IIR_TRANSMIT_HOLDING_REG_EMPTY:
238+
while (uart->UART_USR & UART_USR_TRANSMIT_FIFO_NOT_FULL) {
239+
if (state->tx_src < state->tx_src_max) {
240+
uart->UART_THR = *state->tx_src++;
241+
} else {
242+
uart_disable_tx_irq(uart);
243+
state->status = UART_TRANSFER_STATUS_SEND_COMPLETE;
244+
break;
245+
}
246+
}
247+
break;
248+
249+
case UART_IIR_MODEM_STATUS:
250+
(void)uart->UART_MSR;
251+
break;
107252
}
253+
108254
__SEV();
109255
}
110256

257+
#define DEFINE_IRQ_HANDLER(id) \
258+
void UART##id##_IRQHandler(void) { \
259+
mp_uart_irq_handler(id); \
260+
}
261+
262+
DEFINE_IRQ_HANDLER(0)
263+
DEFINE_IRQ_HANDLER(1)
264+
DEFINE_IRQ_HANDLER(2)
265+
DEFINE_IRQ_HANDLER(3)
266+
DEFINE_IRQ_HANDLER(4)
267+
DEFINE_IRQ_HANDLER(5)
268+
DEFINE_IRQ_HANDLER(6)
269+
DEFINE_IRQ_HANDLER(7)
270+
271+
#if MICROPY_HW_ENABLE_UART_REPL
272+
273+
#define REPL_BAUDRATE (115200)
274+
275+
void mp_uart_init_repl(void) {
276+
mp_uart_init(MICROPY_HW_UART_REPL, REPL_BAUDRATE, pin_REPL_UART_TX, pin_REPL_UART_RX, &stdin_ringbuf);
277+
}
278+
279+
void mp_uart_write_strn_repl(const char *str, size_t len) {
280+
mp_uart_tx_data(MICROPY_HW_UART_REPL, (const uint8_t *)str, len);
281+
}
282+
111283
#endif

ports/alif/mpuart.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,20 @@
2626
#ifndef MICROPY_INCLUDED_ALIF2_UART_H
2727
#define MICROPY_INCLUDED_ALIF2_UART_H
2828

29-
void mp_uart_init(void);
30-
void mp_uart_write_strn(const char *str, size_t len);
29+
#include "py/ringbuf.h"
30+
31+
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);
32+
void mp_uart_deinit(unsigned int uart_id);
33+
34+
void mp_uart_set_irq_callback(unsigned int uart_id, void (*callback)(void));
35+
void mp_uart_set_flow(unsigned int uart_id, mp_hal_pin_obj_t rts, mp_hal_pin_obj_t cts);
36+
void mp_uart_set_baudrate(unsigned int uart_id, uint32_t baudrate);
37+
38+
size_t mp_uart_rx_any(unsigned int uart_id);
39+
int mp_uart_rx_char(unsigned int uart_id);
40+
void mp_uart_tx_data(unsigned int uart_id, const uint8_t *src, size_t len);
41+
42+
void mp_uart_init_repl(void);
43+
void mp_uart_write_strn_repl(const char *str, size_t len);
3144

3245
#endif // MICROPY_INCLUDED_ALIF2_UART_H

0 commit comments

Comments
 (0)