mirror of
https://github.com/micropython/micropython.git
synced 2025-12-13 08:20:13 +01:00
renesas-ra/machine_uart: Implement UART.IRQ_RXIDLE based on softtimer.
Allowing to define the trigger UART.IRQ_RXIDLE as well as UART.IRQ_RX. The delay for the IRQ_RXIDLE interrupt is about 3 character times or 1-2 ms, whichever is larger. The irq.flags() value is changed only with an expected event. Do not change it otherwise. Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
@@ -41,7 +41,8 @@
|
||||
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS \
|
||||
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(0x10) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(UART_IRQ_RX) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_IRQ_RXIDLE) }, \
|
||||
|
||||
static const char *_parity_name[] = {"None", "ODD", "EVEN"};
|
||||
|
||||
@@ -297,6 +298,8 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
|
||||
// reference existing UART object
|
||||
self = MP_STATE_PORT(machine_uart_obj_all)[uart_id];
|
||||
}
|
||||
self->mp_irq_obj = NULL;
|
||||
self->rxidle_state = RXIDLE_INACTIVE;
|
||||
|
||||
// start the peripheral
|
||||
mp_map_t kw_args;
|
||||
@@ -351,6 +354,29 @@ static mp_int_t mp_machine_uart_readchar(machine_uart_obj_t *self) {
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the timer used for IRQ_RXIDLE
|
||||
void uart_irq_configure_timer(machine_uart_obj_t *self, mp_uint_t trigger) {
|
||||
self->rxidle_state = RXIDLE_INACTIVE;
|
||||
|
||||
if (trigger & UART_IRQ_RXIDLE) {
|
||||
// The RXIDLE event is always a soft IRQ.
|
||||
self->mp_irq_obj->ishard = false;
|
||||
mp_int_t ms = 13000 / self->baudrate + 1;
|
||||
if (ms < RXIDLE_TIMER_MIN) {
|
||||
ms = RXIDLE_TIMER_MIN;
|
||||
}
|
||||
self->rxidle_ms = ms;
|
||||
self->rxidle_timer.context = self;
|
||||
soft_timer_static_init(
|
||||
&self->rxidle_timer.base,
|
||||
SOFT_TIMER_MODE_PERIODIC,
|
||||
ms,
|
||||
uart_soft_timer_callback
|
||||
);
|
||||
self->rxidle_state = RXIDLE_STANDBY;
|
||||
}
|
||||
}
|
||||
|
||||
static mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args, mp_arg_val_t *args) {
|
||||
if (self->mp_irq_obj == NULL) {
|
||||
self->mp_irq_trigger = 0;
|
||||
@@ -376,6 +402,7 @@ static mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args
|
||||
self->mp_irq_obj->handler = handler;
|
||||
self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
|
||||
self->mp_irq_trigger = trigger;
|
||||
uart_irq_configure_timer(self, trigger);
|
||||
uart_irq_config(self, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,12 +85,36 @@ static void uart_rx_cb(uint32_t ch, int d) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((self->mp_irq_trigger & UART_IRQ_RXIDLE) && (self->rxidle_state != RXIDLE_INACTIVE)) {
|
||||
if (self->rxidle_state == RXIDLE_STANDBY) {
|
||||
self->rxidle_timer.base.mode = SOFT_TIMER_MODE_PERIODIC;
|
||||
soft_timer_insert(&self->rxidle_timer.base, self->rxidle_ms);
|
||||
}
|
||||
self->rxidle_state = RXIDLE_ALERT;
|
||||
}
|
||||
// Check the flags to see if the user handler should be called
|
||||
if (self->mp_irq_trigger) {
|
||||
if (self->mp_irq_trigger & UART_IRQ_RX) {
|
||||
self->mp_irq_flags = UART_IRQ_RX;
|
||||
mp_irq_handler(self->mp_irq_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void uart_soft_timer_callback(soft_timer_entry_t *self) {
|
||||
machine_uart_obj_t *uart = ((soft_timer_entry_extended_t *)self)->context;
|
||||
if (uart->rxidle_state == RXIDLE_ALERT) {
|
||||
// At the first call, just switch the state
|
||||
uart->rxidle_state = RXIDLE_ARMED;
|
||||
} else if (uart->rxidle_state == RXIDLE_ARMED) {
|
||||
// At the second call, run the irq callback and stop the timer
|
||||
// by setting the mode to SOFT_TIMER_MODE_ONE_SHOT.
|
||||
// Calling soft_timer_remove() would fail here.
|
||||
self->mode = SOFT_TIMER_MODE_ONE_SHOT;
|
||||
uart->rxidle_state = RXIDLE_STANDBY;
|
||||
uart->mp_irq_flags = UART_IRQ_RXIDLE;
|
||||
mp_irq_handler(uart->mp_irq_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void uart_init0(void) {
|
||||
}
|
||||
|
||||
@@ -513,6 +537,7 @@ void uart_tx_strn(machine_uart_obj_t *uart_obj, const char *str, uint len) {
|
||||
static mp_uint_t uart_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uart_irq_config(self, false);
|
||||
uart_irq_configure_timer(self, new_trigger);
|
||||
self->mp_irq_trigger = new_trigger;
|
||||
uart_irq_config(self, true);
|
||||
return 0;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define MICROPY_INCLUDED_RA_UART_H
|
||||
|
||||
#include "shared/runtime/mpirq.h"
|
||||
#include "shared/runtime/softtimer.h"
|
||||
#include "pin.h"
|
||||
|
||||
typedef enum {
|
||||
@@ -57,12 +58,28 @@ typedef enum {
|
||||
#define UART_HWCONTROL_CTS (1)
|
||||
#define UART_HWCONTROL_RTS (2)
|
||||
|
||||
#define UART_IRQ_RX (0x10)
|
||||
#define UART_IRQ_RXIDLE (0x1000)
|
||||
#define RXIDLE_TIMER_MIN (1)
|
||||
|
||||
// OR-ed IRQ flags which are allowed to be used by the user
|
||||
#define MP_UART_ALLOWED_FLAGS ((uint32_t)0x00000010)
|
||||
#define MP_UART_ALLOWED_FLAGS ((uint32_t)(UART_IRQ_RX | UART_IRQ_RXIDLE))
|
||||
|
||||
// OR-ed IRQ flags which should not be touched by the user
|
||||
#define MP_UART_RESERVED_FLAGS ((uint16_t)0x0020)
|
||||
|
||||
enum {
|
||||
RXIDLE_INACTIVE,
|
||||
RXIDLE_STANDBY,
|
||||
RXIDLE_ARMED,
|
||||
RXIDLE_ALERT,
|
||||
};
|
||||
|
||||
typedef struct _soft_timer_entry_extended_t {
|
||||
soft_timer_entry_t base;
|
||||
void *context;
|
||||
} soft_timer_entry_extended_t;
|
||||
|
||||
typedef struct _machine_uart_obj_t {
|
||||
mp_obj_base_t base;
|
||||
machine_uart_t uart_id : 8;
|
||||
@@ -87,6 +104,9 @@ typedef struct _machine_uart_obj_t {
|
||||
uint16_t mp_irq_trigger; // user IRQ trigger mask
|
||||
uint16_t mp_irq_flags; // user IRQ active IRQ flags
|
||||
mp_irq_obj_t *mp_irq_obj; // user IRQ object
|
||||
soft_timer_entry_extended_t rxidle_timer;
|
||||
uint8_t rxidle_state;
|
||||
uint16_t rxidle_ms;
|
||||
} machine_uart_obj_t;
|
||||
|
||||
extern const mp_irq_methods_t uart_irq_methods;
|
||||
@@ -100,6 +120,8 @@ void uart_irq_config(machine_uart_obj_t *self, bool enable);
|
||||
void uart_set_rxbuf(machine_uart_obj_t *self, size_t len, void *buf);
|
||||
void uart_deinit(machine_uart_obj_t *uart_obj);
|
||||
// void uart_irq_handler(mp_uint_t uart_id);
|
||||
void uart_irq_configure_timer(machine_uart_obj_t *self, mp_uint_t trigger);
|
||||
void uart_soft_timer_callback(soft_timer_entry_t *self);
|
||||
|
||||
void uart_attach_to_repl(machine_uart_obj_t *self, bool attached);
|
||||
uint32_t uart_get_baudrate(machine_uart_obj_t *self);
|
||||
|
||||
Reference in New Issue
Block a user