Skip to content

Commit 372e7a4

Browse files
tobbaddpgeorge
authored andcommitted
stm32: Implement UART.irq() method with initial support for RX idle IRQ.
1 parent 06236bf commit 372e7a4

File tree

4 files changed

+148
-1
lines changed

4 files changed

+148
-1
lines changed

ports/stm32/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ SRC_LIB = $(addprefix lib/,\
114114
utils/pyexec.c \
115115
utils/interrupt_char.c \
116116
utils/sys_stdio_mphal.c \
117+
utils/mpirq.c \
117118
)
118119

119120
ifeq ($(MICROPY_FLOAT_IMPL),double)

ports/stm32/machine_uart.c

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "py/mperrno.h"
3434
#include "py/mphal.h"
3535
#include "lib/utils/interrupt_char.h"
36+
#include "lib/utils/mpirq.h"
3637
#include "uart.h"
3738
#include "irq.h"
3839
#include "pendsv.h"
@@ -72,6 +73,77 @@
7273
///
7374
/// uart.any() # returns True if any characters waiting
7475

76+
typedef struct _pyb_uart_irq_map_t {
77+
uint16_t irq_en;
78+
uint16_t flag;
79+
} pyb_uart_irq_map_t;
80+
81+
STATIC const pyb_uart_irq_map_t mp_irq_map[] = {
82+
{ USART_CR1_IDLEIE, UART_FLAG_IDLE}, // RX idle
83+
{ USART_CR1_PEIE, UART_FLAG_PE}, // parity error
84+
{ USART_CR1_TXEIE, UART_FLAG_TXE}, // TX register empty
85+
{ USART_CR1_TCIE, UART_FLAG_TC}, // TX complete
86+
{ USART_CR1_RXNEIE, UART_FLAG_RXNE}, // RX register not empty
87+
#if 0
88+
// For now only IRQs selected by CR1 are supported
89+
#if defined(STM32F4)
90+
{ USART_CR2_LBDIE, UART_FLAG_LBD}, // LIN break detection
91+
#else
92+
{ USART_CR2_LBDIE, UART_FLAG_LBDF}, // LIN break detection
93+
#endif
94+
{ USART_CR3_CTSIE, UART_FLAG_CTS}, // CTS
95+
#endif
96+
};
97+
98+
// OR-ed IRQ flags which should not be touched by the user
99+
STATIC const uint32_t mp_irq_reserved = UART_FLAG_RXNE;
100+
101+
// OR-ed IRQ flags which are allowed to be used by the user
102+
STATIC const uint32_t mp_irq_allowed = UART_FLAG_IDLE;
103+
104+
STATIC mp_obj_t pyb_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
105+
106+
STATIC void pyb_uart_irq_config(pyb_uart_obj_t *self, bool enable) {
107+
if (self->mp_irq_trigger) {
108+
for (size_t entry = 0; entry < MP_ARRAY_SIZE(mp_irq_map); ++entry) {
109+
if (mp_irq_map[entry].flag & mp_irq_reserved) {
110+
continue;
111+
}
112+
if (mp_irq_map[entry].flag & self->mp_irq_trigger) {
113+
if (enable) {
114+
self->uartx->CR1 |= mp_irq_map[entry].irq_en;
115+
} else {
116+
self->uartx->CR1 &= ~mp_irq_map[entry].irq_en;
117+
}
118+
}
119+
}
120+
}
121+
}
122+
123+
STATIC mp_uint_t pyb_uart_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
124+
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
125+
pyb_uart_irq_config(self, false);
126+
self->mp_irq_trigger = new_trigger;
127+
pyb_uart_irq_config(self, true);
128+
return 0;
129+
}
130+
131+
STATIC mp_uint_t pyb_uart_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
132+
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
133+
if (info_type == MP_IRQ_INFO_FLAGS) {
134+
return self->mp_irq_flags;
135+
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {
136+
return self->mp_irq_trigger;
137+
}
138+
return 0;
139+
}
140+
141+
STATIC const mp_irq_methods_t pyb_uart_irq_methods = {
142+
.init = pyb_uart_irq,
143+
.trigger = pyb_uart_irq_trigger,
144+
.info = pyb_uart_irq_info,
145+
};
146+
75147
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
76148
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
77149
if (!self->is_enabled) {
@@ -123,9 +195,13 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
123195
mp_print_str(print, "CTS");
124196
}
125197
}
126-
mp_printf(print, ", timeout=%u, timeout_char=%u, rxbuf=%u)",
198+
mp_printf(print, ", timeout=%u, timeout_char=%u, rxbuf=%u",
127199
self->timeout, self->timeout_char,
128200
self->read_buf_len == 0 ? 0 : self->read_buf_len - 1); // -1 to adjust for usable length of buffer
201+
if (self->mp_irq_trigger != 0) {
202+
mp_printf(print, "; irq=0x%x", self->mp_irq_trigger);
203+
}
204+
mp_print_str(print, ")");
129205
}
130206
}
131207

@@ -414,6 +490,43 @@ STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
414490
}
415491
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);
416492

493+
// irq(handler, trigger, hard)
494+
STATIC mp_obj_t pyb_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
495+
mp_arg_val_t args[MP_IRQ_ARG_INIT_NUM_ARGS];
496+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_IRQ_ARG_INIT_NUM_ARGS, mp_irq_init_args, args);
497+
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
498+
499+
if (self->mp_irq_obj == NULL) {
500+
self->mp_irq_trigger = 0;
501+
self->mp_irq_obj = mp_irq_new(&pyb_uart_irq_methods, MP_OBJ_FROM_PTR(self));
502+
}
503+
504+
if (n_args > 1 || kw_args->used != 0) {
505+
// Check the handler
506+
mp_obj_t handler = args[MP_IRQ_ARG_INIT_handler].u_obj;
507+
if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
508+
mp_raise_ValueError("handler must be None or callable");
509+
}
510+
511+
// Check the trigger
512+
mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
513+
mp_uint_t not_supported = trigger & ~mp_irq_allowed;
514+
if (trigger != 0 && not_supported) {
515+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "trigger 0x%08x unsupported", not_supported));
516+
}
517+
518+
// Reconfigure user IRQs
519+
pyb_uart_irq_config(self, false);
520+
self->mp_irq_obj->handler = handler;
521+
self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
522+
self->mp_irq_trigger = trigger;
523+
pyb_uart_irq_config(self, true);
524+
}
525+
526+
return MP_OBJ_FROM_PTR(self->mp_irq_obj);
527+
}
528+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq);
529+
417530
STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {
418531
// instance methods
419532

@@ -429,6 +542,7 @@ STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {
429542
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
430543
/// \method write(buf)
431544
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
545+
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_uart_irq_obj) },
432546

433547
{ MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&pyb_uart_writechar_obj) },
434548
{ MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&pyb_uart_readchar_obj) },
@@ -437,6 +551,9 @@ STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {
437551
// class constants
438552
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) },
439553
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) },
554+
555+
// IRQ flags
556+
{ MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_FLAG_IDLE) },
440557
};
441558

442559
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);

ports/stm32/uart.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "py/mperrno.h"
3434
#include "py/mphal.h"
3535
#include "lib/utils/interrupt_char.h"
36+
#include "lib/utils/mpirq.h"
3637
#include "uart.h"
3738
#include "irq.h"
3839
#include "pendsv.h"
@@ -327,6 +328,9 @@ bool uart_init(pyb_uart_obj_t *uart_obj,
327328
uart_obj->char_width = CHAR_WIDTH_8BIT;
328329
}
329330

331+
uart_obj->mp_irq_trigger = 0;
332+
uart_obj->mp_irq_obj = NULL;
333+
330334
return true;
331335
}
332336

@@ -697,4 +701,24 @@ void uart_irq_handler(mp_uint_t uart_id) {
697701
}
698702
}
699703
}
704+
705+
// Set user IRQ flags
706+
self->mp_irq_flags = 0;
707+
#if defined(STM32F4)
708+
if (self->uartx->SR & USART_SR_IDLE) {
709+
(void)self->uartx->SR;
710+
(void)self->uartx->DR;
711+
self->mp_irq_flags |= UART_FLAG_IDLE;
712+
}
713+
#else
714+
if (self->uartx->ISR & USART_ISR_IDLE) {
715+
self->uartx->ICR = USART_ICR_IDLECF;
716+
self->mp_irq_flags |= UART_FLAG_IDLE;
717+
}
718+
#endif
719+
720+
// Check the flags to see if the user handler should be called
721+
if (self->mp_irq_trigger & self->mp_irq_flags) {
722+
mp_irq_handler(self->mp_irq_obj);
723+
}
700724
}

ports/stm32/uart.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#ifndef MICROPY_INCLUDED_STM32_UART_H
2727
#define MICROPY_INCLUDED_STM32_UART_H
2828

29+
struct _mp_irq_obj_t;
30+
2931
typedef enum {
3032
PYB_UART_NONE = 0,
3133
PYB_UART_1 = 1,
@@ -57,6 +59,9 @@ typedef struct _pyb_uart_obj_t {
5759
volatile uint16_t read_buf_head; // indexes first empty slot
5860
uint16_t read_buf_tail; // indexes first full slot (not full if equals head)
5961
byte *read_buf; // byte or uint16_t, depending on char size
62+
uint16_t mp_irq_trigger; // user IRQ trigger mask
63+
uint16_t mp_irq_flags; // user IRQ active IRQ flags
64+
struct _mp_irq_obj_t *mp_irq_obj; // user IRQ object
6065
} pyb_uart_obj_t;
6166

6267
extern const mp_obj_type_t pyb_uart_type;

0 commit comments

Comments
 (0)