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:
Damien George 2015-01-07 23:38:50 +00:00
parent 7a0636e80a
commit 3b51b3e90f
16 changed files with 142 additions and 138 deletions

View File

@ -61,6 +61,11 @@ extern const struct _mp_obj_module_t pyb_module;
#define MICROPY_PORT_BUILTIN_MODULES \ #define MICROPY_PORT_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ { 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() // We need to provide a declaration/definition of alloca()
#include <alloca.h> #include <alloca.h>

View File

@ -28,8 +28,6 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <stm32f4xx_hal.h>
#include "py/nlr.h" #include "py/nlr.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "py/gc.h" #include "py/gc.h"
@ -101,13 +99,7 @@ typedef struct {
mp_int_t line; mp_int_t line;
} extint_obj_t; } extint_obj_t;
typedef struct { STATIC uint32_t pyb_extint_mode[EXTI_NUM_VECTORS];
mp_obj_t callback_obj;
void *param;
uint32_t mode;
} extint_vector_t;
STATIC extint_vector_t extint_vector[EXTI_NUM_VECTORS];
#if !defined(ETH) #if !defined(ETH)
#define ETH_WKUP_IRQn 62 // The 405 doesn't have ETH, but we want a value to put in our table #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 // Set override_callback_obj to true if you want to unconditionally set the
// callback function. // callback function.
// uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj) {
// 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) {
const pin_obj_t *pin = NULL; const pin_obj_t *pin = NULL;
uint v_line; 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)); nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid ExtInt Pull: %d", pull));
} }
extint_vector_t *v = &extint_vector[v_line]; mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[v_line];
if (!override_callback_obj && v->callback_obj != mp_const_none && callback_obj != mp_const_none) { 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)); 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. // before we update anything.
extint_disable(v_line); extint_disable(v_line);
v->callback_obj = callback_obj; *cb = callback_obj;
v->param = param; pyb_extint_mode[v_line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
v->mode = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
EXTI_Mode_Interrupt : EXTI_Mode_Event; EXTI_Mode_Interrupt : EXTI_Mode_Event;
if (v->callback_obj != mp_const_none) { if (*cb != mp_const_none) {
GPIO_InitTypeDef exti; GPIO_InitTypeDef exti;
exti.Pin = pin->pin_mask; 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 // 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 // be atomic, we use the bit-band area to just affect the bit we're
// interested in. // 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) { 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); extint_obj_t *self = m_new_obj(extint_obj_t);
self->base.type = type_in; 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; return self;
} }
@ -343,11 +331,10 @@ const mp_obj_type_t extint_type = {
}; };
void extint_init0(void) { void extint_init0(void) {
for (extint_vector_t *v = extint_vector; v < &extint_vector[EXTI_NUM_VECTORS]; v++) { for (int i = 0; i < PYB_EXTI_NUM_VECTORS; i++) {
v->callback_obj = mp_const_none; MP_STATE_PORT(pyb_extint_callback)[i] = mp_const_none;
v->param = NULL; pyb_extint_mode[i] = EXTI_Mode_Interrupt;
v->mode = EXTI_Mode_Interrupt; }
}
} }
// Interrupt handler // Interrupt handler
@ -355,18 +342,18 @@ void Handle_EXTI_Irq(uint32_t line) {
if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) { if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) {
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << line); __HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
if (line < EXTI_NUM_VECTORS) { if (line < EXTI_NUM_VECTORS) {
extint_vector_t *v = &extint_vector[line]; mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
if (v->callback_obj != mp_const_none) { if (*cb != mp_const_none) {
// When executing code within a handler we must lock the GC to prevent // When executing code within a handler we must lock the GC to prevent
// any memory allocations. We must also catch any exceptions. // any memory allocations. We must also catch any exceptions.
gc_lock(); gc_lock();
nlr_buf_t nlr; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { 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(); nlr_pop();
} else { } else {
// Uncaught exception; disable the callback so it doesn't run again. // Uncaught exception; disable the callback so it doesn't run again.
v->callback_obj = mp_const_none; *cb = mp_const_none;
extint_disable(line); extint_disable(line);
printf("Uncaught exception in ExtInt interrupt handler line %lu\n", 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); mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);

View File

@ -37,7 +37,7 @@
#define EXTI_RTC_TIMESTAMP (21) #define EXTI_RTC_TIMESTAMP (21)
#define EXTI_RTC_WAKEUP (22) #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_INTERRUPT (offsetof(EXTI_TypeDef, IMR))
#define EXTI_MODE_EVENT (offsetof(EXTI_TypeDef, EMR)) #define EXTI_MODE_EVENT (offsetof(EXTI_TypeDef, EMR))
@ -48,7 +48,7 @@
void extint_init0(void); 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_enable(uint line);
void extint_disable(uint line); void extint_disable(uint line);

View File

@ -30,24 +30,19 @@
#include "py/obj.h" #include "py/obj.h"
#include "py/gc.h" #include "py/gc.h"
#include "gccollect.h" #include "gccollect.h"
#include MICROPY_HAL_H #include "systick.h"
mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs); 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) { void gc_collect(void) {
// get current time, in case we want to time the GC // 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 // start the GC
gc_collect_start(); 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 // get the registers and the sp
mp_uint_t regs[10]; mp_uint_t regs[10];
mp_uint_t sp = gc_helper_get_regs_and_sp(regs); mp_uint_t sp = gc_helper_get_regs_and_sp(regs);
@ -58,14 +53,14 @@ void gc_collect(void) {
// end the GC // end the GC
gc_collect_end(); gc_collect_end();
if (0) { #if 0
// print GC info // print GC info
uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly uint32_t ticks = sys_tick_get_microseconds() - start;
gc_info_t info; gc_info_t info;
gc_info(&info); gc_info(&info);
printf("GC@%lu %lums\n", start, ticks); printf("GC@%lu %lums\n", start, ticks);
printf(" " UINT_FMT " total\n", info.total); printf(" " UINT_FMT " total\n", info.total);
printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); 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); printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
} #endif
} }

View File

@ -112,12 +112,9 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
} }
#endif #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) { STATIC mp_obj_t pyb_main(mp_obj_t main) {
if (MP_OBJ_IS_STR(main)) { if (MP_OBJ_IS_STR(main)) {
pyb_config_main = main; MP_STATE_PORT(pyb_config_main) = main;
} }
return mp_const_none; 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) { STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) {
if (MP_OBJ_IS_STR(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; 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); pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
} }
#else #else
pyb_stdio_uart = NULL; MP_STATE_PORT(pyb_stdio_uart) = NULL;
#endif #endif
// Initialise low-level sub-systems. Here we need to very basic things like // Initialise low-level sub-systems. Here we need to very basic things like
@ -444,8 +441,8 @@ soft_reset:
#endif #endif
// reset config variables; they should be set by boot.py // reset config variables; they should be set by boot.py
pyb_config_main = MP_OBJ_NULL; MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
pyb_config_usb_mode = MP_OBJ_NULL; MP_STATE_PORT(pyb_config_usb_mode) = MP_OBJ_NULL;
// run boot.py, if it exists // run boot.py, if it exists
// TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py // 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
usb_device_mode_t usb_mode = USB_DEVICE_MODE_CDC_MSC; 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 we are not in reset_mode==1, this config variable will always be NULL
if (pyb_config_usb_mode != MP_OBJ_NULL) { if (MP_STATE_PORT(pyb_config_usb_mode) != MP_OBJ_NULL) {
if (strcmp(mp_obj_str_get_str(pyb_config_usb_mode), "CDC+HID") == 0) { if (strcmp(mp_obj_str_get_str(MP_STATE_PORT(pyb_config_usb_mode)), "CDC+HID") == 0) {
usb_mode = USB_DEVICE_MODE_CDC_HID; usb_mode = USB_DEVICE_MODE_CDC_HID;
} }
} }
@ -509,10 +506,10 @@ soft_reset:
// Run the main script from the current directory. // Run the main script from the current directory.
if (reset_mode == 1 && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { if (reset_mode == 1 && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
const char *main_py; 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"; main_py = "main.py";
} else { } 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); FRESULT res = f_stat(main_py, NULL);
if (res == FR_OK) { if (res == FR_OK) {

View File

@ -29,6 +29,7 @@
#include "stm32f4xx_hal.h" #include "stm32f4xx_hal.h"
#include "py/mpstate.h"
#include "py/nlr.h" #include "py/nlr.h"
#include "py/obj.h" #include "py/obj.h"
#include "py/gc.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. /// 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) { STATIC mp_obj_t pyb_repl_uart(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) { if (n_args == 0) {
if (pyb_stdio_uart == NULL) { if (MP_STATE_PORT(pyb_stdio_uart) == NULL) {
return mp_const_none; return mp_const_none;
} else { } else {
return pyb_stdio_uart; return MP_STATE_PORT(pyb_stdio_uart);
} }
} else { } else {
if (args[0] == mp_const_none) { 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) { } 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 { } else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a UART object")); nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a UART object"));
} }

View File

@ -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_pyb), (mp_obj_t)&pyb_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_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 // type definitions for the specific machine
#define BYTES_PER_WORD (4) #define BYTES_PER_WORD (4)

View File

@ -31,7 +31,10 @@
#include "py/runtime.h" #include "py/runtime.h"
#include "pendsv.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) { void pendsv_init(void) {
// set PendSV interrupt at lowest priority // set PendSV interrupt at lowest priority

View File

@ -91,13 +91,11 @@
/// how a particular object gets mapped to a pin. /// how a particular object gets mapped to a pin.
// Pin class variables // Pin class variables
STATIC mp_obj_t pin_class_mapper;
STATIC mp_obj_t pin_class_map_dict;
STATIC bool pin_class_debug; STATIC bool pin_class_debug;
void pin_init0(void) { void pin_init0(void) {
pin_class_mapper = mp_const_none; MP_STATE_PORT(pin_class_mapper) = mp_const_none;
pin_class_map_dict = mp_const_none; MP_STATE_PORT(pin_class_map_dict) = mp_const_none;
pin_class_debug = false; pin_class_debug = false;
} }
@ -116,8 +114,8 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) {
return pin_obj; return pin_obj;
} }
if (pin_class_mapper != mp_const_none) { if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) {
pin_obj = mp_call_function_1(pin_class_mapper, user_obj); pin_obj = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj);
if (pin_obj != mp_const_none) { if (pin_obj != mp_const_none) {
if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { 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")); 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. // other lookup methods.
} }
if (pin_class_map_dict != mp_const_none) { if (MP_STATE_PORT(pin_class_map_dict) != mp_const_none) {
mp_map_t *pin_map_map = mp_obj_dict_get_map(pin_class_map_dict); 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); mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP);
if (elem != NULL && elem->value != NULL) { if (elem != NULL && elem->value != NULL) {
pin_obj = elem->value; 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. /// Get or set the pin mapper function.
STATIC mp_obj_t pin_mapper(mp_uint_t n_args, const mp_obj_t *args) { STATIC mp_obj_t pin_mapper(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args > 1) { if (n_args > 1) {
pin_class_mapper = args[1]; MP_STATE_PORT(pin_class_mapper) = args[1];
return mp_const_none; 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_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); 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. /// Get or set the pin mapper dictionary.
STATIC mp_obj_t pin_map_dict(mp_uint_t n_args, const mp_obj_t *args) { STATIC mp_obj_t pin_map_dict(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args > 1) { if (n_args > 1) {
pin_class_map_dict = args[1]; MP_STATE_PORT(pin_class_map_dict) = args[1];
return mp_const_none; 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_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); STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj);

View File

@ -29,6 +29,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "py/mpstate.h"
#include "py/obj.h" #include "py/obj.h"
#include "py/stream.h" #include "py/stream.h"
#include "usb.h" #include "usb.h"
@ -40,16 +41,13 @@
// be changed by Python code. This requires some changes, as these // be changed by Python code. This requires some changes, as these
// objects are in a read-only module (py/modsys.c). // 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) { void stdout_tx_str(const char *str) {
stdout_tx_strn(str, strlen(str)); stdout_tx_strn(str, strlen(str));
} }
void stdout_tx_strn(const char *str, mp_uint_t len) { void stdout_tx_strn(const char *str, mp_uint_t len) {
if (pyb_stdio_uart != PYB_UART_NONE) { if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
uart_tx_strn(pyb_stdio_uart, str, len); uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
} }
#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD #if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
lcd_print_strn(str, len); 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) { void stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
// send stdout to UART and USB CDC VCP // send stdout to UART and USB CDC VCP
if (pyb_stdio_uart != PYB_UART_NONE) { if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
uart_tx_strn_cooked(pyb_stdio_uart, str, len); uart_tx_strn_cooked(MP_STATE_PORT(pyb_stdio_uart), str, len);
} }
if (usb_vcp_is_enabled()) { if (usb_vcp_is_enabled()) {
usb_vcp_send_strn_cooked(str, len); usb_vcp_send_strn_cooked(str, len);
@ -84,8 +82,8 @@ int stdin_rx_chr(void) {
byte c; byte c;
if (usb_vcp_recv_byte(&c) != 0) { if (usb_vcp_recv_byte(&c) != 0) {
return c; return c;
} else if (pyb_stdio_uart != PYB_UART_NONE && uart_rx_any(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(pyb_stdio_uart); return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart));
} }
__WFI(); __WFI();
} }

View File

@ -28,8 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "py/mpconfig.h" #include "py/mpstate.h"
#include "py/misc.h"
#include "readline.h" #include "readline.h"
#include "pybstdio.h" #include "pybstdio.h"
@ -40,14 +39,12 @@
#define DEBUG_printf(...) (void)0 #define DEBUG_printf(...) (void)0
#endif #endif
#define READLINE_HIST_SIZE (8) #define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)))
static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O }; enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O };
void readline_init0(void) { 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) { STATIC char *str_dup_maybe(const char *str) {
@ -89,15 +86,15 @@ int readline(vstr_t *line, const char *prompt) {
} else if (c == '\r') { } else if (c == '\r') {
// newline // newline
stdout_tx_str("\r\n"); 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 // a line which is not empty and different from the last one
// so update the history // so update the history
char *most_recent_hist = str_dup_maybe(line->buf + orig_line_len); char *most_recent_hist = str_dup_maybe(line->buf + orig_line_len);
if (most_recent_hist != NULL) { if (most_recent_hist != NULL) {
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) { 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; return 0;
@ -139,12 +136,12 @@ int readline(vstr_t *line, const char *prompt) {
escape_seq = ESEQ_NONE; escape_seq = ESEQ_NONE;
if (c == 'A') { if (c == 'A') {
// up arrow // 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 // increase hist num
hist_cur += 1; hist_cur += 1;
// set line to history // set line to history
line->len = orig_line_len; 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 // set redraw parameters
redraw_step_back = cursor_pos - orig_line_len; redraw_step_back = cursor_pos - orig_line_len;
redraw_from_cursor = true; redraw_from_cursor = true;
@ -158,7 +155,7 @@ int readline(vstr_t *line, const char *prompt) {
// set line to history // set line to history
vstr_cut_tail_bytes(line, line->len - orig_line_len); vstr_cut_tail_bytes(line, line->len - orig_line_len);
if (hist_cur >= 0) { 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 // set redraw parameters
redraw_step_back = cursor_pos - orig_line_len; redraw_step_back = cursor_pos - orig_line_len;

View File

@ -145,9 +145,7 @@ TIM_HandleTypeDef TIM6_Handle;
// Used to divide down TIM3 and periodically call the flash storage IRQ // Used to divide down TIM3 and periodically call the flash storage IRQ
STATIC uint32_t tim3_counter = 0; STATIC uint32_t tim3_counter = 0;
// Used to do callbacks to Python code on interrupt #define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(MP_STATE_PORT(pyb_timer_obj_all))
STATIC pyb_timer_obj_t *pyb_timer_obj_all[14];
#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(pyb_timer_obj_all)
STATIC uint32_t timer_get_source_freq(uint32_t tim_id); STATIC uint32_t timer_get_source_freq(uint32_t tim_id);
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in); 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) { void timer_init0(void) {
tim3_counter = 0; tim3_counter = 0;
for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { 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 // unregister all interrupt sources
void timer_deinit(void) { void timer_deinit(void) {
for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { 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) { if (tim != NULL) {
pyb_timer_deinit(tim); 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 // set the global variable for interrupt callbacks
if (tim->tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) { 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; 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) { void timer_irq_handler(uint tim_id) {
if (tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) { if (tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
// get the timer object // 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) { if (tim == NULL) {
// Timer object has not been set, so we can't do anything. // Timer object has not been set, so we can't do anything.

View File

@ -90,21 +90,18 @@ 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
}; };
// 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); STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
void uart_init0(void) { void uart_init0(void) {
for (int i = 0; i < MP_ARRAY_SIZE(pyb_uart_obj_all); i++) { for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) {
pyb_uart_obj_all[i] = NULL; MP_STATE_PORT(pyb_uart_obj_all)[i] = NULL;
} }
} }
// unregister all interrupt sources // unregister all interrupt sources
void uart_deinit(void) { void uart_deinit(void) {
for (int i = 0; i < MP_ARRAY_SIZE(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 = pyb_uart_obj_all[i]; pyb_uart_obj_t *uart_obj = MP_STATE_PORT(pyb_uart_obj_all)[i];
if (uart_obj != NULL) { if (uart_obj != NULL) {
pyb_uart_deinit(uart_obj); 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 // this IRQ handler is set up to handle RXNE interrupts only
void uart_irq_handler(mp_uint_t uart_id) { void uart_irq_handler(mp_uint_t uart_id) {
// get the uart object // 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) { if (self == NULL) {
// UART object has not been set, so we can't do anything, not // 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 { } else {
uart_id = mp_obj_get_int(args[0]); 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)); nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_id));
} }
} }
pyb_uart_obj_t *self; 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 // create new UART object
self = m_new0(pyb_uart_obj_t, 1); self = m_new0(pyb_uart_obj_t, 1);
self->base.type = &pyb_uart_type; self->base.type = &pyb_uart_type;
self->uart_id = uart_id; 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 { } else {
// reference existing UART object // 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) { if (n_args > 1 || n_kw > 0) {

View File

@ -45,12 +45,11 @@ USBD_HandleTypeDef hUSBDDevice;
#endif #endif
STATIC int dev_is_enabled = 0; STATIC int dev_is_enabled = 0;
STATIC mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
void pyb_usb_init0(void) { void pyb_usb_init0(void) {
// create an exception object for interrupting by VCP // create an exception object for interrupting by VCP
mp_const_vcp_interrupt = mp_obj_new_exception(&mp_type_KeyboardInterrupt); MP_STATE_PORT(mp_const_vcp_interrupt) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
USBD_CDC_SetInterrupt(-1, mp_const_vcp_interrupt); 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) { 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) { void usb_vcp_set_interrupt_char(int c) {
if (dev_is_enabled) { if (dev_is_enabled) {
if (c != -1) { 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));
} }
} }

View File

@ -26,8 +26,6 @@
#include <stdio.h> #include <stdio.h>
#include "stm32f4xx_hal.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "extint.h" #include "extint.h"
#include "pin.h" #include "pin.h"
@ -73,10 +71,9 @@ int switch_get(void) {
typedef struct _pyb_switch_obj_t { typedef struct _pyb_switch_obj_t {
mp_obj_base_t base; mp_obj_base_t base;
mp_obj_t callback;
} pyb_switch_obj_t; } 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) { 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()"); 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 // check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false); 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 // 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, // 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. // 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) { STATIC mp_obj_t switch_callback(mp_obj_t line) {
if (pyb_switch_obj.callback != mp_const_none) { if (MP_STATE_PORT(pyb_switch_callback) != mp_const_none) {
mp_call_function_0(pyb_switch_obj.callback); mp_call_function_0(MP_STATE_PORT(pyb_switch_callback));
} }
return mp_const_none; 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. /// Register the given function to be called when the switch is pressed down.
/// If `fun` is `None`, then it disables the callback. /// If `fun` is `None`, then it disables the callback.
mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) { mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) {
pyb_switch_obj_t *self = self_in; MP_STATE_PORT(pyb_switch_callback) = callback;
self->callback = callback;
// Init the EXTI each time this function is called, since the EXTI // Init the EXTI each time this function is called, since the EXTI
// may have been disabled by an exception in the interrupt, or the // may have been disabled by an exception in the interrupt, or the
// user disabling the line explicitly. // 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_EXTI_MODE,
MICROPY_HW_USRSW_PULL, MICROPY_HW_USRSW_PULL,
callback == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj, callback == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj,
true, NULL); true);
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_switch_callback_obj, pyb_switch_callback); STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_switch_callback_obj, pyb_switch_callback);

View File

@ -44,6 +44,14 @@ extern const struct _mp_obj_module_t time_module;
#define MICROPY_PORT_CONSTANTS \ #define MICROPY_PORT_CONSTANTS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ { 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 // type definitions for the specific machine
#define BYTES_PER_WORD (4) #define BYTES_PER_WORD (4)