stmhal: Collect all root pointers together in 1 place.
A GC in stmhal port now only scans true root pointers, not entire BSS. This reduces base GC time from 1700ms to 900ms.
This commit is contained in:
parent
7a0636e80a
commit
3b51b3e90f
|
@ -61,6 +61,11 @@ extern const struct _mp_obj_module_t pyb_module;
|
|||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8];
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stm32f4xx_hal.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
|
@ -101,13 +99,7 @@ typedef struct {
|
|||
mp_int_t line;
|
||||
} extint_obj_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_t callback_obj;
|
||||
void *param;
|
||||
uint32_t mode;
|
||||
} extint_vector_t;
|
||||
|
||||
STATIC extint_vector_t extint_vector[EXTI_NUM_VECTORS];
|
||||
STATIC uint32_t pyb_extint_mode[EXTI_NUM_VECTORS];
|
||||
|
||||
#if !defined(ETH)
|
||||
#define ETH_WKUP_IRQn 62 // The 405 doesn't have ETH, but we want a value to put in our table
|
||||
|
@ -123,10 +115,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
|
|||
|
||||
// Set override_callback_obj to true if you want to unconditionally set the
|
||||
// callback function.
|
||||
//
|
||||
// NOTE: param is for C callers. Python can use closure to get an object bound
|
||||
// with the function.
|
||||
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj, void *param) {
|
||||
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj) {
|
||||
const pin_obj_t *pin = NULL;
|
||||
uint v_line;
|
||||
|
||||
|
@ -159,22 +148,21 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca
|
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid ExtInt Pull: %d", pull));
|
||||
}
|
||||
|
||||
extint_vector_t *v = &extint_vector[v_line];
|
||||
if (!override_callback_obj && v->callback_obj != mp_const_none && callback_obj != mp_const_none) {
|
||||
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[v_line];
|
||||
if (!override_callback_obj && *cb != mp_const_none && callback_obj != mp_const_none) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d is already in use", v_line));
|
||||
}
|
||||
|
||||
// We need to update callback and param atomically, so we disable the line
|
||||
// We need to update callback atomically, so we disable the line
|
||||
// before we update anything.
|
||||
|
||||
extint_disable(v_line);
|
||||
|
||||
v->callback_obj = callback_obj;
|
||||
v->param = param;
|
||||
v->mode = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
|
||||
*cb = callback_obj;
|
||||
pyb_extint_mode[v_line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
|
||||
EXTI_Mode_Interrupt : EXTI_Mode_Event;
|
||||
|
||||
if (v->callback_obj != mp_const_none) {
|
||||
if (*cb != mp_const_none) {
|
||||
|
||||
GPIO_InitTypeDef exti;
|
||||
exti.Pin = pin->pin_mask;
|
||||
|
@ -199,7 +187,7 @@ void extint_enable(uint line) {
|
|||
// Since manipulating IMR/EMR is a read-modify-write, and we want this to
|
||||
// be atomic, we use the bit-band area to just affect the bit we're
|
||||
// interested in.
|
||||
EXTI_MODE_BB(extint_vector[line].mode, line) = 1;
|
||||
EXTI_MODE_BB(pyb_extint_mode[line], line) = 1;
|
||||
}
|
||||
|
||||
void extint_disable(uint line) {
|
||||
|
@ -303,7 +291,7 @@ STATIC mp_obj_t extint_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_
|
|||
|
||||
extint_obj_t *self = m_new_obj(extint_obj_t);
|
||||
self->base.type = type_in;
|
||||
self->line = extint_register(vals[0].u_obj, vals[1].u_int, vals[2].u_int, vals[3].u_obj, false, NULL);
|
||||
self->line = extint_register(vals[0].u_obj, vals[1].u_int, vals[2].u_int, vals[3].u_obj, false);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -343,11 +331,10 @@ const mp_obj_type_t extint_type = {
|
|||
};
|
||||
|
||||
void extint_init0(void) {
|
||||
for (extint_vector_t *v = extint_vector; v < &extint_vector[EXTI_NUM_VECTORS]; v++) {
|
||||
v->callback_obj = mp_const_none;
|
||||
v->param = NULL;
|
||||
v->mode = EXTI_Mode_Interrupt;
|
||||
}
|
||||
for (int i = 0; i < PYB_EXTI_NUM_VECTORS; i++) {
|
||||
MP_STATE_PORT(pyb_extint_callback)[i] = mp_const_none;
|
||||
pyb_extint_mode[i] = EXTI_Mode_Interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
// Interrupt handler
|
||||
|
@ -355,18 +342,18 @@ void Handle_EXTI_Irq(uint32_t line) {
|
|||
if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) {
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
|
||||
if (line < EXTI_NUM_VECTORS) {
|
||||
extint_vector_t *v = &extint_vector[line];
|
||||
if (v->callback_obj != mp_const_none) {
|
||||
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
|
||||
if (*cb != mp_const_none) {
|
||||
// When executing code within a handler we must lock the GC to prevent
|
||||
// any memory allocations. We must also catch any exceptions.
|
||||
gc_lock();
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_call_function_1(v->callback_obj, MP_OBJ_NEW_SMALL_INT(line));
|
||||
mp_call_function_1(*cb, MP_OBJ_NEW_SMALL_INT(line));
|
||||
nlr_pop();
|
||||
} else {
|
||||
// Uncaught exception; disable the callback so it doesn't run again.
|
||||
v->callback_obj = mp_const_none;
|
||||
*cb = mp_const_none;
|
||||
extint_disable(line);
|
||||
printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line);
|
||||
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#define EXTI_RTC_TIMESTAMP (21)
|
||||
#define EXTI_RTC_WAKEUP (22)
|
||||
|
||||
#define EXTI_NUM_VECTORS (23)
|
||||
#define EXTI_NUM_VECTORS (PYB_EXTI_NUM_VECTORS)
|
||||
|
||||
#define EXTI_MODE_INTERRUPT (offsetof(EXTI_TypeDef, IMR))
|
||||
#define EXTI_MODE_EVENT (offsetof(EXTI_TypeDef, EMR))
|
||||
|
@ -48,7 +48,7 @@
|
|||
|
||||
void extint_init0(void);
|
||||
|
||||
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj, void *param);
|
||||
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj);
|
||||
|
||||
void extint_enable(uint line);
|
||||
void extint_disable(uint line);
|
||||
|
|
|
@ -30,24 +30,19 @@
|
|||
#include "py/obj.h"
|
||||
#include "py/gc.h"
|
||||
#include "gccollect.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "systick.h"
|
||||
|
||||
mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs);
|
||||
|
||||
// obsolete
|
||||
// void gc_helper_get_regs_and_clean_stack(mp_uint_t *regs, mp_uint_t heap_end);
|
||||
|
||||
void gc_collect(void) {
|
||||
// get current time, in case we want to time the GC
|
||||
uint32_t start = HAL_GetTick();
|
||||
#if 0
|
||||
uint32_t start = sys_tick_get_microseconds();
|
||||
#endif
|
||||
|
||||
// start the GC
|
||||
gc_collect_start();
|
||||
|
||||
// We need to scan everything in RAM that can hold a pointer.
|
||||
// The data segment is used, but should not contain pointers, so we just scan the bss.
|
||||
gc_collect_root((void**)&_sbss, ((uint32_t)&_ebss - (uint32_t)&_sbss) / sizeof(uint32_t));
|
||||
|
||||
// get the registers and the sp
|
||||
mp_uint_t regs[10];
|
||||
mp_uint_t sp = gc_helper_get_regs_and_sp(regs);
|
||||
|
@ -58,14 +53,14 @@ void gc_collect(void) {
|
|||
// end the GC
|
||||
gc_collect_end();
|
||||
|
||||
if (0) {
|
||||
// print GC info
|
||||
uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
printf("GC@%lu %lums\n", start, ticks);
|
||||
printf(" " UINT_FMT " total\n", info.total);
|
||||
printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
|
||||
printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
|
||||
}
|
||||
#if 0
|
||||
// print GC info
|
||||
uint32_t ticks = sys_tick_get_microseconds() - start;
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
printf("GC@%lu %lums\n", start, ticks);
|
||||
printf(" " UINT_FMT " total\n", info.total);
|
||||
printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
|
||||
printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -112,12 +112,9 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
|
|||
}
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
|
||||
STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL;
|
||||
|
||||
STATIC mp_obj_t pyb_main(mp_obj_t main) {
|
||||
if (MP_OBJ_IS_STR(main)) {
|
||||
pyb_config_main = main;
|
||||
MP_STATE_PORT(pyb_config_main) = main;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -125,7 +122,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main);
|
|||
|
||||
STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) {
|
||||
if (MP_OBJ_IS_STR(usb_mode)) {
|
||||
pyb_config_usb_mode = usb_mode;
|
||||
MP_STATE_PORT(pyb_config_usb_mode) = usb_mode;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -303,7 +300,7 @@ soft_reset:
|
|||
pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
|
||||
}
|
||||
#else
|
||||
pyb_stdio_uart = NULL;
|
||||
MP_STATE_PORT(pyb_stdio_uart) = NULL;
|
||||
#endif
|
||||
|
||||
// Initialise low-level sub-systems. Here we need to very basic things like
|
||||
|
@ -444,8 +441,8 @@ soft_reset:
|
|||
#endif
|
||||
|
||||
// reset config variables; they should be set by boot.py
|
||||
pyb_config_main = MP_OBJ_NULL;
|
||||
pyb_config_usb_mode = MP_OBJ_NULL;
|
||||
MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
|
||||
MP_STATE_PORT(pyb_config_usb_mode) = MP_OBJ_NULL;
|
||||
|
||||
// run boot.py, if it exists
|
||||
// TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py
|
||||
|
@ -479,8 +476,8 @@ soft_reset:
|
|||
// USB device
|
||||
usb_device_mode_t usb_mode = USB_DEVICE_MODE_CDC_MSC;
|
||||
// if we are not in reset_mode==1, this config variable will always be NULL
|
||||
if (pyb_config_usb_mode != MP_OBJ_NULL) {
|
||||
if (strcmp(mp_obj_str_get_str(pyb_config_usb_mode), "CDC+HID") == 0) {
|
||||
if (MP_STATE_PORT(pyb_config_usb_mode) != MP_OBJ_NULL) {
|
||||
if (strcmp(mp_obj_str_get_str(MP_STATE_PORT(pyb_config_usb_mode)), "CDC+HID") == 0) {
|
||||
usb_mode = USB_DEVICE_MODE_CDC_HID;
|
||||
}
|
||||
}
|
||||
|
@ -509,10 +506,10 @@ soft_reset:
|
|||
// Run the main script from the current directory.
|
||||
if (reset_mode == 1 && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
|
||||
const char *main_py;
|
||||
if (pyb_config_main == MP_OBJ_NULL) {
|
||||
if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) {
|
||||
main_py = "main.py";
|
||||
} else {
|
||||
main_py = mp_obj_str_get_str(pyb_config_main);
|
||||
main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main));
|
||||
}
|
||||
FRESULT res = f_stat(main_py, NULL);
|
||||
if (res == FR_OK) {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/gc.h"
|
||||
|
@ -475,16 +476,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
|
|||
/// Get or set the UART object that the REPL is repeated on.
|
||||
STATIC mp_obj_t pyb_repl_uart(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
if (pyb_stdio_uart == NULL) {
|
||||
if (MP_STATE_PORT(pyb_stdio_uart) == NULL) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return pyb_stdio_uart;
|
||||
return MP_STATE_PORT(pyb_stdio_uart);
|
||||
}
|
||||
} else {
|
||||
if (args[0] == mp_const_none) {
|
||||
pyb_stdio_uart = NULL;
|
||||
MP_STATE_PORT(pyb_stdio_uart) = NULL;
|
||||
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
|
||||
pyb_stdio_uart = args[0];
|
||||
MP_STATE_PORT(pyb_stdio_uart) = args[0];
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a UART object"));
|
||||
}
|
||||
|
|
|
@ -122,6 +122,34 @@ extern const struct _mp_obj_module_t mp_module_network;
|
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \
|
||||
|
||||
#define PYB_EXTI_NUM_VECTORS (23)
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8]; \
|
||||
\
|
||||
mp_obj_t mp_const_vcp_interrupt; \
|
||||
\
|
||||
mp_obj_t pyb_config_main; \
|
||||
mp_obj_t pyb_config_usb_mode; \
|
||||
\
|
||||
mp_obj_t pyb_switch_callback; \
|
||||
\
|
||||
mp_obj_t pin_class_mapper; \
|
||||
mp_obj_t pin_class_map_dict; \
|
||||
\
|
||||
mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \
|
||||
\
|
||||
/* Used to do callbacks to Python code on interrupt */ \
|
||||
struct _pyb_timer_obj_t *pyb_timer_obj_all[14]; \
|
||||
\
|
||||
/* stdio is repeated on this UART object if it's not null */ \
|
||||
struct _pyb_uart_obj_t *pyb_stdio_uart; \
|
||||
\
|
||||
/* pointers to all UART objects (if they have been created) */ \
|
||||
struct _pyb_uart_obj_t *pyb_uart_obj_all[6]; \
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define BYTES_PER_WORD (4)
|
||||
|
|
|
@ -31,7 +31,10 @@
|
|||
#include "py/runtime.h"
|
||||
#include "pendsv.h"
|
||||
|
||||
static void *pendsv_object = NULL;
|
||||
// Note: this can contain point to the heap but is not traced by GC.
|
||||
// This is okay because we only ever set it to mp_const_vcp_interrupt
|
||||
// which is in the root-pointer set.
|
||||
STATIC void *pendsv_object;
|
||||
|
||||
void pendsv_init(void) {
|
||||
// set PendSV interrupt at lowest priority
|
||||
|
|
22
stmhal/pin.c
22
stmhal/pin.c
|
@ -91,13 +91,11 @@
|
|||
/// how a particular object gets mapped to a pin.
|
||||
|
||||
// Pin class variables
|
||||
STATIC mp_obj_t pin_class_mapper;
|
||||
STATIC mp_obj_t pin_class_map_dict;
|
||||
STATIC bool pin_class_debug;
|
||||
|
||||
void pin_init0(void) {
|
||||
pin_class_mapper = mp_const_none;
|
||||
pin_class_map_dict = mp_const_none;
|
||||
MP_STATE_PORT(pin_class_mapper) = mp_const_none;
|
||||
MP_STATE_PORT(pin_class_map_dict) = mp_const_none;
|
||||
pin_class_debug = false;
|
||||
}
|
||||
|
||||
|
@ -116,8 +114,8 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) {
|
|||
return pin_obj;
|
||||
}
|
||||
|
||||
if (pin_class_mapper != mp_const_none) {
|
||||
pin_obj = mp_call_function_1(pin_class_mapper, user_obj);
|
||||
if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) {
|
||||
pin_obj = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj);
|
||||
if (pin_obj != mp_const_none) {
|
||||
if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin.mapper didn't return a Pin object"));
|
||||
|
@ -135,8 +133,8 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) {
|
|||
// other lookup methods.
|
||||
}
|
||||
|
||||
if (pin_class_map_dict != mp_const_none) {
|
||||
mp_map_t *pin_map_map = mp_obj_dict_get_map(pin_class_map_dict);
|
||||
if (MP_STATE_PORT(pin_class_map_dict) != mp_const_none) {
|
||||
mp_map_t *pin_map_map = mp_obj_dict_get_map(MP_STATE_PORT(pin_class_map_dict));
|
||||
mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP);
|
||||
if (elem != NULL && elem->value != NULL) {
|
||||
pin_obj = elem->value;
|
||||
|
@ -266,10 +264,10 @@ STATIC mp_obj_t pin_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
|
|||
/// Get or set the pin mapper function.
|
||||
STATIC mp_obj_t pin_mapper(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args > 1) {
|
||||
pin_class_mapper = args[1];
|
||||
MP_STATE_PORT(pin_class_mapper) = args[1];
|
||||
return mp_const_none;
|
||||
}
|
||||
return pin_class_mapper;
|
||||
return MP_STATE_PORT(pin_class_mapper);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mapper_fun_obj, 1, 2, pin_mapper);
|
||||
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, (mp_obj_t)&pin_mapper_fun_obj);
|
||||
|
@ -278,10 +276,10 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, (mp_obj_t)&pin_mapper_fun
|
|||
/// Get or set the pin mapper dictionary.
|
||||
STATIC mp_obj_t pin_map_dict(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args > 1) {
|
||||
pin_class_map_dict = args[1];
|
||||
MP_STATE_PORT(pin_class_map_dict) = args[1];
|
||||
return mp_const_none;
|
||||
}
|
||||
return pin_class_map_dict;
|
||||
return MP_STATE_PORT(pin_class_map_dict);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict);
|
||||
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/stream.h"
|
||||
#include "usb.h"
|
||||
|
@ -40,16 +41,13 @@
|
|||
// be changed by Python code. This requires some changes, as these
|
||||
// objects are in a read-only module (py/modsys.c).
|
||||
|
||||
// stdio is repeated on this UART object if it's not null
|
||||
pyb_uart_obj_t *pyb_stdio_uart = NULL;
|
||||
|
||||
void stdout_tx_str(const char *str) {
|
||||
stdout_tx_strn(str, strlen(str));
|
||||
}
|
||||
|
||||
void stdout_tx_strn(const char *str, mp_uint_t len) {
|
||||
if (pyb_stdio_uart != PYB_UART_NONE) {
|
||||
uart_tx_strn(pyb_stdio_uart, str, len);
|
||||
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
|
||||
uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
|
||||
}
|
||||
#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
|
||||
lcd_print_strn(str, len);
|
||||
|
@ -61,8 +59,8 @@ void stdout_tx_strn(const char *str, mp_uint_t len) {
|
|||
|
||||
void stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
|
||||
// send stdout to UART and USB CDC VCP
|
||||
if (pyb_stdio_uart != PYB_UART_NONE) {
|
||||
uart_tx_strn_cooked(pyb_stdio_uart, str, len);
|
||||
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
|
||||
uart_tx_strn_cooked(MP_STATE_PORT(pyb_stdio_uart), str, len);
|
||||
}
|
||||
if (usb_vcp_is_enabled()) {
|
||||
usb_vcp_send_strn_cooked(str, len);
|
||||
|
@ -84,8 +82,8 @@ int stdin_rx_chr(void) {
|
|||
byte c;
|
||||
if (usb_vcp_recv_byte(&c) != 0) {
|
||||
return c;
|
||||
} else if (pyb_stdio_uart != PYB_UART_NONE && uart_rx_any(pyb_stdio_uart)) {
|
||||
return uart_rx_char(pyb_stdio_uart);
|
||||
} else if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) {
|
||||
return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart));
|
||||
}
|
||||
__WFI();
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "readline.h"
|
||||
#include "pybstdio.h"
|
||||
|
||||
|
@ -40,14 +39,12 @@
|
|||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
#define READLINE_HIST_SIZE (8)
|
||||
|
||||
static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
#define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)))
|
||||
|
||||
enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O };
|
||||
|
||||
void readline_init0(void) {
|
||||
memset(readline_hist, 0, READLINE_HIST_SIZE * sizeof(const char*));
|
||||
memset(MP_STATE_PORT(readline_hist), 0, READLINE_HIST_SIZE * sizeof(const char*));
|
||||
}
|
||||
|
||||
STATIC char *str_dup_maybe(const char *str) {
|
||||
|
@ -89,15 +86,15 @@ int readline(vstr_t *line, const char *prompt) {
|
|||
} else if (c == '\r') {
|
||||
// newline
|
||||
stdout_tx_str("\r\n");
|
||||
if (line->len > orig_line_len && (readline_hist[0] == NULL || strcmp(readline_hist[0], line->buf + orig_line_len) != 0)) {
|
||||
if (line->len > orig_line_len && (MP_STATE_PORT(readline_hist)[0] == NULL || strcmp(MP_STATE_PORT(readline_hist)[0], line->buf + orig_line_len) != 0)) {
|
||||
// a line which is not empty and different from the last one
|
||||
// so update the history
|
||||
char *most_recent_hist = str_dup_maybe(line->buf + orig_line_len);
|
||||
if (most_recent_hist != NULL) {
|
||||
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
|
||||
readline_hist[i] = readline_hist[i - 1];
|
||||
MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1];
|
||||
}
|
||||
readline_hist[0] = most_recent_hist;
|
||||
MP_STATE_PORT(readline_hist)[0] = most_recent_hist;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -139,12 +136,12 @@ int readline(vstr_t *line, const char *prompt) {
|
|||
escape_seq = ESEQ_NONE;
|
||||
if (c == 'A') {
|
||||
// up arrow
|
||||
if (hist_cur + 1 < READLINE_HIST_SIZE && readline_hist[hist_cur + 1] != NULL) {
|
||||
if (hist_cur + 1 < READLINE_HIST_SIZE && MP_STATE_PORT(readline_hist)[hist_cur + 1] != NULL) {
|
||||
// increase hist num
|
||||
hist_cur += 1;
|
||||
// set line to history
|
||||
line->len = orig_line_len;
|
||||
vstr_add_str(line, readline_hist[hist_cur]);
|
||||
vstr_add_str(line, MP_STATE_PORT(readline_hist)[hist_cur]);
|
||||
// set redraw parameters
|
||||
redraw_step_back = cursor_pos - orig_line_len;
|
||||
redraw_from_cursor = true;
|
||||
|
@ -158,7 +155,7 @@ int readline(vstr_t *line, const char *prompt) {
|
|||
// set line to history
|
||||
vstr_cut_tail_bytes(line, line->len - orig_line_len);
|
||||
if (hist_cur >= 0) {
|
||||
vstr_add_str(line, readline_hist[hist_cur]);
|
||||
vstr_add_str(line, MP_STATE_PORT(readline_hist)[hist_cur]);
|
||||
}
|
||||
// set redraw parameters
|
||||
redraw_step_back = cursor_pos - orig_line_len;
|
||||
|
|
|
@ -145,9 +145,7 @@ TIM_HandleTypeDef TIM6_Handle;
|
|||
// Used to divide down TIM3 and periodically call the flash storage IRQ
|
||||
STATIC uint32_t tim3_counter = 0;
|
||||
|
||||
// Used to do callbacks to Python code on interrupt
|
||||
STATIC pyb_timer_obj_t *pyb_timer_obj_all[14];
|
||||
#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(pyb_timer_obj_all)
|
||||
#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(MP_STATE_PORT(pyb_timer_obj_all))
|
||||
|
||||
STATIC uint32_t timer_get_source_freq(uint32_t tim_id);
|
||||
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in);
|
||||
|
@ -157,14 +155,14 @@ STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback);
|
|||
void timer_init0(void) {
|
||||
tim3_counter = 0;
|
||||
for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) {
|
||||
pyb_timer_obj_all[i] = NULL;
|
||||
MP_STATE_PORT(pyb_timer_obj_all)[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// unregister all interrupt sources
|
||||
void timer_deinit(void) {
|
||||
for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) {
|
||||
pyb_timer_obj_t *tim = pyb_timer_obj_all[i];
|
||||
pyb_timer_obj_t *tim = MP_STATE_PORT(pyb_timer_obj_all)[i];
|
||||
if (tim != NULL) {
|
||||
pyb_timer_deinit(tim);
|
||||
}
|
||||
|
@ -659,7 +657,7 @@ STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
|
|||
|
||||
// set the global variable for interrupt callbacks
|
||||
if (tim->tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
|
||||
pyb_timer_obj_all[tim->tim_id - 1] = tim;
|
||||
MP_STATE_PORT(pyb_timer_obj_all)[tim->tim_id - 1] = tim;
|
||||
}
|
||||
|
||||
return (mp_obj_t)tim;
|
||||
|
@ -1253,7 +1251,7 @@ STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o
|
|||
void timer_irq_handler(uint tim_id) {
|
||||
if (tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
|
||||
// get the timer object
|
||||
pyb_timer_obj_t *tim = pyb_timer_obj_all[tim_id - 1];
|
||||
pyb_timer_obj_t *tim = MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1];
|
||||
|
||||
if (tim == NULL) {
|
||||
// Timer object has not been set, so we can't do anything.
|
||||
|
|
|
@ -90,21 +90,18 @@ struct _pyb_uart_obj_t {
|
|||
byte *read_buf; // byte or uint16_t, depending on char size
|
||||
};
|
||||
|
||||
// pointers to all UART objects (if they have been created)
|
||||
STATIC pyb_uart_obj_t *pyb_uart_obj_all[6];
|
||||
|
||||
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
|
||||
|
||||
void uart_init0(void) {
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(pyb_uart_obj_all); i++) {
|
||||
pyb_uart_obj_all[i] = NULL;
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) {
|
||||
MP_STATE_PORT(pyb_uart_obj_all)[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// unregister all interrupt sources
|
||||
void uart_deinit(void) {
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(pyb_uart_obj_all); i++) {
|
||||
pyb_uart_obj_t *uart_obj = pyb_uart_obj_all[i];
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) {
|
||||
pyb_uart_obj_t *uart_obj = MP_STATE_PORT(pyb_uart_obj_all)[i];
|
||||
if (uart_obj != NULL) {
|
||||
pyb_uart_deinit(uart_obj);
|
||||
}
|
||||
|
@ -302,7 +299,7 @@ void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
|
|||
// this IRQ handler is set up to handle RXNE interrupts only
|
||||
void uart_irq_handler(mp_uint_t uart_id) {
|
||||
// get the uart object
|
||||
pyb_uart_obj_t *self = pyb_uart_obj_all[uart_id - 1];
|
||||
pyb_uart_obj_t *self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1];
|
||||
|
||||
if (self == NULL) {
|
||||
// UART object has not been set, so we can't do anything, not
|
||||
|
@ -502,21 +499,21 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
|
|||
}
|
||||
} else {
|
||||
uart_id = mp_obj_get_int(args[0]);
|
||||
if (uart_id < 1 || uart_id > MP_ARRAY_SIZE(pyb_uart_obj_all)) {
|
||||
if (uart_id < 1 || uart_id > MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all))) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_id));
|
||||
}
|
||||
}
|
||||
|
||||
pyb_uart_obj_t *self;
|
||||
if (pyb_uart_obj_all[uart_id - 1] == NULL) {
|
||||
if (MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] == NULL) {
|
||||
// create new UART object
|
||||
self = m_new0(pyb_uart_obj_t, 1);
|
||||
self->base.type = &pyb_uart_type;
|
||||
self->uart_id = uart_id;
|
||||
pyb_uart_obj_all[uart_id - 1] = self;
|
||||
MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] = self;
|
||||
} else {
|
||||
// reference existing UART object
|
||||
self = pyb_uart_obj_all[uart_id - 1];
|
||||
self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1];
|
||||
}
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
|
|
|
@ -45,12 +45,11 @@ USBD_HandleTypeDef hUSBDDevice;
|
|||
#endif
|
||||
|
||||
STATIC int dev_is_enabled = 0;
|
||||
STATIC mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
|
||||
|
||||
void pyb_usb_init0(void) {
|
||||
// create an exception object for interrupting by VCP
|
||||
mp_const_vcp_interrupt = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
|
||||
USBD_CDC_SetInterrupt(-1, mp_const_vcp_interrupt);
|
||||
MP_STATE_PORT(mp_const_vcp_interrupt) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
|
||||
USBD_CDC_SetInterrupt(-1, MP_STATE_PORT(mp_const_vcp_interrupt));
|
||||
}
|
||||
|
||||
void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium) {
|
||||
|
@ -102,9 +101,9 @@ bool usb_vcp_is_connected(void) {
|
|||
void usb_vcp_set_interrupt_char(int c) {
|
||||
if (dev_is_enabled) {
|
||||
if (c != -1) {
|
||||
mp_obj_exception_clear_traceback(mp_const_vcp_interrupt);
|
||||
mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_const_vcp_interrupt));
|
||||
}
|
||||
USBD_CDC_SetInterrupt(c, mp_const_vcp_interrupt);
|
||||
USBD_CDC_SetInterrupt(c, MP_STATE_PORT(mp_const_vcp_interrupt));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "extint.h"
|
||||
#include "pin.h"
|
||||
|
@ -73,10 +71,9 @@ int switch_get(void) {
|
|||
|
||||
typedef struct _pyb_switch_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t callback;
|
||||
} pyb_switch_obj_t;
|
||||
|
||||
STATIC pyb_switch_obj_t pyb_switch_obj;
|
||||
STATIC const pyb_switch_obj_t pyb_switch_obj = {{&pyb_switch_type}};
|
||||
|
||||
void pyb_switch_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
print(env, "Switch()");
|
||||
|
@ -88,9 +85,6 @@ STATIC mp_obj_t pyb_switch_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_
|
|||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
|
||||
// init the switch object
|
||||
pyb_switch_obj.base.type = &pyb_switch_type;
|
||||
|
||||
// No need to clear the callback member: if it's already been set and registered
|
||||
// with extint then we don't want to reset that behaviour. If it hasn't been set,
|
||||
// then no extint will be called until it is set via the callback method.
|
||||
|
@ -108,8 +102,8 @@ mp_obj_t pyb_switch_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, con
|
|||
}
|
||||
|
||||
STATIC mp_obj_t switch_callback(mp_obj_t line) {
|
||||
if (pyb_switch_obj.callback != mp_const_none) {
|
||||
mp_call_function_0(pyb_switch_obj.callback);
|
||||
if (MP_STATE_PORT(pyb_switch_callback) != mp_const_none) {
|
||||
mp_call_function_0(MP_STATE_PORT(pyb_switch_callback));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -119,8 +113,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(switch_callback_obj, switch_callback);
|
|||
/// Register the given function to be called when the switch is pressed down.
|
||||
/// If `fun` is `None`, then it disables the callback.
|
||||
mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) {
|
||||
pyb_switch_obj_t *self = self_in;
|
||||
self->callback = callback;
|
||||
MP_STATE_PORT(pyb_switch_callback) = callback;
|
||||
// Init the EXTI each time this function is called, since the EXTI
|
||||
// may have been disabled by an exception in the interrupt, or the
|
||||
// user disabling the line explicitly.
|
||||
|
@ -128,7 +121,7 @@ mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) {
|
|||
MICROPY_HW_USRSW_EXTI_MODE,
|
||||
MICROPY_HW_USRSW_PULL,
|
||||
callback == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj,
|
||||
true, NULL);
|
||||
true);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_switch_callback_obj, pyb_switch_callback);
|
||||
|
|
|
@ -44,6 +44,14 @@ extern const struct _mp_obj_module_t time_module;
|
|||
#define MICROPY_PORT_CONSTANTS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8]; \
|
||||
mp_obj_t pin_class_mapper; \
|
||||
mp_obj_t pin_class_map_dict; \
|
||||
struct _pyb_uart_obj_t *pyb_stdio_uart; \
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define BYTES_PER_WORD (4)
|
||||
|
|
Loading…
Reference in New Issue