diff --git a/lib/protomatter b/lib/protomatter index c9c1189e9d..98a2da6da4 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit c9c1189e9d6200bb09bf4a87d84be9459cae481b +Subproject commit 98a2da6da4bdbfee8f3ab2334871e8c360dccae3 diff --git a/main.c b/main.c index 2607217e1b..3d4d665beb 100644 --- a/main.c +++ b/main.c @@ -219,6 +219,10 @@ STATIC void stop_mp(void) { usb_background(); #endif + // Set the qstr pool back to the const pools. The heap allocated ones will + // be overwritten. + qstr_reset(); + gc_deinit(); } diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk index e45e4bc707..d89c365b68 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk @@ -7,7 +7,7 @@ IDF_TARGET = esp32s3 CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_FLASH_MODE = qio -CIRCUITPY_ESP_FLASH_FREQ = 40m +CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_PSRAM_SIZE = 2MB CIRCUITPY_ESP_PSRAM_MODE = qio diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index cc2ddf9f07..84ac4f3e34 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -39,8 +39,7 @@ CIRCUITPY_NVM ?= 1 # Turn off because it uses the old I2S driver which conflicts with the new ADC driver. CIRCUITPY_PARALLELDISPLAY ?= 0 CIRCUITPY_PS2IO ?= 1 -# Disabled temporarily -CIRCUITPY_RGBMATRIX ?= 0 +CIRCUITPY_RGBMATRIX ?= 1 CIRCUITPY_ROTARYIO ?= 1 CIRCUITPY_SYNTHIO_MAX_CHANNELS ?= 12 CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1 diff --git a/py/qstr.c b/py/qstr.c index 5ff8b3bd54..6b7aead5c8 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -122,9 +122,13 @@ extern const qstr_pool_t MICROPY_QSTR_EXTRA_POOL; #define CONST_POOL mp_qstr_const_pool #endif -void qstr_init(void) { +void qstr_reset(void) { MP_STATE_VM(last_pool) = (qstr_pool_t *)&CONST_POOL; // we won't modify the const_pool since it has no allocated room left MP_STATE_VM(qstr_last_chunk) = NULL; +} + +void qstr_init(void) { + qstr_reset(); #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(qstr_mutex)); diff --git a/py/qstr.h b/py/qstr.h index c6c9768d05..24e0e756a3 100644 --- a/py/qstr.h +++ b/py/qstr.h @@ -78,6 +78,7 @@ typedef struct _qstr_pool_t { #define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len) +void qstr_reset(void); void qstr_init(void); mp_uint_t qstr_compute_hash(const byte *data, size_t len); diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 5d3c29b8aa..6b73ad2b6f 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -276,7 +276,7 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); displayio_display_obj_t *self = native_display(pos_args[0]); - uint32_t maximum_ms_per_real_frame = 0xffffffff; + uint32_t maximum_ms_per_real_frame = NO_FPS_LIMIT; mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int; if (minimum_frames_per_second > 0) { maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; @@ -284,7 +284,7 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos uint32_t target_ms_per_frame; if (args[ARG_target_frames_per_second].u_obj == mp_const_none) { - target_ms_per_frame = 0xffffffff; + target_ms_per_frame = NO_FPS_LIMIT; } else { target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj); } diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 50fb7c4bfd..af813866ed 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -35,6 +35,7 @@ extern const mp_obj_type_t displayio_display_type; #define NO_BRIGHTNESS_COMMAND 0x100 +#define NO_FPS_LIMIT 0xffffffff void common_hal_displayio_display_construct(displayio_display_obj_t *self, mp_obj_t bus, uint16_t width, uint16_t height, diff --git a/shared-bindings/framebufferio/FramebufferDisplay.c b/shared-bindings/framebufferio/FramebufferDisplay.c index 45eedcaa95..955761c273 100644 --- a/shared-bindings/framebufferio/FramebufferDisplay.c +++ b/shared-bindings/framebufferio/FramebufferDisplay.c @@ -100,39 +100,55 @@ static framebufferio_framebufferdisplay_obj_t *native_display(mp_obj_t display_o } //| def refresh( -//| self, *, target_frames_per_second: int = 60, minimum_frames_per_second: int = 1 +//| self, +//| *, +//| target_frames_per_second: Optional[int] = None, +//| minimum_frames_per_second: int = 0 //| ) -> bool: -//| """When auto refresh is off, waits for the target frame rate and then refreshes the display, -//| returning True. If the call has taken too long since the last refresh call for the given -//| target frame rate, then the refresh returns False immediately without updating the screen to +//| """When auto_refresh is off, and :py:attr:`target_frames_per_second` is not `None` this waits +//| for the target frame rate and then refreshes the display, +//| returning `True`. If the call has taken too long since the last refresh call for the given +//| target frame rate, then the refresh returns `False` immediately without updating the screen to //| hopefully help getting caught up. //| //| If the time since the last successful refresh is below the minimum frame rate, then an -//| exception will be raised. Set minimum_frames_per_second to 0 to disable. +//| exception will be raised. The default :py:attr:`minimum_frames_per_second` of 0 disables this behavior. //| -//| When auto refresh is on, updates the display immediately. (The display will also update +//| When auto_refresh is off, and :py:attr:`target_frames_per_second` is `None` this +//| will update the display immediately. +//| +//| When auto_refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| -//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. +//| :param Optional[int] target_frames_per_second: The target frame rate that :py:func:`refresh` should try to +//| achieve. Set to `None` for immediate refresh. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second. //| """ //| ... STATIC mp_obj_t framebufferio_framebufferdisplay_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, - { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); framebufferio_framebufferdisplay_obj_t *self = native_display(pos_args[0]); - uint32_t maximum_ms_per_real_frame = 0xffffffff; + uint32_t maximum_ms_per_real_frame = NO_FPS_LIMIT; mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int; if (minimum_frames_per_second > 0) { maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; } - return mp_obj_new_bool(common_hal_framebufferio_framebufferdisplay_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, maximum_ms_per_real_frame)); + + uint32_t target_ms_per_frame; + if (args[ARG_target_frames_per_second].u_obj == mp_const_none) { + target_ms_per_frame = NO_FPS_LIMIT; + } else { + target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj); + } + return mp_obj_new_bool(common_hal_framebufferio_framebufferdisplay_refresh(self, target_ms_per_frame, maximum_ms_per_real_frame)); } MP_DEFINE_CONST_FUN_OBJ_KW(framebufferio_framebufferdisplay_refresh_obj, 1, framebufferio_framebufferdisplay_obj_refresh); diff --git a/shared-bindings/framebufferio/FramebufferDisplay.h b/shared-bindings/framebufferio/FramebufferDisplay.h index 96d39e6aef..87f57b0aaa 100644 --- a/shared-bindings/framebufferio/FramebufferDisplay.h +++ b/shared-bindings/framebufferio/FramebufferDisplay.h @@ -36,6 +36,7 @@ extern const mp_obj_type_t framebufferio_framebufferdisplay_type; #define NO_BRIGHTNESS_COMMAND 0x100 +#define NO_FPS_LIMIT 0xffffffff void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t *self, mp_obj_t framebuffer, diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 5d9cc2357c..94f29d2c93 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -354,7 +354,7 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t *self bool common_hal_displayio_display_refresh(displayio_display_obj_t *self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) { - if (!self->auto_refresh && !self->first_manual_refresh && (target_ms_per_frame != 0xffffffff)) { + if (!self->auto_refresh && !self->first_manual_refresh && (target_ms_per_frame != NO_FPS_LIMIT)) { uint64_t current_time = supervisor_ticks_ms64(); uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum. diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index ec59efef4a..df70010a0f 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -283,7 +283,7 @@ uint16_t common_hal_framebufferio_framebufferdisplay_get_rotation(framebufferio_ bool common_hal_framebufferio_framebufferdisplay_refresh(framebufferio_framebufferdisplay_obj_t *self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) { - if (!self->auto_refresh && !self->first_manual_refresh) { + if (!self->auto_refresh && !self->first_manual_refresh && (target_ms_per_frame != NO_FPS_LIMIT)) { uint64_t current_time = supervisor_ticks_ms64(); uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum.