nrf/modules/machine/uart: Implement Python UART IRQ for nrf52840 boards.
Supported triggers: UART.IRQ_RX and UART.IRQ_TXIDLE. It will probably work on other boards as well, but so far untested. The irq.flags() value is changed only when requested by a triggered event. Do not change it otherwise. Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
parent
4da5de94bb
commit
bae809070e
@ -191,6 +191,7 @@ endif
|
|||||||
SRC_SHARED_C += $(addprefix shared/,\
|
SRC_SHARED_C += $(addprefix shared/,\
|
||||||
libc/string0.c \
|
libc/string0.c \
|
||||||
readline/readline.c \
|
readline/readline.c \
|
||||||
|
runtime/mpirq.c \
|
||||||
runtime/pyexec.c \
|
runtime/pyexec.c \
|
||||||
runtime/stdout_helpers.c \
|
runtime/stdout_helpers.c \
|
||||||
runtime/sys_stdio_mphal.c \
|
runtime/sys_stdio_mphal.c \
|
||||||
|
|||||||
@ -70,6 +70,7 @@ typedef struct _machine_uart_buf_t {
|
|||||||
#define NRF_UART_HWFC_DISABLED NRF_UARTE_HWFC_DISABLED
|
#define NRF_UART_HWFC_DISABLED NRF_UARTE_HWFC_DISABLED
|
||||||
#define NRF_UART_PARITY_EXCLUDED NRF_UARTE_PARITY_EXCLUDED
|
#define NRF_UART_PARITY_EXCLUDED NRF_UARTE_PARITY_EXCLUDED
|
||||||
#define NRFX_UART_EVT_RX_DONE NRFX_UARTE_EVT_RX_DONE
|
#define NRFX_UART_EVT_RX_DONE NRFX_UARTE_EVT_RX_DONE
|
||||||
|
#define NRFX_UART_EVT_TX_DONE NRFX_UARTE_EVT_TX_DONE
|
||||||
#define NRFX_UART_EVT_ERROR NRFX_UARTE_EVT_ERROR
|
#define NRFX_UART_EVT_ERROR NRFX_UARTE_EVT_ERROR
|
||||||
|
|
||||||
#define NRF_UART_BAUDRATE_1200 NRF_UARTE_BAUDRATE_1200
|
#define NRF_UART_BAUDRATE_1200 NRF_UARTE_BAUDRATE_1200
|
||||||
@ -89,18 +90,31 @@ typedef struct _machine_uart_buf_t {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
#define NRFX_UART_IRQ_RX (1 << NRFX_UART_EVT_RX_DONE)
|
||||||
|
#define NRFX_UART_IRQ_TXIDLE (1 << NRFX_UART_EVT_TX_DONE)
|
||||||
|
#define MP_UART_ALLOWED_FLAGS (NRFX_UART_IRQ_RX | NRFX_UART_IRQ_TXIDLE)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct _machine_uart_obj_t {
|
typedef struct _machine_uart_obj_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
const nrfx_uart_t *p_uart; // Driver instance
|
const nrfx_uart_t *p_uart; // Driver instance
|
||||||
machine_uart_buf_t buf;
|
machine_uart_buf_t buf;
|
||||||
uint16_t timeout; // timeout waiting for first char (in ms)
|
uint16_t timeout; // timeout waiting for first char (in ms)
|
||||||
uint16_t timeout_char; // timeout waiting between chars (in ms)
|
uint16_t timeout_char; // timeout waiting between chars (in ms)
|
||||||
|
uint8_t uart_id;
|
||||||
|
bool initialized; // static flag. Initialized to False
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
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
|
||||||
|
#endif
|
||||||
} machine_uart_obj_t;
|
} machine_uart_obj_t;
|
||||||
|
|
||||||
static const nrfx_uart_t instance0 = NRFX_UART_INSTANCE(0);
|
static const nrfx_uart_t instance0 = NRFX_UART_INSTANCE(0);
|
||||||
|
|
||||||
static machine_uart_obj_t machine_uart_obj[] = {
|
static machine_uart_obj_t machine_uart_obj[] = {
|
||||||
{{&machine_uart_type}, .p_uart = &instance0}
|
{{&machine_uart_type}, .p_uart = &instance0, .uart_id = 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
void uart_init0(void) {
|
void uart_init0(void) {
|
||||||
@ -117,6 +131,9 @@ static int uart_find(mp_obj_t id) {
|
|||||||
|
|
||||||
static void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context) {
|
static void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context) {
|
||||||
machine_uart_obj_t *self = p_context;
|
machine_uart_obj_t *self = p_context;
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
uint16_t mp_irq_flags = 0;
|
||||||
|
#endif
|
||||||
if (p_event->type == NRFX_UART_EVT_RX_DONE) {
|
if (p_event->type == NRFX_UART_EVT_RX_DONE) {
|
||||||
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
|
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
|
||||||
int chr = self->buf.rx_buf[0];
|
int chr = self->buf.rx_buf[0];
|
||||||
@ -130,10 +147,24 @@ static void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context
|
|||||||
{
|
{
|
||||||
ringbuf_put((ringbuf_t *)&self->buf.rx_ringbuf, chr);
|
ringbuf_put((ringbuf_t *)&self->buf.rx_ringbuf, chr);
|
||||||
}
|
}
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
mp_irq_flags |= NRFX_UART_IRQ_RX;
|
||||||
|
#endif
|
||||||
} else if (p_event->type == NRFX_UART_EVT_ERROR) {
|
} else if (p_event->type == NRFX_UART_EVT_ERROR) {
|
||||||
// Perform a read to unlock UART in case of an error
|
// Perform a read to unlock UART in case of an error
|
||||||
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
|
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
|
||||||
|
} else if (p_event->type == NRFX_UART_EVT_TX_DONE) {
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
mp_irq_flags |= NRFX_UART_IRQ_TXIDLE;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
// Check the flags to see if the user handler should be called
|
||||||
|
if (self->mp_irq_trigger & mp_irq_flags) {
|
||||||
|
self->mp_irq_flags = mp_irq_flags;
|
||||||
|
mp_irq_handler(self->mp_irq_obj);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uart_rx_any(machine_uart_obj_t *self) {
|
bool uart_rx_any(machine_uart_obj_t *self) {
|
||||||
@ -171,8 +202,14 @@ void uart_tx_strn_cooked(machine_uart_obj_t *uart_obj, const char *str, uint len
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* MicroPython bindings */
|
/* MicroPython bindings */
|
||||||
|
|
||||||
// The UART class doesn't have any constants for this port.
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS \
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(NRFX_UART_IRQ_RX) }, \
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_IRQ_TXIDLE), MP_ROM_INT(NRFX_UART_IRQ_TXIDLE) }, \
|
||||||
|
|
||||||
|
#else
|
||||||
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS
|
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS
|
||||||
|
#endif
|
||||||
|
|
||||||
static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
mp_printf(print, "UART(0)");
|
mp_printf(print, "UART(0)");
|
||||||
@ -255,6 +292,12 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||||||
self->buf.rx_ringbuf.iget = 0;
|
self->buf.rx_ringbuf.iget = 0;
|
||||||
self->buf.rx_ringbuf.iput = 0;
|
self->buf.rx_ringbuf.iput = 0;
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
self->mp_irq_trigger = 0;
|
||||||
|
self->mp_irq_obj = NULL;
|
||||||
|
MP_STATE_PORT(nrf_uart_irq_obj)[self->uart_id] = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable event callback and start asynchronous receive
|
// Enable event callback and start asynchronous receive
|
||||||
if (self->initialized) {
|
if (self->initialized) {
|
||||||
nrfx_uart_uninit(self->p_uart);
|
nrfx_uart_uninit(self->p_uart);
|
||||||
@ -301,6 +344,60 @@ static bool mp_machine_uart_txdone(machine_uart_obj_t *self) {
|
|||||||
return !nrfx_uart_tx_in_progress(self->p_uart);
|
return !nrfx_uart_tx_in_progress(self->p_uart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||||
|
|
||||||
|
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);
|
||||||
|
self->mp_irq_trigger = new_trigger;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_uint_t uart_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
|
||||||
|
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
if (info_type == MP_IRQ_INFO_FLAGS) {
|
||||||
|
return self->mp_irq_flags;
|
||||||
|
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {
|
||||||
|
return self->mp_irq_trigger;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const mp_irq_methods_t uart_irq_methods = {
|
||||||
|
.trigger = uart_irq_trigger,
|
||||||
|
.info = uart_irq_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
self->mp_irq_obj = mp_irq_new(&uart_irq_methods, MP_OBJ_FROM_PTR(self));
|
||||||
|
MP_STATE_PORT(nrf_uart_irq_obj)[self->uart_id] = self->mp_irq_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any_args) {
|
||||||
|
// Check the handler
|
||||||
|
mp_obj_t handler = args[MP_IRQ_ARG_INIT_handler].u_obj;
|
||||||
|
if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("handler must be None or callable"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the trigger
|
||||||
|
mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
|
||||||
|
mp_uint_t not_supported = trigger & ~MP_UART_ALLOWED_FLAGS;
|
||||||
|
if (trigger != 0 && not_supported) {
|
||||||
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("trigger 0x%04x unsupported"), not_supported);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->mp_irq_obj->handler = handler;
|
||||||
|
self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
|
||||||
|
self->mp_irq_trigger = trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self->mp_irq_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
||||||
machine_uart_obj_t *self = self_in;
|
machine_uart_obj_t *self = self_in;
|
||||||
byte *buf = buf_in;
|
byte *buf = buf_in;
|
||||||
@ -383,3 +480,5 @@ static mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uint
|
|||||||
}
|
}
|
||||||
return MP_STREAM_ERROR;
|
return MP_STREAM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MP_REGISTER_ROOT_POINTER(void *nrf_uart_irq_obj[1]);
|
||||||
|
|||||||
@ -230,6 +230,10 @@
|
|||||||
#define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/nrf/modules/machine/uart.c"
|
#define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/nrf/modules/machine/uart.c"
|
||||||
#define MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR (1)
|
#define MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR (1)
|
||||||
|
|
||||||
|
#if defined(NRF52840)
|
||||||
|
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MICROPY_PY_MACHINE_TIMER_NRF
|
#ifndef MICROPY_PY_MACHINE_TIMER_NRF
|
||||||
#define MICROPY_PY_MACHINE_TIMER_NRF (1)
|
#define MICROPY_PY_MACHINE_TIMER_NRF (1)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user