stm32/uart: Allow static IRQ handler registration.
This will allow the HCI UART to use a non-heap mp_irq_obj_t, which avoids needing to make a root pointer for it.
This commit is contained in:
parent
3ff7079277
commit
23109988c2
|
@ -26,7 +26,7 @@
|
||||||
#ifndef MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
|
#ifndef MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
|
||||||
#define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
|
#define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
|
||||||
|
|
||||||
#include "py/obj.h"
|
#include "py/runtime.h"
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
DEFINE CONSTANTS
|
DEFINE CONSTANTS
|
||||||
|
|
|
@ -73,76 +73,6 @@
|
||||||
///
|
///
|
||||||
/// uart.any() # returns True if any characters waiting
|
/// uart.any() # returns True if any characters waiting
|
||||||
|
|
||||||
typedef struct _pyb_uart_irq_map_t {
|
|
||||||
uint16_t irq_en;
|
|
||||||
uint16_t flag;
|
|
||||||
} pyb_uart_irq_map_t;
|
|
||||||
|
|
||||||
STATIC const pyb_uart_irq_map_t mp_irq_map[] = {
|
|
||||||
{ USART_CR1_IDLEIE, UART_FLAG_IDLE}, // RX idle
|
|
||||||
{ USART_CR1_PEIE, UART_FLAG_PE}, // parity error
|
|
||||||
{ USART_CR1_TXEIE, UART_FLAG_TXE}, // TX register empty
|
|
||||||
{ USART_CR1_TCIE, UART_FLAG_TC}, // TX complete
|
|
||||||
{ USART_CR1_RXNEIE, UART_FLAG_RXNE}, // RX register not empty
|
|
||||||
#if 0
|
|
||||||
// For now only IRQs selected by CR1 are supported
|
|
||||||
#if defined(STM32F4)
|
|
||||||
{ USART_CR2_LBDIE, UART_FLAG_LBD}, // LIN break detection
|
|
||||||
#else
|
|
||||||
{ USART_CR2_LBDIE, UART_FLAG_LBDF}, // LIN break detection
|
|
||||||
#endif
|
|
||||||
{ USART_CR3_CTSIE, UART_FLAG_CTS}, // CTS
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// OR-ed IRQ flags which should not be touched by the user
|
|
||||||
STATIC const uint32_t mp_irq_reserved = UART_FLAG_RXNE;
|
|
||||||
|
|
||||||
// OR-ed IRQ flags which are allowed to be used by the user
|
|
||||||
STATIC const uint32_t mp_irq_allowed = UART_FLAG_IDLE;
|
|
||||||
|
|
||||||
STATIC mp_obj_t pyb_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
|
||||||
|
|
||||||
STATIC void pyb_uart_irq_config(pyb_uart_obj_t *self, bool enable) {
|
|
||||||
if (self->mp_irq_trigger) {
|
|
||||||
for (size_t entry = 0; entry < MP_ARRAY_SIZE(mp_irq_map); ++entry) {
|
|
||||||
if (mp_irq_map[entry].flag & mp_irq_reserved) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (mp_irq_map[entry].flag & self->mp_irq_trigger) {
|
|
||||||
if (enable) {
|
|
||||||
self->uartx->CR1 |= mp_irq_map[entry].irq_en;
|
|
||||||
} else {
|
|
||||||
self->uartx->CR1 &= ~mp_irq_map[entry].irq_en;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC mp_uint_t pyb_uart_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
|
|
||||||
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
|
||||||
pyb_uart_irq_config(self, false);
|
|
||||||
self->mp_irq_trigger = new_trigger;
|
|
||||||
pyb_uart_irq_config(self, true);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC mp_uint_t pyb_uart_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
|
|
||||||
pyb_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 pyb_uart_irq_methods = {
|
|
||||||
.trigger = pyb_uart_irq_trigger,
|
|
||||||
.info = pyb_uart_irq_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (!self->is_enabled) {
|
if (!self->is_enabled) {
|
||||||
|
@ -518,7 +448,7 @@ STATIC mp_obj_t pyb_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
|
||||||
|
|
||||||
if (self->mp_irq_obj == NULL) {
|
if (self->mp_irq_obj == NULL) {
|
||||||
self->mp_irq_trigger = 0;
|
self->mp_irq_trigger = 0;
|
||||||
self->mp_irq_obj = mp_irq_new(&pyb_uart_irq_methods, MP_OBJ_FROM_PTR(self));
|
self->mp_irq_obj = mp_irq_new(&uart_irq_methods, MP_OBJ_FROM_PTR(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_args > 1 || kw_args->used != 0) {
|
if (n_args > 1 || kw_args->used != 0) {
|
||||||
|
@ -530,17 +460,17 @@ STATIC mp_obj_t pyb_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
|
||||||
|
|
||||||
// Check the trigger
|
// Check the trigger
|
||||||
mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
|
mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
|
||||||
mp_uint_t not_supported = trigger & ~mp_irq_allowed;
|
mp_uint_t not_supported = trigger & ~MP_UART_ALLOWED_FLAGS;
|
||||||
if (trigger != 0 && not_supported) {
|
if (trigger != 0 && not_supported) {
|
||||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("trigger 0x%08x unsupported"), not_supported);
|
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("trigger 0x%08x unsupported"), not_supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconfigure user IRQs
|
// Reconfigure user IRQs
|
||||||
pyb_uart_irq_config(self, false);
|
uart_irq_config(self, false);
|
||||||
self->mp_irq_obj->handler = handler;
|
self->mp_irq_obj->handler = handler;
|
||||||
self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
|
self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
|
||||||
self->mp_irq_trigger = trigger;
|
self->mp_irq_trigger = trigger;
|
||||||
pyb_uart_irq_config(self, true);
|
uart_irq_config(self, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MP_OBJ_FROM_PTR(self->mp_irq_obj);
|
return MP_OBJ_FROM_PTR(self->mp_irq_obj);
|
||||||
|
|
|
@ -93,6 +93,28 @@
|
||||||
|
|
||||||
extern void NORETURN __fatal_error(const char *msg);
|
extern void NORETURN __fatal_error(const char *msg);
|
||||||
|
|
||||||
|
typedef struct _pyb_uart_irq_map_t {
|
||||||
|
uint16_t irq_en;
|
||||||
|
uint16_t flag;
|
||||||
|
} pyb_uart_irq_map_t;
|
||||||
|
|
||||||
|
STATIC const pyb_uart_irq_map_t mp_uart_irq_map[] = {
|
||||||
|
{ USART_CR1_IDLEIE, UART_FLAG_IDLE}, // RX idle
|
||||||
|
{ USART_CR1_PEIE, UART_FLAG_PE}, // parity error
|
||||||
|
{ USART_CR1_TXEIE, UART_FLAG_TXE}, // TX register empty
|
||||||
|
{ USART_CR1_TCIE, UART_FLAG_TC}, // TX complete
|
||||||
|
{ USART_CR1_RXNEIE, UART_FLAG_RXNE}, // RX register not empty
|
||||||
|
#if 0
|
||||||
|
// For now only IRQs selected by CR1 are supported
|
||||||
|
#if defined(STM32F4)
|
||||||
|
{ USART_CR2_LBDIE, UART_FLAG_LBD}, // LIN break detection
|
||||||
|
#else
|
||||||
|
{ USART_CR2_LBDIE, UART_FLAG_LBDF}, // LIN break detection
|
||||||
|
#endif
|
||||||
|
{ USART_CR3_CTSIE, UART_FLAG_CTS}, // CTS
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
void uart_init0(void) {
|
void uart_init0(void) {
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7)
|
||||||
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit = {0};
|
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit = {0};
|
||||||
|
@ -444,6 +466,23 @@ bool uart_init(pyb_uart_obj_t *uart_obj,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uart_irq_config(pyb_uart_obj_t *self, bool enable) {
|
||||||
|
if (self->mp_irq_trigger) {
|
||||||
|
for (size_t entry = 0; entry < MP_ARRAY_SIZE(mp_uart_irq_map); ++entry) {
|
||||||
|
if (mp_uart_irq_map[entry].flag & MP_UART_RESERVED_FLAGS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mp_uart_irq_map[entry].flag & self->mp_irq_trigger) {
|
||||||
|
if (enable) {
|
||||||
|
self->uartx->CR1 |= mp_uart_irq_map[entry].irq_en;
|
||||||
|
} else {
|
||||||
|
self->uartx->CR1 &= ~mp_uart_irq_map[entry].irq_en;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void uart_set_rxbuf(pyb_uart_obj_t *self, size_t len, void *buf) {
|
void uart_set_rxbuf(pyb_uart_obj_t *self, size_t len, void *buf) {
|
||||||
self->read_buf_head = 0;
|
self->read_buf_head = 0;
|
||||||
self->read_buf_tail = 0;
|
self->read_buf_tail = 0;
|
||||||
|
@ -864,3 +903,26 @@ void uart_irq_handler(mp_uint_t uart_id) {
|
||||||
mp_irq_handler(self->mp_irq_obj);
|
mp_irq_handler(self->mp_irq_obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t uart_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
|
||||||
|
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uart_irq_config(self, false);
|
||||||
|
self->mp_irq_trigger = new_trigger;
|
||||||
|
uart_irq_config(self, true);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t uart_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
|
||||||
|
pyb_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mp_irq_methods_t uart_irq_methods = {
|
||||||
|
.trigger = uart_irq_trigger,
|
||||||
|
.info = uart_irq_info,
|
||||||
|
};
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#ifndef MICROPY_INCLUDED_STM32_UART_H
|
#ifndef MICROPY_INCLUDED_STM32_UART_H
|
||||||
#define MICROPY_INCLUDED_STM32_UART_H
|
#define MICROPY_INCLUDED_STM32_UART_H
|
||||||
|
|
||||||
struct _mp_irq_obj_t;
|
#include "lib/utils/mpirq.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PYB_UART_NONE = 0,
|
PYB_UART_NONE = 0,
|
||||||
|
@ -45,6 +45,12 @@ typedef enum {
|
||||||
#define CHAR_WIDTH_8BIT (0)
|
#define CHAR_WIDTH_8BIT (0)
|
||||||
#define CHAR_WIDTH_9BIT (1)
|
#define CHAR_WIDTH_9BIT (1)
|
||||||
|
|
||||||
|
// OR-ed IRQ flags which are allowed to be used by the user
|
||||||
|
#define MP_UART_ALLOWED_FLAGS UART_FLAG_IDLE
|
||||||
|
|
||||||
|
// OR-ed IRQ flags which should not be touched by the user
|
||||||
|
#define MP_UART_RESERVED_FLAGS UART_FLAG_RXNE
|
||||||
|
|
||||||
typedef struct _pyb_uart_obj_t {
|
typedef struct _pyb_uart_obj_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
USART_TypeDef *uartx;
|
USART_TypeDef *uartx;
|
||||||
|
@ -62,16 +68,18 @@ typedef struct _pyb_uart_obj_t {
|
||||||
byte *read_buf; // byte or uint16_t, depending on char size
|
byte *read_buf; // byte or uint16_t, depending on char size
|
||||||
uint16_t mp_irq_trigger; // user IRQ trigger mask
|
uint16_t mp_irq_trigger; // user IRQ trigger mask
|
||||||
uint16_t mp_irq_flags; // user IRQ active IRQ flags
|
uint16_t mp_irq_flags; // user IRQ active IRQ flags
|
||||||
struct _mp_irq_obj_t *mp_irq_obj; // user IRQ object
|
mp_irq_obj_t *mp_irq_obj; // user IRQ object
|
||||||
} pyb_uart_obj_t;
|
} pyb_uart_obj_t;
|
||||||
|
|
||||||
extern const mp_obj_type_t pyb_uart_type;
|
extern const mp_obj_type_t pyb_uart_type;
|
||||||
|
extern const mp_irq_methods_t uart_irq_methods;
|
||||||
|
|
||||||
void uart_init0(void);
|
void uart_init0(void);
|
||||||
void uart_deinit_all(void);
|
void uart_deinit_all(void);
|
||||||
bool uart_exists(int uart_id);
|
bool uart_exists(int uart_id);
|
||||||
bool uart_init(pyb_uart_obj_t *uart_obj,
|
bool uart_init(pyb_uart_obj_t *uart_obj,
|
||||||
uint32_t baudrate, uint32_t bits, uint32_t parity, uint32_t stop, uint32_t flow);
|
uint32_t baudrate, uint32_t bits, uint32_t parity, uint32_t stop, uint32_t flow);
|
||||||
|
void uart_irq_config(pyb_uart_obj_t *self, bool enable);
|
||||||
void uart_set_rxbuf(pyb_uart_obj_t *self, size_t len, void *buf);
|
void uart_set_rxbuf(pyb_uart_obj_t *self, size_t len, void *buf);
|
||||||
void uart_deinit(pyb_uart_obj_t *uart_obj);
|
void uart_deinit(pyb_uart_obj_t *uart_obj);
|
||||||
void uart_irq_handler(mp_uint_t uart_id);
|
void uart_irq_handler(mp_uint_t uart_id);
|
||||||
|
|
Loading…
Reference in New Issue