Merge pull request #8553 from tannewt/switch_to_split_heap
Switch all ports to auto-growing split heap
This commit is contained in:
commit
01be5f402e
|
@ -351,3 +351,6 @@
|
||||||
[submodule "lib/certificates"]
|
[submodule "lib/certificates"]
|
||||||
path = lib/certificates
|
path = lib/certificates
|
||||||
url = https://github.com/adafruit/certificates
|
url = https://github.com/adafruit/certificates
|
||||||
|
[submodule "lib/tlsf"]
|
||||||
|
path = lib/tlsf
|
||||||
|
url = https://github.com/espressif/tlsf.git
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
// fabsf from musl-0.9.15
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#include "libm.h"
|
||||||
|
|
||||||
|
float fabsf(float x)
|
||||||
|
{
|
||||||
|
union {float f; uint32_t i;} u = {x};
|
||||||
|
u.i &= 0x7fffffff;
|
||||||
|
return u.f;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 8c9cd0517adf99e363812e9a295dfe3898fdd345
|
|
@ -1271,10 +1271,6 @@ msgstr ""
|
||||||
msgid "Invalid BSSID"
|
msgid "Invalid BSSID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: main.c
|
|
||||||
msgid "Invalid CIRCUITPY_PYSTACK_SIZE\n"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: shared-bindings/wifi/Radio.c
|
#: shared-bindings/wifi/Radio.c
|
||||||
msgid "Invalid MAC address"
|
msgid "Invalid MAC address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2164,7 +2160,7 @@ msgid "Unable to allocate buffers for signed conversion"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid "Unable to allocate the heap."
|
msgid "Unable to allocate to the heap."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/common-hal/busio/I2C.c
|
#: ports/espressif/common-hal/busio/I2C.c
|
||||||
|
@ -2735,7 +2731,7 @@ msgstr ""
|
||||||
msgid "can't set attribute"
|
msgid "can't set attribute"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/runtime.c shared-bindings/supervisor/Runtime.c
|
#: py/runtime.c
|
||||||
msgid "can't set attribute '%q'"
|
msgid "can't set attribute '%q'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3004,12 +3000,6 @@ msgstr ""
|
||||||
msgid "error = 0x%08lX"
|
msgid "error = 0x%08lX"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/common-hal/espcamera/Camera.c
|
|
||||||
msgid ""
|
|
||||||
"espcamera.Camera requires reserved PSRAM to be configured. See the "
|
|
||||||
"documentation for instructions."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/runtime.c
|
#: py/runtime.c
|
||||||
msgid "exceptions must derive from BaseException"
|
msgid "exceptions must derive from BaseException"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
177
main.c
177
main.c
|
@ -49,7 +49,6 @@
|
||||||
#include "supervisor/board.h"
|
#include "supervisor/board.h"
|
||||||
#include "supervisor/cpu.h"
|
#include "supervisor/cpu.h"
|
||||||
#include "supervisor/filesystem.h"
|
#include "supervisor/filesystem.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/serial.h"
|
#include "supervisor/serial.h"
|
||||||
#include "supervisor/shared/reload.h"
|
#include "supervisor/shared/reload.h"
|
||||||
|
@ -65,6 +64,7 @@
|
||||||
|
|
||||||
#include "shared-bindings/microcontroller/__init__.h"
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
#include "shared-bindings/microcontroller/Processor.h"
|
#include "shared-bindings/microcontroller/Processor.h"
|
||||||
|
#include "shared-bindings/supervisor/__init__.h"
|
||||||
#include "shared-bindings/supervisor/Runtime.h"
|
#include "shared-bindings/supervisor/Runtime.h"
|
||||||
|
|
||||||
#include "shared-bindings/os/__init__.h"
|
#include "shared-bindings/os/__init__.h"
|
||||||
|
@ -137,24 +137,36 @@ static void reset_devices(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MICROPY_ENABLE_PYSTACK
|
STATIC uint8_t *_heap;
|
||||||
STATIC supervisor_allocation *allocate_pystack(safe_mode_t safe_mode) {
|
STATIC uint8_t *_pystack;
|
||||||
#if CIRCUITPY_OS_GETENV && CIRCUITPY_SETTABLE_PYSTACK
|
|
||||||
|
#if MICROPY_ENABLE_PYSTACK || MICROPY_ENABLE_GC
|
||||||
|
STATIC uint8_t *_allocate_memory(safe_mode_t safe_mode, const char *env_key, size_t default_size, size_t *final_size) {
|
||||||
|
*final_size = default_size;
|
||||||
|
#if CIRCUITPY_OS_GETENV
|
||||||
if (safe_mode == SAFE_MODE_NONE) {
|
if (safe_mode == SAFE_MODE_NONE) {
|
||||||
mp_int_t pystack_size = CIRCUITPY_PYSTACK_SIZE;
|
(void)common_hal_os_getenv_int(env_key, (mp_int_t *)final_size);
|
||||||
(void)common_hal_os_getenv_int("CIRCUITPY_PYSTACK_SIZE", &pystack_size);
|
if (*final_size < 0) {
|
||||||
supervisor_allocation *pystack = allocate_memory(pystack_size >= 384 ? pystack_size : 0, false, false);
|
*final_size = default_size;
|
||||||
if (pystack) {
|
|
||||||
return pystack;
|
|
||||||
}
|
}
|
||||||
serial_write_compressed(MP_ERROR_TEXT("Invalid CIRCUITPY_PYSTACK_SIZE\n"));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return allocate_memory(CIRCUITPY_PYSTACK_SIZE, false, false);
|
uint8_t *ptr = port_malloc(*final_size, false);
|
||||||
|
|
||||||
|
#if CIRCUITPY_OS_GETENV
|
||||||
|
if (ptr == NULL) {
|
||||||
|
// Fallback to the build size.
|
||||||
|
ptr = port_malloc(default_size, false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ptr == NULL) {
|
||||||
|
reset_into_safe_mode(SAFE_MODE_NO_HEAP);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC void start_mp(supervisor_allocation *heap, supervisor_allocation *pystack) {
|
STATIC void start_mp(safe_mode_t safe_mode) {
|
||||||
supervisor_workflow_reset();
|
supervisor_workflow_reset();
|
||||||
|
|
||||||
// Stack limit should be less than real stack size, so we have a chance
|
// Stack limit should be less than real stack size, so we have a chance
|
||||||
|
@ -162,13 +174,12 @@ STATIC void start_mp(supervisor_allocation *heap, supervisor_allocation *pystack
|
||||||
// stack is set to our current state. Not the actual top.
|
// stack is set to our current state. Not the actual top.
|
||||||
mp_stack_ctrl_init();
|
mp_stack_ctrl_init();
|
||||||
|
|
||||||
uint32_t *stack_bottom = stack_get_bottom();
|
uint32_t *stack_bottom = port_stack_get_limit();
|
||||||
if (stack_bottom != NULL) {
|
uint32_t *stack_top = port_stack_get_top();
|
||||||
size_t stack_length = stack_get_length();
|
|
||||||
mp_stack_set_top(stack_bottom + (stack_length / sizeof(uint32_t)));
|
|
||||||
mp_stack_set_limit(stack_length - 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
size_t stack_length = (stack_top - stack_bottom) * sizeof(uint32_t);
|
||||||
|
mp_stack_set_top(stack_top);
|
||||||
|
mp_stack_set_limit(stack_length - CIRCUITPY_EXCEPTION_STACK_SIZE);
|
||||||
|
|
||||||
#if MICROPY_MAX_STACK_USAGE
|
#if MICROPY_MAX_STACK_USAGE
|
||||||
// _ezero (same as _ebss) is an int, so start 4 bytes above it.
|
// _ezero (same as _ebss) is an int, so start 4 bytes above it.
|
||||||
|
@ -186,11 +197,15 @@ STATIC void start_mp(supervisor_allocation *heap, supervisor_allocation *pystack
|
||||||
readline_init0();
|
readline_init0();
|
||||||
|
|
||||||
#if MICROPY_ENABLE_PYSTACK
|
#if MICROPY_ENABLE_PYSTACK
|
||||||
mp_pystack_init(pystack->ptr, pystack->ptr + get_allocation_length(pystack) / sizeof(size_t));
|
size_t pystack_size = 0;
|
||||||
|
_pystack = _allocate_memory(safe_mode, "CIRCUITPY_PYSTACK_SIZE", CIRCUITPY_PYSTACK_SIZE, &pystack_size);
|
||||||
|
mp_pystack_init(_pystack, _pystack + pystack_size / sizeof(size_t));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MICROPY_ENABLE_GC
|
#if MICROPY_ENABLE_GC
|
||||||
gc_init(heap->ptr, heap->ptr + get_allocation_length(heap) / 4);
|
size_t heap_size = 0;
|
||||||
|
_heap = _allocate_memory(safe_mode, "CIRCUITPY_HEAP_START_SIZE", CIRCUITPY_HEAP_START_SIZE, &heap_size);
|
||||||
|
gc_init(_heap, _heap + heap_size / 4);
|
||||||
#endif
|
#endif
|
||||||
mp_init();
|
mp_init();
|
||||||
mp_obj_list_init((mp_obj_list_t *)mp_sys_path, 0);
|
mp_obj_list_init((mp_obj_list_t *)mp_sys_path, 0);
|
||||||
|
@ -227,6 +242,13 @@ STATIC void stop_mp(void) {
|
||||||
qstr_reset();
|
qstr_reset();
|
||||||
|
|
||||||
gc_deinit();
|
gc_deinit();
|
||||||
|
port_free(_heap);
|
||||||
|
_heap = NULL;
|
||||||
|
|
||||||
|
#if MICROPY_ENABLE_PYSTACK
|
||||||
|
port_free(_pystack);
|
||||||
|
_pystack = NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC const char *_current_executing_filename = NULL;
|
STATIC const char *_current_executing_filename = NULL;
|
||||||
|
@ -300,33 +322,34 @@ STATIC void count_strn(void *data, const char *str, size_t len) {
|
||||||
*(size_t *)data += len;
|
*(size_t *)data += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void cleanup_after_vm(supervisor_allocation *heap, supervisor_allocation *pystack, mp_obj_t exception) {
|
STATIC void cleanup_after_vm(mp_obj_t exception) {
|
||||||
// Get the traceback of any exception from this run off the heap.
|
// Get the traceback of any exception from this run off the heap.
|
||||||
// MP_OBJ_SENTINEL means "this run does not contribute to traceback storage, don't touch it"
|
// MP_OBJ_SENTINEL means "this run does not contribute to traceback storage, don't touch it"
|
||||||
// MP_OBJ_NULL (=0) means "this run completed successfully, clear any stored traceback"
|
// MP_OBJ_NULL (=0) means "this run completed successfully, clear any stored traceback"
|
||||||
if (exception != MP_OBJ_SENTINEL) {
|
if (exception != MP_OBJ_SENTINEL) {
|
||||||
free_memory(prev_traceback_allocation);
|
if (prev_traceback_string != NULL) {
|
||||||
|
port_free(prev_traceback_string);
|
||||||
|
prev_traceback_string = NULL;
|
||||||
|
}
|
||||||
// ReloadException is exempt from traceback printing in pyexec_file(), so treat it as "no
|
// ReloadException is exempt from traceback printing in pyexec_file(), so treat it as "no
|
||||||
// traceback" here too.
|
// traceback" here too.
|
||||||
if (exception && exception != MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
|
if (exception && exception != MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
|
||||||
size_t traceback_len = 0;
|
size_t traceback_len = 0;
|
||||||
mp_print_t print_count = {&traceback_len, count_strn};
|
mp_print_t print_count = {&traceback_len, count_strn};
|
||||||
mp_obj_print_exception(&print_count, exception);
|
mp_obj_print_exception(&print_count, exception);
|
||||||
prev_traceback_allocation = allocate_memory(align32_size(traceback_len + 1), false, true);
|
prev_traceback_string = (char *)port_malloc(traceback_len + 1, false);
|
||||||
// Empirically, this never fails in practice - even when the heap is totally filled up
|
// Empirically, this never fails in practice - even when the heap is totally filled up
|
||||||
// with single-block-sized objects referenced by a root pointer, exiting the VM frees
|
// with single-block-sized objects referenced by a root pointer, exiting the VM frees
|
||||||
// up several hundred bytes, sufficient for the traceback (which tends to be shortened
|
// up several hundred bytes, sufficient for the traceback (which tends to be shortened
|
||||||
// because there wasn't memory for the full one). There may be convoluted ways of
|
// because there wasn't memory for the full one). There may be convoluted ways of
|
||||||
// making it fail, but at this point I believe they are not worth spending code on.
|
// making it fail, but at this point I believe they are not worth spending code on.
|
||||||
if (prev_traceback_allocation != NULL) {
|
if (prev_traceback_string != NULL) {
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_fixed_buf(&vstr, traceback_len, (char *)prev_traceback_allocation->ptr);
|
vstr_init_fixed_buf(&vstr, traceback_len, prev_traceback_string);
|
||||||
mp_print_t print = {&vstr, (mp_print_strn_t)vstr_add_strn};
|
mp_print_t print = {&vstr, (mp_print_strn_t)vstr_add_strn};
|
||||||
mp_obj_print_exception(&print, exception);
|
mp_obj_print_exception(&print, exception);
|
||||||
((char *)prev_traceback_allocation->ptr)[traceback_len] = '\0';
|
prev_traceback_string[traceback_len] = '\0';
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
prev_traceback_allocation = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,11 +403,6 @@ STATIC void cleanup_after_vm(supervisor_allocation *heap, supervisor_allocation
|
||||||
// Free the heap last because other modules may reference heap memory and need to shut down.
|
// Free the heap last because other modules may reference heap memory and need to shut down.
|
||||||
filesystem_flush();
|
filesystem_flush();
|
||||||
stop_mp();
|
stop_mp();
|
||||||
free_memory(heap);
|
|
||||||
#if MICROPY_ENABLE_PYSTACK
|
|
||||||
free_memory(pystack);
|
|
||||||
#endif
|
|
||||||
supervisor_move_memory();
|
|
||||||
|
|
||||||
// Let the workflows know we've reset in case they want to restart.
|
// Let the workflows know we've reset in case they want to restart.
|
||||||
supervisor_workflow_reset();
|
supervisor_workflow_reset();
|
||||||
|
@ -424,7 +442,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
|
||||||
// Do the filesystem flush check before reload in case another write comes
|
// Do the filesystem flush check before reload in case another write comes
|
||||||
// in while we're doing the flush.
|
// in while we're doing the flush.
|
||||||
if (safe_mode == SAFE_MODE_NONE) {
|
if (safe_mode == SAFE_MODE_NONE) {
|
||||||
stack_resize();
|
|
||||||
filesystem_flush();
|
filesystem_flush();
|
||||||
}
|
}
|
||||||
if (safe_mode == SAFE_MODE_NONE && !autoreload_pending()) {
|
if (safe_mode == SAFE_MODE_NONE && !autoreload_pending()) {
|
||||||
|
@ -438,12 +455,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
supervisor_allocation *pystack = NULL;
|
start_mp(safe_mode);
|
||||||
#if MICROPY_ENABLE_PYSTACK
|
|
||||||
pystack = allocate_pystack(safe_mode);
|
|
||||||
#endif
|
|
||||||
supervisor_allocation *heap = allocate_remaining_memory();
|
|
||||||
start_mp(heap, pystack);
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB
|
#if CIRCUITPY_USB
|
||||||
usb_setup_with_vm();
|
usb_setup_with_vm();
|
||||||
|
@ -453,16 +465,15 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
|
||||||
common_hal_os_chdir("/");
|
common_hal_os_chdir("/");
|
||||||
|
|
||||||
// Check if a different run file has been allocated
|
// Check if a different run file has been allocated
|
||||||
if (next_code_allocation) {
|
if (next_code_configuration != NULL) {
|
||||||
next_code_info_t *info = ((next_code_info_t *)next_code_allocation->ptr);
|
next_code_configuration->options &= ~SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
|
||||||
info->options &= ~SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
|
next_code_options = next_code_configuration->options;
|
||||||
next_code_options = info->options;
|
if (next_code_configuration->filename[0] != '\0') {
|
||||||
if (info->filename[0] != '\0') {
|
|
||||||
// This is where the user's python code is actually executed:
|
// This is where the user's python code is actually executed:
|
||||||
const char *const filenames[] = { info->filename };
|
const char *const filenames[] = { next_code_configuration->filename };
|
||||||
found_main = maybe_run_list(filenames, MP_ARRAY_SIZE(filenames));
|
found_main = maybe_run_list(filenames, MP_ARRAY_SIZE(filenames));
|
||||||
if (!found_main) {
|
if (!found_main) {
|
||||||
serial_write(info->filename);
|
serial_write(next_code_configuration->filename);
|
||||||
serial_write_compressed(MP_ERROR_TEXT(" not found.\n"));
|
serial_write_compressed(MP_ERROR_TEXT(" not found.\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,16 +505,16 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
|
||||||
|
|
||||||
|
|
||||||
// Finished executing python code. Cleanup includes filesystem flush and a board reset.
|
// Finished executing python code. Cleanup includes filesystem flush and a board reset.
|
||||||
cleanup_after_vm(heap, pystack, _exec_result.exception);
|
cleanup_after_vm(_exec_result.exception);
|
||||||
_exec_result.exception = NULL;
|
_exec_result.exception = NULL;
|
||||||
|
|
||||||
// If a new next code file was set, that is a reason to keep it (obviously). Stuff this into
|
// If a new next code file was set, that is a reason to keep it (obviously). Stuff this into
|
||||||
// the options because it can be treated like any other reason-for-stickiness bit. The
|
// the options because it can be treated like any other reason-for-stickiness bit. The
|
||||||
// source is different though: it comes from the options that will apply to the next run,
|
// source is different though: it comes from the options that will apply to the next run,
|
||||||
// while the rest of next_code_options is what applied to this run.
|
// while the rest of next_code_options is what applied to this run.
|
||||||
if (next_code_allocation != NULL &&
|
if (next_code_configuration != NULL &&
|
||||||
(((next_code_info_t *)next_code_allocation->ptr)->options & SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET)) {
|
next_code_configuration->options & SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET) {
|
||||||
next_code_options |= SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
|
next_code_configuration->options |= SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_exec_result.return_code & PYEXEC_RELOAD) {
|
if (_exec_result.return_code & PYEXEC_RELOAD) {
|
||||||
|
@ -757,9 +768,9 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// free code allocation if unused
|
// free code allocation if unused
|
||||||
if ((next_code_options & next_code_stickiness_situation) == 0) {
|
if (next_code_configuration != NULL && (next_code_configuration->options & next_code_stickiness_situation) == 0) {
|
||||||
free_memory(next_code_allocation);
|
port_free(next_code_configuration);
|
||||||
next_code_allocation = NULL;
|
next_code_configuration = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CIRCUITPY_STATUS_LED
|
#if CIRCUITPY_STATUS_LED
|
||||||
|
@ -791,12 +802,7 @@ STATIC void __attribute__ ((noinline)) run_safemode_py(safe_mode_t safe_mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
supervisor_allocation *pystack = NULL;
|
start_mp(safe_mode);
|
||||||
#if MICROPY_ENABLE_PYSTACK
|
|
||||||
pystack = allocate_pystack(safe_mode);
|
|
||||||
#endif
|
|
||||||
supervisor_allocation *heap = allocate_remaining_memory();
|
|
||||||
start_mp(heap, pystack);
|
|
||||||
|
|
||||||
static const char *const safemode_py_filenames[] = {"safemode.py", "safemode.txt"};
|
static const char *const safemode_py_filenames[] = {"safemode.py", "safemode.txt"};
|
||||||
maybe_run_list(safemode_py_filenames, MP_ARRAY_SIZE(safemode_py_filenames));
|
maybe_run_list(safemode_py_filenames, MP_ARRAY_SIZE(safemode_py_filenames));
|
||||||
|
@ -807,7 +813,7 @@ STATIC void __attribute__ ((noinline)) run_safemode_py(safe_mode_t safe_mode) {
|
||||||
set_safe_mode(SAFE_MODE_SAFEMODE_PY_ERROR);
|
set_safe_mode(SAFE_MODE_SAFEMODE_PY_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup_after_vm(heap, pystack, _exec_result.exception);
|
cleanup_after_vm(_exec_result.exception);
|
||||||
_exec_result.exception = NULL;
|
_exec_result.exception = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -828,12 +834,7 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
|
||||||
|
|
||||||
// Do USB setup even if boot.py is not run.
|
// Do USB setup even if boot.py is not run.
|
||||||
|
|
||||||
supervisor_allocation *pystack = NULL;
|
start_mp(safe_mode);
|
||||||
#if MICROPY_ENABLE_PYSTACK
|
|
||||||
pystack = allocate_pystack(safe_mode);
|
|
||||||
#endif
|
|
||||||
supervisor_allocation *heap = allocate_remaining_memory();
|
|
||||||
start_mp(heap, pystack);
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB
|
#if CIRCUITPY_USB
|
||||||
// Set up default USB values after boot.py VM starts but before running boot.py.
|
// Set up default USB values after boot.py VM starts but before running boot.py.
|
||||||
|
@ -906,40 +907,19 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CIRCUITPY_USB
|
|
||||||
// Some data needs to be carried over from the USB settings in boot.py
|
|
||||||
// to the next VM, while the heap is still available.
|
|
||||||
// Its size can vary, so save it temporarily on the stack,
|
|
||||||
// and then when the heap goes away, copy it in into a
|
|
||||||
// storage_allocation.
|
|
||||||
size_t size = usb_boot_py_data_size();
|
|
||||||
uint8_t usb_boot_py_data[size];
|
|
||||||
usb_get_boot_py_data(usb_boot_py_data, size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
port_post_boot_py(true);
|
port_post_boot_py(true);
|
||||||
|
|
||||||
cleanup_after_vm(heap, pystack, _exec_result.exception);
|
cleanup_after_vm(_exec_result.exception);
|
||||||
_exec_result.exception = NULL;
|
_exec_result.exception = NULL;
|
||||||
|
|
||||||
port_post_boot_py(false);
|
port_post_boot_py(false);
|
||||||
|
|
||||||
#if CIRCUITPY_USB
|
|
||||||
// Now give back the data we saved from the heap going away.
|
|
||||||
usb_return_boot_py_data(usb_boot_py_data, size);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int run_repl(safe_mode_t safe_mode) {
|
STATIC int run_repl(safe_mode_t safe_mode) {
|
||||||
int exit_code = PYEXEC_FORCED_EXIT;
|
int exit_code = PYEXEC_FORCED_EXIT;
|
||||||
stack_resize();
|
|
||||||
filesystem_flush();
|
filesystem_flush();
|
||||||
supervisor_allocation *pystack = NULL;
|
|
||||||
#if MICROPY_ENABLE_PYSTACK
|
start_mp(safe_mode);
|
||||||
pystack = allocate_pystack(safe_mode);
|
|
||||||
#endif
|
|
||||||
supervisor_allocation *heap = allocate_remaining_memory();
|
|
||||||
start_mp(heap, pystack);
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB
|
#if CIRCUITPY_USB
|
||||||
usb_setup_with_vm();
|
usb_setup_with_vm();
|
||||||
|
@ -987,7 +967,7 @@ STATIC int run_repl(safe_mode_t safe_mode) {
|
||||||
exit_code = PYEXEC_DEEP_SLEEP;
|
exit_code = PYEXEC_DEEP_SLEEP;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
cleanup_after_vm(heap, pystack, MP_OBJ_SENTINEL);
|
cleanup_after_vm(MP_OBJ_SENTINEL);
|
||||||
|
|
||||||
// Also reset bleio. The above call omits it in case workflows should continue. In this case,
|
// Also reset bleio. The above call omits it in case workflows should continue. In this case,
|
||||||
// we're switching straight to another VM so we want to reset.
|
// we're switching straight to another VM so we want to reset.
|
||||||
|
@ -1010,6 +990,8 @@ int __attribute__((used)) main(void) {
|
||||||
// initialise the cpu and peripherals
|
// initialise the cpu and peripherals
|
||||||
set_safe_mode(port_init());
|
set_safe_mode(port_init());
|
||||||
|
|
||||||
|
port_heap_init();
|
||||||
|
|
||||||
// Turn on RX and TX LEDs if we have them.
|
// Turn on RX and TX LEDs if we have them.
|
||||||
init_rxtx_leds();
|
init_rxtx_leds();
|
||||||
|
|
||||||
|
@ -1055,10 +1037,6 @@ int __attribute__((used)) main(void) {
|
||||||
set_safe_mode(SAFE_MODE_NO_CIRCUITPY);
|
set_safe_mode(SAFE_MODE_NO_CIRCUITPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We maybe can't initialize the heap until here, because on espressif port we need to be able to check for reserved psram in settings.toml
|
|
||||||
// (but it's OK if this is a no-op due to the heap being initialized in port_init())
|
|
||||||
set_safe_mode(port_heap_init(get_safe_mode()));
|
|
||||||
|
|
||||||
#if CIRCUITPY_ALARM
|
#if CIRCUITPY_ALARM
|
||||||
// Record which alarm woke us up, if any.
|
// Record which alarm woke us up, if any.
|
||||||
// common_hal_alarm_record_wake_alarm() should return a static, non-heap object
|
// common_hal_alarm_record_wake_alarm() should return a static, non-heap object
|
||||||
|
@ -1188,11 +1166,8 @@ void gc_collect(void) {
|
||||||
MP_WEAK void port_gc_collect() {
|
MP_WEAK void port_gc_collect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A port may initialize the heap in port_init but if it cannot (for instance
|
size_t gc_get_max_new_split(void) {
|
||||||
// in espressif it must be done after CIRCUITPY is mounted) then it must provde
|
return port_heap_get_largest_free_size();
|
||||||
// an implementation of this function.
|
|
||||||
MP_WEAK safe_mode_t port_heap_init(safe_mode_t safe_mode_in) {
|
|
||||||
return safe_mode_in;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NORETURN nlr_jump_fail(void *val) {
|
void NORETURN nlr_jump_fail(void *val) {
|
||||||
|
|
|
@ -176,7 +176,10 @@ ifeq ($(GCC_VERSION_GTEQ_11),1)
|
||||||
CFLAGS += -Wno-stringop-overread -Wno-stringop-overflow
|
CFLAGS += -Wno-stringop-overread -Wno-stringop-overflow
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LDFLAGS = $(CFLAGS) -nostartfiles -Wl,-nostdlib -Wl,-T,$(GENERATED_LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nano.specs
|
# Somehow the lto doesn't know it needs __ffssi2 until it is too late. (Maybe
|
||||||
|
# because the code uses __builtin_ffs().) So, explicitly say we'll need it up
|
||||||
|
# front. -u is to say a symbol is undefined from the start.
|
||||||
|
LDFLAGS = $(CFLAGS) -u __ffssi2 -nostartfiles -Wl,-nostdlib -Wl,-T,$(GENERATED_LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nano.specs
|
||||||
|
|
||||||
# Use toolchain libm if we're not using our own.
|
# Use toolchain libm if we're not using our own.
|
||||||
ifndef INTERNAL_LIBM
|
ifndef INTERNAL_LIBM
|
||||||
|
@ -302,6 +305,8 @@ SRC_C += \
|
||||||
timer_handler.c \
|
timer_handler.c \
|
||||||
$(SRC_PERIPHERALS) \
|
$(SRC_PERIPHERALS) \
|
||||||
|
|
||||||
|
$(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align
|
||||||
|
|
||||||
$(BUILD)/lib/tinyusb/src/portable/microchip/samd/dcd_samd.o: CFLAGS += -Wno-missing-prototypes
|
$(BUILD)/lib/tinyusb/src/portable/microchip/samd/dcd_samd.o: CFLAGS += -Wno-missing-prototypes
|
||||||
|
|
||||||
# This is an OR because it filters to any 1s and then checks to see if it is not
|
# This is an OR because it filters to any 1s and then checks to see if it is not
|
||||||
|
|
|
@ -95,13 +95,5 @@ SECTIONS
|
||||||
_ebss = .;
|
_ebss = .;
|
||||||
} >RAM
|
} >RAM
|
||||||
|
|
||||||
/* this just checks there is enough RAM for the requested stack. */
|
|
||||||
.stack (NOLOAD) :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
. = . + ${CIRCUITPY_DEFAULT_STACK_SIZE};
|
|
||||||
. = ALIGN(4);
|
|
||||||
} >RAM
|
|
||||||
|
|
||||||
.ARM.attributes 0 : { *(.ARM.attributes) }
|
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#define MICROPY_HW_NEOPIXEL (&pin_PA30)
|
#define MICROPY_HW_NEOPIXEL (&pin_PA30)
|
||||||
|
|
||||||
// Clock rates are off: Salae reads 12MHz which is the limit even though we set it to the safer 8MHz.
|
// Clock rates are off: Saleae reads 12MHz which is the limit even though we set it to the safer 8MHz.
|
||||||
#define SPI_FLASH_BAUDRATE (8000000)
|
#define SPI_FLASH_BAUDRATE (8000000)
|
||||||
|
|
||||||
#define SPI_FLASH_MOSI_PIN &pin_PB22
|
#define SPI_FLASH_MOSI_PIN &pin_PB22
|
||||||
|
|
|
@ -477,24 +477,21 @@ void reset_cpu(void) {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
return &_ebss;
|
return port_stack_get_top() - (CIRCUITPY_DEFAULT_STACK_SIZE + CIRCUITPY_EXCEPTION_STACK_SIZE) / sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_top(void) {
|
uint32_t *port_stack_get_top(void) {
|
||||||
return &_estack;
|
return &_estack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for the shared heap allocator.
|
||||||
uint32_t *port_heap_get_bottom(void) {
|
uint32_t *port_heap_get_bottom(void) {
|
||||||
return port_stack_get_limit();
|
return &_ebss;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_top(void) {
|
uint32_t *port_heap_get_top(void) {
|
||||||
return port_stack_get_top();
|
return port_stack_get_limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place the word to save 8k from the end of RAM so we and the bootloader don't clobber it.
|
// Place the word to save 8k from the end of RAM so we and the bootloader don't clobber it.
|
||||||
|
|
|
@ -127,6 +127,7 @@ endif
|
||||||
|
|
||||||
CFLAGS += $(INC) -Wall -Werror -std=gnu11 $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS)
|
CFLAGS += $(INC) -Wall -Werror -std=gnu11 $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS)
|
||||||
|
|
||||||
|
$(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align
|
||||||
|
|
||||||
SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) $(SRC_CIRCUITPY_COMMON)
|
SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) $(SRC_CIRCUITPY_COMMON)
|
||||||
|
|
||||||
|
|
|
@ -123,10 +123,6 @@ void reset_cpu(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From the linker script
|
// From the linker script
|
||||||
extern uint32_t __bss_end;
|
extern uint32_t __bss_end;
|
||||||
extern uint32_t _ld_ram_end;
|
extern uint32_t _ld_ram_end;
|
||||||
|
|
|
@ -104,10 +104,6 @@ void reset_to_bootloader(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
struct tcb_s *rtcb = this_task();
|
struct tcb_s *rtcb = this_task();
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,8 @@ else ifeq ($(IDF_TARGET_ARCH),riscv)
|
||||||
CFLAGS += -march=rv32imac_zicsr_zifencei
|
CFLAGS += -march=rv32imac_zicsr_zifencei
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
$(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align
|
||||||
|
|
||||||
LDFLAGS = $(CFLAGS) -Wl,-nostdlib -Wl,-Map=$@.map -Wl,-cref -Wl,--undefined=uxTopUsedPriority
|
LDFLAGS = $(CFLAGS) -Wl,-nostdlib -Wl,-Map=$@.map -Wl,-cref -Wl,--undefined=uxTopUsedPriority
|
||||||
|
|
||||||
LDFLAGS += \
|
LDFLAGS += \
|
||||||
|
|
|
@ -141,14 +141,6 @@ STATIC mp_obj_t espidf_get_total_psram(void) {
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_0(espidf_get_total_psram_obj, espidf_get_total_psram);
|
MP_DEFINE_CONST_FUN_OBJ_0(espidf_get_total_psram_obj, espidf_get_total_psram);
|
||||||
|
|
||||||
//| def get_reserved_psram() -> int:
|
|
||||||
//| """Returns number of bytes of psram reserved for use by esp-idf, either a board-specific default value or the value defined in ``settings.toml``."""
|
|
||||||
//|
|
|
||||||
STATIC mp_obj_t espidf_get_reserved_psram(void) {
|
|
||||||
return MP_OBJ_NEW_SMALL_INT(common_hal_espidf_get_reserved_psram());
|
|
||||||
}
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_0(espidf_get_reserved_psram_obj, espidf_get_reserved_psram);
|
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t espidf_module_globals_table[] = {
|
STATIC const mp_rom_map_elem_t espidf_module_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espidf) },
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espidf) },
|
||||||
|
|
||||||
|
@ -159,7 +151,6 @@ STATIC const mp_rom_map_elem_t espidf_module_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_erase_nvs), MP_ROM_PTR(&espidf_erase_nvs_obj)},
|
{ MP_ROM_QSTR(MP_QSTR_erase_nvs), MP_ROM_PTR(&espidf_erase_nvs_obj)},
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_get_total_psram), MP_ROM_PTR(&espidf_get_total_psram_obj)},
|
{ MP_ROM_QSTR(MP_QSTR_get_total_psram), MP_ROM_PTR(&espidf_get_total_psram_obj)},
|
||||||
{ MP_ROM_QSTR(MP_QSTR_get_reserved_psram), MP_ROM_PTR(&espidf_get_reserved_psram_obj)},
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_IDFError), MP_ROM_PTR(&mp_type_espidf_IDFError) },
|
{ MP_ROM_QSTR(MP_QSTR_IDFError), MP_ROM_PTR(&mp_type_espidf_IDFError) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_espidf_MemoryError) },
|
{ MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_espidf_MemoryError) },
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,7 +49,7 @@ void ble_event_remove_heap_handlers(void) {
|
||||||
ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries);
|
ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries);
|
||||||
while (it != NULL) {
|
while (it != NULL) {
|
||||||
// If the param is on the heap, then delete the handler.
|
// If the param is on the heap, then delete the handler.
|
||||||
if (HEAP_PTR(it->param)) {
|
if (gc_ptr_on_heap(it->param)) {
|
||||||
ble_event_remove_handler(it->func, it->param);
|
ble_event_remove_handler(it->func, it->param);
|
||||||
}
|
}
|
||||||
it = it->next;
|
it = it->next;
|
||||||
|
|
|
@ -77,10 +77,6 @@ void common_hal_espcamera_camera_construct(
|
||||||
mp_int_t framebuffer_count,
|
mp_int_t framebuffer_count,
|
||||||
camera_grab_mode_t grab_mode) {
|
camera_grab_mode_t grab_mode) {
|
||||||
|
|
||||||
if (common_hal_espidf_get_reserved_psram() == 0) {
|
|
||||||
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT(
|
|
||||||
"espcamera.Camera requires reserved PSRAM to be configured. See the documentation for instructions."));
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
claim_pin_number(data_pins[i]);
|
claim_pin_number(data_pins[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "bindings/espidf/__init__.h"
|
#include "bindings/espidf/__init__.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
|
||||||
#include "esp_now.h"
|
#include "esp_now.h"
|
||||||
|
@ -71,36 +70,6 @@ bool common_hal_espidf_set_reserved_psram(size_t amount) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
supervisor_allocation *psram_for_idf;
|
|
||||||
|
|
||||||
void common_hal_espidf_reserve_psram(void) {
|
|
||||||
#ifdef CONFIG_SPIRAM_USE_MEMMAP
|
|
||||||
if (!psram_for_idf) {
|
|
||||||
ESP_LOGI(TAG, "Reserving %d bytes of psram", reserved_psram);
|
|
||||||
if (reserved_psram == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
psram_for_idf = allocate_memory(reserved_psram, true, false);
|
|
||||||
if (psram_for_idf) {
|
|
||||||
intptr_t psram_for_idf_start = (intptr_t)psram_for_idf->ptr;
|
|
||||||
intptr_t psram_for_idf_end = psram_for_idf_start + reserved_psram;
|
|
||||||
ESP_LOGI(TAG, "Reserved %x..%x", psram_for_idf_start, psram_for_idf_end);
|
|
||||||
heap_caps_add_region(psram_for_idf_start, psram_for_idf_end);
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "supervisor allocation failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t common_hal_espidf_get_reserved_psram(void) {
|
|
||||||
#ifdef CONFIG_SPIRAM
|
|
||||||
return reserved_psram;
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t common_hal_espidf_get_total_psram(void) {
|
size_t common_hal_espidf_get_total_psram(void) {
|
||||||
return psram_size_usable();
|
return psram_size_usable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,6 @@
|
||||||
# ESP PSRAM
|
# ESP PSRAM
|
||||||
#
|
#
|
||||||
CONFIG_SPIRAM=y
|
CONFIG_SPIRAM=y
|
||||||
#
|
|
||||||
# SPI RAM config
|
|
||||||
#
|
|
||||||
CONFIG_SPIRAM_USE_MEMMAP=y
|
|
||||||
# end of SPI RAM config
|
|
||||||
|
|
||||||
# end of ESP PSRAM
|
# end of ESP PSRAM
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -55,7 +55,6 @@
|
||||||
#include "common-hal/socketpool/Socket.h"
|
#include "common-hal/socketpool/Socket.h"
|
||||||
#include "common-hal/wifi/__init__.h"
|
#include "common-hal/wifi/__init__.h"
|
||||||
#include "supervisor/background_callback.h"
|
#include "supervisor/background_callback.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "supervisor/shared/tick.h"
|
#include "supervisor/shared/tick.h"
|
||||||
#include "shared-bindings/microcontroller/__init__.h"
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
#include "shared-bindings/microcontroller/RunMode.h"
|
#include "shared-bindings/microcontroller/RunMode.h"
|
||||||
|
@ -321,55 +320,29 @@ safe_mode_t port_init(void) {
|
||||||
return SAFE_MODE_NONE;
|
return SAFE_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
safe_mode_t port_heap_init(safe_mode_t sm) {
|
void port_heap_init(void) {
|
||||||
mp_int_t reserved = 0;
|
// The IDF sets up the heap, so we don't need to.
|
||||||
if (filesystem_present() && common_hal_os_getenv_int("CIRCUITPY_RESERVED_PSRAM", &reserved) == GETENV_OK) {
|
}
|
||||||
common_hal_espidf_set_reserved_psram(reserved);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_SPIRAM_USE_MEMMAP)
|
void *port_malloc(size_t size, bool dma_capable) {
|
||||||
{
|
size_t caps = MALLOC_CAP_8BIT;
|
||||||
intptr_t heap_start = common_hal_espidf_get_psram_start();
|
if (dma_capable) {
|
||||||
intptr_t heap_end = common_hal_espidf_get_psram_end();
|
caps |= MALLOC_CAP_DMA;
|
||||||
size_t spiram_size = heap_end - heap_start;
|
|
||||||
if (spiram_size > 0) {
|
|
||||||
heap = (uint32_t *)heap_start;
|
|
||||||
heap_size = (heap_end - heap_start) / sizeof(uint32_t);
|
|
||||||
common_hal_espidf_reserve_psram();
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "CONFIG_SPIRAM_USE_MMAP enabled but no spiram heap available");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#elif defined(CONFIG_SPIRAM_USE_CAPS_ALLOC)
|
return heap_caps_malloc(size, caps);
|
||||||
{
|
}
|
||||||
intptr_t psram_start = common_hal_espidf_get_psram_start();
|
|
||||||
intptr_t psram_end = common_hal_espidf_get_psram_end();
|
|
||||||
size_t psram_amount = psram_end - psram_start;
|
|
||||||
size_t biggest_block = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
|
|
||||||
size_t try_alloc = MIN(biggest_block, psram_amount - common_hal_espidf_get_reserved_psram());
|
|
||||||
heap = heap_caps_malloc(try_alloc, MALLOC_CAP_SPIRAM);
|
|
||||||
|
|
||||||
if (heap) {
|
void port_free(void *ptr) {
|
||||||
heap_size = try_alloc;
|
heap_caps_free(ptr);
|
||||||
} else {
|
}
|
||||||
ESP_LOGE(TAG, "CONFIG_SPIRAM_USE_CAPS_ALLOC but no spiram heap available");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (heap == NULL) {
|
void port_realloc(void *ptr, size_t size) {
|
||||||
size_t heap_total = heap_caps_get_total_size(MALLOC_CAP_8BIT);
|
heap_caps_realloc(ptr, size, MALLOC_CAP_8BIT);
|
||||||
heap_size = MIN(heap_caps_get_largest_free_block(MALLOC_CAP_8BIT), heap_total / 2);
|
}
|
||||||
heap = malloc(heap_size);
|
|
||||||
heap_size = heap_size / sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
if (heap == NULL) {
|
|
||||||
heap_size = 0;
|
|
||||||
return SAFE_MODE_NO_HEAP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sm;
|
|
||||||
|
|
||||||
|
size_t port_heap_get_largest_free_size(void) {
|
||||||
|
size_t free_size = heap_caps_get_largest_free_block(0);
|
||||||
|
return free_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_port(void) {
|
void reset_port(void) {
|
||||||
|
@ -455,14 +428,6 @@ void reset_cpu(void) {
|
||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_bottom(void) {
|
|
||||||
return heap;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *port_heap_get_top(void) {
|
|
||||||
return heap + heap_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||||
|
@ -485,10 +450,6 @@ uint32_t *port_stack_get_top(void) {
|
||||||
return port_stack_get_limit() + ESP_TASK_MAIN_STACK / (sizeof(uint32_t) / sizeof(StackType_t));
|
return port_stack_get_limit() + ESP_TASK_MAIN_STACK / (sizeof(uint32_t) / sizeof(StackType_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void port_set_saved_word(uint32_t value) {
|
void port_set_saved_word(uint32_t value) {
|
||||||
REG_WRITE(CP_SAVED_WORD_REGISTER, value);
|
REG_WRITE(CP_SAVED_WORD_REGISTER, value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE))
|
||||||
$(addprefix shared-module/, $(SRC_SHARED_MODULE)) \
|
$(addprefix shared-module/, $(SRC_SHARED_MODULE)) \
|
||||||
$(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL))
|
$(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL))
|
||||||
|
|
||||||
|
$(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align
|
||||||
|
|
||||||
ifneq ($(FROZEN_MPY_DIR),)
|
ifneq ($(FROZEN_MPY_DIR),)
|
||||||
FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py')
|
FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py')
|
||||||
|
|
|
@ -101,20 +101,19 @@ void reset_cpu(void) {
|
||||||
for (;;) {}
|
for (;;) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *port_heap_get_bottom(void) {
|
uint32_t *port_heap_get_bottom(void) {
|
||||||
return port_stack_get_limit();
|
return &_ebss;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_top(void) {
|
uint32_t *port_heap_get_top(void) {
|
||||||
return port_stack_get_top();
|
return port_stack_get_limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
return &_ebss;
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||||
|
return port_stack_get_top() - (CIRCUITPY_DEFAULT_STACK_SIZE + CIRCUITPY_EXCEPTION_STACK_SIZE) / sizeof(uint32_t);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_top(void) {
|
uint32_t *port_stack_get_top(void) {
|
||||||
|
|
|
@ -89,6 +89,8 @@ ifeq ($(CIRCUITPY_SWO_TRACE), 1)
|
||||||
CFLAGS += -finstrument-functions -finstrument-functions-exclude-file-list=tinyusb -finstrument-functions-exclude-function-list='USB_OTG1_IRQHandler,usb_irq_handler,nlr_push,CLOCK_EnableClock,CLOCK_SetDiv,CLOCK_SetMux,__DMB,__ISB,__DSB,SCB_EnableICache,SCB_EnableDCache,ARM_MPU_Disable,ARM_MPU_Enable,SCB_DisableDCache,SCB_DisableICache,__enable_irq,__disable_irq,__set_MSP,port_get_raw_ticks,supervisor_ticks_ms64'
|
CFLAGS += -finstrument-functions -finstrument-functions-exclude-file-list=tinyusb -finstrument-functions-exclude-function-list='USB_OTG1_IRQHandler,usb_irq_handler,nlr_push,CLOCK_EnableClock,CLOCK_SetDiv,CLOCK_SetMux,__DMB,__ISB,__DSB,SCB_EnableICache,SCB_EnableDCache,ARM_MPU_Disable,ARM_MPU_Enable,SCB_DisableDCache,SCB_DisableICache,__enable_irq,__disable_irq,__set_MSP,port_get_raw_ticks,supervisor_ticks_ms64'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
$(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align
|
||||||
|
|
||||||
LD_FILES = $(wildcard boards/$(BOARD)/*.ld) $(addprefix linking/, flash/$(FLASH).ld chip_family/$(CHIP_FAMILY).ld common.ld)
|
LD_FILES = $(wildcard boards/$(BOARD)/*.ld) $(addprefix linking/, flash/$(FLASH).ld chip_family/$(CHIP_FAMILY).ld common.ld)
|
||||||
|
|
||||||
LD_SCRIPT_FLAG := -Wl,-T,
|
LD_SCRIPT_FLAG := -Wl,-T,
|
||||||
|
|
|
@ -499,10 +499,6 @@ uint32_t *port_stack_get_top(void) {
|
||||||
return &_ld_stack_top;
|
return &_ld_stack_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *port_heap_get_bottom(void) {
|
uint32_t *port_heap_get_bottom(void) {
|
||||||
return &_ld_heap_start;
|
return &_ld_heap_start;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ void ble_drv_remove_heap_handlers(void) {
|
||||||
ble_drv_evt_handler_entry_t *it = MP_STATE_VM(ble_drv_evt_handler_entries);
|
ble_drv_evt_handler_entry_t *it = MP_STATE_VM(ble_drv_evt_handler_entries);
|
||||||
while (it != NULL) {
|
while (it != NULL) {
|
||||||
// If the param is on the heap, then delete the handler.
|
// If the param is on the heap, then delete the handler.
|
||||||
if (HEAP_PTR(it->param)) {
|
if (gc_ptr_on_heap(it->param)) {
|
||||||
ble_drv_remove_event_handler(it->func, it->param);
|
ble_drv_remove_event_handler(it->func, it->param);
|
||||||
}
|
}
|
||||||
it = it->next;
|
it = it->next;
|
||||||
|
|
|
@ -16,3 +16,7 @@ CIRCUITPY_ONEWIREIO = 0
|
||||||
CIRCUITPY_PIXELBUF = 1
|
CIRCUITPY_PIXELBUF = 1
|
||||||
CIRCUITPY_PIXELMAP = 0
|
CIRCUITPY_PIXELMAP = 0
|
||||||
CIRCUITPY_TOUCHIO = 0
|
CIRCUITPY_TOUCHIO = 0
|
||||||
|
|
||||||
|
# Features to disable
|
||||||
|
CIRCUITPY_SAFEMODE_PY = 0
|
||||||
|
CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH = 0
|
||||||
|
|
|
@ -286,15 +286,14 @@ uint32_t *port_heap_get_bottom(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_top(void) {
|
uint32_t *port_heap_get_top(void) {
|
||||||
return port_stack_get_top();
|
return port_stack_get_limit();
|
||||||
}
|
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
return &_euninitialized;
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||||
|
return port_stack_get_top() - (CIRCUITPY_DEFAULT_STACK_SIZE + CIRCUITPY_EXCEPTION_STACK_SIZE) / sizeof(uint32_t);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_top(void) {
|
uint32_t *port_stack_get_top(void) {
|
||||||
|
|
|
@ -173,7 +173,7 @@ endif
|
||||||
# Remove -Wno-stringop-overflow after we can test with CI's GCC 10. Mac's looks weird.
|
# Remove -Wno-stringop-overflow after we can test with CI's GCC 10. Mac's looks weird.
|
||||||
DISABLE_WARNINGS = -Wno-stringop-overflow -Wno-cast-align
|
DISABLE_WARNINGS = -Wno-stringop-overflow -Wno-cast-align
|
||||||
|
|
||||||
CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes
|
CFLAGS += $(INC) -Wall -Werror -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes
|
||||||
|
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-march=armv6-m \
|
-march=armv6-m \
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "shared-bindings/time/__init__.h"
|
#include "shared-bindings/time/__init__.h"
|
||||||
#include "common-hal/pwmio/PWMOut.h"
|
#include "common-hal/pwmio/PWMOut.h"
|
||||||
#include "common-hal/rp2pio/StateMachine.h"
|
#include "common-hal/rp2pio/StateMachine.h"
|
||||||
|
#include "supervisor/port.h"
|
||||||
|
|
||||||
#include "src/common/pico_stdlib/include/pico/stdlib.h"
|
#include "src/common/pico_stdlib/include/pico/stdlib.h"
|
||||||
#include "src/rp2040/hardware_structs/include/hardware/structs/mpu.h"
|
#include "src/rp2040/hardware_structs/include/hardware/structs/mpu.h"
|
||||||
|
@ -123,8 +124,6 @@ static void __not_in_flash_func(core1_scanline_callback)(void) {
|
||||||
self->next_scanline += 1;
|
self->next_scanline += 1;
|
||||||
if (self->next_scanline >= self->height) {
|
if (self->next_scanline >= self->height) {
|
||||||
self->next_scanline = 0;
|
self->next_scanline = 0;
|
||||||
// Update the framebuffer pointer in case it moved.
|
|
||||||
self->framebuffer = self->allocation->ptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,8 +242,8 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
|
||||||
size_t framebuffer_size = self->pitch * self->height;
|
size_t framebuffer_size = self->pitch * self->height;
|
||||||
self->tmdsbuf_size = tmds_bufs_per_scanline * scanline_width / DVI_SYMBOLS_PER_WORD + 1;
|
self->tmdsbuf_size = tmds_bufs_per_scanline * scanline_width / DVI_SYMBOLS_PER_WORD + 1;
|
||||||
size_t total_allocation_size = sizeof(uint32_t) * (framebuffer_size + DVI_N_TMDS_BUFFERS * self->tmdsbuf_size);
|
size_t total_allocation_size = sizeof(uint32_t) * (framebuffer_size + DVI_N_TMDS_BUFFERS * self->tmdsbuf_size);
|
||||||
self->allocation = allocate_memory(total_allocation_size, false, true);
|
self->framebuffer = (uint32_t *)port_malloc(total_allocation_size, true);
|
||||||
if (self->allocation == NULL) {
|
if (self->framebuffer == NULL) {
|
||||||
m_malloc_fail(total_allocation_size);
|
m_malloc_fail(total_allocation_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -270,7 +269,6 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
|
||||||
// For the output.
|
// For the output.
|
||||||
user_irq_claim(DMA_IRQ_1);
|
user_irq_claim(DMA_IRQ_1);
|
||||||
self->framebuffer_len = framebuffer_size;
|
self->framebuffer_len = framebuffer_size;
|
||||||
self->framebuffer = self->allocation->ptr;
|
|
||||||
self->color_depth = color_depth;
|
self->color_depth = color_depth;
|
||||||
|
|
||||||
self->dvi.timing = timing;
|
self->dvi.timing = timing;
|
||||||
|
@ -383,7 +381,7 @@ void common_hal_picodvi_framebuffer_deinit(picodvi_framebuffer_obj_t *self) {
|
||||||
|
|
||||||
active_picodvi = NULL;
|
active_picodvi = NULL;
|
||||||
|
|
||||||
free_memory(self->allocation);
|
port_free(self->framebuffer);
|
||||||
self->framebuffer = NULL;
|
self->framebuffer = NULL;
|
||||||
|
|
||||||
self->base.type = &mp_type_NoneType;
|
self->base.type = &mp_type_NoneType;
|
||||||
|
|
|
@ -28,13 +28,10 @@
|
||||||
|
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
|
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
#include "lib/PicoDVI/software/libdvi/dvi.h"
|
#include "lib/PicoDVI/software/libdvi/dvi.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
supervisor_allocation *allocation;
|
|
||||||
uint32_t *framebuffer;
|
uint32_t *framebuffer;
|
||||||
size_t framebuffer_len; // in words
|
size_t framebuffer_len; // in words
|
||||||
size_t tmdsbuf_size; // in words
|
size_t tmdsbuf_size; // in words
|
||||||
|
|
|
@ -233,15 +233,15 @@ void reset_cpu(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From the linker script
|
// From the linker script
|
||||||
extern uint32_t _ld_cp_dynamic_mem_start;
|
extern uint32_t _ld_cp_dynamic_mem_start;
|
||||||
extern uint32_t _ld_cp_dynamic_mem_end;
|
extern uint32_t _ld_cp_dynamic_mem_end;
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
return &_ld_cp_dynamic_mem_start;
|
#pragma GCC diagnostic push
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||||
|
return port_stack_get_top() - (CIRCUITPY_DEFAULT_STACK_SIZE + CIRCUITPY_EXCEPTION_STACK_SIZE) / sizeof(uint32_t);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_top(void) {
|
uint32_t *port_stack_get_top(void) {
|
||||||
|
@ -249,11 +249,11 @@ uint32_t *port_stack_get_top(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_bottom(void) {
|
uint32_t *port_heap_get_bottom(void) {
|
||||||
return port_stack_get_limit();
|
return &_ld_cp_dynamic_mem_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_top(void) {
|
uint32_t *port_heap_get_top(void) {
|
||||||
return port_stack_get_top();
|
return port_stack_get_limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t __uninitialized_ram(saved_word);
|
uint32_t __uninitialized_ram(saved_word);
|
||||||
|
|
|
@ -218,10 +218,6 @@ uint32_t *port_heap_get_top(void) {
|
||||||
return heap + heap_size;
|
return heap + heap_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include "shared-bindings/audiobusio/PDMIn.h"
|
#include "shared-bindings/audiobusio/PDMIn.h"
|
||||||
#include "shared-bindings/microcontroller/Pin.h"
|
#include "shared-bindings/microcontroller/Pin.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "MEMS_Audio_ll_stm32l4.h"
|
#include "MEMS_Audio_ll_stm32l4.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "peripherals/pins.h"
|
#include "peripherals/pins.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
typedef struct MemsAudio_t MemsAudio;
|
typedef struct MemsAudio_t MemsAudio;
|
||||||
typedef struct MemsAudio_STM32L4SAIPDM_t MemsAudio_STM32L4SAIPDM;
|
typedef struct MemsAudio_STM32L4SAIPDM_t MemsAudio_STM32L4SAIPDM;
|
||||||
|
@ -43,7 +42,6 @@ typedef struct {
|
||||||
uint8_t bit_depth;
|
uint8_t bit_depth;
|
||||||
bool mono;
|
bool mono;
|
||||||
uint8_t oversample;
|
uint8_t oversample;
|
||||||
supervisor_allocation *audio_allocation;
|
|
||||||
MemsAudio *audio;
|
MemsAudio *audio;
|
||||||
MemsAudio_STM32L4SAIPDM *audio_impl;
|
MemsAudio_STM32L4SAIPDM *audio_impl;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -330,15 +330,15 @@ uint32_t *port_heap_get_bottom(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_top(void) {
|
uint32_t *port_heap_get_top(void) {
|
||||||
return &_ld_heap_end;
|
return port_stack_get_limit();
|
||||||
}
|
|
||||||
|
|
||||||
bool port_has_fixed_stack(void) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_limit(void) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
return &_ld_stack_bottom;
|
#pragma GCC diagnostic push
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||||
|
return port_stack_get_top() - (CIRCUITPY_DEFAULT_STACK_SIZE + CIRCUITPY_EXCEPTION_STACK_SIZE) / sizeof(uint32_t);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_top(void) {
|
uint32_t *port_stack_get_top(void) {
|
||||||
|
|
|
@ -779,6 +779,7 @@ SRC_LIBM = \
|
||||||
$(addprefix lib/,\
|
$(addprefix lib/,\
|
||||||
libm/math.c \
|
libm/math.c \
|
||||||
libm/roundf.c \
|
libm/roundf.c \
|
||||||
|
libm/fabsf.c \
|
||||||
libm/fmodf.c \
|
libm/fmodf.c \
|
||||||
libm/nearbyintf.c \
|
libm/nearbyintf.c \
|
||||||
libm/ef_sqrt.c \
|
libm/ef_sqrt.c \
|
||||||
|
|
|
@ -91,6 +91,11 @@ extern void common_hal_mcu_enable_interrupts(void);
|
||||||
#define MICROPY_FLOAT_HIGH_QUALITY_HASH (0)
|
#define MICROPY_FLOAT_HIGH_QUALITY_HASH (0)
|
||||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
||||||
#define MICROPY_GC_ALLOC_THRESHOLD (0)
|
#define MICROPY_GC_ALLOC_THRESHOLD (0)
|
||||||
|
#define MICROPY_GC_SPLIT_HEAP (1)
|
||||||
|
#define MICROPY_GC_SPLIT_HEAP_AUTO (1)
|
||||||
|
#define MP_PLAT_ALLOC_HEAP(size) port_malloc(size, true)
|
||||||
|
#define MP_PLAT_FREE_HEAP(ptr) port_free(ptr)
|
||||||
|
#include "supervisor/port_heap.h"
|
||||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||||
#define MICROPY_HELPER_REPL (1)
|
#define MICROPY_HELPER_REPL (1)
|
||||||
#define MICROPY_KBD_EXCEPTION (1)
|
#define MICROPY_KBD_EXCEPTION (1)
|
||||||
|
@ -155,7 +160,6 @@ extern void common_hal_mcu_enable_interrupts(void);
|
||||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||||
#define MICROPY_REPL_AUTO_INDENT (1)
|
#define MICROPY_REPL_AUTO_INDENT (1)
|
||||||
#define MICROPY_REPL_EVENT_DRIVEN (0)
|
#define MICROPY_REPL_EVENT_DRIVEN (0)
|
||||||
#define CIRCUITPY_SETTABLE_PYSTACK (1)
|
|
||||||
#define MICROPY_STACK_CHECK (1)
|
#define MICROPY_STACK_CHECK (1)
|
||||||
#define MICROPY_STREAMS_NON_BLOCK (1)
|
#define MICROPY_STREAMS_NON_BLOCK (1)
|
||||||
#ifndef MICROPY_USE_INTERNAL_PRINTF
|
#ifndef MICROPY_USE_INTERNAL_PRINTF
|
||||||
|
@ -431,6 +435,18 @@ void background_callback_run_all(void);
|
||||||
#define CIRCUITPY_PYSTACK_SIZE 1536
|
#define CIRCUITPY_PYSTACK_SIZE 1536
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The VM heap starts at this size and doubles in size as needed until it runs
|
||||||
|
// out of memory in the outer heap. Once it can't double, it'll then grow into
|
||||||
|
// the largest contiguous free area.
|
||||||
|
#ifndef CIRCUITPY_HEAP_START_SIZE
|
||||||
|
#define CIRCUITPY_HEAP_START_SIZE (8 * 1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// How much of the c stack we leave to ensure we can process exceptions.
|
||||||
|
#ifndef CIRCUITPY_EXCEPTION_STACK_SIZE
|
||||||
|
#define CIRCUITPY_EXCEPTION_STACK_SIZE 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
// Wait this long before sleeping immediately after startup, to see if we are connected via USB or BLE.
|
// Wait this long before sleeping immediately after startup, to see if we are connected via USB or BLE.
|
||||||
#ifndef CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY
|
#ifndef CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY
|
||||||
#define CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY 5
|
#define CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY 5
|
||||||
|
|
66
py/gc.c
66
py/gc.c
|
@ -338,16 +338,13 @@ STATIC bool gc_try_add_heap(size_t failed_alloc) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !MICROPY_GC_SPLIT_HEAP
|
|
||||||
// CIRCUITPY-CHANGE
|
// CIRCUITPY-CHANGE
|
||||||
// TODO FOR MERGE: fix this for split heap
|
|
||||||
void gc_deinit(void) {
|
void gc_deinit(void) {
|
||||||
// Run any finalisers before we stop using the heap.
|
// Run any finalisers before we stop using the heap. This will also free
|
||||||
|
// any additional heap areas (but not the first.)
|
||||||
gc_sweep_all();
|
gc_sweep_all();
|
||||||
/// MP_STATIC_ASSERT(!MICROPY_GC_SPLIT_HEAP);
|
|
||||||
memset(&MP_STATE_MEM(area), 0, sizeof(MP_STATE_MEM(area)));
|
memset(&MP_STATE_MEM(area), 0, sizeof(MP_STATE_MEM(area)));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void gc_lock(void) {
|
void gc_lock(void) {
|
||||||
// This does not need to be atomic or have the GC mutex because:
|
// This does not need to be atomic or have the GC mutex because:
|
||||||
|
@ -366,6 +363,17 @@ bool gc_is_locked(void) {
|
||||||
return MP_STATE_THREAD(gc_lock_depth) != 0;
|
return MP_STATE_THREAD(gc_lock_depth) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CIRCUITPY-CHANGE
|
||||||
|
bool gc_ptr_on_heap(void *ptr) {
|
||||||
|
for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) {
|
||||||
|
if (ptr >= (void *)area->gc_pool_start // must be above start of pool
|
||||||
|
&& ptr < (void *)area->gc_pool_end) { // must be below end of pool
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#if MICROPY_GC_SPLIT_HEAP
|
#if MICROPY_GC_SPLIT_HEAP
|
||||||
// Returns the area to which this pointer belongs, or NULL if it isn't
|
// Returns the area to which this pointer belongs, or NULL if it isn't
|
||||||
// allocated on the GC-managed heap.
|
// allocated on the GC-managed heap.
|
||||||
|
@ -383,7 +391,12 @@ STATIC inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// CIRCUITPY-CHANGE: VERIFY_PTR moved to gc.h to make it available elsewhere.
|
// ptr should be of type void*
|
||||||
|
#define VERIFY_PTR(ptr) ( \
|
||||||
|
((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
|
||||||
|
&& ptr >= (void *)MP_STATE_MEM(area).gc_pool_start /* must be above start of pool */ \
|
||||||
|
&& ptr < (void *)MP_STATE_MEM(area).gc_pool_end /* must be below end of pool */ \
|
||||||
|
)
|
||||||
|
|
||||||
#ifndef TRACE_MARK
|
#ifndef TRACE_MARK
|
||||||
#if DEBUG_PRINT
|
#if DEBUG_PRINT
|
||||||
|
@ -837,6 +850,10 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_DEBUG
|
||||||
|
gc_dump_alloc_table(&mp_plat_print);
|
||||||
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes);
|
DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes);
|
||||||
|
@ -963,7 +980,7 @@ void gc_free(void *ptr) {
|
||||||
// assert(area);
|
// assert(area);
|
||||||
#else
|
#else
|
||||||
// CIRCUITPY-CHANGE: extra checking
|
// CIRCUITPY-CHANGE: extra checking
|
||||||
if (MP_STATE_MEM(area.gc_pool_start) == 0) {
|
if (MP_STATE_MEM(area).gc_pool_start == 0) {
|
||||||
reset_into_safe_mode(SAFE_MODE_GC_ALLOC_OUTSIDE_VM);
|
reset_into_safe_mode(SAFE_MODE_GC_ALLOC_OUTSIDE_VM);
|
||||||
}
|
}
|
||||||
assert(VERIFY_PTR(ptr));
|
assert(VERIFY_PTR(ptr));
|
||||||
|
@ -1245,39 +1262,6 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
|
||||||
}
|
}
|
||||||
#endif // Alternative gc_realloc impl
|
#endif // Alternative gc_realloc impl
|
||||||
|
|
||||||
// CIRCUITPY-CHANGE
|
|
||||||
bool gc_never_free(void *ptr) {
|
|
||||||
// Check to make sure the pointer is on the heap in the first place.
|
|
||||||
if (gc_nbytes(ptr) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Pointers are stored in a linked list where each block is BYTES_PER_BLOCK long and the first
|
|
||||||
// pointer is the next block of pointers.
|
|
||||||
void **current_reference_block = MP_STATE_MEM(permanent_pointers);
|
|
||||||
void **last_reference_block = NULL;
|
|
||||||
while (current_reference_block != NULL) {
|
|
||||||
for (size_t i = 1; i < BYTES_PER_BLOCK / sizeof(void *); i++) {
|
|
||||||
if (current_reference_block[i] == NULL) {
|
|
||||||
current_reference_block[i] = ptr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_reference_block = current_reference_block; // keep a record of last "proper" reference block
|
|
||||||
current_reference_block = current_reference_block[0];
|
|
||||||
}
|
|
||||||
void **next_block = gc_alloc(BYTES_PER_BLOCK, false);
|
|
||||||
if (next_block == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (MP_STATE_MEM(permanent_pointers) == NULL) {
|
|
||||||
MP_STATE_MEM(permanent_pointers) = next_block;
|
|
||||||
} else {
|
|
||||||
last_reference_block[0] = next_block;
|
|
||||||
}
|
|
||||||
next_block[1] = ptr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gc_dump_info(const mp_print_t *print) {
|
void gc_dump_info(const mp_print_t *print) {
|
||||||
gc_info_t info;
|
gc_info_t info;
|
||||||
gc_info(&info);
|
gc_info(&info);
|
||||||
|
@ -1421,8 +1405,6 @@ void gc_dump_alloc_table(const mp_print_t *print) {
|
||||||
}
|
}
|
||||||
mp_print_str(print, "\n");
|
mp_print_str(print, "\n");
|
||||||
}
|
}
|
||||||
// CIRCUITPY-CHANGE
|
|
||||||
mp_print_str(&mp_plat_print, "\n");
|
|
||||||
GC_EXIT();
|
GC_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
21
py/gc.h
21
py/gc.h
|
@ -34,22 +34,6 @@
|
||||||
#include "py/mpstate.h"
|
#include "py/mpstate.h"
|
||||||
#include "py/misc.h"
|
#include "py/misc.h"
|
||||||
|
|
||||||
// CIRCUITPY-CHANGE: - this may change when use split heap
|
|
||||||
#if !MICROPY_GC_SPLIT_HEAP
|
|
||||||
#define HEAP_PTR(ptr) ( \
|
|
||||||
MP_STATE_MEM(area).gc_pool_start != 0 /* Not on the heap if it isn't inited */ \
|
|
||||||
&& ptr >= (void *)MP_STATE_MEM(area).gc_pool_start /* must be above start of pool */ \
|
|
||||||
&& ptr < (void *)MP_STATE_MEM(area).gc_pool_end /* must be below end of pool */ \
|
|
||||||
)
|
|
||||||
|
|
||||||
// CIRCUITPY-CHANGE: defined here so available outside of gc.c
|
|
||||||
// ptr should be of type void*
|
|
||||||
#define VERIFY_PTR(ptr) ( \
|
|
||||||
((uintptr_t)(ptr) & (MICROPY_BYTES_PER_GC_BLOCK - 1)) == 0 /* must be aligned on a block */ \
|
|
||||||
&& HEAP_PTR(ptr) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void gc_init(void *start, void *end);
|
void gc_init(void *start, void *end);
|
||||||
// CIRCUITPY-CHANGE
|
// CIRCUITPY-CHANGE
|
||||||
void gc_deinit(void);
|
void gc_deinit(void);
|
||||||
|
@ -101,6 +85,11 @@ void *gc_realloc(void *ptr, size_t n_bytes, bool allow_move);
|
||||||
// very sparingly because it can leak memory.
|
// very sparingly because it can leak memory.
|
||||||
bool gc_never_free(void *ptr);
|
bool gc_never_free(void *ptr);
|
||||||
|
|
||||||
|
// CIRCUITPY-CHANGE
|
||||||
|
// True if the pointer is on the MP heap. Doesn't require that it is the start
|
||||||
|
// of a block.
|
||||||
|
bool gc_ptr_on_heap(void *ptr);
|
||||||
|
|
||||||
typedef struct _gc_info_t {
|
typedef struct _gc_info_t {
|
||||||
size_t total;
|
size_t total;
|
||||||
size_t used;
|
size_t used;
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
//| """
|
//| """
|
||||||
//|
|
//|
|
||||||
//| annotations: Any
|
//| annotations: Any
|
||||||
//| """In CPython, ``from __future import annotations``
|
//| """In CPython, ``from __future__ import annotations``
|
||||||
//| indicates that evaluation of annotations is postponed, as described in PEP 563.
|
//| indicates that evaluation of annotations is postponed, as described in PEP 563.
|
||||||
//| CircuitPython (and MicroPython) ignore annotations entirely, whether or not this feature is imported.
|
//| CircuitPython (and MicroPython) ignore annotations entirely, whether or not this feature is imported.
|
||||||
//| This is a limitation of CircuitPython and MicroPython for efficiency reasons.
|
//| This is a limitation of CircuitPython and MicroPython for efficiency reasons.
|
||||||
|
|
|
@ -66,3 +66,4 @@ typedef bool (*display_bus_begin_transaction)(mp_obj_t bus);
|
||||||
typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type,
|
typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type,
|
||||||
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
||||||
typedef void (*display_bus_end_transaction)(mp_obj_t bus);
|
typedef void (*display_bus_end_transaction)(mp_obj_t bus);
|
||||||
|
typedef void (*display_bus_collect_ptrs)(mp_obj_t bus);
|
||||||
|
|
|
@ -51,3 +51,7 @@ void common_hal_fourwire_fourwire_send(mp_obj_t self, display_byte_type_t byte_t
|
||||||
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
||||||
|
|
||||||
void common_hal_fourwire_fourwire_end_transaction(mp_obj_t self);
|
void common_hal_fourwire_fourwire_end_transaction(mp_obj_t self);
|
||||||
|
|
||||||
|
// The FourWire object always lives off the MP heap. So, code must collect any pointers
|
||||||
|
// back to the MP heap manually. Otherwise they'll get freed.
|
||||||
|
void common_hal_fourwire_fourwire_collect_ptrs(mp_obj_t obj);
|
||||||
|
|
|
@ -47,3 +47,7 @@ void common_hal_i2cdisplaybus_i2cdisplaybus_send(mp_obj_t self, display_byte_typ
|
||||||
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
||||||
|
|
||||||
void common_hal_i2cdisplaybus_i2cdisplaybus_end_transaction(mp_obj_t self);
|
void common_hal_i2cdisplaybus_i2cdisplaybus_end_transaction(mp_obj_t self);
|
||||||
|
|
||||||
|
// The I2CDisplayBus object always lives off the MP heap. So, code must collect any pointers
|
||||||
|
// back to the MP heap manually. Otherwise they'll get freed.
|
||||||
|
void common_hal_i2cdisplaybus_i2cdisplaybus_collect_ptrs(mp_obj_t obj);
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
//| :param bool scale: if True display is scaled down by 3 when displayed
|
//| :param bool scale: if True display is scaled down by 3 when displayed
|
||||||
//| :param bool gamma: if True apply gamma correction to all LEDs"""
|
//| :param bool gamma: if True apply gamma correction to all LEDs"""
|
||||||
//| ...
|
//| ...
|
||||||
STATIC mp_obj_t is31fl3741_FrameBuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
STATIC mp_obj_t is31fl3741_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||||
enum { ARG_is31, ARG_width, ARG_height, ARG_mapping, ARG_framebuffer, ARG_scale, ARG_gamma };
|
enum { ARG_is31, ARG_width, ARG_height, ARG_mapping, ARG_framebuffer, ARG_scale, ARG_gamma };
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_is31, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
{ MP_QSTR_is31, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||||
|
@ -85,8 +85,8 @@ STATIC mp_obj_t is31fl3741_FrameBuffer_make_new(const mp_obj_type_t *type, size_
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
is31fl3741_FrameBuffer_obj_t *self = &allocate_display_bus_or_raise()->is31fl3741;
|
is31fl3741_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->is31fl3741;
|
||||||
self->base.type = &is31fl3741_FrameBuffer_type;
|
self->base.type = &is31fl3741_framebuffer_type;
|
||||||
|
|
||||||
if (args[ARG_width].u_int <= 0) {
|
if (args[ARG_width].u_int <= 0) {
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("width must be greater than zero"));
|
mp_raise_ValueError(MP_ERROR_TEXT("width must be greater than zero"));
|
||||||
|
@ -115,7 +115,7 @@ STATIC mp_obj_t is31fl3741_FrameBuffer_make_new(const mp_obj_type_t *type, size_
|
||||||
framebuffer = mp_obj_new_bytearray_of_zeros(bufsize);
|
framebuffer = mp_obj_new_bytearray_of_zeros(bufsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
common_hal_is31fl3741_FrameBuffer_construct(self,
|
common_hal_is31fl3741_framebuffer_construct(self,
|
||||||
args[ARG_width].u_int,
|
args[ARG_width].u_int,
|
||||||
args[ARG_height].u_int,
|
args[ARG_height].u_int,
|
||||||
framebuffer,
|
framebuffer,
|
||||||
|
@ -131,14 +131,14 @@ STATIC mp_obj_t is31fl3741_FrameBuffer_make_new(const mp_obj_type_t *type, size_
|
||||||
//| IS31FL3741 instance. After deinitialization, no further operations
|
//| IS31FL3741 instance. After deinitialization, no further operations
|
||||||
//| may be performed."""
|
//| may be performed."""
|
||||||
//| ...
|
//| ...
|
||||||
STATIC mp_obj_t is31fl3741_FrameBuffer_deinit(mp_obj_t self_in) {
|
STATIC mp_obj_t is31fl3741_framebuffer_deinit(mp_obj_t self_in) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
common_hal_is31fl3741_FrameBuffer_deinit(self);
|
common_hal_is31fl3741_framebuffer_deinit(self);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_deinit_obj, is31fl3741_FrameBuffer_deinit);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_framebuffer_deinit_obj, is31fl3741_framebuffer_deinit);
|
||||||
|
|
||||||
static void check_for_deinit(is31fl3741_FrameBuffer_obj_t *self) {
|
static void check_for_deinit(is31fl3741_framebuffer_obj_t *self) {
|
||||||
if (self->framebuffer == NULL) {
|
if (self->framebuffer == NULL) {
|
||||||
raise_deinited_error();
|
raise_deinited_error();
|
||||||
}
|
}
|
||||||
|
@ -147,18 +147,18 @@ static void check_for_deinit(is31fl3741_FrameBuffer_obj_t *self) {
|
||||||
//| brightness: float
|
//| brightness: float
|
||||||
//| """In the current implementation, 0.0 turns the display off entirely
|
//| """In the current implementation, 0.0 turns the display off entirely
|
||||||
//| and any other value up to 1.0 turns the display on fully."""
|
//| and any other value up to 1.0 turns the display on fully."""
|
||||||
STATIC mp_obj_t is31fl3741_FrameBuffer_get_brightness(mp_obj_t self_in) {
|
STATIC mp_obj_t is31fl3741_framebuffer_get_brightness(mp_obj_t self_in) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
check_for_deinit(self);
|
check_for_deinit(self);
|
||||||
uint8_t current = common_hal_is31fl3741_get_current(self->is31fl3741);
|
uint8_t current = common_hal_is31fl3741_get_current(self->is31fl3741);
|
||||||
|
|
||||||
float brightness = (float)current / (float)0xFF;
|
float brightness = (float)current / (float)0xFF;
|
||||||
return mp_obj_new_float(brightness);
|
return mp_obj_new_float(brightness);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_brightness_obj, is31fl3741_FrameBuffer_get_brightness);
|
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_framebuffer_get_brightness_obj, is31fl3741_framebuffer_get_brightness);
|
||||||
|
|
||||||
STATIC mp_obj_t is31fl3741_FrameBuffer_set_brightness(mp_obj_t self_in, mp_obj_t value_in) {
|
STATIC mp_obj_t is31fl3741_framebuffer_set_brightness(mp_obj_t self_in, mp_obj_t value_in) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
check_for_deinit(self);
|
check_for_deinit(self);
|
||||||
mp_float_t brightness = mp_obj_get_float(value_in);
|
mp_float_t brightness = mp_obj_get_float(value_in);
|
||||||
if (brightness < 0.0f || brightness > 1.0f) {
|
if (brightness < 0.0f || brightness > 1.0f) {
|
||||||
|
@ -170,119 +170,119 @@ STATIC mp_obj_t is31fl3741_FrameBuffer_set_brightness(mp_obj_t self_in, mp_obj_t
|
||||||
|
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_FrameBuffer_set_brightness_obj, is31fl3741_FrameBuffer_set_brightness);
|
MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_framebuffer_set_brightness_obj, is31fl3741_framebuffer_set_brightness);
|
||||||
|
|
||||||
MP_PROPERTY_GETSET(is31fl3741_FrameBuffer_brightness_obj,
|
MP_PROPERTY_GETSET(is31fl3741_framebuffer_brightness_obj,
|
||||||
(mp_obj_t)&is31fl3741_FrameBuffer_get_brightness_obj,
|
(mp_obj_t)&is31fl3741_framebuffer_get_brightness_obj,
|
||||||
(mp_obj_t)&is31fl3741_FrameBuffer_set_brightness_obj);
|
(mp_obj_t)&is31fl3741_framebuffer_set_brightness_obj);
|
||||||
|
|
||||||
//| def refresh(self) -> None:
|
//| def refresh(self) -> None:
|
||||||
//| """Transmits the color data in the buffer to the pixels so that
|
//| """Transmits the color data in the buffer to the pixels so that
|
||||||
//| they are shown."""
|
//| they are shown."""
|
||||||
//| ...
|
//| ...
|
||||||
STATIC mp_obj_t is31fl3741_FrameBuffer_refresh(mp_obj_t self_in) {
|
STATIC mp_obj_t is31fl3741_framebuffer_refresh(mp_obj_t self_in) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
check_for_deinit(self);
|
check_for_deinit(self);
|
||||||
common_hal_is31fl3741_FrameBuffer_refresh(self, 0);
|
common_hal_is31fl3741_framebuffer_refresh(self, 0);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_refresh_obj, is31fl3741_FrameBuffer_refresh);
|
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_framebuffer_refresh_obj, is31fl3741_framebuffer_refresh);
|
||||||
|
|
||||||
//| width: int
|
//| width: int
|
||||||
//| """The width of the display, in pixels"""
|
//| """The width of the display, in pixels"""
|
||||||
STATIC mp_obj_t is31fl3741_FrameBuffer_get_width(mp_obj_t self_in) {
|
STATIC mp_obj_t is31fl3741_framebuffer_get_width(mp_obj_t self_in) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
check_for_deinit(self);
|
check_for_deinit(self);
|
||||||
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_FrameBuffer_get_width(self));
|
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_framebuffer_get_width(self));
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_width_obj, is31fl3741_FrameBuffer_get_width);
|
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_framebuffer_get_width_obj, is31fl3741_framebuffer_get_width);
|
||||||
MP_PROPERTY_GETTER(is31fl3741_FrameBuffer_width_obj,
|
MP_PROPERTY_GETTER(is31fl3741_framebuffer_width_obj,
|
||||||
(mp_obj_t)&is31fl3741_FrameBuffer_get_width_obj);
|
(mp_obj_t)&is31fl3741_framebuffer_get_width_obj);
|
||||||
|
|
||||||
//| height: int
|
//| height: int
|
||||||
//| """The height of the display, in pixels"""
|
//| """The height of the display, in pixels"""
|
||||||
//|
|
//|
|
||||||
STATIC mp_obj_t is31fl3741_FrameBuffer_get_height(mp_obj_t self_in) {
|
STATIC mp_obj_t is31fl3741_framebuffer_get_height(mp_obj_t self_in) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
check_for_deinit(self);
|
check_for_deinit(self);
|
||||||
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_FrameBuffer_get_height(self));
|
return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_framebuffer_get_height(self));
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_height_obj, is31fl3741_FrameBuffer_get_height);
|
MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_framebuffer_get_height_obj, is31fl3741_framebuffer_get_height);
|
||||||
MP_PROPERTY_GETTER(is31fl3741_FrameBuffer_height_obj,
|
MP_PROPERTY_GETTER(is31fl3741_framebuffer_height_obj,
|
||||||
(mp_obj_t)&is31fl3741_FrameBuffer_get_height_obj);
|
(mp_obj_t)&is31fl3741_framebuffer_get_height_obj);
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t is31fl3741_FrameBuffer_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t is31fl3741_framebuffer_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&is31fl3741_FrameBuffer_deinit_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&is31fl3741_framebuffer_deinit_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&is31fl3741_FrameBuffer_brightness_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&is31fl3741_framebuffer_brightness_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&is31fl3741_FrameBuffer_refresh_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&is31fl3741_framebuffer_refresh_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&is31fl3741_FrameBuffer_width_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&is31fl3741_framebuffer_width_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&is31fl3741_FrameBuffer_height_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&is31fl3741_framebuffer_height_obj) },
|
||||||
};
|
};
|
||||||
STATIC MP_DEFINE_CONST_DICT(is31fl3741_FrameBuffer_locals_dict, is31fl3741_FrameBuffer_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(is31fl3741_framebuffer_locals_dict, is31fl3741_framebuffer_locals_dict_table);
|
||||||
|
|
||||||
STATIC void is31fl3741_FrameBuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
|
STATIC void is31fl3741_framebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
check_for_deinit(self);
|
check_for_deinit(self);
|
||||||
|
|
||||||
*bufinfo = self->bufinfo;
|
*bufinfo = self->bufinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void is31fl3741_FrameBuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
|
STATIC void is31fl3741_framebuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
|
||||||
common_hal_is31fl3741_FrameBuffer_refresh(self_in, dirty_row_bitmap);
|
common_hal_is31fl3741_framebuffer_refresh(self_in, dirty_row_bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void is31fl3741_FrameBuffer_deinit_proto(mp_obj_t self_in) {
|
STATIC void is31fl3741_framebuffer_deinit_proto(mp_obj_t self_in) {
|
||||||
common_hal_is31fl3741_FrameBuffer_deinit(self_in);
|
common_hal_is31fl3741_framebuffer_deinit(self_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC float is31fl3741_FrameBuffer_get_brightness_proto(mp_obj_t self_in) {
|
STATIC float is31fl3741_framebuffer_get_brightness_proto(mp_obj_t self_in) {
|
||||||
return common_hal_is31fl3741_FrameBuffer_get_paused(self_in) ? 0.0f : 1.0f;
|
return common_hal_is31fl3741_framebuffer_get_paused(self_in) ? 0.0f : 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC bool is31fl3741_FrameBuffer_set_brightness_proto(mp_obj_t self_in, mp_float_t value) {
|
STATIC bool is31fl3741_framebuffer_set_brightness_proto(mp_obj_t self_in, mp_float_t value) {
|
||||||
common_hal_is31fl3741_FrameBuffer_set_paused(self_in, value <= 0);
|
common_hal_is31fl3741_framebuffer_set_paused(self_in, value <= 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int is31fl3741_FrameBuffer_get_width_proto(mp_obj_t self_in) {
|
STATIC int is31fl3741_framebuffer_get_width_proto(mp_obj_t self_in) {
|
||||||
return common_hal_is31fl3741_FrameBuffer_get_width(self_in);
|
return common_hal_is31fl3741_framebuffer_get_width(self_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int is31fl3741_FrameBuffer_get_height_proto(mp_obj_t self_in) {
|
STATIC int is31fl3741_framebuffer_get_height_proto(mp_obj_t self_in) {
|
||||||
return common_hal_is31fl3741_FrameBuffer_get_height(self_in);
|
return common_hal_is31fl3741_framebuffer_get_height(self_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int is31fl3741_FrameBuffer_get_color_depth_proto(mp_obj_t self_in) {
|
STATIC int is31fl3741_framebuffer_get_color_depth_proto(mp_obj_t self_in) {
|
||||||
// The way displayio works depth is used to calculate bytes
|
// The way displayio works depth is used to calculate bytes
|
||||||
// We use an uint32_t for color already so setting to 24 causes
|
// We use an uint32_t for color already so setting to 24 causes
|
||||||
// more changes required
|
// more changes required
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int is31fl3741_FrameBuffer_get_bytes_per_cell_proto(mp_obj_t self_in) {
|
STATIC int is31fl3741_framebuffer_get_bytes_per_cell_proto(mp_obj_t self_in) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int is31fl3741_FrameBuffer_get_native_frames_per_second_proto(mp_obj_t self_in) {
|
STATIC int is31fl3741_framebuffer_get_native_frames_per_second_proto(mp_obj_t self_in) {
|
||||||
return 60; // This was just chosen may vary based on LEDs used?
|
return 60; // This was just chosen may vary based on LEDs used?
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC const framebuffer_p_t is31fl3741_FrameBuffer_proto = {
|
STATIC const framebuffer_p_t is31fl3741_framebuffer_proto = {
|
||||||
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
|
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
|
||||||
.get_bufinfo = is31fl3741_FrameBuffer_get_bufinfo,
|
.get_bufinfo = is31fl3741_framebuffer_get_bufinfo,
|
||||||
.set_brightness = is31fl3741_FrameBuffer_set_brightness_proto,
|
.set_brightness = is31fl3741_framebuffer_set_brightness_proto,
|
||||||
.get_brightness = is31fl3741_FrameBuffer_get_brightness_proto,
|
.get_brightness = is31fl3741_framebuffer_get_brightness_proto,
|
||||||
.get_width = is31fl3741_FrameBuffer_get_width_proto,
|
.get_width = is31fl3741_framebuffer_get_width_proto,
|
||||||
.get_height = is31fl3741_FrameBuffer_get_height_proto,
|
.get_height = is31fl3741_framebuffer_get_height_proto,
|
||||||
.get_color_depth = is31fl3741_FrameBuffer_get_color_depth_proto,
|
.get_color_depth = is31fl3741_framebuffer_get_color_depth_proto,
|
||||||
.get_bytes_per_cell = is31fl3741_FrameBuffer_get_bytes_per_cell_proto,
|
.get_bytes_per_cell = is31fl3741_framebuffer_get_bytes_per_cell_proto,
|
||||||
.get_native_frames_per_second = is31fl3741_FrameBuffer_get_native_frames_per_second_proto,
|
.get_native_frames_per_second = is31fl3741_framebuffer_get_native_frames_per_second_proto,
|
||||||
.swapbuffers = is31fl3741_FrameBuffer_swapbuffers,
|
.swapbuffers = is31fl3741_framebuffer_swapbuffers,
|
||||||
.deinit = is31fl3741_FrameBuffer_deinit_proto,
|
.deinit = is31fl3741_framebuffer_deinit_proto,
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC mp_int_t is31fl3741_FrameBuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
|
STATIC mp_int_t is31fl3741_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
|
||||||
is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
|
is31fl3741_framebuffer_obj_t *self = (is31fl3741_framebuffer_obj_t *)self_in;
|
||||||
// a readonly framebuffer would be unusual but not impossible
|
// a readonly framebuffer would be unusual but not impossible
|
||||||
if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
|
if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -293,11 +293,11 @@ STATIC mp_int_t is31fl3741_FrameBuffer_get_buffer(mp_obj_t self_in, mp_buffer_in
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_OBJ_TYPE(
|
MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
is31fl3741_FrameBuffer_type,
|
is31fl3741_framebuffer_type,
|
||||||
MP_QSTR_is31fl3741,
|
MP_QSTR_is31fl3741,
|
||||||
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
|
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
|
||||||
locals_dict, &is31fl3741_FrameBuffer_locals_dict,
|
locals_dict, &is31fl3741_framebuffer_locals_dict,
|
||||||
make_new, is31fl3741_FrameBuffer_make_new,
|
make_new, is31fl3741_framebuffer_make_new,
|
||||||
buffer, is31fl3741_FrameBuffer_get_buffer,
|
buffer, is31fl3741_framebuffer_get_buffer,
|
||||||
protocol, &is31fl3741_FrameBuffer_proto
|
protocol, &is31fl3741_framebuffer_proto
|
||||||
);
|
);
|
||||||
|
|
|
@ -29,22 +29,22 @@
|
||||||
#include "shared-module/is31fl3741/FrameBuffer.h"
|
#include "shared-module/is31fl3741/FrameBuffer.h"
|
||||||
#include "shared-module/is31fl3741/IS31FL3741.h"
|
#include "shared-module/is31fl3741/IS31FL3741.h"
|
||||||
|
|
||||||
extern const mp_obj_type_t is31fl3741_FrameBuffer_type;
|
extern const mp_obj_type_t is31fl3741_framebuffer_type;
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *self, int width, int height, mp_obj_t framebuffer, is31fl3741_IS31FL3741_obj_t *is31, mp_obj_t mapping);
|
void common_hal_is31fl3741_framebuffer_construct(is31fl3741_framebuffer_obj_t *self, int width, int height, mp_obj_t framebuffer, is31fl3741_IS31FL3741_obj_t *is31, mp_obj_t mapping);
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_deinit(is31fl3741_FrameBuffer_obj_t *);
|
void common_hal_is31fl3741_framebuffer_deinit(is31fl3741_framebuffer_obj_t *);
|
||||||
|
|
||||||
int common_hal_is31fl3741_FrameBuffer_get_width(is31fl3741_FrameBuffer_obj_t *self);
|
int common_hal_is31fl3741_framebuffer_get_width(is31fl3741_framebuffer_obj_t *self);
|
||||||
int common_hal_is31fl3741_FrameBuffer_get_height(is31fl3741_FrameBuffer_obj_t *self);
|
int common_hal_is31fl3741_framebuffer_get_height(is31fl3741_framebuffer_obj_t *self);
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_set_global_current(is31fl3741_FrameBuffer_obj_t *self, uint8_t current);
|
void common_hal_is31fl3741_framebuffer_set_global_current(is31fl3741_framebuffer_obj_t *self, uint8_t current);
|
||||||
uint8_t common_hal_is31fl3741_FrameBuffer_get_global_current(is31fl3741_FrameBuffer_obj_t *self);
|
uint8_t common_hal_is31fl3741_framebuffer_get_global_current(is31fl3741_framebuffer_obj_t *self);
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_set_paused(is31fl3741_FrameBuffer_obj_t *self, bool paused);
|
void common_hal_is31fl3741_framebuffer_set_paused(is31fl3741_framebuffer_obj_t *self, bool paused);
|
||||||
bool common_hal_is31fl3741_FrameBuffer_get_paused(is31fl3741_FrameBuffer_obj_t *self);
|
bool common_hal_is31fl3741_framebuffer_get_paused(is31fl3741_framebuffer_obj_t *self);
|
||||||
void common_hal_is31fl3741_FrameBuffer_refresh(is31fl3741_FrameBuffer_obj_t *self, uint8_t *dirtyrows);
|
void common_hal_is31fl3741_framebuffer_refresh(is31fl3741_framebuffer_obj_t *self, uint8_t *dirtyrows);
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_reconstruct(is31fl3741_FrameBuffer_obj_t *self, mp_obj_t framebuffer);
|
void common_hal_is31fl3741_framebuffer_reconstruct(is31fl3741_framebuffer_obj_t *self, mp_obj_t framebuffer);
|
||||||
|
|
||||||
void is31fl3741_FrameBuffer_collect_ptrs(is31fl3741_FrameBuffer_obj_t *self);
|
void is31fl3741_framebuffer_collect_ptrs(is31fl3741_framebuffer_obj_t *self);
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
STATIC const mp_rom_map_elem_t is31fl3741_module_globals_table[] = {
|
STATIC const mp_rom_map_elem_t is31fl3741_module_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_is31fl3741) },
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_is31fl3741) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_IS31FL3741), MP_ROM_PTR(&is31fl3741_IS31FL3741_type) },
|
{ MP_ROM_QSTR(MP_QSTR_IS31FL3741), MP_ROM_PTR(&is31fl3741_IS31FL3741_type) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_IS31FL3741_FrameBuffer), MP_ROM_PTR(&is31fl3741_FrameBuffer_type) },
|
{ MP_ROM_QSTR(MP_QSTR_IS31FL3741_FrameBuffer), MP_ROM_PTR(&is31fl3741_framebuffer_type) },
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(is31fl3741_module_globals, is31fl3741_module_globals_table);
|
STATIC MP_DEFINE_CONST_DICT(is31fl3741_module_globals, is31fl3741_module_globals_table);
|
||||||
|
|
|
@ -53,3 +53,7 @@ void common_hal_paralleldisplaybus_parallelbus_send(mp_obj_t self, display_byte_
|
||||||
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
|
||||||
|
|
||||||
void common_hal_paralleldisplaybus_parallelbus_end_transaction(mp_obj_t self);
|
void common_hal_paralleldisplaybus_parallelbus_end_transaction(mp_obj_t self);
|
||||||
|
|
||||||
|
// The ParallelBus object always lives off the MP heap. So, code must collect any pointers
|
||||||
|
// back to the MP heap manually. Otherwise they'll get freed.
|
||||||
|
void common_hal_paralleldisplaybus_parallelbus_collect_ptrs(mp_obj_t self);
|
||||||
|
|
|
@ -186,32 +186,6 @@ MP_PROPERTY_GETSET(supervisor_runtime_ble_workflow_obj,
|
||||||
(mp_obj_t)&supervisor_runtime_get_ble_workflow_obj,
|
(mp_obj_t)&supervisor_runtime_get_ble_workflow_obj,
|
||||||
(mp_obj_t)&supervisor_runtime_set_ble_workflow_obj);
|
(mp_obj_t)&supervisor_runtime_set_ble_workflow_obj);
|
||||||
|
|
||||||
//| next_stack_limit: int
|
|
||||||
//| """The size of the stack for the next vm run. If its too large, the default will be used.
|
|
||||||
//|
|
|
||||||
//| **Limitations**: Stack size is fixed at startup on the ``espressif`` port; setting this will have no effect.
|
|
||||||
//| """
|
|
||||||
STATIC mp_obj_t supervisor_runtime_get_next_stack_limit(mp_obj_t self) {
|
|
||||||
return mp_obj_new_int(get_next_stack_size());
|
|
||||||
}
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_next_stack_limit_obj, supervisor_runtime_get_next_stack_limit);
|
|
||||||
|
|
||||||
STATIC mp_obj_t supervisor_runtime_set_next_stack_limit(mp_obj_t self, mp_obj_t size_obj) {
|
|
||||||
mp_int_t size = mp_obj_get_int(size_obj);
|
|
||||||
mp_arg_validate_int_min(size, 256, MP_QSTR_size);
|
|
||||||
if (!set_next_stack_size(size)) {
|
|
||||||
mp_raise_msg_varg(&mp_type_AttributeError,
|
|
||||||
MP_ERROR_TEXT("can't set attribute '%q'"),
|
|
||||||
MP_QSTR_next_stack_limit);
|
|
||||||
}
|
|
||||||
return mp_const_none;
|
|
||||||
}
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(supervisor_runtime_set_next_stack_limit_obj, supervisor_runtime_set_next_stack_limit);
|
|
||||||
|
|
||||||
MP_PROPERTY_GETSET(supervisor_runtime_next_stack_limit_obj,
|
|
||||||
(mp_obj_t)&supervisor_runtime_get_next_stack_limit_obj,
|
|
||||||
(mp_obj_t)&supervisor_runtime_set_next_stack_limit_obj);
|
|
||||||
|
|
||||||
//| rgb_status_brightness: int
|
//| rgb_status_brightness: int
|
||||||
//| """Set brightness of status RGB LED from 0-255. This will take effect
|
//| """Set brightness of status RGB LED from 0-255. This will take effect
|
||||||
//| after the current code finishes and the status LED is used to show
|
//| after the current code finishes and the status LED is used to show
|
||||||
|
@ -245,7 +219,6 @@ STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_safe_mode_reason), MP_ROM_PTR(&supervisor_runtime_safe_mode_reason_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_safe_mode_reason), MP_ROM_PTR(&supervisor_runtime_safe_mode_reason_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_autoreload), MP_ROM_PTR(&supervisor_runtime_autoreload_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_autoreload), MP_ROM_PTR(&supervisor_runtime_autoreload_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ble_workflow), MP_ROM_PTR(&supervisor_runtime_ble_workflow_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_ble_workflow), MP_ROM_PTR(&supervisor_runtime_ble_workflow_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_next_stack_limit), MP_ROM_PTR(&supervisor_runtime_next_stack_limit_obj) },
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_rgb_status_brightness), MP_ROM_PTR(&supervisor_runtime_rgb_status_brightness_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_rgb_status_brightness), MP_ROM_PTR(&supervisor_runtime_rgb_status_brightness_obj) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "py/objstr.h"
|
#include "py/objstr.h"
|
||||||
|
|
||||||
#include "shared/runtime/interrupt_char.h"
|
#include "shared/runtime/interrupt_char.h"
|
||||||
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/shared/display.h"
|
#include "supervisor/shared/display.h"
|
||||||
#include "supervisor/shared/reload.h"
|
#include "supervisor/shared/reload.h"
|
||||||
#include "supervisor/shared/traceback.h"
|
#include "supervisor/shared/traceback.h"
|
||||||
|
@ -153,18 +154,18 @@ STATIC mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos
|
||||||
}
|
}
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *filename = mp_obj_str_get_data(args.filename.u_obj, &len);
|
const char *filename = mp_obj_str_get_data(args.filename.u_obj, &len);
|
||||||
free_memory(next_code_allocation);
|
if (next_code_configuration != NULL) {
|
||||||
|
port_free(next_code_configuration);
|
||||||
|
next_code_configuration = NULL;
|
||||||
|
}
|
||||||
if (options != 0 || len != 0) {
|
if (options != 0 || len != 0) {
|
||||||
next_code_allocation = allocate_memory(align32_size(sizeof(next_code_info_t) + len + 1), false, true);
|
next_code_configuration = port_malloc(sizeof(supervisor_next_code_info_t) + len + 1, false);
|
||||||
if (next_code_allocation == NULL) {
|
if (next_code_configuration == NULL) {
|
||||||
m_malloc_fail(sizeof(next_code_info_t) + len + 1);
|
m_malloc_fail(sizeof(supervisor_next_code_info_t) + len + 1);
|
||||||
}
|
}
|
||||||
next_code_info_t *next_code = (next_code_info_t *)next_code_allocation->ptr;
|
next_code_configuration->options = options | SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
|
||||||
next_code->options = options | SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
|
memcpy(&next_code_configuration->filename, filename, len);
|
||||||
memcpy(&next_code->filename, filename, len);
|
next_code_configuration->filename[len] = '\0';
|
||||||
next_code->filename[len] = '\0';
|
|
||||||
} else {
|
|
||||||
next_code_allocation = NULL;
|
|
||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
@ -229,14 +230,14 @@ MP_DEFINE_CONST_FUN_OBJ_0(supervisor_ticks_ms_obj, supervisor_ticks_ms);
|
||||||
//| ...
|
//| ...
|
||||||
//|
|
//|
|
||||||
STATIC mp_obj_t supervisor_get_previous_traceback(void) {
|
STATIC mp_obj_t supervisor_get_previous_traceback(void) {
|
||||||
if (prev_traceback_allocation) {
|
if (prev_traceback_string) {
|
||||||
size_t len = strlen((const char *)prev_traceback_allocation->ptr);
|
size_t len = strlen(prev_traceback_string);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
mp_obj_str_t *o = mp_obj_malloc(mp_obj_str_t, &mp_type_str);
|
mp_obj_str_t *o = mp_obj_malloc(mp_obj_str_t, &mp_type_str);
|
||||||
o->len = len;
|
o->len = len;
|
||||||
// callers probably aren't going to compare this string, so skip computing the hash
|
// callers probably aren't going to compare this string, so skip computing the hash
|
||||||
o->hash = 0;
|
o->hash = 0;
|
||||||
o->data = (const byte *)prev_traceback_allocation->ptr;
|
o->data = (const byte *)prev_traceback_string;
|
||||||
return MP_OBJ_FROM_PTR(o);
|
return MP_OBJ_FROM_PTR(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,34 +293,33 @@ STATIC mp_obj_t supervisor_set_usb_identification(size_t n_args, const mp_obj_t
|
||||||
} args;
|
} args;
|
||||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
|
||||||
|
|
||||||
if (!usb_identification_allocation) {
|
if (custom_usb_identification == NULL) {
|
||||||
usb_identification_allocation = allocate_memory(sizeof(usb_identification_t), false, true);
|
custom_usb_identification = port_malloc(sizeof(usb_identification_t), false);
|
||||||
}
|
}
|
||||||
usb_identification_t *identification = (usb_identification_t *)usb_identification_allocation->ptr;
|
|
||||||
|
|
||||||
mp_arg_validate_int_range(args.vid.u_int, -1, (1 << 16) - 1, MP_QSTR_vid);
|
mp_arg_validate_int_range(args.vid.u_int, -1, (1 << 16) - 1, MP_QSTR_vid);
|
||||||
mp_arg_validate_int_range(args.pid.u_int, -1, (1 << 16) - 1, MP_QSTR_pid);
|
mp_arg_validate_int_range(args.pid.u_int, -1, (1 << 16) - 1, MP_QSTR_pid);
|
||||||
|
|
||||||
identification->vid = args.vid.u_int > -1 ? args.vid.u_int : USB_VID;
|
custom_usb_identification->vid = args.vid.u_int > -1 ? args.vid.u_int : USB_VID;
|
||||||
identification->pid = args.pid.u_int > -1 ? args.pid.u_int : USB_PID;
|
custom_usb_identification->pid = args.pid.u_int > -1 ? args.pid.u_int : USB_PID;
|
||||||
|
|
||||||
mp_buffer_info_t info;
|
mp_buffer_info_t info;
|
||||||
if (args.manufacturer.u_obj != mp_const_none) {
|
if (args.manufacturer.u_obj != mp_const_none) {
|
||||||
mp_get_buffer_raise(args.manufacturer.u_obj, &info, MP_BUFFER_READ);
|
mp_get_buffer_raise(args.manufacturer.u_obj, &info, MP_BUFFER_READ);
|
||||||
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_manufacturer);
|
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_manufacturer);
|
||||||
memcpy(identification->manufacturer_name, info.buf, info.len);
|
memcpy(custom_usb_identification->manufacturer_name, info.buf, info.len);
|
||||||
identification->manufacturer_name[info.len] = 0;
|
custom_usb_identification->manufacturer_name[info.len] = 0;
|
||||||
} else {
|
} else {
|
||||||
strcpy(identification->manufacturer_name, USB_MANUFACTURER);
|
strcpy(custom_usb_identification->manufacturer_name, USB_MANUFACTURER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.product.u_obj != mp_const_none) {
|
if (args.product.u_obj != mp_const_none) {
|
||||||
mp_get_buffer_raise(args.product.u_obj, &info, MP_BUFFER_READ);
|
mp_get_buffer_raise(args.product.u_obj, &info, MP_BUFFER_READ);
|
||||||
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_product);
|
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_product);
|
||||||
memcpy(identification->product_name, info.buf, info.len);
|
memcpy(custom_usb_identification->product_name, info.buf, info.len);
|
||||||
identification->product_name[info.len] = 0;
|
custom_usb_identification->product_name[info.len] = 0;
|
||||||
} else {
|
} else {
|
||||||
strcpy(identification->product_name, USB_PRODUCT);
|
strcpy(custom_usb_identification->product_name, USB_PRODUCT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
|
|
|
@ -32,10 +32,20 @@
|
||||||
|
|
||||||
#include "common-hal/supervisor/Runtime.h"
|
#include "common-hal/supervisor/Runtime.h"
|
||||||
#include "shared-module/supervisor/StatusBar.h"
|
#include "shared-module/supervisor/StatusBar.h"
|
||||||
|
#include "supervisor/usb.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t options;
|
||||||
|
char filename[];
|
||||||
|
} supervisor_next_code_info_t;
|
||||||
|
|
||||||
extern const super_runtime_obj_t common_hal_supervisor_runtime_obj;
|
extern const super_runtime_obj_t common_hal_supervisor_runtime_obj;
|
||||||
extern supervisor_status_bar_obj_t shared_module_supervisor_status_bar_obj;
|
extern supervisor_status_bar_obj_t shared_module_supervisor_status_bar_obj;
|
||||||
extern mp_obj_t supervisor_ticks_ms(void);
|
extern mp_obj_t supervisor_ticks_ms(void);
|
||||||
|
|
||||||
|
extern char *prev_traceback_string;
|
||||||
|
|
||||||
|
extern supervisor_next_code_info_t *next_code_configuration;
|
||||||
|
extern usb_identification_t *custom_usb_identification;
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SUPERVISOR___INIT___H
|
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SUPERVISOR___INIT___H
|
||||||
|
|
|
@ -441,4 +441,5 @@ void reset_busdisplay(busdisplay_busdisplay_obj_t *self) {
|
||||||
|
|
||||||
void busdisplay_busdisplay_collect_ptrs(busdisplay_busdisplay_obj_t *self) {
|
void busdisplay_busdisplay_collect_ptrs(busdisplay_busdisplay_obj_t *self) {
|
||||||
displayio_display_core_collect_ptrs(&self->core);
|
displayio_display_core_collect_ptrs(&self->core);
|
||||||
|
displayio_display_bus_collect_ptrs(&self->bus);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
#include "shared-module/displayio/area.h"
|
#include "shared-module/displayio/area.h"
|
||||||
#include "supervisor/shared/display.h"
|
#include "supervisor/shared/display.h"
|
||||||
#include "supervisor/shared/reload.h"
|
#include "supervisor/shared/reload.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
#include "supervisor/spi_flash_api.h"
|
#include "supervisor/spi_flash_api.h"
|
||||||
#include "py/mpconfig.h"
|
#include "py/mpconfig.h"
|
||||||
|
@ -166,8 +165,8 @@ void common_hal_displayio_release_displays(void) {
|
||||||
common_hal_rgbmatrix_rgbmatrix_deinit(&display_buses[i].rgbmatrix);
|
common_hal_rgbmatrix_rgbmatrix_deinit(&display_buses[i].rgbmatrix);
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_IS31FL3741
|
#if CIRCUITPY_IS31FL3741
|
||||||
} else if (bus_type == &is31fl3741_FrameBuffer_type) {
|
} else if (bus_type == &is31fl3741_framebuffer_type) {
|
||||||
common_hal_is31fl3741_FrameBuffer_deinit(&display_buses[i].is31fl3741);
|
common_hal_is31fl3741_framebuffer_deinit(&display_buses[i].is31fl3741);
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_SHARPDISPLAY
|
#if CIRCUITPY_SHARPDISPLAY
|
||||||
} else if (bus_type == &sharpdisplay_framebuffer_type) {
|
} else if (bus_type == &sharpdisplay_framebuffer_type) {
|
||||||
|
@ -260,8 +259,8 @@ void reset_displays(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_IS31FL3741
|
#if CIRCUITPY_IS31FL3741
|
||||||
} else if (display_bus_type == &is31fl3741_FrameBuffer_type) {
|
} else if (display_bus_type == &is31fl3741_framebuffer_type) {
|
||||||
is31fl3741_FrameBuffer_obj_t *is31fb = &display_buses[i].is31fl3741;
|
is31fl3741_framebuffer_obj_t *is31fb = &display_buses[i].is31fl3741;
|
||||||
|
|
||||||
if (((uint32_t)is31fb->is31fl3741->i2c) < ((uint32_t)&display_buses) ||
|
if (((uint32_t)is31fb->is31fl3741->i2c) < ((uint32_t)&display_buses) ||
|
||||||
((uint32_t)is31fb->is31fl3741->i2c) > ((uint32_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT)) {
|
((uint32_t)is31fb->is31fl3741->i2c) > ((uint32_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT)) {
|
||||||
|
@ -284,9 +283,9 @@ void reset_displays(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!any_display_uses_this_framebuffer(&is31fb->base)) {
|
if (!any_display_uses_this_framebuffer(&is31fb->base)) {
|
||||||
common_hal_is31fl3741_FrameBuffer_deinit(is31fb);
|
common_hal_is31fl3741_framebuffer_deinit(is31fb);
|
||||||
} else {
|
} else {
|
||||||
common_hal_is31fl3741_FrameBuffer_set_paused(is31fb, true);
|
common_hal_is31fl3741_framebuffer_set_paused(is31fb, true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_SHARPDISPLAY
|
#if CIRCUITPY_SHARPDISPLAY
|
||||||
|
@ -351,8 +350,8 @@ void displayio_gc_collect(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_IS31FL3741
|
#if CIRCUITPY_IS31FL3741
|
||||||
if (display_bus_type == &is31fl3741_FrameBuffer_type) {
|
if (display_bus_type == &is31fl3741_framebuffer_type) {
|
||||||
is31fl3741_FrameBuffer_collect_ptrs(&display_buses[i].is31fl3741);
|
is31fl3741_framebuffer_collect_ptrs(&display_buses[i].is31fl3741);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_SHARPDISPLAY
|
#if CIRCUITPY_SHARPDISPLAY
|
||||||
|
|
|
@ -81,7 +81,7 @@ typedef struct {
|
||||||
rgbmatrix_rgbmatrix_obj_t rgbmatrix;
|
rgbmatrix_rgbmatrix_obj_t rgbmatrix;
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_IS31FL3741
|
#if CIRCUITPY_IS31FL3741
|
||||||
is31fl3741_FrameBuffer_obj_t is31fl3741;
|
is31fl3741_framebuffer_obj_t is31fl3741;
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_SHARPDISPLAY
|
#if CIRCUITPY_SHARPDISPLAY
|
||||||
sharpdisplay_framebuffer_obj_t sharpdisplay;
|
sharpdisplay_framebuffer_obj_t sharpdisplay;
|
||||||
|
|
|
@ -76,6 +76,7 @@ void displayio_display_bus_construct(displayio_display_bus_t *self,
|
||||||
self->begin_transaction = common_hal_paralleldisplaybus_parallelbus_begin_transaction;
|
self->begin_transaction = common_hal_paralleldisplaybus_parallelbus_begin_transaction;
|
||||||
self->send = common_hal_paralleldisplaybus_parallelbus_send;
|
self->send = common_hal_paralleldisplaybus_parallelbus_send;
|
||||||
self->end_transaction = common_hal_paralleldisplaybus_parallelbus_end_transaction;
|
self->end_transaction = common_hal_paralleldisplaybus_parallelbus_end_transaction;
|
||||||
|
self->collect_ptrs = common_hal_paralleldisplaybus_parallelbus_collect_ptrs;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_FOURWIRE
|
#if CIRCUITPY_FOURWIRE
|
||||||
|
@ -85,6 +86,7 @@ void displayio_display_bus_construct(displayio_display_bus_t *self,
|
||||||
self->begin_transaction = common_hal_fourwire_fourwire_begin_transaction;
|
self->begin_transaction = common_hal_fourwire_fourwire_begin_transaction;
|
||||||
self->send = common_hal_fourwire_fourwire_send;
|
self->send = common_hal_fourwire_fourwire_send;
|
||||||
self->end_transaction = common_hal_fourwire_fourwire_end_transaction;
|
self->end_transaction = common_hal_fourwire_fourwire_end_transaction;
|
||||||
|
self->collect_ptrs = common_hal_fourwire_fourwire_collect_ptrs;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_I2CDISPLAYBUS
|
#if CIRCUITPY_I2CDISPLAYBUS
|
||||||
|
@ -94,6 +96,7 @@ void displayio_display_bus_construct(displayio_display_bus_t *self,
|
||||||
self->begin_transaction = common_hal_i2cdisplaybus_i2cdisplaybus_begin_transaction;
|
self->begin_transaction = common_hal_i2cdisplaybus_i2cdisplaybus_begin_transaction;
|
||||||
self->send = common_hal_i2cdisplaybus_i2cdisplaybus_send;
|
self->send = common_hal_i2cdisplaybus_i2cdisplaybus_send;
|
||||||
self->end_transaction = common_hal_i2cdisplaybus_i2cdisplaybus_end_transaction;
|
self->end_transaction = common_hal_i2cdisplaybus_i2cdisplaybus_end_transaction;
|
||||||
|
self->collect_ptrs = common_hal_i2cdisplaybus_i2cdisplaybus_collect_ptrs;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -231,3 +234,7 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d
|
||||||
displayio_display_bus_end_transaction(self);
|
displayio_display_bus_end_transaction(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void displayio_display_bus_collect_ptrs(displayio_display_bus_t *self) {
|
||||||
|
self->collect_ptrs(self->bus);
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ typedef struct {
|
||||||
display_bus_begin_transaction begin_transaction;
|
display_bus_begin_transaction begin_transaction;
|
||||||
display_bus_send send;
|
display_bus_send send;
|
||||||
display_bus_end_transaction end_transaction;
|
display_bus_end_transaction end_transaction;
|
||||||
|
display_bus_collect_ptrs collect_ptrs;
|
||||||
uint16_t ram_width;
|
uint16_t ram_width;
|
||||||
uint16_t ram_height;
|
uint16_t ram_height;
|
||||||
int16_t colstart;
|
int16_t colstart;
|
||||||
|
|
|
@ -504,6 +504,7 @@ void epaperdisplay_epaperdisplay_reset(epaperdisplay_epaperdisplay_obj_t *self)
|
||||||
|
|
||||||
void epaperdisplay_epaperdisplay_collect_ptrs(epaperdisplay_epaperdisplay_obj_t *self) {
|
void epaperdisplay_epaperdisplay_collect_ptrs(epaperdisplay_epaperdisplay_obj_t *self) {
|
||||||
displayio_display_core_collect_ptrs(&self->core);
|
displayio_display_core_collect_ptrs(&self->core);
|
||||||
|
displayio_display_bus_collect_ptrs(&self->bus);
|
||||||
gc_collect_ptr((void *)self->start_sequence);
|
gc_collect_ptr((void *)self->start_sequence);
|
||||||
gc_collect_ptr((void *)self->stop_sequence);
|
gc_collect_ptr((void *)self->stop_sequence);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,9 +42,6 @@ void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self,
|
||||||
|
|
||||||
self->bus = spi;
|
self->bus = spi;
|
||||||
common_hal_busio_spi_never_reset(self->bus);
|
common_hal_busio_spi_never_reset(self->bus);
|
||||||
// Our object is statically allocated off the heap so make sure the bus object lives to the end
|
|
||||||
// of the heap as well.
|
|
||||||
gc_never_free(self->bus);
|
|
||||||
|
|
||||||
self->frequency = baudrate;
|
self->frequency = baudrate;
|
||||||
self->polarity = polarity;
|
self->polarity = polarity;
|
||||||
|
@ -176,3 +173,8 @@ void common_hal_fourwire_fourwire_end_transaction(mp_obj_t obj) {
|
||||||
common_hal_digitalio_digitalinout_set_value(&self->chip_select, true);
|
common_hal_digitalio_digitalinout_set_value(&self->chip_select, true);
|
||||||
common_hal_busio_spi_unlock(self->bus);
|
common_hal_busio_spi_unlock(self->bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void common_hal_fourwire_fourwire_collect_ptrs(mp_obj_t obj) {
|
||||||
|
fourwire_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj);
|
||||||
|
gc_collect_ptr((void *)self->bus);
|
||||||
|
}
|
||||||
|
|
|
@ -61,9 +61,6 @@ void common_hal_i2cdisplaybus_i2cdisplaybus_construct(i2cdisplaybus_i2cdisplaybu
|
||||||
// Write to the device and return 0 on success or an appropriate error code from mperrno.h
|
// Write to the device and return 0 on success or an appropriate error code from mperrno.h
|
||||||
self->bus = i2c;
|
self->bus = i2c;
|
||||||
common_hal_busio_i2c_never_reset(self->bus);
|
common_hal_busio_i2c_never_reset(self->bus);
|
||||||
// Our object is statically allocated off the heap so make sure the bus object lives to the end
|
|
||||||
// of the heap as well.
|
|
||||||
gc_never_free(self->bus);
|
|
||||||
|
|
||||||
self->address = device_address;
|
self->address = device_address;
|
||||||
}
|
}
|
||||||
|
@ -72,6 +69,10 @@ void common_hal_i2cdisplaybus_i2cdisplaybus_deinit(i2cdisplaybus_i2cdisplaybus_o
|
||||||
if (self->bus == &self->inline_bus) {
|
if (self->bus == &self->inline_bus) {
|
||||||
common_hal_busio_i2c_deinit(self->bus);
|
common_hal_busio_i2c_deinit(self->bus);
|
||||||
}
|
}
|
||||||
|
// TODO figure out how to undo never_reset. maybe only mark never_reset when
|
||||||
|
// we subsume objects off the mp heap.
|
||||||
|
|
||||||
|
self->bus = NULL;
|
||||||
|
|
||||||
if (self->reset.base.type == &digitalio_digitalinout_type) {
|
if (self->reset.base.type == &digitalio_digitalinout_type) {
|
||||||
common_hal_digitalio_digitalinout_deinit(&self->reset);
|
common_hal_digitalio_digitalinout_deinit(&self->reset);
|
||||||
|
@ -126,3 +127,8 @@ void common_hal_i2cdisplaybus_i2cdisplaybus_end_transaction(mp_obj_t obj) {
|
||||||
i2cdisplaybus_i2cdisplaybus_obj_t *self = MP_OBJ_TO_PTR(obj);
|
i2cdisplaybus_i2cdisplaybus_obj_t *self = MP_OBJ_TO_PTR(obj);
|
||||||
common_hal_busio_i2c_unlock(self->bus);
|
common_hal_busio_i2c_unlock(self->bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void common_hal_i2cdisplaybus_i2cdisplaybus_collect_ptrs(mp_obj_t obj) {
|
||||||
|
i2cdisplaybus_i2cdisplaybus_obj_t *self = MP_OBJ_TO_PTR(obj);
|
||||||
|
gc_collect_ptr((void *)self->bus);
|
||||||
|
}
|
||||||
|
|
|
@ -32,14 +32,14 @@
|
||||||
#include "py/objproperty.h"
|
#include "py/objproperty.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
|
||||||
#include "shared-module/is31fl3741/allocator.h"
|
|
||||||
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
#include "shared-bindings/is31fl3741/IS31FL3741.h"
|
||||||
#include "shared-bindings/is31fl3741/FrameBuffer.h"
|
#include "shared-bindings/is31fl3741/FrameBuffer.h"
|
||||||
#include "shared-bindings/util.h"
|
#include "shared-bindings/util.h"
|
||||||
#include "shared-module/framebufferio/FramebufferDisplay.h"
|
#include "shared-module/framebufferio/FramebufferDisplay.h"
|
||||||
#include "shared-bindings/busio/I2C.h"
|
#include "shared-bindings/busio/I2C.h"
|
||||||
|
#include "supervisor/port.h"
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *self, int width, int height, mp_obj_t framebuffer, is31fl3741_IS31FL3741_obj_t *is31, mp_obj_t mapping) {
|
void common_hal_is31fl3741_framebuffer_construct(is31fl3741_framebuffer_obj_t *self, int width, int height, mp_obj_t framebuffer, is31fl3741_IS31FL3741_obj_t *is31, mp_obj_t mapping) {
|
||||||
self->width = width;
|
self->width = width;
|
||||||
self->height = height;
|
self->height = height;
|
||||||
|
|
||||||
|
@ -48,10 +48,6 @@ void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *s
|
||||||
self->is31fl3741 = is31;
|
self->is31fl3741 = is31;
|
||||||
|
|
||||||
common_hal_busio_i2c_never_reset(self->is31fl3741->i2c);
|
common_hal_busio_i2c_never_reset(self->is31fl3741->i2c);
|
||||||
// Our object is statically allocated off the heap so make sure the bus object lives to the end
|
|
||||||
// of the heap as well.
|
|
||||||
gc_never_free(self->is31fl3741->i2c);
|
|
||||||
gc_never_free(self->is31fl3741);
|
|
||||||
|
|
||||||
mp_obj_t *items;
|
mp_obj_t *items;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
@ -61,7 +57,10 @@ void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *s
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("LED mappings must match display size"));
|
mp_raise_ValueError(MP_ERROR_TEXT("LED mappings must match display size"));
|
||||||
}
|
}
|
||||||
|
|
||||||
self->mapping = common_hal_is31fl3741_allocator_impl(sizeof(uint16_t) * len);
|
self->mapping = port_malloc(sizeof(uint16_t) * len, false);
|
||||||
|
if (self->mapping == NULL) {
|
||||||
|
m_malloc_fail(sizeof(uint16_t) * len);
|
||||||
|
}
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
mp_int_t value = mp_obj_get_int(items[i]);
|
mp_int_t value = mp_obj_get_int(items[i]);
|
||||||
// We only store up to 16 bits
|
// We only store up to 16 bits
|
||||||
|
@ -71,10 +70,10 @@ void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *s
|
||||||
self->mapping[i] = (uint16_t)value;
|
self->mapping[i] = (uint16_t)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
common_hal_is31fl3741_FrameBuffer_reconstruct(self, framebuffer);
|
common_hal_is31fl3741_framebuffer_reconstruct(self, framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_reconstruct(is31fl3741_FrameBuffer_obj_t *self, mp_obj_t framebuffer) {
|
void common_hal_is31fl3741_framebuffer_reconstruct(is31fl3741_framebuffer_obj_t *self, mp_obj_t framebuffer) {
|
||||||
self->paused = 1;
|
self->paused = 1;
|
||||||
|
|
||||||
if (framebuffer) {
|
if (framebuffer) {
|
||||||
|
@ -89,10 +88,15 @@ void common_hal_is31fl3741_FrameBuffer_reconstruct(is31fl3741_FrameBuffer_obj_t
|
||||||
// verify that the matrix is big enough
|
// verify that the matrix is big enough
|
||||||
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
|
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
|
||||||
} else {
|
} else {
|
||||||
common_hal_is31fl3741_free_impl(self->bufinfo.buf);
|
if (self->framebuffer == NULL && self->bufinfo.buf != NULL) {
|
||||||
|
port_free(self->bufinfo.buf);
|
||||||
|
}
|
||||||
|
|
||||||
self->framebuffer = NULL;
|
self->framebuffer = NULL;
|
||||||
self->bufinfo.buf = common_hal_is31fl3741_allocator_impl(self->bufsize);
|
self->bufinfo.buf = port_malloc(self->bufsize, false);
|
||||||
|
if (self->bufinfo.buf == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self->bufinfo.len = self->bufsize;
|
self->bufinfo.len = self->bufsize;
|
||||||
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
||||||
}
|
}
|
||||||
|
@ -112,14 +116,18 @@ void common_hal_is31fl3741_FrameBuffer_reconstruct(is31fl3741_FrameBuffer_obj_t
|
||||||
self->paused = 0;
|
self->paused = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_deinit(is31fl3741_FrameBuffer_obj_t *self) {
|
void common_hal_is31fl3741_framebuffer_deinit(is31fl3741_framebuffer_obj_t *self) {
|
||||||
common_hal_is31fl3741_end_transaction(self->is31fl3741); // in case we still had a lock
|
common_hal_is31fl3741_end_transaction(self->is31fl3741); // in case we still had a lock
|
||||||
|
|
||||||
common_hal_is31fl3741_IS31FL3741_deinit(self->is31fl3741);
|
common_hal_is31fl3741_IS31FL3741_deinit(self->is31fl3741);
|
||||||
|
|
||||||
if (self->mapping != 0) {
|
if (self->mapping != NULL) {
|
||||||
common_hal_is31fl3741_free_impl(self->mapping);
|
port_free(self->mapping);
|
||||||
self->mapping = 0;
|
self->mapping = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->framebuffer == NULL && self->bufinfo.buf != NULL) {
|
||||||
|
port_free(self->bufinfo.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->base.type = NULL;
|
self->base.type = NULL;
|
||||||
|
@ -129,15 +137,15 @@ void common_hal_is31fl3741_FrameBuffer_deinit(is31fl3741_FrameBuffer_obj_t *self
|
||||||
self->framebuffer = NULL;
|
self->framebuffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_set_paused(is31fl3741_FrameBuffer_obj_t *self, bool paused) {
|
void common_hal_is31fl3741_framebuffer_set_paused(is31fl3741_framebuffer_obj_t *self, bool paused) {
|
||||||
self->paused = paused;
|
self->paused = paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_is31fl3741_FrameBuffer_get_paused(is31fl3741_FrameBuffer_obj_t *self) {
|
bool common_hal_is31fl3741_framebuffer_get_paused(is31fl3741_framebuffer_obj_t *self) {
|
||||||
return self->paused;
|
return self->paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_is31fl3741_FrameBuffer_refresh(is31fl3741_FrameBuffer_obj_t *self, uint8_t *dirtyrows) {
|
void common_hal_is31fl3741_framebuffer_refresh(is31fl3741_framebuffer_obj_t *self, uint8_t *dirtyrows) {
|
||||||
if (!self->paused) {
|
if (!self->paused) {
|
||||||
common_hal_is31fl3741_begin_transaction(self->is31fl3741);
|
common_hal_is31fl3741_begin_transaction(self->is31fl3741);
|
||||||
|
|
||||||
|
@ -205,24 +213,16 @@ void common_hal_is31fl3741_FrameBuffer_refresh(is31fl3741_FrameBuffer_obj_t *sel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int common_hal_is31fl3741_FrameBuffer_get_width(is31fl3741_FrameBuffer_obj_t *self) {
|
int common_hal_is31fl3741_framebuffer_get_width(is31fl3741_framebuffer_obj_t *self) {
|
||||||
return self->width;
|
return self->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
int common_hal_is31fl3741_FrameBuffer_get_height(is31fl3741_FrameBuffer_obj_t *self) {
|
int common_hal_is31fl3741_framebuffer_get_height(is31fl3741_framebuffer_obj_t *self) {
|
||||||
return self->height;
|
return self->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *common_hal_is31fl3741_allocator_impl(size_t sz) {
|
void is31fl3741_framebuffer_collect_ptrs(is31fl3741_framebuffer_obj_t *self) {
|
||||||
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true);
|
|
||||||
return allocation ? allocation->ptr : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_hal_is31fl3741_free_impl(void *ptr_in) {
|
|
||||||
free_memory(allocation_from_ptr(ptr_in));
|
|
||||||
}
|
|
||||||
|
|
||||||
void is31fl3741_FrameBuffer_collect_ptrs(is31fl3741_FrameBuffer_obj_t *self) {
|
|
||||||
gc_collect_ptr(self->framebuffer);
|
gc_collect_ptr(self->framebuffer);
|
||||||
gc_collect_ptr(self->mapping);
|
gc_collect_ptr(self->is31fl3741->i2c);
|
||||||
|
gc_collect_ptr(self->is31fl3741);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include "lib/protomatter/src/core.h"
|
#include "lib/protomatter/src/core.h"
|
||||||
#include "shared-module/is31fl3741/IS31FL3741.h"
|
#include "shared-module/is31fl3741/IS31FL3741.h"
|
||||||
|
|
||||||
extern const mp_obj_type_t is31fl3741_FrameBuffer_type;
|
extern const mp_obj_type_t is31fl3741_framebuffer_type;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
is31fl3741_IS31FL3741_obj_t *is31fl3741;
|
is31fl3741_IS31FL3741_obj_t *is31fl3741;
|
||||||
|
@ -43,4 +43,4 @@ typedef struct {
|
||||||
bool paused;
|
bool paused;
|
||||||
bool scale;
|
bool scale;
|
||||||
bool auto_gamma;
|
bool auto_gamma;
|
||||||
} is31fl3741_FrameBuffer_obj_t;
|
} is31fl3741_framebuffer_obj_t;
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
#include "py/parsenum.h"
|
#include "py/parsenum.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "supervisor/filesystem.h"
|
#include "supervisor/filesystem.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
#define GETENV_PATH "/settings.toml"
|
#define GETENV_PATH "/settings.toml"
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,12 @@
|
||||||
|
|
||||||
// If non-sequential pins aren't supported, then this default (weak)
|
// If non-sequential pins aren't supported, then this default (weak)
|
||||||
// implementation will raise an exception for you.
|
// implementation will raise an exception for you.
|
||||||
__attribute__((weak))
|
MP_WEAK void common_hal_paralleldisplaybus_parallelbus_construct_nonsequential(paralleldisplaybus_parallelbus_obj_t *self,
|
||||||
void common_hal_paralleldisplaybus_parallelbus_construct_nonsequential(paralleldisplaybus_parallelbus_obj_t *self,
|
|
||||||
uint8_t n_pins, const mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select,
|
uint8_t n_pins, const mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select,
|
||||||
const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency) {
|
const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency) {
|
||||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("This microcontroller only supports data0=, not data_pins=, because it requires contiguous pins."));
|
mp_raise_NotImplementedError(MP_ERROR_TEXT("This microcontroller only supports data0=, not data_pins=, because it requires contiguous pins."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MP_WEAK void common_hal_paralleldisplaybus_parallelbus_collect_ptrs(mp_obj_t self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -79,12 +79,11 @@ STATIC void common_hal_rgbmatrix_rgbmatrix_construct1(rgbmatrix_rgbmatrix_obj_t
|
||||||
}
|
}
|
||||||
// verify that the matrix is big enough
|
// verify that the matrix is big enough
|
||||||
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
|
mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize - 1), false);
|
||||||
self->allocation = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
// The supervisor allocation can move memory by changing self->allocation->ptr.
|
self->bufinfo.buf = port_malloc(self->bufsize, false);
|
||||||
// So we hold onto it and update bufinfo every time we use it.
|
if (self->bufinfo.buf == NULL) {
|
||||||
self->allocation = allocate_memory(align32_size(self->bufsize), false, true);
|
m_malloc_fail(self->bufsize);
|
||||||
self->bufinfo.buf = self->allocation->ptr;
|
}
|
||||||
self->bufinfo.len = self->bufsize;
|
self->bufinfo.len = self->bufsize;
|
||||||
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
||||||
}
|
}
|
||||||
|
@ -150,9 +149,7 @@ STATIC void free_pin_seq(uint8_t *seq, int count) {
|
||||||
|
|
||||||
extern int pm_row_count;
|
extern int pm_row_count;
|
||||||
STATIC void common_hal_rgbmatrix_rgbmatrix_deinit1(rgbmatrix_rgbmatrix_obj_t *self) {
|
STATIC void common_hal_rgbmatrix_rgbmatrix_deinit1(rgbmatrix_rgbmatrix_obj_t *self) {
|
||||||
if (self->timer != NULL) {
|
common_hal_rgbmatrix_timer_disable(self->timer);
|
||||||
common_hal_rgbmatrix_timer_disable(self->timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_PM_protoPtr == &self->protomatter) {
|
if (_PM_protoPtr == &self->protomatter) {
|
||||||
_PM_protoPtr = NULL;
|
_PM_protoPtr = NULL;
|
||||||
|
@ -166,15 +163,14 @@ STATIC void common_hal_rgbmatrix_rgbmatrix_deinit1(rgbmatrix_rgbmatrix_obj_t *se
|
||||||
|
|
||||||
// If it was supervisor-allocated, it is supervisor-freed and the pointer
|
// If it was supervisor-allocated, it is supervisor-freed and the pointer
|
||||||
// is zeroed, otherwise the pointer is just zeroed
|
// is zeroed, otherwise the pointer is just zeroed
|
||||||
if (self->allocation != NULL) {
|
if (self->framebuffer == mp_const_none) {
|
||||||
free_memory(self->allocation);
|
port_free(self->bufinfo.buf);
|
||||||
}
|
}
|
||||||
|
self->bufinfo.buf = NULL;
|
||||||
|
|
||||||
// If a framebuffer was passed in to the constructor, clear the reference
|
// If a framebuffer was passed in to the constructor, clear the reference
|
||||||
// here so that it will become GC'able
|
// here so that it will become GC'able
|
||||||
self->framebuffer = mp_const_none;
|
self->framebuffer = mp_const_none;
|
||||||
|
|
||||||
self->bufinfo.buf = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t *self) {
|
void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t *self) {
|
||||||
|
@ -194,21 +190,22 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t *self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_rgbmatrix_rgbmatrix_get_bufinfo(rgbmatrix_rgbmatrix_obj_t *self, mp_buffer_info_t *bufinfo) {
|
void common_hal_rgbmatrix_rgbmatrix_get_bufinfo(rgbmatrix_rgbmatrix_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||||
if (self->allocation != NULL) {
|
|
||||||
self->bufinfo.buf = self->allocation->ptr;
|
|
||||||
}
|
|
||||||
*bufinfo = self->bufinfo;
|
*bufinfo = self->bufinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t *self) {
|
void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t *self) {
|
||||||
|
common_hal_rgbmatrix_rgbmatrix_set_paused(self, true);
|
||||||
|
// Stop using any Python provided framebuffer.
|
||||||
if (self->framebuffer != mp_const_none) {
|
if (self->framebuffer != mp_const_none) {
|
||||||
memset(&self->bufinfo, 0, sizeof(self->bufinfo));
|
memset(&self->bufinfo, 0, sizeof(self->bufinfo));
|
||||||
|
self->bufinfo.buf = port_malloc(self->bufsize, false);
|
||||||
|
if (self->bufinfo.buf == NULL) {
|
||||||
|
common_hal_rgbmatrix_rgbmatrix_deinit(self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self->bufinfo.len = self->bufsize;
|
||||||
|
self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW;
|
||||||
}
|
}
|
||||||
#if CIRCUITPY_RGBMATRIX_USES_SUPERVISOR_ALLOCATION
|
|
||||||
common_hal_rgbmatrix_rgbmatrix_set_paused(self, true);
|
|
||||||
common_hal_rgbmatrix_rgbmatrix_deinit1(self);
|
|
||||||
common_hal_rgbmatrix_rgbmatrix_construct1(self, mp_const_none);
|
|
||||||
#endif
|
|
||||||
memset(self->bufinfo.buf, 0, self->bufinfo.len);
|
memset(self->bufinfo.buf, 0, self->bufinfo.len);
|
||||||
common_hal_rgbmatrix_rgbmatrix_set_paused(self, false);
|
common_hal_rgbmatrix_rgbmatrix_set_paused(self, false);
|
||||||
}
|
}
|
||||||
|
@ -222,9 +219,6 @@ void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t *self,
|
||||||
_PM_stop(&self->protomatter);
|
_PM_stop(&self->protomatter);
|
||||||
} else if (!paused && self->paused) {
|
} else if (!paused && self->paused) {
|
||||||
_PM_resume(&self->protomatter);
|
_PM_resume(&self->protomatter);
|
||||||
if (self->allocation) {
|
|
||||||
self->bufinfo.buf = self->allocation->ptr;
|
|
||||||
}
|
|
||||||
_PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width);
|
_PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width);
|
||||||
_PM_swapbuffer_maybe(&self->protomatter);
|
_PM_swapbuffer_maybe(&self->protomatter);
|
||||||
}
|
}
|
||||||
|
@ -237,9 +231,6 @@ bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t *self)
|
||||||
|
|
||||||
void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t *self) {
|
void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t *self) {
|
||||||
if (!self->paused) {
|
if (!self->paused) {
|
||||||
if (self->allocation != NULL) {
|
|
||||||
self->bufinfo.buf = self->allocation->ptr;
|
|
||||||
}
|
|
||||||
_PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width);
|
_PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width);
|
||||||
_PM_swapbuffer_maybe(&self->protomatter);
|
_PM_swapbuffer_maybe(&self->protomatter);
|
||||||
}
|
}
|
||||||
|
@ -253,44 +244,3 @@ int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t *self) {
|
||||||
int computed_height = (self->rgb_count / 3) * (1 << (self->addr_count)) * self->tile;
|
int computed_height = (self->rgb_count / 3) * (1 << (self->addr_count)) * self->tile;
|
||||||
return computed_height;
|
return computed_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track the returned pointers and their matching allocation so that we can free
|
|
||||||
// them even when the memory was moved by the supervisor. This prevents leaks
|
|
||||||
// but doesn't protect against the memory being used after its been freed! The
|
|
||||||
// long term fix is to utilize a permanent heap that can be shared with MP's
|
|
||||||
// split heap.
|
|
||||||
typedef struct matrix_allocation {
|
|
||||||
void *original_pointer;
|
|
||||||
supervisor_allocation *allocation;
|
|
||||||
} matrix_allocation_t;
|
|
||||||
|
|
||||||
// Four should be more than we ever need. ProtoMatter does 3 allocations currently.
|
|
||||||
static matrix_allocation_t allocations[4];
|
|
||||||
|
|
||||||
void *common_hal_rgbmatrix_allocator_impl(size_t sz) {
|
|
||||||
supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true);
|
|
||||||
if (allocation == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < sizeof(allocations); i++) {
|
|
||||||
matrix_allocation_t *matrix_allocation = &allocations[i];
|
|
||||||
if (matrix_allocation->original_pointer == NULL) {
|
|
||||||
matrix_allocation->original_pointer = allocation->ptr;
|
|
||||||
matrix_allocation->allocation = allocation;
|
|
||||||
return allocation->ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_hal_rgbmatrix_free_impl(void *ptr_in) {
|
|
||||||
for (size_t i = 0; i < sizeof(allocations); i++) {
|
|
||||||
matrix_allocation_t *matrix_allocation = &allocations[i];
|
|
||||||
if (matrix_allocation->original_pointer == ptr_in) {
|
|
||||||
matrix_allocation->original_pointer = NULL;
|
|
||||||
free_memory(matrix_allocation->allocation);
|
|
||||||
matrix_allocation->allocation = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,14 +28,12 @@
|
||||||
|
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "lib/protomatter/src/core.h"
|
#include "lib/protomatter/src/core.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
extern const mp_obj_type_t rgbmatrix_RGBMatrix_type;
|
extern const mp_obj_type_t rgbmatrix_RGBMatrix_type;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_obj_t framebuffer;
|
mp_obj_t framebuffer;
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
supervisor_allocation *allocation;
|
|
||||||
Protomatter_core protomatter;
|
Protomatter_core protomatter;
|
||||||
void *timer;
|
void *timer;
|
||||||
uint16_t bufsize, width;
|
uint16_t bufsize, width;
|
||||||
|
|
|
@ -29,17 +29,13 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "py/gc.h"
|
#include "py/gc.h"
|
||||||
#include "py/misc.h"
|
#include "py/misc.h"
|
||||||
#include "supervisor/memory.h"
|
#include "supervisor/port.h"
|
||||||
|
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
// Use DMA-capable RAM (not PSRAM) for framebuffer:
|
|
||||||
#include "components/heap/include/esp_heap_caps.h"
|
#include "components/heap/include/esp_heap_caps.h"
|
||||||
#define _PM_allocate(x) heap_caps_malloc(x, MALLOC_CAP_DMA | MALLOC_CAP_8BIT)
|
#define _PM_allocate(x) heap_caps_malloc(x, MALLOC_CAP_DMA | MALLOC_CAP_8BIT)
|
||||||
#define _PM_free(x) heap_caps_free(x)
|
#define _PM_free(x) heap_caps_free(x)
|
||||||
#else
|
#else
|
||||||
#define _PM_allocate common_hal_rgbmatrix_allocator_impl
|
#define _PM_allocate(x) port_malloc(x, true)
|
||||||
#define _PM_free(x) (common_hal_rgbmatrix_free_impl((x)), (x) = NULL, (void)0)
|
#define _PM_free(x) port_free(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void *common_hal_rgbmatrix_allocator_impl(size_t sz);
|
|
||||||
extern void common_hal_rgbmatrix_free_impl(void *);
|
|
||||||
|
|
|
@ -32,8 +32,7 @@
|
||||||
#include "shared-bindings/microcontroller/Pin.h"
|
#include "shared-bindings/microcontroller/Pin.h"
|
||||||
#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
|
#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
|
||||||
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
|
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
|
||||||
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
#define SHARPMEM_BIT_WRITECMD_LSB (0x80)
|
#define SHARPMEM_BIT_WRITECMD_LSB (0x80)
|
||||||
#define JDI_BIT_WRITECMD_LSB (0x90)
|
#define JDI_BIT_WRITECMD_LSB (0x90)
|
||||||
|
@ -86,9 +85,6 @@ void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *s
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) {
|
void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) {
|
||||||
// Look up the allocation by the old pointer and get the new pointer from it.
|
|
||||||
supervisor_allocation *alloc = allocation_from_ptr(self->bufinfo.buf);
|
|
||||||
self->bufinfo.buf = alloc ? alloc->ptr : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) {
|
void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||||
|
@ -96,12 +92,11 @@ void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_ob
|
||||||
int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self);
|
int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self);
|
||||||
int height = common_hal_sharpdisplay_framebuffer_get_height(self);
|
int height = common_hal_sharpdisplay_framebuffer_get_height(self);
|
||||||
self->bufinfo.len = row_stride * height + 2;
|
self->bufinfo.len = row_stride * height + 2;
|
||||||
supervisor_allocation *alloc = allocate_memory(align32_size(self->bufinfo.len), false, true);
|
self->bufinfo.buf = port_malloc(self->bufinfo.len, false);
|
||||||
if (alloc == NULL) {
|
if (self->bufinfo.buf == NULL) {
|
||||||
m_malloc_fail(self->bufinfo.len);
|
m_malloc_fail(self->bufinfo.len);
|
||||||
}
|
}
|
||||||
self->bufinfo.buf = alloc->ptr;
|
memset(self->bufinfo.buf, 0, self->bufinfo.len);
|
||||||
memset(alloc->ptr, 0, self->bufinfo.len);
|
|
||||||
|
|
||||||
uint8_t *data = self->bufinfo.buf;
|
uint8_t *data = self->bufinfo.buf;
|
||||||
if (self->jdi_display) {
|
if (self->jdi_display) {
|
||||||
|
@ -136,7 +131,7 @@ void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *
|
||||||
|
|
||||||
common_hal_reset_pin(self->chip_select.pin);
|
common_hal_reset_pin(self->chip_select.pin);
|
||||||
|
|
||||||
free_memory(allocation_from_ptr(self->bufinfo.buf));
|
port_free(self->bufinfo.buf);
|
||||||
|
|
||||||
memset(self, 0, sizeof(*self));
|
memset(self, 0, sizeof(*self));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,3 +35,12 @@ supervisor_status_bar_obj_t shared_module_supervisor_status_bar_obj = {
|
||||||
.type = &supervisor_status_bar_type,
|
.type = &supervisor_status_bar_type,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// String of the last traceback.
|
||||||
|
char *prev_traceback_string = NULL;
|
||||||
|
|
||||||
|
// Custom settings for next code run.
|
||||||
|
supervisor_next_code_info_t *next_code_configuration = NULL;
|
||||||
|
|
||||||
|
// Custom USB settings.
|
||||||
|
usb_identification_t *custom_usb_identification = NULL;
|
||||||
|
|
|
@ -36,8 +36,7 @@
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
|
|
||||||
#if CIRCUITPY_USB_VENDOR
|
#if CIRCUITPY_USB_VENDOR
|
||||||
// todo - this doesn't feel like it should be here.
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_CDC != 2
|
#if CFG_TUD_CDC != 2
|
||||||
|
@ -370,27 +369,25 @@ size_t usb_vendor_descriptor_length(void) {
|
||||||
return sizeof(usb_vendor_descriptor_template);
|
return sizeof(usb_vendor_descriptor_template);
|
||||||
}
|
}
|
||||||
|
|
||||||
static supervisor_allocation *ms_os_20_descriptor_allocation;
|
static uint8_t *ms_os_20_descriptor = NULL;
|
||||||
|
|
||||||
size_t vendor_ms_os_20_descriptor_length() {
|
size_t vendor_ms_os_20_descriptor_length() {
|
||||||
return sizeof(ms_os_20_descriptor_template);
|
return ms_os_20_descriptor != NULL ? sizeof(ms_os_20_descriptor_template) : 0;
|
||||||
}
|
}
|
||||||
uint8_t const *vendor_ms_os_20_descriptor() {
|
uint8_t const *vendor_ms_os_20_descriptor() {
|
||||||
return (uint8_t *)ms_os_20_descriptor_allocation->ptr;
|
return ms_os_20_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t usb_vendor_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) {
|
size_t usb_vendor_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) {
|
||||||
|
if (ms_os_20_descriptor == NULL) {
|
||||||
if (ms_os_20_descriptor_template[MS_OS_20_ITF_NUM_OFFSET] == MS_OS_20_ITF_NUM_MAGIC) {
|
ms_os_20_descriptor = port_malloc(sizeof(ms_os_20_descriptor_template), false);
|
||||||
ms_os_20_descriptor_allocation =
|
if (ms_os_20_descriptor == NULL) {
|
||||||
allocate_memory(align32_size(sizeof(ms_os_20_descriptor_template)),
|
return 0;
|
||||||
/*high_address*/ false, /*movable*/ false);
|
}
|
||||||
uint8_t *ms_os_20_descriptor_buf = (uint8_t *)ms_os_20_descriptor_allocation->ptr;
|
memcpy(ms_os_20_descriptor, ms_os_20_descriptor_template, sizeof(ms_os_20_descriptor_template));
|
||||||
memcpy(ms_os_20_descriptor_buf, ms_os_20_descriptor_template, sizeof(ms_os_20_descriptor_template));
|
ms_os_20_descriptor[MS_OS_20_ITF_NUM_OFFSET] = descriptor_counts->current_interface;
|
||||||
ms_os_20_descriptor_buf[MS_OS_20_ITF_NUM_OFFSET] = descriptor_counts->current_interface;
|
ms_os_20_descriptor[VENDOR_IN_ENDPOINT_INDEX] = 0x80 | descriptor_counts->current_endpoint;
|
||||||
ms_os_20_descriptor_buf[VENDOR_IN_ENDPOINT_INDEX] = 0x80 | descriptor_counts->current_endpoint;
|
ms_os_20_descriptor[VENDOR_OUT_ENDPOINT_INDEX] = descriptor_counts->current_endpoint;
|
||||||
ms_os_20_descriptor_buf[VENDOR_OUT_ENDPOINT_INDEX] = descriptor_counts->current_endpoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(descriptor_buf, usb_vendor_descriptor_template, sizeof(usb_vendor_descriptor_template));
|
memcpy(descriptor_buf, usb_vendor_descriptor_template, sizeof(usb_vendor_descriptor_template));
|
||||||
|
@ -411,7 +408,4 @@ size_t usb_vendor_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *d
|
||||||
return sizeof(usb_vendor_descriptor_template);
|
return sizeof(usb_vendor_descriptor_template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "shared-bindings/usb_hid/__init__.h"
|
#include "shared-bindings/usb_hid/__init__.h"
|
||||||
#include "shared-bindings/usb_hid/Device.h"
|
#include "shared-bindings/usb_hid/Device.h"
|
||||||
#include "supervisor/memory.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/usb.h"
|
#include "supervisor/usb.h"
|
||||||
|
|
||||||
static const uint8_t usb_hid_descriptor_template[] = {
|
static const uint8_t usb_hid_descriptor_template[] = {
|
||||||
|
@ -78,7 +78,7 @@ static const uint8_t usb_hid_descriptor_template[] = {
|
||||||
|
|
||||||
#define MAX_HID_DEVICES 8
|
#define MAX_HID_DEVICES 8
|
||||||
|
|
||||||
static supervisor_allocation *hid_report_descriptor_allocation;
|
static uint8_t *hid_report_descriptor = NULL;
|
||||||
static usb_hid_device_obj_t hid_devices[MAX_HID_DEVICES];
|
static usb_hid_device_obj_t hid_devices[MAX_HID_DEVICES];
|
||||||
// If 0, USB HID is disabled.
|
// If 0, USB HID is disabled.
|
||||||
static mp_int_t num_hid_devices;
|
static mp_int_t num_hid_devices;
|
||||||
|
@ -270,12 +270,17 @@ size_t usb_hid_report_descriptor_length(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the combined HID report descriptor in the given space.
|
// Build the combined HID report descriptor in the given space.
|
||||||
void usb_hid_build_report_descriptor(uint8_t *report_descriptor_space, size_t report_descriptor_length) {
|
void usb_hid_build_report_descriptor(void) {
|
||||||
if (!usb_hid_enabled()) {
|
if (!usb_hid_enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
size_t report_length = usb_hid_report_descriptor_length();
|
||||||
|
hid_report_descriptor = port_malloc(report_length, false);
|
||||||
|
if (hid_report_descriptor == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *report_descriptor_start = report_descriptor_space;
|
uint8_t *report_descriptor_start = hid_report_descriptor;
|
||||||
|
|
||||||
for (mp_int_t i = 0; i < num_hid_devices; i++) {
|
for (mp_int_t i = 0; i < num_hid_devices; i++) {
|
||||||
usb_hid_device_obj_t *device = &hid_devices[i];
|
usb_hid_device_obj_t *device = &hid_devices[i];
|
||||||
|
@ -291,23 +296,6 @@ void usb_hid_build_report_descriptor(uint8_t *report_descriptor_space, size_t re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this after the heap and VM are finished.
|
|
||||||
void usb_hid_save_report_descriptor(uint8_t *report_descriptor_space, size_t report_descriptor_length) {
|
|
||||||
if (!usb_hid_enabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate storage that persists across VMs to hold the combined report descriptor.
|
|
||||||
// and to remember the device details.
|
|
||||||
|
|
||||||
// Copy the descriptor from the temporary area to a supervisor storage allocation that
|
|
||||||
// will leave between VM instantiations.
|
|
||||||
hid_report_descriptor_allocation =
|
|
||||||
allocate_memory(align32_size(report_descriptor_length),
|
|
||||||
/*high_address*/ false, /*movable*/ false);
|
|
||||||
memcpy((uint8_t *)hid_report_descriptor_allocation->ptr, report_descriptor_space, report_descriptor_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void usb_hid_gc_collect(void) {
|
void usb_hid_gc_collect(void) {
|
||||||
gc_collect_ptr(hid_devices_tuple);
|
gc_collect_ptr(hid_devices_tuple);
|
||||||
|
|
||||||
|
@ -345,7 +333,7 @@ bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t *
|
||||||
// Application returns pointer to descriptor
|
// Application returns pointer to descriptor
|
||||||
// Descriptor contents must exist long enough for transfer to complete
|
// Descriptor contents must exist long enough for transfer to complete
|
||||||
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
|
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
|
||||||
return (uint8_t *)hid_report_descriptor_allocation->ptr;
|
return (uint8_t *)hid_report_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when we receive a SET_PROTOCOL request.
|
// Callback invoked when we receive a SET_PROTOCOL request.
|
||||||
|
|
|
@ -42,8 +42,7 @@ size_t usb_hid_report_descriptor_length(void);
|
||||||
|
|
||||||
void usb_hid_setup_devices(void);
|
void usb_hid_setup_devices(void);
|
||||||
size_t usb_hid_report_descriptor_length(void);
|
size_t usb_hid_report_descriptor_length(void);
|
||||||
void usb_hid_build_report_descriptor(uint8_t *report_descriptor_space, size_t report_descriptor_length);
|
void usb_hid_build_report_descriptor(void);
|
||||||
void usb_hid_save_report_descriptor(uint8_t *report_descriptor_space, size_t report_descriptor_length);
|
|
||||||
|
|
||||||
bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t **device_out, size_t *id_idx_out);
|
bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t **device_out, size_t *id_idx_out);
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include "py/objtuple.h"
|
#include "py/objtuple.h"
|
||||||
#include "shared-bindings/usb_midi/PortIn.h"
|
#include "shared-bindings/usb_midi/PortIn.h"
|
||||||
#include "shared-bindings/usb_midi/PortOut.h"
|
#include "shared-bindings/usb_midi/PortOut.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "supervisor/usb.h"
|
#include "supervisor/usb.h"
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
|
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the MicroPython project, http://micropython.org/
|
|
||||||
*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Basic allocations outside them for areas such as the VM heap and stack.
|
|
||||||
// supervisor/shared/memory.c has a basic implementation for a continuous chunk of memory. Add it
|
|
||||||
// to a SRC_ in a Makefile to use it.
|
|
||||||
|
|
||||||
#ifndef MICROPY_INCLUDED_SUPERVISOR_MEMORY_H
|
|
||||||
#define MICROPY_INCLUDED_SUPERVISOR_MEMORY_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t *ptr;
|
|
||||||
} supervisor_allocation;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void free_memory(supervisor_allocation *allocation);
|
|
||||||
|
|
||||||
// Find the allocation with the given ptr, NULL if not found. When called from the context of a
|
|
||||||
// supervisor_move_memory() callback, finds the allocation that had that ptr *before* the move, but
|
|
||||||
// the returned allocation already contains the ptr after the move.
|
|
||||||
// When called with NULL, may return either NULL or an unused allocation whose ptr is NULL (this is
|
|
||||||
// a feature used internally in allocate_memory to save code size). Passing the return value to
|
|
||||||
// free_memory() is a permissible no-op in either case.
|
|
||||||
supervisor_allocation *allocation_from_ptr(void *ptr);
|
|
||||||
|
|
||||||
supervisor_allocation *allocate_remaining_memory(void);
|
|
||||||
|
|
||||||
// Allocate a piece of a given length in bytes. If high_address is true then it should be allocated
|
|
||||||
// at a lower address from the top of the stack. Otherwise, addresses will increase starting after
|
|
||||||
// statically allocated memory. If movable is false, memory will be taken from outside the GC heap
|
|
||||||
// and will stay stationary until freed. While the VM is running, this will fail unless a previous
|
|
||||||
// allocation of exactly matching length has recently been freed. If movable is true, memory will be
|
|
||||||
// taken from either outside or inside the GC heap, and when the VM exits, will be moved outside.
|
|
||||||
// The ptr of the returned supervisor_allocation will change at that point. If you need to be
|
|
||||||
// notified of that, add your own callback function at the designated place near the end of
|
|
||||||
// supervisor_move_memory().
|
|
||||||
supervisor_allocation *allocate_memory(uint32_t length, bool high_address, bool movable);
|
|
||||||
|
|
||||||
static inline size_t align32_size(size_t size) {
|
|
||||||
return (size + 3) & ~3;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t get_allocation_length(supervisor_allocation *allocation);
|
|
||||||
|
|
||||||
// Called after the GC heap is freed, transfers movable allocations from the GC heap to the
|
|
||||||
// supervisor heap and compacts the supervisor heap.
|
|
||||||
void supervisor_move_memory(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SUPERVISOR_MEMORY_H
|
|
|
@ -24,12 +24,11 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MICROPY_INCLUDED_SUPERVISOR_PORT_H
|
#pragma once
|
||||||
#define MICROPY_INCLUDED_SUPERVISOR_PORT_H
|
|
||||||
|
|
||||||
#include "py/mpconfig.h"
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "supervisor/shared/safe_mode.h"
|
#include "supervisor/shared/safe_mode.h"
|
||||||
|
|
||||||
// Provided by the linker;
|
// Provided by the linker;
|
||||||
|
@ -43,11 +42,6 @@ extern uint32_t _ebss;
|
||||||
|
|
||||||
safe_mode_t port_init(void);
|
safe_mode_t port_init(void);
|
||||||
|
|
||||||
// If the port does not initialize the heap during port_init(), it must provide
|
|
||||||
// this function which is called after CIRCUITPY is mounted.
|
|
||||||
// If not required, a default (weak) implementation that does nothing is used.
|
|
||||||
safe_mode_t port_heap_init(safe_mode_t);
|
|
||||||
|
|
||||||
// Reset the microcontroller completely.
|
// Reset the microcontroller completely.
|
||||||
void reset_cpu(void) NORETURN;
|
void reset_cpu(void) NORETURN;
|
||||||
|
|
||||||
|
@ -63,9 +57,6 @@ uint32_t *port_stack_get_limit(void);
|
||||||
// Get stack top address
|
// Get stack top address
|
||||||
uint32_t *port_stack_get_top(void);
|
uint32_t *port_stack_get_top(void);
|
||||||
|
|
||||||
// True if stack is not located inside heap (at the top)
|
|
||||||
bool port_has_fixed_stack(void);
|
|
||||||
|
|
||||||
// Get heap bottom address
|
// Get heap bottom address
|
||||||
uint32_t *port_heap_get_bottom(void);
|
uint32_t *port_heap_get_bottom(void);
|
||||||
|
|
||||||
|
@ -137,5 +128,3 @@ void port_boot_info(void);
|
||||||
// Some ports want to mark additional pointers as gc roots.
|
// Some ports want to mark additional pointers as gc roots.
|
||||||
// A default weak implementation is provided that does nothing.
|
// A default weak implementation is provided that does nothing.
|
||||||
void port_gc_collect(void);
|
void port_gc_collect(void);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Micro Python project, http://micropython.org/
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Mark Komus
|
* Copyright (c) 2023 Scott Shawcroft for Adafruit Industries
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -27,9 +27,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "py/gc.h"
|
#include <stddef.h>
|
||||||
#include "py/misc.h"
|
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
extern void *common_hal_is31fl3741_allocator_impl(size_t sz);
|
// Ports provide a heap for allocations that live outside the VM. The VM heap
|
||||||
extern void common_hal_is31fl3741_free_impl(void *);
|
// is allocated into it in split chunks. The supervisor provides a default heap
|
||||||
|
// implementation for ports that don't have one of their own. Allocations done
|
||||||
|
// to the outer heap *must* be explicitly managed. Only VM allocations are garbage
|
||||||
|
// collected.
|
||||||
|
|
||||||
|
// Called after port_init(). Ports can init the heap earlier in `port_init()` if
|
||||||
|
// they need and leave this empty. Splitting this out allows us to provide a weak
|
||||||
|
// implementation to use by default.
|
||||||
|
void port_heap_init(void);
|
||||||
|
|
||||||
|
void *port_malloc(size_t size, bool dma_capable);
|
||||||
|
|
||||||
|
void port_free(void *ptr);
|
||||||
|
|
||||||
|
void port_realloc(void *ptr, size_t size);
|
||||||
|
|
||||||
|
size_t port_heap_get_largest_free_size(void);
|
|
@ -126,7 +126,7 @@ void background_callback_reset() {
|
||||||
background_callback_t *cb = (background_callback_t *)callback_head;
|
background_callback_t *cb = (background_callback_t *)callback_head;
|
||||||
while (cb) {
|
while (cb) {
|
||||||
background_callback_t *next = cb->next;
|
background_callback_t *next = cb->next;
|
||||||
if (!HEAP_PTR((void *)cb)) {
|
if (gc_ptr_on_heap((void *)cb)) {
|
||||||
*previous_next = cb;
|
*previous_next = cb;
|
||||||
previous_next = &cb->next;
|
previous_next = &cb->next;
|
||||||
cb->next = NULL;
|
cb->next = NULL;
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include "shared-bindings/displayio/Group.h"
|
#include "shared-bindings/displayio/Group.h"
|
||||||
#include "shared-bindings/displayio/Palette.h"
|
#include "shared-bindings/displayio/Palette.h"
|
||||||
#include "shared-bindings/displayio/TileGrid.h"
|
#include "shared-bindings/displayio/TileGrid.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
#if CIRCUITPY_RGBMATRIX
|
#if CIRCUITPY_RGBMATRIX
|
||||||
#include "shared-module/displayio/__init__.h"
|
#include "shared-module/displayio/__init__.h"
|
||||||
|
@ -49,6 +48,10 @@
|
||||||
#include "supervisor/shared/status_bar.h"
|
#include "supervisor/shared/status_bar.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_TERMINALIO
|
||||||
|
#include "supervisor/port.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_REPL_LOGO
|
#if CIRCUITPY_REPL_LOGO
|
||||||
extern uint32_t blinka_bitmap_data[];
|
extern uint32_t blinka_bitmap_data[];
|
||||||
extern displayio_bitmap_t blinka_bitmap;
|
extern displayio_bitmap_t blinka_bitmap;
|
||||||
|
@ -56,7 +59,8 @@ extern displayio_bitmap_t blinka_bitmap;
|
||||||
extern displayio_group_t circuitpython_splash;
|
extern displayio_group_t circuitpython_splash;
|
||||||
|
|
||||||
#if CIRCUITPY_TERMINALIO
|
#if CIRCUITPY_TERMINALIO
|
||||||
static supervisor_allocation *tilegrid_tiles = NULL;
|
static uint8_t *tilegrid_tiles = NULL;
|
||||||
|
static size_t tilegrid_tiles_size = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
|
void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
|
||||||
|
@ -89,14 +93,15 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
|
||||||
}
|
}
|
||||||
// Reuse the previous allocation if possible
|
// Reuse the previous allocation if possible
|
||||||
if (tilegrid_tiles) {
|
if (tilegrid_tiles) {
|
||||||
if (get_allocation_length(tilegrid_tiles) != align32_size(total_tiles)) {
|
if (tilegrid_tiles_size != total_tiles) {
|
||||||
free_memory(tilegrid_tiles);
|
port_free(tilegrid_tiles);
|
||||||
tilegrid_tiles = NULL;
|
tilegrid_tiles = NULL;
|
||||||
|
tilegrid_tiles_size = 0;
|
||||||
reset_tiles = true;
|
reset_tiles = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tilegrid_tiles) {
|
if (!tilegrid_tiles) {
|
||||||
tilegrid_tiles = allocate_memory(align32_size(total_tiles), false, true);
|
tilegrid_tiles = port_malloc(total_tiles, false);
|
||||||
reset_tiles = true;
|
reset_tiles = true;
|
||||||
if (!tilegrid_tiles) {
|
if (!tilegrid_tiles) {
|
||||||
return;
|
return;
|
||||||
|
@ -104,8 +109,6 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reset_tiles) {
|
if (reset_tiles) {
|
||||||
uint8_t *tiles = (uint8_t *)tilegrid_tiles->ptr;
|
|
||||||
|
|
||||||
// Adjust the display dimensions to account for scale of the outer group.
|
// Adjust the display dimensions to account for scale of the outer group.
|
||||||
width_px /= scale;
|
width_px /= scale;
|
||||||
height_px /= scale;
|
height_px /= scale;
|
||||||
|
@ -127,7 +130,7 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
|
||||||
// Right align the status bar.
|
// Right align the status bar.
|
||||||
status_bar->x = width_px - status_bar->pixel_width;
|
status_bar->x = width_px - status_bar->pixel_width;
|
||||||
status_bar->top_left_y = 0;
|
status_bar->top_left_y = 0;
|
||||||
status_bar->tiles = tiles;
|
status_bar->tiles = tilegrid_tiles;
|
||||||
status_bar->full_change = true;
|
status_bar->full_change = true;
|
||||||
|
|
||||||
scroll_area->width_in_tiles = width_in_tiles;
|
scroll_area->width_in_tiles = width_in_tiles;
|
||||||
|
@ -141,7 +144,7 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
|
||||||
// Align the scroll area to the bottom so that the newest line isn't cutoff. The top line
|
// Align the scroll area to the bottom so that the newest line isn't cutoff. The top line
|
||||||
// may be clipped by the status bar and that's ok.
|
// may be clipped by the status bar and that's ok.
|
||||||
scroll_area->y = height_px - scroll_area->pixel_height;
|
scroll_area->y = height_px - scroll_area->pixel_height;
|
||||||
scroll_area->tiles = tiles + width_in_tiles;
|
scroll_area->tiles = tilegrid_tiles + width_in_tiles;
|
||||||
scroll_area->full_change = true;
|
scroll_area->full_change = true;
|
||||||
|
|
||||||
common_hal_terminalio_terminal_construct(&supervisor_terminal, scroll_area, &supervisor_terminal_font, status_bar);
|
common_hal_terminalio_terminal_construct(&supervisor_terminal, scroll_area, &supervisor_terminal_font, status_bar);
|
||||||
|
@ -156,8 +159,9 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) {
|
||||||
void supervisor_stop_terminal(void) {
|
void supervisor_stop_terminal(void) {
|
||||||
#if CIRCUITPY_TERMINALIO
|
#if CIRCUITPY_TERMINALIO
|
||||||
if (tilegrid_tiles != NULL) {
|
if (tilegrid_tiles != NULL) {
|
||||||
free_memory(tilegrid_tiles);
|
port_free(tilegrid_tiles);
|
||||||
tilegrid_tiles = NULL;
|
tilegrid_tiles = NULL;
|
||||||
|
tilegrid_tiles_size = 0;
|
||||||
supervisor_terminal_scroll_area_text_grid.tiles = NULL;
|
supervisor_terminal_scroll_area_text_grid.tiles = NULL;
|
||||||
supervisor_terminal_status_bar_text_grid.tiles = NULL;
|
supervisor_terminal_status_bar_text_grid.tiles = NULL;
|
||||||
supervisor_terminal.scroll_area = NULL;
|
supervisor_terminal.scroll_area = NULL;
|
||||||
|
@ -174,37 +178,6 @@ bool supervisor_terminal_started(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void supervisor_display_move_memory(void) {
|
|
||||||
#if CIRCUITPY_TERMINALIO
|
|
||||||
displayio_tilegrid_t *scroll_area = &supervisor_terminal_scroll_area_text_grid;
|
|
||||||
displayio_tilegrid_t *status_bar = &supervisor_terminal_status_bar_text_grid;
|
|
||||||
if (tilegrid_tiles != NULL) {
|
|
||||||
status_bar->tiles = (uint8_t *)tilegrid_tiles->ptr;
|
|
||||||
scroll_area->tiles = (uint8_t *)tilegrid_tiles->ptr + scroll_area->width_in_tiles;
|
|
||||||
} else {
|
|
||||||
scroll_area->tiles = NULL;
|
|
||||||
status_bar->tiles = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
|
|
||||||
#if CIRCUITPY_RGBMATRIX
|
|
||||||
if (display_buses[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
|
|
||||||
rgbmatrix_rgbmatrix_obj_t *pm = &display_buses[i].rgbmatrix;
|
|
||||||
common_hal_rgbmatrix_rgbmatrix_reconstruct(pm);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if CIRCUITPY_SHARPDISPLAY
|
|
||||||
if (display_buses[i].bus_base.type == &sharpdisplay_framebuffer_type) {
|
|
||||||
sharpdisplay_framebuffer_obj_t *sharp = &display_buses[i].sharpdisplay;
|
|
||||||
common_hal_sharpdisplay_framebuffer_reconstruct(sharp);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CIRCUITPY_TERMINALIO
|
#if CIRCUITPY_TERMINALIO
|
||||||
#if CIRCUITPY_REPL_LOGO
|
#if CIRCUITPY_REPL_LOGO
|
||||||
mp_obj_t members[] = { &supervisor_terminal_scroll_area_text_grid, &supervisor_blinka_sprite, &supervisor_terminal_status_bar_text_grid, };
|
mp_obj_t members[] = { &supervisor_terminal_scroll_area_text_grid, &supervisor_blinka_sprite, &supervisor_terminal_status_bar_text_grid, };
|
||||||
|
|
|
@ -56,6 +56,4 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px);
|
||||||
void supervisor_stop_terminal(void);
|
void supervisor_stop_terminal(void);
|
||||||
bool supervisor_terminal_started(void);
|
bool supervisor_terminal_started(void);
|
||||||
|
|
||||||
void supervisor_display_move_memory(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_DISPLAY_H
|
#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_DISPLAY_H
|
||||||
|
|
|
@ -29,17 +29,16 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "genhdr/devices.h"
|
#include "genhdr/devices.h"
|
||||||
#include "supervisor/flash.h"
|
#include "supervisor/flash.h"
|
||||||
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/spi_flash_api.h"
|
#include "supervisor/spi_flash_api.h"
|
||||||
#include "supervisor/shared/external_flash/common_commands.h"
|
#include "supervisor/shared/external_flash/common_commands.h"
|
||||||
#include "extmod/vfs.h"
|
#include "extmod/vfs.h"
|
||||||
#include "extmod/vfs_fat.h"
|
#include "extmod/vfs_fat.h"
|
||||||
#include "py/gc.h"
|
|
||||||
#include "py/misc.h"
|
#include "py/misc.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "lib/oofatfs/ff.h"
|
#include "lib/oofatfs/ff.h"
|
||||||
#include "shared-bindings/microcontroller/__init__.h"
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
#define NO_SECTOR_LOADED 0xFFFFFFFF
|
#define NO_SECTOR_LOADED 0xFFFFFFFF
|
||||||
|
|
||||||
|
@ -55,7 +54,8 @@ static const external_flash_device *flash_device = NULL;
|
||||||
// cache.
|
// cache.
|
||||||
static uint32_t dirty_mask;
|
static uint32_t dirty_mask;
|
||||||
|
|
||||||
static supervisor_allocation *supervisor_cache = NULL;
|
// Table of pointers to each cached block
|
||||||
|
static uint8_t **flash_cache_table = NULL;
|
||||||
|
|
||||||
// Wait until both the write enable and write in progress bits have cleared.
|
// Wait until both the write enable and write in progress bits have cleared.
|
||||||
static bool wait_for_flash_ready(void) {
|
static bool wait_for_flash_ready(void) {
|
||||||
|
@ -295,7 +295,7 @@ void supervisor_flash_init(void) {
|
||||||
|
|
||||||
current_sector = NO_SECTOR_LOADED;
|
current_sector = NO_SECTOR_LOADED;
|
||||||
dirty_mask = 0;
|
dirty_mask = 0;
|
||||||
MP_STATE_VM(flash_ram_cache) = NULL;
|
flash_cache_table = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The size of each individual block.
|
// The size of each individual block.
|
||||||
|
@ -352,47 +352,23 @@ static bool allocate_ram_cache(void) {
|
||||||
uint8_t blocks_per_sector = SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE;
|
uint8_t blocks_per_sector = SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE;
|
||||||
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
|
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
|
||||||
|
|
||||||
uint32_t table_size = blocks_per_sector * pages_per_block * sizeof(uint32_t);
|
uint32_t table_size = blocks_per_sector * pages_per_block * sizeof(size_t);
|
||||||
// Attempt to allocate outside the heap first.
|
// Attempt to allocate outside the heap first.
|
||||||
supervisor_cache = allocate_memory(table_size + SPI_FLASH_ERASE_SIZE, false, false);
|
flash_cache_table = port_malloc(table_size, false);
|
||||||
if (supervisor_cache != NULL) {
|
|
||||||
MP_STATE_VM(flash_ram_cache) = (uint8_t **)supervisor_cache->ptr;
|
|
||||||
uint8_t *page_start = (uint8_t *)supervisor_cache->ptr + table_size;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < blocks_per_sector; i++) {
|
|
||||||
for (uint8_t j = 0; j < pages_per_block; j++) {
|
|
||||||
uint32_t offset = i * pages_per_block + j;
|
|
||||||
MP_STATE_VM(flash_ram_cache)[offset] = page_start + offset * SPI_FLASH_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Couldn't allocate outside the heap. Is the heap available?
|
|
||||||
if (!gc_alloc_possible()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MP_STATE_VM(flash_ram_cache) = m_malloc_maybe(blocks_per_sector * pages_per_block * sizeof(uint32_t));
|
|
||||||
if (MP_STATE_VM(flash_ram_cache) == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Declare i and j outside the loops in case we fail to allocate everything
|
// Declare i and j outside the loops in case we fail to allocate everything
|
||||||
// we need. In that case we'll give it back.
|
// we need. In that case we'll give it back.
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
uint8_t j = 0;
|
uint8_t j = 0;
|
||||||
bool success = true;
|
bool success = flash_cache_table != NULL;
|
||||||
for (i = 0; i < blocks_per_sector; i++) {
|
for (i = 0; i < blocks_per_sector && success; i++) {
|
||||||
for (j = 0; j < pages_per_block; j++) {
|
for (j = 0; j < pages_per_block && success; j++) {
|
||||||
uint8_t *page_cache = m_malloc_maybe(SPI_FLASH_PAGE_SIZE);
|
uint8_t *page_cache = port_malloc(SPI_FLASH_PAGE_SIZE, false);
|
||||||
if (page_cache == NULL) {
|
if (page_cache == NULL) {
|
||||||
success = false;
|
success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j] = page_cache;
|
flash_cache_table[i * pages_per_block + j] = page_cache;
|
||||||
}
|
|
||||||
if (!success) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We couldn't allocate enough so give back what we got.
|
// We couldn't allocate enough so give back what we got.
|
||||||
|
@ -402,24 +378,27 @@ static bool allocate_ram_cache(void) {
|
||||||
i++;
|
i++;
|
||||||
for (; i > 0; i--) {
|
for (; i > 0; i--) {
|
||||||
for (; j > 0; j--) {
|
for (; j > 0; j--) {
|
||||||
m_free(MP_STATE_VM(flash_ram_cache)[(i - 1) * pages_per_block + (j - 1)]);
|
port_free(flash_cache_table[(i - 1) * pages_per_block + (j - 1)]);
|
||||||
}
|
}
|
||||||
j = pages_per_block;
|
j = pages_per_block;
|
||||||
}
|
}
|
||||||
m_free(MP_STATE_VM(flash_ram_cache));
|
port_free(flash_cache_table);
|
||||||
MP_STATE_VM(flash_ram_cache) = NULL;
|
flash_cache_table = NULL;
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void release_ram_cache(void) {
|
static void release_ram_cache(void) {
|
||||||
if (supervisor_cache != NULL) {
|
uint8_t blocks_per_sector = SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE;
|
||||||
free_memory(supervisor_cache);
|
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
|
||||||
supervisor_cache = NULL;
|
for (uint8_t i = 0; i < blocks_per_sector; i++) {
|
||||||
} else if (gc_alloc_possible()) {
|
for (uint8_t j = 0; j < pages_per_block; j++) {
|
||||||
m_free(MP_STATE_VM(flash_ram_cache));
|
uint32_t offset = i * pages_per_block + j;
|
||||||
|
port_free(flash_cache_table[offset]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MP_STATE_VM(flash_ram_cache) = NULL;
|
port_free(flash_cache_table);
|
||||||
|
flash_cache_table = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush the cached sector from ram onto the flash. We'll free the cache unless
|
// Flush the cached sector from ram onto the flash. We'll free the cache unless
|
||||||
|
@ -441,7 +420,7 @@ static bool flush_ram_cache(bool keep_cache) {
|
||||||
for (uint8_t j = 0; j < pages_per_block; j++) {
|
for (uint8_t j = 0; j < pages_per_block; j++) {
|
||||||
copy_to_ram_ok = read_flash(
|
copy_to_ram_ok = read_flash(
|
||||||
current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
|
current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
|
||||||
MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j],
|
flash_cache_table[i * pages_per_block + j],
|
||||||
SPI_FLASH_PAGE_SIZE);
|
SPI_FLASH_PAGE_SIZE);
|
||||||
if (!copy_to_ram_ok) {
|
if (!copy_to_ram_ok) {
|
||||||
break;
|
break;
|
||||||
|
@ -462,11 +441,8 @@ static bool flush_ram_cache(bool keep_cache) {
|
||||||
for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
|
for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
|
||||||
for (uint8_t j = 0; j < pages_per_block; j++) {
|
for (uint8_t j = 0; j < pages_per_block; j++) {
|
||||||
write_flash(current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
|
write_flash(current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
|
||||||
MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j],
|
flash_cache_table[i * pages_per_block + j],
|
||||||
SPI_FLASH_PAGE_SIZE);
|
SPI_FLASH_PAGE_SIZE);
|
||||||
if (!keep_cache && supervisor_cache == NULL && gc_alloc_possible()) {
|
|
||||||
m_free(MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We're done with the cache for now so give it back.
|
// We're done with the cache for now so give it back.
|
||||||
|
@ -483,7 +459,7 @@ static void spi_flash_flush_keep_cache(bool keep_cache) {
|
||||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
|
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
|
||||||
#endif
|
#endif
|
||||||
// If we've cached to the flash itself flush from there.
|
// If we've cached to the flash itself flush from there.
|
||||||
if (MP_STATE_VM(flash_ram_cache) == NULL) {
|
if (flash_cache_table == NULL) {
|
||||||
flush_scratch_flash();
|
flush_scratch_flash();
|
||||||
} else {
|
} else {
|
||||||
flush_ram_cache(keep_cache);
|
flush_ram_cache(keep_cache);
|
||||||
|
@ -524,11 +500,11 @@ static bool external_flash_read_block(uint8_t *dest, uint32_t block) {
|
||||||
uint8_t mask = 1 << (block_index);
|
uint8_t mask = 1 << (block_index);
|
||||||
// We're reading from the currently cached sector.
|
// We're reading from the currently cached sector.
|
||||||
if (current_sector == this_sector && (mask & dirty_mask) > 0) {
|
if (current_sector == this_sector && (mask & dirty_mask) > 0) {
|
||||||
if (MP_STATE_VM(flash_ram_cache) != NULL) {
|
if (flash_cache_table != NULL) {
|
||||||
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
|
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
|
||||||
for (int i = 0; i < pages_per_block; i++) {
|
for (int i = 0; i < pages_per_block; i++) {
|
||||||
memcpy(dest + i * SPI_FLASH_PAGE_SIZE,
|
memcpy(dest + i * SPI_FLASH_PAGE_SIZE,
|
||||||
MP_STATE_VM(flash_ram_cache)[block_index * pages_per_block + i],
|
flash_cache_table[block_index * pages_per_block + i],
|
||||||
SPI_FLASH_PAGE_SIZE);
|
SPI_FLASH_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -564,7 +540,7 @@ static bool external_flash_write_block(const uint8_t *data, uint32_t block) {
|
||||||
if (current_sector != NO_SECTOR_LOADED) {
|
if (current_sector != NO_SECTOR_LOADED) {
|
||||||
supervisor_flash_flush();
|
supervisor_flash_flush();
|
||||||
}
|
}
|
||||||
if (MP_STATE_VM(flash_ram_cache) == NULL && !allocate_ram_cache()) {
|
if (flash_cache_table == NULL && !allocate_ram_cache()) {
|
||||||
erase_sector(flash_device->total_size - SPI_FLASH_ERASE_SIZE);
|
erase_sector(flash_device->total_size - SPI_FLASH_ERASE_SIZE);
|
||||||
wait_for_flash_ready();
|
wait_for_flash_ready();
|
||||||
}
|
}
|
||||||
|
@ -573,10 +549,10 @@ static bool external_flash_write_block(const uint8_t *data, uint32_t block) {
|
||||||
}
|
}
|
||||||
dirty_mask |= mask;
|
dirty_mask |= mask;
|
||||||
// Copy the block to the appropriate cache.
|
// Copy the block to the appropriate cache.
|
||||||
if (MP_STATE_VM(flash_ram_cache) != NULL) {
|
if (flash_cache_table != NULL) {
|
||||||
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
|
uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
|
||||||
for (int i = 0; i < pages_per_block; i++) {
|
for (int i = 0; i < pages_per_block; i++) {
|
||||||
memcpy(MP_STATE_VM(flash_ram_cache)[block_index * pages_per_block + i],
|
memcpy(flash_cache_table[block_index * pages_per_block + i],
|
||||||
data + i * SPI_FLASH_PAGE_SIZE,
|
data + i * SPI_FLASH_PAGE_SIZE,
|
||||||
SPI_FLASH_PAGE_SIZE);
|
SPI_FLASH_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -607,5 +583,3 @@ mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t block_num,
|
||||||
|
|
||||||
void MP_WEAK external_flash_setup(void) {
|
void MP_WEAK external_flash_setup(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_REGISTER_ROOT_POINTER(uint8_t * *flash_ram_cache);
|
|
||||||
|
|
|
@ -1,350 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the MicroPython project, http://micropython.org/
|
|
||||||
*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "supervisor/port.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "py/gc.h"
|
|
||||||
#include "supervisor/shared/display.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
CIRCUITPY_SUPERVISOR_IMMOVABLE_ALLOC_COUNT =
|
|
||||||
0
|
|
||||||
// stack + heap
|
|
||||||
+ 2
|
|
||||||
|
|
||||||
#if INTERNAL_FLASH_FILESYSTEM == 0
|
|
||||||
+ 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB
|
|
||||||
+ 1 // device_descriptor_allocation
|
|
||||||
+ 1 // configuration_descriptor_allocation
|
|
||||||
+ 1 // string_descriptors_allocation
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB_HID
|
|
||||||
+ 1 // hid_report_descriptor_allocation
|
|
||||||
+ 1 // hid_devices_allocation
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB_VENDOR
|
|
||||||
+ 1 // usb_vendor_add_descriptor
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+ CIRCUITPY_PORT_NUM_SUPERVISOR_ALLOCATIONS
|
|
||||||
#if CIRCUITPY_AUDIOBUSIO_PDMIN
|
|
||||||
+ 1
|
|
||||||
#endif
|
|
||||||
,
|
|
||||||
|
|
||||||
CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT =
|
|
||||||
0
|
|
||||||
// next_code_allocation
|
|
||||||
+ 1
|
|
||||||
// prev_traceback_allocation
|
|
||||||
+ 1
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
#if CIRCUITPY_TERMINALIO
|
|
||||||
+ 1
|
|
||||||
#endif
|
|
||||||
+ CIRCUITPY_DISPLAY_LIMIT * (
|
|
||||||
// Maximum needs of one display: max(4 if RGBMATRIX, 1 if SHARPDISPLAY, 0)
|
|
||||||
#if CIRCUITPY_RGBMATRIX
|
|
||||||
4
|
|
||||||
#elif CIRCUITPY_PICODVI
|
|
||||||
2
|
|
||||||
#elif CIRCUITPY_SHARPDISPLAY
|
|
||||||
1
|
|
||||||
#else
|
|
||||||
0
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
,
|
|
||||||
|
|
||||||
CIRCUITPY_SUPERVISOR_ALLOC_COUNT = CIRCUITPY_SUPERVISOR_IMMOVABLE_ALLOC_COUNT + CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
// The lowest two bits of a valid length are always zero, so we can use them to mark an allocation
|
|
||||||
// as a hole (freed by the client but not yet reclaimed into the free middle) and as movable.
|
|
||||||
#define FLAGS 3
|
|
||||||
#define HOLE 1
|
|
||||||
#define MOVABLE 2
|
|
||||||
|
|
||||||
static supervisor_allocation allocations[CIRCUITPY_SUPERVISOR_ALLOC_COUNT];
|
|
||||||
supervisor_allocation *old_allocations;
|
|
||||||
|
|
||||||
typedef struct _supervisor_allocation_node {
|
|
||||||
struct _supervisor_allocation_node *next;
|
|
||||||
size_t length;
|
|
||||||
// We use uint32_t to ensure word (4 byte) alignment.
|
|
||||||
uint32_t data[];
|
|
||||||
} supervisor_allocation_node;
|
|
||||||
|
|
||||||
supervisor_allocation_node *low_head;
|
|
||||||
supervisor_allocation_node *high_head;
|
|
||||||
|
|
||||||
// Intermediate (void*) is to suppress -Wcast-align warning. Alignment will always be correct
|
|
||||||
// because this only reverses how (alloc)->ptr was obtained as &(node->data[0]).
|
|
||||||
#define ALLOCATION_NODE(alloc) ((supervisor_allocation_node *)(void *)((char *)((alloc)->ptr) - sizeof(supervisor_allocation_node)))
|
|
||||||
|
|
||||||
void free_memory(supervisor_allocation *allocation) {
|
|
||||||
if (allocation == NULL || allocation->ptr == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
supervisor_allocation_node *node = ALLOCATION_NODE(allocation);
|
|
||||||
if (node == low_head) {
|
|
||||||
do {
|
|
||||||
low_head = low_head->next;
|
|
||||||
} while (low_head != NULL && (low_head->length & HOLE));
|
|
||||||
} else if (node == high_head) {
|
|
||||||
do {
|
|
||||||
high_head = high_head->next;
|
|
||||||
} while (high_head != NULL && (high_head->length & HOLE));
|
|
||||||
} else {
|
|
||||||
// Check if it's in the list of embedded allocations.
|
|
||||||
supervisor_allocation_node **emb = &MP_STATE_VM(first_embedded_allocation);
|
|
||||||
while (*emb != NULL && *emb != node) {
|
|
||||||
emb = &((*emb)->next);
|
|
||||||
}
|
|
||||||
if (*emb != NULL) {
|
|
||||||
// Found, remove it from the list.
|
|
||||||
*emb = node->next;
|
|
||||||
m_free(node
|
|
||||||
#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
|
|
||||||
, sizeof(supervisor_allocation_node) + (node->length & ~FLAGS)
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Else it must be within the low or high ranges and becomes a hole.
|
|
||||||
node->length = ((node->length & ~FLAGS) | HOLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allocation->ptr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
supervisor_allocation *allocation_from_ptr(void *ptr) {
|
|
||||||
// When called from the context of supervisor_move_memory() (old_allocations != NULL), search
|
|
||||||
// by old pointer to give clients a way of mapping from old to new pointer. But not if
|
|
||||||
// ptr == NULL, then the caller wants an allocation whose current ptr is NULL.
|
|
||||||
supervisor_allocation *list = (old_allocations && ptr) ? old_allocations : &allocations[0];
|
|
||||||
for (size_t index = 0; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) {
|
|
||||||
if (list[index].ptr == ptr) {
|
|
||||||
return &allocations[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
supervisor_allocation *allocate_remaining_memory(void) {
|
|
||||||
return allocate_memory((uint32_t)-1, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static supervisor_allocation_node *find_hole(supervisor_allocation_node *node, size_t length) {
|
|
||||||
for (; node != NULL; node = node->next) {
|
|
||||||
if (node->length == (length | HOLE)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static supervisor_allocation_node *allocate_memory_node(uint32_t length, bool high, bool movable) {
|
|
||||||
if (CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT == 0) {
|
|
||||||
assert(!movable);
|
|
||||||
}
|
|
||||||
// supervisor_move_memory() currently does not support movable allocations on the high side, it
|
|
||||||
// must be extended first if this is ever needed.
|
|
||||||
assert(!(high && movable));
|
|
||||||
uint32_t *low_address = low_head ? low_head->data + low_head->length / 4 : port_heap_get_bottom();
|
|
||||||
uint32_t *high_address = high_head ? (uint32_t *)high_head : port_heap_get_top();
|
|
||||||
// Special case for allocate_remaining_memory(), avoids computing low/high_address twice.
|
|
||||||
if (length == (uint32_t)-1) {
|
|
||||||
length = (high_address - low_address) * 4 - sizeof(supervisor_allocation_node);
|
|
||||||
}
|
|
||||||
if (length == 0 || length % 4 != 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// 1. Matching hole on the requested side?
|
|
||||||
supervisor_allocation_node *node = find_hole(high ? high_head : low_head, length);
|
|
||||||
if (!node) {
|
|
||||||
// 2. Enough free space in the middle?
|
|
||||||
if ((high_address - low_address) * 4 >= (int32_t)(sizeof(supervisor_allocation_node) + length)) {
|
|
||||||
if (high) {
|
|
||||||
high_address -= (sizeof(supervisor_allocation_node) + length) / 4;
|
|
||||||
node = (supervisor_allocation_node *)high_address;
|
|
||||||
node->next = high_head;
|
|
||||||
high_head = node;
|
|
||||||
} else {
|
|
||||||
node = (supervisor_allocation_node *)low_address;
|
|
||||||
node->next = low_head;
|
|
||||||
low_head = node;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 3. Matching hole on the other side?
|
|
||||||
node = find_hole(high ? low_head : high_head, length);
|
|
||||||
if (!node) {
|
|
||||||
// 4. GC allocation?
|
|
||||||
if (movable && gc_alloc_possible()) {
|
|
||||||
node = m_malloc_maybe(sizeof(supervisor_allocation_node) + length);
|
|
||||||
if (node) {
|
|
||||||
node->next = MP_STATE_VM(first_embedded_allocation);
|
|
||||||
MP_STATE_VM(first_embedded_allocation) = node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!node) {
|
|
||||||
// 5. Give up.
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node->length = length;
|
|
||||||
if (movable) {
|
|
||||||
node->length |= MOVABLE;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
supervisor_allocation *allocate_memory(uint32_t length, bool high, bool movable) {
|
|
||||||
supervisor_allocation_node *node = allocate_memory_node(length, high, movable);
|
|
||||||
if (!node) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// Find the first free allocation.
|
|
||||||
supervisor_allocation *alloc = allocation_from_ptr(NULL);
|
|
||||||
if (!alloc) {
|
|
||||||
// We should free node again to avoid leaking, but something is wrong anyway if clients try
|
|
||||||
// to make more allocations than available, so don't bother.
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
alloc->ptr = &(node->data[0]);
|
|
||||||
return alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t get_allocation_length(supervisor_allocation *allocation) {
|
|
||||||
return ALLOCATION_NODE(allocation)->length & ~FLAGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void supervisor_move_memory(void) {
|
|
||||||
// This whole function is not needed when there are no movable allocations, let it be optimized
|
|
||||||
// out.
|
|
||||||
if (CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// This must be called exactly after freeing the heap, so that the embedded allocations, if any,
|
|
||||||
// are now in the free region.
|
|
||||||
assert(MP_STATE_VM(first_embedded_allocation) == NULL || (
|
|
||||||
(low_head == NULL || low_head < MP_STATE_VM(first_embedded_allocation)) &&
|
|
||||||
(high_head == NULL || MP_STATE_VM(first_embedded_allocation) < high_head)));
|
|
||||||
|
|
||||||
// Save the old pointers for allocation_from_ptr().
|
|
||||||
supervisor_allocation old_allocations_array[CIRCUITPY_SUPERVISOR_ALLOC_COUNT];
|
|
||||||
memcpy(old_allocations_array, allocations, sizeof(allocations));
|
|
||||||
|
|
||||||
// Compact the low side. Traverse the list repeatedly, finding movable allocations preceded by a
|
|
||||||
// hole and swapping them, until no more are found. This is not the most runtime-efficient way,
|
|
||||||
// but probably the shortest and simplest code.
|
|
||||||
bool acted;
|
|
||||||
do {
|
|
||||||
acted = false;
|
|
||||||
supervisor_allocation_node **nodep = &low_head;
|
|
||||||
while (*nodep != NULL && (*nodep)->next != NULL) {
|
|
||||||
if (((*nodep)->length & MOVABLE) && ((*nodep)->next->length & HOLE)) {
|
|
||||||
supervisor_allocation_node *oldnode = *nodep;
|
|
||||||
supervisor_allocation_node *start = oldnode->next;
|
|
||||||
supervisor_allocation *alloc = allocation_from_ptr(&(oldnode->data[0]));
|
|
||||||
assert(alloc != NULL);
|
|
||||||
alloc->ptr = &(start->data[0]);
|
|
||||||
oldnode->next = start->next;
|
|
||||||
size_t holelength = start->length;
|
|
||||||
size_t size = sizeof(supervisor_allocation_node) + (oldnode->length & ~FLAGS);
|
|
||||||
memmove(start, oldnode, size);
|
|
||||||
supervisor_allocation_node *newhole = (supervisor_allocation_node *)(void *)((char *)start + size);
|
|
||||||
newhole->next = start;
|
|
||||||
newhole->length = holelength;
|
|
||||||
*nodep = newhole;
|
|
||||||
acted = true;
|
|
||||||
}
|
|
||||||
nodep = &((*nodep)->next);
|
|
||||||
}
|
|
||||||
} while (acted);
|
|
||||||
// Any holes bubbled to the top can be absorbed into the free middle.
|
|
||||||
while (low_head != NULL && (low_head->length & HOLE)) {
|
|
||||||
low_head = low_head->next;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
// Don't bother compacting the high side, there are no movable allocations and no holes there in
|
|
||||||
// current usage.
|
|
||||||
|
|
||||||
// Promote the embedded allocations to top-level ones, compacting them at the beginning of the
|
|
||||||
// now free region (or possibly in matching holes).
|
|
||||||
// The linked list is unordered, but allocations must be processed in order to avoid risking
|
|
||||||
// overwriting each other. To that end, repeatedly find the lowest element of the list, remove
|
|
||||||
// it from the list, and process it. This ad-hoc selection sort results in substantially shorter
|
|
||||||
// code than using the qsort() function from the C library.
|
|
||||||
while (MP_STATE_VM(first_embedded_allocation)) {
|
|
||||||
// First element is first candidate.
|
|
||||||
supervisor_allocation_node **pminnode = &MP_STATE_VM(first_embedded_allocation);
|
|
||||||
// Iterate from second element (if any) on.
|
|
||||||
for (supervisor_allocation_node **pnode = &(MP_STATE_VM(first_embedded_allocation)->next); *pnode != NULL; pnode = &(*pnode)->next) {
|
|
||||||
if (*pnode < *pminnode) {
|
|
||||||
pminnode = pnode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Remove from list.
|
|
||||||
supervisor_allocation_node *node = *pminnode;
|
|
||||||
*pminnode = node->next;
|
|
||||||
// Process.
|
|
||||||
size_t length = (node->length & ~FLAGS);
|
|
||||||
supervisor_allocation *alloc = allocation_from_ptr(&(node->data[0]));
|
|
||||||
assert(alloc != NULL);
|
|
||||||
// This may overwrite the header of node if it happened to be there already, but not the
|
|
||||||
// data.
|
|
||||||
supervisor_allocation_node *new_node = allocate_memory_node(length, false, true);
|
|
||||||
// There must be enough free space.
|
|
||||||
assert(new_node != NULL);
|
|
||||||
memmove(&(new_node->data[0]), &(node->data[0]), length);
|
|
||||||
alloc->ptr = &(new_node->data[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify clients that their movable allocations may have moved.
|
|
||||||
old_allocations = &old_allocations_array[0];
|
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
supervisor_display_move_memory();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Add calls to further clients here.
|
|
||||||
old_allocations = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
MP_REGISTER_ROOT_POINTER(struct _supervisor_allocation_node *first_embedded_allocation);
|
|
|
@ -26,6 +26,14 @@
|
||||||
|
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "py/runtime.h"
|
||||||
|
|
||||||
|
#include "lib/tlsf/tlsf.h"
|
||||||
|
|
||||||
|
static tlsf_t heap;
|
||||||
|
|
||||||
MP_WEAK void port_wake_main_task(void) {
|
MP_WEAK void port_wake_main_task(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,3 +45,37 @@ MP_WEAK void port_yield(void) {
|
||||||
|
|
||||||
MP_WEAK void port_boot_info(void) {
|
MP_WEAK void port_boot_info(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MP_WEAK void port_heap_init(void) {
|
||||||
|
uint32_t *heap_bottom = port_heap_get_bottom();
|
||||||
|
uint32_t *heap_top = port_heap_get_top();
|
||||||
|
size_t size = (heap_top - heap_bottom) * sizeof(uint32_t);
|
||||||
|
heap = tlsf_create_with_pool(heap_bottom, size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_WEAK void *port_malloc(size_t size, bool dma_capable) {
|
||||||
|
void *block = tlsf_malloc(heap, size);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_WEAK void port_free(void *ptr) {
|
||||||
|
tlsf_free(heap, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_WEAK void port_realloc(void *ptr, size_t size) {
|
||||||
|
tlsf_realloc(heap, ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void max_size_walker(void *ptr, size_t size, int used, void *user) {
|
||||||
|
size_t *max_size = (size_t *)user;
|
||||||
|
if (!used && *max_size < size) {
|
||||||
|
*max_size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_WEAK size_t port_heap_get_largest_free_size(void) {
|
||||||
|
size_t max_size = 0;
|
||||||
|
tlsf_walk_pool(tlsf_get_pool(heap), max_size_walker, &max_size);
|
||||||
|
// IDF does this. Not sure why.
|
||||||
|
return tlsf_fit_size(heap, max_size);
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "supervisor/shared/reload.h"
|
#include "supervisor/shared/reload.h"
|
||||||
#include "supervisor/shared/tick.h"
|
#include "supervisor/shared/tick.h"
|
||||||
|
|
||||||
supervisor_allocation *next_code_allocation;
|
|
||||||
#include "shared-bindings/supervisor/Runtime.h"
|
#include "shared-bindings/supervisor/Runtime.h"
|
||||||
|
|
||||||
// True if user has disabled autoreload.
|
// True if user has disabled autoreload.
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#ifndef MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
|
#ifndef MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
|
||||||
#define MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
|
#define MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H
|
||||||
|
|
||||||
#include "supervisor/memory.h"
|
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "shared-bindings/supervisor/RunReason.h"
|
#include "shared-bindings/supervisor/RunReason.h"
|
||||||
|
|
||||||
|
@ -47,13 +46,6 @@ enum {
|
||||||
AUTORELOAD_SUSPEND_WEB = 0x8
|
AUTORELOAD_SUSPEND_WEB = 0x8
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t options;
|
|
||||||
char filename[];
|
|
||||||
} next_code_info_t;
|
|
||||||
|
|
||||||
extern supervisor_allocation *next_code_allocation;
|
|
||||||
|
|
||||||
// Helper for exiting the VM and reloading immediately.
|
// Helper for exiting the VM and reloading immediately.
|
||||||
void reload_initiate(supervisor_run_reason_t run_reason);
|
void reload_initiate(supervisor_run_reason_t run_reason);
|
||||||
|
|
||||||
|
|
|
@ -218,7 +218,7 @@ void print_safe_mode_message(safe_mode_t reason) {
|
||||||
message = MP_ERROR_TEXT("NLR jump failed. Likely memory corruption.");
|
message = MP_ERROR_TEXT("NLR jump failed. Likely memory corruption.");
|
||||||
break;
|
break;
|
||||||
case SAFE_MODE_NO_HEAP:
|
case SAFE_MODE_NO_HEAP:
|
||||||
message = MP_ERROR_TEXT("Unable to allocate the heap.");
|
message = MP_ERROR_TEXT("Unable to allocate to the heap.");
|
||||||
break;
|
break;
|
||||||
case SAFE_MODE_SDK_FATAL_ERROR:
|
case SAFE_MODE_SDK_FATAL_ERROR:
|
||||||
message = MP_ERROR_TEXT("Third-party firmware fatal error.");
|
message = MP_ERROR_TEXT("Third-party firmware fatal error.");
|
||||||
|
|
|
@ -32,48 +32,14 @@
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/shared/safe_mode.h"
|
#include "supervisor/shared/safe_mode.h"
|
||||||
|
|
||||||
extern uint32_t _estack;
|
void stack_init(void) {
|
||||||
|
uint32_t *stack_limit = port_stack_get_limit();
|
||||||
// Requested size.
|
|
||||||
static uint32_t next_stack_size = 0;
|
|
||||||
static uint32_t current_stack_size = 0;
|
|
||||||
// Actual location and size, may be larger than requested.
|
|
||||||
static uint32_t *stack_limit = NULL;
|
|
||||||
static size_t stack_length = 0;
|
|
||||||
|
|
||||||
#define EXCEPTION_STACK_SIZE 1024
|
|
||||||
|
|
||||||
static void allocate_stack(void) {
|
|
||||||
|
|
||||||
if (port_has_fixed_stack()) {
|
|
||||||
stack_limit = port_stack_get_limit();
|
|
||||||
stack_length = (port_stack_get_top() - stack_limit) * sizeof(uint32_t);
|
|
||||||
current_stack_size = stack_length;
|
|
||||||
next_stack_size = stack_length;
|
|
||||||
} else {
|
|
||||||
mp_uint_t regs[10];
|
|
||||||
mp_uint_t sp = cpu_get_regs_and_sp(regs);
|
|
||||||
|
|
||||||
mp_uint_t c_size = (mp_uint_t)port_stack_get_top() - sp;
|
|
||||||
if (next_stack_size == 0) {
|
|
||||||
next_stack_size = CIRCUITPY_DEFAULT_STACK_SIZE;
|
|
||||||
}
|
|
||||||
supervisor_allocation *stack_alloc = allocate_memory(c_size + next_stack_size + EXCEPTION_STACK_SIZE, true, false);
|
|
||||||
if (stack_alloc == NULL) {
|
|
||||||
stack_alloc = allocate_memory(c_size + CIRCUITPY_DEFAULT_STACK_SIZE + EXCEPTION_STACK_SIZE, true, false);
|
|
||||||
current_stack_size = CIRCUITPY_DEFAULT_STACK_SIZE;
|
|
||||||
} else {
|
|
||||||
current_stack_size = next_stack_size;
|
|
||||||
}
|
|
||||||
stack_limit = stack_alloc->ptr;
|
|
||||||
stack_length = get_allocation_length(stack_alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
*stack_limit = STACK_CANARY_VALUE;
|
*stack_limit = STACK_CANARY_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool stack_ok(void) {
|
inline bool stack_ok(void) {
|
||||||
return stack_limit == NULL || *stack_limit == STACK_CANARY_VALUE;
|
uint32_t *stack_limit = port_stack_get_limit();
|
||||||
|
return *stack_limit == STACK_CANARY_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void assert_heap_ok(void) {
|
inline void assert_heap_ok(void) {
|
||||||
|
@ -81,44 +47,3 @@ inline void assert_heap_ok(void) {
|
||||||
reset_into_safe_mode(SAFE_MODE_STACK_OVERFLOW);
|
reset_into_safe_mode(SAFE_MODE_STACK_OVERFLOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stack_init(void) {
|
|
||||||
allocate_stack();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stack_resize(void) {
|
|
||||||
if (stack_limit == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (next_stack_size == current_stack_size) {
|
|
||||||
*stack_limit = STACK_CANARY_VALUE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
free_memory(allocation_from_ptr(stack_limit));
|
|
||||||
stack_limit = NULL;
|
|
||||||
allocate_stack();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *stack_get_bottom(void) {
|
|
||||||
return stack_limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t stack_get_length(void) {
|
|
||||||
return stack_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_next_stack_size(uint32_t size) {
|
|
||||||
if (port_has_fixed_stack()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
next_stack_size = size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t get_next_stack_size(void) {
|
|
||||||
return next_stack_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t get_current_stack_size(void) {
|
|
||||||
return current_stack_size;
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,22 +24,16 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MICROPY_INCLUDED_SUPERVISOR_STACK_H
|
#pragma once
|
||||||
#define MICROPY_INCLUDED_SUPERVISOR_STACK_H
|
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
void stack_init(void);
|
void stack_init(void);
|
||||||
void stack_resize(void);
|
|
||||||
// Actual stack location and size, may be larger than requested.
|
// Actual stack location and size, may be larger than requested.
|
||||||
uint32_t *stack_get_bottom(void);
|
uint32_t *stack_get_bottom(void);
|
||||||
size_t stack_get_length(void);
|
size_t stack_get_length(void);
|
||||||
// Next/current requested stack size.
|
|
||||||
bool set_next_stack_size(uint32_t size);
|
|
||||||
uint32_t get_next_stack_size(void);
|
|
||||||
uint32_t get_current_stack_size(void);
|
|
||||||
bool stack_ok(void);
|
bool stack_ok(void);
|
||||||
|
|
||||||
// Use this after any calls into a library which may use a lot of stack. This will raise a Python
|
// Use this after any calls into a library which may use a lot of stack. This will raise a Python
|
||||||
|
@ -49,5 +43,3 @@ void assert_heap_ok(void);
|
||||||
#ifndef STACK_CANARY_VALUE
|
#ifndef STACK_CANARY_VALUE
|
||||||
#define STACK_CANARY_VALUE 0x017829ef
|
#define STACK_CANARY_VALUE 0x017829ef
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SUPERVISOR_STACK_H
|
|
||||||
|
|
|
@ -25,5 +25,3 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "traceback.h"
|
#include "traceback.h"
|
||||||
|
|
||||||
supervisor_allocation *prev_traceback_allocation;
|
|
||||||
|
|
|
@ -27,8 +27,4 @@
|
||||||
#ifndef MICROPY_INCLUDED_SUPERVISOR_TRACEBACK_H
|
#ifndef MICROPY_INCLUDED_SUPERVISOR_TRACEBACK_H
|
||||||
#define MICROPY_INCLUDED_SUPERVISOR_TRACEBACK_H
|
#define MICROPY_INCLUDED_SUPERVISOR_TRACEBACK_H
|
||||||
|
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
extern supervisor_allocation *prev_traceback_allocation;
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SUPERVISOR_TRACEBACK_H
|
#endif // MICROPY_INCLUDED_SUPERVISOR_TRACEBACK_H
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "py/objstr.h"
|
#include "py/objstr.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "shared-bindings/microcontroller/Processor.h"
|
#include "shared-bindings/microcontroller/Processor.h"
|
||||||
|
#include "shared-bindings/supervisor/__init__.h"
|
||||||
#include "supervisor/background_callback.h"
|
#include "supervisor/background_callback.h"
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/serial.h"
|
#include "supervisor/serial.h"
|
||||||
|
@ -85,7 +86,27 @@ MP_WEAK void post_usb_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_init(void) {
|
void usb_init(void) {
|
||||||
|
|
||||||
|
usb_identification_t defaults;
|
||||||
|
usb_identification_t *identification;
|
||||||
|
if (custom_usb_identification != NULL) {
|
||||||
|
identification = custom_usb_identification;
|
||||||
|
} else {
|
||||||
|
// This compiles to less code than using a struct initializer.
|
||||||
|
defaults.vid = USB_VID;
|
||||||
|
defaults.pid = USB_PID;
|
||||||
|
strcpy(defaults.manufacturer_name, USB_MANUFACTURER);
|
||||||
|
strcpy(defaults.product_name, USB_PRODUCT);
|
||||||
|
identification = &defaults;
|
||||||
|
// This memory only needs to be live through the end of usb_build_descriptors.
|
||||||
|
}
|
||||||
|
if (!usb_build_descriptors(identification)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
init_usb_hardware();
|
init_usb_hardware();
|
||||||
|
#if CIRCUITPY_USB_HID
|
||||||
|
usb_hid_build_report_descriptor();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Only init device. Host gets inited by the `usb_host` module common-hal.
|
// Only init device. Host gets inited by the `usb_host` module common-hal.
|
||||||
tud_init(TUD_OPT_RHPORT);
|
tud_init(TUD_OPT_RHPORT);
|
||||||
|
@ -123,66 +144,6 @@ void usb_set_defaults(void) {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#if CIRCUITPY_USB_IDENTIFICATION
|
|
||||||
supervisor_allocation *usb_identification_allocation = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Some dynamic USB data must be saved after boot.py. How much is needed?
|
|
||||||
size_t usb_boot_py_data_size(void) {
|
|
||||||
size_t size = sizeof(usb_identification_t);
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB_HID
|
|
||||||
size += usb_hid_report_descriptor_length();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in the data to save.
|
|
||||||
void usb_get_boot_py_data(uint8_t *temp_storage, size_t temp_storage_size) {
|
|
||||||
#if CIRCUITPY_USB_IDENTIFICATION
|
|
||||||
if (usb_identification_allocation) {
|
|
||||||
memcpy(temp_storage, usb_identification_allocation->ptr, sizeof(usb_identification_t));
|
|
||||||
free_memory(usb_identification_allocation);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (false) {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
usb_identification_t defaults;
|
|
||||||
// This compiles to less code than using a struct initializer.
|
|
||||||
defaults.vid = USB_VID;
|
|
||||||
defaults.pid = USB_PID;
|
|
||||||
strcpy(defaults.manufacturer_name, USB_MANUFACTURER);
|
|
||||||
strcpy(defaults.product_name, USB_PRODUCT);
|
|
||||||
memcpy(temp_storage, &defaults, sizeof(defaults));
|
|
||||||
}
|
|
||||||
|
|
||||||
temp_storage += sizeof(usb_identification_t);
|
|
||||||
temp_storage_size -= sizeof(usb_identification_t);
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB_HID
|
|
||||||
usb_hid_build_report_descriptor(temp_storage, temp_storage_size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// After VM is gone, save data into non-heap storage (storage_allocations).
|
|
||||||
void usb_return_boot_py_data(uint8_t *temp_storage, size_t temp_storage_size) {
|
|
||||||
usb_identification_t identification;
|
|
||||||
memcpy(&identification, temp_storage, sizeof(usb_identification_t));
|
|
||||||
|
|
||||||
temp_storage += sizeof(usb_identification_t);
|
|
||||||
temp_storage_size -= sizeof(usb_identification_t);
|
|
||||||
|
|
||||||
#if CIRCUITPY_USB_HID
|
|
||||||
usb_hid_save_report_descriptor(temp_storage, temp_storage_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Now we can also build the rest of the descriptors and place them in storage_allocations.
|
|
||||||
usb_build_descriptors(&identification);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call this when ready to run code.py or a REPL, and a VM has been started.
|
// Call this when ready to run code.py or a REPL, and a VM has been started.
|
||||||
void usb_setup_with_vm(void) {
|
void usb_setup_with_vm(void) {
|
||||||
#if CIRCUITPY_USB_HID
|
#if CIRCUITPY_USB_HID
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
#include "py/objstr.h"
|
#include "py/objstr.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "supervisor/memory.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/shared/safe_mode.h"
|
#include "supervisor/shared/safe_mode.h"
|
||||||
#include "supervisor/usb.h"
|
#include "supervisor/usb.h"
|
||||||
|
|
||||||
|
@ -64,14 +64,13 @@ static interface_string_t collected_interface_strings[MAX_INTERFACE_STRINGS];
|
||||||
static size_t collected_interface_strings_length;
|
static size_t collected_interface_strings_length;
|
||||||
static uint8_t current_interface_string;
|
static uint8_t current_interface_string;
|
||||||
|
|
||||||
static supervisor_allocation *device_descriptor_allocation;
|
static uint8_t *device_descriptor;
|
||||||
static supervisor_allocation *configuration_descriptor_allocation;
|
static uint8_t *configuration_descriptor;
|
||||||
static supervisor_allocation *string_descriptors_allocation;
|
static uint16_t *string_descriptors;
|
||||||
|
|
||||||
// Serial number string is UID length * 2 (2 nibbles per byte) + 1 byte for null termination.
|
// Serial number string is UID length * 2 (2 nibbles per byte) + 1 byte for null termination.
|
||||||
static char serial_number_hex_string[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2 + 1];
|
static char serial_number_hex_string[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2 + 1];
|
||||||
|
|
||||||
|
|
||||||
static const uint8_t device_descriptor_template[] = {
|
static const uint8_t device_descriptor_template[] = {
|
||||||
0x12, // 0 bLength
|
0x12, // 0 bLength
|
||||||
0x01, // 1 bDescriptorType (Device)
|
0x01, // 1 bDescriptorType (Device)
|
||||||
|
@ -110,11 +109,13 @@ static const uint8_t configuration_descriptor_template[] = {
|
||||||
0x32, // 8 bMaxPower 100mA
|
0x32, // 8 bMaxPower 100mA
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usb_build_device_descriptor(const usb_identification_t *identification) {
|
static bool usb_build_device_descriptor(const usb_identification_t *identification) {
|
||||||
device_descriptor_allocation =
|
device_descriptor =
|
||||||
allocate_memory(align32_size(sizeof(device_descriptor_template)),
|
(uint8_t *)port_malloc(sizeof(device_descriptor_template),
|
||||||
/*high_address*/ false, /*movable*/ false);
|
/*dma_capable*/ false);
|
||||||
uint8_t *device_descriptor = (uint8_t *)device_descriptor_allocation->ptr;
|
if (device_descriptor == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
memcpy(device_descriptor, device_descriptor_template, sizeof(device_descriptor_template));
|
memcpy(device_descriptor, device_descriptor_template, sizeof(device_descriptor_template));
|
||||||
|
|
||||||
device_descriptor[DEVICE_VID_LO_INDEX] = identification->vid & 0xFF;
|
device_descriptor[DEVICE_VID_LO_INDEX] = identification->vid & 0xFF;
|
||||||
|
@ -133,9 +134,11 @@ static void usb_build_device_descriptor(const usb_identification_t *identificati
|
||||||
usb_add_interface_string(current_interface_string, serial_number_hex_string);
|
usb_add_interface_string(current_interface_string, serial_number_hex_string);
|
||||||
device_descriptor[DEVICE_SERIAL_NUMBER_STRING_INDEX] = current_interface_string;
|
device_descriptor[DEVICE_SERIAL_NUMBER_STRING_INDEX] = current_interface_string;
|
||||||
current_interface_string++;
|
current_interface_string++;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_build_configuration_descriptor(void) {
|
static bool usb_build_configuration_descriptor(void) {
|
||||||
size_t total_descriptor_length = sizeof(configuration_descriptor_template);
|
size_t total_descriptor_length = sizeof(configuration_descriptor_template);
|
||||||
|
|
||||||
// CDC should be first, for compatibility with Adafruit Windows 7 drivers.
|
// CDC should be first, for compatibility with Adafruit Windows 7 drivers.
|
||||||
|
@ -174,11 +177,13 @@ static void usb_build_configuration_descriptor(void) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Now we now how big the configuration descriptor will be, so we can allocate space for it.
|
// Now we know how big the configuration descriptor will be, so we can allocate space for it.
|
||||||
configuration_descriptor_allocation =
|
configuration_descriptor =
|
||||||
allocate_memory(align32_size(total_descriptor_length),
|
(uint8_t *)port_malloc(total_descriptor_length,
|
||||||
/*high_address*/ false, /*movable*/ false);
|
/*dma_capable*/ false);
|
||||||
uint8_t *configuration_descriptor = (uint8_t *)configuration_descriptor_allocation->ptr;
|
if (configuration_descriptor == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the template, which is the first part of the descriptor, and fix up its length.
|
// Copy the template, which is the first part of the descriptor, and fix up its length.
|
||||||
|
|
||||||
|
@ -260,6 +265,7 @@ static void usb_build_configuration_descriptor(void) {
|
||||||
descriptor_counts.num_out_endpoints > USB_NUM_OUT_ENDPOINTS) {
|
descriptor_counts.num_out_endpoints > USB_NUM_OUT_ENDPOINTS) {
|
||||||
reset_into_safe_mode(SAFE_MODE_USB_TOO_MANY_ENDPOINTS);
|
reset_into_safe_mode(SAFE_MODE_USB_TOO_MANY_ENDPOINTS);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// str must not be on the heap.
|
// str must not be on the heap.
|
||||||
|
@ -277,14 +283,15 @@ static const uint16_t language_id[] = {
|
||||||
0x0409,
|
0x0409,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usb_build_interface_string_table(void) {
|
static bool usb_build_interface_string_table(void) {
|
||||||
// Allocate space for the le16 String descriptors.
|
// Allocate space for the le16 String descriptors.
|
||||||
// Space needed is 2 bytes for String Descriptor header, then 2 bytes for each character
|
// Space needed is 2 bytes for String Descriptor header, then 2 bytes for each character
|
||||||
string_descriptors_allocation =
|
string_descriptors =
|
||||||
allocate_memory(align32_size(current_interface_string * 2 + collected_interface_strings_length * 2),
|
port_malloc(current_interface_string * 2 + collected_interface_strings_length * 2,
|
||||||
/*high_address*/ false, /*movable*/ false);
|
/*dma_capable*/ false);
|
||||||
uint16_t *string_descriptors = (uint16_t *)string_descriptors_allocation->ptr;
|
if (string_descriptors == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t *string_descriptor = string_descriptors;
|
uint16_t *string_descriptor = string_descriptors;
|
||||||
|
|
||||||
|
@ -312,11 +319,11 @@ static void usb_build_interface_string_table(void) {
|
||||||
// Move to next descriptor slot.
|
// Move to next descriptor slot.
|
||||||
string_descriptor += descriptor_size_words;
|
string_descriptor += descriptor_size_words;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// After boot.py runs, the USB devices to be used have been chosen, and the descriptors can be set up.
|
// After boot.py runs, the USB devices to be used have been chosen, and the descriptors can be set up.
|
||||||
// This is called after the VM is finished, because it uses storage_allocations.
|
bool usb_build_descriptors(const usb_identification_t *identification) {
|
||||||
void usb_build_descriptors(const usb_identification_t *identification) {
|
|
||||||
uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH];
|
uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH];
|
||||||
common_hal_mcu_processor_get_uid(raw_id);
|
common_hal_mcu_processor_get_uid(raw_id);
|
||||||
|
|
||||||
|
@ -333,15 +340,15 @@ void usb_build_descriptors(const usb_identification_t *identification) {
|
||||||
current_interface_string = 1;
|
current_interface_string = 1;
|
||||||
collected_interface_strings_length = 0;
|
collected_interface_strings_length = 0;
|
||||||
|
|
||||||
usb_build_device_descriptor(identification);
|
return usb_build_device_descriptor(identification) &&
|
||||||
usb_build_configuration_descriptor();
|
usb_build_configuration_descriptor() &&
|
||||||
usb_build_interface_string_table();
|
usb_build_interface_string_table();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when GET DEVICE DESCRIPTOR is received.
|
// Invoked when GET DEVICE DESCRIPTOR is received.
|
||||||
// Application return pointer to descriptor
|
// Application return pointer to descriptor
|
||||||
uint8_t const *tud_descriptor_device_cb(void) {
|
uint8_t const *tud_descriptor_device_cb(void) {
|
||||||
return (uint8_t *)device_descriptor_allocation->ptr;
|
return device_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when GET CONFIGURATION DESCRIPTOR is received.
|
// Invoked when GET CONFIGURATION DESCRIPTOR is received.
|
||||||
|
@ -349,7 +356,7 @@ uint8_t const *tud_descriptor_device_cb(void) {
|
||||||
// Descriptor contents must exist long enough for transfer to complete
|
// Descriptor contents must exist long enough for transfer to complete
|
||||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
||||||
(void)index; // for multiple configurations
|
(void)index; // for multiple configurations
|
||||||
return (uint8_t *)configuration_descriptor_allocation->ptr;
|
return configuration_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when GET STRING DESCRIPTOR request is received.
|
// Invoked when GET STRING DESCRIPTOR request is received.
|
||||||
|
|
|
@ -35,15 +35,3 @@ void assert_heap_ok(void) {
|
||||||
|
|
||||||
void stack_init(void) {
|
void stack_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void stack_resize(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_next_stack_size(uint32_t size) {
|
|
||||||
(void)size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t get_current_stack_size(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
SRC_SUPERVISOR = \
|
SRC_SUPERVISOR = \
|
||||||
main.c \
|
main.c \
|
||||||
|
lib/tlsf/tlsf.c \
|
||||||
supervisor/port.c \
|
supervisor/port.c \
|
||||||
supervisor/shared/background_callback.c \
|
supervisor/shared/background_callback.c \
|
||||||
supervisor/shared/board.c \
|
supervisor/shared/board.c \
|
||||||
|
@ -7,7 +8,6 @@ SRC_SUPERVISOR = \
|
||||||
supervisor/shared/fatfs.c \
|
supervisor/shared/fatfs.c \
|
||||||
supervisor/shared/flash.c \
|
supervisor/shared/flash.c \
|
||||||
supervisor/shared/lock.c \
|
supervisor/shared/lock.c \
|
||||||
supervisor/shared/memory.c \
|
|
||||||
supervisor/shared/micropython.c \
|
supervisor/shared/micropython.c \
|
||||||
supervisor/shared/port.c \
|
supervisor/shared/port.c \
|
||||||
supervisor/shared/reload.c \
|
supervisor/shared/reload.c \
|
||||||
|
@ -21,6 +21,9 @@ SRC_SUPERVISOR = \
|
||||||
supervisor/shared/workflow.c \
|
supervisor/shared/workflow.c \
|
||||||
supervisor/stub/misc.c \
|
supervisor/stub/misc.c \
|
||||||
|
|
||||||
|
# For tlsf
|
||||||
|
CFLAGS += -D_DEBUG=0
|
||||||
|
|
||||||
NO_USB ?= $(wildcard supervisor/usb.c)
|
NO_USB ?= $(wildcard supervisor/usb.c)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,6 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "supervisor/memory.h"
|
|
||||||
|
|
||||||
// Ports must call this as frequently as they can in order to keep the USB
|
// Ports must call this as frequently as they can in order to keep the USB
|
||||||
// connection alive and responsive. Normally this is called from background
|
// connection alive and responsive. Normally this is called from background
|
||||||
// tasks after the USB IRQ handler is executed, but in specific circumstances
|
// tasks after the USB IRQ handler is executed, but in specific circumstances
|
||||||
|
@ -67,12 +65,10 @@ typedef struct {
|
||||||
char product_name[128];
|
char product_name[128];
|
||||||
} usb_identification_t;
|
} usb_identification_t;
|
||||||
|
|
||||||
extern supervisor_allocation *usb_identification_allocation;
|
|
||||||
|
|
||||||
// Shared implementation.
|
// Shared implementation.
|
||||||
bool usb_enabled(void);
|
bool usb_enabled(void);
|
||||||
void usb_add_interface_string(uint8_t interface_string_index, const char str[]);
|
void usb_add_interface_string(uint8_t interface_string_index, const char str[]);
|
||||||
void usb_build_descriptors(const usb_identification_t *identification);
|
bool usb_build_descriptors(const usb_identification_t *identification);
|
||||||
void usb_disconnect(void);
|
void usb_disconnect(void);
|
||||||
void usb_init(void);
|
void usb_init(void);
|
||||||
void usb_set_defaults(void);
|
void usb_set_defaults(void);
|
||||||
|
|
Loading…
Reference in New Issue