From 2dcd745434757cf0737d5edd7d841aae1e4bffa4 Mon Sep 17 00:00:00 2001 From: Damien Tournoud Date: Thu, 15 Dec 2022 14:09:19 -0800 Subject: [PATCH 001/121] py/gc: Speed up incremental GC cycles by tracking the last used block. In applications that use little memory and run GC regularly, the cost of the sweep phase quickly becomes prohibitives as the amount of RAM increases. On an ESP32-S3 with 2 MB of external SPIRAM, for example, a trivial GC cycle takes a minimum of 40ms, virtually all of it in the sweep phase. Similarly, on the UNIX port with 1 GB of heap, a trivial GC takes 47 ms, again virtually all of it in the sweep phase. This commit speeds up the sweep phase in the case most of the heap is empty by keeping track of the ID of the highest block we allocated in an area since the last GC. The performance benchmark run on PYBV10 shows between +0 and +2% improvement across the existing performance tests. These tests don't really stress the GC, so they were also run with gc.threshold(30000) and gc.threshold(10000). For the 30000 case, performance improved by up to +10% with this commit. For the 10000 case, performance improved by at least +10% on 6 tests, and up to +25%. Signed-off-by: Damien George --- py/gc.c | 22 ++++++++++++++++++++-- py/mpstate.h | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/py/gc.c b/py/gc.c index 9fefd3638b..541632d12b 100644 --- a/py/gc.c +++ b/py/gc.c @@ -158,6 +158,7 @@ STATIC void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { #endif area->gc_last_free_atb_index = 0; + area->gc_last_used_block = 0; #if MICROPY_GC_SPLIT_HEAP area->next = NULL; @@ -378,7 +379,14 @@ STATIC void gc_sweep(void) { // free unmarked heads and their tails int free_tail = 0; for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) { - for (size_t block = 0; block < area->gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) { + size_t end_block = area->gc_alloc_table_byte_len * BLOCKS_PER_ATB; + if (area->gc_last_used_block < end_block) { + end_block = area->gc_last_used_block + 1; + } + + size_t last_used_block = 0; + + for (size_t block = 0; block < end_block; block++) { MICROPY_GC_HOOK_LOOP(block); switch (ATB_GET_KIND(area, block)) { case AT_HEAD: @@ -418,15 +426,20 @@ STATIC void gc_sweep(void) { #if CLEAR_ON_SWEEP memset((void *)PTR_FROM_BLOCK(area, block), 0, BYTES_PER_BLOCK); #endif + } else { + last_used_block = block; } break; case AT_MARK: ATB_MARK_TO_HEAD(area, block); free_tail = 0; + last_used_block = block; break; } } + + area->gc_last_used_block = last_used_block; } } @@ -680,6 +693,8 @@ found: area->gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB; } + area->gc_last_used_block = MAX(area->gc_last_used_block, end_block); + // mark first block as used head ATB_FREE_TO_HEAD(area, start_block); @@ -971,11 +986,14 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { // check if we can expand in place if (new_blocks <= n_blocks + n_free) { // mark few more blocks as used tail - for (size_t bl = block + n_blocks; bl < block + new_blocks; bl++) { + size_t end_block = block + new_blocks; + for (size_t bl = block + n_blocks; bl < end_block; bl++) { assert(ATB_GET_KIND(area, bl) == AT_FREE); ATB_FREE_TO_TAIL(area, bl); } + area->gc_last_used_block = MAX(area->gc_last_used_block, end_block); + GC_EXIT(); #if MICROPY_GC_CONSERVATIVE_CLEAR diff --git a/py/mpstate.h b/py/mpstate.h index 080dc1380b..64915ab87d 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -93,6 +93,7 @@ typedef struct _mp_state_mem_area_t { byte *gc_pool_end; size_t gc_last_free_atb_index; + size_t gc_last_used_block; // The block ID of the highest block allocated in the area } mp_state_mem_area_t; // This structure hold information about the memory allocation system. From 7fad499d1e4d31ffdd4a93a61a9c604189636e3c Mon Sep 17 00:00:00 2001 From: Rene Straub Date: Fri, 4 Aug 2023 12:27:37 +0200 Subject: [PATCH 002/121] docs/develop/gettingstarted: Clarify submodule initialization. When building for a specific board this must be specified in make submodules. I.e. make BOARD=STM32F769DISC submodules. Signed-off-by: Rene Straub --- docs/develop/gettingstarted.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst index c2d3816d42..c51cac360c 100644 --- a/docs/develop/gettingstarted.rst +++ b/docs/develop/gettingstarted.rst @@ -228,7 +228,7 @@ You can also specify which board to use: .. code-block:: bash $ cd ports/stm32 - $ make submodules + $ make BOARD= submodules $ make BOARD= See `ports/stm32/boards `_ From b714f4181276b349873451bde291322bcb842f47 Mon Sep 17 00:00:00 2001 From: Elecia White Date: Thu, 3 Aug 2023 08:04:28 -0700 Subject: [PATCH 003/121] docs/develop/gettingstarted: Update ARM package list. Signed-off-by: Elecia White --- docs/develop/gettingstarted.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst index c51cac360c..34ca1c9c63 100644 --- a/docs/develop/gettingstarted.rst +++ b/docs/develop/gettingstarted.rst @@ -100,7 +100,7 @@ For the stm32 port, the ARM cross-compiler is required: .. code-block:: bash - $ sudo apt-get install arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib + $ sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi See the `ARM GCC toolchain `_ From 6a179019e882c181f2eec1a472f6ec4baf699a9b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 31 Jul 2023 12:21:21 +1000 Subject: [PATCH 004/121] unix/modsocket: Add poll support for missing ERR,HUP,NVAL poll values. Signed-off-by: Damien George --- ports/unix/modsocket.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/unix/modsocket.c b/ports/unix/modsocket.c index 871be8dcf7..737550b428 100644 --- a/ports/unix/modsocket.c +++ b/ports/unix/modsocket.c @@ -164,6 +164,15 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i if (pfd.revents & POLLOUT) { ret |= MP_STREAM_POLL_WR; } + if (pfd.revents & POLLERR) { + ret |= MP_STREAM_POLL_ERR; + } + if (pfd.revents & POLLHUP) { + ret |= MP_STREAM_POLL_HUP; + } + if (pfd.revents & POLLNVAL) { + ret |= MP_STREAM_POLL_NVAL; + } } return ret; } From 22106bf2fa574ba947eceb3b9cfa401c67c6a7eb Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 31 Jul 2023 12:32:02 +1000 Subject: [PATCH 005/121] extmod/vfs_posix_file: Add poll support for missing ERR,HUP,NVAL values. Signed-off-by: Damien George --- extmod/vfs_posix_file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index cfc56df99f..41d7622b37 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -209,6 +209,15 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ if (pfd.revents & POLLOUT) { ret |= MP_STREAM_POLL_WR; } + if (pfd.revents & POLLERR) { + ret |= MP_STREAM_POLL_ERR; + } + if (pfd.revents & POLLHUP) { + ret |= MP_STREAM_POLL_HUP; + } + if (pfd.revents & POLLNVAL) { + ret |= MP_STREAM_POLL_NVAL; + } } return ret; #endif From df08c38c286561c08d5ac354428074817eb0c163 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 31 Jul 2023 12:10:18 +1000 Subject: [PATCH 006/121] unix/modselect: Remove unix-specific implementation of select module. The unix port has a custom select module which only works with objects that have a file descriptor, eg files and sockets. On the other hand, bare metal ports use the common extmod/modselect.c implementation of the select module that supports polling of arbitrary objects, as long as those objects provide a MP_STREAM_POLL in their ioctl implementation (which can be done in C or Python). This commit removes the unix-specific code and makes unix use the common one provided by extmod/modselect.c instead. All objects with file descriptors implement MP_STREAM_POLL so they continue to work. Signed-off-by: Damien George --- ports/unix/Makefile | 1 - ports/unix/modselect.c | 356 ------------------- ports/unix/variants/mpconfigvariant_common.h | 10 +- 3 files changed, 2 insertions(+), 365 deletions(-) delete mode 100644 ports/unix/modselect.c diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 188e4be633..eae02bf257 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -201,7 +201,6 @@ SRC_C += \ mpthreadport.c \ input.c \ modmachine.c \ - modselect.c \ alloc.c \ fatfs_port.c \ mpbthciport.c \ diff --git a/ports/unix/modselect.c b/ports/unix/modselect.c deleted file mode 100644 index 894820c63d..0000000000 --- a/ports/unix/modselect.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2014 Damien P. George - * Copyright (c) 2015-2017 Paul Sokolovsky - * - * 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 "py/mpconfig.h" - -#if MICROPY_PY_SELECT_POSIX - -#if MICROPY_PY_SELECT -#error "Can't have both MICROPY_PY_SELECT and MICROPY_PY_SELECT_POSIX." -#endif - -#include -#include -#include - -#include "py/runtime.h" -#include "py/stream.h" -#include "py/obj.h" -#include "py/objlist.h" -#include "py/objtuple.h" -#include "py/mphal.h" -#include "py/mpthread.h" - -#define DEBUG 0 - -#if MICROPY_PY_SOCKET -extern const mp_obj_type_t mp_type_socket; -#endif - -// Flags for poll() -#define FLAG_ONESHOT (1) - -/// \class Poll - poll class - -typedef struct _mp_obj_poll_t { - mp_obj_base_t base; - unsigned short alloc; - unsigned short len; - struct pollfd *entries; - mp_obj_t *obj_map; - short iter_cnt; - short iter_idx; - int flags; - // callee-owned tuple - mp_obj_t ret_tuple; -} mp_obj_poll_t; - -STATIC int get_fd(mp_obj_t fdlike) { - if (mp_obj_is_obj(fdlike)) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(fdlike, MP_STREAM_OP_IOCTL); - int err; - mp_uint_t res = stream_p->ioctl(fdlike, MP_STREAM_GET_FILENO, 0, &err); - if (res != MP_STREAM_ERROR) { - return res; - } - } - return mp_obj_get_int(fdlike); -} - -/// \method register(obj[, eventmask]) -STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { - mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); - bool is_fd = mp_obj_is_int(args[1]); - int fd = get_fd(args[1]); - - mp_uint_t flags; - if (n_args == 3) { - flags = mp_obj_get_int(args[2]); - } else { - flags = POLLIN | POLLOUT; - } - - struct pollfd *free_slot = NULL; - - struct pollfd *entry = self->entries; - for (int i = 0; i < self->len; i++, entry++) { - int entry_fd = entry->fd; - if (entry_fd == fd) { - entry->events = flags; - return mp_const_false; - } - if (entry_fd == -1) { - free_slot = entry; - } - } - - if (free_slot == NULL) { - if (self->len >= self->alloc) { - self->entries = m_renew(struct pollfd, self->entries, self->alloc, self->alloc + 4); - if (self->obj_map) { - self->obj_map = m_renew(mp_obj_t, self->obj_map, self->alloc, self->alloc + 4); - } - self->alloc += 4; - } - free_slot = &self->entries[self->len++]; - } - - if (!is_fd) { - if (self->obj_map == NULL) { - self->obj_map = m_new0(mp_obj_t, self->alloc); - } - self->obj_map[free_slot - self->entries] = args[1]; - } - - free_slot->fd = fd; - free_slot->events = flags; - free_slot->revents = 0; - return mp_const_true; -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); - -/// \method unregister(obj) -STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) { - mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); - struct pollfd *entries = self->entries; - int fd = get_fd(obj_in); - for (int i = self->len - 1; i >= 0; i--) { - if (entries->fd == fd) { - entries->fd = -1; - if (self->obj_map) { - self->obj_map[entries - self->entries] = MP_OBJ_NULL; - } - break; - } - entries++; - } - - // TODO raise KeyError if obj didn't exist in map - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister); - -/// \method modify(obj, eventmask) -STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) { - mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); - struct pollfd *entries = self->entries; - int fd = get_fd(obj_in); - for (int i = self->len - 1; i >= 0; i--) { - if (entries->fd == fd) { - entries->events = mp_obj_get_int(eventmask_in); - return mp_const_none; - } - entries++; - } - - // obj doesn't exist in poller - mp_raise_OSError(MP_ENOENT); -} -MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify); - -STATIC int poll_poll_internal(size_t n_args, const mp_obj_t *args) { - mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); - - // work out timeout (it's given already in ms) - int timeout = -1; - int flags = 0; - if (n_args >= 2) { - if (args[1] != mp_const_none) { - mp_int_t timeout_i = mp_obj_get_int(args[1]); - if (timeout_i >= 0) { - timeout = timeout_i; - } - } - if (n_args >= 3) { - flags = mp_obj_get_int(args[2]); - } - } - - self->flags = flags; - - int n_ready; - MP_HAL_RETRY_SYSCALL(n_ready, poll(self->entries, self->len, timeout), mp_raise_OSError(err)); - return n_ready; -} - -/// \method poll([timeout]) -/// Timeout is in milliseconds. -STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { - int n_ready = poll_poll_internal(n_args, args); - - if (n_ready == 0) { - return mp_const_empty_tuple; - } - - mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); - - mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL)); - int ret_i = 0; - struct pollfd *entries = self->entries; - for (int i = 0; i < self->len; i++, entries++) { - if (entries->revents != 0) { - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); - // If there's an object stored, return it, otherwise raw fd - if (self->obj_map && self->obj_map[i] != MP_OBJ_NULL) { - t->items[0] = self->obj_map[i]; - } else { - t->items[0] = MP_OBJ_NEW_SMALL_INT(entries->fd); - } - t->items[1] = MP_OBJ_NEW_SMALL_INT(entries->revents); - ret_list->items[ret_i++] = MP_OBJ_FROM_PTR(t); - if (self->flags & FLAG_ONESHOT) { - entries->events = 0; - } - } - } - - return MP_OBJ_FROM_PTR(ret_list); -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll); - -STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) { - mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); - - if (self->ret_tuple == MP_OBJ_NULL) { - self->ret_tuple = mp_obj_new_tuple(2, NULL); - } - - int n_ready = poll_poll_internal(n_args, args); - self->iter_cnt = n_ready; - self->iter_idx = 0; - - return args[0]; -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_ipoll_obj, 1, 3, poll_ipoll); - -STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { - mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); - - if (self->iter_cnt == 0) { - return MP_OBJ_STOP_ITERATION; - } - - self->iter_cnt--; - - struct pollfd *entries = self->entries + self->iter_idx; - for (int i = self->iter_idx; i < self->len; i++, entries++) { - self->iter_idx++; - if (entries->revents != 0) { - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple); - // If there's an object stored, return it, otherwise raw fd - if (self->obj_map && self->obj_map[i] != MP_OBJ_NULL) { - t->items[0] = self->obj_map[i]; - } else { - t->items[0] = MP_OBJ_NEW_SMALL_INT(entries->fd); - } - t->items[1] = MP_OBJ_NEW_SMALL_INT(entries->revents); - if (self->flags & FLAG_ONESHOT) { - entries->events = 0; - } - return MP_OBJ_FROM_PTR(t); - } - } - - assert(!"inconsistent number of poll active entries"); - self->iter_cnt = 0; - return MP_OBJ_STOP_ITERATION; -} - -#if DEBUG -STATIC mp_obj_t poll_dump(mp_obj_t self_in) { - mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); - - struct pollfd *entries = self->entries; - for (int i = self->len - 1; i >= 0; i--) { - printf("fd: %d ev: %x rev: %x", entries->fd, entries->events, entries->revents); - if (self->obj_map) { - printf(" obj: %p", self->obj_map[entries - self->entries]); - } - printf("\n"); - entries++; - } - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(poll_dump_obj, poll_dump); -#endif - -STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) }, - { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) }, - { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) }, - { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) }, - { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) }, - #if DEBUG - { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) }, - #endif -}; -STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table); - -STATIC MP_DEFINE_CONST_OBJ_TYPE( - mp_type_poll, - MP_QSTR_poll, - MP_TYPE_FLAG_ITER_IS_ITERNEXT, - iter, poll_iternext, - locals_dict, &poll_locals_dict - ); - -STATIC mp_obj_t select_poll(size_t n_args, const mp_obj_t *args) { - int alloc = 4; - if (n_args > 0) { - alloc = mp_obj_get_int(args[0]); - } - mp_obj_poll_t *poll = mp_obj_malloc(mp_obj_poll_t, &mp_type_poll); - poll->entries = m_new(struct pollfd, alloc); - poll->alloc = alloc; - poll->len = 0; - poll->obj_map = NULL; - poll->iter_cnt = 0; - poll->ret_tuple = MP_OBJ_NULL; - return MP_OBJ_FROM_PTR(poll); -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_poll_obj, 0, 1, select_poll); - -STATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_select) }, - { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) }, - { MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(POLLIN) }, - { MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(POLLOUT) }, - { MP_ROM_QSTR(MP_QSTR_POLLERR), MP_ROM_INT(POLLERR) }, - { MP_ROM_QSTR(MP_QSTR_POLLHUP), MP_ROM_INT(POLLHUP) }, -}; - -STATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table); - -const mp_obj_module_t mp_module_select = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&mp_module_select_globals, -}; - -MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_select, mp_module_select); - -#endif // MICROPY_PY_SELECT_POSIX diff --git a/ports/unix/variants/mpconfigvariant_common.h b/ports/unix/variants/mpconfigvariant_common.h index 8cb1f88e68..9e320d5841 100644 --- a/ports/unix/variants/mpconfigvariant_common.h +++ b/ports/unix/variants/mpconfigvariant_common.h @@ -106,14 +106,8 @@ #define MICROPY_PY_CRYPTOLIB (1) #endif -// Use the posix implementation of the "select" module (unless the variant -// specifically asks for the MicroPython version). -#ifndef MICROPY_PY_SELECT -#define MICROPY_PY_SELECT (0) -#endif -#ifndef MICROPY_PY_SELECT_POSIX -#define MICROPY_PY_SELECT_POSIX (!MICROPY_PY_SELECT) -#endif +// The "select" module is enabled by default, but disable select.select(). +#define MICROPY_PY_SELECT_SELECT (0) // Enable the "websocket" module. #define MICROPY_PY_WEBSOCKET (1) From 7f2efb4144ae2049988574d233ce308f90067b02 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 31 Jul 2023 16:36:08 +1000 Subject: [PATCH 007/121] extmod/modselect: Abstract out a poll_set_t struct and functions. To make it easier to extend and modify this polling implementation. Signed-off-by: Damien George --- extmod/modselect.c | 81 +++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/extmod/modselect.c b/extmod/modselect.c index 3d7ccbd995..2b463176d4 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Damien P. George + * Copyright (c) 2014-2023 Damien P. George * Copyright (c) 2015-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,10 +26,6 @@ */ #include "py/mpconfig.h" -#if MICROPY_PY_SELECT - -#include - #include "py/runtime.h" #include "py/obj.h" #include "py/objlist.h" @@ -37,9 +33,12 @@ #include "py/mperrno.h" #include "py/mphal.h" +#if MICROPY_PY_SELECT + // Flags for poll() #define FLAG_ONESHOT (1) +// A single pollable object. typedef struct _poll_obj_t { mp_obj_t obj; mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); @@ -47,9 +46,25 @@ typedef struct _poll_obj_t { mp_uint_t flags_ret; } poll_obj_t; -STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) { +// A set of pollable objects. +typedef struct _poll_set_t { + // Map containing a dict with key=object to poll, value=its corresponding poll_obj_t. + mp_map_t map; +} poll_set_t; + +STATIC void poll_set_init(poll_set_t *poll_set, size_t n) { + mp_map_init(&poll_set->map, n); +} + +#if MICROPY_PY_SELECT_SELECT +STATIC void poll_set_deinit(poll_set_t *poll_set) { + mp_map_deinit(&poll_set->map); +} +#endif + +STATIC void poll_set_add_obj(poll_set_t *poll_set, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) { for (mp_uint_t i = 0; i < obj_len; i++) { - mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + mp_map_elem_t *elem = mp_map_lookup(&poll_set->map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); if (elem->value == MP_OBJ_NULL) { // object not found; get its ioctl and add it to the poll list const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL); @@ -71,14 +86,14 @@ STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_ } // poll each object in the map -STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) { +STATIC mp_uint_t poll_map_poll(poll_set_t *poll_set, size_t *rwx_num) { mp_uint_t n_ready = 0; - for (mp_uint_t i = 0; i < poll_map->alloc; ++i) { - if (!mp_map_slot_is_filled(poll_map, i)) { + for (mp_uint_t i = 0; i < poll_set->map.alloc; ++i) { + if (!mp_map_slot_is_filled(&poll_set->map, i)) { continue; } - poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map->table[i].value); + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set->map.table[i].value); int errcode; mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode); poll_obj->flags_ret = ret; @@ -133,17 +148,17 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { } // merge separate lists and get the ioctl function for each object - mp_map_t poll_map; - mp_map_init(&poll_map, rwx_len[0] + rwx_len[1] + rwx_len[2]); - poll_map_add(&poll_map, r_array, rwx_len[0], MP_STREAM_POLL_RD, true); - poll_map_add(&poll_map, w_array, rwx_len[1], MP_STREAM_POLL_WR, true); - poll_map_add(&poll_map, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true); + poll_set_t poll_set; + poll_set_init(&poll_set, rwx_len[0] + rwx_len[1] + rwx_len[2]); + poll_set_add_obj(&poll_set, r_array, rwx_len[0], MP_STREAM_POLL_RD, true); + poll_set_add_obj(&poll_set, w_array, rwx_len[1], MP_STREAM_POLL_WR, true); + poll_set_add_obj(&poll_set, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true); mp_uint_t start_tick = mp_hal_ticks_ms(); rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; for (;;) { // poll the objects - mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len); + mp_uint_t n_ready = poll_map_poll(&poll_set, rwx_len); if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { // one or more objects are ready, or we had a timeout @@ -152,11 +167,11 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { list_array[1] = mp_obj_new_list(rwx_len[1], NULL); list_array[2] = mp_obj_new_list(rwx_len[2], NULL); rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; - for (mp_uint_t i = 0; i < poll_map.alloc; ++i) { - if (!mp_map_slot_is_filled(&poll_map, i)) { + for (mp_uint_t i = 0; i < poll_set.map.alloc; ++i) { + if (!mp_map_slot_is_filled(&poll_set.map, i)) { continue; } - poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value); + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set.map.table[i].value); if (poll_obj->flags_ret & MP_STREAM_POLL_RD) { ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj; } @@ -167,7 +182,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj; } } - mp_map_deinit(&poll_map); + poll_set_deinit(&poll_set); return mp_obj_new_tuple(3, list_array); } MICROPY_EVENT_POLL_HOOK @@ -178,7 +193,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select); typedef struct _mp_obj_poll_t { mp_obj_base_t base; - mp_map_t poll_map; + poll_set_t poll_set; short iter_cnt; short iter_idx; int flags; @@ -195,7 +210,7 @@ STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { } else { flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR; } - poll_map_add(&self->poll_map, &args[1], 1, flags, false); + poll_set_add_obj(&self->poll_set, &args[1], 1, flags, false); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); @@ -203,7 +218,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); // unregister(obj) STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); - mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + mp_map_lookup(&self->poll_set.map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND); // TODO raise KeyError if obj didn't exist in map return mp_const_none; } @@ -212,7 +227,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister); // modify(obj, eventmask) STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); - mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&self->poll_set.map, mp_obj_id(obj_in), MP_MAP_LOOKUP); if (elem == NULL) { mp_raise_OSError(MP_ENOENT); } @@ -245,7 +260,7 @@ STATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) { mp_uint_t n_ready; for (;;) { // poll the objects - n_ready = poll_map_poll(&self->poll_map, NULL); + n_ready = poll_map_poll(&self->poll_set, NULL); if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { break; } @@ -262,11 +277,11 @@ STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { // one or more objects are ready, or we had a timeout mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL)); n_ready = 0; - for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) { - if (!mp_map_slot_is_filled(&self->poll_map, i)) { + for (mp_uint_t i = 0; i < self->poll_set.map.alloc; ++i) { + if (!mp_map_slot_is_filled(&self->poll_set.map, i)) { continue; } - poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_set.map.table[i].value); if (poll_obj->flags_ret != 0) { mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)}; ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple); @@ -304,12 +319,12 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { self->iter_cnt--; - for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) { + for (mp_uint_t i = self->iter_idx; i < self->poll_set.map.alloc; ++i) { self->iter_idx++; - if (!mp_map_slot_is_filled(&self->poll_map, i)) { + if (!mp_map_slot_is_filled(&self->poll_set.map, i)) { continue; } - poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_set.map.table[i].value); if (poll_obj->flags_ret != 0) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple); t->items[0] = poll_obj->obj; @@ -347,7 +362,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( // poll() STATIC mp_obj_t select_poll(void) { mp_obj_poll_t *poll = mp_obj_malloc(mp_obj_poll_t, &mp_type_poll); - mp_map_init(&poll->poll_map, 0); + poll_set_init(&poll->poll_set, 0); poll->iter_cnt = 0; poll->ret_tuple = MP_OBJ_NULL; return MP_OBJ_FROM_PTR(poll); From ebc655634650274727c71881e0d36ff738793928 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 31 Jul 2023 17:00:19 +1000 Subject: [PATCH 008/121] extmod/modselect: Factor low-level polling code into common function. Signed-off-by: Damien George --- extmod/modselect.c | 81 ++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/extmod/modselect.c b/extmod/modselect.c index 2b463176d4..7c4e968e80 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -85,8 +85,8 @@ STATIC void poll_set_add_obj(poll_set_t *poll_set, const mp_obj_t *obj, mp_uint_ } } -// poll each object in the map -STATIC mp_uint_t poll_map_poll(poll_set_t *poll_set, size_t *rwx_num) { +// For each object in the poll set, poll it once. +STATIC mp_uint_t poll_set_poll_once(poll_set_t *poll_set, size_t *rwx_num) { mp_uint_t n_ready = 0; for (mp_uint_t i = 0; i < poll_set->map.alloc; ++i) { if (!mp_map_slot_is_filled(&poll_set->map, i)) { @@ -122,6 +122,18 @@ STATIC mp_uint_t poll_map_poll(poll_set_t *poll_set, size_t *rwx_num) { return n_ready; } +STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size_t *rwx_num, mp_uint_t timeout) { + mp_uint_t start_tick = mp_hal_ticks_ms(); + for (;;) { + // poll the objects + mp_uint_t n_ready = poll_set_poll_once(poll_set, rwx_num); + if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { + return n_ready; + } + MICROPY_EVENT_POLL_HOOK + } +} + #if MICROPY_PY_SELECT_SELECT // select(rlist, wlist, xlist[, timeout]) STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { @@ -154,39 +166,33 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { poll_set_add_obj(&poll_set, w_array, rwx_len[1], MP_STREAM_POLL_WR, true); poll_set_add_obj(&poll_set, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true); - mp_uint_t start_tick = mp_hal_ticks_ms(); + // poll all objects rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; - for (;;) { - // poll the objects - mp_uint_t n_ready = poll_map_poll(&poll_set, rwx_len); + poll_set_poll_until_ready_or_timeout(&poll_set, rwx_len, timeout); - if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { - // one or more objects are ready, or we had a timeout - mp_obj_t list_array[3]; - list_array[0] = mp_obj_new_list(rwx_len[0], NULL); - list_array[1] = mp_obj_new_list(rwx_len[1], NULL); - list_array[2] = mp_obj_new_list(rwx_len[2], NULL); - rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; - for (mp_uint_t i = 0; i < poll_set.map.alloc; ++i) { - if (!mp_map_slot_is_filled(&poll_set.map, i)) { - continue; - } - poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set.map.table[i].value); - if (poll_obj->flags_ret & MP_STREAM_POLL_RD) { - ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj; - } - if (poll_obj->flags_ret & MP_STREAM_POLL_WR) { - ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj; - } - if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) { - ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj; - } - } - poll_set_deinit(&poll_set); - return mp_obj_new_tuple(3, list_array); + // one or more objects are ready, or we had a timeout + mp_obj_t list_array[3]; + list_array[0] = mp_obj_new_list(rwx_len[0], NULL); + list_array[1] = mp_obj_new_list(rwx_len[1], NULL); + list_array[2] = mp_obj_new_list(rwx_len[2], NULL); + rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; + for (mp_uint_t i = 0; i < poll_set.map.alloc; ++i) { + if (!mp_map_slot_is_filled(&poll_set.map, i)) { + continue; + } + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set.map.table[i].value); + if (poll_obj->flags_ret & MP_STREAM_POLL_RD) { + ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj; + } + if (poll_obj->flags_ret & MP_STREAM_POLL_WR) { + ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj; + } + if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) { + ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj; } - MICROPY_EVENT_POLL_HOOK } + poll_set_deinit(&poll_set); + return mp_obj_new_tuple(3, list_array); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select); #endif // MICROPY_PY_SELECT_SELECT @@ -256,18 +262,7 @@ STATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) { self->flags = flags; - mp_uint_t start_tick = mp_hal_ticks_ms(); - mp_uint_t n_ready; - for (;;) { - // poll the objects - n_ready = poll_map_poll(&self->poll_set, NULL); - if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { - break; - } - MICROPY_EVENT_POLL_HOOK - } - - return n_ready; + return poll_set_poll_until_ready_or_timeout(&self->poll_set, NULL, timeout); } STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { From ef71028f77e4a6fc449c64906ebad0a160f35240 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 Aug 2023 12:39:39 +1000 Subject: [PATCH 009/121] extmod/modselect: Add optimisation to use system poll when possible. A previous commit removed the unix-specific select module implementation and made unix use the common one. This commit adds an optimisation so that the system poll function is used when polling objects that have a file descriptor. With this optimisation enabled, if code registers both file-descriptor-based objects, and non- file-descriptor-based objects with select.poll() then the following occurs: - the system poll is called for all file-descriptor-based objects with a timeout of 1ms - then the bare-metal polling implementation is used for remaining objects, which calls into their ioctl method (which can be in C or Python) In the case where all objects have file descriptors, the system poll is called with the full timeout requested by the caller. That makes it as efficient as possible in the case everything has a file descriptor. Benefits of this approach: - all ports use the same select module implementation - the unix port now supports polling of all objects and matches bare metal implementations - it's still efficient for existing cases where only files and sockets are polled (on unix) - the bare metal implementation does not change - polling of SSL objects will now work on unix by calling in to the ioctl method on SSL objects (this is required for asyncio ssl support) Note that extmod/vfs_posix_file.c has poll disable when the optimisation is enabled, because the code is not reachable when the optimisation is used. Signed-off-by: Damien George --- extmod/modselect.c | 308 +++++++++++++++++-- extmod/vfs_posix_file.c | 2 +- ports/unix/variants/mpconfigvariant_common.h | 1 + py/mpconfig.h | 7 +- 4 files changed, 284 insertions(+), 34 deletions(-) diff --git a/extmod/modselect.c b/extmod/modselect.c index 7c4e968e80..01b1474d75 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -35,6 +35,29 @@ #if MICROPY_PY_SELECT +#if MICROPY_PY_SELECT_SELECT && MICROPY_PY_SELECT_POSIX_OPTIMISATIONS +#error "select.select is not supported with MICROPY_PY_SELECT_POSIX_OPTIMISATIONS" +#endif + +#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + +#include + +#if !((MP_STREAM_POLL_RD) == (POLLIN) && \ + (MP_STREAM_POLL_WR) == (POLLOUT) && \ + (MP_STREAM_POLL_ERR) == (POLLERR) && \ + (MP_STREAM_POLL_HUP) == (POLLHUP) && \ + (MP_STREAM_POLL_NVAL) == (POLLNVAL)) +#error "With MICROPY_PY_SELECT_POSIX_OPTIMISATIONS enabled, POLL constants must match" +#endif + +// When non-file-descriptor objects are on the list to be polled (the polling of +// which involves repeatedly calling ioctl(MP_STREAM_POLL)), this variable sets +// the period between polling these objects. +#define MICROPY_PY_SELECT_IOCTL_CALL_PERIOD_MS (1) + +#endif + // Flags for poll() #define FLAG_ONESHOT (1) @@ -42,18 +65,42 @@ typedef struct _poll_obj_t { mp_obj_t obj; mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); - mp_uint_t flags; - mp_uint_t flags_ret; + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + // If the pollable object has an associated file descriptor, then pollfd points to an entry + // in poll_set_t::pollfds, and the events/revents fields for this object are stored in the + // pollfd entry (and the nonfd_* members are unused). + // Otherwise the object is a non-file-descriptor object and pollfd==NULL, and the events/ + // revents fields are stored in the nonfd_* members (which are named as such so that code + // doesn't accidentally mix the use of these members when this optimisation is used). + struct pollfd *pollfd; + uint16_t nonfd_events; + uint16_t nonfd_revents; + #else + mp_uint_t events; + mp_uint_t revents; + #endif } poll_obj_t; // A set of pollable objects. typedef struct _poll_set_t { // Map containing a dict with key=object to poll, value=its corresponding poll_obj_t. mp_map_t map; + + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + // Array of pollfd entries for objects that have a file descriptor. + unsigned short alloc; + unsigned short len; + struct pollfd *pollfds; + #endif } poll_set_t; STATIC void poll_set_init(poll_set_t *poll_set, size_t n) { mp_map_init(&poll_set->map, n); + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + poll_set->alloc = 0; + poll_set->len = 0; + poll_set->pollfds = NULL; + #endif } #if MICROPY_PY_SELECT_SELECT @@ -62,25 +109,141 @@ STATIC void poll_set_deinit(poll_set_t *poll_set) { } #endif -STATIC void poll_set_add_obj(poll_set_t *poll_set, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) { +#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + +STATIC mp_uint_t poll_obj_get_events(poll_obj_t *poll_obj) { + assert(poll_obj->pollfd == NULL); + return poll_obj->nonfd_events; +} + +STATIC void poll_obj_set_events(poll_obj_t *poll_obj, mp_uint_t events) { + if (poll_obj->pollfd != NULL) { + poll_obj->pollfd->events = events; + } else { + poll_obj->nonfd_events = events; + } +} + +STATIC mp_uint_t poll_obj_get_revents(poll_obj_t *poll_obj) { + if (poll_obj->pollfd != NULL) { + return poll_obj->pollfd->revents; + } else { + return poll_obj->nonfd_revents; + } +} + +STATIC void poll_obj_set_revents(poll_obj_t *poll_obj, mp_uint_t revents) { + if (poll_obj->pollfd != NULL) { + poll_obj->pollfd->revents = revents; + } else { + poll_obj->nonfd_revents = revents; + } +} + +STATIC struct pollfd *poll_set_add_fd(poll_set_t *poll_set, int fd) { + struct pollfd *free_slot = NULL; + for (unsigned int i = 0; i < poll_set->len; ++i) { + struct pollfd *slot = &poll_set->pollfds[i]; + if (slot->fd == -1) { + free_slot = slot; + break; + } + } + + if (free_slot == NULL) { + if (poll_set->len >= poll_set->alloc) { + poll_set->pollfds = m_renew(struct pollfd, poll_set->pollfds, poll_set->alloc, poll_set->alloc + 4); + poll_set->alloc += 4; + } + free_slot = &poll_set->pollfds[poll_set->len++]; + } + + free_slot->fd = fd; + + return free_slot; +} + +static inline bool poll_set_all_are_fds(poll_set_t *poll_set) { + return poll_set->map.used == poll_set->len; +} + +#else + +static inline mp_uint_t poll_obj_get_events(poll_obj_t *poll_obj) { + return poll_obj->events; +} + +static inline void poll_obj_set_events(poll_obj_t *poll_obj, mp_uint_t events) { + poll_obj->events = events; +} + +static inline mp_uint_t poll_obj_get_revents(poll_obj_t *poll_obj) { + return poll_obj->revents; +} + +static inline void poll_obj_set_revents(poll_obj_t *poll_obj, mp_uint_t revents) { + poll_obj->revents = revents; +} + +#endif + +STATIC void poll_set_add_obj(poll_set_t *poll_set, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t events, bool or_events) { for (mp_uint_t i = 0; i < obj_len; i++) { mp_map_elem_t *elem = mp_map_lookup(&poll_set->map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); if (elem->value == MP_OBJ_NULL) { // object not found; get its ioctl and add it to the poll list - const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL); + + // If an exception is raised below when adding the new object then the map entry for that + // object remains unpopulated, and methods like poll() may crash. This case is not handled. + poll_obj_t *poll_obj = m_new_obj(poll_obj_t); poll_obj->obj = obj[i]; + + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + int fd = -1; + if (mp_obj_is_int(obj[i])) { + // A file descriptor integer passed in as the object, so use it directly. + fd = mp_obj_get_int(obj[i]); + if (fd < 0) { + mp_raise_ValueError(NULL); + } + poll_obj->ioctl = NULL; + } else { + // An object passed in. Check if it has a file descriptor. + const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL); + poll_obj->ioctl = stream_p->ioctl; + int err; + mp_uint_t res = stream_p->ioctl(obj[i], MP_STREAM_GET_FILENO, 0, &err); + if (res != MP_STREAM_ERROR) { + fd = res; + } + } + if (fd >= 0) { + // Object has a file descriptor so add it to pollfds. + poll_obj->pollfd = poll_set_add_fd(poll_set, fd); + } else { + // Object doesn't have a file descriptor. + poll_obj->pollfd = NULL; + } + #else + const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL); poll_obj->ioctl = stream_p->ioctl; - poll_obj->flags = flags; - poll_obj->flags_ret = 0; + #endif + + poll_obj_set_events(poll_obj, events); + poll_obj_set_revents(poll_obj, 0); elem->value = MP_OBJ_FROM_PTR(poll_obj); } else { - // object exists; update its flags - if (or_flags) { - ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags |= flags; - } else { - ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = flags; + // object exists; update its events + poll_obj_t *poll_obj = (poll_obj_t *)MP_OBJ_TO_PTR(elem->value); + #if MICROPY_PY_SELECT_SELECT + if (or_events) { + events |= poll_obj_get_events(poll_obj); } + #else + (void)or_events; + #endif + poll_obj_set_events(poll_obj, events); } } } @@ -94,9 +257,17 @@ STATIC mp_uint_t poll_set_poll_once(poll_set_t *poll_set, size_t *rwx_num) { } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set->map.table[i].value); + + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + if (poll_obj->pollfd != NULL) { + // Object has file descriptor so will be polled separately by poll(). + continue; + } + #endif + int errcode; - mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode); - poll_obj->flags_ret = ret; + mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj_get_events(poll_obj), &errcode); + poll_obj_set_revents(poll_obj, ret); if (ret == -1) { // error doing ioctl @@ -106,6 +277,7 @@ STATIC mp_uint_t poll_set_poll_once(poll_set_t *poll_set, size_t *rwx_num) { if (ret != 0) { // object is ready n_ready += 1; + #if MICROPY_PY_SELECT_SELECT if (rwx_num != NULL) { if (ret & MP_STREAM_POLL_RD) { rwx_num[0] += 1; @@ -117,21 +289,80 @@ STATIC mp_uint_t poll_set_poll_once(poll_set_t *poll_set, size_t *rwx_num) { rwx_num[2] += 1; } } + #else + (void)rwx_num; + #endif } } return n_ready; } STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size_t *rwx_num, mp_uint_t timeout) { - mp_uint_t start_tick = mp_hal_ticks_ms(); + mp_uint_t start_ticks = mp_hal_ticks_ms(); + + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + + for (;;) { + MP_THREAD_GIL_EXIT(); + + // Compute the timeout. + int t = MICROPY_PY_SELECT_IOCTL_CALL_PERIOD_MS; + if (poll_set_all_are_fds(poll_set)) { + // All our pollables are file descriptors, so we can use a blocking + // poll and let it (the underlying system) handle the timeout. + if (timeout == (mp_uint_t)-1) { + t = -1; + } else { + mp_uint_t delta = mp_hal_ticks_ms() - start_ticks; + if (delta >= timeout) { + t = 0; + } else { + t = timeout - delta; + } + } + } + + // Call system poll for those objects that have a file descriptor. + int n_ready = poll(poll_set->pollfds, poll_set->len, t); + + MP_THREAD_GIL_ENTER(); + + // The call to poll() may have been interrupted, but per PEP 475 we must retry if the + // signal is EINTR (this implements a special case of calling MP_HAL_RETRY_SYSCALL()). + if (n_ready == -1) { + int err = errno; + if (err != EINTR) { + mp_raise_OSError(err); + } + n_ready = 0; + } + + // Explicitly poll any objects that do not have a file descriptor. + if (!poll_set_all_are_fds(poll_set)) { + n_ready += poll_set_poll_once(poll_set, rwx_num); + } + + // Return if an object is ready, or if the timeout expired. + if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) { + return n_ready; + } + + // This would be MICROPY_EVENT_POLL_HOOK but the call to poll() above already includes a delay. + mp_handle_pending(true); + } + + #else + for (;;) { // poll the objects mp_uint_t n_ready = poll_set_poll_once(poll_set, rwx_num); - if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) { + if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) { return n_ready; } MICROPY_EVENT_POLL_HOOK } + + #endif } #if MICROPY_PY_SELECT_SELECT @@ -181,13 +412,13 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set.map.table[i].value); - if (poll_obj->flags_ret & MP_STREAM_POLL_RD) { + if (poll_obj->revents & MP_STREAM_POLL_RD) { ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj; } - if (poll_obj->flags_ret & MP_STREAM_POLL_WR) { + if (poll_obj->revents & MP_STREAM_POLL_WR) { ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj; } - if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) { + if ((poll_obj->revents & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) { ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj; } } @@ -210,13 +441,13 @@ typedef struct _mp_obj_poll_t { // register(obj[, eventmask]) STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); - mp_uint_t flags; + mp_uint_t events; if (n_args == 3) { - flags = mp_obj_get_int(args[2]); + events = mp_obj_get_int(args[2]); } else { - flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR; + events = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR; } - poll_set_add_obj(&self->poll_set, &args[1], 1, flags, false); + poll_set_add_obj(&self->poll_set, &args[1], 1, events, false); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); @@ -224,7 +455,20 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); // unregister(obj) STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); - mp_map_lookup(&self->poll_set.map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + mp_map_elem_t *elem = mp_map_lookup(&self->poll_set.map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + + #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS + if (elem != NULL) { + poll_obj_t *poll_obj = (poll_obj_t *)MP_OBJ_TO_PTR(elem->value); + if (poll_obj->pollfd != NULL) { + poll_obj->pollfd->fd = -1; + } + elem->value = MP_OBJ_NULL; + } + #else + (void)elem; + #endif + // TODO raise KeyError if obj didn't exist in map return mp_const_none; } @@ -237,7 +481,7 @@ STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmas if (elem == NULL) { mp_raise_OSError(MP_ENOENT); } - ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = mp_obj_get_int(eventmask_in); + poll_obj_set_events((poll_obj_t *)MP_OBJ_TO_PTR(elem->value), mp_obj_get_int(eventmask_in)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify); @@ -277,12 +521,12 @@ STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_set.map.table[i].value); - if (poll_obj->flags_ret != 0) { - mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)}; + if (poll_obj_get_revents(poll_obj) != 0) { + mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj_get_revents(poll_obj))}; ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple); if (self->flags & FLAG_ONESHOT) { - // Don't poll next time, until new event flags will be set explicitly - poll_obj->flags = 0; + // Don't poll next time, until new event mask will be set explicitly + poll_obj_set_events(poll_obj, 0); } } } @@ -320,13 +564,13 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { continue; } poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_set.map.table[i].value); - if (poll_obj->flags_ret != 0) { + if (poll_obj_get_revents(poll_obj) != 0) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple); t->items[0] = poll_obj->obj; - t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret); + t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj_get_revents(poll_obj)); if (self->flags & FLAG_ONESHOT) { - // Don't poll next time, until new event flags will be set explicitly - poll_obj->flags = 0; + // Don't poll next time, until new event mask will be set explicitly + poll_obj_set_events(poll_obj, 0); } return MP_OBJ_FROM_PTR(t); } diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 41d7622b37..d70bc4738e 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -188,7 +188,7 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ return 0; case MP_STREAM_GET_FILENO: return o->fd; - #if MICROPY_PY_SELECT + #if MICROPY_PY_SELECT && !MICROPY_PY_SELECT_POSIX_OPTIMISATIONS case MP_STREAM_POLL: { #ifdef _WIN32 mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32")); diff --git a/ports/unix/variants/mpconfigvariant_common.h b/ports/unix/variants/mpconfigvariant_common.h index 9e320d5841..082938ed5f 100644 --- a/ports/unix/variants/mpconfigvariant_common.h +++ b/ports/unix/variants/mpconfigvariant_common.h @@ -107,6 +107,7 @@ #endif // The "select" module is enabled by default, but disable select.select(). +#define MICROPY_PY_SELECT_POSIX_OPTIMISATIONS (1) #define MICROPY_PY_SELECT_SELECT (0) // Enable the "websocket" module. diff --git a/py/mpconfig.h b/py/mpconfig.h index c617f573b6..4a15205ae3 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1485,11 +1485,16 @@ typedef double mp_float_t; #define MICROPY_PY_ERRNO_ERRORCODE (1) #endif -// Whether to provide "select" module (baremetal implementation) +// Whether to provide "select" module #ifndef MICROPY_PY_SELECT #define MICROPY_PY_SELECT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif +// Whether to enable POSIX optimisations in the "select" module (requires system poll) +#ifndef MICROPY_PY_SELECT_POSIX_OPTIMISATIONS +#define MICROPY_PY_SELECT_POSIX_OPTIMISATIONS (0) +#endif + // Whether to enable the select() function in the "select" module (baremetal // implementation). This is present for compatibility but can be disabled to // save space. From 3f417e894309ee769b80aea85e9a45a826482c64 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 2 Aug 2023 10:04:13 +1000 Subject: [PATCH 010/121] extmod/modselect: Remove undocumented support for flags arg to poll. The signature of this method was poller.poll(timeout=-1, flags=0, /) but the flags argument was not documented and is not CPython compatible. So it's removed in this commit. (The optional flags remains for the ipoll() method, which is documented.) Signed-off-by: Damien George --- extmod/modselect.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/extmod/modselect.c b/extmod/modselect.c index 01b1474d75..7c65e7dcaf 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -58,7 +58,7 @@ #endif -// Flags for poll() +// Flags for ipoll() #define FLAG_ONESHOT (1) // A single pollable object. @@ -524,15 +524,11 @@ STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { if (poll_obj_get_revents(poll_obj) != 0) { mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj_get_revents(poll_obj))}; ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple); - if (self->flags & FLAG_ONESHOT) { - // Don't poll next time, until new event mask will be set explicitly - poll_obj_set_events(poll_obj, 0); - } } } return MP_OBJ_FROM_PTR(ret_list); } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 2, poll_poll); STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) { mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); From 6b78a1bf00b4d95b018e64f84bc1f5a36502940e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 1 Aug 2023 22:54:52 +1000 Subject: [PATCH 011/121] tests/extmod: Add coverage tests for select module. Signed-off-by: Damien George --- tests/extmod/select_ipoll.py | 55 +++++++++++++++++ tests/extmod/select_ipoll.py.exp | 6 ++ tests/extmod/select_poll_basic.py | 1 + tests/extmod/select_poll_custom.py | 83 ++++++++++++++++++++++++++ tests/extmod/select_poll_custom.py.exp | 11 ++++ tests/extmod/select_poll_eintr.py | 47 +++++++++++++++ tests/extmod/select_poll_fd.py | 44 ++++++++++++++ 7 files changed, 247 insertions(+) create mode 100644 tests/extmod/select_ipoll.py create mode 100644 tests/extmod/select_ipoll.py.exp create mode 100644 tests/extmod/select_poll_custom.py create mode 100644 tests/extmod/select_poll_custom.py.exp create mode 100644 tests/extmod/select_poll_eintr.py create mode 100644 tests/extmod/select_poll_fd.py diff --git a/tests/extmod/select_ipoll.py b/tests/extmod/select_ipoll.py new file mode 100644 index 0000000000..0b661c11c8 --- /dev/null +++ b/tests/extmod/select_ipoll.py @@ -0,0 +1,55 @@ +# Test select.ipoll(). + +try: + import socket, select +except ImportError: + print("SKIP") + raise SystemExit + + +def print_poll_output(lst): + print([(type(obj), flags) for obj, flags in lst]) + + +poller = select.poll() + +# Use a new UDP socket for tests, which should be writable but not readable. +try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) +except OSError: + print("SKIP") + raise SystemExit + +poller.register(s) + +# Basic polling. +print_poll_output(poller.ipoll(0)) + +# Pass in flags=1 for one-shot behaviour. +print_poll_output(poller.ipoll(0, 1)) + +# Socket should be deregistered and poll should return nothing. +print_poll_output(poller.ipoll(0)) + +# Create a second socket. +s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +s2.bind(socket.getaddrinfo("127.0.0.1", 8001)[0][-1]) + +# Register both sockets (to reset the first one). +poller.register(s) +poller.register(s2) + +# Basic polling with two sockets. +print_poll_output(poller.ipoll(0)) + +# Unregister the first socket, to test polling the remaining one. +poller.unregister(s) +print_poll_output(poller.ipoll(0)) + +# Unregister the second socket, to test polling none. +poller.unregister(s2) +print_poll_output(poller.ipoll(0)) + +s2.close() +s.close() diff --git a/tests/extmod/select_ipoll.py.exp b/tests/extmod/select_ipoll.py.exp new file mode 100644 index 0000000000..cbeabdce90 --- /dev/null +++ b/tests/extmod/select_ipoll.py.exp @@ -0,0 +1,6 @@ +[(, 4)] +[(, 4)] +[] +[(, 4), (, 4)] +[(, 4)] +[] diff --git a/tests/extmod/select_poll_basic.py b/tests/extmod/select_poll_basic.py index b36e16f018..0814d89ce9 100644 --- a/tests/extmod/select_poll_basic.py +++ b/tests/extmod/select_poll_basic.py @@ -16,6 +16,7 @@ poller.register(s) # "Registering a file descriptor that’s already registered is not an error, # and has the same effect as registering the descriptor exactly once." poller.register(s) +poller.register(s, select.POLLIN | select.POLLOUT) # 2 args are mandatory unlike register() try: diff --git a/tests/extmod/select_poll_custom.py b/tests/extmod/select_poll_custom.py new file mode 100644 index 0000000000..0cbb610327 --- /dev/null +++ b/tests/extmod/select_poll_custom.py @@ -0,0 +1,83 @@ +# Test custom pollable objects implemented in Python. + +from micropython import const + +try: + import socket, select, io +except ImportError: + print("SKIP") + raise SystemExit + +_MP_STREAM_POLL = const(3) +_MP_STREAM_GET_FILENO = const(10) + +_MP_STREAM_POLL_RD = const(0x0001) +_MP_STREAM_POLL_WR = const(0x0004) + + +def print_poll_output(lst): + print([(type(obj), flags) for obj, flags in lst]) + + +class CustomPollable(io.IOBase): + def __init__(self): + self.poll_state = 0 + + def ioctl(self, cmd, arg): + if cmd == _MP_STREAM_GET_FILENO: + # Bare-metal ports don't call this ioctl, so don't print it. + return -1 + + print("CustomPollable.ioctl", cmd, arg) + if cmd == _MP_STREAM_POLL: + if self.poll_state == "delay_rd": + self.poll_state = _MP_STREAM_POLL_RD + return 0 + elif self.poll_state < 0: + return self.poll_state + else: + return self.poll_state & arg + + +poller = select.poll() + +# Use a new UDP socket for tests, which should be writable but not readable. +try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) +except OSError: + print("SKIP") + raise SystemExit + +x = CustomPollable() + +# Register both a file-descriptor-based object and a custom pure-Python object. +poller.register(s) +poller.register(x) + +# Modify the flags for the custom object. +poller.modify(x, select.POLLIN) + +# Test polling. +print_poll_output(poller.poll(0)) +x.poll_state = _MP_STREAM_POLL_WR +print_poll_output(poller.poll(0)) +x.poll_state = _MP_STREAM_POLL_RD +print_poll_output(poller.poll(0)) + +# The custom object becomes readable only after being polled. +poller.modify(s, select.POLLIN) +x.poll_state = "delay_rd" +print_poll_output(poller.poll()) + +# The custom object returns an error. +x.poll_state = -1000 +try: + poller.poll(0) +except OSError as er: + print("OSError", er.errno) + +poller.unregister(x) +poller.unregister(s) + +s.close() diff --git a/tests/extmod/select_poll_custom.py.exp b/tests/extmod/select_poll_custom.py.exp new file mode 100644 index 0000000000..bcb4d83e2d --- /dev/null +++ b/tests/extmod/select_poll_custom.py.exp @@ -0,0 +1,11 @@ +CustomPollable.ioctl 3 1 +[(, 4)] +CustomPollable.ioctl 3 1 +[(, 4)] +CustomPollable.ioctl 3 1 +[(, 4), (, 1)] +CustomPollable.ioctl 3 1 +CustomPollable.ioctl 3 1 +[(, 1)] +CustomPollable.ioctl 3 1 +OSError 1000 diff --git a/tests/extmod/select_poll_eintr.py b/tests/extmod/select_poll_eintr.py new file mode 100644 index 0000000000..f53efcc83e --- /dev/null +++ b/tests/extmod/select_poll_eintr.py @@ -0,0 +1,47 @@ +# Test interruption of select.poll by EINTR signal, when +# MICROPY_PY_SELECT_POSIX_OPTIMISATIONS is enabled. + +try: + import time, gc, select, socket, _thread + + time.time_ns # Check for time_ns on MicroPython + select.poll # Raises AttributeError for CPython implementations without poll() +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +def thread_main(): + lock.acquire() + time.sleep(0.2) + print("thread gc start") + # The unix gc.collect() implementation will raise EINTR on other threads. + # Could possibly use _thread._interrupt_main() instead if MicroPython had it. + gc.collect() + print("thread gc end") + + +# Start a thread to interrupt the main thread during its call to poll. +lock = _thread.allocate_lock() +lock.acquire() +_thread.start_new_thread(thread_main, ()) + +# Use a new UDP socket for tests, which should be writable but not readable. +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) + +# Create the poller object. +poller = select.poll() +poller.register(s, select.POLLIN) + +# Poll on the UDP socket for a set timeout, which should be reached. +print("poll") +lock.release() +t0 = time.time_ns() +result = poller.poll(400) +dt_ms = (time.time_ns() - t0) / 1e6 +print("result:", result) +print("dt in range:", 380 <= dt_ms <= 500) + +# Clean up. +s.close() diff --git a/tests/extmod/select_poll_fd.py b/tests/extmod/select_poll_fd.py new file mode 100644 index 0000000000..fab9c0e0e9 --- /dev/null +++ b/tests/extmod/select_poll_fd.py @@ -0,0 +1,44 @@ +# Test select.poll in combination with file descriptors. + +try: + import select, errno + + select.poll # Raises AttributeError for CPython implementations without poll() +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +# Check that poll supports registering file descriptors (integers). +try: + select.poll().register(0) +except OSError: + print("SKIP") + raise SystemExit + +# Register invalid file descriptor. +try: + select.poll().register(-1) +except ValueError: + print("ValueError") + +# Test polling stdout, it should be writable. +poller = select.poll() +poller.register(1) +poller.modify(1, select.POLLOUT) +print(poller.poll()) + +# Unregister then re-register. +poller.unregister(1) +poller.register(1, select.POLLIN) + +# Poll for input, should return an empty list. +print(poller.poll(0)) + +# Test registering a very large number of file descriptors. +poller = select.poll() +for fd in range(6000): + poller.register(fd) +try: + poller.poll() +except OSError as er: + print(er.errno == errno.EINVAL) From 218242d1de781124307be8720a7a9d2f373ca46b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 7 Aug 2023 12:36:00 +1000 Subject: [PATCH 012/121] tests/extmod: Skip select/socket tests if they can't create UDP socket. Some targets (eg PYBV10) have the socket module but are unable to create UDP sockets without a registered NIC. So skip UDP tests on these targets. Signed-off-by: Damien George --- tests/extmod/select_poll_udp.py | 8 ++++++-- tests/extmod/socket_udp_nonblock.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/extmod/select_poll_udp.py b/tests/extmod/select_poll_udp.py index 336f987c12..133871b1a4 100644 --- a/tests/extmod/select_poll_udp.py +++ b/tests/extmod/select_poll_udp.py @@ -8,9 +8,13 @@ except (ImportError, AttributeError): print("SKIP") raise SystemExit +try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) +except OSError: + print("SKIP") + raise SystemExit -s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) poll = select.poll() # UDP socket should not be readable diff --git a/tests/extmod/socket_udp_nonblock.py b/tests/extmod/socket_udp_nonblock.py index f7ce5f3444..1e74e2917d 100644 --- a/tests/extmod/socket_udp_nonblock.py +++ b/tests/extmod/socket_udp_nonblock.py @@ -6,9 +6,13 @@ except ImportError: print("SKIP") raise SystemExit +try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) +except OSError: + print("SKIP") + raise SystemExit -s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) s.settimeout(0) try: From 20d3a6b1964705596d690182956f56b4f7678041 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 9 Aug 2023 13:17:04 +1000 Subject: [PATCH 013/121] extmod/modssl_mbedtls: Reject ioctls that are not supported. An SSL stream can only handle CLOSE and POLL ioctls. Other ones do not make sense, or at least it doesn't make sense to pass the ioctl request directly down to the underlying stream. In particular MP_STREAM_GET_FILENO should not be passed to the underlying stream because the SSL stream is not directly related to a file descriptor, and the SSL stream must handle the polling itself. Signed-off-by: Damien George --- extmod/modssl_mbedtls.c | 4 ++++ tests/extmod/ssl_ioctl.py | 31 +++++++++++++++++++++++++++++++ tests/extmod/ssl_ioctl.py.exp | 6 ++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/extmod/ssl_ioctl.py create mode 100644 tests/extmod/ssl_ioctl.py.exp diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 6d78d7d1b3..8974ff65dd 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -514,6 +514,10 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i } } } + } else { + // Unsupported ioctl. + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; } // Pass all requests down to the underlying socket diff --git a/tests/extmod/ssl_ioctl.py b/tests/extmod/ssl_ioctl.py new file mode 100644 index 0000000000..4db7c2df82 --- /dev/null +++ b/tests/extmod/ssl_ioctl.py @@ -0,0 +1,31 @@ +# Test SSL ioctl method. +# Direct access to this method is only available if MICROPY_UNIX_COVERAGE is enabled. + +try: + import io, ssl + + io.BytesIO +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +_MP_STREAM_POLL = 3 +_MP_STREAM_CLOSE = 4 +_MP_STREAM_GET_FILENO = 10 + +s = ssl.wrap_socket(io.BytesIO(), server_side=1, do_handshake=0) + +if not hasattr(s, "ioctl"): + print("SKIP") + raise SystemExit + +# These ioctl's should be unsupported. +for request in (-1, 0, _MP_STREAM_GET_FILENO): + try: + s.ioctl(request, 0) + except OSError: + print(request, "OSError") + +# These ioctl's should be supported. +for request in (_MP_STREAM_CLOSE, _MP_STREAM_POLL, _MP_STREAM_CLOSE): + print(request, s.ioctl(request, 0)) diff --git a/tests/extmod/ssl_ioctl.py.exp b/tests/extmod/ssl_ioctl.py.exp new file mode 100644 index 0000000000..72de7ed06d --- /dev/null +++ b/tests/extmod/ssl_ioctl.py.exp @@ -0,0 +1,6 @@ +-1 OSError +0 OSError +10 OSError +4 0 +3 32 +4 32 From d529c20674131b9ce36853b92784e901a1bc86f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 9 Aug 2023 13:19:18 +1000 Subject: [PATCH 014/121] extmod/modssl_mbedtls: Fix ioctl of a socket in closed/error state. Signed-off-by: Damien George --- extmod/modssl_mbedtls.c | 13 +++++++++---- tests/extmod/ssl_ioctl.py.exp | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 8974ff65dd..b02b77b76f 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -486,15 +486,20 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i mp_uint_t ret = 0; uintptr_t saved_arg = 0; mp_obj_t sock = self->sock; - if (sock == MP_OBJ_NULL || (request != MP_STREAM_CLOSE && self->last_error != 0)) { - // Closed or error socket: - return MP_STREAM_POLL_NVAL; - } if (request == MP_STREAM_CLOSE) { + if (sock == MP_OBJ_NULL) { + // Already closed socket, do nothing. + return 0; + } self->sock = MP_OBJ_NULL; mbedtls_ssl_free(&self->ssl); } else if (request == MP_STREAM_POLL) { + if (sock == MP_OBJ_NULL || self->last_error != 0) { + // Closed or error socket, return NVAL flag. + return MP_STREAM_POLL_NVAL; + } + // If the library signaled us that it needs reading or writing, only check that direction, // but save what the caller asked because we need to restore it later if (self->poll_mask && (arg & MP_STREAM_POLL_RDWR)) { diff --git a/tests/extmod/ssl_ioctl.py.exp b/tests/extmod/ssl_ioctl.py.exp index 72de7ed06d..22208b00cc 100644 --- a/tests/extmod/ssl_ioctl.py.exp +++ b/tests/extmod/ssl_ioctl.py.exp @@ -3,4 +3,4 @@ 10 OSError 4 0 3 32 -4 32 +4 0 From 597fcb47518c842d445975961737832569fe3529 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 17:41:54 +1000 Subject: [PATCH 015/121] tools/mpy-tool.py: Use isinstance() for type checking. Ruff version 283 expanded E721 to fail when making direct comparison against a built-in type. Change the code to use isinstance() as suggested, these usages appear to have equivalent functionality. Signed-off-by: Angus Gratton --- tools/mpy-tool.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 7f581d0b13..a5112de9a1 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -33,9 +33,9 @@ if platform.python_version_tuple()[0] == "2": str_cons = lambda val, enc=None: str(val) bytes_cons = lambda val, enc=None: bytearray(val) - is_str_type = lambda o: type(o) is str + is_str_type = lambda o: isinstance(o, str) is_bytes_type = lambda o: type(o) is bytearray - is_int_type = lambda o: type(o) is int or type(o) is long + is_int_type = lambda o: isinstance(o, int) or isinstance(o, long) def hexlify_to_str(b): x = hexlify_py2(b) @@ -46,9 +46,9 @@ else: str_cons = str bytes_cons = bytes - is_str_type = lambda o: type(o) is str - is_bytes_type = lambda o: type(o) is bytes - is_int_type = lambda o: type(o) is int + is_str_type = lambda o: isinstance(o, str) + is_bytes_type = lambda o: isinstance(o, bytes) + is_int_type = lambda o: isinstance(o, int) def hexlify_to_str(b): return str(hexlify(b, ":"), "ascii") @@ -756,7 +756,7 @@ class CompiledModule: const_int_content += (digs.count(",") + 1) * bits_per_dig // 8 const_obj_content += 4 * 4 return "MP_ROM_PTR(&%s)" % obj_name - elif type(obj) is float: + elif isinstance(obj, float): macro_name = "%s_macro" % obj_name print( "#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B" @@ -777,7 +777,7 @@ class CompiledModule: print("#endif") const_obj_content += 3 * 4 return macro_name - elif type(obj) is complex: + elif isinstance(obj, complex): print( "static const mp_obj_complex_t %s = {{&mp_type_complex}, (mp_float_t)%.16g, (mp_float_t)%.16g};" % (obj_name, obj.real, obj.imag) From 8dbb29da3fe733f5a1350c5f9d3d7c3bc71870d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20de=20Giessen?= Date: Wed, 9 Aug 2023 12:50:24 +0200 Subject: [PATCH 016/121] tools/codeformat.py: Skip formatting ESP-IDF managed components. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniël van de Giessen --- tools/codeformat.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/codeformat.py b/tools/codeformat.py index 517aced37a..93a4b14123 100755 --- a/tools/codeformat.py +++ b/tools/codeformat.py @@ -60,6 +60,8 @@ PATHS = [ EXCLUSIONS = [ # The cc3200 port is not fully formatted yet. "ports/cc3200/*/*.[ch]", + # ESP-IDF downloads 3rd party code. + "ports/esp32/managed_components/*", # The nrf port is not fully formatted yet. "ports/nrf/boards/*.[ch]", "ports/nrf/device/*.[ch]", From 232c29c2ed799a520bbdb5e4729a71ea7f0335ce Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Wed, 2 Aug 2023 10:07:31 +0200 Subject: [PATCH 017/121] tools/codeformat.py: Use pyproject.toml for black config. Signed-off-by: Jos Verlinde --- tools/codeformat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/codeformat.py b/tools/codeformat.py index 93a4b14123..761bde3a81 100755 --- a/tools/codeformat.py +++ b/tools/codeformat.py @@ -90,6 +90,7 @@ EXCLUSIONS = [ TOP = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) UNCRUSTIFY_CFG = os.path.join(TOP, "tools/uncrustify.cfg") +PYPROJECT_TOML = os.path.join(TOP, "pyproject.toml") C_EXTS = ( ".c", @@ -208,7 +209,7 @@ def main(): # Format Python files with black. if format_py: - command = ["black", "--fast", "--line-length=99"] + command = ["black", "--fast", "--config={}".format(PYPROJECT_TOML)] if args.v: command.append("-v") else: From 4bbe879c2668e5fd81f266a0779387337858cbf9 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 7 Aug 2023 11:20:12 +1000 Subject: [PATCH 018/121] tools/mpremote: Make soft-reset count as an action. Otherwise `mpremote soft-reset` will implicitly run the repl command. Fixes issue #10871. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- tools/mpremote/mpremote/commands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/mpremote/mpremote/commands.py b/tools/mpremote/mpremote/commands.py index de12aa0bb1..aae612765b 100644 --- a/tools/mpremote/mpremote/commands.py +++ b/tools/mpremote/mpremote/commands.py @@ -238,6 +238,7 @@ def do_resume(state, _args=None): def do_soft_reset(state, _args=None): state.ensure_raw_repl(soft_reset=True) + state.did_action() def do_rtc(state, args): From 24a6e951ec7696b8d18d95fe5da36f7e489913d0 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 4 Aug 2023 16:54:33 +1000 Subject: [PATCH 019/121] ports: Simplify board feature tags in board.json. This commit: - Finds a common set of board feature tags and maps existing features to that reduced set. - Removes some less-useful board feature tags. - Ensures all MCUs are specified correctly. - Ensures all boards have a vendor (and fixes some vendor names). This is to make the downloads page show a less intimidating set of filters. Work done in conjunction with Matt Trentini . This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/cc3200/boards/WIPY/board.json | 7 +++---- .../esp32/boards/ARDUINO_NANO_ESP32/board.json | 5 +++-- ports/esp32/boards/ESP32_S2_WROVER/board.json | 3 ++- ports/esp32/boards/GENERIC/board.json | 1 + ports/esp32/boards/GENERIC_C3/board.json | 1 + ports/esp32/boards/GENERIC_C3_USB/board.json | 1 + ports/esp32/boards/GENERIC_D2WD/board.json | 1 + ports/esp32/boards/GENERIC_OTA/board.json | 1 + ports/esp32/boards/GENERIC_S2/board.json | 1 + ports/esp32/boards/GENERIC_S3/board.json | 1 + .../esp32/boards/GENERIC_S3_SPIRAM/board.json | 1 + .../boards/GENERIC_S3_SPIRAM_OCT/board.json | 1 + ports/esp32/boards/GENERIC_SPIRAM/board.json | 3 ++- ports/esp32/boards/GENERIC_UNICORE/board.json | 1 + .../esp32/boards/LILYGO_TTGO_LORA32/board.json | 5 +++-- ports/esp32/boards/LOLIN_C3_MINI/board.json | 1 + ports/esp32/boards/LOLIN_S2_MINI/board.json | 3 ++- ports/esp32/boards/LOLIN_S2_PICO/board.json | 8 ++++---- ports/esp32/boards/M5STACK_ATOM/board.json | 4 ++-- ports/esp32/boards/OLIMEX_ESP32_POE/board.json | 6 +++--- ports/esp32/boards/SIL_WESP32/board.json | 3 ++- ports/esp32/boards/UM_FEATHERS2/board.json | 5 +++-- ports/esp32/boards/UM_FEATHERS2NEO/board.json | 5 +++-- ports/esp32/boards/UM_FEATHERS3/board.json | 18 +++++++++--------- ports/esp32/boards/UM_PROS3/board.json | 18 +++++++++--------- ports/esp32/boards/UM_TINYPICO/board.json | 5 +++-- ports/esp32/boards/UM_TINYS2/board.json | 5 +++-- ports/esp32/boards/UM_TINYS3/board.json | 7 ++++--- ports/esp8266/boards/GENERIC/board.json | 1 + ports/esp8266/boards/GENERIC_1M/board.json | 1 + ports/esp8266/boards/GENERIC_512K/board.json | 1 + .../mimxrt/boards/ADAFRUIT_METRO_M7/board.json | 14 +++++--------- ports/mimxrt/boards/MIMXRT1010_EVK/board.json | 8 +++----- ports/mimxrt/boards/MIMXRT1015_EVK/board.json | 9 +++------ ports/mimxrt/boards/MIMXRT1020_EVK/board.json | 15 +++++++-------- ports/mimxrt/boards/MIMXRT1050_EVK/board.json | 16 +++++++--------- ports/mimxrt/boards/MIMXRT1060_EVK/board.json | 16 +++++++--------- ports/mimxrt/boards/MIMXRT1064_EVK/board.json | 16 +++++++--------- ports/mimxrt/boards/MIMXRT1170_EVK/board.json | 17 +++++++---------- ports/mimxrt/boards/OLIMEX_RT1010/board.json | 8 +++----- ports/mimxrt/boards/SEEED_ARCH_MIX/board.json | 11 ++++++----- ports/mimxrt/boards/TEENSY40/board.json | 3 ++- ports/mimxrt/boards/TEENSY41/board.json | 5 +++-- .../arduino_nano_33_ble_sense/board.json | 15 ++++++--------- ports/nrf/boards/arduino_primo/board.json | 2 +- .../boards/nrf52840-mdk-usb-dongle/board.json | 2 +- ports/nrf/boards/seeed_xiao_nrf52/board.json | 13 ++++++------- ports/renesas-ra/boards/EK_RA4M1/board.json | 9 ++------- ports/renesas-ra/boards/EK_RA4W1/board.json | 9 ++------- ports/renesas-ra/boards/EK_RA6M1/board.json | 9 ++------- ports/renesas-ra/boards/EK_RA6M2/board.json | 9 ++------- .../renesas-ra/boards/RA4M1_CLICKER/board.json | 9 ++------- ports/renesas-ra/boards/VK_RA6M5/board.json | 9 ++------- .../boards/ADAFRUIT_FEATHER_RP2040/board.json | 6 +++--- .../ADAFRUIT_ITSYBITSY_RP2040/board.json | 6 +++--- .../rp2/boards/ADAFRUIT_QTPY_RP2040/board.json | 7 +++---- .../ARDUINO_NANO_RP2040_CONNECT/board.json | 17 ++++++++--------- .../GARATRONIC_PYBSTICK26_RP2040/board.json | 10 ++++------ ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json | 6 +++--- ports/rp2/boards/PICO/board.json | 6 +++--- ports/rp2/boards/PICO_W/board.json | 10 +++++----- .../boards/PIMORONI_PICOLIPO_16MB/board.json | 7 +++---- .../boards/PIMORONI_PICOLIPO_4MB/board.json | 7 +++---- ports/rp2/boards/PIMORONI_TINY2040/board.json | 4 ++-- ports/rp2/boards/SPARKFUN_PROMICRO/board.json | 6 +++--- ports/rp2/boards/SPARKFUN_THINGPLUS/board.json | 10 +++++----- ports/rp2/boards/W5100S_EVB_PICO/board.json | 6 +++--- ports/rp2/boards/W5500_EVB_PICO/board.json | 6 +++--- ports/rp2/boards/WEACTSTUDIO/board.json | 4 ++-- .../ADAFRUIT_FEATHER_M0_EXPRESS/board.json | 5 ++--- .../ADAFRUIT_FEATHER_M4_EXPRESS/board.json | 5 ++--- .../ADAFRUIT_ITSYBITSY_M0_EXPRESS/board.json | 5 ++--- .../ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json | 5 ++--- .../ADAFRUIT_METRO_M4_EXPRESS/board.json | 12 +++++------- .../samd/boards/ADAFRUIT_TRINKET_M0/board.json | 5 ++--- ports/samd/boards/MINISAM_M4/board.json | 4 ++-- .../samd/boards/SAMD21_XPLAINED_PRO/board.json | 8 +++++--- .../samd/boards/SEEED_WIO_TERMINAL/board.json | 15 +++++++++------ ports/samd/boards/SEEED_XIAO_SAMD21/board.json | 4 +++- .../SPARKFUN_SAMD51_THING_PLUS/board.json | 7 +++---- ports/stm32/boards/ARDUINO_GIGA/board.json | 11 ++++++----- .../boards/ARDUINO_NICLA_VISION/board.json | 11 ++++++----- .../boards/ARDUINO_PORTENTA_H7/board.json | 15 +++++++-------- ports/stm32/boards/CERB40/board.json | 4 ++-- ports/stm32/boards/HYDRABUS/board.json | 4 ++-- ports/stm32/boards/LEGO_HUB_NO6/board.json | 2 +- ports/stm32/boards/LIMIFROG/board.json | 4 ++-- ports/stm32/boards/MIKROE_QUAIL/board.json | 2 +- ports/stm32/boards/NETDUINO_PLUS_2/board.json | 4 ++-- ports/stm32/boards/PYBD_SF6/board.json | 4 ++-- ports/stm32/boards/STM32F439/board.json | 2 +- ports/stm32/boards/USBDONGLE_WB55/board.json | 2 +- 92 files changed, 286 insertions(+), 320 deletions(-) diff --git a/ports/cc3200/boards/WIPY/board.json b/ports/cc3200/boards/WIPY/board.json index d8293b2481..4a5a81f99f 100644 --- a/ports/cc3200/boards/WIPY/board.json +++ b/ports/cc3200/boards/WIPY/board.json @@ -5,11 +5,10 @@ "docs": "https://docs.pycom.io/datasheets/development/wipy3/", "features": [ "BLE", - "Breadboard Friendly", - "MicroSD", + "External Flash", "RGB LED", - "SPI Flash", - "WiFi" + "WiFi", + "microSD" ], "id": "wipy", "images": [ diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json b/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json index afb24e1049..77aa192959 100644 --- a/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json +++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json @@ -5,9 +5,10 @@ "docs": "", "features": [ "BLE", - "WiFi", + "External Flash", + "RGB LED", "USB-C", - "RGB LED" + "WiFi" ], "images": [ "ABX00092_01.iso_1000x750.jpg" diff --git a/ports/esp32/boards/ESP32_S2_WROVER/board.json b/ports/esp32/boards/ESP32_S2_WROVER/board.json index 7ebc84415c..d4c4ce21df 100644 --- a/ports/esp32/boards/ESP32_S2_WROVER/board.json +++ b/ports/esp32/boards/ESP32_S2_WROVER/board.json @@ -5,7 +5,8 @@ "docs": "", "features": [ "BLE", - "SPIRAM", + "External Flash", + "External RAM", "WiFi" ], "images": [ diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json index a52d58007d..f70e2e0890 100644 --- a/ports/esp32/boards/GENERIC/board.json +++ b/ports/esp32/boards/GENERIC/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "id": "esp32", diff --git a/ports/esp32/boards/GENERIC_C3/board.json b/ports/esp32/boards/GENERIC_C3/board.json index 6cc326bf14..c993c87603 100644 --- a/ports/esp32/boards/GENERIC_C3/board.json +++ b/ports/esp32/boards/GENERIC_C3/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "id": "esp32c3", diff --git a/ports/esp32/boards/GENERIC_C3_USB/board.json b/ports/esp32/boards/GENERIC_C3_USB/board.json index 23f9a8eb20..6d51e0a2c1 100644 --- a/ports/esp32/boards/GENERIC_C3_USB/board.json +++ b/ports/esp32/boards/GENERIC_C3_USB/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "id": "esp32c3-usb", diff --git a/ports/esp32/boards/GENERIC_D2WD/board.json b/ports/esp32/boards/GENERIC_D2WD/board.json index 39fce46bca..0582820445 100644 --- a/ports/esp32/boards/GENERIC_D2WD/board.json +++ b/ports/esp32/boards/GENERIC_D2WD/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "id": "esp32-d2wd", diff --git a/ports/esp32/boards/GENERIC_OTA/board.json b/ports/esp32/boards/GENERIC_OTA/board.json index 97756a9fb2..3b882e04f8 100644 --- a/ports/esp32/boards/GENERIC_OTA/board.json +++ b/ports/esp32/boards/GENERIC_OTA/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "id": "esp32-ota", diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/GENERIC_S2/board.json index dbd3b5b015..102b039bf8 100644 --- a/ports/esp32/boards/GENERIC_S2/board.json +++ b/ports/esp32/boards/GENERIC_S2/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "images": [ diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/GENERIC_S3/board.json index 0db9b32503..c30d4ed993 100644 --- a/ports/esp32/boards/GENERIC_S3/board.json +++ b/ports/esp32/boards/GENERIC_S3/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "images": [ diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json index 3b405d4a12..947787f3af 100644 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json +++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "images": [ diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json index f3ca177ef9..4cf15e888c 100644 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json +++ b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "images": [ diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.json b/ports/esp32/boards/GENERIC_SPIRAM/board.json index afb57b2ed1..02242028fb 100644 --- a/ports/esp32/boards/GENERIC_SPIRAM/board.json +++ b/ports/esp32/boards/GENERIC_SPIRAM/board.json @@ -5,7 +5,8 @@ "docs": "", "features": [ "BLE", - "SPIRAM", + "External Flash", + "External RAM", "WiFi" ], "id": "esp32spiram", diff --git a/ports/esp32/boards/GENERIC_UNICORE/board.json b/ports/esp32/boards/GENERIC_UNICORE/board.json index 8fed71a018..1f3beaf6e0 100644 --- a/ports/esp32/boards/GENERIC_UNICORE/board.json +++ b/ports/esp32/boards/GENERIC_UNICORE/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "WiFi" ], "id": "esp32-unicore", diff --git a/ports/esp32/boards/LILYGO_TTGO_LORA32/board.json b/ports/esp32/boards/LILYGO_TTGO_LORA32/board.json index 9dd76b5792..525551df3b 100644 --- a/ports/esp32/boards/LILYGO_TTGO_LORA32/board.json +++ b/ports/esp32/boards/LILYGO_TTGO_LORA32/board.json @@ -5,10 +5,11 @@ "docs": "", "features": [ "BLE", + "Display", + "External Flash", "LoRa", - "OLED", "SDCard", - "USB-MICRO", + "USB", "WiFi" ], "images": [ diff --git a/ports/esp32/boards/LOLIN_C3_MINI/board.json b/ports/esp32/boards/LOLIN_C3_MINI/board.json index f47c672fa4..c9b91641e5 100644 --- a/ports/esp32/boards/LOLIN_C3_MINI/board.json +++ b/ports/esp32/boards/LOLIN_C3_MINI/board.json @@ -5,6 +5,7 @@ "docs": "", "features": [ "BLE", + "External Flash", "USB-C", "WiFi" ], diff --git a/ports/esp32/boards/LOLIN_S2_MINI/board.json b/ports/esp32/boards/LOLIN_S2_MINI/board.json index 41e62a0228..a45d0434d9 100644 --- a/ports/esp32/boards/LOLIN_S2_MINI/board.json +++ b/ports/esp32/boards/LOLIN_S2_MINI/board.json @@ -4,7 +4,8 @@ ], "docs": "", "features": [ - "SPIRAM", + "External Flash", + "External RAM", "USB-C", "WiFi" ], diff --git a/ports/esp32/boards/LOLIN_S2_PICO/board.json b/ports/esp32/boards/LOLIN_S2_PICO/board.json index 43322b87b0..6c72e60f80 100644 --- a/ports/esp32/boards/LOLIN_S2_PICO/board.json +++ b/ports/esp32/boards/LOLIN_S2_PICO/board.json @@ -4,10 +4,10 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "OLED", - "SPIRAM", - "STEMMA QT/QWIIC", + "Display", + "External Flash", + "External RAM", + "JST-SH", "USB-C", "WiFi" ], diff --git a/ports/esp32/boards/M5STACK_ATOM/board.json b/ports/esp32/boards/M5STACK_ATOM/board.json index 9d1886887c..4b6c09db3a 100644 --- a/ports/esp32/boards/M5STACK_ATOM/board.json +++ b/ports/esp32/boards/M5STACK_ATOM/board.json @@ -4,9 +4,9 @@ ], "docs": "", "features": [ - "Grove", + "External Flash", "IMU", - "Infrared", + "JST-PH", "RGB LED", "USB-C", "WiFi" diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/board.json b/ports/esp32/boards/OLIMEX_ESP32_POE/board.json index 84b6680d59..e62b960ccd 100644 --- a/ports/esp32/boards/OLIMEX_ESP32_POE/board.json +++ b/ports/esp32/boards/OLIMEX_ESP32_POE/board.json @@ -5,12 +5,12 @@ "docs": "", "features": [ "BLE", - "WiFi", - "MicroSD", "Battery Charging", "Ethernet", + "External Flash", "PoE", - "Breadboard friendly" + "WiFi", + "microSD" ], "images": [ "ESP32-POE-ISO-1.jpg" diff --git a/ports/esp32/boards/SIL_WESP32/board.json b/ports/esp32/boards/SIL_WESP32/board.json index 050620d618..5c77b4887a 100644 --- a/ports/esp32/boards/SIL_WESP32/board.json +++ b/ports/esp32/boards/SIL_WESP32/board.json @@ -6,6 +6,7 @@ "features": [ "BLE", "Ethernet", + "External Flash", "PoE", "WiFi" ], @@ -18,5 +19,5 @@ "product": "SIL WESP32", "thumbnail": "", "url": "https://wesp32.com/", - "vendor": "Silicognition LLC" + "vendor": "Silicognition" } diff --git a/ports/esp32/boards/UM_FEATHERS2/board.json b/ports/esp32/boards/UM_FEATHERS2/board.json index fa5b213db0..4b6ea88558 100644 --- a/ports/esp32/boards/UM_FEATHERS2/board.json +++ b/ports/esp32/boards/UM_FEATHERS2/board.json @@ -5,10 +5,11 @@ "docs": "", "features": [ "Battery Charging", + "External Flash", + "External RAM", "Feather", + "JST-SH", "RGB LED", - "SPIRAM", - "STEMMA QT/QWIIC", "USB-C", "WiFi" ], diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.json b/ports/esp32/boards/UM_FEATHERS2NEO/board.json index d809485e86..51bb02b97b 100644 --- a/ports/esp32/boards/UM_FEATHERS2NEO/board.json +++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.json @@ -5,10 +5,11 @@ "docs": "", "features": [ "Battery Charging", + "External Flash", + "External RAM", "Feather", + "JST-SH", "RGB LED", - "SPIRAM", - "STEMMA QT/QWIIC", "USB-C", "WiFi" ], diff --git a/ports/esp32/boards/UM_FEATHERS3/board.json b/ports/esp32/boards/UM_FEATHERS3/board.json index 68423cca5e..0ad1ff73be 100644 --- a/ports/esp32/boards/UM_FEATHERS3/board.json +++ b/ports/esp32/boards/UM_FEATHERS3/board.json @@ -4,17 +4,17 @@ ], "docs": "", "features": [ - "Battery Charging", - "RGB LED", - "SPIRAM", - "USB-C", - "WiFi", "BLE", - "STEMMA QT/QWIIC", - "Feather" - ], - "features_non_filterable": [ + "Battery Charging", + "External Flash", + "External RAM", + "Feather", + "JST-SH", + "RGB LED", + "USB-C", + "WiFi" ], + "features_non_filterable": [], "id": "feathers3", "images": [ "unexpectedmaker_feathers3.jpg" diff --git a/ports/esp32/boards/UM_PROS3/board.json b/ports/esp32/boards/UM_PROS3/board.json index 0122e4b991..3e83a813f4 100644 --- a/ports/esp32/boards/UM_PROS3/board.json +++ b/ports/esp32/boards/UM_PROS3/board.json @@ -4,17 +4,17 @@ ], "docs": "", "features": [ - "Battery Charging", - "RGB LED", - "SPIRAM", - "USB-C", - "WiFi", "BLE", - "STEMMA QT/QWIIC", - "Feather" - ], - "features_non_filterable": [ + "Battery Charging", + "External Flash", + "External RAM", + "Feather", + "JST-SH", + "RGB LED", + "USB-C", + "WiFi" ], + "features_non_filterable": [], "id": "pros3", "images": [ "unexpectedmaker_pros3.jpg" diff --git a/ports/esp32/boards/UM_TINYPICO/board.json b/ports/esp32/boards/UM_TINYPICO/board.json index 9f1783a9f1..f6ba9ddb0e 100644 --- a/ports/esp32/boards/UM_TINYPICO/board.json +++ b/ports/esp32/boards/UM_TINYPICO/board.json @@ -4,10 +4,11 @@ ], "docs": "", "features": [ - "Battery Charging", "BLE", + "Battery Charging", + "External Flash", + "External RAM", "RGB LED", - "SPIRAM", "USB-C", "WiFi" ], diff --git a/ports/esp32/boards/UM_TINYS2/board.json b/ports/esp32/boards/UM_TINYS2/board.json index e7068170cb..b6c94ba9e8 100644 --- a/ports/esp32/boards/UM_TINYS2/board.json +++ b/ports/esp32/boards/UM_TINYS2/board.json @@ -5,9 +5,10 @@ "docs": "", "features": [ "Battery Charging", + "External Flash", + "External RAM", + "JST-SH", "RGB LED", - "SPIRAM", - "STEMMA QT/QWIIC", "USB-C", "WiFi" ], diff --git a/ports/esp32/boards/UM_TINYS3/board.json b/ports/esp32/boards/UM_TINYS3/board.json index 73482a6284..3b7bb13345 100644 --- a/ports/esp32/boards/UM_TINYS3/board.json +++ b/ports/esp32/boards/UM_TINYS3/board.json @@ -4,12 +4,13 @@ ], "docs": "", "features": [ + "BLE", "Battery Charging", + "External Flash", + "External RAM", "RGB LED", - "SPIRAM", "USB-C", - "WiFi", - "BLE" + "WiFi" ], "features_non_filterable": [ "TinyPICO Compatible" diff --git a/ports/esp8266/boards/GENERIC/board.json b/ports/esp8266/boards/GENERIC/board.json index 46c2659d8a..ebdd95493b 100644 --- a/ports/esp8266/boards/GENERIC/board.json +++ b/ports/esp8266/boards/GENERIC/board.json @@ -4,6 +4,7 @@ ], "docs": "", "features": [ + "External Flash", "WiFi" ], "id": "esp8266", diff --git a/ports/esp8266/boards/GENERIC_1M/board.json b/ports/esp8266/boards/GENERIC_1M/board.json index 2ef4bd99fa..5446f29128 100644 --- a/ports/esp8266/boards/GENERIC_1M/board.json +++ b/ports/esp8266/boards/GENERIC_1M/board.json @@ -4,6 +4,7 @@ ], "docs": "", "features": [ + "External Flash", "WiFi" ], "id": "esp8266-1m", diff --git a/ports/esp8266/boards/GENERIC_512K/board.json b/ports/esp8266/boards/GENERIC_512K/board.json index 10050592cf..1feac4a05c 100644 --- a/ports/esp8266/boards/GENERIC_512K/board.json +++ b/ports/esp8266/boards/GENERIC_512K/board.json @@ -4,6 +4,7 @@ ], "docs": "", "features": [ + "External Flash", "WiFi" ], "id": "esp8266-512k", diff --git a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/board.json b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/board.json index c96e9b08fe..9f260b3a00 100644 --- a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/board.json +++ b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/board.json @@ -4,16 +4,12 @@ ], "docs": "", "features": [ - "USB-C", - "SPI", - "I2C", - "UART", + "BLE", + "External Flash", + "JST-SH", "RGB LED", - "QSPI Flash", - "QWIIC", - "JLink", - "WiFi", - "BLE" + "USB-C", + "WiFi" ], "images": [ "Metro_M7.jpg" diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json index 4bf9ce0524..3fc3403c06 100644 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json @@ -4,12 +4,10 @@ ], "docs": "", "features": [ - "MicroUSB", + "Audio Codec", + "External Flash", "Microphone", - "AudioCodec", - "SPDIF", - "OpenSDA", - "JLink" + "USB" ], "images": [ "i.MXRT1010-TOP.jpg" diff --git a/ports/mimxrt/boards/MIMXRT1015_EVK/board.json b/ports/mimxrt/boards/MIMXRT1015_EVK/board.json index 78044c134e..d0bdd920bc 100644 --- a/ports/mimxrt/boards/MIMXRT1015_EVK/board.json +++ b/ports/mimxrt/boards/MIMXRT1015_EVK/board.json @@ -4,13 +4,10 @@ ], "docs": "", "features": [ - "MicroSD", - "MicroUSB", + "Audio Codec", + "External Flash", "Microphone", - "AudioCodec", - "CAN", - "OpenSDA", - "JLink" + "USB" ], "images": [ "MIMXRT1015-EVK-TOP.jpg" diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json index cc74c25fed..4da224fc99 100644 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json @@ -4,15 +4,14 @@ ], "docs": "", "features": [ - "Ethernet", - "SDRAM", - "MicroSD", - "MicroUSB", - "Microphone", - "AudioCodec", + "Audio Codec", "CAN", - "OpenSDA", - "JLink" + "Ethernet", + "External Flash", + "External RAM", + "Microphone", + "USB", + "microSD" ], "images": [ "MIMXRT-1020-EVKBD.jpg" diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json index d99ad9fcfd..d7c82358cc 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json @@ -4,16 +4,14 @@ ], "docs": "", "features": [ - "Ethernet", - "SDRAM", - "MicroSD", - "MicroUSB", - "Microphone", - "AudioCodec", - "SPDIF", + "Audio Codec", "CAN", - "OpenSDA", - "JLink" + "Ethernet", + "External Flash", + "External RAM", + "Microphone", + "USB", + "microSD" ], "images": [ "IMX_RT1050-EVKB_TOP-LR.jpg" diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json index 67a3818ee2..73c0cd1395 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json @@ -4,17 +4,15 @@ ], "docs": "", "features": [ - "Ethernet", - "SDRAM", - "MicroSD", - "MicroUSB", - "Microphone", - "AudioCodec", - "SPDIF", + "Audio Codec", "CAN", "Camera", - "OpenSDA", - "JLink" + "Ethernet", + "External Flash", + "External RAM", + "Microphone", + "USB", + "microSD" ], "images": [ "X-MIMXRT1060-EVK-BOARD-BOTTOM.jpg" diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json index ef12336c44..a573009d38 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json @@ -4,17 +4,15 @@ ], "docs": "", "features": [ - "Ethernet", - "SDRAM", - "MicroSD", - "MicroUSB", - "Microphone", - "AudioAmp", - "SPDIF", + "Audio Codec", "CAN", "Camera", - "OpenSDA", - "JLink" + "Ethernet", + "External Flash", + "External RAM", + "Microphone", + "USB", + "microSD" ], "images": [ "MIMXRT1064EVK-TOP.jpg" diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/board.json b/ports/mimxrt/boards/MIMXRT1170_EVK/board.json index 01e554751b..73453b45a6 100644 --- a/ports/mimxrt/boards/MIMXRT1170_EVK/board.json +++ b/ports/mimxrt/boards/MIMXRT1170_EVK/board.json @@ -4,18 +4,15 @@ ], "docs": "", "features": [ - "Ethernet", - "SDRAM", - "MicroSD", - "MicroUSB", - "Microphone", - "AudioCodec", - "SPDIF", + "Audio Codec", "CAN", "Camera", - "SIM Socket", - "OpenSDA", - "JLink" + "Ethernet", + "External Flash", + "External RAM", + "Microphone", + "USB", + "microSD" ], "images": [ "IMX-RT1170-EVK-TOP.jpg" diff --git a/ports/mimxrt/boards/OLIMEX_RT1010/board.json b/ports/mimxrt/boards/OLIMEX_RT1010/board.json index 1778725658..882b931f8b 100644 --- a/ports/mimxrt/boards/OLIMEX_RT1010/board.json +++ b/ports/mimxrt/boards/OLIMEX_RT1010/board.json @@ -4,11 +4,9 @@ ], "docs": "", "features": [ - "MicroUSB", - "MicroSD", - "AudioCodec", - "SPDIF", - "JLink" + "External Flash", + "USB", + "microSD" ], "images": [ "OLIMEX_RT1010Py.jpg" diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json b/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json index 3142f1a814..138d28418c 100644 --- a/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json @@ -4,10 +4,11 @@ ], "docs": "", "features": [ - "MicroSD", - "MicroUSB", - "SDRAM", - "RGB LED" + "External Flash", + "External RAM", + "RGB LED", + "USB", + "microSD" ], "images": [ "main1.jpg" @@ -16,5 +17,5 @@ "product": "Arch Mix", "thumbnail": "", "url": "https://wiki.seeedstudio.com/Arch_Mix/", - "vendor": "Seeed Technology Co.,Ltd." + "vendor": "Seeed Studio" } diff --git a/ports/mimxrt/boards/TEENSY40/board.json b/ports/mimxrt/boards/TEENSY40/board.json index daa6dbf99e..599fb2f729 100644 --- a/ports/mimxrt/boards/TEENSY40/board.json +++ b/ports/mimxrt/boards/TEENSY40/board.json @@ -4,7 +4,8 @@ ], "docs": "", "features": [ - "Breadboard Friendly" + "External Flash", + "USB" ], "images": [ "teensy40_front.jpg" diff --git a/ports/mimxrt/boards/TEENSY41/board.json b/ports/mimxrt/boards/TEENSY41/board.json index 1f8fe37a99..08235d4dae 100644 --- a/ports/mimxrt/boards/TEENSY41/board.json +++ b/ports/mimxrt/boards/TEENSY41/board.json @@ -4,9 +4,10 @@ ], "docs": "", "features": [ - "MicroSD", "Ethernet", - "Breadboard Friendly" + "External Flash", + "USB", + "microSD" ], "images": [ "teensy41_4.jpg" diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/board.json b/ports/nrf/boards/arduino_nano_33_ble_sense/board.json index 65a8e24350..9079fbd666 100644 --- a/ports/nrf/boards/arduino_nano_33_ble_sense/board.json +++ b/ports/nrf/boards/arduino_nano_33_ble_sense/board.json @@ -4,15 +4,12 @@ ], "docs": "", "features": [ - "Bluetooth 5.0", - "IMU LSM9DS1", - "Humidity sensor HTS221", - "Pressure sensor LPS22H", - "Proximity, Light, RGB sensor APDS-9960", - "Microphone MPM3610", - "Crypto IC ARM CC310", - "USB-MICRO", - "Breadboard Friendly" + "BLE", + "Environment Sensor", + "IMU", + "Microphone", + "Secure Element", + "USB" ], "images": [ "ABX00031_01.iso_998x749.jpg" diff --git a/ports/nrf/boards/arduino_primo/board.json b/ports/nrf/boards/arduino_primo/board.json index d16ce1c346..f7afed0ced 100644 --- a/ports/nrf/boards/arduino_primo/board.json +++ b/ports/nrf/boards/arduino_primo/board.json @@ -11,5 +11,5 @@ "product": "arduino_primo", "thumbnail": "", "url": "", - "vendor": "" + "vendor": "Arduino" } diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json index 853c375710..99d0caad23 100644 --- a/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json +++ b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json @@ -11,5 +11,5 @@ "product": "nrf52840-mdk-usb-dongle", "thumbnail": "", "url": "https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle", - "vendor": "" + "vendor": "Makerdiary" } diff --git a/ports/nrf/boards/seeed_xiao_nrf52/board.json b/ports/nrf/boards/seeed_xiao_nrf52/board.json index 619a7c23b9..d40355bb2e 100644 --- a/ports/nrf/boards/seeed_xiao_nrf52/board.json +++ b/ports/nrf/boards/seeed_xiao_nrf52/board.json @@ -4,14 +4,13 @@ ], "docs": "", "features": [ - "Bluetooth 5.0", - "IMU LSM6DS3TR", - "Microphone MSM261D3526H1CPM", - "USB-C", - "Breadboard Friendly", - "Battery Management", + "BLE", + "Battery Charging", + "External Flash", + "IMU", + "Microphone", "RGB LED", - "QSPI Flash" + "USB-C" ], "images": [ "XIAO_nrf52840_front.jpg" diff --git a/ports/renesas-ra/boards/EK_RA4M1/board.json b/ports/renesas-ra/boards/EK_RA4M1/board.json index bab3bcacee..d21fe0c121 100644 --- a/ports/renesas-ra/boards/EK_RA4M1/board.json +++ b/ports/renesas-ra/boards/EK_RA4M1/board.json @@ -3,17 +3,12 @@ "../deploy.md" ], "docs": "", - "features": [ - "UART", - "SPI", - "I2C", - "ADC" - ], + "features": [], "id": "EK-RA4M1", "images": [ "ek_ra4m1_board.jpg" ], - "mcu": "RA4M1", + "mcu": "ra4m1", "product": "EK-RA4M1", "thumbnail": "", "url": "https://www.renesas.com/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ek-ra4m1-evaluation-kit-ra4m1-mcu-group", diff --git a/ports/renesas-ra/boards/EK_RA4W1/board.json b/ports/renesas-ra/boards/EK_RA4W1/board.json index db06b6751d..878d97a8ac 100644 --- a/ports/renesas-ra/boards/EK_RA4W1/board.json +++ b/ports/renesas-ra/boards/EK_RA4W1/board.json @@ -3,17 +3,12 @@ "../deploy.md" ], "docs": "", - "features": [ - "UART", - "SPI", - "I2C", - "ADC" - ], + "features": [], "id": "EK-RA4W1", "images": [ "ek_ra4w1_board.jpg" ], - "mcu": "RA4W1", + "mcu": "ra4w1", "product": "EK-RA4W1", "thumbnail": "", "url": "https://www.renesas.com/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ek-ra4w1-evaluation-kit-ra4w1-mcu-group", diff --git a/ports/renesas-ra/boards/EK_RA6M1/board.json b/ports/renesas-ra/boards/EK_RA6M1/board.json index babcc5c166..d678fa387e 100644 --- a/ports/renesas-ra/boards/EK_RA6M1/board.json +++ b/ports/renesas-ra/boards/EK_RA6M1/board.json @@ -3,17 +3,12 @@ "../deploy.md" ], "docs": "", - "features": [ - "UART", - "SPI", - "I2C", - "ADC" - ], + "features": [], "id": "EK-RA6M1", "images": [ "ek_ra6m1_board.jpg" ], - "mcu": "RA6M1", + "mcu": "ra6m1", "product": "EK-RA6M1", "thumbnail": "", "url": "https://www.renesas.com/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ek-ra6m1-evaluation-kit-ra6m1-mcu-group", diff --git a/ports/renesas-ra/boards/EK_RA6M2/board.json b/ports/renesas-ra/boards/EK_RA6M2/board.json index 63547d8807..3d6b95aacb 100644 --- a/ports/renesas-ra/boards/EK_RA6M2/board.json +++ b/ports/renesas-ra/boards/EK_RA6M2/board.json @@ -3,12 +3,7 @@ "../deploy.md" ], "docs": "", - "features": [ - "UART", - "SPI", - "I2C", - "ADC" - ], + "features": [], "id": "EK-RA6M2", "images": [ "ek_ra6m2_board.jpg", @@ -17,7 +12,7 @@ "ek_ra6m2_j3_pins.jpg", "ek_ra6m2_j4_pins.jpg" ], - "mcu": "RA6M2", + "mcu": "ra6m2", "product": "EK-RA6M2", "thumbnail": "", "url": "https://www.renesas.com/products/microcontrollers-microprocessors/ra-cortex-m-mcus/ek-ra6m2-evaluation-kit-ra6m2-mcu-group", diff --git a/ports/renesas-ra/boards/RA4M1_CLICKER/board.json b/ports/renesas-ra/boards/RA4M1_CLICKER/board.json index 1c3c4c8e91..8cb64f6601 100644 --- a/ports/renesas-ra/boards/RA4M1_CLICKER/board.json +++ b/ports/renesas-ra/boards/RA4M1_CLICKER/board.json @@ -3,18 +3,13 @@ "../deploy.md" ], "docs": "", - "features": [ - "UART", - "SPI", - "I2C", - "ADC" - ], + "features": [], "id": "RA4M1-CLICKER", "images": [ "ra4m1_clicker_board.jpg", "ra4m1_clicker_pins.jpg" ], - "mcu": "RA4M1", + "mcu": "ra4m1", "product": "Mikroe RA4M1 Clicker", "thumbnail": "", "url": "https://www.mikroe.com/ra4m1-clicker", diff --git a/ports/renesas-ra/boards/VK_RA6M5/board.json b/ports/renesas-ra/boards/VK_RA6M5/board.json index ae11d52213..b2ff6b0e40 100644 --- a/ports/renesas-ra/boards/VK_RA6M5/board.json +++ b/ports/renesas-ra/boards/VK_RA6M5/board.json @@ -4,18 +4,13 @@ ], "docs": "", "features": [ - "UART", - "SPI", - "I2C", - "ADC", - "DAC", - "PWM" + "DAC" ], "id": "VK-RA6M5", "images": [ "VK-RA6M5.jpg" ], - "mcu": "RA6M5", + "mcu": "ra6m5", "product": "VK-RA6M5", "thumbnail": "", "url": "https://vekatech.com/VK-RA6M5_docs/brochures/VK-RA6M5%20Flyer%20R2.pdf", diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json index a7db469389..be63f4430b 100644 --- a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json @@ -5,11 +5,11 @@ "docs": "", "features": [ "Battery Charging", - "Breadboard Friendly", + "Dual-core", + "External Flash", "Feather", + "JST-SH", "RGB LED", - "SPI Flash", - "STEMMA QT/QWIIC", "USB-C" ], "images": [ diff --git a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json index 7ca0db0698..ea9070e13c 100644 --- a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json +++ b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json @@ -4,10 +4,10 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Micro USB", + "Dual-core", + "External Flash", "RGB LED", - "SPI Flash" + "USB" ], "images": [ "4888-05.jpg" diff --git a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json index d63166616f..d5e4394f4e 100644 --- a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json +++ b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json @@ -4,11 +4,10 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Castellated Pads", + "Dual-core", + "External Flash", + "JST-SH", "RGB LED", - "SPI Flash", - "STEMMA QT/QWIIC", "USB-C" ], "images": [ diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json index 5bd03e1e0b..5639aaa2a4 100644 --- a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json +++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json @@ -4,15 +4,14 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Castellated Pads", - "WiFi Nina-W102", - "Bluetooth Nina-W102", - "IMU LSM6DSOXTR", - "Crypto IC ATECC608A-MAHDA-T", - "Microphone MP34DT05", - "SPI Flash 16MB", - "USB-MICRO" + "BLE", + "Dual-core", + "External Flash", + "IMU", + "Microphone", + "Secure Element", + "USB", + "WiFi" ], "images": [ "ABX00052_01.iso_999x750.jpg" diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json index 1b9e113143..df9dd5d0de 100644 --- a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json +++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json @@ -4,12 +4,10 @@ ], "docs": "", "features": [ - "USB Stick form factor", - "Breadboard Friendly", - "Reset/User button", - "Red/green/orange/blue leds", - "1MB SPI Flash", - "USB-A" + "Dual-core", + "External Flash", + "RGB LED", + "USB" ], "images": [ "pybstick-rp2040-26-broches-micropython-c.jpg" diff --git a/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json b/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json index 2aff0580d8..08aa7068ef 100644 --- a/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json +++ b/ports/rp2/boards/NULLBITS_BIT_C_PRO/board.json @@ -4,10 +4,10 @@ ], "docs": "", "features": [ - "Breadboard Friendly", + "Dual-core", + "External Flash", "RGB LED", - "USB-C", - "SPI Flash" + "USB-C" ], "images": [ "nullbits_bit_c_pro.jpg" diff --git a/ports/rp2/boards/PICO/board.json b/ports/rp2/boards/PICO/board.json index 9abf505e54..8c0a12ae76 100644 --- a/ports/rp2/boards/PICO/board.json +++ b/ports/rp2/boards/PICO/board.json @@ -4,9 +4,9 @@ ], "docs": "", "features": [ - "Breadboard friendly", - "Castellated Pads", - "Micro USB" + "Dual-core", + "External Flash", + "USB" ], "id": "rp2-pico", "images": [ diff --git a/ports/rp2/boards/PICO_W/board.json b/ports/rp2/boards/PICO_W/board.json index a85d7e0446..7ee7ef505e 100644 --- a/ports/rp2/boards/PICO_W/board.json +++ b/ports/rp2/boards/PICO_W/board.json @@ -4,11 +4,11 @@ ], "docs": "", "features": [ - "Breadboard friendly", - "Castellated Pads", - "Micro USB", - "WiFi", - "Bluetooth" + "BLE", + "Dual-core", + "External Flash", + "USB", + "WiFi" ], "id": "rp2-pico-w", "images": [ diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json index 9121154d81..c44ea55514 100644 --- a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json +++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json @@ -5,10 +5,9 @@ "docs": "", "features": [ "Battery Charging", - "Breadboard Friendly", - "Castellated Pads", - "SPI Flash", - "STEMMA QT/QWIIC", + "Dual-core", + "External Flash", + "JST-SH", "USB-C" ], "images": [ diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json index 69d8532397..cb06c746b6 100644 --- a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json +++ b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json @@ -5,10 +5,9 @@ "docs": "", "features": [ "Battery Charging", - "Breadboard Friendly", - "Castellated Pads", - "SPI Flash", - "STEMMA QT/QWIIC", + "Dual-core", + "External Flash", + "JST-SH", "USB-C" ], "images": [ diff --git a/ports/rp2/boards/PIMORONI_TINY2040/board.json b/ports/rp2/boards/PIMORONI_TINY2040/board.json index 753a25beae..207647f6b2 100644 --- a/ports/rp2/boards/PIMORONI_TINY2040/board.json +++ b/ports/rp2/boards/PIMORONI_TINY2040/board.json @@ -4,8 +4,8 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Castellated Pads", + "Dual-core", + "External Flash", "RGB LED", "USB-C" ], diff --git a/ports/rp2/boards/SPARKFUN_PROMICRO/board.json b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json index a0d39165af..46878a29cd 100644 --- a/ports/rp2/boards/SPARKFUN_PROMICRO/board.json +++ b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json @@ -4,10 +4,10 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Castellated Pads", + "Dual-core", + "External Flash", + "JST-SH", "RGB LED", - "STEMMA QT/QWIIC", "USB-C" ], "images": [ diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json index 871a411b5b..3eeb397265 100644 --- a/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json +++ b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json @@ -5,13 +5,13 @@ "docs": "", "features": [ "Battery Charging", - "Breadboard Friendly", + "Dual-core", + "External Flash", "Feather", - "MicroSD", + "JST-SH", "RGB LED", - "SPI Flash", - "STEMMA QT/QWIIC", - "USB-C" + "USB-C", + "microSD" ], "images": [ "17745-SparkFun_Thing_Plus_-_RP2040-01a.jpg" diff --git a/ports/rp2/boards/W5100S_EVB_PICO/board.json b/ports/rp2/boards/W5100S_EVB_PICO/board.json index 4091b78433..daaf1cf8ac 100644 --- a/ports/rp2/boards/W5100S_EVB_PICO/board.json +++ b/ports/rp2/boards/W5100S_EVB_PICO/board.json @@ -4,10 +4,10 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Castellated Pads", + "Dual-core", "Ethernet", - "Micro USB" + "External Flash", + "USB" ], "images": [ "W5100S-EVB-Pico.jpg" diff --git a/ports/rp2/boards/W5500_EVB_PICO/board.json b/ports/rp2/boards/W5500_EVB_PICO/board.json index 90b3186cd6..9359825559 100644 --- a/ports/rp2/boards/W5500_EVB_PICO/board.json +++ b/ports/rp2/boards/W5500_EVB_PICO/board.json @@ -4,10 +4,10 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Castellated Pads", + "Dual-core", "Ethernet", - "Micro USB" + "External Flash", + "USB" ], "images": [ "W5500-EVB-Pico.jpg" diff --git a/ports/rp2/boards/WEACTSTUDIO/board.json b/ports/rp2/boards/WEACTSTUDIO/board.json index bac5263627..3a3f2f741f 100644 --- a/ports/rp2/boards/WEACTSTUDIO/board.json +++ b/ports/rp2/boards/WEACTSTUDIO/board.json @@ -4,8 +4,8 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "SPI Flash", + "Dual-core", + "External Flash", "USB-C" ], "images": [ diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json index b0cb02cd4f..22a9ffccba 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json @@ -5,11 +5,10 @@ "docs": "", "features": [ "Battery Charging", - "Breadboard Friendly", + "External Flash", "Feather", - "Micro USB", "RGB LED", - "SPI Flash" + "USB" ], "images": [ "feather_m0_express.jpg" diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json index c8042aa254..06cd9a4fe4 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json @@ -5,11 +5,10 @@ "docs": "", "features": [ "Battery Charging", - "Breadboard Friendly", + "External Flash", "Feather", - "Micro USB", "RGB LED", - "SPI Flash" + "USB" ], "images": [ "feather_m4_express.jpg" diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/board.json index f99d19ca87..0e423b2b8e 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/board.json @@ -4,10 +4,9 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Micro USB", + "External Flash", "RGB LED", - "SPI Flash" + "USB" ], "images": [ "itsybitsy_m0_express.jpg" diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json index 83db285b4d..a998529ccd 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json @@ -4,10 +4,9 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Micro USB", + "External Flash", "RGB LED", - "SPI Flash" + "USB" ], "images": [ "itsybitsy_m4_express.jpg" diff --git a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json index e0a256cf88..f830ff223f 100644 --- a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json @@ -4,14 +4,12 @@ ], "docs": "", "features": [ - "Micro USB", - "ADC", - "DAC", - "RGB LED", - "QSPI Flash", - "WiFi", "BLE", - "JLink" + "DAC", + "External Flash", + "RGB LED", + "USB", + "WiFi" ], "images": [ "metro_m4_express_airlift.jpg" diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json index 9112bc06ef..d77282db01 100644 --- a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json @@ -4,9 +4,8 @@ ], "docs": "", "features": [ - "Breadboard Friendly", - "Micro USB", - "RGB LED" + "RGB LED", + "USB" ], "images": [ "trinket_m0.jpg" diff --git a/ports/samd/boards/MINISAM_M4/board.json b/ports/samd/boards/MINISAM_M4/board.json index 126e036400..6489dae863 100644 --- a/ports/samd/boards/MINISAM_M4/board.json +++ b/ports/samd/boards/MINISAM_M4/board.json @@ -4,9 +4,9 @@ ], "docs": "", "features": [ - "Micro USB", + "External Flash", "RGB LED", - "SPI Flash" + "USB" ], "images": [ "mini_sam_m4.jpg" diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json index 4d22c42bad..c59ebc1b7b 100644 --- a/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json @@ -4,10 +4,12 @@ ], "docs": "", "features": [ - "Micro USB", - "SPI Flash" + "External Flash", + "USB" + ], + "images": [ + "2033-atsamd21-xpro.jpg" ], - "images": ["2033-atsamd21-xpro.jpg"], "mcu": "samd21", "product": "SAMD21 Xplained Pro", "thumbnail": "", diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/board.json b/ports/samd/boards/SEEED_WIO_TERMINAL/board.json index 350ada4c4a..5300b03808 100644 --- a/ports/samd/boards/SEEED_WIO_TERMINAL/board.json +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/board.json @@ -4,14 +4,17 @@ ], "docs": "", "features": [ - "USB-C", - "Display", - "Grove", - "WiFi", "BLE", - "SDCard" + "Display", + "External Flash", + "JST-PH", + "SDCard", + "USB-C", + "WiFi" + ], + "images": [ + "wio-terminal.jpg" ], - "images": ["wio-terminal.jpg"], "mcu": "samd51", "product": "Wio Terminal D51R", "thumbnail": "", diff --git a/ports/samd/boards/SEEED_XIAO_SAMD21/board.json b/ports/samd/boards/SEEED_XIAO_SAMD21/board.json index 4e6217e19e..4d19f6b945 100644 --- a/ports/samd/boards/SEEED_XIAO_SAMD21/board.json +++ b/ports/samd/boards/SEEED_XIAO_SAMD21/board.json @@ -6,7 +6,9 @@ "features": [ "USB-C" ], - "images": ["seeeduino-xiao.jpg"], + "images": [ + "seeeduino-xiao.jpg" + ], "mcu": "samd21", "product": "Seeeduino XIAO (SAMD21)", "thumbnail": "", diff --git a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json index af643f5c5f..ee9ca9d368 100644 --- a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json +++ b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json @@ -5,10 +5,9 @@ "docs": "", "features": [ "Battery Charging", - "Breadboard Friendly", - "Micro USB", - "QWIIC", - "SPI Flash" + "External Flash", + "JST-SH", + "USB" ], "images": [ "sparkfun_samd51_thing_plus.jpg" diff --git a/ports/stm32/boards/ARDUINO_GIGA/board.json b/ports/stm32/boards/ARDUINO_GIGA/board.json index f0595d4ad5..53c636c774 100644 --- a/ports/stm32/boards/ARDUINO_GIGA/board.json +++ b/ports/stm32/boards/ARDUINO_GIGA/board.json @@ -4,11 +4,12 @@ ], "docs": "", "features": [ - "8MB SDRAM", - "16MB Flash", - "Dual-core processor", - "USB Full speed", - "CYW43 WiFi/BT Module" + "BLE", + "Dual-core", + "External Flash", + "External RAM", + "USB", + "WiFi" ], "images": [ "ABX00063_01.front_1000x750.jpg" diff --git a/ports/stm32/boards/ARDUINO_NICLA_VISION/board.json b/ports/stm32/boards/ARDUINO_NICLA_VISION/board.json index 801bc320b5..a4c81d69d4 100644 --- a/ports/stm32/boards/ARDUINO_NICLA_VISION/board.json +++ b/ports/stm32/boards/ARDUINO_NICLA_VISION/board.json @@ -4,11 +4,12 @@ ], "docs": "", "features": [ - "16MB Flash", - "Dual-core processor", - "USB High Speed Phy", - "CYW43 WiFi/BT Module", - "NXP SE050 crypto device" + "BLE", + "Dual-core", + "External Flash", + "Secure Element", + "USB", + "WiFi" ], "images": [ "ABX00051_01.iso_1000x750.jpg" diff --git a/ports/stm32/boards/ARDUINO_PORTENTA_H7/board.json b/ports/stm32/boards/ARDUINO_PORTENTA_H7/board.json index 6467e43bb9..f39d7d4c47 100644 --- a/ports/stm32/boards/ARDUINO_PORTENTA_H7/board.json +++ b/ports/stm32/boards/ARDUINO_PORTENTA_H7/board.json @@ -4,14 +4,13 @@ ], "docs": "", "features": [ - "8MB SDRAM", - "16MB Flash", - "Dual-core processor", - "USB High Speed Phy", - "10/100 Ethernet Phy", - "CYW43 WiFi/BT Module", - "DisplayPort over USB-C", - "2x80 pin HD connectors" + "BLE", + "Dual-core", + "Ethernet", + "External Flash", + "External RAM", + "USB", + "WiFi" ], "images": [ "ABX00042_01.iso_1000x750.jpg" diff --git a/ports/stm32/boards/CERB40/board.json b/ports/stm32/boards/CERB40/board.json index f80b3f5cab..e3bd4296ba 100644 --- a/ports/stm32/boards/CERB40/board.json +++ b/ports/stm32/boards/CERB40/board.json @@ -8,8 +8,8 @@ "cerb40.jpg" ], "mcu": "stm32f4", - "product": "CERB40", + "product": "Cerb40", "thumbnail": "", "url": "", - "vendor": "" + "vendor": "Fez" } diff --git a/ports/stm32/boards/HYDRABUS/board.json b/ports/stm32/boards/HYDRABUS/board.json index 32561e6525..20a2ac5eae 100644 --- a/ports/stm32/boards/HYDRABUS/board.json +++ b/ports/stm32/boards/HYDRABUS/board.json @@ -8,8 +8,8 @@ "hydrabus.jpg" ], "mcu": "stm32f4", - "product": "HYDRABUS", + "product": "HydraBus v1.0", "thumbnail": "", "url": "", - "vendor": "" + "vendor": "HydraBus" } diff --git a/ports/stm32/boards/LEGO_HUB_NO6/board.json b/ports/stm32/boards/LEGO_HUB_NO6/board.json index c11b9f1818..3c602abba1 100644 --- a/ports/stm32/boards/LEGO_HUB_NO6/board.json +++ b/ports/stm32/boards/LEGO_HUB_NO6/board.json @@ -9,5 +9,5 @@ "product": "Hub No.6", "thumbnail": "", "url": "", - "vendor": "Lego" + "vendor": "LEGO" } diff --git a/ports/stm32/boards/LIMIFROG/board.json b/ports/stm32/boards/LIMIFROG/board.json index 3137350074..f516963a5b 100644 --- a/ports/stm32/boards/LIMIFROG/board.json +++ b/ports/stm32/boards/LIMIFROG/board.json @@ -8,8 +8,8 @@ "limifrog.jpg" ], "mcu": "stm32l4", - "product": "LIMIFROG", + "product": "LimiFrog", "thumbnail": "", "url": "", - "vendor": "" + "vendor": "LimiFrog" } diff --git a/ports/stm32/boards/MIKROE_QUAIL/board.json b/ports/stm32/boards/MIKROE_QUAIL/board.json index ccd9b4fdc0..15d8b5fc13 100644 --- a/ports/stm32/boards/MIKROE_QUAIL/board.json +++ b/ports/stm32/boards/MIKROE_QUAIL/board.json @@ -8,7 +8,7 @@ ], "id": "MIKROE-QUAIL", "images": [ - "quail_top.jpg" + "quail_top.jpg" ], "mcu": "stm32f4", "product": "MikroE Quail", diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board.json b/ports/stm32/boards/NETDUINO_PLUS_2/board.json index 044bc2736b..603032ee98 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/board.json +++ b/ports/stm32/boards/NETDUINO_PLUS_2/board.json @@ -8,8 +8,8 @@ "netduino_plus_2.jpg" ], "mcu": "stm32f4", - "product": "NETDUINO_PLUS_2", + "product": "Netduino Plus 2", "thumbnail": "", "url": "", - "vendor": "" + "vendor": "Netduino" } diff --git a/ports/stm32/boards/PYBD_SF6/board.json b/ports/stm32/boards/PYBD_SF6/board.json index 3e689d69be..3a39763d5b 100644 --- a/ports/stm32/boards/PYBD_SF6/board.json +++ b/ports/stm32/boards/PYBD_SF6/board.json @@ -4,8 +4,8 @@ ], "docs": "", "features": [ - "WiFi", - "BLE" + "BLE", + "WiFi" ], "id": "PYBD-SF6", "images": [ diff --git a/ports/stm32/boards/STM32F439/board.json b/ports/stm32/boards/STM32F439/board.json index 140c3474ca..068a9022d7 100644 --- a/ports/stm32/boards/STM32F439/board.json +++ b/ports/stm32/boards/STM32F439/board.json @@ -11,5 +11,5 @@ "product": "STM32F439", "thumbnail": "", "url": "", - "vendor": "" + "vendor": "ST Microelectronics" } diff --git a/ports/stm32/boards/USBDONGLE_WB55/board.json b/ports/stm32/boards/USBDONGLE_WB55/board.json index 858e94d105..6d61f0c280 100644 --- a/ports/stm32/boards/USBDONGLE_WB55/board.json +++ b/ports/stm32/boards/USBDONGLE_WB55/board.json @@ -11,5 +11,5 @@ "product": "USBDONGLE_WB55", "thumbnail": "", "url": "", - "vendor": "" + "vendor": "ST Microelectronics" } From f6af48416d6423016fd4395fd3260ba66f56cf56 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 Aug 2023 13:45:53 +1000 Subject: [PATCH 020/121] extmod/modselect: Properly track number of poll objects that are fd's. Signed-off-by: Damien George --- extmod/modselect.c | 38 ++++++++++++++++---------- tests/extmod/select_poll_custom.py | 21 +++++++++++++- tests/extmod/select_poll_custom.py.exp | 6 ++++ 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/extmod/modselect.c b/extmod/modselect.c index 7c65e7dcaf..d665a10827 100644 --- a/extmod/modselect.c +++ b/extmod/modselect.c @@ -88,8 +88,9 @@ typedef struct _poll_set_t { #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS // Array of pollfd entries for objects that have a file descriptor. - unsigned short alloc; - unsigned short len; + unsigned short alloc; // memory allocated for pollfds + unsigned short max_used; // maximum number of used entries in pollfds + unsigned short used; // actual number of used entries in pollfds struct pollfd *pollfds; #endif } poll_set_t; @@ -98,7 +99,8 @@ STATIC void poll_set_init(poll_set_t *poll_set, size_t n) { mp_map_init(&poll_set->map, n); #if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS poll_set->alloc = 0; - poll_set->len = 0; + poll_set->max_used = 0; + poll_set->used = 0; poll_set->pollfds = NULL; #endif } @@ -142,29 +144,34 @@ STATIC void poll_obj_set_revents(poll_obj_t *poll_obj, mp_uint_t revents) { STATIC struct pollfd *poll_set_add_fd(poll_set_t *poll_set, int fd) { struct pollfd *free_slot = NULL; - for (unsigned int i = 0; i < poll_set->len; ++i) { - struct pollfd *slot = &poll_set->pollfds[i]; - if (slot->fd == -1) { - free_slot = slot; - break; - } - } - if (free_slot == NULL) { - if (poll_set->len >= poll_set->alloc) { + if (poll_set->used == poll_set->max_used) { + // No free slots below max_used, so expand max_used (and possibly allocate). + if (poll_set->max_used >= poll_set->alloc) { poll_set->pollfds = m_renew(struct pollfd, poll_set->pollfds, poll_set->alloc, poll_set->alloc + 4); poll_set->alloc += 4; } - free_slot = &poll_set->pollfds[poll_set->len++]; + free_slot = &poll_set->pollfds[poll_set->max_used++]; + } else { + // There should be a free slot below max_used. + for (unsigned int i = 0; i < poll_set->max_used; ++i) { + struct pollfd *slot = &poll_set->pollfds[i]; + if (slot->fd == -1) { + free_slot = slot; + break; + } + } + assert(free_slot != NULL); } free_slot->fd = fd; + ++poll_set->used; return free_slot; } static inline bool poll_set_all_are_fds(poll_set_t *poll_set) { - return poll_set->map.used == poll_set->len; + return poll_set->map.used == poll_set->used; } #else @@ -323,7 +330,7 @@ STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size } // Call system poll for those objects that have a file descriptor. - int n_ready = poll(poll_set->pollfds, poll_set->len, t); + int n_ready = poll(poll_set->pollfds, poll_set->max_used, t); MP_THREAD_GIL_ENTER(); @@ -462,6 +469,7 @@ STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) { poll_obj_t *poll_obj = (poll_obj_t *)MP_OBJ_TO_PTR(elem->value); if (poll_obj->pollfd != NULL) { poll_obj->pollfd->fd = -1; + --self->poll_set.used; } elem->value = MP_OBJ_NULL; } diff --git a/tests/extmod/select_poll_custom.py b/tests/extmod/select_poll_custom.py index 0cbb610327..b854a8a14d 100644 --- a/tests/extmod/select_poll_custom.py +++ b/tests/extmod/select_poll_custom.py @@ -77,7 +77,26 @@ try: except OSError as er: print("OSError", er.errno) +# Register then unregister a socket (a native stream), then test +# that the Python object is still pollable. +s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +x.poll_state = _MP_STREAM_POLL_RD +poller.register(s2) +poller.unregister(s2) +print_poll_output(poller.poll()) + +# Test registering and unregistering multiple times. +for _ in range(2): + poller.unregister(s) + poller.unregister(x) + poller.register(s2) + poller.register(s, select.POLLIN) + poller.register(x, select.POLLIN) + poller.unregister(s2) + print_poll_output(poller.poll()) + +# Clean up. poller.unregister(x) poller.unregister(s) - +s2.close() s.close() diff --git a/tests/extmod/select_poll_custom.py.exp b/tests/extmod/select_poll_custom.py.exp index bcb4d83e2d..d85508bab2 100644 --- a/tests/extmod/select_poll_custom.py.exp +++ b/tests/extmod/select_poll_custom.py.exp @@ -9,3 +9,9 @@ CustomPollable.ioctl 3 1 [(, 1)] CustomPollable.ioctl 3 1 OSError 1000 +CustomPollable.ioctl 3 1 +[(, 1)] +CustomPollable.ioctl 3 1 +[(, 1)] +CustomPollable.ioctl 3 1 +[(, 1)] From 88518009cec91d48451b97df35ca8ee053190378 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 Aug 2023 19:37:01 +1000 Subject: [PATCH 021/121] tests/extmod/select_poll_eintr.py: Improve robustness of test. Increase allowed range of dt_ms, and print it in case of failure. Signed-off-by: Damien George --- tests/extmod/select_poll_eintr.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/extmod/select_poll_eintr.py b/tests/extmod/select_poll_eintr.py index f53efcc83e..e1cbc2aaf5 100644 --- a/tests/extmod/select_poll_eintr.py +++ b/tests/extmod/select_poll_eintr.py @@ -41,7 +41,10 @@ t0 = time.time_ns() result = poller.poll(400) dt_ms = (time.time_ns() - t0) / 1e6 print("result:", result) -print("dt in range:", 380 <= dt_ms <= 500) +if 380 <= dt_ms <= 600: + print("dt in range") +else: + print("dt not in range:", dt_ms) # Clean up. s.close() From d325ee4509d8f68e341d5efc5ddbe3c30f86089e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 2 Aug 2023 16:48:57 +1000 Subject: [PATCH 022/121] py/gc: Apply some code formatting cleanup. This commit: - Breaks up some long lines for readability. - Fixes a potential macro argument expansion issue. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- py/gc.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/py/gc.c b/py/gc.c index 541632d12b..11be30dfef 100644 --- a/py/gc.c +++ b/py/gc.c @@ -79,7 +79,7 @@ #define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0) #if MICROPY_GC_SPLIT_HEAP -#define NEXT_AREA(area) (area->next) +#define NEXT_AREA(area) ((area)->next) #else #define NEXT_AREA(area) (NULL) #endif @@ -129,7 +129,13 @@ STATIC void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK) size_t total_byte_len = (byte *)end - (byte *)start; #if MICROPY_ENABLE_FINALISER - area->gc_alloc_table_byte_len = (total_byte_len - ALLOC_TABLE_GAP_BYTE) * MP_BITS_PER_BYTE / (MP_BITS_PER_BYTE + MP_BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + MP_BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK); + area->gc_alloc_table_byte_len = (total_byte_len - ALLOC_TABLE_GAP_BYTE) + * MP_BITS_PER_BYTE + / ( + MP_BITS_PER_BYTE + + MP_BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + + MP_BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK + ); #else area->gc_alloc_table_byte_len = (total_byte_len - ALLOC_TABLE_GAP_BYTE) / (1 + MP_BITS_PER_BYTE / 2 * BYTES_PER_BLOCK); #endif @@ -165,11 +171,19 @@ STATIC void gc_setup_area(mp_state_mem_area_t *area, void *start, void *end) { #endif DEBUG_printf("GC layout:\n"); - DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(area).gc_alloc_table_start, MP_STATE_MEM(area).gc_alloc_table_byte_len, MP_STATE_MEM(area).gc_alloc_table_byte_len * BLOCKS_PER_ATB); + DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " + UINT_FMT " blocks\n", + area->gc_alloc_table_start, area->gc_alloc_table_byte_len, + area->gc_alloc_table_byte_len * BLOCKS_PER_ATB); #if MICROPY_ENABLE_FINALISER - DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(area).gc_finaliser_table_start, gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB); + DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " + UINT_FMT " blocks\n", area->gc_finaliser_table_start, + gc_finaliser_table_byte_len, + gc_finaliser_table_byte_len * BLOCKS_PER_FTB); #endif - DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(area).gc_pool_start, gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len); + DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " + UINT_FMT " blocks\n", area->gc_pool_start, + gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len); } void gc_init(void *start, void *end) { From 519c24dd48764f28593112dbeac7e30b8b2a6240 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 2 Aug 2023 16:49:44 +1000 Subject: [PATCH 023/121] py/gc: Add new MICROPY_GC_SPLIT_HEAP_AUTO "auto grow heap" mode. When set, the split heap is automatically extended with new areas on demand, and shrunk if a heap area becomes empty during a GC pass or soft reset. To save code size the size allocation for a new heap block (including metadata) is estimated at 103% of the failed allocation, rather than working from the more complex algorithm in gc_try_add_heap(). This appears to work well except in the extreme limit case when almost all RAM is exhausted (~last few hundred bytes). However in this case some allocation is likely to fail soon anyhow. Currently there is no API to manually add a block of a given size to the heap, although that could easily be added if necessary. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- py/gc.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++- py/gc.h | 8 +++- py/mpconfig.h | 15 +++++++ 3 files changed, 127 insertions(+), 3 deletions(-) diff --git a/py/gc.c b/py/gc.c index 11be30dfef..b2e4aa4aae 100644 --- a/py/gc.c +++ b/py/gc.c @@ -236,6 +236,83 @@ void gc_add(void *start, void *end) { // Add this area to the linked list prev_area->next = area; } + +#if MICROPY_GC_SPLIT_HEAP_AUTO +// Try to automatically add a heap area large enough to fulfill 'failed_alloc'. +STATIC bool gc_try_add_heap(size_t failed_alloc) { + // 'needed' is the size of a heap large enough to hold failed_alloc, with + // the additional metadata overheads as calculated in gc_setup_area(). + // + // Rather than reproduce all of that logic here, we approximate that adding + // (13/512) is enough overhead for sufficiently large heap areas (the + // overhead converges to 3/128, but there's some fixed overhead and some + // rounding up of partial block sizes). + size_t needed = failed_alloc + MAX(2048, failed_alloc * 13 / 512); + + size_t avail = gc_get_max_new_split(); + + DEBUG_printf("gc_try_add_heap failed_alloc " UINT_FMT ", " + "needed " UINT_FMT ", avail " UINT_FMT " bytes \n", + failed_alloc, + needed, + avail); + + if (avail < needed) { + // Can't fit this allocation, or system heap has nearly run out anyway + return false; + } + + // Deciding how much to grow the total heap by each time is tricky: + // + // - Grow by too small amounts, leads to heap fragmentation issues. + // + // - Grow by too large amounts, may lead to system heap running out of + // space. + // + // Currently, this implementation is: + // + // - At minimum, aim to double the total heap size each time we add a new + // heap. i.e. without any large single allocations, total size will be + // 64KB -> 128KB -> 256KB -> 512KB -> 1MB, etc + // + // - If the failed allocation is too large to fit in that size, the new + // heap is made exactly large enough for that allocation. Future growth + // will double the total heap size again. + // + // - If the new heap won't fit in the available free space, add the largest + // new heap that will fit (this may lead to failed system heap allocations + // elsewhere, but some allocation will likely fail in this circumstance!) + size_t total_heap = 0; + for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); + area != NULL; + area = NEXT_AREA(area)) { + total_heap += area->gc_pool_end - area->gc_alloc_table_start; + total_heap += ALLOC_TABLE_GAP_BYTE + sizeof(mp_state_mem_area_t); + } + + DEBUG_printf("total_heap " UINT_FMT " bytes\n", total_heap); + + size_t to_alloc = MIN(avail, MAX(total_heap, needed)); + + mp_state_mem_area_t *new_heap = MP_PLAT_ALLOC_HEAP(to_alloc); + + DEBUG_printf("MP_PLAT_ALLOC_HEAP " UINT_FMT " = %p\n", + to_alloc, new_heap); + + if (new_heap == NULL) { + // This should only fail: + // - In a threaded environment if another thread has + // allocated while this function ran. + // - If there is a bug in gc_get_max_new_split(). + return false; + } + + gc_add(new_heap, (void *)new_heap + to_alloc); + + return true; +} +#endif + #endif void gc_lock(void) { @@ -392,6 +469,9 @@ STATIC void gc_sweep(void) { #endif // free unmarked heads and their tails int free_tail = 0; + #if MICROPY_GC_SPLIT_HEAP_AUTO + mp_state_mem_area_t *prev_area = NULL; + #endif for (mp_state_mem_area_t *area = &MP_STATE_MEM(area); area != NULL; area = NEXT_AREA(area)) { size_t end_block = area->gc_alloc_table_byte_len * BLOCKS_PER_ATB; if (area->gc_last_used_block < end_block) { @@ -454,6 +534,17 @@ STATIC void gc_sweep(void) { } area->gc_last_used_block = last_used_block; + + #if MICROPY_GC_SPLIT_HEAP_AUTO + // Free any empty area, aside from the first one + if (last_used_block == 0 && prev_area != NULL) { + DEBUG_printf("gc_sweep free empty area %p\n", area); + NEXT_AREA(prev_area) = NEXT_AREA(area); + MP_PLAT_FREE_HEAP(area); + area = prev_area; + } + prev_area = area; + #endif } } @@ -636,6 +727,9 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) { size_t start_block; size_t n_free; int collected = !MP_STATE_MEM(gc_auto_collect_enabled); + #if MICROPY_GC_SPLIT_HEAP_AUTO + bool added = false; + #endif #if MICROPY_GC_ALLOC_THRESHOLD if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) { @@ -681,6 +775,12 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) { GC_EXIT(); // nothing found! if (collected) { + #if MICROPY_GC_SPLIT_HEAP_AUTO + if (!added && gc_try_add_heap(n_bytes)) { + added = true; + continue; + } + #endif return NULL; } DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes); @@ -1056,9 +1156,12 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { void gc_dump_info(const mp_print_t *print) { gc_info_t info; gc_info(&info); - mp_printf(print, "GC: total: %u, used: %u, free: %u\n", + mp_printf(print, "GC: total: %u, used: %u, free: %u", (uint)info.total, (uint)info.used, (uint)info.free); - mp_printf(print, " No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u, max free sz: %u\n", + #if MICROPY_GC_SPLIT_HEAP_AUTO + mp_printf(print, ", max new split: %u", (uint)gc_get_max_new_split()); + #endif + mp_printf(print, "\n No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u, max free sz: %u\n", (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block, (uint)info.max_free); } diff --git a/py/gc.h b/py/gc.h index 8431c0a6cf..7eec6265c8 100644 --- a/py/gc.h +++ b/py/gc.h @@ -35,7 +35,13 @@ void gc_init(void *start, void *end); #if MICROPY_GC_SPLIT_HEAP // Used to add additional memory areas to the heap. void gc_add(void *start, void *end); -#endif + +#if MICROPY_GC_SPLIT_HEAP_AUTO +// Port must implement this function to return the maximum available block of +// RAM to allocate a new heap area into using MP_PLAT_ALLOC_HEAP. +size_t gc_get_max_new_split(void); +#endif // MICROPY_GC_SPLIT_HEAP_AUTO +#endif // MICROPY_GC_SPLIT_HEAP // These lock/unlock functions can be nested. // They can be used to prevent the GC from allocating/freeing. diff --git a/py/mpconfig.h b/py/mpconfig.h index 4a15205ae3..de4a89206b 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -616,6 +616,11 @@ #define MICROPY_GC_SPLIT_HEAP (0) #endif +// Whether regions should be added/removed from the split heap as needed. +#ifndef MICROPY_GC_SPLIT_HEAP_AUTO +#define MICROPY_GC_SPLIT_HEAP_AUTO (0) +#endif + // Hook to run code during time consuming garbage collector operations // *i* is the loop index variable (e.g. can be used to run every x loops) #ifndef MICROPY_GC_HOOK_LOOP @@ -1896,6 +1901,16 @@ typedef double mp_float_t; #define MP_PLAT_FREE_EXEC(ptr, size) m_del(byte, ptr, size) #endif +// Allocating new heap area at runtime requires port to be able to allocate from system heap +#if MICROPY_GC_SPLIT_HEAP_AUTO +#ifndef MP_PLAT_ALLOC_HEAP +#define MP_PLAT_ALLOC_HEAP(size) malloc(size) +#endif +#ifndef MP_PLAT_FREE_HEAP +#define MP_PLAT_FREE_HEAP(ptr) free(ptr) +#endif +#endif + // This macro is used to do all output (except when MICROPY_PY_IO is defined) #ifndef MP_PLAT_PRINT_STRN #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) From 98fd78437c56efeebe2e38c944f5af0a1a59fe8a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 28 Jul 2023 12:16:05 +1000 Subject: [PATCH 024/121] esp32: Allow malloc() to allocate from SPIRAM. Also shrinks the "prefer internal" threshold to 8KB, any allocation larger than this will try PSRAM first. Change the mbedTLS config to use regular malloc() as well, instead of internal only. The default is set to internal-only due to to potential physical security issue of readout via PSRAM on the original ESP32. However, as MicroPython runs from plaintext flash and all other context is in the MP heap of PSRAM then it's hard to see how worsens physical security for MP. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- ports/esp32/boards/sdkconfig.base | 9 +++++++++ ports/esp32/boards/sdkconfig.spiram | 6 +++++- ports/esp32/boards/sdkconfig.spiram_sx | 6 +++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index bf6c3f45c5..b98d5d0678 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -49,6 +49,15 @@ CONFIG_LWIP_PPP_CHAP_SUPPORT=y # Use 4kiB output buffer instead of default 16kiB CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +# Allow mbedTLS to allocate from PSRAM or internal memory +# +# (The ESP-IDF default is internal-only, partly for physical security to prevent +# possible information leakage from unencrypted PSRAM contents on the original +# ESP32 - no PSRAM encryption on that chip. MicroPython doesn't support flash +# encryption and is already storing the Python heap in PSRAM so this isn't a +# significant factor in overall physical security.) +CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC=y + # ULP coprocessor support # Only on: ESP32, ESP32S2, ESP32S3 CONFIG_ULP_COPROC_ENABLED=y diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram index 74d35f7b4a..4dfc63624b 100644 --- a/ports/esp32/boards/sdkconfig.spiram +++ b/ports/esp32/boards/sdkconfig.spiram @@ -3,7 +3,11 @@ CONFIG_SPIRAM=y CONFIG_SPIRAM_CACHE_WORKAROUND=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y -CONFIG_SPIRAM_USE_CAPS_ALLOC=y +CONFIG_SPIRAM_USE_MALLOC=y + +# This is the threshold for preferring small allocations from internal memory +# first, before failing over to PSRAM. +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=8192 # SPIRAM increases the size of the firmware and overflows iram0_0_seg, due # to PSRAM bug workarounds. Apply some options to reduce the firmware size. diff --git a/ports/esp32/boards/sdkconfig.spiram_sx b/ports/esp32/boards/sdkconfig.spiram_sx index 329a507337..efe53ada41 100644 --- a/ports/esp32/boards/sdkconfig.spiram_sx +++ b/ports/esp32/boards/sdkconfig.spiram_sx @@ -7,4 +7,8 @@ CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM=y CONFIG_SPIRAM_BOOT_INIT=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y -CONFIG_SPIRAM_USE_CAPS_ALLOC=y +CONFIG_SPIRAM_USE_MALLOC=y + +# This is the threshold for preferring small allocations from internal memory +# first, before failing over to PSRAM. +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=8192 From 05dcb8be9957d0ed6c9694629be186a40c1a3fd9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 2 Aug 2023 16:51:07 +1000 Subject: [PATCH 025/121] esp32: Enable automatic Python heap growth. Via MICROPY_GC_SPLIT_HEAP_AUTO feature flag added in previous commit. Tested on ESP32 GENERIC_SPIRAM and GENERIC_S3 configurations, with some worst-case allocation patterns and the standard test suite. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- docs/library/esp32.rst | 11 +++++++++-- ports/esp32/gccollect.c | 10 ++++++++++ ports/esp32/main.c | 14 ++++++-------- ports/esp32/mpconfigport.h | 3 +++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index efdd6c1be2..856d9aef8d 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -51,13 +51,20 @@ Functions buffers and other data. This data is useful to get a sense of how much memory is available to ESP-IDF and the networking stack in particular. It may shed some light on situations where ESP-IDF operations fail due to allocation failures. - The information returned is *not* useful to troubleshoot Python allocation failures, - use `micropython.mem_info()` instead. The capabilities parameter corresponds to ESP-IDF's ``MALLOC_CAP_XXX`` values but the two most useful ones are predefined as `esp32.HEAP_DATA` for data heap regions and `esp32.HEAP_EXEC` for executable regions as used by the native code emitter. + Free IDF heap memory in the `esp32.HEAP_DATA` region is available to be + automatically added to the MicroPython heap to prevent a MicroPython + allocation from failing. However, the information returned here is otherwise + *not* useful to troubleshoot Python allocation failures, use + `micropython.mem_info()` instead. The "max new split" value in + `micropython.mem_info()` output corresponds to the largest free block of + ESP-IDF heap that could be automatically added on demand to the MicroPython + heap. + The return value is a list of 4-tuples, where each 4-tuple corresponds to one heap and contains: the total bytes, the free bytes, the largest free block, and the minimum free seen over time. diff --git a/ports/esp32/gccollect.c b/ports/esp32/gccollect.c index 6fa287de28..e16e8028ad 100644 --- a/ports/esp32/gccollect.c +++ b/ports/esp32/gccollect.c @@ -80,3 +80,13 @@ void gc_collect(void) { } #endif + +#if MICROPY_GC_SPLIT_HEAP_AUTO + +// The largest new region that is available to become Python heap is the largest +// free block in the ESP-IDF system heap. +size_t gc_get_max_new_split(void) { + return heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT); +} + +#endif diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 3a172e6f8d..a6346b027a 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -75,6 +75,10 @@ #define MP_TASK_STACK_LIMIT_MARGIN (1024) #endif +// Initial Python heap size. This starts small but adds new heap areas on +// demand due to settings MICROPY_GC_SPLIT_HEAP & MICROPY_GC_SPLIT_HEAP_AUTO +#define MP_TASK_HEAP_SIZE (64 * 1024) + int vprintf_null(const char *format, va_list ap) { // do nothing: this is used as a log target during raw repl mode return 0; @@ -100,19 +104,13 @@ void mp_task(void *pvParameter) { ESP_LOGE("esp_init", "can't create event loop: 0x%x\n", err); } - // Allocate the uPy heap using malloc and get the largest available region, - // limiting to 1/2 total available memory to leave memory for the OS. - // When SPIRAM is enabled, this will allocate from SPIRAM. - uint32_t caps = MALLOC_CAP_8BIT; - size_t heap_total = heap_caps_get_total_size(caps); - size_t mp_task_heap_size = MIN(heap_caps_get_largest_free_block(caps), heap_total / 2); - void *mp_task_heap = heap_caps_malloc(mp_task_heap_size, caps); + void *mp_task_heap = MP_PLAT_ALLOC_HEAP(MP_TASK_HEAP_SIZE); soft_reset: // initialise the stack pointer for the main thread mp_stack_set_top((void *)sp); mp_stack_set_limit(MP_TASK_STACK_SIZE - MP_TASK_STACK_LIMIT_MARGIN); - gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size); + gc_init(mp_task_heap, mp_task_heap + MP_TASK_HEAP_SIZE); mp_init(); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); readline_init0(); diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index aa13eaf2fe..55035b5f86 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -68,6 +68,9 @@ #define MICROPY_PY_THREAD_GIL (1) #define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) +#define MICROPY_GC_SPLIT_HEAP (1) +#define MICROPY_GC_SPLIT_HEAP_AUTO (1) + // extended modules #ifndef MICROPY_ESPNOW #define MICROPY_ESPNOW (1) From fa1ea21f75601a93827d143bb9074b1f7474a953 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 Aug 2023 14:34:25 +1000 Subject: [PATCH 026/121] esp32/gccollect: Make level arg volatile to force recursive function. Otherwise the compiler may inline the gc_collect_inner() function and/or remove the recursion, which is necessary to spill all the windowed registers to the C stack. Signed-off-by: Damien George --- ports/esp32/gccollect.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/ports/esp32/gccollect.c b/ports/esp32/gccollect.c index e16e8028ad..4b6dd8ab61 100644 --- a/ports/esp32/gccollect.c +++ b/ports/esp32/gccollect.c @@ -39,30 +39,25 @@ #include "xtensa/hal.h" -static void gc_collect_inner(int level) { +// The level argument must be volatile to force the compiler to emit code that +// will call this function recursively, to nest the C stack. +static void gc_collect_inner(volatile unsigned int level) { if (level < XCHAL_NUM_AREGS / 8) { + // Go deeper on the stack to spill more registers from the register window. gc_collect_inner(level + 1); - if (level != 0) { - return; - } - } - - if (level == XCHAL_NUM_AREGS / 8) { - // get the sp + } else { + // Deep enough so that all registers are on the C stack, now trace the stack. volatile uint32_t sp = (uint32_t)esp_cpu_get_sp(); gc_collect_root((void **)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); - return; } - - // trace root pointers from any threads - #if MICROPY_PY_THREAD - mp_thread_gc_others(); - #endif } void gc_collect(void) { gc_collect_start(); gc_collect_inner(0); + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif gc_collect_end(); } From ad123ed01393f34d31c7c9ac0f535a023f9385b7 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 31 Jul 2023 17:24:38 +1000 Subject: [PATCH 027/121] esp32/Makefile: Implement `make submodules` to match other ports. Signed-off-by: Jim Mussared --- extmod/extmod.cmake | 87 +++++++++++++++++++--------------- ports/esp32/Makefile | 25 ++++++---- ports/esp32/esp32_common.cmake | 3 ++ ports/rp2/Makefile | 7 ++- py/mkrules.cmake | 7 ++- 5 files changed, 79 insertions(+), 50 deletions(-) diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake index 305cdee942..7a7b892c96 100644 --- a/extmod/extmod.cmake +++ b/extmod/extmod.cmake @@ -60,51 +60,62 @@ set(MICROPY_SOURCE_EXTMOD if(MICROPY_PY_BTREE) set(MICROPY_LIB_BERKELEY_DIR "${MICROPY_DIR}/lib/berkeley-db-1.xx") + string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/berkeley-db-1.xx) - add_library(micropy_extmod_btree OBJECT - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_conv.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_debug.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_delete.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_get.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_open.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_overflow.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_page.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_put.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_search.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_seq.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_split.c - ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_utils.c - ${MICROPY_LIB_BERKELEY_DIR}/mpool/mpool.c - ) + if(ECHO_SUBMODULES OR ECHO_QUERY_VARIANTS) + # No-op, we're just doing submodule/variant discovery. + # Cannot run the add_library/target_include_directories rules (even though + # the build won't run) because IDF will attempt verify the files exist. + elseif(NOT EXISTS ${MICROPY_LIB_BERKELEY_DIR}/README) + # Regular build, submodule not initialised -- fail with a clear error. + message(FATAL_ERROR " MICROPY_PY_BTREE is enabled but the berkeley-db submodule is not initialised.\n Run 'make BOARD=${MICROPY_BOARD} submodules'") + else() + # Regular build, we have the submodule. + add_library(micropy_extmod_btree OBJECT + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_conv.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_debug.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_delete.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_get.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_open.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_overflow.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_page.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_put.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_search.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_seq.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_split.c + ${MICROPY_LIB_BERKELEY_DIR}/btree/bt_utils.c + ${MICROPY_LIB_BERKELEY_DIR}/mpool/mpool.c + ) - target_include_directories(micropy_extmod_btree PRIVATE - ${MICROPY_LIB_BERKELEY_DIR}/PORT/include - ) + target_include_directories(micropy_extmod_btree PRIVATE + ${MICROPY_LIB_BERKELEY_DIR}/PORT/include + ) - target_compile_definitions(micropy_extmod_btree PRIVATE - __DBINTERFACE_PRIVATE=1 - mpool_error=printf - abort=abort_ - "virt_fd_t=void*" - ) + target_compile_definitions(micropy_extmod_btree PRIVATE + __DBINTERFACE_PRIVATE=1 + mpool_error=printf + abort=abort_ + "virt_fd_t=void*" + ) - # The include directories and compile definitions below are needed to build - # modbtree.c and should be added to the main MicroPython target. + # The include directories and compile definitions below are needed to build + # modbtree.c and should be added to the main MicroPython target. - list(APPEND MICROPY_INC_CORE - "${MICROPY_LIB_BERKELEY_DIR}/PORT/include" - ) + list(APPEND MICROPY_INC_CORE + "${MICROPY_LIB_BERKELEY_DIR}/PORT/include" + ) - list(APPEND MICROPY_DEF_CORE - MICROPY_PY_BTREE=1 - __DBINTERFACE_PRIVATE=1 - "virt_fd_t=void*" - ) + list(APPEND MICROPY_DEF_CORE + MICROPY_PY_BTREE=1 + __DBINTERFACE_PRIVATE=1 + "virt_fd_t=void*" + ) - list(APPEND MICROPY_SOURCE_EXTMOD - ${MICROPY_EXTMOD_DIR}/modbtree.c - ) + list(APPEND MICROPY_SOURCE_EXTMOD + ${MICROPY_EXTMOD_DIR}/modbtree.c + ) + endif() endif() # Library for mbedtls diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 7c8c225dfb..239618c6f7 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -26,12 +26,6 @@ BAUD ?= 460800 PYTHON ?= python3 -# Would be good to use cmake to discover submodules (see how rp2/Makefile does -# it), but on ESP32 the same trick doesn't work because "idf.py build" fails -# on berkeley-db dependency before printing out the submodule list. -# For now just force the submodule dependencies here. -GIT_SUBMODULES += lib/berkeley-db-1.xx lib/micropython-lib - .PHONY: all clean deploy erase submodules FORCE CMAKE_ARGS = @@ -40,20 +34,24 @@ ifdef USER_C_MODULES CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} endif -IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -D MICROPY_BOARD_DIR=$(abspath $(BOARD_DIR)) -B $(BUILD) $(CMAKE_ARGS) +IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -D MICROPY_BOARD_DIR=$(abspath $(BOARD_DIR)) $(CMAKE_ARGS) ifdef FROZEN_MANIFEST IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST) endif +ifdef BOARD_VARIANT + IDFPY_FLAGS += -D MICROPY_BOARD_VARIANT=$(BOARD_VARIANT) +endif + HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m" define RUN_IDF_PY - idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) $(1) + idf.py $(IDFPY_FLAGS) -B $(BUILD) -p $(PORT) -b $(BAUD) $(1) endef all: - idf.py $(IDFPY_FLAGS) build || (echo -e $(HELP_BUILD_ERROR); false) + idf.py $(IDFPY_FLAGS) -B $(BUILD) build || (echo -e $(HELP_BUILD_ERROR); false) @$(PYTHON) makeimg.py \ $(BUILD)/sdkconfig \ $(BUILD)/bootloader/bootloader.bin \ @@ -85,5 +83,12 @@ size-components: size-files: $(call RUN_IDF_PY,size-files) +# Running the build with ECHO_SUBMODULES set will trigger py/mkrules.cmake to +# print out the value of the GIT_SUBMODULES variable, prefixed with +# "GIT_SUBMODULES", and then abort. This extracts out that line from the idf.py +# output and passes the list of submodules to py/mkrules.mk which does the +# `git submodule init` on each. submodules: - $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules + @GIT_SUBMODULES=$$(idf.py $(IDFPY_FLAGS) -B $(BUILD)/submodules -D ECHO_SUBMODULES=1 build 2>&1 | \ + grep '^GIT_SUBMODULES=' | cut -d= -f2); \ + $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$${GIT_SUBMODULES}" submodules diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index 37a19316b6..098df1f1ae 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -11,6 +11,9 @@ endif() # Include core source components. include(${MICROPY_DIR}/py/py.cmake) +# CMAKE_BUILD_EARLY_EXPANSION is set during the component-discovery phase of +# `idf.py build`, so none of the extmod/usermod (and in reality, most of the +# micropython) rules need to happen. Specifically, you cannot invoke add_library. if(NOT CMAKE_BUILD_EARLY_EXPANSION) # Enable extmod components that will be configured by extmod.cmake. # A board may also have enabled additional components. diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index 4f5b4728ec..7c14415ad5 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -50,9 +50,14 @@ clean: # First ensure that pico-sdk is initialised, then use cmake to pick everything # else (including board-specific dependencies). +# Running the build with ECHO_SUBMODULES set will trigger py/mkrules.cmake to +# print out the value of the GIT_SUBMODULES variable, prefixed with +# "GIT_SUBMODULES", and then abort. This extracts out that line from the cmake +# output and passes the list of submodules to py/mkrules.mk which does the +# `git submodule init` on each. submodules: $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="lib/pico-sdk" submodules - GIT_SUBMODULES=$$(cmake -B $(BUILD)/submodules -DECHO_SUBMODULES=1 ${CMAKE_ARGS} -S . 2>&1 | \ + @GIT_SUBMODULES=$$(cmake -B $(BUILD)/submodules -DECHO_SUBMODULES=1 ${CMAKE_ARGS} -S . 2>&1 | \ grep '^GIT_SUBMODULES=' | cut -d= -f2); \ $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$${GIT_SUBMODULES}" submodules diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 7eb5fcf018..21d5c27334 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -178,7 +178,12 @@ if(MICROPY_FROZEN_MANIFEST) set(MICROPY_LIB_DIR ${MICROPY_DIR}/lib/micropython-lib) endif() - if(NOT (${ECHO_SUBMODULES}) AND NOT EXISTS ${MICROPY_LIB_DIR}/README.md) + if(ECHO_SUBMODULES OR ECHO_QUERY_VARIANTS) + # No-op, we're just doing submodule/variant discovery. + # Note: All the following rules are safe to run in discovery mode even + # though the submodule might not be available as they do not directly depend + # on anything from the submodule. + elseif(NOT EXISTS ${MICROPY_LIB_DIR}/README.md) message(FATAL_ERROR " micropython-lib not initialized.\n Run 'make BOARD=${MICROPY_BOARD} submodules'") endif() From 9573d31071b069713ac7bc803777fba65c4ead41 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 31 Jul 2023 17:32:27 +1000 Subject: [PATCH 028/121] all: Remove query-variants make target. This is difficult to implement on cmake-based ports, and having the list of variants in mpconfigboard.{cmake,mk} duplicates information that's already in board.json. This removes the existing query-variants make target from stm32 & rp2 and the definition of BOARD_VARIANTS from the various board files. Also renames the cmake variable to MICROPY_BOARD_VARIANT to match other variables such as MICROPY_BOARD. The make variable stays as BOARD_VARIANT. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- extmod/extmod.cmake | 2 +- ports/rp2/Makefile | 7 +------ ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake | 14 ++++++-------- .../ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk | 1 - ports/stm32/Makefile | 3 --- ports/stm32/boards/PYBLITEV10/mpconfigboard.mk | 2 -- ports/stm32/boards/PYBV10/mpconfigboard.mk | 2 -- ports/stm32/boards/PYBV11/mpconfigboard.mk | 2 -- py/mkrules.cmake | 8 +------- 9 files changed, 9 insertions(+), 32 deletions(-) diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake index 7a7b892c96..c8756a682e 100644 --- a/extmod/extmod.cmake +++ b/extmod/extmod.cmake @@ -62,7 +62,7 @@ if(MICROPY_PY_BTREE) set(MICROPY_LIB_BERKELEY_DIR "${MICROPY_DIR}/lib/berkeley-db-1.xx") string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/berkeley-db-1.xx) - if(ECHO_SUBMODULES OR ECHO_QUERY_VARIANTS) + if(ECHO_SUBMODULES) # No-op, we're just doing submodule/variant discovery. # Cannot run the add_library/target_include_directories rules (even though # the build won't run) because IDF will attempt verify the files exist. diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index 7c14415ad5..ccfc1ac7d6 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -36,7 +36,7 @@ CMAKE_ARGS += -DCMAKE_BUILD_TYPE=Debug endif ifdef BOARD_VARIANT -CMAKE_ARGS += -DBOARD_VARIANT=${BOARD_VARIANT} +CMAKE_ARGS += -DMICROPY_BOARD_VARIANT=$(BOARD_VARIANT) endif HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m" @@ -60,8 +60,3 @@ submodules: @GIT_SUBMODULES=$$(cmake -B $(BUILD)/submodules -DECHO_SUBMODULES=1 ${CMAKE_ARGS} -S . 2>&1 | \ grep '^GIT_SUBMODULES=' | cut -d= -f2); \ $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$${GIT_SUBMODULES}" submodules - -query-variants: - @BOARD_VARIANTS=$$(cmake -B $(BUILD)/variants -DECHO_BOARD_VARIANTS=1 ${CMAKE_ARGS} -S . 2>&1 | \ - grep '^BOARD_VARIANTS=' | cut -d= -f2); \ - echo "VARIANTS: $${BOARD_VARIANTS}" diff --git a/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake b/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake index 5fd3eec897..28a30f4580 100644 --- a/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake +++ b/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake @@ -7,20 +7,18 @@ list(APPEND PICO_BOARD_HEADER_DIRS ${MICROPY_BOARD_DIR}) # Freeze board.py set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) -# Provide different variants for the downloads page -set(BOARD_VARIANTS "flash_2mb flash_4mb flash_8mb flash_16mb") - # Select the 16MB variant as the default set(PICO_BOARD "weactstudio_16mb") -if("${BOARD_VARIANT}" STREQUAL "flash_2mb") +# Provide different variants for the downloads page +if(MICROPY_BOARD_VARIANT STREQUAL "flash_2mb") set(PICO_BOARD "weactstudio_2mb") endif() -if("${BOARD_VARIANT}" STREQUAL "flash_4mb") -set(PICO_BOARD "weactstudio_4mb") +if(MICROPY_BOARD_VARIANT STREQUAL "flash_4mb") + set(PICO_BOARD "weactstudio_4mb") endif() -if("${BOARD_VARIANT}" STREQUAL "flash_8mb") -set(PICO_BOARD "weactstudio_8mb") +if(MICROPY_BOARD_VARIANT STREQUAL "flash_8mb") + set(PICO_BOARD "weactstudio_8mb") endif() diff --git a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk index 1a2635f7af..43ca5a59cc 100644 --- a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk @@ -7,5 +7,4 @@ TEXT0 = 0x4000 MICROPY_PY_NETWORK ?= 1 MICROPY_PY_NETWORK_NINAW10 ?= 1 -BOARD_VARIANTS += "wlan" MICROPY_HW_CODESIZE ?= 496K diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 81a48249e8..2bfd11157e 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -43,9 +43,6 @@ include $(TOP)/extmod/extmod.mk GIT_SUBMODULES += lib/libhydrogen lib/stm32lib -query-variants: - $(ECHO) "VARIANTS:" $(BOARD_VARIANTS) - LD_DIR=boards USBDEV_DIR=usbdev #USBHOST_DIR=usbhost diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk index 461886b63c..afee27e94f 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk @@ -6,8 +6,6 @@ TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 # Provide different variants for the downloads page. -BOARD_VARIANTS += "dp thread dp-thread network" - ifeq ($(BOARD_VARIANT),dp) MICROPY_FLOAT_IMPL=double endif diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk index 363f6b4806..d26ebd5ae9 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk @@ -16,8 +16,6 @@ endif MICROPY_VFS_LFS2 = 1 # Provide different variants for the downloads page. -BOARD_VARIANTS += "dp thread dp-thread network" - ifeq ($(BOARD_VARIANT),dp) MICROPY_FLOAT_IMPL=double endif diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk index 857049f215..df2d70cda1 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk @@ -16,8 +16,6 @@ endif MICROPY_VFS_LFS2 = 1 # Provide different variants for the downloads page. -BOARD_VARIANTS += "dp thread dp-thread network" - ifeq ($(BOARD_VARIANT),dp) MICROPY_FLOAT_IMPL=double endif diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 21d5c27334..02e3148f2b 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -178,7 +178,7 @@ if(MICROPY_FROZEN_MANIFEST) set(MICROPY_LIB_DIR ${MICROPY_DIR}/lib/micropython-lib) endif() - if(ECHO_SUBMODULES OR ECHO_QUERY_VARIANTS) + if(ECHO_SUBMODULES) # No-op, we're just doing submodule/variant discovery. # Note: All the following rules are safe to run in discovery mode even # though the submodule might not be available as they do not directly depend @@ -223,9 +223,3 @@ if(ECHO_SUBMODULES) execute_process(COMMAND ${CMAKE_COMMAND} -E echo "GIT_SUBMODULES=${GIT_SUBMODULES}") message(FATAL_ERROR "Done") endif() - -# Display BOARD_VARIANTS -if(ECHO_BOARD_VARIANTS) - execute_process(COMMAND ${CMAKE_COMMAND} -E echo "BOARD_VARIANTS=${BOARD_VARIANTS}") - message(FATAL_ERROR "Done") -endif() From 2fbf42d3ad974b7de12823bb5a86df8a08d917ce Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 25 Jul 2023 15:03:30 +1000 Subject: [PATCH 029/121] esp32/boards/GENERIC: Merge with GENERIC_{SPIRAM,OTA,D2WD,UNICORE}. These are now variants of the GENERIC board. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/boards/GENERIC/board.json | 8 +++- ports/esp32/boards/GENERIC/board.md | 10 ++++- .../esp32/boards/GENERIC/mpconfigboard.cmake | 44 +++++++++++++++++++ ports/esp32/boards/GENERIC/mpconfigboard.h | 10 ++++- .../sdkconfig.d2wd} | 0 .../sdkconfig.board => GENERIC/sdkconfig.ota} | 0 .../sdkconfig.unicore} | 0 ports/esp32/boards/GENERIC_D2WD/board.json | 20 --------- .../boards/GENERIC_D2WD/mpconfigboard.cmake | 5 --- .../esp32/boards/GENERIC_D2WD/mpconfigboard.h | 2 - ports/esp32/boards/GENERIC_OTA/board.json | 20 --------- .../boards/GENERIC_OTA/mpconfigboard.cmake | 5 --- .../esp32/boards/GENERIC_OTA/mpconfigboard.h | 2 - ports/esp32/boards/GENERIC_SPIRAM/board.json | 24 ---------- ports/esp32/boards/GENERIC_SPIRAM/board.md | 1 - .../boards/GENERIC_SPIRAM/mpconfigboard.cmake | 5 --- .../boards/GENERIC_SPIRAM/mpconfigboard.h | 2 - ports/esp32/boards/GENERIC_UNICORE/board.json | 20 --------- ports/esp32/boards/GENERIC_UNICORE/board.md | 1 - .../GENERIC_UNICORE/mpconfigboard.cmake | 5 --- .../boards/GENERIC_UNICORE/mpconfigboard.h | 2 - ports/esp32/esp32_common.cmake | 1 + 22 files changed, 69 insertions(+), 118 deletions(-) rename ports/esp32/boards/{GENERIC_D2WD/sdkconfig.board => GENERIC/sdkconfig.d2wd} (100%) rename ports/esp32/boards/{GENERIC_OTA/sdkconfig.board => GENERIC/sdkconfig.ota} (100%) rename ports/esp32/boards/{GENERIC_UNICORE/sdkconfig.board => GENERIC/sdkconfig.unicore} (100%) delete mode 100644 ports/esp32/boards/GENERIC_D2WD/board.json delete mode 100644 ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h delete mode 100644 ports/esp32/boards/GENERIC_OTA/board.json delete mode 100644 ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/GENERIC_OTA/mpconfigboard.h delete mode 100644 ports/esp32/boards/GENERIC_SPIRAM/board.json delete mode 100644 ports/esp32/boards/GENERIC_SPIRAM/board.md delete mode 100644 ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h delete mode 100644 ports/esp32/boards/GENERIC_UNICORE/board.json delete mode 100644 ports/esp32/boards/GENERIC_UNICORE/board.md delete mode 100644 ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json index f70e2e0890..d08fcfec15 100644 --- a/ports/esp32/boards/GENERIC/board.json +++ b/ports/esp32/boards/GENERIC/board.json @@ -13,11 +13,15 @@ "esp32_devkitc.jpg" ], "mcu": "esp32", - "product": "ESP32", + "product": "ESP32 / WROOM", "thumbnail": "", "url": "https://www.espressif.com/en/products/modules", "variants": { - "idf3": "Compiled with IDF 3.x" + "idf3": "Compiled with IDF 3.x", + "d2wd": "ESP32 D2WD", + "spiram": "Support for SPIRAM / WROVER", + "unicore": "ESP32 Unicore", + "ota": "Support for OTA" }, "vendor": "Espressif" } diff --git a/ports/esp32/boards/GENERIC/board.md b/ports/esp32/boards/GENERIC/board.md index efb2b2cab7..8a669411d0 100644 --- a/ports/esp32/boards/GENERIC/board.md +++ b/ports/esp32/boards/GENERIC/board.md @@ -1 +1,9 @@ -The following files are firmware for ESP32-based boards without external SPIRAM. +The following files are firmware that should work on most ESP32-based boards +with 4MiB of flash, including WROOM WROVER, SOLO, PICO, and MINI modules. + +If your board is based on a WROVER module, or otherwise has SPIRAM (also known +as PSRAM), then use the "spiram" variant. + +The "d2wd" variant is for ESP32-D2WD chips (with 2MiB flash), and "unicore" is +for single-core ESP32 chips (e.g. the "SOLO" modules). The "ota" variant sets +up the partition table to allow for Over-the-Air updates. diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.cmake b/ports/esp32/boards/GENERIC/mpconfigboard.cmake index ac60dc8630..29096c2768 100644 --- a/ports/esp32/boards/GENERIC/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC/mpconfigboard.cmake @@ -2,3 +2,47 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.base boards/sdkconfig.ble ) + +if(MICROPY_BOARD_VARIANT STREQUAL "d2wd") + set(SDKCONFIG_DEFAULTS + ${SDKCONFIG_DEFAULTS} + boards/GENERIC/sdkconfig.d2wd + ) + + list(APPEND MICROPY_DEF_BOARD + MICROPY_HW_MCU_NAME="ESP32-D2WD" + ) +endif() + +if(MICROPY_BOARD_VARIANT STREQUAL "ota") + set(SDKCONFIG_DEFAULTS + ${SDKCONFIG_DEFAULTS} + boards/GENERIC/sdkconfig.ota + ) + + list(APPEND MICROPY_DEF_BOARD + MICROPY_HW_BOARD_NAME="Generic ESP32 module with OTA" + ) +endif() + +if(MICROPY_BOARD_VARIANT STREQUAL "spiram") + set(SDKCONFIG_DEFAULTS + ${SDKCONFIG_DEFAULTS} + boards/sdkconfig.spiram + ) + + list(APPEND MICROPY_DEF_BOARD + MICROPY_HW_BOARD_NAME="Generic ESP32 module with SPIRAM" + ) +endif() + +if(MICROPY_BOARD_VARIANT STREQUAL "unicore") + set(SDKCONFIG_DEFAULTS + ${SDKCONFIG_DEFAULTS} + boards/GENERIC/sdkconfig.unicore + ) + + list(APPEND MICROPY_DEF_BOARD + MICROPY_HW_MCU_NAME="ESP32-UNICORE" + ) +endif() diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.h b/ports/esp32/boards/GENERIC/mpconfigboard.h index 644807f78e..7171a84bb3 100644 --- a/ports/esp32/boards/GENERIC/mpconfigboard.h +++ b/ports/esp32/boards/GENERIC/mpconfigboard.h @@ -1,2 +1,10 @@ -#define MICROPY_HW_BOARD_NAME "ESP32 module" +// Both of these can be set by mpconfigboard.cmake if a BOARD_VARIANT is +// specified. + +#ifndef MICROPY_HW_BOARD_NAME +#define MICROPY_HW_BOARD_NAME "Generic ESP32 module" +#endif + +#ifndef MICROPY_HW_MCU_NAME #define MICROPY_HW_MCU_NAME "ESP32" +#endif diff --git a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board b/ports/esp32/boards/GENERIC/sdkconfig.d2wd similarity index 100% rename from ports/esp32/boards/GENERIC_D2WD/sdkconfig.board rename to ports/esp32/boards/GENERIC/sdkconfig.d2wd diff --git a/ports/esp32/boards/GENERIC_OTA/sdkconfig.board b/ports/esp32/boards/GENERIC/sdkconfig.ota similarity index 100% rename from ports/esp32/boards/GENERIC_OTA/sdkconfig.board rename to ports/esp32/boards/GENERIC/sdkconfig.ota diff --git a/ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board b/ports/esp32/boards/GENERIC/sdkconfig.unicore similarity index 100% rename from ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board rename to ports/esp32/boards/GENERIC/sdkconfig.unicore diff --git a/ports/esp32/boards/GENERIC_D2WD/board.json b/ports/esp32/boards/GENERIC_D2WD/board.json deleted file mode 100644 index 0582820445..0000000000 --- a/ports/esp32/boards/GENERIC_D2WD/board.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "deploy": [ - "../deploy.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "WiFi" - ], - "id": "esp32-d2wd", - "images": [ - "generic_d2wd.jpg" - ], - "mcu": "esp32", - "product": "ESP32 D2WD", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake deleted file mode 100644 index 88cc7a730e..0000000000 --- a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.ble - boards/GENERIC_D2WD/sdkconfig.board -) diff --git a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h b/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h deleted file mode 100644 index 8923d46fd1..0000000000 --- a/ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h +++ /dev/null @@ -1,2 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "Generic ESP32-D2WD module" -#define MICROPY_HW_MCU_NAME "ESP32-D2WD" diff --git a/ports/esp32/boards/GENERIC_OTA/board.json b/ports/esp32/boards/GENERIC_OTA/board.json deleted file mode 100644 index 3b882e04f8..0000000000 --- a/ports/esp32/boards/GENERIC_OTA/board.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "deploy": [ - "../deploy.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "WiFi" - ], - "id": "esp32-ota", - "images": [ - "esp32_devkitc.jpg" - ], - "mcu": "esp32", - "product": "ESP32 with OTA support", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake deleted file mode 100644 index 8bc9d507af..0000000000 --- a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.ble - boards/GENERIC_OTA/sdkconfig.board -) diff --git a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.h b/ports/esp32/boards/GENERIC_OTA/mpconfigboard.h deleted file mode 100644 index ff39c4b2b7..0000000000 --- a/ports/esp32/boards/GENERIC_OTA/mpconfigboard.h +++ /dev/null @@ -1,2 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "4MB/OTA module" -#define MICROPY_HW_MCU_NAME "ESP32" diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.json b/ports/esp32/boards/GENERIC_SPIRAM/board.json deleted file mode 100644 index 02242028fb..0000000000 --- a/ports/esp32/boards/GENERIC_SPIRAM/board.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "deploy": [ - "../deploy.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "External RAM", - "WiFi" - ], - "id": "esp32spiram", - "images": [ - "esp32_psram.jpg" - ], - "mcu": "esp32", - "product": "ESP32 with SPIRAM", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "variants": { - "idf3": "Compiled with IDF 3.x" - }, - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.md b/ports/esp32/boards/GENERIC_SPIRAM/board.md deleted file mode 100644 index c638f63dd3..0000000000 --- a/ports/esp32/boards/GENERIC_SPIRAM/board.md +++ /dev/null @@ -1 +0,0 @@ -The following files are firmware for ESP32-based boards with external SPIRAM (also known as PSRAM). diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake deleted file mode 100644 index 2e1d799b93..0000000000 --- a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.ble - boards/sdkconfig.spiram -) diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h deleted file mode 100644 index a5982e47e5..0000000000 --- a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h +++ /dev/null @@ -1,2 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP32 module (spiram)" -#define MICROPY_HW_MCU_NAME "ESP32" diff --git a/ports/esp32/boards/GENERIC_UNICORE/board.json b/ports/esp32/boards/GENERIC_UNICORE/board.json deleted file mode 100644 index 1f3beaf6e0..0000000000 --- a/ports/esp32/boards/GENERIC_UNICORE/board.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "deploy": [ - "../deploy.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "WiFi" - ], - "id": "esp32-unicore", - "images": [ - "generic_unicore.jpg" - ], - "mcu": "esp32", - "product": "ESP32 Unicore", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/GENERIC_UNICORE/board.md b/ports/esp32/boards/GENERIC_UNICORE/board.md deleted file mode 100644 index b41c167498..0000000000 --- a/ports/esp32/boards/GENERIC_UNICORE/board.md +++ /dev/null @@ -1 +0,0 @@ -The following files are daily firmware for single-core ESP32-based boards without external SPIRAM. diff --git a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake deleted file mode 100644 index 2f34688c8c..0000000000 --- a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.ble - boards/GENERIC_UNICORE/sdkconfig.board -) diff --git a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h deleted file mode 100644 index 5d0624b9c3..0000000000 --- a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h +++ /dev/null @@ -1,2 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP32 Unicore module" -#define MICROPY_HW_MCU_NAME "ESP32-UNICORE" diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index 098df1f1ae..f5219048f3 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -170,6 +170,7 @@ set(MICROPY_CROSS_FLAGS -march=xtensawin) # Set compile options for this port. target_compile_definitions(${MICROPY_TARGET} PUBLIC ${MICROPY_DEF_CORE} + ${MICROPY_DEF_BOARD} MICROPY_ESP_IDF_4=1 MICROPY_VFS_FAT=1 MICROPY_VFS_LFS2=1 From 4815af75bc0bc21e1e66b958fd4ee4e90c24ba10 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 25 Jul 2023 14:45:07 +1000 Subject: [PATCH 030/121] esp32/boards/GENERIC_C3: Merge with GENERIC_C3_USB. As the IDF no longer supports earlier revisions of the C3 by default, we now just explicitly support rev 3+ and enable USB (which wasn't supported in earlier revisions). This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/boards/GENERIC_C3/board.md | 7 +++++++ .../boards/GENERIC_C3/mpconfigboard.cmake | 1 + .../sdkconfig.c3usb} | 0 ports/esp32/boards/GENERIC_C3_USB/board.json | 20 ------------------- .../boards/GENERIC_C3_USB/mpconfigboard.cmake | 7 ------- .../boards/GENERIC_C3_USB/mpconfigboard.h | 8 -------- 6 files changed, 8 insertions(+), 35 deletions(-) create mode 100644 ports/esp32/boards/GENERIC_C3/board.md rename ports/esp32/boards/{GENERIC_C3_USB/sdkconfig.board => GENERIC_C3/sdkconfig.c3usb} (100%) delete mode 100644 ports/esp32/boards/GENERIC_C3_USB/board.json delete mode 100644 ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.h diff --git a/ports/esp32/boards/GENERIC_C3/board.md b/ports/esp32/boards/GENERIC_C3/board.md new file mode 100644 index 0000000000..1604b879c5 --- /dev/null +++ b/ports/esp32/boards/GENERIC_C3/board.md @@ -0,0 +1,7 @@ +The following files are firmware images that should work on most +ESP32-C3-based boards with 4MiB of flash, including WROOM and MINI modules, +that use the revision 3 silicon (or newer). + +USB serial/JTAG support is enabled on pin 18 and 19. Note that this +is not a full USB stack, the C3 just provides a CDC/ACM class serial +and JTAG interface. diff --git a/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake index 38bf7388fa..c8f78c161d 100644 --- a/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake @@ -3,4 +3,5 @@ set(IDF_TARGET esp32c3) set(SDKCONFIG_DEFAULTS boards/sdkconfig.base boards/sdkconfig.ble + boards/GENERIC_C3/sdkconfig.c3usb ) diff --git a/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board b/ports/esp32/boards/GENERIC_C3/sdkconfig.c3usb similarity index 100% rename from ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board rename to ports/esp32/boards/GENERIC_C3/sdkconfig.c3usb diff --git a/ports/esp32/boards/GENERIC_C3_USB/board.json b/ports/esp32/boards/GENERIC_C3_USB/board.json deleted file mode 100644 index 6d51e0a2c1..0000000000 --- a/ports/esp32/boards/GENERIC_C3_USB/board.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "deploy": [ - "../deploy_c3.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "WiFi" - ], - "id": "esp32c3-usb", - "images": [ - "esp32c3_devkitmini.jpg" - ], - "mcu": "esp32c3", - "product": "ESP32-C3 with USB", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.cmake deleted file mode 100644 index 7436eead87..0000000000 --- a/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.cmake +++ /dev/null @@ -1,7 +0,0 @@ -set(IDF_TARGET esp32c3) - -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.ble - boards/GENERIC_C3_USB/sdkconfig.board -) diff --git a/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.h b/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.h deleted file mode 100644 index d403e70e46..0000000000 --- a/ports/esp32/boards/GENERIC_C3_USB/mpconfigboard.h +++ /dev/null @@ -1,8 +0,0 @@ -// This configuration is for a generic ESP32C3 board with 4MiB (or more) of flash. - -#define MICROPY_HW_BOARD_NAME "ESP32C3 module" -#define MICROPY_HW_MCU_NAME "ESP32C3" - -#define MICROPY_HW_ENABLE_SDCARD (0) -#define MICROPY_PY_MACHINE_DAC (0) -#define MICROPY_PY_MACHINE_I2S (0) From b25a67590d2cd123a7d5dd453da5175bf735c748 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 25 Jul 2023 15:20:05 +1000 Subject: [PATCH 031/121] esp32/boards/GENERIC_S2: Merge with ESP32_S2_WROVER. Unsure of the history of the ESP32_S2_WROVER board (and why it wasn't named GENERIC_S2_...) but now it's a variant of the generic S2 board. Also removes the non-existent CONFIG_USB_AND_UART from all S2 boards. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/boards/ESP32_S2_WROVER/board.json | 20 ------------------- .../ESP32_S2_WROVER/mpconfigboard.cmake | 8 -------- .../boards/ESP32_S2_WROVER/mpconfigboard.h | 8 -------- .../boards/ESP32_S2_WROVER/sdkconfig.board | 10 ---------- ports/esp32/boards/GENERIC_S2/board.json | 1 + ports/esp32/boards/GENERIC_S2/board.md | 6 ++++++ .../boards/GENERIC_S2/mpconfigboard.cmake | 1 + ports/esp32/boards/GENERIC_S2/mpconfigboard.h | 8 ++++---- .../boards/LOLIN_S2_MINI/sdkconfig.board | 1 - .../boards/LOLIN_S2_PICO/sdkconfig.board | 1 - .../boards/UM_FEATHERS2NEO/sdkconfig.board | 1 - ports/esp32/boards/UM_TINYS2/sdkconfig.board | 1 - 12 files changed, 12 insertions(+), 54 deletions(-) delete mode 100644 ports/esp32/boards/ESP32_S2_WROVER/board.json delete mode 100644 ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h delete mode 100644 ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board create mode 100644 ports/esp32/boards/GENERIC_S2/board.md diff --git a/ports/esp32/boards/ESP32_S2_WROVER/board.json b/ports/esp32/boards/ESP32_S2_WROVER/board.json deleted file mode 100644 index d4c4ce21df..0000000000 --- a/ports/esp32/boards/ESP32_S2_WROVER/board.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "deploy": [ - "../deploy_s2.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "External RAM", - "WiFi" - ], - "images": [ - "ESP32-S2-WROVER_L_0.jpg" - ], - "mcu": "esp32s2", - "product": "ESP32-S2 WROVER", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake deleted file mode 100644 index 056c9ab4a6..0000000000 --- a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake +++ /dev/null @@ -1,8 +0,0 @@ -set(IDF_TARGET esp32s2) - -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.spiram_sx - boards/sdkconfig.usb - boards/ESP32_S2_WROVER/sdkconfig.board -) diff --git a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h deleted file mode 100644 index a96262c607..0000000000 --- a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h +++ /dev/null @@ -1,8 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP32-S2-WROVER" -#define MICROPY_HW_MCU_NAME "ESP32-S2" - -#define MICROPY_PY_BLUETOOTH (0) -#define MICROPY_HW_ENABLE_SDCARD (0) - -#define MICROPY_HW_I2C0_SCL (7) -#define MICROPY_HW_I2C0_SDA (6) diff --git a/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board b/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board deleted file mode 100644 index 40a8e3047c..0000000000 --- a/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board +++ /dev/null @@ -1,10 +0,0 @@ -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y - -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_USB_AND_UART=y - -# LWIP -CONFIG_LWIP_LOCAL_HOSTNAME="ESP32-S2-WROVER" -# end of LWIP diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/GENERIC_S2/board.json index 102b039bf8..35d06f2f7e 100644 --- a/ports/esp32/boards/GENERIC_S2/board.json +++ b/ports/esp32/boards/GENERIC_S2/board.json @@ -6,6 +6,7 @@ "features": [ "BLE", "External Flash", + "External RAM", "WiFi" ], "images": [ diff --git a/ports/esp32/boards/GENERIC_S2/board.md b/ports/esp32/boards/GENERIC_S2/board.md new file mode 100644 index 0000000000..3e46c02467 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S2/board.md @@ -0,0 +1,6 @@ +The following files are firmware that should work on most ESP32-S2-based +boards with 4MiB of flash, including WROOM, WROVER, and MINI modules. + +This firmware supports configurations with and without SPIRAM (also known as +PSRAM) and will auto-detect a connected SPIRAM chip at startup and allocate +the MicroPython heap accordingly. diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake index 59ca906f4d..76d185d90d 100644 --- a/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake @@ -3,4 +3,5 @@ set(IDF_TARGET esp32s2) set(SDKCONFIG_DEFAULTS boards/sdkconfig.base boards/sdkconfig.usb + boards/sdkconfig.spiram_sx ) diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.h b/ports/esp32/boards/GENERIC_S2/mpconfigboard.h index c4f86a8fc6..aaea41bcde 100644 --- a/ports/esp32/boards/GENERIC_S2/mpconfigboard.h +++ b/ports/esp32/boards/GENERIC_S2/mpconfigboard.h @@ -1,8 +1,8 @@ -#define MICROPY_HW_BOARD_NAME "ESP32S2 module" -#define MICROPY_HW_MCU_NAME "ESP32S2" +#define MICROPY_HW_BOARD_NAME "Generic ESP32S2 module" +#define MICROPY_HW_MCU_NAME "ESP32S2" -#define MICROPY_PY_BLUETOOTH (0) -#define MICROPY_HW_ENABLE_SDCARD (0) +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_HW_ENABLE_SDCARD (0) // Enable UART REPL for modules that have an external USB-UART and don't use native USB. #define MICROPY_HW_ENABLE_UART_REPL (1) diff --git a/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board index cbb3ad06d9..00ccc281ea 100644 --- a/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board +++ b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_USB_AND_UART=y # LWIP CONFIG_LWIP_LOCAL_HOSTNAME="LOLIN_S2_MINI" # end of LWIP diff --git a/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board index eadff2f1b9..a49f3936e7 100644 --- a/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board +++ b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_USB_AND_UART=y # LWIP CONFIG_LWIP_LOCAL_HOSTNAME="LOLIN_S2_PICO" # end of LWIP diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board index b2c6979a70..a624f7fd97 100644 --- a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board +++ b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_USB_AND_UART=y CONFIG_ESPTOOLPY_AFTER_NORESET=y # LWIP diff --git a/ports/esp32/boards/UM_TINYS2/sdkconfig.board b/ports/esp32/boards/UM_TINYS2/sdkconfig.board index 09e0deb078..0a2097e242 100644 --- a/ports/esp32/boards/UM_TINYS2/sdkconfig.board +++ b/ports/esp32/boards/UM_TINYS2/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_USB_AND_UART=y CONFIG_ESPTOOLPY_AFTER_NORESET=y # LWIP From afd407af8f1049aa764cc46d501286be36345a82 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 25 Jul 2023 15:25:07 +1000 Subject: [PATCH 032/121] esp32/boards/GENERIC_S3: Merge with GENERIC_S3_{SPIRAM,SPIRAM_OCT}. These are now variants of the GENERIC_S3 board. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/boards/GENERIC_S3/board.json | 6 +++++- ports/esp32/boards/GENERIC_S3/board.md | 7 +++++++ .../boards/GENERIC_S3/mpconfigboard.cmake | 13 +++++++++++++ ports/esp32/boards/GENERIC_S3/mpconfigboard.h | 5 ++++- .../esp32/boards/GENERIC_S3_SPIRAM/board.json | 19 ------------------- .../GENERIC_S3_SPIRAM/mpconfigboard.cmake | 9 --------- .../boards/GENERIC_S3_SPIRAM/mpconfigboard.h | 10 ---------- .../boards/GENERIC_S3_SPIRAM/sdkconfig.board | 9 --------- .../boards/GENERIC_S3_SPIRAM_OCT/board.json | 19 ------------------- .../GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake | 11 ----------- .../GENERIC_S3_SPIRAM_OCT/mpconfigboard.h | 10 ---------- .../GENERIC_S3_SPIRAM_OCT/sdkconfig.board | 9 --------- 12 files changed, 29 insertions(+), 98 deletions(-) create mode 100644 ports/esp32/boards/GENERIC_S3/board.md delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/board.json delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.h delete mode 100644 ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/GENERIC_S3/board.json index c30d4ed993..be2170c12f 100644 --- a/ports/esp32/boards/GENERIC_S3/board.json +++ b/ports/esp32/boards/GENERIC_S3/board.json @@ -6,6 +6,7 @@ "features": [ "BLE", "External Flash", + "External RAM", "WiFi" ], "images": [ @@ -15,5 +16,8 @@ "product": "ESP32-S3", "thumbnail": "", "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" + "vendor": "Espressif", + "variants": { + "spiram-oct": "Support for Octal-SPIRAM" + } } diff --git a/ports/esp32/boards/GENERIC_S3/board.md b/ports/esp32/boards/GENERIC_S3/board.md new file mode 100644 index 0000000000..cc902eeb89 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3/board.md @@ -0,0 +1,7 @@ +The following files are firmware that should work on most ESP32-S3-based +boards with 8MiB of flash, including WROOM and MINI modules. + +This firmware supports configurations with and without SPIRAM (also known as +PSRAM) and will auto-detect a connected SPIRAM chip at startup and allocate +the MicroPython heap accordingly. However if your board has Octal SPIRAM, then +use the "spiram-oct" variant. diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake index 3d83f89044..bd163f9f33 100644 --- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake @@ -4,5 +4,18 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.base boards/sdkconfig.usb boards/sdkconfig.ble + boards/sdkconfig.spiram_sx boards/GENERIC_S3/sdkconfig.board ) + +if(MICROPY_BOARD_VARIANT STREQUAL "spiram-oct") + set(SDKCONFIG_DEFAULTS + ${SDKCONFIG_DEFAULTS} + boards/sdkconfig.240mhz + boards/sdkconfig.spiram_oct + ) + + list(APPEND MICROPY_DEF_BOARD + MICROPY_HW_BOARD_NAME="Generic ESP32S3 module with Octal-SPIRAM" + ) +endif() diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h index b8f5fb2560..8d369c7db0 100644 --- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h +++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h @@ -1,4 +1,7 @@ -#define MICROPY_HW_BOARD_NAME "ESP32S3 module" +#ifndef MICROPY_HW_BOARD_NAME +// Can be set by mpconfigboard.cmake. +#define MICROPY_HW_BOARD_NAME "Generic ESP32S3 module" +#endif #define MICROPY_HW_MCU_NAME "ESP32S3" #define MICROPY_PY_MACHINE_DAC (0) diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json deleted file mode 100644 index 947787f3af..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "deploy": [ - "../deploy_s3.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "WiFi" - ], - "images": [ - "generic_s3.jpg" - ], - "mcu": "esp32s3", - "product": "Generic ESP32-S3 (SPIRAM)", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake deleted file mode 100644 index e0b92dcd26..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake +++ /dev/null @@ -1,9 +0,0 @@ -set(IDF_TARGET esp32s3) - -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.usb - boards/sdkconfig.ble - boards/sdkconfig.spiram_sx - boards/GENERIC_S3_SPIRAM/sdkconfig.board -) diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h deleted file mode 100644 index 1a8560a2d7..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h +++ /dev/null @@ -1,10 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP32S3 module (spiram)" -#define MICROPY_HW_MCU_NAME "ESP32S3" - -#define MICROPY_PY_MACHINE_DAC (0) - -// Enable UART REPL for modules that have an external USB-UART and don't use native USB. -#define MICROPY_HW_ENABLE_UART_REPL (1) - -#define MICROPY_HW_I2C0_SCL (9) -#define MICROPY_HW_I2C0_SDA (8) diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board b/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board deleted file mode 100644 index a36b971162..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y - -CONFIG_ESPTOOLPY_FLASHSIZE_4MB= -CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y -CONFIG_ESPTOOLPY_FLASHSIZE_16MB= -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv" diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json deleted file mode 100644 index 4cf15e888c..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "deploy": [ - "../deploy_s3.md" - ], - "docs": "", - "features": [ - "BLE", - "External Flash", - "WiFi" - ], - "images": [ - "generic_s3.jpg" - ], - "mcu": "esp32s3", - "product": "Generic ESP32-S3 (SPIRAM Octal)", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake deleted file mode 100644 index 7a767c49d4..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake +++ /dev/null @@ -1,11 +0,0 @@ -set(IDF_TARGET esp32s3) - -set(SDKCONFIG_DEFAULTS - boards/sdkconfig.base - boards/sdkconfig.usb - boards/sdkconfig.ble - boards/sdkconfig.240mhz - boards/sdkconfig.spiram_sx - boards/sdkconfig.spiram_oct - boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board -) diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.h deleted file mode 100644 index 88f6835c94..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.h +++ /dev/null @@ -1,10 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP32S3 module (spiram octal)" -#define MICROPY_HW_MCU_NAME "ESP32S3" - -#define MICROPY_PY_MACHINE_DAC (0) - -// Enable UART REPL for modules that have an external USB-UART and don't use native USB. -#define MICROPY_HW_ENABLE_UART_REPL (1) - -#define MICROPY_HW_I2C0_SCL (9) -#define MICROPY_HW_I2C0_SDA (8) diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board deleted file mode 100644 index a36b971162..0000000000 --- a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y - -CONFIG_ESPTOOLPY_FLASHSIZE_4MB= -CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y -CONFIG_ESPTOOLPY_FLASHSIZE_16MB= -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv" From 96258d371614c74ac2e4e9461ff6cb1ea0f97ced Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 16:04:19 +1000 Subject: [PATCH 033/121] esp32/partitions.csv: Rename to partitions-4MiB.csv. To be consistent with the other partitions files (which have the "- {2,8,16,32}MiB" suffix). Also renames partitions-ota.csv. Signed-off-by: Jim Mussared --- ports/esp32/boards/GENERIC/sdkconfig.ota | 2 +- ports/esp32/boards/sdkconfig.base | 2 +- ports/esp32/{partitions-ota.csv => partitions-4MiB-ota.csv} | 0 ports/esp32/{partitions.csv => partitions-4MiB.csv} | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename ports/esp32/{partitions-ota.csv => partitions-4MiB-ota.csv} (100%) rename ports/esp32/{partitions.csv => partitions-4MiB.csv} (100%) diff --git a/ports/esp32/boards/GENERIC/sdkconfig.ota b/ports/esp32/boards/GENERIC/sdkconfig.ota index 7ff939aa99..4a164aa6f8 100644 --- a/ports/esp32/boards/GENERIC/sdkconfig.ota +++ b/ports/esp32/boards/GENERIC/sdkconfig.ota @@ -1,6 +1,6 @@ CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-ota.csv" +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-4MiB-ota.csv" # Reduce firmware size to fit in the OTA partition. CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index b98d5d0678..7443b34aa7 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -67,7 +67,7 @@ CONFIG_ULP_COPROC_RESERVE_MEM=2040 # For cmake build CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-4MiB.csv" # To reduce iRAM usage CONFIG_ESP32_WIFI_IRAM_OPT=n diff --git a/ports/esp32/partitions-ota.csv b/ports/esp32/partitions-4MiB-ota.csv similarity index 100% rename from ports/esp32/partitions-ota.csv rename to ports/esp32/partitions-4MiB-ota.csv diff --git a/ports/esp32/partitions.csv b/ports/esp32/partitions-4MiB.csv similarity index 100% rename from ports/esp32/partitions.csv rename to ports/esp32/partitions-4MiB.csv From 91674c41b85b2d22ed263cebb46cc5d99c51c4df Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 25 Jul 2023 17:12:52 +1000 Subject: [PATCH 034/121] tools/autobuild: Automatically build all variants for each board. Removes the special-case for stm32. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- tools/autobuild/autobuild.sh | 1 - tools/autobuild/build-boards.sh | 76 ++++++++++++++++++---------- tools/autobuild/build-stm32-extra.sh | 39 -------------- 3 files changed, 50 insertions(+), 66 deletions(-) delete mode 100755 tools/autobuild/build-stm32-extra.sh diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh index b3c9c19c7c..999a42c0ed 100755 --- a/tools/autobuild/autobuild.sh +++ b/tools/autobuild/autobuild.sh @@ -77,7 +77,6 @@ cd ../samd build_samd_boards ${FW_TAG} ${LOCAL_FIRMWARE} cd ../stm32 build_stm32_boards ${FW_TAG} ${LOCAL_FIRMWARE} -${AUTODIR}/build-stm32-extra.sh ${FW_TAG} ${LOCAL_FIRMWARE} popd diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh index 689444a988..f75ccba398 100755 --- a/tools/autobuild/build-boards.sh +++ b/tools/autobuild/build-boards.sh @@ -3,8 +3,36 @@ # The functions in this file can be run independently to build boards. # For example: # -# $ source build-boards.sh -# $ MICROPY_AUTOBUILD_MAKE=make build_rp2_boards -latest /tmp +# $ source tools/autobuild/build-boards.sh +# $ cd ports/rp2 +# $ MICROPY_AUTOBUILD_MAKE="make -j8" build_rp2_boards -latest /tmp +# +# Or to build a single board: +# +# $ source tools/autobuild/build-boards.sh +# $ cd ports/rp2 +# $ MICROPY_AUTOBUILD_MAKE="make -j8" build_board boards/PICO/board.json -latest /tmp uf2 + +function copy_artefacts { + local dest_dir=$1 + local descr=$2 + local fw_tag=$3 + local build_dir=$4 + shift 4 + + for ext in $@; do + dest=$dest_dir/$descr$fw_tag.$ext + if [ -r $build_dir/firmware.$ext ]; then + mv $build_dir/firmware.$ext $dest + elif [ -r $build_dir/micropython.$ext ]; then + # esp32 has micropython.elf, etc + mv $build_dir/micropython.$ext $dest + elif [ $ext = app-bin -a -r $build_dir/micropython.bin ]; then + # esp32 has micropython.bin which is just the application + mv $build_dir/micropython.bin $dest + fi + done +} function build_board { # check/get parameters @@ -13,33 +41,29 @@ function build_board { return 1 fi - board_json=$1 - fw_tag=$2 - dest_dir=$3 - shift - shift - shift + local board_json=$1 + local fw_tag=$2 + local dest_dir=$3 + shift 3 - board=$(echo $board_json | awk -F '/' '{ print $2 }') - descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))") - build_dir=/tmp/micropython-build-$board + local board=$(echo $board_json | awk -F '/' '{ print $2 }') + local descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))") + # Build the "default" variant. For most boards this is the only thing we build. echo "building $descr $board" - $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && ( - for ext in $@; do - dest=$dest_dir/$descr$fw_tag.$ext - if [ -r $build_dir/firmware.$ext ]; then - mv $build_dir/firmware.$ext $dest - elif [ -r $build_dir/micropython.$ext ]; then - # esp32 has micropython.elf, etc - mv $build_dir/micropython.$ext $dest - elif [ $ext = app-bin -a -r $build_dir/micropython.bin ]; then - # esp32 has micropython.bin which is just the application - mv $build_dir/micropython.bin $dest - fi - done - ) + local build_dir=/tmp/micropython-build-$board + $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && copy_artefacts $dest_dir $descr $fw_tag $build_dir $@ rm -rf $build_dir + + # Query variants from board.json and build them. Ignore the special "idf3" + # variant for ESP32 boards (this allows the downloads page to still have + # the idf3 files for older releases that used to be explicitly built). + for variant in `cat $board_json | python3 -c "import json,sys; print(' '.join(v for v in json.load(sys.stdin).get('variants', {}).keys() if v != 'idf3'))"`; do + local variant_build_dir=$build_dir-$variant + echo "building variant $descr $board $variant" + $MICROPY_AUTOBUILD_MAKE BOARD=$board BOARD_VARIANT=$variant BUILD=$variant_build_dir && copy_artefacts $dest_dir $descr-$variant $fw_tag $variant_build_dir $@ + rm -rf $variant_build_dir + done } function build_boards { @@ -49,7 +73,7 @@ function build_boards { return 1 fi - check_file=$1 + local check_file=$1 shift # check we are in the correct directory diff --git a/tools/autobuild/build-stm32-extra.sh b/tools/autobuild/build-stm32-extra.sh deleted file mode 100755 index 887e3cd246..0000000000 --- a/tools/autobuild/build-stm32-extra.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# Build additional variants of pyboard firmware (base variants are built by build-boards.sh). - -# function for building firmware -function do_build() { - descr=$1 - board=$2 - shift - shift - for variant in `$MICROPY_AUTOBUILD_MAKE BOARD=$board query-variants | grep VARIANTS: | cut -d' ' -f2-`; do - target=$descr-$variant - echo "building $target $board" - build_dir=/tmp/stm-build-$board-$variant - $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BOARD_VARIANT=$variant BUILD=$build_dir || exit 1 - mv $build_dir/firmware.dfu $dest_dir/$target$fw_tag.dfu - mv $build_dir/firmware.hex $dest_dir/$target$fw_tag.hex - rm -rf $build_dir - done -} - -# check/get parameters -if [ $# != 2 ]; then - echo "usage: $0 " - exit 1 -fi - -fw_tag=$1 -dest_dir=$2 - -# check we are in the correct directory -if [ ! -r modpyb.c ]; then - echo "must be in stm directory" - exit 1 -fi - -# build the variants for each board -do_build pybv10 PYBV10 -do_build pybv11 PYBV11 -do_build pyblitev10 PYBLITEV10 From a9821c01852201426e9439d7a704e791add333ab Mon Sep 17 00:00:00 2001 From: robert-hh Date: Fri, 28 Jul 2023 22:29:32 +0200 Subject: [PATCH 035/121] mimxrt/machine_pin: Fix bug when Pin.irq is called without a handler. When called without a handler, the IRQ data was not cleared. That caused a crash at the second soft reset in a row. Signed-off-by: robert-hh --- ports/mimxrt/machine_pin.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c index f005e38d69..c66718e976 100644 --- a/ports/mimxrt/machine_pin.c +++ b/ports/mimxrt/machine_pin.c @@ -337,6 +337,13 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_ } machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[index]); + if (args[ARG_handler].u_obj == mp_const_none) { + // remove the IRQ from the table, leave it to gc to free it. + GPIO_PortDisableInterrupts(self->gpio, 1U << self->pin); + MP_STATE_PORT(machine_pin_irq_objects[index]) = NULL; + return mp_const_none; + } + // Allocate the IRQ object if it doesn't already exist. if (irq == NULL) { irq = m_new_obj(machine_pin_irq_obj_t); @@ -371,9 +378,9 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_ GPIO_PinSetInterruptConfig(self->gpio, self->pin, irq->trigger); // Enable the specific Pin interrupt GPIO_PortEnableInterrupts(self->gpio, 1U << self->pin); + // Enable LEVEL1 interrupt again + EnableIRQ(irq_num); } - // Enable LEVEL1 interrupt again - EnableIRQ(irq_num); } return MP_OBJ_FROM_PTR(irq); From a9a219d8bffe6843201d016e9dfb1d25c6a2eb3c Mon Sep 17 00:00:00 2001 From: robert-hh Date: Sat, 29 Jul 2023 13:30:43 +0200 Subject: [PATCH 036/121] mimxrt/hal/pwm_backport: Fix 0 and 65536 edge cases of PWM's duty_u16. It should be that: - duty_u16=0: output low, no pulse - duty_u16=65536: output high, no pulse That previously did not apply to all of the three PWM mechanisms of this port. This commit fixes it. Signed-off-by: robert-hh --- ports/mimxrt/hal/pwm_backport.c | 61 +++++++++++++++++++++------------ ports/mimxrt/hal/pwm_backport.h | 8 ++--- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/ports/mimxrt/hal/pwm_backport.c b/ports/mimxrt/hal/pwm_backport.c index 018f8f6279..7732e0e816 100644 --- a/ports/mimxrt/hal/pwm_backport.c +++ b/ports/mimxrt/hal/pwm_backport.c @@ -18,10 +18,10 @@ #include "hal/pwm_backport.h" void PWM_UpdatePwmDutycycle_u16( - PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t Center_u16) { + PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, uint32_t dutyCycle, uint16_t Center_u16) { assert((uint16_t)pwmSignal < 2U); - uint16_t pulseCnt = 0, pwmHighPulse = 0; - uint16_t center; + uint32_t pulseCnt = 0, pwmHighPulse = 0; + uint32_t center; // check and confine bounds for Center_u16 if ((Center_u16 + dutyCycle / 2) >= PWM_FULL_SCALE) { @@ -36,11 +36,21 @@ void PWM_UpdatePwmDutycycle_u16( // Setup the PWM dutycycle of channel A or B if (pwmSignal == kPWM_PwmA) { - base->SM[subModule].VAL2 = center - pwmHighPulse / 2; - base->SM[subModule].VAL3 = base->SM[subModule].VAL2 + pwmHighPulse; + if (dutyCycle >= 65536) { + base->SM[subModule].VAL2 = 0; + base->SM[subModule].VAL3 = pulseCnt; + } else { + base->SM[subModule].VAL2 = center - pwmHighPulse / 2; + base->SM[subModule].VAL3 = base->SM[subModule].VAL2 + pwmHighPulse; + } } else { - base->SM[subModule].VAL4 = center - pwmHighPulse / 2; - base->SM[subModule].VAL5 = base->SM[subModule].VAL4 + pwmHighPulse; + if (dutyCycle >= 65536) { + base->SM[subModule].VAL4 = 0; + base->SM[subModule].VAL5 = pulseCnt; + } else { + base->SM[subModule].VAL4 = center - pwmHighPulse / 2; + base->SM[subModule].VAL5 = base->SM[subModule].VAL4 + pwmHighPulse; + } } } @@ -86,33 +96,33 @@ void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_para } void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule, - uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz) { + uint32_t pwmFreq_Hz, uint32_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz) { uint32_t pulseCnt; uint32_t pwmClock; // Divide the clock by the prescale value pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT))); - pulseCnt = (pwmClock + (pwmFreq_Hz - 1) / 2) / pwmFreq_Hz; + pulseCnt = (pwmClock + (pwmFreq_Hz - 1) / 2) / pwmFreq_Hz - 1; base->SM[subModule].INIT = 0; - base->SM[subModule].VAL0 = ((uint32_t)duty_cycle * pulseCnt) / PWM_FULL_SCALE - 1; - base->SM[subModule].VAL1 = pulseCnt - 1; + base->SM[subModule].VAL0 = ((uint32_t)duty_cycle * pulseCnt) / PWM_FULL_SCALE; + base->SM[subModule].VAL1 = pulseCnt; base->SM[subModule].OCTRL = (base->SM[subModule].OCTRL & ~PWM_OCTRL_POLX_MASK) | PWM_OCTRL_POLX(!invert); - base->OUTEN |= (1U << subModule); + // Switch the output on or off. + if (duty_cycle == 0) { + base->OUTEN &= ~(1U << subModule); + } else { + base->OUTEN |= (1U << subModule); + } } #ifdef FSL_FEATURE_SOC_TMR_COUNT status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz, - uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init) { + uint32_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init) { uint32_t periodCount, highCount, lowCount, reg; - if (dutyCycleU16 >= PWM_FULL_SCALE) { - // Invalid dutycycle - return kStatus_Fail; - } - // Counter values to generate a PWM signal periodCount = ((srcClock_Hz + (pwmFreqHz - 1) / 2) / pwmFreqHz) - 2; highCount = (periodCount * dutyCycleU16) / PWM_FULL_SCALE; @@ -147,11 +157,18 @@ status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uin reg = base->CHANNEL[channel].CTRL; reg &= ~(TMR_CTRL_OUTMODE_MASK); - // Count until compare value is reached and re-initialize the counter, toggle OFLAG output - // using alternating compare register - reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg)); + if (dutyCycleU16 == 0) { + // Clear the output at the next compare + reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ClearOnCompare)); + } else if (dutyCycleU16 >= 65536) { + // Set the output at the next compare + reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_SetOnCompare)); + } else { + // Count until compare value is reached and re-initialize the counter, toggle OFLAG output + // using alternating compare register + reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg)); + } base->CHANNEL[channel].CTRL = reg; - return kStatus_Success; } #endif // FSL_FEATURE_SOC_TMR_COUNT diff --git a/ports/mimxrt/hal/pwm_backport.h b/ports/mimxrt/hal/pwm_backport.h index 516726961c..04899173e2 100644 --- a/ports/mimxrt/hal/pwm_backport.h +++ b/ports/mimxrt/hal/pwm_backport.h @@ -18,7 +18,7 @@ typedef struct _pwm_signal_param_u16 { pwm_channels_t pwmChannel; // PWM channel being configured; PWM A or PWM B - uint16_t dutyCycle_u16; // PWM pulse width, value should be between 0 to 65536 + uint32_t dutyCycle_u16; // PWM pulse width, value should be between 0 to 65536 uint16_t Center_u16; // Center of the pulse, value should be between 0 to 65536 pwm_level_select_t level; // PWM output active level select */ uint16_t deadtimeValue; // The deadtime value; only used if channel pair is operating in complementary mode @@ -27,17 +27,17 @@ typedef struct _pwm_signal_param_u16 #define PWM_FULL_SCALE (65536UL) void PWM_UpdatePwmDutycycle_u16(PWM_Type *base, pwm_submodule_t subModule, - pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t center); + pwm_channels_t pwmSignal, uint32_t dutyCycle, uint16_t center); void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_param_u16_t *chnlParams, uint32_t pwmFreq_Hz, uint32_t srcClock_Hz, bool output_enable); void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule, - uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz); + uint32_t pwmFreq_Hz, uint32_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz); #ifdef FSL_FEATURE_SOC_TMR_COUNT status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz, - uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init); + uint32_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init); #endif // FSL_FEATURE_SOC_TMR_COUNT #endif // PWM_BACKPORT_H From e43c669b4aec1fc43188ac38a8dce6825dcdf346 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Thu, 10 Aug 2023 17:15:47 +0200 Subject: [PATCH 037/121] mimxrt/machine_uart: Add uart.deinit method and machine_uart_deinit_all. The call to machine_uart_deinit_all() is needed to avoid a crash after soft reset, if a UART had been used and data arrives before it is instantiated again. Signed-off-by: robert-hh --- ports/mimxrt/machine_uart.c | 18 ++++++++++++++++++ ports/mimxrt/main.c | 1 + ports/mimxrt/modmachine.h | 1 + 3 files changed, 20 insertions(+) diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c index ac9351da8a..d0563232e2 100644 --- a/ports/mimxrt/machine_uart.c +++ b/ports/mimxrt/machine_uart.c @@ -288,6 +288,14 @@ STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t } MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init); +// uart.deinit() +STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + LPUART_Deinit(self->lpuart); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit); + STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); size_t count = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle); @@ -314,8 +322,18 @@ STATIC mp_obj_t machine_uart_txdone(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone); +// Deinitialize all defined UARTs +void machine_uart_deinit_all(void) { + for (int i = 0; i < sizeof(uart_index_table); i++) { + if (uart_index_table[i] != 0) { + LPUART_Deinit(uart_base_ptr_table[uart_index_table[i]]); + } + } +} + STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_uart_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) }, diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 9ac46e4814..2d0760964c 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -124,6 +124,7 @@ int main(void) { #if MICROPY_PY_NETWORK mod_network_deinit(); #endif + machine_uart_deinit_all(); machine_pwm_deinit_all(); soft_timer_deinit(); gc_sweep_all(); diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h index ed1c4e34a0..1f669af09e 100644 --- a/ports/mimxrt/modmachine.h +++ b/ports/mimxrt/modmachine.h @@ -43,6 +43,7 @@ extern const mp_obj_type_t machine_wdt_type; void machine_adc_init(void); void machine_pin_irq_deinit(void); void machine_pwm_deinit_all(void); +void machine_uart_deinit_all(void); void machine_timer_init_PIT(void); void machine_sdcard_init0(void); void mimxrt_sdram_init(void); From afe2ca1a0af0fea2f8033eb900626725e30cf40c Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sun, 30 Jul 2023 17:01:59 -0700 Subject: [PATCH 038/121] mimxrt/machine_uart: Add support for UART hardware flow control. Signed-off-by: "Kwabena W. Agyeman" --- .../boards/MIMXRT1010_EVK/mpconfigboard.h | 6 ++ .../boards/MIMXRT1015_EVK/mpconfigboard.h | 6 ++ .../boards/MIMXRT1020_EVK/mpconfigboard.h | 10 +++ .../boards/MIMXRT1050_EVK/mpconfigboard.h | 10 +++ .../boards/MIMXRT1060_EVK/mpconfigboard.h | 10 +++ .../boards/MIMXRT1064_EVK/mpconfigboard.h | 10 +++ .../boards/MIMXRT1170_EVK/mpconfigboard.h | 14 ++++ .../boards/OLIMEX_RT1010/mpconfigboard.h | 6 ++ .../boards/SEEED_ARCH_MIX/mpconfigboard.h | 10 +++ ports/mimxrt/boards/TEENSY40/mpconfigboard.h | 10 +++ ports/mimxrt/boards/TEENSY41/mpconfigboard.h | 10 +++ ports/mimxrt/machine_uart.c | 67 ++++++++++++++++++- 12 files changed, 167 insertions(+), 2 deletions(-) diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h index eff9e9c2cd..26811fdab8 100644 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h @@ -23,6 +23,12 @@ { IOMUXC_GPIO_08_LPUART3_TXD }, { IOMUXC_GPIO_AD_07_LPUART3_RXD }, \ { IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_08_LPUART1_CTS_B }, { IOMUXC_GPIO_07_LPUART1_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_14_LPUART4_CTS_B }, { IOMUXC_GPIO_AD_13_LPUART4_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 1 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h index f37ba824f4..655bb62c27 100644 --- a/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h @@ -28,6 +28,12 @@ { IOMUXC_GPIO_AD_B0_14_LPUART3_TX }, { IOMUXC_GPIO_AD_B0_15_LPUART3_RX }, \ { IOMUXC_GPIO_EMC_32_LPUART4_TX }, { IOMUXC_GPIO_EMC_33_LPUART4_RX }, \ +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_08_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_09_LPUART1_RTS_B }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B0_12_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B0_13_LPUART3_RTS_B }, \ + { 0 }, { 0 }, + #define MICROPY_HW_SPI_INDEX { 1 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h index 390e91814d..8b7316c8da 100644 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h @@ -34,6 +34,16 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_SD_B1_02_LPUART8_TX }, { IOMUXC_GPIO_SD_B1_03_LPUART8_RX }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_08_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_09_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_06_LPUART2_CTS_B }, { IOMUXC_GPIO_AD_B1_07_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_AD_B0_12_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B0_13_LPUART3_RTS_B }, \ + { IOMUXC_GPIO_EMC_00_LPUART4_CTS_B }, { IOMUXC_GPIO_EMC_01_LPUART4_RTS_B }, \ + { IOMUXC_GPIO_EMC_36_LPUART5_CTS_B }, { IOMUXC_GPIO_EMC_37_LPUART5_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_EMC_24_LPUART8_CTS_B }, { IOMUXC_GPIO_EMC_25_LPUART8_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 1, 3 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h index 134c9637ea..74666562a8 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h @@ -30,6 +30,16 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B }, { IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_04_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B1_05_LPUART3_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_EMC_30_LPUART6_CTS_B }, { IOMUXC_GPIO_EMC_29_LPUART6_RTS_B }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_SD_B0_02_LPUART8_CTS_B }, { IOMUXC_GPIO_SD_B0_03_LPUART8_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 1 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h index 01ae3ba303..824f9977c2 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h @@ -30,6 +30,16 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B }, { IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_04_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B1_05_LPUART3_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_EMC_30_LPUART6_CTS_B }, { IOMUXC_GPIO_EMC_29_LPUART6_RTS_B }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_SD_B0_02_LPUART8_CTS_B }, { IOMUXC_GPIO_SD_B0_03_LPUART8_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 1 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h index b6752c3e1b..cb64d2b9d2 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h @@ -30,6 +30,16 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B }, { IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_04_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B1_05_LPUART3_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_EMC_30_LPUART6_CTS_B }, { IOMUXC_GPIO_EMC_29_LPUART6_RTS_B }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_SD_B0_02_LPUART8_CTS_B }, { IOMUXC_GPIO_SD_B0_03_LPUART8_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 1 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h index d37050eb56..8ce91adbaf 100644 --- a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h @@ -43,6 +43,20 @@ { IOMUXC_GPIO_LPSR_04_LPUART11_TXD }, { IOMUXC_GPIO_LPSR_05_LPUART11_RXD }, \ { IOMUXC_GPIO_LPSR_10_LPUART12_TXD }, { IOMUXC_GPIO_LPSR_11_LPUART12_RXD }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_26_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_27_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_DISP_B2_12_LPUART2_CTS_B }, { IOMUXC_GPIO_DISP_B2_13_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_SD_B2_07_LPUART3_CTS_B }, { IOMUXC_GPIO_SD_B2_08_LPUART3_RTS_B }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_SD_B2_09_LPUART5_CTS_B }, { IOMUXC_GPIO_SD_B2_10_LPUART5_RTS_B }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_02_LPUART7_CTS_B }, { IOMUXC_GPIO_AD_03_LPUART7_RTS_B }, \ + { IOMUXC_GPIO_AD_04_LPUART8_CTS_B }, { IOMUXC_GPIO_AD_05_LPUART8_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_LPSR_10_LPUART11_CTS_B }, { IOMUXC_GPIO_LPSR_11_LPUART11_RTS_B }, \ + { IOMUXC_GPIO_LPSR_05_LPUART12_CTS_B }, { IOMUXC_GPIO_LPSR_04_LPUART12_RTS_B }, + // Define the mapping hardware SPI # to logical SPI # // SCK/CS/SDO/SDI HW-SPI Logical SPI // D13/D10/D11/D12 LPSPI1 -> 0 diff --git a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h index 3d080ff25f..828855d4d3 100644 --- a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h +++ b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h @@ -25,6 +25,12 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_06_LPUART4_TXD }, { IOMUXC_GPIO_05_LPUART4_RXD }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_EMC_17_LPUART4_CTS_B }, { IOMUXC_GPIO_EMC_18_LPUART4_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 0, 1, 2 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h index c98cdcb0a7..edda72f266 100644 --- a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h @@ -32,6 +32,16 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B }, { IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_04_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B1_05_LPUART3_RTS_B }, \ + { IOMUXC_GPIO_EMC_17_LPUART4_CTS_B }, { IOMUXC_GPIO_EMC_18_LPUART4_RTS_B }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_SD_B0_02_LPUART8_CTS_B }, { IOMUXC_GPIO_SD_B0_03_LPUART8_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 3, 4 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h index 07da87db10..1a6227a60e 100644 --- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h @@ -22,6 +22,16 @@ { IOMUXC_GPIO_EMC_31_LPUART7_TX }, { IOMUXC_GPIO_EMC_32_LPUART7_RX }, \ { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B }, { IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_04_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B1_05_LPUART3_RTS_B }, \ + { IOMUXC_GPIO_EMC_17_LPUART4_CTS_B }, { IOMUXC_GPIO_EMC_18_LPUART4_RTS_B }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_EMC_30_LPUART6_CTS_B }, { IOMUXC_GPIO_EMC_29_LPUART6_RTS_B }, \ + { IOMUXC_GPIO_SD_B1_06_LPUART7_CTS_B }, { IOMUXC_GPIO_SD_B1_07_LPUART7_RTS_B }, \ + { IOMUXC_GPIO_SD_B0_02_LPUART8_CTS_B }, { IOMUXC_GPIO_SD_B0_03_LPUART8_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 4, 3} #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h index 56740f48ea..09addbe52c 100644 --- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h @@ -24,6 +24,16 @@ { IOMUXC_GPIO_EMC_31_LPUART7_TX }, { IOMUXC_GPIO_EMC_32_LPUART7_RX }, \ { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B }, { IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B }, \ + { IOMUXC_GPIO_AD_B1_04_LPUART3_CTS_B }, { IOMUXC_GPIO_AD_B1_05_LPUART3_RTS_B }, \ + { IOMUXC_GPIO_EMC_17_LPUART4_CTS_B }, { IOMUXC_GPIO_EMC_18_LPUART4_RTS_B }, \ + { IOMUXC_GPIO_EMC_28_LPUART5_CTS_B }, { IOMUXC_GPIO_EMC_27_LPUART5_RTS_B }, \ + { IOMUXC_GPIO_EMC_30_LPUART6_CTS_B }, { IOMUXC_GPIO_EMC_29_LPUART6_RTS_B }, \ + { IOMUXC_GPIO_SD_B1_06_LPUART7_CTS_B }, { IOMUXC_GPIO_SD_B1_07_LPUART7_RTS_B }, \ + { IOMUXC_GPIO_SD_B0_02_LPUART8_CTS_B }, { IOMUXC_GPIO_SD_B0_03_LPUART8_RTS_B }, + #define MICROPY_HW_SPI_INDEX { 4, 3, 1 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c index d0563232e2..17d789886c 100644 --- a/ports/mimxrt/machine_uart.c +++ b/ports/mimxrt/machine_uart.c @@ -40,6 +40,10 @@ #define MIN_BUFFER_SIZE (32) #define MAX_BUFFER_SIZE (32766) +#define UART_HWCONTROL_RTS (1) +#define UART_HWCONTROL_CTS (2) +#define UART_HWCONTROL_MASK (UART_HWCONTROL_RTS | UART_HWCONTROL_CTS) + #define UART_INVERT_TX (1) #define UART_INVERT_RX (2) #define UART_INVERT_MASK (UART_INVERT_TX | UART_INVERT_RX) @@ -74,12 +78,18 @@ STATIC LPUART_Type *uart_base_ptr_table[] = LPUART_BASE_PTRS; static const iomux_table_t iomux_table_uart[] = { IOMUX_TABLE_UART }; +static const iomux_table_t iomux_table_uart_cts_rts[] = { + IOMUX_TABLE_UART_CTS_RTS +}; STATIC const char *_parity_name[] = {"None", "", "0", "1"}; // Is defined as 0, 2, 3 STATIC const char *_invert_name[] = {"None", "INV_TX", "INV_RX", "INV_TX|INV_RX"}; +STATIC const char *_flow_name[] = {"None", "RTS", "CTS", "RTS|CTS"}; #define RX (iomux_table_uart[index + 1]) #define TX (iomux_table_uart[index]) +#define RTS (iomux_table_uart_cts_rts[index + 1]) +#define CTS (iomux_table_uart_cts_rts[index]) bool lpuart_set_iomux(int8_t uart) { int index = (uart - 1) * 2; @@ -98,6 +108,33 @@ bool lpuart_set_iomux(int8_t uart) { } } +bool lpuart_set_iomux_rts(int8_t uart) { + MP_STATIC_ASSERT(MP_ARRAY_SIZE(iomux_table_uart) == MP_ARRAY_SIZE(iomux_table_uart_cts_rts)); + int index = (uart - 1) * 2; + + if (RTS.muxRegister != 0) { + IOMUXC_SetPinMux(RTS.muxRegister, RTS.muxMode, RTS.inputRegister, RTS.inputDaisy, RTS.configRegister, 0U); + IOMUXC_SetPinConfig(RTS.muxRegister, RTS.muxMode, RTS.inputRegister, RTS.inputDaisy, RTS.configRegister, + pin_generate_config(PIN_PULL_UP_100K, PIN_MODE_OUT, PIN_DRIVE_6, RTS.configRegister)); + return true; + } else { + return false; + } +} + +bool lpuart_set_iomux_cts(int8_t uart) { + int index = (uart - 1) * 2; + + if (CTS.muxRegister != 0) { + IOMUXC_SetPinMux(CTS.muxRegister, CTS.muxMode, CTS.inputRegister, CTS.inputDaisy, CTS.configRegister, 0U); + IOMUXC_SetPinConfig(CTS.muxRegister, CTS.muxMode, CTS.inputRegister, CTS.inputDaisy, CTS.configRegister, + pin_generate_config(PIN_PULL_UP_100K, PIN_MODE_IN, PIN_DRIVE_6, CTS.configRegister)); + return true; + } else { + return false; + } +} + void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t status, void *userData) { machine_uart_obj_t *self = userData; if (kStatus_LPUART_TxIdle == status) { @@ -111,22 +148,24 @@ void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t st STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, " + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, flow=%s, " "rxbuf=%d, txbuf=%d, timeout=%u, timeout_char=%u, invert=%s)", self->id, self->config.baudRate_Bps, 8 - self->config.dataBitsCount, _parity_name[self->config.parityMode], self->config.stopBitCount + 1, + _flow_name[(self->config.enableTxCTS << 1) | self->config.enableRxRTS], self->handle.rxRingBufferSize, self->txbuf_len, self->timeout, self->timeout_char, _invert_name[self->invert]); } STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_flow, ARG_timeout, ARG_timeout_char, ARG_invert, ARG_rxbuf, ARG_txbuf}; static const mp_arg_t allowed_args[] = { { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_bits, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_parity, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} }, { MP_QSTR_stop, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 } }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, @@ -164,6 +203,27 @@ STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args self->config.stopBitCount = args[ARG_stop].u_int - 1; } + // Set flow if configured. + if (args[ARG_flow].u_int >= 0) { + if (args[ARG_flow].u_int & ~UART_HWCONTROL_MASK) { + mp_raise_ValueError(MP_ERROR_TEXT("bad flow mask")); + } + + if (args[ARG_flow].u_int & UART_HWCONTROL_RTS) { + if (!lpuart_set_iomux_rts(uart_index_table[self->id])) { + mp_raise_ValueError(MP_ERROR_TEXT("rts not available")); + } + self->config.enableRxRTS = true; + } + + if (args[ARG_flow].u_int & UART_HWCONTROL_CTS) { + if (!lpuart_set_iomux_cts(uart_index_table[self->id])) { + mp_raise_ValueError(MP_ERROR_TEXT("cts not available")); + } + self->config.enableTxCTS = true; + } + } + // Set timeout if configured. if (args[ARG_timeout].u_int >= 0) { self->timeout = args[ARG_timeout].u_int; @@ -346,6 +406,9 @@ STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) }, { MP_ROM_QSTR(MP_QSTR_txdone), MP_ROM_PTR(&machine_uart_txdone_obj) }, + { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, + { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, + { MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INVERT_TX) }, { MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERT_RX) }, From cb7e133dbe0e13333534a21fc11bbf6a800ac4a2 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Tue, 25 Jul 2023 18:20:37 -0700 Subject: [PATCH 039/121] mimxrt/boards: Add support for GPIO control of SNVS pins. Signed-off-by: "Kwabena W. Agyeman" --- ports/mimxrt/boards/MIMXRT1062_af.csv | 3 ++ ports/mimxrt/boards/MIMXRT1176_af.csv | 20 ++++++------- ports/mimxrt/boards/make-pins.py | 42 ++++++++++++++++++++++++--- ports/mimxrt/boards/mimxrt_prefix.c | 14 +++++++++ 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/ports/mimxrt/boards/MIMXRT1062_af.csv b/ports/mimxrt/boards/MIMXRT1062_af.csv index 9b83efeddc..d2f0b22023 100644 --- a/ports/mimxrt/boards/MIMXRT1062_af.csv +++ b/ports/mimxrt/boards/MIMXRT1062_af.csv @@ -123,3 +123,6 @@ GPIO_SD_B1_08,USDHC2_DATA4,FLEXSPI_A_DATA0,LPUART7_TXD,SAI1_TX_BCLK,LPSPI2_SOUT, GPIO_SD_B1_09,USDHC2_DATA5,FLEXSPI_A_DATA1,LPUART7_RXD,SAI1_TX_SYNC,LPSPI2_SIN,GPIO3_IO09,,,,,,,ALT5 GPIO_SD_B1_10,USDHC2_DATA6,FLEXSPI_A_DATA2,LPUART2_RXD,LPI2C2_SDA,LPSPI2_PCS2,GPIO3_IO10,,,,,,,ALT5 GPIO_SD_B1_11,USDHC2_DATA7,FLEXSPI_A_DATA3,LPUART2_TXD,LPI2C2_SCL,LPSPI2_PCS3,GPIO3_IO11,,,,,,,ALT5 +WAKEUP,,,,,,GPIO5_IO00,,NMI,,,,,ALT5 +PMIC_ON_REQ,SNVS_PMIC_ON_REQ,,,,,GPIO5_IO01,,,,,,,ALT0 +PMIC_STBY_REQ,CCM_PMIC_STBY_REQ,,,,,GPIO5_IO02,,,,,,,ALT0 diff --git a/ports/mimxrt/boards/MIMXRT1176_af.csv b/ports/mimxrt/boards/MIMXRT1176_af.csv index fe31f502e4..21fd2a2417 100644 --- a/ports/mimxrt/boards/MIMXRT1176_af.csv +++ b/ports/mimxrt/boards/MIMXRT1176_af.csv @@ -80,16 +80,16 @@ GPIO_EMC_B2_17,SEMC_DM03,XBAR1_INOUT15,ENET_1G_RX_EN,SAI3_MCLK,FLEXSPI2_A_DATA04 GPIO_EMC_B2_18,SEMC_DQS4,XBAR1_INOUT16,ENET_1G_RX_ER,EWM_OUT_B,FLEXSPI2_A_DATA05,GPIO2_IO28,FLEXSPI1_A_DQS,,WDOG1_B,TMR3_TIMER1,GPIO8_IO28,,, GPIO_EMC_B2_19,SEMC_CLKX00,ENET_MDC,ENET_1G_MDC,ENET_1G_REF_CLK,FLEXSPI2_A_DATA06,GPIO2_IO29,,,ENET_QOS_MDC,TMR3_TIMER2,GPIO8_IO29,,, GPIO_EMC_B2_20,SEMC_CLKX01,ENET_MDIO,ENET_1G_MDIO,ENET_QOS_REF_CLK,FLEXSPI2_A_DATA07,GPIO2_IO30,,,ENET_QOS_MDIO,TMR3_TIMER3,GPIO8_IO30,,, -GPIO_SNVS_00,SNVS_TAMPER0,,,,,GPIO13_IO03,,,,,,,, -GPIO_SNVS_01,SNVS_TAMPER1,,,,,GPIO13_IO04,,,,,,,, -GPIO_SNVS_02,SNVS_TAMPER2,,,,,GPIO13_IO05,,,,,,,, -GPIO_SNVS_03,SNVS_TAMPER3,,,,,GPIO13_IO06,,,,,,,, -GPIO_SNVS_04,SNVS_TAMPER4,,,,,GPIO13_IO07,,,,,,,, -GPIO_SNVS_05,SNVS_TAMPER5,,,,,GPIO13_IO08,,,,,,,, -GPIO_SNVS_06,SNVS_TAMPER6,,,,,GPIO13_IO09,,,,,,,, -GPIO_SNVS_07,SNVS_TAMPER7,,,,,GPIO13_IO10,,,,,,,, -GPIO_SNVS_08,SNVS_TAMPER8,,,,,GPIO13_IO11,,,,,,,, -GPIO_SNVS_09,SNVS_TAMPER9,,,,,GPIO13_IO12,,,,,,,, +GPIO_SNVS_00_DIG,SNVS_TAMPER0,,,,,GPIO13_IO03,,,,,,,, +GPIO_SNVS_01_DIG,SNVS_TAMPER1,,,,,GPIO13_IO04,,,,,,,, +GPIO_SNVS_02_DIG,SNVS_TAMPER2,,,,,GPIO13_IO05,,,,,,,, +GPIO_SNVS_03_DIG,SNVS_TAMPER3,,,,,GPIO13_IO06,,,,,,,, +GPIO_SNVS_04_DIG,SNVS_TAMPER4,,,,,GPIO13_IO07,,,,,,,, +GPIO_SNVS_05_DIG,SNVS_TAMPER5,,,,,GPIO13_IO08,,,,,,,, +GPIO_SNVS_06_DIG,SNVS_TAMPER6,,,,,GPIO13_IO09,,,,,,,, +GPIO_SNVS_07_DIG,SNVS_TAMPER7,,,,,GPIO13_IO10,,,,,,,, +GPIO_SNVS_08_DIG,SNVS_TAMPER8,,,,,GPIO13_IO11,,,,,,,, +GPIO_SNVS_09_DIG,SNVS_TAMPER9,,,,,GPIO13_IO12,,,,,,,, GPIO_LPSR_00,FLEXCAN3_TX,MIC_CLK,MQS_RIGHT,ARM_CM4_EVENTO,,GPIO6_IO00,LPUART12_TXD,SAI4_MCLK,,,GPIO12_IO00,,, GPIO_LPSR_01,FLEXCAN3_RX,MIC_BITSTREAM0,MQS_LEFT,ARM_CM4_EVENTI,,GPIO6_IO01,LPUART12_RXD,,,,GPIO12_IO01,,, GPIO_LPSR_02,SRC_BOOT_MODE00,LPSPI5_SCK,SAI4_TX_DATA,MQS_RIGHT,,GPIO6_IO02,,,,,GPIO12_IO02,,, diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py index 429d648696..51ae9eb717 100644 --- a/ports/mimxrt/boards/make-pins.py +++ b/ports/mimxrt/boards/make-pins.py @@ -24,6 +24,10 @@ regexes = [ r"IOMUXC_(?PGPIO_EMC_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_DISP_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_LPSR_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_[SNVS_]*(?PWAKEUP[_DIG]*)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_SNVS_(?PPMIC_ON_REQ)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_SNVS_(?PPMIC_STBY_REQ)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_SNVS_\d\d_DIG)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", ] @@ -118,10 +122,43 @@ class Pin(object): self.print_pin_af() self.print_pin_adc() + options = { + "GPIO_LPSR_00": "PIN_LPSR", + "GPIO_LPSR_01": "PIN_LPSR", + "GPIO_LPSR_02": "PIN_LPSR", + "GPIO_LPSR_03": "PIN_LPSR", + "GPIO_LPSR_04": "PIN_LPSR", + "GPIO_LPSR_05": "PIN_LPSR", + "GPIO_LPSR_06": "PIN_LPSR", + "GPIO_LPSR_07": "PIN_LPSR", + "GPIO_LPSR_08": "PIN_LPSR", + "GPIO_LPSR_09": "PIN_LPSR", + "GPIO_LPSR_10": "PIN_LPSR", + "GPIO_LPSR_11": "PIN_LPSR", + "GPIO_LPSR_12": "PIN_LPSR", + "GPIO_LPSR_13": "PIN_LPSR", + "GPIO_LPSR_14": "PIN_LPSR", + "GPIO_LPSR_15": "PIN_LPSR", + "GPIO_SNVS_00_DIG": "PIN_SNVS", + "GPIO_SNVS_01_DIG": "PIN_SNVS", + "GPIO_SNVS_02_DIG": "PIN_SNVS", + "GPIO_SNVS_03_DIG": "PIN_SNVS", + "GPIO_SNVS_04_DIG": "PIN_SNVS", + "GPIO_SNVS_05_DIG": "PIN_SNVS", + "GPIO_SNVS_06_DIG": "PIN_SNVS", + "GPIO_SNVS_07_DIG": "PIN_SNVS", + "GPIO_SNVS_08_DIG": "PIN_SNVS", + "GPIO_SNVS_09_DIG": "PIN_SNVS", + "WAKEUP": "PIN_SNVS", + "WAKEUP_DIG": "PIN_SNVS", + "PMIC_ON_REQ": "PIN_SNVS", + "PMIC_STBY_REQ": "PIN_SNVS", + } + print( "const machine_pin_obj_t pin_{0} = {1}({0}, {2}, {3}, pin_{0}_af, {4}, {5});\n".format( self.name, - "PIN_LPSR" if "LPSR" in self.name else "PIN", + options.get(self.name, "PIN"), self.gpio, int(self.pin), len(self.adc_fns), @@ -233,9 +270,6 @@ class Pins(object): pin_number = pin.lstrip("IO") pin = Pin(pad, gpio, pin_number, idx=idx) - if any(s in pad for s in ("SNVS", "WAKEUP")): - continue - # Parse alternate functions af_idx = 0 for af_idx, af in enumerate(row[(pad_col + 1) : adc_col]): diff --git a/ports/mimxrt/boards/mimxrt_prefix.c b/ports/mimxrt/boards/mimxrt_prefix.c index 09c0aa109e..d7a2bcfc80 100644 --- a/ports/mimxrt/boards/mimxrt_prefix.c +++ b/ports/mimxrt/boards/mimxrt_prefix.c @@ -49,3 +49,17 @@ .adc_list = (_adc_list), \ } \ +#define PIN_SNVS(_name, _gpio, _pin, _af_list, _adc_list_len, _adc_list) \ + { \ + .base = { &machine_pin_type }, \ + .name = MP_QSTR_##_name, \ + .gpio = (_gpio), \ + .pin = (uint32_t)(_pin), \ + .muxRegister = (uint32_t)&(IOMUXC_SNVS->SW_MUX_CTL_PAD_##_name), \ + .configRegister = (uint32_t)&(IOMUXC_SNVS->SW_PAD_CTL_PAD_##_name), \ + .af_list_len = (uint8_t)(sizeof((_af_list)) / sizeof(machine_pin_af_obj_t)), \ + .adc_list_len = (_adc_list_len), \ + .af_list = (_af_list), \ + .adc_list = (_adc_list), \ + } \ + From 00855eeb36acaf626f153d8c1850ca75744b1c55 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Thu, 3 Aug 2023 17:55:27 -0700 Subject: [PATCH 040/121] mimxrt/hal: Make flash clock frequency configurable. Signed-off-by: "Kwabena W. Agyeman" --- ports/mimxrt/Makefile | 4 ++++ ports/mimxrt/hal/qspi_hyper_flash_config.c | 6 +++++- ports/mimxrt/hal/qspi_nor_flash_config.c | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 63cba7d7a6..8cb46245ae 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -397,6 +397,10 @@ CFLAGS += \ -DFSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE=1 endif +ifdef MICROPY_HW_FLASH_CLK + CFLAGS += -DMICROPY_HW_FLASH_CLK=$(MICROPY_HW_FLASH_CLK) +endif + CFLAGS += $(CFLAGS_EXTRA) MPY_CROSS_FLAGS += -march=armv7m diff --git a/ports/mimxrt/hal/qspi_hyper_flash_config.c b/ports/mimxrt/hal/qspi_hyper_flash_config.c index f5ffbe8413..aaf2e923c1 100644 --- a/ports/mimxrt/hal/qspi_hyper_flash_config.c +++ b/ports/mimxrt/hal/qspi_hyper_flash_config.c @@ -22,6 +22,10 @@ __attribute__((section(".boot_hdr.conf"))) #pragma location = ".boot_hdr.conf" #endif +#ifndef MICROPY_HW_FLASH_CLK +#define MICROPY_HW_FLASH_CLK kFlexSpiSerialClk_133MHz +#endif + const flexspi_nor_config_t qspiflash_config = { .memConfig = { @@ -36,7 +40,7 @@ const flexspi_nor_config_t qspiflash_config = { (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) | (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable), .sflashPadType = kSerialFlash_8Pads, - .serialClkFreq = kFlexSpiSerialClk_133MHz, + .serialClkFreq = MICROPY_HW_FLASH_CLK, .sflashA1Size = MICROPY_HW_FLASH_SIZE, .dataValidTime = {16u, 16u}, .lookupTable = diff --git a/ports/mimxrt/hal/qspi_nor_flash_config.c b/ports/mimxrt/hal/qspi_nor_flash_config.c index a6bbd624ed..a8040737e5 100644 --- a/ports/mimxrt/hal/qspi_nor_flash_config.c +++ b/ports/mimxrt/hal/qspi_nor_flash_config.c @@ -28,6 +28,10 @@ __attribute__((section(".boot_hdr.conf"))) #define MICROPY_HW_FLASH_DQS kFlexSPIReadSampleClk_LoopbackFromDqsPad #endif +#ifndef MICROPY_HW_FLASH_CLK +#define MICROPY_HW_FLASH_CLK kFlexSpiSerialClk_100MHz +#endif + const flexspi_nor_config_t qspiflash_config = { .memConfig = { @@ -48,7 +52,7 @@ const flexspi_nor_config_t qspiflash_config = { // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock .deviceType = kFlexSpiDeviceType_SerialNOR, .sflashPadType = kSerialFlash_4Pads, - .serialClkFreq = kFlexSpiSerialClk_100MHz, + .serialClkFreq = MICROPY_HW_FLASH_CLK, .sflashA1Size = MICROPY_HW_FLASH_SIZE, .lookupTable = { From 861fbf6ab5bb0c2a21a04a312453bb7adb92b8be Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 18:14:33 +1000 Subject: [PATCH 041/121] examples: Mark asm, pio, etc. as noqa: F821 (undefined-name). These files all use decorators (@asm_thumb, @asm_pio) that add names to the function scope, that the linter cannot see. It's useful to clear them in the file not in pyproject.toml as example code will be copied and adapted elsewhere, and those developers may also use Ruff (we hope!) Signed-off-by: Angus Gratton --- examples/asmled.py | 4 ++++ examples/asmsum.py | 3 +++ examples/natmod/btree/btree_py.py | 4 ++++ examples/natmod/features2/test.py | 2 ++ examples/rp2/pio_1hz.py | 2 ++ examples/rp2/pio_exec.py | 2 ++ examples/rp2/pio_pinchange.py | 2 ++ examples/rp2/pio_pwm.py | 2 ++ examples/rp2/pio_uart_rx.py | 2 ++ examples/rp2/pio_uart_tx.py | 2 ++ examples/rp2/pio_ws2812.py | 2 ++ examples/rp2/pwm_fade.py | 2 ++ ports/qemu-arm/test-frzmpy/frozen_asm.py | 2 ++ 13 files changed, 31 insertions(+) diff --git a/examples/asmled.py b/examples/asmled.py index 09a06c184a..4ff35dfdf8 100644 --- a/examples/asmled.py +++ b/examples/asmled.py @@ -1,5 +1,9 @@ # flash LED #1 using inline assembler # this version is overly verbose and uses word stores +# +# ruff: noqa: F821 - @asm_thumb decorator adds names to function scope + + @micropython.asm_thumb def flash_led(r0): movw(r1, (stm.GPIOA + stm.GPIO_BSRRL) & 0xFFFF) diff --git a/examples/asmsum.py b/examples/asmsum.py index f2c7f285ba..2d8c2b2c99 100644 --- a/examples/asmsum.py +++ b/examples/asmsum.py @@ -1,3 +1,6 @@ +# ruff: noqa: F821 - @asm_thumb decorator adds names to function scope + + @micropython.asm_thumb def asm_sum_words(r0, r1): # r0 = len diff --git a/examples/natmod/btree/btree_py.py b/examples/natmod/btree/btree_py.py index bd53c084a1..461b045c98 100644 --- a/examples/natmod/btree/btree_py.py +++ b/examples/natmod/btree/btree_py.py @@ -1,3 +1,7 @@ # Implemented in Python to support keyword arguments + +# ruff: noqa: F821 - this file is evaluated with C-defined names in scope + + def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0): return _open(stream, flags, cachesize, pagesize, minkeypage) diff --git a/examples/natmod/features2/test.py b/examples/natmod/features2/test.py index 5ac80120d7..af79b9692c 100644 --- a/examples/natmod/features2/test.py +++ b/examples/natmod/features2/test.py @@ -1,5 +1,7 @@ # This Python code will be merged with the C code in main.c +# ruff: noqa: F821 - this file is evaluated with C-defined names in scope + import array diff --git a/examples/rp2/pio_1hz.py b/examples/rp2/pio_1hz.py index 84d761fa14..3ffab79d56 100644 --- a/examples/rp2/pio_1hz.py +++ b/examples/rp2/pio_1hz.py @@ -1,6 +1,8 @@ # Example using PIO to blink an LED and raise an IRQ at 1Hz. # Note: this does not work on Pico W because it uses Pin(25) for LED output. +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + import time from machine import Pin import rp2 diff --git a/examples/rp2/pio_exec.py b/examples/rp2/pio_exec.py index ce39f2df84..3bea51f8dd 100644 --- a/examples/rp2/pio_exec.py +++ b/examples/rp2/pio_exec.py @@ -5,6 +5,8 @@ # - using set_init and set_base # - using StateMachine.exec +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + import time from machine import Pin import rp2 diff --git a/examples/rp2/pio_pinchange.py b/examples/rp2/pio_pinchange.py index 767c8e78c2..4a210e7f39 100644 --- a/examples/rp2/pio_pinchange.py +++ b/examples/rp2/pio_pinchange.py @@ -8,6 +8,8 @@ # - setting an irq handler for a StateMachine # - instantiating 2x StateMachine's with the same program and different pins +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + import time from machine import Pin import rp2 diff --git a/examples/rp2/pio_pwm.py b/examples/rp2/pio_pwm.py index 176a238091..24fd6b85a3 100644 --- a/examples/rp2/pio_pwm.py +++ b/examples/rp2/pio_pwm.py @@ -1,5 +1,7 @@ # Example of using PIO for PWM, and fading the brightness of an LED +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + from machine import Pin from rp2 import PIO, StateMachine, asm_pio from time import sleep diff --git a/examples/rp2/pio_uart_rx.py b/examples/rp2/pio_uart_rx.py index 080b6bd639..f46aaa6a5e 100644 --- a/examples/rp2/pio_uart_rx.py +++ b/examples/rp2/pio_uart_rx.py @@ -8,6 +8,8 @@ # - PIO irq handler # - using the second core via _thread +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + import _thread from machine import Pin, UART from rp2 import PIO, StateMachine, asm_pio diff --git a/examples/rp2/pio_uart_tx.py b/examples/rp2/pio_uart_tx.py index 5e4af8f6cc..04abf2d0d1 100644 --- a/examples/rp2/pio_uart_tx.py +++ b/examples/rp2/pio_uart_tx.py @@ -1,5 +1,7 @@ # Example using PIO to create a UART TX interface +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + from machine import Pin from rp2 import PIO, StateMachine, asm_pio diff --git a/examples/rp2/pio_ws2812.py b/examples/rp2/pio_ws2812.py index dd021a9d56..6de21ab8b7 100644 --- a/examples/rp2/pio_ws2812.py +++ b/examples/rp2/pio_ws2812.py @@ -1,5 +1,7 @@ # Example using PIO to drive a set of WS2812 LEDs. +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + import array, time from machine import Pin import rp2 diff --git a/examples/rp2/pwm_fade.py b/examples/rp2/pwm_fade.py index 5b7089c6b1..6672f3443f 100644 --- a/examples/rp2/pwm_fade.py +++ b/examples/rp2/pwm_fade.py @@ -1,6 +1,8 @@ # Example using PWM to fade an LED. # Note: this does not work on Pico W because it uses Pin(25) for LED output. +# ruff: noqa: F821 - @asm_pio decorator adds names to function scope + import time from machine import Pin, PWM diff --git a/ports/qemu-arm/test-frzmpy/frozen_asm.py b/ports/qemu-arm/test-frzmpy/frozen_asm.py index 2c7f5c92cd..ba43264b38 100644 --- a/ports/qemu-arm/test-frzmpy/frozen_asm.py +++ b/ports/qemu-arm/test-frzmpy/frozen_asm.py @@ -1,5 +1,7 @@ # Test freezing inline-asm code. +# ruff: noqa: F821 - @asm_thumb decorator adds names to function scope + import micropython From cec3ff5526d1aa09b0eb86a371d7312ddb8a33b4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 18:16:39 +1000 Subject: [PATCH 042/121] mpy-cross: Fix source file name in file-not-found error. Found by Ruff with F821. Signed-off-by: Angus Gratton --- mpy-cross/mpy_cross/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpy-cross/mpy_cross/__init__.py b/mpy-cross/mpy_cross/__init__.py index 8eadbc8352..5020033e8c 100644 --- a/mpy-cross/mpy_cross/__init__.py +++ b/mpy-cross/mpy_cross/__init__.py @@ -100,7 +100,7 @@ def compile(src, dest=None, src_path=None, opt=None, march=None, mpy_cross=None, if not src: raise ValueError("src is required") if not os.path.exists(src): - raise CrossCompileError("Input .py file not found: {}.".format(src_py)) + raise CrossCompileError("Input .py file not found: {}.".format(src)) args = [] From ef864a4aa4370ea1b659496e4d0f145bbc28bec3 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 18:17:06 +1000 Subject: [PATCH 043/121] cc3200/tools: Fix exception raised on process failure. subprocess.CalledProcessError() constructor arguments aren't documented, but these are them. Even if they change, it's an improvement over a non-existent exception name! Found by Ruff checking F821. Signed-off-by: Angus Gratton --- ports/cc3200/tools/uniflash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/cc3200/tools/uniflash.py b/ports/cc3200/tools/uniflash.py index 83445a12d3..2fa2c02f45 100644 --- a/ports/cc3200/tools/uniflash.py +++ b/ports/cc3200/tools/uniflash.py @@ -41,7 +41,7 @@ def execute(command): if exitCode == 0: return cmd_log else: - raise ProcessException(command, exitCode, output) + raise subprocess.CalledProcessError(exitCode, command, output) def main(): From 801910fc837919688b98e9abce04a679f14037be Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 18:18:50 +1000 Subject: [PATCH 044/121] all: Add missing imports for micropython.const. Found by Ruff checking F821. Signed-off-by: Angus Gratton --- examples/bluetooth/ble_uart_repl.py | 1 + ports/nrf/examples/ssd1306_mod.py | 1 + ports/nrf/examples/ubluepy_eddystone.py | 1 + ports/stm32/boards/NUCLEO_WB55/rfcore_debug.py | 1 + 4 files changed, 4 insertions(+) diff --git a/examples/bluetooth/ble_uart_repl.py b/examples/bluetooth/ble_uart_repl.py index 7d92c1f318..5812a5cc13 100644 --- a/examples/bluetooth/ble_uart_repl.py +++ b/examples/bluetooth/ble_uart_repl.py @@ -7,6 +7,7 @@ import bluetooth import io import os import micropython +from micropython import const import machine from ble_uart_peripheral import BLEUART diff --git a/ports/nrf/examples/ssd1306_mod.py b/ports/nrf/examples/ssd1306_mod.py index b083a3aa7e..d42d165fa8 100644 --- a/ports/nrf/examples/ssd1306_mod.py +++ b/ports/nrf/examples/ssd1306_mod.py @@ -19,6 +19,7 @@ # disp = SSD1306_I2C_Mod(128, 64, i2c) from ssd1306 import SSD1306_I2C +from micropython import const SET_COL_ADDR = const(0x21) SET_PAGE_ADDR = const(0x22) diff --git a/ports/nrf/examples/ubluepy_eddystone.py b/ports/nrf/examples/ubluepy_eddystone.py index 96818d01c2..c98a2266f5 100644 --- a/ports/nrf/examples/ubluepy_eddystone.py +++ b/ports/nrf/examples/ubluepy_eddystone.py @@ -1,3 +1,4 @@ +from micropython import const from ubluepy import Peripheral, constants BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE = const(0x02) diff --git a/ports/stm32/boards/NUCLEO_WB55/rfcore_debug.py b/ports/stm32/boards/NUCLEO_WB55/rfcore_debug.py index 4dbead0acc..db533f18dc 100644 --- a/ports/stm32/boards/NUCLEO_WB55/rfcore_debug.py +++ b/ports/stm32/boards/NUCLEO_WB55/rfcore_debug.py @@ -35,6 +35,7 @@ # See rfcore_firmware.py for more information. from machine import mem8, mem16, mem32 +from micropython import const import stm SRAM2A_BASE = const(0x2003_0000) From 29c022e0f141be4228d9e71469c691daabf372b2 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 16 Aug 2023 15:04:42 +1000 Subject: [PATCH 045/121] examples/hwapi: Add missing import for 96Boards Carbon example. Found by Ruff checking F821. Signed-off-by: Angus Gratton --- examples/hwapi/hwconfig_z_96b_carbon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hwapi/hwconfig_z_96b_carbon.py b/examples/hwapi/hwconfig_z_96b_carbon.py index 97fd57a07f..d4f98139bc 100644 --- a/examples/hwapi/hwconfig_z_96b_carbon.py +++ b/examples/hwapi/hwconfig_z_96b_carbon.py @@ -1,4 +1,4 @@ -from machine import Signal +from machine import Pin, Signal # 96Boards Carbon board # USR1 - User controlled led, connected to PD2 From 974f99482cc54fdc9be1623569c46e4be569ebd6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 18:21:15 +1000 Subject: [PATCH 046/121] renesas-ra/boards: Remove unreachable code in make-pins.py. Looks like copy-paste from the stm32 make-pins.py, references a function that is not present in the renesas-ra version. Found by Ruff checking F821. Signed-off-by: Angus Gratton --- ports/renesas-ra/boards/make-pins.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ports/renesas-ra/boards/make-pins.py b/ports/renesas-ra/boards/make-pins.py index 1b4588f02f..5147d27940 100644 --- a/ports/renesas-ra/boards/make-pins.py +++ b/ports/renesas-ra/boards/make-pins.py @@ -220,13 +220,7 @@ class Pins(object): for named_pin in self.board_pins: qstr_set |= set([named_pin.name()]) for qstr in sorted(qstr_set): - cond_var = None - if qstr.startswith("AF"): - af_words = qstr.split("_") - cond_var = conditional_var(af_words[1]) - print_conditional_if(cond_var, file=qstr_file) print("Q({})".format(qstr), file=qstr_file) - # print_conditional_endif(cond_var, file=qstr_file) def print_ad_hdr(self, ad_const_filename): with open(ad_const_filename, "wt") as ad_const_file: From b8189d039d0a9cbda54a7cab8cf12a0aee9603a0 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 18:22:01 +1000 Subject: [PATCH 047/121] tools/mpy_ld.py: Pre-declare some local variables to appease linter. Spurious fix as the logic is structured such that these variables will be set before dereferenced, but this keeps Ruff happy (no more F821 undefined-name). Signed-off-by: Angus Gratton --- tools/mpy_ld.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 87e57869f6..60fa41ce1f 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -966,6 +966,9 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): # MPY: relocation information prev_kind = None + prev_base = None + prev_offset = None + prev_n = None for base, addr, kind in env.mpy_relocs: if isinstance(kind, str) and kind.startswith(".text"): kind = 0 From 1a5c9b9da4f16f5f7bd91c3420022d4ec0e6fa1a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 19:08:44 +1000 Subject: [PATCH 048/121] tools/mpy-tool.py: Ignore linter failure in Python 2 compatibility code. Found by Ruff checking F821. Signed-off-by: Angus Gratton --- tools/mpy-tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index a5112de9a1..5ef69b267a 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -35,7 +35,7 @@ if platform.python_version_tuple()[0] == "2": bytes_cons = lambda val, enc=None: bytearray(val) is_str_type = lambda o: isinstance(o, str) is_bytes_type = lambda o: type(o) is bytearray - is_int_type = lambda o: isinstance(o, int) or isinstance(o, long) + is_int_type = lambda o: isinstance(o, int) or isinstance(o, long) # noqa: F821 def hexlify_to_str(b): x = hexlify_py2(b) From 40fcbe1246e95eea33a727b1c6f22f76abb34d95 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 18:24:29 +1000 Subject: [PATCH 049/121] top: Enable ruff linter check for F821 undefined-name. Very helpful for catching typos or missing imports when writing code! Description can be found at https://beta.ruff.rs/docs/rules/undefined-name/ Parent commits contain various small fixes and inline ignores for this check. The only blanket exception is manifest files, which are numerous and evaluated with some global names pre-defined - these can be globally ignored. Signed-off-by: Angus Gratton --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dfd26bd8c9..a05abf887e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,6 @@ ignore = [ "F401", "F403", "F405", - "F821", "PLC1901", ] line-length = 337 @@ -46,3 +45,7 @@ max-complexity = 40 [tool.ruff.per-file-ignores] "ports/cc3200/tools/uniflash.py" = ["E711"] + +# manifest.py files are evaluated with some global names pre-defined +"**/manifest.py" = ["F821"] +"ports/**/boards/manifest*.py" = ["F821"] From a18d62e06727e0c424da1f43f80a5b0cb76bcc04 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 16 Aug 2023 08:41:40 +0200 Subject: [PATCH 050/121] mimxrt: Fix UART RTS/CTS assignments for the OLIMEX and Adafruit boards. At the Adafruit Metro M7 the pin GPIO_AD_13 is used for JTAG. Therefore it is not configured for RTS at UART 2 and 3. Signed-off-by: robert-hh --- ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h | 6 ++++++ ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h index ac9cf97058..7d759df5e6 100644 --- a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h +++ b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h @@ -23,6 +23,12 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD }, +#define IOMUX_TABLE_UART_CTS_RTS \ + { IOMUXC_GPIO_08_LPUART1_CTS_B }, { IOMUXC_GPIO_07_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_AD_14_LPUART3_CTS_B }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_14_LPUART4_CTS_B }, { 0 }, + #define MICROPY_HW_SPI_INDEX { 1 } #define IOMUX_TABLE_SPI \ diff --git a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h index 828855d4d3..9443bb3732 100644 --- a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h +++ b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h @@ -26,10 +26,10 @@ { IOMUXC_GPIO_06_LPUART4_TXD }, { IOMUXC_GPIO_05_LPUART4_RXD }, #define IOMUX_TABLE_UART_CTS_RTS \ - { IOMUXC_GPIO_AD_B0_14_LPUART1_CTS_B }, { IOMUXC_GPIO_AD_B0_15_LPUART1_RTS_B }, \ + { IOMUXC_GPIO_08_LPUART1_CTS_B }, { IOMUXC_GPIO_07_LPUART1_RTS_B }, \ { 0 }, { 0 }, \ { 0 }, { 0 }, \ - { IOMUXC_GPIO_EMC_17_LPUART4_CTS_B }, { IOMUXC_GPIO_EMC_18_LPUART4_RTS_B }, + { IOMUXC_GPIO_AD_14_LPUART4_CTS_B }, { IOMUXC_GPIO_AD_13_LPUART4_RTS_B }, #define MICROPY_HW_SPI_INDEX { 0, 1, 2 } From e6cfb77342c475d3b4453317cfffbda30cf89e29 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 8 Jul 2022 12:46:27 +1000 Subject: [PATCH 051/121] stm32/spi: Add STM32WL5 SUBGHZ SPI peripheral. This is a "normal" SPI peripheral with no external pins, to avoid having to grow spi_obj[] for just this one board map it as SPI ID 3 (board has SPI IDs 1,2 already). Signed-off-by: Angus Gratton --- .../stm32/boards/NUCLEO_WL55/mpconfigboard.h | 4 ++ ports/stm32/dma.c | 4 ++ ports/stm32/dma.h | 2 + ports/stm32/spi.c | 48 ++++++++++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h index 51700ba8a5..4087ba4fbc 100644 --- a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h @@ -48,6 +48,10 @@ #define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 5 on CN5 #define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 4 on CN5 +// SUBGHZSPI Internal radio SPI BUS +#define MICROPY_HW_SUBGHZSPI_NAME "SUBGHZ" +#define MICROPY_HW_SUBGHZSPI_ID 3 + // User switch; pressing the button makes the input go low #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index cdbb90e5d8..b2ba787ce6 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -558,6 +558,10 @@ const dma_descr_t dma_SPI_1_RX = { DMA1_Channel1, DMA_REQUEST_SPI1_RX, dma_id_0, const dma_descr_t dma_SPI_1_TX = { DMA1_Channel2, DMA_REQUEST_SPI1_TX, dma_id_1, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_2_RX = { DMA1_Channel3, DMA_REQUEST_SPI2_RX, dma_id_2, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_2_TX = { DMA1_Channel4, DMA_REQUEST_SPI2_TX, dma_id_3, &dma_init_struct_spi_i2c }; +#if defined(STM32WL) +const dma_descr_t dma_SPI_SUBGHZ_RX = { DMA1_Channel5, DMA_REQUEST_SUBGHZSPI_RX, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_SUBGHZ_TX = { DMA1_Channel6, DMA_REQUEST_SUBGHZSPI_TX, dma_id_5, &dma_init_struct_spi_i2c }; +#endif static const uint8_t dma_irqn[NSTREAM] = { DMA1_Channel1_IRQn, diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 92d5db6c0a..2afc947541 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -136,6 +136,8 @@ extern const dma_descr_t dma_SPI_3_TX; extern const dma_descr_t dma_SDIO_0; extern const dma_descr_t dma_I2C_4_TX; extern const dma_descr_t dma_I2C_4_RX; +extern const dma_descr_t dma_SPI_SUBGHZ_TX; +extern const dma_descr_t dma_SPI_SUBGHZ_RX; #endif diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index 11a9a74ea3..1f5996165e 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -62,6 +62,9 @@ STATIC SPI_HandleTypeDef SPIHandle5 = {.Instance = NULL}; #if defined(MICROPY_HW_SPI6_SCK) STATIC SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL}; #endif +#if defined(MICROPY_HW_SUBGHZSPI_ID) +static SPI_HandleTypeDef SPIHandleSubGhz = {.Instance = NULL}; +#endif const spi_t spi_obj[6] = { #if defined(MICROPY_HW_SPI1_SCK) @@ -76,6 +79,8 @@ const spi_t spi_obj[6] = { #endif #if defined(MICROPY_HW_SPI3_SCK) {&SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX}, + #elif MICROPY_HW_SUBGHZSPI_ID == 3 + {&SPIHandleSubGhz, &dma_SPI_SUBGHZ_TX, &dma_SPI_SUBGHZ_RX}, #else {NULL, NULL, NULL}, #endif @@ -96,6 +101,10 @@ const spi_t spi_obj[6] = { #endif }; +#if defined(MICROPY_HW_SUBGHZSPI_ID) && MICROPY_HW_SUBGHZSPI_ID != 3 +#error "spi_obj needs updating for new value of MICROPY_HW_SUBGHZSPI_ID" +#endif + #if defined(STM32H5) || defined(STM32H7) // STM32H5/H7 HAL requires SPI IRQs to be enabled and handled. #if defined(MICROPY_HW_SPI1_SCK) @@ -163,6 +172,9 @@ void spi_init0(void) { #if defined(MICROPY_HW_SPI6_SCK) SPIHandle6.Instance = SPI6; #endif + #if defined(MICROPY_HW_SUBGHZSPI_ID) + SPIHandleSubGhz.Instance = SUBGHZSPI; + #endif } int spi_find_index(mp_obj_t id) { @@ -195,6 +207,10 @@ int spi_find_index(mp_obj_t id) { } else if (strcmp(port, MICROPY_HW_SPI6_NAME) == 0) { spi_id = 6; #endif + #ifdef MICROPY_HW_SUBGHZSPI_NAME + } else if (strcmp(port, MICROPY_HW_SUBGHZSPI_NAME) == 0) { + spi_id = MICROPY_HW_SUBGHZSPI_ID; + #endif } else { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%s) doesn't exist"), port); } @@ -239,7 +255,7 @@ STATIC uint32_t spi_get_source_freq(SPI_HandleTypeDef *spi) { } else { return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6); } - #else + #else // !STM32F0, !STM32G0, !STM32H #if defined(SPI2) if (spi->Instance == SPI2) { // SPI2 is on APB1 @@ -252,11 +268,20 @@ STATIC uint32_t spi_get_source_freq(SPI_HandleTypeDef *spi) { return HAL_RCC_GetPCLK1Freq(); } else #endif + #if defined(MICROPY_HW_SUBGHZSPI_ID) + if (spi->Instance == SUBGHZSPI) { + // In STM32WL5x, SUBGHZSPI is PCLK3 which is same as HCLK3, no HCLK3->PCLK3 divider exists in clock tree + #if !defined(LL_APB3_GRP1_PERIPH_SUBGHZSPI) + #error "SPI needs updating for new SUBGHZSPI clock configuration" + #endif + return HAL_RCC_GetHCLK3Freq(); + } else + #endif { // SPI1, SPI4, SPI5 and SPI6 are on APB2 return HAL_RCC_GetPCLK2Freq(); } - #endif + #endif // STM32F0, STM32G0, STM32H } // sets the parameters in the SPI_InitTypeDef struct @@ -411,6 +436,12 @@ int spi_init(const spi_t *self, bool enable_nss_pin) { // enable the SPI clock __HAL_RCC_SPI6_CLK_ENABLE(); #endif + #if defined(MICROPY_HW_SUBGHZSPI_ID) + } else if (spi->Instance == SUBGHZSPI) { + irqn = SUBGHZSPI_IRQn; + // pins remain all NULL, internal bus has no GPIO mappings + __HAL_RCC_SUBGHZSPI_CLK_ENABLE(); + #endif } else { // SPI does not exist for this board (shouldn't get here, should be checked by caller) return -MP_EINVAL; @@ -502,6 +533,14 @@ void spi_deinit(const spi_t *spi_obj) { __HAL_RCC_SPI6_CLK_DISABLE(); HAL_NVIC_DisableIRQ(SPI6_IRQn); #endif + #if defined(MICROPY_HW_SUBGHZSPI_ID) + } else if (spi->Instance == SUBGHZSPI) { + __HAL_RCC_SUBGHZSPI_FORCE_RESET(); + __HAL_RCC_SUBGHZSPI_RELEASE_RESET(); + __HAL_RCC_SUBGHZSPI_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(SUBGHZSPI_IRQn); + + #endif } } @@ -661,6 +700,11 @@ void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { spi_num = 6; } #endif + #if defined(MICROPY_HW_SUBGHZSPI_ID) + else if (spi->Instance == SUBGHZSPI) { + spi_num = MICROPY_HW_SUBGHZSPI_ID; + } + #endif mp_printf(print, "SPI(%u", spi_num); if (spi->State != HAL_SPI_STATE_RESET) { From 2c62adb42c241f0ddb523011dbf082c53ba8c742 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 16 Aug 2023 14:11:26 +1000 Subject: [PATCH 052/121] stm32/powerctrlboot: Support STM32WL system clock from HSE+PLL. Switches default on the NUCLEO_WL55 board to use the HSE oscillator powered from PB0_VDDTCXO pin. Build-time configuration can select from MSI internal oscillator (previous default), HSE via crystal, or HSE bypass with TCXO powered from PB0_VDDTCXO pin (new default) Signed-off-by: Angus Gratton --- .../stm32/boards/NUCLEO_WL55/mpconfigboard.h | 7 +++ ports/stm32/boards/NUCLEO_WL55/pins.csv | 3 +- ports/stm32/mpconfigboard_common.h | 4 ++ ports/stm32/powerctrlboot.c | 62 ++++++++++++++++++- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h index 4087ba4fbc..ec5904a359 100644 --- a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h @@ -28,6 +28,13 @@ #define MICROPY_HW_RTC_USE_LSE (1) #define MICROPY_HW_RTC_USE_US (1) +// Use external 32MHz TCXO + PLL as system clock source +// (If unset, board will use the internal MSI oscillator instead.) +#define MICROPY_HW_CLK_USE_HSE (1) + +// HSE bypass for STM32WL5x means TCXO is powered from PB0_VDDTCXO pin +#define MICROPY_HW_CLK_USE_BYPASS (1) + // UART buses #define MICROPY_HW_UART1_TX (pin_B6) // Arduino D1, pin 7 on CN9 #define MICROPY_HW_UART1_RX (pin_B7) // Arduino D0, pin 8 on CN9 diff --git a/ports/stm32/boards/NUCLEO_WL55/pins.csv b/ports/stm32/boards/NUCLEO_WL55/pins.csv index afcf34df11..78a0ef8d04 100644 --- a/ports/stm32/boards/NUCLEO_WL55/pins.csv +++ b/ports/stm32/boards/NUCLEO_WL55/pins.csv @@ -14,7 +14,8 @@ ,PA13 ,PA14 ,PA15 -,PB0 +# in the default board configuration, PB0 must stay muxed to analog for HSE VDDTCXO function +,-PB0 ,PB1 ,PB2 ,PB3 diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 149d2ae73a..3331b38400 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -471,8 +471,12 @@ #define MICROPY_HW_RCC_HSI_STATE (RCC_HSI_OFF) #define MICROPY_HW_RCC_FLAG_HSxRDY (RCC_FLAG_HSERDY) #if MICROPY_HW_CLK_USE_BYPASS +#if !defined(STM32WL) #define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_BYPASS) #else +#define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_BYPASS_PWR) +#endif +#else #define MICROPY_HW_RCC_HSE_STATE (RCC_HSE_ON) #endif #endif diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index 51b740a809..b075073a5b 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -460,13 +460,71 @@ void SystemClock_Config(void) { #include "stm32wlxx_ll_utils.h" void SystemClock_Config(void) { - // Set flash latency + // Set flash latency (2 wait states, sysclk > 36MHz) LL_FLASH_SetLatency(LL_FLASH_LATENCY_2); while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) { } LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + #if MICROPY_HW_CLK_USE_HSE + // Enable the 32MHz external oscillator and 48MHZ SYSCLK via PLL + + #if MICROPY_HW_CLK_USE_BYPASS + // Use "bypass power" option, port PB0_VDDTCXO supplies TCXO + // (STM32WL5x has no other HSE bypass mode.) + + // "PB0 must be configured in analog mode prior enabling the HSE" + // + // Note: PB0 analog mode muxes PB0_VDDTCXO pin to the VDDTCXO regulator, set + // to default voltage of 1.7V. Changing this voltage requires initializing + // the SUBGHZ radio and sending a Set_Tcxo command to it. + // + // For the Nucelo-WL55 board, ST uses the NDK "NT2016SF-32M-END5875A" TCXO + // which has no publicly available datasheet. However, the ST code for this + // board always keeps the pin at the default 1.7V voltage level so changing + // the level would only be needed if a different TCXO is used. + // + // (Note also that setting pin PB0 as a push-pull GPIO output is technically + // possible too, but 3.3V will be too high for many TCXOs.) + mp_hal_pin_config(pin_B0, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0); + + LL_RCC_HSE_EnableTcxo(); + + #endif // MICROPY_HW_CLK_USE_BYPASS + + LL_RCC_HSE_Enable(); + while (!LL_RCC_HSE_IsReady()) { + // Wait for HSE Ready signal + } + + // Configure PLL for a 48MHz SYSCLK + #define PLLM (HSE_VALUE / 16000000) // VCO input 16MHz (recommended in ST docs) + #define PLLN (6) // 7*8MHz = 96MHz + #define PLLP (2) // f_P = 48MHz + #define PLLQ (2) // f_Q = 48MHz + #define PLLR (2) // f_R = 48MHz + RCC->PLLCFGR = + (PLLR - 1) << RCC_PLLCFGR_PLLR_Pos | RCC_PLLCFGR_PLLREN + | (PLLQ - 1) << RCC_PLLCFGR_PLLQ_Pos | RCC_PLLCFGR_PLLQEN + | (PLLP - 1) << RCC_PLLCFGR_PLLP_Pos | RCC_PLLCFGR_PLLPEN + | PLLN << RCC_PLLCFGR_PLLN_Pos + | (PLLM - 1) << RCC_PLLCFGR_PLLM_Pos + | LL_RCC_PLLSOURCE_HSE; + + LL_RCC_PLL_Enable(); + LL_RCC_PLL_EnableDomain_SYS(); + while (!LL_RCC_PLL_IsReady()) { + // Wait for PLL to lock + } + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) { + // Wait for system clock source to switch + } + + #else // Use MSI as 48MHz source for SYSCLK + // Enable MSI LL_RCC_MSI_Enable(); while (!LL_RCC_MSI_IsReady()) { @@ -482,6 +540,8 @@ void SystemClock_Config(void) { while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) { } + #endif // MICROPY_HW_CLK_USE_HSE + // Set bus dividers LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); LL_RCC_SetAHB3Prescaler(LL_RCC_SYSCLK_DIV_1); From 9e0f934cdf195ca8d06ce51eb89f89e590984176 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 8 Jul 2022 14:18:44 +1000 Subject: [PATCH 053/121] stm32/dma: Fix DMA completion on WL55 boards. No IRQHandlers were compiled in for this board. Includes small consolidation of the same DMAMUX_ENABLE line for STM32G4, STM32WB, STM32WL. Signed-off-by: Angus Gratton --- ports/stm32/dma.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index b2ba787ce6..bfa4fb23ff 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -161,7 +161,7 @@ static const DMA_InitTypeDef dma_init_struct_i2s = { static const DMA_InitTypeDef dma_init_struct_sdio = { #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) + #elif defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB)) || defined(STM32WL) .Request = 0, #endif .Direction = 0, @@ -171,7 +171,7 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { .MemDataAlignment = DMA_MDATAALIGN_WORD, #if defined(STM32F4) || defined(STM32F7) .Mode = DMA_PFCTRL, - #elif defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) + #elif defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) .Mode = DMA_NORMAL, #endif .Priority = DMA_PRIORITY_VERY_HIGH, @@ -189,7 +189,7 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { static const DMA_InitTypeDef dma_init_struct_dac = { #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) + #elif defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) .Request = 0, #endif .Direction = 0, @@ -1221,7 +1221,7 @@ void DMA1_Channel4_5_6_7_IRQHandler(void) { IRQ_EXIT(DMA1_Channel4_5_6_7_IRQn); } -#elif defined(STM32L1) || defined(STM32L4) || defined(STM32WB) +#elif defined(STM32L1) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) void DMA1_Channel1_IRQHandler(void) { IRQ_ENTER(DMA1_Channel1_IRQn); @@ -1344,9 +1344,9 @@ static void dma_enable_clock(dma_id_t dma_id) { dma_enable_mask |= (1 << dma_id); MICROPY_END_ATOMIC_SECTION(irq_state); - #if defined(STM32WB) - // This MCU has a DMAMUX peripheral which needs to be enabled to multiplex the channels. + #if defined(STM32G4) || defined(STM32WB) || defined(STM32WL) if (!__HAL_RCC_DMAMUX1_IS_CLK_ENABLED()) { + // MCU has a DMAMUX peripheral which needs to be enabled to multiplex the channels. __HAL_RCC_DMAMUX1_CLK_ENABLE(); } #endif @@ -1354,9 +1354,6 @@ static void dma_enable_clock(dma_id_t dma_id) { if (dma_id < NSTREAMS_PER_CONTROLLER) { if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) { __HAL_RCC_DMA1_CLK_ENABLE(); - #if defined(STM32G4) - __HAL_RCC_DMAMUX1_CLK_ENABLE(); - #endif // We just turned on the clock. This means that anything stored // in dma_last_channel (for DMA1) needs to be invalidated. @@ -1371,9 +1368,6 @@ static void dma_enable_clock(dma_id_t dma_id) { if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) { __HAL_RCC_DMA2_CLK_ENABLE(); - #if defined(STM32G4) - __HAL_RCC_DMAMUX1_CLK_ENABLE(); - #endif // We just turned on the clock. This means that anything stored // in dma_last_channel (for DMA2) needs to be invalidated. From 02620c2236e948b1899d122359a1eb150e5a9ee0 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 15 Jul 2022 14:04:33 +1000 Subject: [PATCH 054/121] stm32/subghz: Add STM32WL55 subghz radio interface to stm module. This is the minimum C interface to allow a modem driver to be built in Python. Interface is simple, with the intention that the micropython-lib driver is the main (only) consumer of it. Signed-off-by: Angus Gratton --- docs/library/stm.rst | 36 +++++ ports/stm32/Makefile | 1 + .../stm32/boards/NUCLEO_WL55/mpconfigboard.h | 2 +- ports/stm32/boards/NUCLEO_WL55/pins.csv | 6 +- ports/stm32/irq.h | 2 + ports/stm32/main.c | 7 + ports/stm32/modstm.c | 7 + ports/stm32/subghz.c | 139 ++++++++++++++++++ ports/stm32/subghz.h | 40 +++++ 9 files changed, 236 insertions(+), 4 deletions(-) create mode 100644 ports/stm32/subghz.c create mode 100644 ports/stm32/subghz.h diff --git a/docs/library/stm.rst b/docs/library/stm.rst index a181d6044c..970ab18834 100644 --- a/docs/library/stm.rst +++ b/docs/library/stm.rst @@ -102,3 +102,39 @@ the second CPU, the RF core. Execute a HCI command on the SYS channel. The execution is synchronous. Returns a bytes object with the result of the SYS command. + +Functions specific to STM32WLxx MCUs +------------------------------------ + +These functions are available on STM32WLxx microcontrollers, and interact with +the integrated "SUBGHZ" radio modem peripheral. + +.. function:: subghz_cs(level) + + Sets the internal SPI CS pin attached to the radio peripheral. The ``level`` + argument is active-low: a truthy value means "CS pin high" and de-asserts the + signal, a falsey value means "CS pin low" and asserts the signal. + + The internal-only SPI bus corresponding to this CS signal can be instantiated + using :ref:`machine.SPI()` ``id`` value ``"SUBGHZ"``. + +.. function:: subghz_irq(handler) + + Sets the internal SUBGHZ radio interrupt handler to the provided + function. The handler function is called as a "hard" interrupt in response to + radio peripheral interrupts. See :ref:`isr_rules` for more information about + interrupt handlers in MicroPython. + + Calling this function with the handler argument set to None disables the IRQ. + + Due to a hardware limitation, each time this IRQ fires MicroPython disables + it before calling the handler. In order to receive another interrupt, Python + code should call ``subghz_irq()`` to set the handler again. This has the side + effect of re-enabling the IRQ. + +.. function:: subghz_is_busy() + + Return a ``bool`` corresponding to the internal "RFBUSYS" signal from the + radio peripheral. Before sending a new command to the radio over SPI then + this function should be polled until it returns ``False``, to confirm the + busy signal is de-asserted. diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 2bfd11157e..7051398970 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -355,6 +355,7 @@ SRC_C += \ dac.c \ adc.c \ sdio.c \ + subghz.c \ $(wildcard $(BOARD_DIR)/*.c) SRC_O += \ diff --git a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h index ec5904a359..c87fcdea9b 100644 --- a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h @@ -14,7 +14,7 @@ #define MICROPY_PY_SOCKET (0) #define MICROPY_PY_NETWORK (0) #define MICROPY_PY_ONEWIRE (0) -#define MICROPY_PY_STM (0) +#define MICROPY_PY_STM (1) #define MICROPY_PY_PYB_LEGACY (0) #define MICROPY_PY_HEAPQ (0) diff --git a/ports/stm32/boards/NUCLEO_WL55/pins.csv b/ports/stm32/boards/NUCLEO_WL55/pins.csv index 78a0ef8d04..41e2d725a2 100644 --- a/ports/stm32/boards/NUCLEO_WL55/pins.csv +++ b/ports/stm32/boards/NUCLEO_WL55/pins.csv @@ -34,9 +34,9 @@ ,PC0 ,PC1 ,PC2 -,PC3 -,PC4 -,PC5 +FE_CTRL3,PC3 +FE_CTRL1,PC4 +FE_CTRL2,PC5 ,PC6 SW,PA0 SW1,PA0 diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 8e98b4cc5e..7f10d0d004 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -155,6 +155,8 @@ static inline void restore_irq_pri(uint32_t state) { #define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0) +#define IRQ_PRI_SUBGHZ_RADIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 8, 0) + #define IRQ_PRI_SPI NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 8, 0) // Interrupt priority for non-special timers. diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 2235e4de35..95b74c621a 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -86,6 +86,7 @@ #include "servo.h" #include "dac.h" #include "can.h" +#include "subghz.h" #if MICROPY_PY_THREAD STATIC pyb_thread_t pyb_thread_main; @@ -403,6 +404,9 @@ void stm32_main(uint32_t reset_mode) { #if defined(STM32WB) rfcore_init(); #endif + #if defined(STM32WL) + subghz_init(); + #endif #if MICROPY_HW_SDRAM_SIZE sdram_init(); bool sdram_valid = true; @@ -650,6 +654,9 @@ soft_reset_exit: #if MICROPY_PY_BLUETOOTH mp_bluetooth_deinit(); #endif + #if defined(STM32WL) + subghz_deinit(); + #endif #if MICROPY_PY_NETWORK mod_network_deinit(); #endif diff --git a/ports/stm32/modstm.c b/ports/stm32/modstm.c index 94d56d4d08..53bc0db79c 100644 --- a/ports/stm32/modstm.c +++ b/ports/stm32/modstm.c @@ -32,6 +32,7 @@ #include "extmod/machine_mem.h" #include "rfcore.h" #include "portmodules.h" +#include "subghz.h" #if MICROPY_PY_STM @@ -51,6 +52,12 @@ STATIC const mp_rom_map_elem_t stm_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_rfcore_fw_version), MP_ROM_PTR(&rfcore_fw_version_obj) }, { MP_ROM_QSTR(MP_QSTR_rfcore_sys_hci), MP_ROM_PTR(&rfcore_sys_hci_obj) }, #endif + + #if defined(STM32WL) + { MP_ROM_QSTR(MP_QSTR_subghz_cs), MP_ROM_PTR(&subghz_cs_obj) }, + { MP_ROM_QSTR(MP_QSTR_subghz_irq), MP_ROM_PTR(&subghz_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_subghz_is_busy), MP_ROM_PTR(&subghz_is_busy_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(stm_module_globals, stm_module_globals_table); diff --git a/ports/stm32/subghz.c b/ports/stm32/subghz.c new file mode 100644 index 0000000000..1daed59aaf --- /dev/null +++ b/ports/stm32/subghz.c @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Angus Gratton + * + * 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 "py/gc.h" +#include "py/runtime.h" +#include "subghz.h" +#include "irq.h" +#include "spi.h" + +#if defined(STM32WL) + +// Interface to the STM32WL series "SUBGHZ Radio" module + +STATIC void handle_radio_irq() { + // Level-triggered interrupts means the interrupt has to be cleared before + // this function returns. + // + // Rather than writing to SUBGHZ SPI in Interrupt Context to clear the + // interrupt, disable the IRQ and rely on Python code to call + // subghz_irq(handler) to re-enable when needed. + HAL_NVIC_DisableIRQ(SUBGHZ_Radio_IRQn); + + mp_obj_t callback = MP_STATE_PORT(subghz_callback); + if (callback != mp_const_none) { + mp_sched_lock(); + gc_lock(); + // Passing dummy 'pin' argument of None, to keep + // compatibility with machine.Pin.isr() handlers + mp_call_function_1_protected(callback, mp_const_none); + gc_unlock(); + mp_sched_unlock(); + } +} + +void SUBGHZ_Radio_IRQHandler(void) { + IRQ_ENTER(SUBGHZ_Radio_IRQn); + handle_radio_irq(); + IRQ_EXIT(SUBGHZ_Radio_IRQn); +} + +void subghz_init(void) { + __HAL_RCC_SUBGHZ_RADIO_FORCE_RESET(); + + #if !MICROPY_HW_CLK_USE_HSE && MICROPY_HW_CLK_USE_BYPASS + // SUBGHZ clock source is HSE oscillator. + // + // If this is not already enabled for the system clock, and we're depending + // on the VDDTCXO pin to power the HSE ("bypass mode"), then enable it. + __HAL_RCC_HSE_CONFIG(RCC_HSE_BYPASS_PWR); + #endif + + NVIC_DisableIRQ(SUBGHZ_Radio_IRQn); + NVIC_SetPriority(SUBGHZ_Radio_IRQn, IRQ_PRI_SUBGHZ_RADIO); + + __HAL_RCC_SUBGHZ_RADIO_RELEASE_RESET(); + + while (__HAL_RCC_GET_FLAG(RCC_FLAG_RFRST) != 0) { + } + + MP_STATE_PORT(subghz_callback) = mp_const_none; +} + +void subghz_deinit(void) { + MP_STATE_PORT(subghz_callback) = mp_const_none; + NVIC_DisableIRQ(SUBGHZ_Radio_IRQn); + __HAL_RCC_SUBGHZ_RADIO_FORCE_RESET(); + __HAL_RCC_SUBGHZ_RADIO_RELEASE_RESET(); +} + +STATIC mp_obj_t subghz_cs(mp_obj_t value) { + // Treat the same as normal SPI - truthy is "unselected", + // falsey is active low "selected", + if (mp_obj_is_true(value)) { + LL_PWR_UnselectSUBGHZSPI_NSS(); + } else { + LL_PWR_SelectSUBGHZSPI_NSS(); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(subghz_cs_obj, subghz_cs); + +STATIC mp_obj_t subghz_irq(mp_obj_t handler) { + MP_STATE_PORT(subghz_callback) = handler; + + if (mp_obj_is_true(handler)) { + HAL_NVIC_ClearPendingIRQ(SUBGHZ_Radio_IRQn); + HAL_NVIC_EnableIRQ(SUBGHZ_Radio_IRQn); + } else { + HAL_NVIC_DisableIRQ(SUBGHZ_Radio_IRQn); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(subghz_irq_obj, subghz_irq); + +STATIC mp_obj_t subghz_is_busy(void) { + // Read the raw unmasked busy signal. This should be checked before driving + // CS low to start a command. + // + // Reads the raw RFBUSYS not the masked RFBUSYMS, in contradiction to EM0453 + // 6.3 "Radio busy management". This is because the RFBUSYMS signal doesn't + // seem to match the reference manual. Observed behaviour matches this bug + // report instead: https://community.st.com/s/question/0D53W000014zFx9SAE + // + // Reading RFBUSYS won't cause any problems here provided a new SPI command + // isn't immediately after the previous command, which shouldn't be possible + // with MicroPython. + return mp_obj_new_bool(LL_PWR_IsActiveFlag_RFBUSYS()); + +} +MP_DEFINE_CONST_FUN_OBJ_0(subghz_is_busy_obj, subghz_is_busy); + +MP_REGISTER_ROOT_POINTER(mp_obj_t subghz_callback); + +#endif // STM32WL diff --git a/ports/stm32/subghz.h b/ports/stm32/subghz.h new file mode 100644 index 0000000000..f8678cd087 --- /dev/null +++ b/ports/stm32/subghz.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Angus Gratton + * + * 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. + */ +#ifndef MICROPY_INCLUDED_STM32_SUBGHZ_H +#define MICROPY_INCLUDED_STM32_SUBGHZ_H + +#include "py/obj.h" + +// Interface to the STM32WL series "SUBGHZ Radio" module + +void subghz_init(void); +void subghz_deinit(void); + +MP_DECLARE_CONST_FUN_OBJ_1(subghz_cs_obj); +MP_DECLARE_CONST_FUN_OBJ_1(subghz_irq_obj); +MP_DECLARE_CONST_FUN_OBJ_0(subghz_is_busy_obj); + +#endif From 2919a9fbf33b2e9c0cfeeb73e1a7240d70b5310d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Aug 2023 11:53:03 +1000 Subject: [PATCH 055/121] stm32/modstm: Add MICROPY_PY_STM_CONST flag, clear it for STM32WL5. MICROPY_PY_STM_CONST defaults to 1 if MICROPY_PY_STM is set. Overriding to 0 disables the named register peripheral constants being including in the stm32 module. This saves about 7.5KB of code size for the STM32WL55, which is significant as this SoC doesn't have a lot of flash. Signed-off-by: Angus Gratton --- ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h | 3 ++- ports/stm32/make-stmconst.py | 4 ++-- ports/stm32/modstm.c | 2 ++ ports/stm32/mpconfigboard_common.h | 7 ++++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h index c87fcdea9b..843e855ce7 100644 --- a/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WL55/mpconfigboard.h @@ -14,7 +14,8 @@ #define MICROPY_PY_SOCKET (0) #define MICROPY_PY_NETWORK (0) #define MICROPY_PY_ONEWIRE (0) -#define MICROPY_PY_STM (1) +#define MICROPY_PY_STM (1) // for subghz radio functions +#define MICROPY_PY_STM_CONST (0) // saves size, no named registers #define MICROPY_PY_PYB_LEGACY (0) #define MICROPY_PY_HEAPQ (0) diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py index 49b5c1a17b..4e4f2d7155 100644 --- a/ports/stm32/make-stmconst.py +++ b/ports/stm32/make-stmconst.py @@ -319,10 +319,10 @@ def main(): print("") with open(args.qstr_filename, "wt") as qstr_file: - print("#if MICROPY_PY_STM", file=qstr_file) + print("#if MICROPY_PY_STM_CONST", file=qstr_file) for qstr in sorted(needed_qstrs): print("Q({})".format(qstr), file=qstr_file) - print("#endif // MICROPY_PY_STM", file=qstr_file) + print("#endif // MICROPY_PY_STM_CONST", file=qstr_file) with open(args.mpz_filename, "wt") as mpz_file: for mpz in sorted(needed_mpzs): diff --git a/ports/stm32/modstm.c b/ports/stm32/modstm.c index 53bc0db79c..251360594a 100644 --- a/ports/stm32/modstm.c +++ b/ports/stm32/modstm.c @@ -45,7 +45,9 @@ STATIC const mp_rom_map_elem_t stm_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + #if MICROPY_PY_STM_CONST #include "genhdr/modstm_const.h" + #endif #if defined(STM32WB) { MP_ROM_QSTR(MP_QSTR_rfcore_status), MP_ROM_PTR(&rfcore_status_obj) }, diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 3331b38400..611a08252d 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -32,11 +32,16 @@ /*****************************************************************************/ // Feature settings with defaults -// Whether to include the stm module, with peripheral register constants +// Whether to include the stm module #ifndef MICROPY_PY_STM #define MICROPY_PY_STM (1) #endif +// Whether to include named register constants in the stm module +#ifndef MICROPY_PY_STM_CONST +#define MICROPY_PY_STM_CONST (MICROPY_PY_STM) +#endif + // Whether to include the pyb module #ifndef MICROPY_PY_PYB #define MICROPY_PY_PYB (1) From f007d0aa3d91df70a79c5ebded7ac303c451f63f Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 23:05:26 +1000 Subject: [PATCH 056/121] nrf/boards: Rename all nRF boards to use uppercase. This is to match all the other ports. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/nrf/Makefile | 4 +- ports/nrf/README.md | 62 +++++++++---------- .../board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../pins.csv | 0 .../board.c | 0 .../board.json | 0 .../deploy.md | 0 .../manifest.py | 0 .../modules/imu.py | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 2 +- .../nano_bootloader.ld | 0 .../pins.csv | 0 .../board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../{arduino_primo => ARDUINO_PRIMO}/pins.csv | 0 .../board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../pins.csv | 0 .../{dvk_bl652 => DVK_BL652}/board.json | 0 .../{dvk_bl652 => DVK_BL652}/mpconfigboard.h | 0 .../{dvk_bl652 => DVK_BL652}/mpconfigboard.mk | 0 .../boards/{dvk_bl652 => DVK_BL652}/pins.csv | 0 .../{evk_nina_b1 => EVK_NINA_B1}/board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../{evk_nina_b1 => EVK_NINA_B1}/pins.csv | 0 .../{evk_nina_b3 => EVK_NINA_B3}/board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../{evk_nina_b3 => EVK_NINA_B3}/pins.csv | 0 .../{feather52 => FEATHER52}/board.json | 0 .../{feather52 => FEATHER52}/mpconfigboard.h | 0 .../{feather52 => FEATHER52}/mpconfigboard.mk | 0 .../boards/{feather52 => FEATHER52}/pins.csv | 0 .../board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../pins.csv | 0 .../board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../pins.csv | 0 .../boards/{microbit => MICROBIT}/board.json | 0 .../custom_nrf51822_s110_microbit.ld | 0 .../{microbit => MICROBIT}/modules/AUTHORS | 0 .../{microbit => MICROBIT}/modules/LICENSE | 0 .../modules/boardmodules.h | 0 .../modules/boardmodules.mk | 2 +- .../{microbit => MICROBIT}/modules/iters.c | 0 .../{microbit => MICROBIT}/modules/iters.h | 0 .../modules/microbitconstimage.c | 0 .../modules/microbitconstimage.h | 0 .../modules/microbitconstimagetuples.c | 0 .../modules/microbitdisplay.c | 0 .../modules/microbitdisplay.h | 0 .../modules/microbitfont.h | 0 .../modules/microbitimage.c | 0 .../modules/microbitimage.h | 0 .../modules/modmicrobit.c | 0 .../modules/modmicrobit.h | 0 .../{microbit => MICROBIT}/mpconfigboard.h | 0 .../{microbit => MICROBIT}/mpconfigboard.mk | 2 +- .../boards/{microbit => MICROBIT}/pins.csv | 0 .../README.md | 0 .../board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../pins.csv | 0 .../board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../pins.csv | 0 .../boards/{pca10000 => PCA10000}/board.json | 0 .../{pca10000 => PCA10000}/mpconfigboard.h | 0 .../{pca10000 => PCA10000}/mpconfigboard.mk | 0 .../boards/{pca10000 => PCA10000}/pins.csv | 0 .../boards/{pca10001 => PCA10001}/board.json | 0 .../{pca10001 => PCA10001}/mpconfigboard.h | 0 .../{pca10001 => PCA10001}/mpconfigboard.mk | 0 .../boards/{pca10001 => PCA10001}/pins.csv | 0 .../boards/{pca10028 => PCA10028}/board.json | 0 .../{pca10028 => PCA10028}/mpconfigboard.h | 0 .../{pca10028 => PCA10028}/mpconfigboard.mk | 0 .../boards/{pca10028 => PCA10028}/pins.csv | 0 .../boards/{pca10031 => PCA10031}/board.json | 0 .../{pca10031 => PCA10031}/mpconfigboard.h | 0 .../{pca10031 => PCA10031}/mpconfigboard.mk | 0 .../boards/{pca10031 => PCA10031}/pins.csv | 0 .../boards/{pca10040 => PCA10040}/board.json | 0 .../{pca10040 => PCA10040}/mpconfigboard.h | 0 .../{pca10040 => PCA10040}/mpconfigboard.mk | 0 .../boards/{pca10040 => PCA10040}/pins.csv | 0 .../boards/{pca10056 => PCA10056}/board.json | 0 .../{pca10056 => PCA10056}/mpconfigboard.h | 0 .../{pca10056 => PCA10056}/mpconfigboard.mk | 0 .../boards/{pca10056 => PCA10056}/pins.csv | 0 .../boards/{pca10059 => PCA10059}/board.json | 0 .../modules/boardmodules.h | 0 .../modules/boardmodules.mk | 2 +- .../modules/recover_uicr_regout0.c | 0 .../{pca10059 => PCA10059}/mpconfigboard.h | 0 .../{pca10059 => PCA10059}/mpconfigboard.mk | 0 .../boards/{pca10059 => PCA10059}/pins.csv | 0 .../boards/{pca10090 => PCA10090}/board.json | 0 .../{pca10090 => PCA10090}/mpconfigboard.h | 0 .../{pca10090 => PCA10090}/mpconfigboard.mk | 0 .../boards/{pca10090 => PCA10090}/pins.csv | 0 .../XIAO_bootloader.ld | 0 .../board.c | 0 .../board.json | 0 .../deploy.md | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 2 +- .../pins.csv | 0 .../{wt51822_s4at => WT51822_S4AT}/board.json | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../{wt51822_s4at => WT51822_S4AT}/pins.csv | 0 tools/ci.sh | 8 +-- 124 files changed, 42 insertions(+), 42 deletions(-) rename ports/nrf/boards/{actinius_icarus => ACTINIUS_ICARUS}/board.json (100%) rename ports/nrf/boards/{actinius_icarus => ACTINIUS_ICARUS}/mpconfigboard.h (100%) rename ports/nrf/boards/{actinius_icarus => ACTINIUS_ICARUS}/mpconfigboard.mk (100%) rename ports/nrf/boards/{actinius_icarus => ACTINIUS_ICARUS}/pins.csv (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/board.c (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/board.json (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/deploy.md (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/manifest.py (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/modules/imu.py (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/mpconfigboard.h (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/mpconfigboard.mk (77%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/nano_bootloader.ld (100%) rename ports/nrf/boards/{arduino_nano_33_ble_sense => ARDUINO_NANO_33_BLE_SENSE}/pins.csv (100%) rename ports/nrf/boards/{arduino_primo => ARDUINO_PRIMO}/board.json (100%) rename ports/nrf/boards/{arduino_primo => ARDUINO_PRIMO}/mpconfigboard.h (100%) rename ports/nrf/boards/{arduino_primo => ARDUINO_PRIMO}/mpconfigboard.mk (100%) rename ports/nrf/boards/{arduino_primo => ARDUINO_PRIMO}/pins.csv (100%) rename ports/nrf/boards/{blueio_tag_evim => BLUEIO_TAG_EVIM}/board.json (100%) rename ports/nrf/boards/{blueio_tag_evim => BLUEIO_TAG_EVIM}/mpconfigboard.h (100%) rename ports/nrf/boards/{blueio_tag_evim => BLUEIO_TAG_EVIM}/mpconfigboard.mk (100%) rename ports/nrf/boards/{blueio_tag_evim => BLUEIO_TAG_EVIM}/pins.csv (100%) rename ports/nrf/boards/{dvk_bl652 => DVK_BL652}/board.json (100%) rename ports/nrf/boards/{dvk_bl652 => DVK_BL652}/mpconfigboard.h (100%) rename ports/nrf/boards/{dvk_bl652 => DVK_BL652}/mpconfigboard.mk (100%) rename ports/nrf/boards/{dvk_bl652 => DVK_BL652}/pins.csv (100%) rename ports/nrf/boards/{evk_nina_b1 => EVK_NINA_B1}/board.json (100%) rename ports/nrf/boards/{evk_nina_b1 => EVK_NINA_B1}/mpconfigboard.h (100%) rename ports/nrf/boards/{evk_nina_b1 => EVK_NINA_B1}/mpconfigboard.mk (100%) rename ports/nrf/boards/{evk_nina_b1 => EVK_NINA_B1}/pins.csv (100%) rename ports/nrf/boards/{evk_nina_b3 => EVK_NINA_B3}/board.json (100%) rename ports/nrf/boards/{evk_nina_b3 => EVK_NINA_B3}/mpconfigboard.h (100%) rename ports/nrf/boards/{evk_nina_b3 => EVK_NINA_B3}/mpconfigboard.mk (100%) rename ports/nrf/boards/{evk_nina_b3 => EVK_NINA_B3}/pins.csv (100%) rename ports/nrf/boards/{feather52 => FEATHER52}/board.json (100%) rename ports/nrf/boards/{feather52 => FEATHER52}/mpconfigboard.h (100%) rename ports/nrf/boards/{feather52 => FEATHER52}/mpconfigboard.mk (100%) rename ports/nrf/boards/{feather52 => FEATHER52}/pins.csv (100%) rename ports/nrf/boards/{ibk_blyst_nano => IBK_BLYST_NANO}/board.json (100%) rename ports/nrf/boards/{ibk_blyst_nano => IBK_BLYST_NANO}/mpconfigboard.h (100%) rename ports/nrf/boards/{ibk_blyst_nano => IBK_BLYST_NANO}/mpconfigboard.mk (100%) rename ports/nrf/boards/{ibk_blyst_nano => IBK_BLYST_NANO}/pins.csv (100%) rename ports/nrf/boards/{idk_blyst_nano => IDK_BLYST_NANO}/board.json (100%) rename ports/nrf/boards/{idk_blyst_nano => IDK_BLYST_NANO}/mpconfigboard.h (100%) rename ports/nrf/boards/{idk_blyst_nano => IDK_BLYST_NANO}/mpconfigboard.mk (100%) rename ports/nrf/boards/{idk_blyst_nano => IDK_BLYST_NANO}/pins.csv (100%) rename ports/nrf/boards/{microbit => MICROBIT}/board.json (100%) rename ports/nrf/boards/{microbit => MICROBIT}/custom_nrf51822_s110_microbit.ld (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/AUTHORS (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/LICENSE (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/boardmodules.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/boardmodules.mk (91%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/iters.c (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/iters.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitconstimage.c (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitconstimage.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitconstimagetuples.c (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitdisplay.c (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitdisplay.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitfont.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitimage.c (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/microbitimage.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/modmicrobit.c (100%) rename ports/nrf/boards/{microbit => MICROBIT}/modules/modmicrobit.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/mpconfigboard.h (100%) rename ports/nrf/boards/{microbit => MICROBIT}/mpconfigboard.mk (79%) rename ports/nrf/boards/{microbit => MICROBIT}/pins.csv (100%) rename ports/nrf/boards/{nrf52840-mdk-usb-dongle => NRF52840_MDK_USB_DONGLE}/README.md (100%) rename ports/nrf/boards/{nrf52840-mdk-usb-dongle => NRF52840_MDK_USB_DONGLE}/board.json (100%) rename ports/nrf/boards/{nrf52840-mdk-usb-dongle => NRF52840_MDK_USB_DONGLE}/mpconfigboard.h (100%) rename ports/nrf/boards/{nrf52840-mdk-usb-dongle => NRF52840_MDK_USB_DONGLE}/mpconfigboard.mk (100%) rename ports/nrf/boards/{nrf52840-mdk-usb-dongle => NRF52840_MDK_USB_DONGLE}/pins.csv (100%) rename ports/nrf/boards/{particle_xenon => PARTICLE_XENON}/board.json (100%) rename ports/nrf/boards/{particle_xenon => PARTICLE_XENON}/mpconfigboard.h (100%) rename ports/nrf/boards/{particle_xenon => PARTICLE_XENON}/mpconfigboard.mk (100%) rename ports/nrf/boards/{particle_xenon => PARTICLE_XENON}/pins.csv (100%) rename ports/nrf/boards/{pca10000 => PCA10000}/board.json (100%) rename ports/nrf/boards/{pca10000 => PCA10000}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10000 => PCA10000}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10000 => PCA10000}/pins.csv (100%) rename ports/nrf/boards/{pca10001 => PCA10001}/board.json (100%) rename ports/nrf/boards/{pca10001 => PCA10001}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10001 => PCA10001}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10001 => PCA10001}/pins.csv (100%) rename ports/nrf/boards/{pca10028 => PCA10028}/board.json (100%) rename ports/nrf/boards/{pca10028 => PCA10028}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10028 => PCA10028}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10028 => PCA10028}/pins.csv (100%) rename ports/nrf/boards/{pca10031 => PCA10031}/board.json (100%) rename ports/nrf/boards/{pca10031 => PCA10031}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10031 => PCA10031}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10031 => PCA10031}/pins.csv (100%) rename ports/nrf/boards/{pca10040 => PCA10040}/board.json (100%) rename ports/nrf/boards/{pca10040 => PCA10040}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10040 => PCA10040}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10040 => PCA10040}/pins.csv (100%) rename ports/nrf/boards/{pca10056 => PCA10056}/board.json (100%) rename ports/nrf/boards/{pca10056 => PCA10056}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10056 => PCA10056}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10056 => PCA10056}/pins.csv (100%) rename ports/nrf/boards/{pca10059 => PCA10059}/board.json (100%) rename ports/nrf/boards/{pca10059 => PCA10059}/modules/boardmodules.h (100%) rename ports/nrf/boards/{pca10059 => PCA10059}/modules/boardmodules.mk (85%) rename ports/nrf/boards/{pca10059 => PCA10059}/modules/recover_uicr_regout0.c (100%) rename ports/nrf/boards/{pca10059 => PCA10059}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10059 => PCA10059}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10059 => PCA10059}/pins.csv (100%) rename ports/nrf/boards/{pca10090 => PCA10090}/board.json (100%) rename ports/nrf/boards/{pca10090 => PCA10090}/mpconfigboard.h (100%) rename ports/nrf/boards/{pca10090 => PCA10090}/mpconfigboard.mk (100%) rename ports/nrf/boards/{pca10090 => PCA10090}/pins.csv (100%) rename ports/nrf/boards/{seeed_xiao_nrf52 => SEEED_XIAO_NRF52}/XIAO_bootloader.ld (100%) rename ports/nrf/boards/{seeed_xiao_nrf52 => SEEED_XIAO_NRF52}/board.c (100%) rename ports/nrf/boards/{seeed_xiao_nrf52 => SEEED_XIAO_NRF52}/board.json (100%) rename ports/nrf/boards/{seeed_xiao_nrf52 => SEEED_XIAO_NRF52}/deploy.md (100%) rename ports/nrf/boards/{seeed_xiao_nrf52 => SEEED_XIAO_NRF52}/mpconfigboard.h (100%) rename ports/nrf/boards/{seeed_xiao_nrf52 => SEEED_XIAO_NRF52}/mpconfigboard.mk (82%) rename ports/nrf/boards/{seeed_xiao_nrf52 => SEEED_XIAO_NRF52}/pins.csv (100%) rename ports/nrf/boards/{wt51822_s4at => WT51822_S4AT}/board.json (100%) rename ports/nrf/boards/{wt51822_s4at => WT51822_S4AT}/mpconfigboard.h (100%) rename ports/nrf/boards/{wt51822_s4at => WT51822_S4AT}/mpconfigboard.mk (100%) rename ports/nrf/boards/{wt51822_s4at => WT51822_S4AT}/pins.csv (100%) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 3a4b0ef23d..5e9e31ad01 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -4,8 +4,8 @@ ifdef BOARD_DIR # the path as the board name. BOARD ?= $(notdir $(BOARD_DIR:/=)) else -# If not given on the command line, then default to pca10040. -BOARD ?= pca10040 +# If not given on the command line, then default to PCA10040. +BOARD ?= PCA10040 BOARD_DIR ?= boards/$(BOARD) endif diff --git a/ports/nrf/README.md b/ports/nrf/README.md index fde04e61f1..889ead5d4d 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -41,7 +41,7 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. * [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK) * [PCA10059](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle) * [Particle Xenon](https://docs.particle.io/xenon/) - * [nRF52840 MDK USB Dongle](boards/nrf52840-mdk-usb-dongle/README.md) + * [nRF52840 MDK USB Dongle](boards/NRF52840_MDK_USB_DONGLE/README.md) * nRF9160 * [PCA10090](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF9160-DK) * [Actinius Icarus](https://www.actinius.com/icarus) @@ -63,8 +63,8 @@ By default, the PCA10040 (nrf52832) is used as compile target. To build and flas Alternatively the target board could be defined: make submodules - make BOARD=pca10040 - make BOARD=pca10040 deploy + make BOARD=PCA10040 + make BOARD=PCA10040 deploy ## Compile without LTO enabled @@ -73,7 +73,7 @@ targets in the nrf-port. The `-flto` linker flag can be toggled easily by using the argument LTO when building. The example below shows how to disable LTO for the compilation: - make BOARD=pca10040 LTO=0 + make BOARD=PCA10040 LTO=0 **Note**: There have been several issues with use of LTO in conjunction with GNU ARM Embedded Toolchain 7.2.1/4Q17. It's recommended to use a toolchain after @@ -88,11 +88,11 @@ First prepare the bluetooth folder by downloading Bluetooth LE stacks and header If the Bluetooth stacks has been downloaded, compile the target with the following command: - make BOARD=pca10040 SD=s132 + make BOARD=PCA10040 SD=s132 The **make sd** will trigger a flash of the bluetooth stack before that application is flashed. Note that **make sd** will perform a full erase of the chip, which could cause 3rd party bootloaders to also be wiped. - make BOARD=pca10040 SD=s132 sd + make BOARD=PCA10040 SD=s132 sd Note: further tuning of features to include in bluetooth or even setting up the device to use REPL over Bluetooth can be configured in the `bluetooth_conf.h`. @@ -104,7 +104,7 @@ it in the specific target board's `mpconfigboard.mk`. For example: - make BOARD=pca10040 FROZEN_MANIFEST=path/to/manifest.py + make BOARD=PCA10040 FROZEN_MANIFEST=path/to/manifest.py In case of using the target board's makefile, add a line similar to this: @@ -117,7 +117,7 @@ As the `oofatfs` module is not having header guards that can exclude the impleme For example: - make BOARD=pca10040 MICROPY_VFS_FAT=1 + make BOARD=PCA10040 MICROPY_VFS_FAT=1 ## Enable MICROPY_VFS_LFS1 or MICROPY_VFS_LFS2 @@ -127,7 +127,7 @@ or `MICROPY_VFS_LFS2` can be set. This will be in addition of setting For example: - make BOARD=pca10056 MICROPY_VFS_LFS2=1 + make BOARD=PCA10056 MICROPY_VFS_LFS2=1 ## Set file system size @@ -141,7 +141,7 @@ linker script syntax as it is passed directly. For example, if we want to override the default file system size set by the linker scripts to use 256K: - make BOARD=pca10056 MICROPY_VFS_LFS2=1 FS_SIZE=256K + make BOARD=PCA10056 MICROPY_VFS_LFS2=1 FS_SIZE=256K Also note that changing this size between builds might cause loss of files present from a previous firmware as it will format the file system due to a new @@ -151,25 +151,25 @@ location. Target Board (BOARD) | Bluetooth Stack (SD) | Bluetooth Support | Bootloader | Default Flash Util ---------------------|-------------------------|------------------------|----------------|------------------- -microbit | s110 | Peripheral | | [PyOCD](#pyocdopenocd-targets) -pca10000 | s110 | Peripheral | | [Segger](#segger-targets) -pca10001 | s110 | Peripheral | | [Segger](#segger-targets) -pca10028 | s110 | Peripheral | | [Segger](#segger-targets) -pca10031 | s110 | Peripheral | | [Segger](#segger-targets) -wt51822_s4at | s110 | Peripheral | | Manual, see [datasheet](https://4tronix.co.uk/picobot2/WT51822-S4AT.pdf) for pinout -pca10040 | s132 | Peripheral and Central | | [Segger](#segger-targets) -feather52 | s132 | Peripheral and Central | | Manual, SWDIO and SWCLK solder points on the bottom side of the board -arduino_primo | s132 | Peripheral and Central | | [PyOCD](#pyocdopenocd-targets) -ibk_blyst_nano | s132 | Peripheral and Central | | [IDAP](#idap-midap-link-targets) -idk_blyst_nano | s132 | Peripheral and Central | | [IDAP](#idap-midap-link-targets) -blueio_tag_evim | s132 | Peripheral and Central | | [IDAP](#idap-midap-link-targets) -evk_nina_b1 | s132 | Peripheral and Central | | [Segger](#segger-targets) -pca10056 | s140 | Peripheral and Central | | [Segger](#segger-targets) -pca10059 | s140 | Peripheral and Central | OpenBootloader | [nrfutil](#nrfutil-targets) -particle_xenon | s140 | Peripheral and Central | | [Black Magic Probe](#black-magic-probe-targets) -nrf52840-mdk-usb-dongle | s140 | Peripheral and Central | OpenBootloader | [nrfutil](#nrfutil-targets) -pca10090 | None (bsdlib.a) | None (LTE/GNSS) | | [Segger](#segger-targets) -actinius_icarus | None (bsdlib.a) | None (LTE/GNSS) | | [Segger](#segger-targets) +MICROBIT | s110 | Peripheral | | [PyOCD](#pyocdopenocd-targets) +PCA10000 | s110 | Peripheral | | [Segger](#segger-targets) +PCA10001 | s110 | Peripheral | | [Segger](#segger-targets) +PCA10028 | s110 | Peripheral | | [Segger](#segger-targets) +PCA10031 | s110 | Peripheral | | [Segger](#segger-targets) +WT51822_S4AT | s110 | Peripheral | | Manual, see [datasheet](https://4tronix.co.uk/picobot2/WT51822-S4AT.pdf) for pinout +PCA10040 | s132 | Peripheral and Central | | [Segger](#segger-targets) +FEATHER52 | s132 | Peripheral and Central | | Manual, SWDIO and SWCLK solder points on the bottom side of the board +ARDUINO_PRIMO | s132 | Peripheral and Central | | [PyOCD](#pyocdopenocd-targets) +IBK_BLYST_NANO | s132 | Peripheral and Central | | [IDAP](#idap-midap-link-targets) +IDK_BLYST_NANO | s132 | Peripheral and Central | | [IDAP](#idap-midap-link-targets) +BLUEIO_TAG_EVIM | s132 | Peripheral and Central | | [IDAP](#idap-midap-link-targets) +EVK_NINA_B1 | s132 | Peripheral and Central | | [Segger](#segger-targets) +PCA10056 | s140 | Peripheral and Central | | [Segger](#segger-targets) +PCA10059 | s140 | Peripheral and Central | OpenBootloader | [nrfutil](#nrfutil-targets) +PARTICLE_XENON | s140 | Peripheral and Central | | [Black Magic Probe](#black-magic-probe-targets) +NRF52840_MDK_USB_DONGLE | s140 | Peripheral and Central | OpenBootloader | [nrfutil](#nrfutil-targets) +PCA10090 | None (bsdlib.a) | None (LTE/GNSS) | | [Segger](#segger-targets) +ACTINIUS_ICARUS | None (bsdlib.a) | None (LTE/GNSS) | | [Segger](#segger-targets) ## IDAP-M/IDAP-Link Targets @@ -218,7 +218,7 @@ to trim of the MBR in case SoftDevice flashing is requested. `nrfutil` as flashing backend also requires a serial port parameter to be defined in addition to the `deploy` target of make. For example: - make BOARD=nrf52840-mdk-usb-dongle NRFUTIL_PORT=/dev/ttyACM0 deploy + make BOARD=NRF52840_MDK_USB_DONGLE NRFUTIL_PORT=/dev/ttyACM0 deploy If the target device is connected to `/dev/ttyACM0` serial port, the `NRFUTIL_PORT` parameter to make can be elided as it is the default serial @@ -228,7 +228,7 @@ When enabling Bluetooth LE, as with the other flash utils, the SoftDevice needs to be flashed in the first firmware update. This can be done by issuing the `sd` target instead of `deploy`. For example: - make BOARD=nrf52840-mdk-usb-dongle SD=s140 NRFUTIL_PORT=/dev/ttyACM0 sd + make BOARD=NRF52840_MDK_USB_DONGLE SD=s140 NRFUTIL_PORT=/dev/ttyACM0 sd ## Bluetooth LE REPL diff --git a/ports/nrf/boards/actinius_icarus/board.json b/ports/nrf/boards/ACTINIUS_ICARUS/board.json similarity index 100% rename from ports/nrf/boards/actinius_icarus/board.json rename to ports/nrf/boards/ACTINIUS_ICARUS/board.json diff --git a/ports/nrf/boards/actinius_icarus/mpconfigboard.h b/ports/nrf/boards/ACTINIUS_ICARUS/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/actinius_icarus/mpconfigboard.h rename to ports/nrf/boards/ACTINIUS_ICARUS/mpconfigboard.h diff --git a/ports/nrf/boards/actinius_icarus/mpconfigboard.mk b/ports/nrf/boards/ACTINIUS_ICARUS/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/actinius_icarus/mpconfigboard.mk rename to ports/nrf/boards/ACTINIUS_ICARUS/mpconfigboard.mk diff --git a/ports/nrf/boards/actinius_icarus/pins.csv b/ports/nrf/boards/ACTINIUS_ICARUS/pins.csv similarity index 100% rename from ports/nrf/boards/actinius_icarus/pins.csv rename to ports/nrf/boards/ACTINIUS_ICARUS/pins.csv diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/board.c b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/board.c similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/board.c rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/board.c diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/board.json b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/board.json similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/board.json rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/board.json diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/deploy.md b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/deploy.md similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/deploy.md rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/deploy.md diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/manifest.py b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/manifest.py similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/manifest.py rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/manifest.py diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/modules/imu.py b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/modules/imu.py similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/modules/imu.py rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/modules/imu.py diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.h b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.h rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/mpconfigboard.h diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.mk b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/mpconfigboard.mk similarity index 77% rename from ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.mk rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/mpconfigboard.mk index cb2ff5c6b8..148a9f1017 100644 --- a/ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.mk +++ b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/mpconfigboard.mk @@ -4,7 +4,7 @@ MCU_SUB_VARIANT = nrf52840 SOFTDEV_VERSION = 6.1.1 SD=s140 -LD_FILES += boards/arduino_nano_33_ble_sense/nano_bootloader.ld boards/nrf52840_1M_256k.ld +LD_FILES += boards/ARDUINO_NANO_33_BLE_SENSE/nano_bootloader.ld boards/nrf52840_1M_256k.ld NRF_DEFINES += -DNRF52840_XXAA diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/nano_bootloader.ld b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/nano_bootloader.ld similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/nano_bootloader.ld rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/nano_bootloader.ld diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/pins.csv b/ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/pins.csv similarity index 100% rename from ports/nrf/boards/arduino_nano_33_ble_sense/pins.csv rename to ports/nrf/boards/ARDUINO_NANO_33_BLE_SENSE/pins.csv diff --git a/ports/nrf/boards/arduino_primo/board.json b/ports/nrf/boards/ARDUINO_PRIMO/board.json similarity index 100% rename from ports/nrf/boards/arduino_primo/board.json rename to ports/nrf/boards/ARDUINO_PRIMO/board.json diff --git a/ports/nrf/boards/arduino_primo/mpconfigboard.h b/ports/nrf/boards/ARDUINO_PRIMO/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/arduino_primo/mpconfigboard.h rename to ports/nrf/boards/ARDUINO_PRIMO/mpconfigboard.h diff --git a/ports/nrf/boards/arduino_primo/mpconfigboard.mk b/ports/nrf/boards/ARDUINO_PRIMO/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/arduino_primo/mpconfigboard.mk rename to ports/nrf/boards/ARDUINO_PRIMO/mpconfigboard.mk diff --git a/ports/nrf/boards/arduino_primo/pins.csv b/ports/nrf/boards/ARDUINO_PRIMO/pins.csv similarity index 100% rename from ports/nrf/boards/arduino_primo/pins.csv rename to ports/nrf/boards/ARDUINO_PRIMO/pins.csv diff --git a/ports/nrf/boards/blueio_tag_evim/board.json b/ports/nrf/boards/BLUEIO_TAG_EVIM/board.json similarity index 100% rename from ports/nrf/boards/blueio_tag_evim/board.json rename to ports/nrf/boards/BLUEIO_TAG_EVIM/board.json diff --git a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h b/ports/nrf/boards/BLUEIO_TAG_EVIM/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/blueio_tag_evim/mpconfigboard.h rename to ports/nrf/boards/BLUEIO_TAG_EVIM/mpconfigboard.h diff --git a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk b/ports/nrf/boards/BLUEIO_TAG_EVIM/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/blueio_tag_evim/mpconfigboard.mk rename to ports/nrf/boards/BLUEIO_TAG_EVIM/mpconfigboard.mk diff --git a/ports/nrf/boards/blueio_tag_evim/pins.csv b/ports/nrf/boards/BLUEIO_TAG_EVIM/pins.csv similarity index 100% rename from ports/nrf/boards/blueio_tag_evim/pins.csv rename to ports/nrf/boards/BLUEIO_TAG_EVIM/pins.csv diff --git a/ports/nrf/boards/dvk_bl652/board.json b/ports/nrf/boards/DVK_BL652/board.json similarity index 100% rename from ports/nrf/boards/dvk_bl652/board.json rename to ports/nrf/boards/DVK_BL652/board.json diff --git a/ports/nrf/boards/dvk_bl652/mpconfigboard.h b/ports/nrf/boards/DVK_BL652/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/dvk_bl652/mpconfigboard.h rename to ports/nrf/boards/DVK_BL652/mpconfigboard.h diff --git a/ports/nrf/boards/dvk_bl652/mpconfigboard.mk b/ports/nrf/boards/DVK_BL652/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/dvk_bl652/mpconfigboard.mk rename to ports/nrf/boards/DVK_BL652/mpconfigboard.mk diff --git a/ports/nrf/boards/dvk_bl652/pins.csv b/ports/nrf/boards/DVK_BL652/pins.csv similarity index 100% rename from ports/nrf/boards/dvk_bl652/pins.csv rename to ports/nrf/boards/DVK_BL652/pins.csv diff --git a/ports/nrf/boards/evk_nina_b1/board.json b/ports/nrf/boards/EVK_NINA_B1/board.json similarity index 100% rename from ports/nrf/boards/evk_nina_b1/board.json rename to ports/nrf/boards/EVK_NINA_B1/board.json diff --git a/ports/nrf/boards/evk_nina_b1/mpconfigboard.h b/ports/nrf/boards/EVK_NINA_B1/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/evk_nina_b1/mpconfigboard.h rename to ports/nrf/boards/EVK_NINA_B1/mpconfigboard.h diff --git a/ports/nrf/boards/evk_nina_b1/mpconfigboard.mk b/ports/nrf/boards/EVK_NINA_B1/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/evk_nina_b1/mpconfigboard.mk rename to ports/nrf/boards/EVK_NINA_B1/mpconfigboard.mk diff --git a/ports/nrf/boards/evk_nina_b1/pins.csv b/ports/nrf/boards/EVK_NINA_B1/pins.csv similarity index 100% rename from ports/nrf/boards/evk_nina_b1/pins.csv rename to ports/nrf/boards/EVK_NINA_B1/pins.csv diff --git a/ports/nrf/boards/evk_nina_b3/board.json b/ports/nrf/boards/EVK_NINA_B3/board.json similarity index 100% rename from ports/nrf/boards/evk_nina_b3/board.json rename to ports/nrf/boards/EVK_NINA_B3/board.json diff --git a/ports/nrf/boards/evk_nina_b3/mpconfigboard.h b/ports/nrf/boards/EVK_NINA_B3/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/evk_nina_b3/mpconfigboard.h rename to ports/nrf/boards/EVK_NINA_B3/mpconfigboard.h diff --git a/ports/nrf/boards/evk_nina_b3/mpconfigboard.mk b/ports/nrf/boards/EVK_NINA_B3/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/evk_nina_b3/mpconfigboard.mk rename to ports/nrf/boards/EVK_NINA_B3/mpconfigboard.mk diff --git a/ports/nrf/boards/evk_nina_b3/pins.csv b/ports/nrf/boards/EVK_NINA_B3/pins.csv similarity index 100% rename from ports/nrf/boards/evk_nina_b3/pins.csv rename to ports/nrf/boards/EVK_NINA_B3/pins.csv diff --git a/ports/nrf/boards/feather52/board.json b/ports/nrf/boards/FEATHER52/board.json similarity index 100% rename from ports/nrf/boards/feather52/board.json rename to ports/nrf/boards/FEATHER52/board.json diff --git a/ports/nrf/boards/feather52/mpconfigboard.h b/ports/nrf/boards/FEATHER52/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/feather52/mpconfigboard.h rename to ports/nrf/boards/FEATHER52/mpconfigboard.h diff --git a/ports/nrf/boards/feather52/mpconfigboard.mk b/ports/nrf/boards/FEATHER52/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/feather52/mpconfigboard.mk rename to ports/nrf/boards/FEATHER52/mpconfigboard.mk diff --git a/ports/nrf/boards/feather52/pins.csv b/ports/nrf/boards/FEATHER52/pins.csv similarity index 100% rename from ports/nrf/boards/feather52/pins.csv rename to ports/nrf/boards/FEATHER52/pins.csv diff --git a/ports/nrf/boards/ibk_blyst_nano/board.json b/ports/nrf/boards/IBK_BLYST_NANO/board.json similarity index 100% rename from ports/nrf/boards/ibk_blyst_nano/board.json rename to ports/nrf/boards/IBK_BLYST_NANO/board.json diff --git a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h b/ports/nrf/boards/IBK_BLYST_NANO/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h rename to ports/nrf/boards/IBK_BLYST_NANO/mpconfigboard.h diff --git a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk b/ports/nrf/boards/IBK_BLYST_NANO/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/ibk_blyst_nano/mpconfigboard.mk rename to ports/nrf/boards/IBK_BLYST_NANO/mpconfigboard.mk diff --git a/ports/nrf/boards/ibk_blyst_nano/pins.csv b/ports/nrf/boards/IBK_BLYST_NANO/pins.csv similarity index 100% rename from ports/nrf/boards/ibk_blyst_nano/pins.csv rename to ports/nrf/boards/IBK_BLYST_NANO/pins.csv diff --git a/ports/nrf/boards/idk_blyst_nano/board.json b/ports/nrf/boards/IDK_BLYST_NANO/board.json similarity index 100% rename from ports/nrf/boards/idk_blyst_nano/board.json rename to ports/nrf/boards/IDK_BLYST_NANO/board.json diff --git a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h b/ports/nrf/boards/IDK_BLYST_NANO/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/idk_blyst_nano/mpconfigboard.h rename to ports/nrf/boards/IDK_BLYST_NANO/mpconfigboard.h diff --git a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk b/ports/nrf/boards/IDK_BLYST_NANO/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/idk_blyst_nano/mpconfigboard.mk rename to ports/nrf/boards/IDK_BLYST_NANO/mpconfigboard.mk diff --git a/ports/nrf/boards/idk_blyst_nano/pins.csv b/ports/nrf/boards/IDK_BLYST_NANO/pins.csv similarity index 100% rename from ports/nrf/boards/idk_blyst_nano/pins.csv rename to ports/nrf/boards/IDK_BLYST_NANO/pins.csv diff --git a/ports/nrf/boards/microbit/board.json b/ports/nrf/boards/MICROBIT/board.json similarity index 100% rename from ports/nrf/boards/microbit/board.json rename to ports/nrf/boards/MICROBIT/board.json diff --git a/ports/nrf/boards/microbit/custom_nrf51822_s110_microbit.ld b/ports/nrf/boards/MICROBIT/custom_nrf51822_s110_microbit.ld similarity index 100% rename from ports/nrf/boards/microbit/custom_nrf51822_s110_microbit.ld rename to ports/nrf/boards/MICROBIT/custom_nrf51822_s110_microbit.ld diff --git a/ports/nrf/boards/microbit/modules/AUTHORS b/ports/nrf/boards/MICROBIT/modules/AUTHORS similarity index 100% rename from ports/nrf/boards/microbit/modules/AUTHORS rename to ports/nrf/boards/MICROBIT/modules/AUTHORS diff --git a/ports/nrf/boards/microbit/modules/LICENSE b/ports/nrf/boards/MICROBIT/modules/LICENSE similarity index 100% rename from ports/nrf/boards/microbit/modules/LICENSE rename to ports/nrf/boards/MICROBIT/modules/LICENSE diff --git a/ports/nrf/boards/microbit/modules/boardmodules.h b/ports/nrf/boards/MICROBIT/modules/boardmodules.h similarity index 100% rename from ports/nrf/boards/microbit/modules/boardmodules.h rename to ports/nrf/boards/MICROBIT/modules/boardmodules.h diff --git a/ports/nrf/boards/microbit/modules/boardmodules.mk b/ports/nrf/boards/MICROBIT/modules/boardmodules.mk similarity index 91% rename from ports/nrf/boards/microbit/modules/boardmodules.mk rename to ports/nrf/boards/MICROBIT/modules/boardmodules.mk index eb8f108615..84a606c448 100644 --- a/ports/nrf/boards/microbit/modules/boardmodules.mk +++ b/ports/nrf/boards/MICROBIT/modules/boardmodules.mk @@ -1,4 +1,4 @@ -BOARD_MICROBIT_DIR = boards/microbit/modules +BOARD_MICROBIT_DIR = boards/MICROBIT/modules INC += -I./$(BOARD_MICROBIT_DIR) CFLAGS += -DBOARD_SPECIFIC_MODULES diff --git a/ports/nrf/boards/microbit/modules/iters.c b/ports/nrf/boards/MICROBIT/modules/iters.c similarity index 100% rename from ports/nrf/boards/microbit/modules/iters.c rename to ports/nrf/boards/MICROBIT/modules/iters.c diff --git a/ports/nrf/boards/microbit/modules/iters.h b/ports/nrf/boards/MICROBIT/modules/iters.h similarity index 100% rename from ports/nrf/boards/microbit/modules/iters.h rename to ports/nrf/boards/MICROBIT/modules/iters.h diff --git a/ports/nrf/boards/microbit/modules/microbitconstimage.c b/ports/nrf/boards/MICROBIT/modules/microbitconstimage.c similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitconstimage.c rename to ports/nrf/boards/MICROBIT/modules/microbitconstimage.c diff --git a/ports/nrf/boards/microbit/modules/microbitconstimage.h b/ports/nrf/boards/MICROBIT/modules/microbitconstimage.h similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitconstimage.h rename to ports/nrf/boards/MICROBIT/modules/microbitconstimage.h diff --git a/ports/nrf/boards/microbit/modules/microbitconstimagetuples.c b/ports/nrf/boards/MICROBIT/modules/microbitconstimagetuples.c similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitconstimagetuples.c rename to ports/nrf/boards/MICROBIT/modules/microbitconstimagetuples.c diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.c b/ports/nrf/boards/MICROBIT/modules/microbitdisplay.c similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitdisplay.c rename to ports/nrf/boards/MICROBIT/modules/microbitdisplay.c diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.h b/ports/nrf/boards/MICROBIT/modules/microbitdisplay.h similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitdisplay.h rename to ports/nrf/boards/MICROBIT/modules/microbitdisplay.h diff --git a/ports/nrf/boards/microbit/modules/microbitfont.h b/ports/nrf/boards/MICROBIT/modules/microbitfont.h similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitfont.h rename to ports/nrf/boards/MICROBIT/modules/microbitfont.h diff --git a/ports/nrf/boards/microbit/modules/microbitimage.c b/ports/nrf/boards/MICROBIT/modules/microbitimage.c similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitimage.c rename to ports/nrf/boards/MICROBIT/modules/microbitimage.c diff --git a/ports/nrf/boards/microbit/modules/microbitimage.h b/ports/nrf/boards/MICROBIT/modules/microbitimage.h similarity index 100% rename from ports/nrf/boards/microbit/modules/microbitimage.h rename to ports/nrf/boards/MICROBIT/modules/microbitimage.h diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.c b/ports/nrf/boards/MICROBIT/modules/modmicrobit.c similarity index 100% rename from ports/nrf/boards/microbit/modules/modmicrobit.c rename to ports/nrf/boards/MICROBIT/modules/modmicrobit.c diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.h b/ports/nrf/boards/MICROBIT/modules/modmicrobit.h similarity index 100% rename from ports/nrf/boards/microbit/modules/modmicrobit.h rename to ports/nrf/boards/MICROBIT/modules/modmicrobit.h diff --git a/ports/nrf/boards/microbit/mpconfigboard.h b/ports/nrf/boards/MICROBIT/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/microbit/mpconfigboard.h rename to ports/nrf/boards/MICROBIT/mpconfigboard.h diff --git a/ports/nrf/boards/microbit/mpconfigboard.mk b/ports/nrf/boards/MICROBIT/mpconfigboard.mk similarity index 79% rename from ports/nrf/boards/microbit/mpconfigboard.mk rename to ports/nrf/boards/MICROBIT/mpconfigboard.mk index 6fdd2bc500..6c7e1b46b9 100644 --- a/ports/nrf/boards/microbit/mpconfigboard.mk +++ b/ports/nrf/boards/MICROBIT/mpconfigboard.mk @@ -4,7 +4,7 @@ MCU_SUB_VARIANT = nrf51822 SOFTDEV_VERSION = 8.0.0 ifneq ($(SD),) -LD_FILES += boards/microbit/custom_nrf51822_s110_microbit.ld +LD_FILES += boards/MICROBIT/custom_nrf51822_s110_microbit.ld FROZEN_MANIFEST ?= else MICROPY_VFS_LFS2 = 1 diff --git a/ports/nrf/boards/microbit/pins.csv b/ports/nrf/boards/MICROBIT/pins.csv similarity index 100% rename from ports/nrf/boards/microbit/pins.csv rename to ports/nrf/boards/MICROBIT/pins.csv diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/README.md b/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/README.md similarity index 100% rename from ports/nrf/boards/nrf52840-mdk-usb-dongle/README.md rename to ports/nrf/boards/NRF52840_MDK_USB_DONGLE/README.md diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json b/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/board.json similarity index 100% rename from ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json rename to ports/nrf/boards/NRF52840_MDK_USB_DONGLE/board.json diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.h b/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.h rename to ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.h diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.mk b/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.mk rename to ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.mk diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/pins.csv b/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/pins.csv similarity index 100% rename from ports/nrf/boards/nrf52840-mdk-usb-dongle/pins.csv rename to ports/nrf/boards/NRF52840_MDK_USB_DONGLE/pins.csv diff --git a/ports/nrf/boards/particle_xenon/board.json b/ports/nrf/boards/PARTICLE_XENON/board.json similarity index 100% rename from ports/nrf/boards/particle_xenon/board.json rename to ports/nrf/boards/PARTICLE_XENON/board.json diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.h b/ports/nrf/boards/PARTICLE_XENON/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/particle_xenon/mpconfigboard.h rename to ports/nrf/boards/PARTICLE_XENON/mpconfigboard.h diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.mk b/ports/nrf/boards/PARTICLE_XENON/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/particle_xenon/mpconfigboard.mk rename to ports/nrf/boards/PARTICLE_XENON/mpconfigboard.mk diff --git a/ports/nrf/boards/particle_xenon/pins.csv b/ports/nrf/boards/PARTICLE_XENON/pins.csv similarity index 100% rename from ports/nrf/boards/particle_xenon/pins.csv rename to ports/nrf/boards/PARTICLE_XENON/pins.csv diff --git a/ports/nrf/boards/pca10000/board.json b/ports/nrf/boards/PCA10000/board.json similarity index 100% rename from ports/nrf/boards/pca10000/board.json rename to ports/nrf/boards/PCA10000/board.json diff --git a/ports/nrf/boards/pca10000/mpconfigboard.h b/ports/nrf/boards/PCA10000/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10000/mpconfigboard.h rename to ports/nrf/boards/PCA10000/mpconfigboard.h diff --git a/ports/nrf/boards/pca10000/mpconfigboard.mk b/ports/nrf/boards/PCA10000/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10000/mpconfigboard.mk rename to ports/nrf/boards/PCA10000/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10000/pins.csv b/ports/nrf/boards/PCA10000/pins.csv similarity index 100% rename from ports/nrf/boards/pca10000/pins.csv rename to ports/nrf/boards/PCA10000/pins.csv diff --git a/ports/nrf/boards/pca10001/board.json b/ports/nrf/boards/PCA10001/board.json similarity index 100% rename from ports/nrf/boards/pca10001/board.json rename to ports/nrf/boards/PCA10001/board.json diff --git a/ports/nrf/boards/pca10001/mpconfigboard.h b/ports/nrf/boards/PCA10001/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10001/mpconfigboard.h rename to ports/nrf/boards/PCA10001/mpconfigboard.h diff --git a/ports/nrf/boards/pca10001/mpconfigboard.mk b/ports/nrf/boards/PCA10001/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10001/mpconfigboard.mk rename to ports/nrf/boards/PCA10001/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10001/pins.csv b/ports/nrf/boards/PCA10001/pins.csv similarity index 100% rename from ports/nrf/boards/pca10001/pins.csv rename to ports/nrf/boards/PCA10001/pins.csv diff --git a/ports/nrf/boards/pca10028/board.json b/ports/nrf/boards/PCA10028/board.json similarity index 100% rename from ports/nrf/boards/pca10028/board.json rename to ports/nrf/boards/PCA10028/board.json diff --git a/ports/nrf/boards/pca10028/mpconfigboard.h b/ports/nrf/boards/PCA10028/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10028/mpconfigboard.h rename to ports/nrf/boards/PCA10028/mpconfigboard.h diff --git a/ports/nrf/boards/pca10028/mpconfigboard.mk b/ports/nrf/boards/PCA10028/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10028/mpconfigboard.mk rename to ports/nrf/boards/PCA10028/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10028/pins.csv b/ports/nrf/boards/PCA10028/pins.csv similarity index 100% rename from ports/nrf/boards/pca10028/pins.csv rename to ports/nrf/boards/PCA10028/pins.csv diff --git a/ports/nrf/boards/pca10031/board.json b/ports/nrf/boards/PCA10031/board.json similarity index 100% rename from ports/nrf/boards/pca10031/board.json rename to ports/nrf/boards/PCA10031/board.json diff --git a/ports/nrf/boards/pca10031/mpconfigboard.h b/ports/nrf/boards/PCA10031/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10031/mpconfigboard.h rename to ports/nrf/boards/PCA10031/mpconfigboard.h diff --git a/ports/nrf/boards/pca10031/mpconfigboard.mk b/ports/nrf/boards/PCA10031/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10031/mpconfigboard.mk rename to ports/nrf/boards/PCA10031/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10031/pins.csv b/ports/nrf/boards/PCA10031/pins.csv similarity index 100% rename from ports/nrf/boards/pca10031/pins.csv rename to ports/nrf/boards/PCA10031/pins.csv diff --git a/ports/nrf/boards/pca10040/board.json b/ports/nrf/boards/PCA10040/board.json similarity index 100% rename from ports/nrf/boards/pca10040/board.json rename to ports/nrf/boards/PCA10040/board.json diff --git a/ports/nrf/boards/pca10040/mpconfigboard.h b/ports/nrf/boards/PCA10040/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10040/mpconfigboard.h rename to ports/nrf/boards/PCA10040/mpconfigboard.h diff --git a/ports/nrf/boards/pca10040/mpconfigboard.mk b/ports/nrf/boards/PCA10040/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10040/mpconfigboard.mk rename to ports/nrf/boards/PCA10040/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10040/pins.csv b/ports/nrf/boards/PCA10040/pins.csv similarity index 100% rename from ports/nrf/boards/pca10040/pins.csv rename to ports/nrf/boards/PCA10040/pins.csv diff --git a/ports/nrf/boards/pca10056/board.json b/ports/nrf/boards/PCA10056/board.json similarity index 100% rename from ports/nrf/boards/pca10056/board.json rename to ports/nrf/boards/PCA10056/board.json diff --git a/ports/nrf/boards/pca10056/mpconfigboard.h b/ports/nrf/boards/PCA10056/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10056/mpconfigboard.h rename to ports/nrf/boards/PCA10056/mpconfigboard.h diff --git a/ports/nrf/boards/pca10056/mpconfigboard.mk b/ports/nrf/boards/PCA10056/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10056/mpconfigboard.mk rename to ports/nrf/boards/PCA10056/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10056/pins.csv b/ports/nrf/boards/PCA10056/pins.csv similarity index 100% rename from ports/nrf/boards/pca10056/pins.csv rename to ports/nrf/boards/PCA10056/pins.csv diff --git a/ports/nrf/boards/pca10059/board.json b/ports/nrf/boards/PCA10059/board.json similarity index 100% rename from ports/nrf/boards/pca10059/board.json rename to ports/nrf/boards/PCA10059/board.json diff --git a/ports/nrf/boards/pca10059/modules/boardmodules.h b/ports/nrf/boards/PCA10059/modules/boardmodules.h similarity index 100% rename from ports/nrf/boards/pca10059/modules/boardmodules.h rename to ports/nrf/boards/PCA10059/modules/boardmodules.h diff --git a/ports/nrf/boards/pca10059/modules/boardmodules.mk b/ports/nrf/boards/PCA10059/modules/boardmodules.mk similarity index 85% rename from ports/nrf/boards/pca10059/modules/boardmodules.mk rename to ports/nrf/boards/PCA10059/modules/boardmodules.mk index 413790fbea..d1457cde7c 100644 --- a/ports/nrf/boards/pca10059/modules/boardmodules.mk +++ b/ports/nrf/boards/PCA10059/modules/boardmodules.mk @@ -1,4 +1,4 @@ -BOARD_PCA10059_DIR = boards/pca10059/modules +BOARD_PCA10059_DIR = boards/PCA10059/modules INC += -I./$(BOARD_PCA10059_DIR) CFLAGS += -DBOARD_SPECIFIC_MODULES diff --git a/ports/nrf/boards/pca10059/modules/recover_uicr_regout0.c b/ports/nrf/boards/PCA10059/modules/recover_uicr_regout0.c similarity index 100% rename from ports/nrf/boards/pca10059/modules/recover_uicr_regout0.c rename to ports/nrf/boards/PCA10059/modules/recover_uicr_regout0.c diff --git a/ports/nrf/boards/pca10059/mpconfigboard.h b/ports/nrf/boards/PCA10059/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10059/mpconfigboard.h rename to ports/nrf/boards/PCA10059/mpconfigboard.h diff --git a/ports/nrf/boards/pca10059/mpconfigboard.mk b/ports/nrf/boards/PCA10059/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10059/mpconfigboard.mk rename to ports/nrf/boards/PCA10059/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10059/pins.csv b/ports/nrf/boards/PCA10059/pins.csv similarity index 100% rename from ports/nrf/boards/pca10059/pins.csv rename to ports/nrf/boards/PCA10059/pins.csv diff --git a/ports/nrf/boards/pca10090/board.json b/ports/nrf/boards/PCA10090/board.json similarity index 100% rename from ports/nrf/boards/pca10090/board.json rename to ports/nrf/boards/PCA10090/board.json diff --git a/ports/nrf/boards/pca10090/mpconfigboard.h b/ports/nrf/boards/PCA10090/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/pca10090/mpconfigboard.h rename to ports/nrf/boards/PCA10090/mpconfigboard.h diff --git a/ports/nrf/boards/pca10090/mpconfigboard.mk b/ports/nrf/boards/PCA10090/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/pca10090/mpconfigboard.mk rename to ports/nrf/boards/PCA10090/mpconfigboard.mk diff --git a/ports/nrf/boards/pca10090/pins.csv b/ports/nrf/boards/PCA10090/pins.csv similarity index 100% rename from ports/nrf/boards/pca10090/pins.csv rename to ports/nrf/boards/PCA10090/pins.csv diff --git a/ports/nrf/boards/seeed_xiao_nrf52/XIAO_bootloader.ld b/ports/nrf/boards/SEEED_XIAO_NRF52/XIAO_bootloader.ld similarity index 100% rename from ports/nrf/boards/seeed_xiao_nrf52/XIAO_bootloader.ld rename to ports/nrf/boards/SEEED_XIAO_NRF52/XIAO_bootloader.ld diff --git a/ports/nrf/boards/seeed_xiao_nrf52/board.c b/ports/nrf/boards/SEEED_XIAO_NRF52/board.c similarity index 100% rename from ports/nrf/boards/seeed_xiao_nrf52/board.c rename to ports/nrf/boards/SEEED_XIAO_NRF52/board.c diff --git a/ports/nrf/boards/seeed_xiao_nrf52/board.json b/ports/nrf/boards/SEEED_XIAO_NRF52/board.json similarity index 100% rename from ports/nrf/boards/seeed_xiao_nrf52/board.json rename to ports/nrf/boards/SEEED_XIAO_NRF52/board.json diff --git a/ports/nrf/boards/seeed_xiao_nrf52/deploy.md b/ports/nrf/boards/SEEED_XIAO_NRF52/deploy.md similarity index 100% rename from ports/nrf/boards/seeed_xiao_nrf52/deploy.md rename to ports/nrf/boards/SEEED_XIAO_NRF52/deploy.md diff --git a/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.h b/ports/nrf/boards/SEEED_XIAO_NRF52/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.h rename to ports/nrf/boards/SEEED_XIAO_NRF52/mpconfigboard.h diff --git a/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.mk b/ports/nrf/boards/SEEED_XIAO_NRF52/mpconfigboard.mk similarity index 82% rename from ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.mk rename to ports/nrf/boards/SEEED_XIAO_NRF52/mpconfigboard.mk index c2fc219187..1f495a9c64 100644 --- a/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.mk +++ b/ports/nrf/boards/SEEED_XIAO_NRF52/mpconfigboard.mk @@ -3,7 +3,7 @@ MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52840 SOFTDEV_VERSION = 7.3.0 SD=s140 -LD_FILES += boards/seeed_xiao_nrf52/XIAO_bootloader.ld boards/nrf52840_1M_256k.ld +LD_FILES += boards/SEEED_XIAO_NRF52/XIAO_bootloader.ld boards/nrf52840_1M_256k.ld NRF_DEFINES += -DNRF52840_XXAA diff --git a/ports/nrf/boards/seeed_xiao_nrf52/pins.csv b/ports/nrf/boards/SEEED_XIAO_NRF52/pins.csv similarity index 100% rename from ports/nrf/boards/seeed_xiao_nrf52/pins.csv rename to ports/nrf/boards/SEEED_XIAO_NRF52/pins.csv diff --git a/ports/nrf/boards/wt51822_s4at/board.json b/ports/nrf/boards/WT51822_S4AT/board.json similarity index 100% rename from ports/nrf/boards/wt51822_s4at/board.json rename to ports/nrf/boards/WT51822_S4AT/board.json diff --git a/ports/nrf/boards/wt51822_s4at/mpconfigboard.h b/ports/nrf/boards/WT51822_S4AT/mpconfigboard.h similarity index 100% rename from ports/nrf/boards/wt51822_s4at/mpconfigboard.h rename to ports/nrf/boards/WT51822_S4AT/mpconfigboard.h diff --git a/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk b/ports/nrf/boards/WT51822_S4AT/mpconfigboard.mk similarity index 100% rename from ports/nrf/boards/wt51822_s4at/mpconfigboard.mk rename to ports/nrf/boards/WT51822_S4AT/mpconfigboard.mk diff --git a/ports/nrf/boards/wt51822_s4at/pins.csv b/ports/nrf/boards/WT51822_S4AT/pins.csv similarity index 100% rename from ports/nrf/boards/wt51822_s4at/pins.csv rename to ports/nrf/boards/WT51822_S4AT/pins.csv diff --git a/tools/ci.sh b/tools/ci.sh index 98e78dc78a..b9bfb7eef8 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -204,10 +204,10 @@ function ci_nrf_build { ports/nrf/drivers/bluetooth/download_ble_stack.sh s140_nrf52_6_1_1 make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/nrf submodules - make ${MAKEOPTS} -C ports/nrf BOARD=pca10040 - make ${MAKEOPTS} -C ports/nrf BOARD=microbit - make ${MAKEOPTS} -C ports/nrf BOARD=pca10056 SD=s140 - make ${MAKEOPTS} -C ports/nrf BOARD=pca10090 + make ${MAKEOPTS} -C ports/nrf BOARD=PCA10040 + make ${MAKEOPTS} -C ports/nrf BOARD=MICROBIT + make ${MAKEOPTS} -C ports/nrf BOARD=PCA10056 SD=s140 + make ${MAKEOPTS} -C ports/nrf BOARD=PCA10090 } ######################################################################################## From b5836e7252f78831d4ce45778a5f84c46f096df5 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 23:12:42 +1000 Subject: [PATCH 057/121] esp32: Use uppercase variant names. This is to support a future change to add the variant name to the build directory and therefore should be the same style as the board name. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/boards/GENERIC/board.json | 10 +++++----- ports/esp32/boards/GENERIC/mpconfigboard.cmake | 8 ++++---- ports/esp32/boards/GENERIC_S3/board.json | 2 +- ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake | 2 +- ports/esp32/boards/UM_TINYPICO/board.json | 2 +- tools/autobuild/build-boards.sh | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json index d08fcfec15..8e2f224328 100644 --- a/ports/esp32/boards/GENERIC/board.json +++ b/ports/esp32/boards/GENERIC/board.json @@ -17,11 +17,11 @@ "thumbnail": "", "url": "https://www.espressif.com/en/products/modules", "variants": { - "idf3": "Compiled with IDF 3.x", - "d2wd": "ESP32 D2WD", - "spiram": "Support for SPIRAM / WROVER", - "unicore": "ESP32 Unicore", - "ota": "Support for OTA" + "IDF3": "Compiled with IDF 3.x", + "D2WD": "ESP32 D2WD", + "SPIRAM": "Support for SPIRAM / WROVER", + "UNICORE": "ESP32 Unicore", + "OTA": "Support for OTA" }, "vendor": "Espressif" } diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.cmake b/ports/esp32/boards/GENERIC/mpconfigboard.cmake index 29096c2768..14b47b3e59 100644 --- a/ports/esp32/boards/GENERIC/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC/mpconfigboard.cmake @@ -3,7 +3,7 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.ble ) -if(MICROPY_BOARD_VARIANT STREQUAL "d2wd") +if(MICROPY_BOARD_VARIANT STREQUAL "D2WD") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} boards/GENERIC/sdkconfig.d2wd @@ -14,7 +14,7 @@ if(MICROPY_BOARD_VARIANT STREQUAL "d2wd") ) endif() -if(MICROPY_BOARD_VARIANT STREQUAL "ota") +if(MICROPY_BOARD_VARIANT STREQUAL "OTA") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} boards/GENERIC/sdkconfig.ota @@ -25,7 +25,7 @@ if(MICROPY_BOARD_VARIANT STREQUAL "ota") ) endif() -if(MICROPY_BOARD_VARIANT STREQUAL "spiram") +if(MICROPY_BOARD_VARIANT STREQUAL "SPIRAM") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} boards/sdkconfig.spiram @@ -36,7 +36,7 @@ if(MICROPY_BOARD_VARIANT STREQUAL "spiram") ) endif() -if(MICROPY_BOARD_VARIANT STREQUAL "unicore") +if(MICROPY_BOARD_VARIANT STREQUAL "UNICORE") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} boards/GENERIC/sdkconfig.unicore diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/GENERIC_S3/board.json index be2170c12f..671936c922 100644 --- a/ports/esp32/boards/GENERIC_S3/board.json +++ b/ports/esp32/boards/GENERIC_S3/board.json @@ -18,6 +18,6 @@ "url": "https://www.espressif.com/en/products/modules", "vendor": "Espressif", "variants": { - "spiram-oct": "Support for Octal-SPIRAM" + "SPIRAM_OCT": "Support for Octal-SPIRAM" } } diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake index bd163f9f33..29974aaba4 100644 --- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake +++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake @@ -8,7 +8,7 @@ set(SDKCONFIG_DEFAULTS boards/GENERIC_S3/sdkconfig.board ) -if(MICROPY_BOARD_VARIANT STREQUAL "spiram-oct") +if(MICROPY_BOARD_VARIANT STREQUAL "SPIRAM_OCT") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} boards/sdkconfig.240mhz diff --git a/ports/esp32/boards/UM_TINYPICO/board.json b/ports/esp32/boards/UM_TINYPICO/board.json index f6ba9ddb0e..3e15e99112 100644 --- a/ports/esp32/boards/UM_TINYPICO/board.json +++ b/ports/esp32/boards/UM_TINYPICO/board.json @@ -24,7 +24,7 @@ "thumbnail": "", "url": "https://www.tinypico.com/", "variants": { - "idf3": "Compiled with IDF 3.x" + "IDF3": "Compiled with IDF 3.x" }, "vendor": "Unexpected Maker" } diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh index f75ccba398..82d7f36057 100755 --- a/tools/autobuild/build-boards.sh +++ b/tools/autobuild/build-boards.sh @@ -55,10 +55,10 @@ function build_board { $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && copy_artefacts $dest_dir $descr $fw_tag $build_dir $@ rm -rf $build_dir - # Query variants from board.json and build them. Ignore the special "idf3" + # Query variants from board.json and build them. Ignore the special "IDF3" # variant for ESP32 boards (this allows the downloads page to still have # the idf3 files for older releases that used to be explicitly built). - for variant in `cat $board_json | python3 -c "import json,sys; print(' '.join(v for v in json.load(sys.stdin).get('variants', {}).keys() if v != 'idf3'))"`; do + for variant in `cat $board_json | python3 -c "import json,sys; print(' '.join(v for v in json.load(sys.stdin).get('variants', {}).keys() if v != 'IDF3'))"`; do local variant_build_dir=$build_dir-$variant echo "building variant $descr $board $variant" $MICROPY_AUTOBUILD_MAKE BOARD=$board BOARD_VARIANT=$variant BUILD=$variant_build_dir && copy_artefacts $dest_dir $descr-$variant $fw_tag $variant_build_dir $@ From 45845acf6d1cba5705f11abd08d8491bcc35c0a5 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 23:12:57 +1000 Subject: [PATCH 058/121] rp2: Use uppercase variant names. This is to support a future change to add the variant name to the build directory and therefore should be the same style as the board name. This only affects the WEACTSTUDIO board. Also standardises on a convention for naming flash-size variants. Normally we would write e.g. 2MiB, but in uppercase, it's awkward to write 2MIB, so instead use 2M, 512K, etc for variant names, but use 2MiB when not constrained by case (e.g. a regular filename). This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/rp2/boards/WEACTSTUDIO/README.md | 11 ++++------- ports/rp2/boards/WEACTSTUDIO/board.json | 6 +++--- ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake | 14 +++++++------- .../{weactstudio_16mb.h => weactstudio_16MiB.h} | 0 .../{weactstudio_2mb.h => weactstudio_2MiB.h} | 0 .../{weactstudio_4mb.h => weactstudio_4MiB.h} | 0 .../{weactstudio_8mb.h => weactstudio_8MiB.h} | 0 7 files changed, 14 insertions(+), 17 deletions(-) rename ports/rp2/boards/WEACTSTUDIO/{weactstudio_16mb.h => weactstudio_16MiB.h} (100%) rename ports/rp2/boards/WEACTSTUDIO/{weactstudio_2mb.h => weactstudio_2MiB.h} (100%) rename ports/rp2/boards/WEACTSTUDIO/{weactstudio_4mb.h => weactstudio_4MiB.h} (100%) rename ports/rp2/boards/WEACTSTUDIO/{weactstudio_8mb.h => weactstudio_8MiB.h} (100%) diff --git a/ports/rp2/boards/WEACTSTUDIO/README.md b/ports/rp2/boards/WEACTSTUDIO/README.md index ae0acfd2c7..1d55350900 100644 --- a/ports/rp2/boards/WEACTSTUDIO/README.md +++ b/ports/rp2/boards/WEACTSTUDIO/README.md @@ -9,18 +9,15 @@ repository containing information on the board. ## Build notes -Builds can be configured with the `BOARD_VARIANT` parameter. Valid variants -can be displayed with the `query-variant` target. An example: +By default the firmware supports boards with 16MiB flash. This can be +configured using the `BOARD_VARIANT` parameter. The valid options are +`FLASH_2M`, 'FLASH_4M', and 'FLASH_8M'. ```bash > cd ports/rp2 -> make BOARD=WEACTSTUDIO query-variants -VARIANTS: flash_2mb flash_4mb flash_8mb flash_16mb -> make BOARD=WEACTSTUDIO BOARD_VARIANT=flash_8mb submodules all # Build the 8 MiB variant +> make BOARD=WEACTSTUDIO BOARD_VARIANT=FLASH_8M submodules all # Build the 8 MiB variant ``` -`flash_16mb` is the default if `BOARD_VARIANT` is not supplied. - ## Board-specific modules The `board` module contains definitions for the onboard LED and user button. diff --git a/ports/rp2/boards/WEACTSTUDIO/board.json b/ports/rp2/boards/WEACTSTUDIO/board.json index 3a3f2f741f..223bbdc07b 100644 --- a/ports/rp2/boards/WEACTSTUDIO/board.json +++ b/ports/rp2/boards/WEACTSTUDIO/board.json @@ -15,9 +15,9 @@ "product": "WeAct Studio RP2040", "url": "https://github.com/WeActTC/WeActStudio.RP2040CoreBoard", "variants": { - "flash_2mb": "2 MiB Flash", - "flash_4mb": "4 MiB Flash", - "flash_8mb": "8 MiB Flash" + "FLASH_2MB": "2 MiB Flash", + "FLASH_4MB": "4 MiB Flash", + "FLASH_8MB": "8 MiB Flash" }, "vendor": "WeAct" } diff --git a/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake b/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake index 28a30f4580..848b50f604 100644 --- a/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake +++ b/ports/rp2/boards/WEACTSTUDIO/mpconfigboard.cmake @@ -8,17 +8,17 @@ list(APPEND PICO_BOARD_HEADER_DIRS ${MICROPY_BOARD_DIR}) set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) # Select the 16MB variant as the default -set(PICO_BOARD "weactstudio_16mb") +set(PICO_BOARD "weactstudio_16MiB") # Provide different variants for the downloads page -if(MICROPY_BOARD_VARIANT STREQUAL "flash_2mb") - set(PICO_BOARD "weactstudio_2mb") +if(MICROPY_BOARD_VARIANT STREQUAL "FLASH_2M") + set(PICO_BOARD "weactstudio_2MiB") endif() -if(MICROPY_BOARD_VARIANT STREQUAL "flash_4mb") - set(PICO_BOARD "weactstudio_4mb") +if(MICROPY_BOARD_VARIANT STREQUAL "FLASH_4M") + set(PICO_BOARD "weactstudio_4MiB") endif() -if(MICROPY_BOARD_VARIANT STREQUAL "flash_8mb") - set(PICO_BOARD "weactstudio_8mb") +if(MICROPY_BOARD_VARIANT STREQUAL "FLASH_8M") + set(PICO_BOARD "weactstudio_8MiB") endif() diff --git a/ports/rp2/boards/WEACTSTUDIO/weactstudio_16mb.h b/ports/rp2/boards/WEACTSTUDIO/weactstudio_16MiB.h similarity index 100% rename from ports/rp2/boards/WEACTSTUDIO/weactstudio_16mb.h rename to ports/rp2/boards/WEACTSTUDIO/weactstudio_16MiB.h diff --git a/ports/rp2/boards/WEACTSTUDIO/weactstudio_2mb.h b/ports/rp2/boards/WEACTSTUDIO/weactstudio_2MiB.h similarity index 100% rename from ports/rp2/boards/WEACTSTUDIO/weactstudio_2mb.h rename to ports/rp2/boards/WEACTSTUDIO/weactstudio_2MiB.h diff --git a/ports/rp2/boards/WEACTSTUDIO/weactstudio_4mb.h b/ports/rp2/boards/WEACTSTUDIO/weactstudio_4MiB.h similarity index 100% rename from ports/rp2/boards/WEACTSTUDIO/weactstudio_4mb.h rename to ports/rp2/boards/WEACTSTUDIO/weactstudio_4MiB.h diff --git a/ports/rp2/boards/WEACTSTUDIO/weactstudio_8mb.h b/ports/rp2/boards/WEACTSTUDIO/weactstudio_8MiB.h similarity index 100% rename from ports/rp2/boards/WEACTSTUDIO/weactstudio_8mb.h rename to ports/rp2/boards/WEACTSTUDIO/weactstudio_8MiB.h From c3093080b1cfc1606f545ebfba3013be67e73d96 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 23:18:47 +1000 Subject: [PATCH 059/121] stm32: Use uppercase variant names. This is to support a future change to add the variant name to the build directory and therefore should be the same style as the board name. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/stm32/boards/PYBLITEV10/board.json | 8 ++++---- ports/stm32/boards/PYBLITEV10/mpconfigboard.mk | 8 ++++---- ports/stm32/boards/PYBV10/board.json | 8 ++++---- ports/stm32/boards/PYBV10/mpconfigboard.mk | 8 ++++---- ports/stm32/boards/PYBV11/board.json | 8 ++++---- ports/stm32/boards/PYBV11/mpconfigboard.mk | 8 ++++---- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ports/stm32/boards/PYBLITEV10/board.json b/ports/stm32/boards/PYBLITEV10/board.json index ce98ba7de7..38bb7fe1a0 100644 --- a/ports/stm32/boards/PYBLITEV10/board.json +++ b/ports/stm32/boards/PYBLITEV10/board.json @@ -15,10 +15,10 @@ "thumbnail": "", "url": "https://store.micropython.org/product/PYBLITEv1.0", "variants": { - "dp": "Double-precision float", - "dp-thread": "Double precision float + Threads", - "network": "Wiznet 5200 Driver", - "thread": "Threading" + "DP": "Double-precision float", + "DP_THREAD": "Double precision float + Threads", + "NETWORK": "Wiznet 5200 Driver", + "THREAD": "Threading" }, "vendor": "George Robotics" } diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk index afee27e94f..1fe609cbb5 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk @@ -6,20 +6,20 @@ TEXT0_ADDR = 0x08000000 TEXT1_ADDR = 0x08020000 # Provide different variants for the downloads page. -ifeq ($(BOARD_VARIANT),dp) +ifeq ($(BOARD_VARIANT),DP) MICROPY_FLOAT_IMPL=double endif -ifeq ($(BOARD_VARIANT),thread) +ifeq ($(BOARD_VARIANT),THREAD) CFLAGS += -DMICROPY_PY_THREAD=1 endif -ifeq ($(BOARD_VARIANT),dp-thread) +ifeq ($(BOARD_VARIANT),DP_THREAD) MICROPY_FLOAT_IMPL=double CFLAGS += -DMICROPY_PY_THREAD=1 endif -ifeq ($(BOARD_VARIANT),network) +ifeq ($(BOARD_VARIANT),NETWORK) MICROPY_PY_NETWORK_WIZNET5K=5200 endif diff --git a/ports/stm32/boards/PYBV10/board.json b/ports/stm32/boards/PYBV10/board.json index 2907b8fc45..5f8f906172 100644 --- a/ports/stm32/boards/PYBV10/board.json +++ b/ports/stm32/boards/PYBV10/board.json @@ -13,10 +13,10 @@ "thumbnail": "", "url": "", "variants": { - "dp": "Double-precision float", - "dp-thread": "Double precision float + Threads", - "network": "Wiznet 5200 Driver", - "thread": "Threading" + "DP": "Double-precision float", + "DP_THREAD": "Double precision float + Threads", + "NETWORK": "Wiznet 5200 Driver", + "THREAD": "Threading" }, "vendor": "George Robotics" } diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk index d26ebd5ae9..1a4d676319 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk @@ -16,20 +16,20 @@ endif MICROPY_VFS_LFS2 = 1 # Provide different variants for the downloads page. -ifeq ($(BOARD_VARIANT),dp) +ifeq ($(BOARD_VARIANT),DP) MICROPY_FLOAT_IMPL=double endif -ifeq ($(BOARD_VARIANT),thread) +ifeq ($(BOARD_VARIANT),THREAD) CFLAGS += -DMICROPY_PY_THREAD=1 endif -ifeq ($(BOARD_VARIANT),dp-thread) +ifeq ($(BOARD_VARIANT),DP_THREAD) MICROPY_FLOAT_IMPL=double CFLAGS += -DMICROPY_PY_THREAD=1 endif -ifeq ($(BOARD_VARIANT),network) +ifeq ($(BOARD_VARIANT),NETWORK) MICROPY_PY_NETWORK_WIZNET5K=5200 endif diff --git a/ports/stm32/boards/PYBV11/board.json b/ports/stm32/boards/PYBV11/board.json index fe59a7b16d..1fd04310fd 100644 --- a/ports/stm32/boards/PYBV11/board.json +++ b/ports/stm32/boards/PYBV11/board.json @@ -15,10 +15,10 @@ "thumbnail": "", "url": "https://store.micropython.org/product/PYBv1.1", "variants": { - "dp": "Double-precision float", - "dp-thread": "Double precision float + Threads", - "network": "Wiznet 5200 Driver", - "thread": "Threading" + "DP": "Double-precision float", + "DP_THREAD": "Double precision float + Threads", + "NETWORK": "Wiznet 5200 Driver", + "THREAD": "Threading" }, "vendor": "George Robotics" } diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk index df2d70cda1..6dcb2fd1b4 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk @@ -16,20 +16,20 @@ endif MICROPY_VFS_LFS2 = 1 # Provide different variants for the downloads page. -ifeq ($(BOARD_VARIANT),dp) +ifeq ($(BOARD_VARIANT),DP) MICROPY_FLOAT_IMPL=double endif -ifeq ($(BOARD_VARIANT),thread) +ifeq ($(BOARD_VARIANT),THREAD) CFLAGS += -DMICROPY_PY_THREAD=1 endif -ifeq ($(BOARD_VARIANT),dp-thread) +ifeq ($(BOARD_VARIANT),DP_THREAD) MICROPY_FLOAT_IMPL=double CFLAGS += -DMICROPY_PY_THREAD=1 endif -ifeq ($(BOARD_VARIANT),network) +ifeq ($(BOARD_VARIANT),NETWORK) MICROPY_PY_NETWORK_WIZNET5K=5200 endif From 1a99f74063569df0927e1ada0256059fcdef128c Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 23:25:15 +1000 Subject: [PATCH 060/121] ports/*/boards/*/board.json: Remove "id" field. This was used to override the firmware filename generated by the build server (to match the historical name before board definitions existed). Now we're making everything use the board definition name (i.e. the directory name). This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/cc3200/boards/WIPY/board.json | 1 - ports/esp32/boards/GENERIC/board.json | 1 - ports/esp32/boards/GENERIC_C3/board.json | 1 - ports/esp32/boards/SIL_WESP32/board.json | 1 - ports/esp32/boards/UM_FEATHERS2/board.json | 1 - ports/esp32/boards/UM_FEATHERS2NEO/board.json | 1 - ports/esp32/boards/UM_FEATHERS3/board.json | 1 - ports/esp32/boards/UM_PROS3/board.json | 1 - ports/esp32/boards/UM_TINYPICO/board.json | 1 - ports/esp32/boards/UM_TINYS2/board.json | 1 - ports/esp32/boards/UM_TINYS3/board.json | 1 - ports/esp8266/boards/GENERIC/board.json | 1 - ports/esp8266/boards/GENERIC_1M/board.json | 1 - ports/esp8266/boards/GENERIC_512K/board.json | 1 - ports/renesas-ra/boards/EK_RA4M1/board.json | 1 - ports/renesas-ra/boards/EK_RA4W1/board.json | 1 - ports/renesas-ra/boards/EK_RA6M1/board.json | 1 - ports/renesas-ra/boards/EK_RA6M2/board.json | 1 - ports/renesas-ra/boards/RA4M1_CLICKER/board.json | 1 - ports/renesas-ra/boards/VK_RA6M5/board.json | 1 - ports/rp2/boards/PICO/board.json | 1 - ports/rp2/boards/PICO_W/board.json | 1 - ports/stm32/boards/MIKROE_QUAIL/board.json | 1 - ports/stm32/boards/PYBD_SF2/board.json | 1 - ports/stm32/boards/PYBD_SF3/board.json | 1 - ports/stm32/boards/PYBD_SF6/board.json | 1 - ports/stm32/boards/PYBLITEV10/board.json | 1 - ports/stm32/boards/PYBV10/board.json | 1 - ports/stm32/boards/PYBV11/board.json | 1 - 29 files changed, 29 deletions(-) diff --git a/ports/cc3200/boards/WIPY/board.json b/ports/cc3200/boards/WIPY/board.json index 4a5a81f99f..f615953af7 100644 --- a/ports/cc3200/boards/WIPY/board.json +++ b/ports/cc3200/boards/WIPY/board.json @@ -10,7 +10,6 @@ "WiFi", "microSD" ], - "id": "wipy", "images": [ "wipy.jpg" ], diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json index 8e2f224328..0db38c25d3 100644 --- a/ports/esp32/boards/GENERIC/board.json +++ b/ports/esp32/boards/GENERIC/board.json @@ -8,7 +8,6 @@ "External Flash", "WiFi" ], - "id": "esp32", "images": [ "esp32_devkitc.jpg" ], diff --git a/ports/esp32/boards/GENERIC_C3/board.json b/ports/esp32/boards/GENERIC_C3/board.json index c993c87603..4a81d227a0 100644 --- a/ports/esp32/boards/GENERIC_C3/board.json +++ b/ports/esp32/boards/GENERIC_C3/board.json @@ -8,7 +8,6 @@ "External Flash", "WiFi" ], - "id": "esp32c3", "images": [ "esp32c3_devkitmini.jpg" ], diff --git a/ports/esp32/boards/SIL_WESP32/board.json b/ports/esp32/boards/SIL_WESP32/board.json index 5c77b4887a..50dd2cc660 100644 --- a/ports/esp32/boards/SIL_WESP32/board.json +++ b/ports/esp32/boards/SIL_WESP32/board.json @@ -10,7 +10,6 @@ "PoE", "WiFi" ], - "id": "wesp32", "images": [ "wesp32-iso.jpg", "wesp32-top.jpg" diff --git a/ports/esp32/boards/UM_FEATHERS2/board.json b/ports/esp32/boards/UM_FEATHERS2/board.json index 4b6ea88558..4de9a7d4f7 100644 --- a/ports/esp32/boards/UM_FEATHERS2/board.json +++ b/ports/esp32/boards/UM_FEATHERS2/board.json @@ -16,7 +16,6 @@ "features_non_filterable": [ "Second LDO" ], - "id": "featherS2", "images": [ "unexpectedmaker_feathers2.jpg" ], diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.json b/ports/esp32/boards/UM_FEATHERS2NEO/board.json index 51bb02b97b..dfa1f46dc3 100644 --- a/ports/esp32/boards/UM_FEATHERS2NEO/board.json +++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.json @@ -16,7 +16,6 @@ "features_non_filterable": [ "5x5 RGB LED Matrix" ], - "id": "featherS2neo", "images": [ "FeatherS2_Neo_White_Product2.jpg" ], diff --git a/ports/esp32/boards/UM_FEATHERS3/board.json b/ports/esp32/boards/UM_FEATHERS3/board.json index 0ad1ff73be..235d52a12d 100644 --- a/ports/esp32/boards/UM_FEATHERS3/board.json +++ b/ports/esp32/boards/UM_FEATHERS3/board.json @@ -15,7 +15,6 @@ "WiFi" ], "features_non_filterable": [], - "id": "feathers3", "images": [ "unexpectedmaker_feathers3.jpg" ], diff --git a/ports/esp32/boards/UM_PROS3/board.json b/ports/esp32/boards/UM_PROS3/board.json index 3e83a813f4..8efc4e5ab5 100644 --- a/ports/esp32/boards/UM_PROS3/board.json +++ b/ports/esp32/boards/UM_PROS3/board.json @@ -15,7 +15,6 @@ "WiFi" ], "features_non_filterable": [], - "id": "pros3", "images": [ "unexpectedmaker_pros3.jpg" ], diff --git a/ports/esp32/boards/UM_TINYPICO/board.json b/ports/esp32/boards/UM_TINYPICO/board.json index 3e15e99112..bf0b3d2c8c 100644 --- a/ports/esp32/boards/UM_TINYPICO/board.json +++ b/ports/esp32/boards/UM_TINYPICO/board.json @@ -15,7 +15,6 @@ "features_non_filterable": [ "TinyPICO Compatible" ], - "id": "tinypico", "images": [ "tinypico-v2-both.jpg" ], diff --git a/ports/esp32/boards/UM_TINYS2/board.json b/ports/esp32/boards/UM_TINYS2/board.json index b6c94ba9e8..1b4c934dfa 100644 --- a/ports/esp32/boards/UM_TINYS2/board.json +++ b/ports/esp32/boards/UM_TINYS2/board.json @@ -15,7 +15,6 @@ "features_non_filterable": [ "TinyPICO Compatible" ], - "id": "tinys2", "images": [ "TinyS2+Product+Shot.jpg" ], diff --git a/ports/esp32/boards/UM_TINYS3/board.json b/ports/esp32/boards/UM_TINYS3/board.json index 3b7bb13345..27ae46a249 100644 --- a/ports/esp32/boards/UM_TINYS3/board.json +++ b/ports/esp32/boards/UM_TINYS3/board.json @@ -15,7 +15,6 @@ "features_non_filterable": [ "TinyPICO Compatible" ], - "id": "tinys3", "images": [ "unexpectedmaker_tinys3.jpg" ], diff --git a/ports/esp8266/boards/GENERIC/board.json b/ports/esp8266/boards/GENERIC/board.json index ebdd95493b..dffe6d2711 100644 --- a/ports/esp8266/boards/GENERIC/board.json +++ b/ports/esp8266/boards/GENERIC/board.json @@ -7,7 +7,6 @@ "External Flash", "WiFi" ], - "id": "esp8266", "images": [], "mcu": "esp8266", "product": "ESP8266 with 2MiB+ flash", diff --git a/ports/esp8266/boards/GENERIC_1M/board.json b/ports/esp8266/boards/GENERIC_1M/board.json index 5446f29128..4ab5c79df0 100644 --- a/ports/esp8266/boards/GENERIC_1M/board.json +++ b/ports/esp8266/boards/GENERIC_1M/board.json @@ -7,7 +7,6 @@ "External Flash", "WiFi" ], - "id": "esp8266-1m", "images": [], "mcu": "esp8266", "product": "ESP8266 with 1MiB flash", diff --git a/ports/esp8266/boards/GENERIC_512K/board.json b/ports/esp8266/boards/GENERIC_512K/board.json index 1feac4a05c..e035562be7 100644 --- a/ports/esp8266/boards/GENERIC_512K/board.json +++ b/ports/esp8266/boards/GENERIC_512K/board.json @@ -7,7 +7,6 @@ "External Flash", "WiFi" ], - "id": "esp8266-512k", "images": [], "mcu": "esp8266", "product": "ESP8266 with 512kiB flash", diff --git a/ports/renesas-ra/boards/EK_RA4M1/board.json b/ports/renesas-ra/boards/EK_RA4M1/board.json index d21fe0c121..4d8dcd5e6d 100644 --- a/ports/renesas-ra/boards/EK_RA4M1/board.json +++ b/ports/renesas-ra/boards/EK_RA4M1/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "EK-RA4M1", "images": [ "ek_ra4m1_board.jpg" ], diff --git a/ports/renesas-ra/boards/EK_RA4W1/board.json b/ports/renesas-ra/boards/EK_RA4W1/board.json index 878d97a8ac..edc4fcbfe0 100644 --- a/ports/renesas-ra/boards/EK_RA4W1/board.json +++ b/ports/renesas-ra/boards/EK_RA4W1/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "EK-RA4W1", "images": [ "ek_ra4w1_board.jpg" ], diff --git a/ports/renesas-ra/boards/EK_RA6M1/board.json b/ports/renesas-ra/boards/EK_RA6M1/board.json index d678fa387e..3bdb08b92f 100644 --- a/ports/renesas-ra/boards/EK_RA6M1/board.json +++ b/ports/renesas-ra/boards/EK_RA6M1/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "EK-RA6M1", "images": [ "ek_ra6m1_board.jpg" ], diff --git a/ports/renesas-ra/boards/EK_RA6M2/board.json b/ports/renesas-ra/boards/EK_RA6M2/board.json index 3d6b95aacb..5760b19736 100644 --- a/ports/renesas-ra/boards/EK_RA6M2/board.json +++ b/ports/renesas-ra/boards/EK_RA6M2/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "EK-RA6M2", "images": [ "ek_ra6m2_board.jpg", "ek_ra6m2_j1_pins.jpg", diff --git a/ports/renesas-ra/boards/RA4M1_CLICKER/board.json b/ports/renesas-ra/boards/RA4M1_CLICKER/board.json index 8cb64f6601..be1dd977c3 100644 --- a/ports/renesas-ra/boards/RA4M1_CLICKER/board.json +++ b/ports/renesas-ra/boards/RA4M1_CLICKER/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "RA4M1-CLICKER", "images": [ "ra4m1_clicker_board.jpg", "ra4m1_clicker_pins.jpg" diff --git a/ports/renesas-ra/boards/VK_RA6M5/board.json b/ports/renesas-ra/boards/VK_RA6M5/board.json index b2ff6b0e40..48371138b1 100644 --- a/ports/renesas-ra/boards/VK_RA6M5/board.json +++ b/ports/renesas-ra/boards/VK_RA6M5/board.json @@ -6,7 +6,6 @@ "features": [ "DAC" ], - "id": "VK-RA6M5", "images": [ "VK-RA6M5.jpg" ], diff --git a/ports/rp2/boards/PICO/board.json b/ports/rp2/boards/PICO/board.json index 8c0a12ae76..07938978f3 100644 --- a/ports/rp2/boards/PICO/board.json +++ b/ports/rp2/boards/PICO/board.json @@ -8,7 +8,6 @@ "External Flash", "USB" ], - "id": "rp2-pico", "images": [ "rp2-pico.jpg" ], diff --git a/ports/rp2/boards/PICO_W/board.json b/ports/rp2/boards/PICO_W/board.json index 7ee7ef505e..6ea326c6cd 100644 --- a/ports/rp2/boards/PICO_W/board.json +++ b/ports/rp2/boards/PICO_W/board.json @@ -10,7 +10,6 @@ "USB", "WiFi" ], - "id": "rp2-pico-w", "images": [ "rp2-pico-w.jpg" ], diff --git a/ports/stm32/boards/MIKROE_QUAIL/board.json b/ports/stm32/boards/MIKROE_QUAIL/board.json index 15d8b5fc13..689bdb1052 100644 --- a/ports/stm32/boards/MIKROE_QUAIL/board.json +++ b/ports/stm32/boards/MIKROE_QUAIL/board.json @@ -6,7 +6,6 @@ "features": [ "mikroBUS" ], - "id": "MIKROE-QUAIL", "images": [ "quail_top.jpg" ], diff --git a/ports/stm32/boards/PYBD_SF2/board.json b/ports/stm32/boards/PYBD_SF2/board.json index 534a048ff0..06a83e4d89 100644 --- a/ports/stm32/boards/PYBD_SF2/board.json +++ b/ports/stm32/boards/PYBD_SF2/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "PYBD-SF2", "images": [ "PYBD_SF2_W4F2.jpg", "PYBD_SF2_W4F2_top.jpg", diff --git a/ports/stm32/boards/PYBD_SF3/board.json b/ports/stm32/boards/PYBD_SF3/board.json index 3e4731b3d2..e89f268cff 100644 --- a/ports/stm32/boards/PYBD_SF3/board.json +++ b/ports/stm32/boards/PYBD_SF3/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "PYBD-SF3", "images": [ "PYBD_SF3_W4F2.jpg", "PYBD_SF3_W4F2_top.jpg", diff --git a/ports/stm32/boards/PYBD_SF6/board.json b/ports/stm32/boards/PYBD_SF6/board.json index 3a39763d5b..b6d85d6fd7 100644 --- a/ports/stm32/boards/PYBD_SF6/board.json +++ b/ports/stm32/boards/PYBD_SF6/board.json @@ -7,7 +7,6 @@ "BLE", "WiFi" ], - "id": "PYBD-SF6", "images": [ "PYBD_SF6_W4F2.jpg", "PYBD_SF6_W4F2_top.jpg", diff --git a/ports/stm32/boards/PYBLITEV10/board.json b/ports/stm32/boards/PYBLITEV10/board.json index 38bb7fe1a0..0d2338d3db 100644 --- a/ports/stm32/boards/PYBLITEV10/board.json +++ b/ports/stm32/boards/PYBLITEV10/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "pyblitev10", "images": [ "PYBLITEv1_0.jpg", "PYBLITEv1_0-B.jpg", diff --git a/ports/stm32/boards/PYBV10/board.json b/ports/stm32/boards/PYBV10/board.json index 5f8f906172..0c5fea2eb8 100644 --- a/ports/stm32/boards/PYBV10/board.json +++ b/ports/stm32/boards/PYBV10/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "pybv10", "images": [ "PYBv1_0-C.jpg" ], diff --git a/ports/stm32/boards/PYBV11/board.json b/ports/stm32/boards/PYBV11/board.json index 1fd04310fd..5d7abbaa83 100644 --- a/ports/stm32/boards/PYBV11/board.json +++ b/ports/stm32/boards/PYBV11/board.json @@ -4,7 +4,6 @@ ], "docs": "", "features": [], - "id": "pybv11", "images": [ "PYBv1_1.jpg", "PYBv1_1-C.jpg", From 97ffc53ec9ff10c7585125229ef077233c77cc48 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 23:30:22 +1000 Subject: [PATCH 061/121] {esp32,rp2,stm32}/Makefile: Append board variant to BUILD. This allows switching between variants without clobbering the build output. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/Makefile | 7 ++++++- ports/rp2/Makefile | 8 +++++++- ports/stm32/Makefile | 7 ++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 239618c6f7..9d57ee4c21 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -17,8 +17,13 @@ ifeq ($(wildcard $(BOARD_DIR)/.),) $(error Invalid BOARD specified: $(BOARD_DIR)) endif -# If the build directory is not given, make it reflect the board name. +# If the build directory is not given, make it reflect the board name (and +# optionally the board variant). +ifneq ($(BOARD_VARIANT),) +BUILD ?= build-$(BOARD)-$(BOARD_VARIANT) +else BUILD ?= build-$(BOARD) +endif # Device serial settings. PORT ?= /dev/ttyUSB0 diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index ccfc1ac7d6..fdca11d11e 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -16,8 +16,14 @@ endif ifeq ($(wildcard $(BOARD_DIR)/.),) $(error Invalid BOARD specified: $(BOARD_DIR)) endif - + +# If the build directory is not given, make it reflect the board name (and +# optionally the board variant). +ifneq ($(BOARD_VARIANT),) +BUILD ?= build-$(BOARD)-$(BOARD_VARIANT) +else BUILD ?= build-$(BOARD) +endif $(VERBOSE)MAKESILENT = -s diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 7051398970..475d8f1004 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -13,8 +13,13 @@ ifeq ($(wildcard $(BOARD_DIR)/.),) $(error Invalid BOARD specified: $(BOARD_DIR)) endif -# If the build directory is not given, make it reflect the board name. +# If the build directory is not given, make it reflect the board name (and +# optionally the board variant). +ifneq ($(BOARD_VARIANT),) +BUILD ?= build-$(BOARD)-$(BOARD_VARIANT) +else BUILD ?= build-$(BOARD) +endif include ../../py/mkenv.mk -include mpconfigport.mk From aa236981192395cda555efa3db5f490c168bebdd Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 15 Aug 2023 23:49:35 +1000 Subject: [PATCH 062/121] esp32: Rename GENERIC* boards to ESP32_GENERIC*. Board names need to be unique across ports, and GENERIC clashes with the ESP8266 (which will be renamed to ESP8266_GENERIC). This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/CMakeLists.txt | 2 +- ports/esp32/Makefile | 7 ++-- ports/esp32/README.md | 33 ++++++++++++++----- .../{GENERIC => ESP32_GENERIC}/board.json | 0 .../{GENERIC => ESP32_GENERIC}/board.md | 0 .../mpconfigboard.cmake | 6 ++-- .../mpconfigboard.h | 0 .../{GENERIC => ESP32_GENERIC}/sdkconfig.d2wd | 0 .../{GENERIC => ESP32_GENERIC}/sdkconfig.ota | 0 .../sdkconfig.unicore | 0 .../board.json | 0 .../{GENERIC_C3 => ESP32_GENERIC_C3}/board.md | 0 .../mpconfigboard.cmake | 2 +- .../mpconfigboard.h | 0 .../sdkconfig.c3usb | 0 .../board.json | 0 .../{GENERIC_S2 => ESP32_GENERIC_S2}/board.md | 0 .../mpconfigboard.cmake | 0 .../mpconfigboard.h | 0 .../board.json | 0 .../{GENERIC_S3 => ESP32_GENERIC_S3}/board.md | 0 .../mpconfigboard.cmake | 2 +- .../mpconfigboard.h | 0 .../sdkconfig.board | 0 tools/ci.sh | 6 ++-- 25 files changed, 38 insertions(+), 20 deletions(-) rename ports/esp32/boards/{GENERIC => ESP32_GENERIC}/board.json (100%) rename ports/esp32/boards/{GENERIC => ESP32_GENERIC}/board.md (100%) rename ports/esp32/boards/{GENERIC => ESP32_GENERIC}/mpconfigboard.cmake (87%) rename ports/esp32/boards/{GENERIC => ESP32_GENERIC}/mpconfigboard.h (100%) rename ports/esp32/boards/{GENERIC => ESP32_GENERIC}/sdkconfig.d2wd (100%) rename ports/esp32/boards/{GENERIC => ESP32_GENERIC}/sdkconfig.ota (100%) rename ports/esp32/boards/{GENERIC => ESP32_GENERIC}/sdkconfig.unicore (100%) rename ports/esp32/boards/{GENERIC_C3 => ESP32_GENERIC_C3}/board.json (100%) rename ports/esp32/boards/{GENERIC_C3 => ESP32_GENERIC_C3}/board.md (100%) rename ports/esp32/boards/{GENERIC_C3 => ESP32_GENERIC_C3}/mpconfigboard.cmake (69%) rename ports/esp32/boards/{GENERIC_C3 => ESP32_GENERIC_C3}/mpconfigboard.h (100%) rename ports/esp32/boards/{GENERIC_C3 => ESP32_GENERIC_C3}/sdkconfig.c3usb (100%) rename ports/esp32/boards/{GENERIC_S2 => ESP32_GENERIC_S2}/board.json (100%) rename ports/esp32/boards/{GENERIC_S2 => ESP32_GENERIC_S2}/board.md (100%) rename ports/esp32/boards/{GENERIC_S2 => ESP32_GENERIC_S2}/mpconfigboard.cmake (100%) rename ports/esp32/boards/{GENERIC_S2 => ESP32_GENERIC_S2}/mpconfigboard.h (100%) rename ports/esp32/boards/{GENERIC_S3 => ESP32_GENERIC_S3}/board.json (100%) rename ports/esp32/boards/{GENERIC_S3 => ESP32_GENERIC_S3}/board.md (100%) rename ports/esp32/boards/{GENERIC_S3 => ESP32_GENERIC_S3}/mpconfigboard.cmake (91%) rename ports/esp32/boards/{GENERIC_S3 => ESP32_GENERIC_S3}/mpconfigboard.h (100%) rename ports/esp32/boards/{GENERIC_S3 => ESP32_GENERIC_S3}/sdkconfig.board (100%) diff --git a/ports/esp32/CMakeLists.txt b/ports/esp32/CMakeLists.txt index 4e29e96109..94047a0482 100644 --- a/ports/esp32/CMakeLists.txt +++ b/ports/esp32/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.12) # Set the board if it's not already set. if(NOT MICROPY_BOARD) - set(MICROPY_BOARD GENERIC) + set(MICROPY_BOARD ESP32_GENERIC) endif() # Set the board directory and check that it exists. diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 9d57ee4c21..bf275ffe66 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -8,12 +8,15 @@ ifdef BOARD_DIR # the path as the board name. BOARD ?= $(notdir $(BOARD_DIR:/=)) else -# If not given on the command line, then default to GENERIC. -BOARD ?= GENERIC +# If not given on the command line, then default to ESP32_GENERIC. +BOARD ?= ESP32_GENERIC BOARD_DIR ?= boards/$(BOARD) endif ifeq ($(wildcard $(BOARD_DIR)/.),) +ifeq ($(findstring boards/GENERIC,$(BOARD_DIR)),boards/GENERIC) +$(warning The GENERIC* boards have been renamed to ESP32_GENERIC*) +endif $(error Invalid BOARD specified: $(BOARD_DIR)) endif diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 2d5b05b926..169de4073b 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -93,7 +93,7 @@ $ make submodules $ make ``` -This will produce a combined `firmware.bin` image in the `build-GENERIC/` +This will produce a combined `firmware.bin` image in the `build-ESP32_GENERIC/` subdirectory (this firmware image is made up of: bootloader.bin, partitions.bin and micropython.bin). @@ -123,12 +123,12 @@ To flash the MicroPython firmware to your ESP32 use: $ make deploy ``` -The default ESP32 board build by the above commands is the `GENERIC` one, which -should work on most ESP32 modules. You can specify a different board by passing -`BOARD=` to the make commands, for example: +The default ESP32 board build by the above commands is the `ESP32_GENERIC` +one, which should work on most ESP32 modules. You can specify a different +board by passing `BOARD=` to the make commands, for example: ```bash -$ make BOARD=GENERIC_SPIRAM +$ make BOARD=ESP32_GENERIC_S3 ``` Note: the above "make" commands are thin wrappers for the underlying `idf.py` @@ -137,10 +137,25 @@ for example: ```bash $ idf.py build -$ idf.py -D MICROPY_BOARD=GENERIC_SPIRAM build +$ idf.py -D MICROPY_BOARD=ESP32_GENERIC build $ idf.py flash ``` +Some boards also support "variants", which are allow for small variations of +an otherwise similar board. For example different flash sizes or features. For +example to build the `OTA` variant of `ESP32_GENERIC`. + +```bash +$ make BOARD=ESP32_GENERIC BOARD_VARIANT=OTA +``` + +or to enable octal-SPIRAM support for the `ESP32_GENERIC_S3` board: + +```bash +$ make BOARD=ESP32_GENERIC BOARD_VARIANT=SPIRAM_OCT +``` + + Getting a Python prompt on the device ------------------------------------- @@ -202,10 +217,10 @@ antenna = machine.Pin(16, machine.Pin.OUT, value=0) Defining a custom ESP32 board ----------------------------- -The default ESP-IDF configuration settings are provided by the `GENERIC` -board definition in the directory `boards/GENERIC`. For a custom configuration +The default ESP-IDF configuration settings are provided by the `ESP32_GENERIC` +board definition in the directory `boards/ESP32_GENERIC`. For a custom configuration you can define your own board directory. Start a new board configuration by -copying an existing one (like `GENERIC`) and modifying it to suit your board. +copying an existing one (like `ESP32_GENERIC`) and modifying it to suit your board. MicroPython specific configuration values are defined in the board-specific `mpconfigboard.h` file, which is included by `mpconfigport.h`. Additional diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/ESP32_GENERIC/board.json similarity index 100% rename from ports/esp32/boards/GENERIC/board.json rename to ports/esp32/boards/ESP32_GENERIC/board.json diff --git a/ports/esp32/boards/GENERIC/board.md b/ports/esp32/boards/ESP32_GENERIC/board.md similarity index 100% rename from ports/esp32/boards/GENERIC/board.md rename to ports/esp32/boards/ESP32_GENERIC/board.md diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC/mpconfigboard.cmake similarity index 87% rename from ports/esp32/boards/GENERIC/mpconfigboard.cmake rename to ports/esp32/boards/ESP32_GENERIC/mpconfigboard.cmake index 14b47b3e59..74cb591c07 100644 --- a/ports/esp32/boards/GENERIC/mpconfigboard.cmake +++ b/ports/esp32/boards/ESP32_GENERIC/mpconfigboard.cmake @@ -6,7 +6,7 @@ set(SDKCONFIG_DEFAULTS if(MICROPY_BOARD_VARIANT STREQUAL "D2WD") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} - boards/GENERIC/sdkconfig.d2wd + boards/ESP32_GENERIC/sdkconfig.d2wd ) list(APPEND MICROPY_DEF_BOARD @@ -17,7 +17,7 @@ endif() if(MICROPY_BOARD_VARIANT STREQUAL "OTA") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} - boards/GENERIC/sdkconfig.ota + boards/ESP32_GENERIC/sdkconfig.ota ) list(APPEND MICROPY_DEF_BOARD @@ -39,7 +39,7 @@ endif() if(MICROPY_BOARD_VARIANT STREQUAL "UNICORE") set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} - boards/GENERIC/sdkconfig.unicore + boards/ESP32_GENERIC/sdkconfig.unicore ) list(APPEND MICROPY_DEF_BOARD diff --git a/ports/esp32/boards/GENERIC/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC/mpconfigboard.h similarity index 100% rename from ports/esp32/boards/GENERIC/mpconfigboard.h rename to ports/esp32/boards/ESP32_GENERIC/mpconfigboard.h diff --git a/ports/esp32/boards/GENERIC/sdkconfig.d2wd b/ports/esp32/boards/ESP32_GENERIC/sdkconfig.d2wd similarity index 100% rename from ports/esp32/boards/GENERIC/sdkconfig.d2wd rename to ports/esp32/boards/ESP32_GENERIC/sdkconfig.d2wd diff --git a/ports/esp32/boards/GENERIC/sdkconfig.ota b/ports/esp32/boards/ESP32_GENERIC/sdkconfig.ota similarity index 100% rename from ports/esp32/boards/GENERIC/sdkconfig.ota rename to ports/esp32/boards/ESP32_GENERIC/sdkconfig.ota diff --git a/ports/esp32/boards/GENERIC/sdkconfig.unicore b/ports/esp32/boards/ESP32_GENERIC/sdkconfig.unicore similarity index 100% rename from ports/esp32/boards/GENERIC/sdkconfig.unicore rename to ports/esp32/boards/ESP32_GENERIC/sdkconfig.unicore diff --git a/ports/esp32/boards/GENERIC_C3/board.json b/ports/esp32/boards/ESP32_GENERIC_C3/board.json similarity index 100% rename from ports/esp32/boards/GENERIC_C3/board.json rename to ports/esp32/boards/ESP32_GENERIC_C3/board.json diff --git a/ports/esp32/boards/GENERIC_C3/board.md b/ports/esp32/boards/ESP32_GENERIC_C3/board.md similarity index 100% rename from ports/esp32/boards/GENERIC_C3/board.md rename to ports/esp32/boards/ESP32_GENERIC_C3/board.md diff --git a/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.cmake similarity index 69% rename from ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake rename to ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.cmake index c8f78c161d..429366afac 100644 --- a/ports/esp32/boards/GENERIC_C3/mpconfigboard.cmake +++ b/ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.cmake @@ -3,5 +3,5 @@ set(IDF_TARGET esp32c3) set(SDKCONFIG_DEFAULTS boards/sdkconfig.base boards/sdkconfig.ble - boards/GENERIC_C3/sdkconfig.c3usb + boards/ESP32_GENERIC_C3/sdkconfig.c3usb ) diff --git a/ports/esp32/boards/GENERIC_C3/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h similarity index 100% rename from ports/esp32/boards/GENERIC_C3/mpconfigboard.h rename to ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h diff --git a/ports/esp32/boards/GENERIC_C3/sdkconfig.c3usb b/ports/esp32/boards/ESP32_GENERIC_C3/sdkconfig.c3usb similarity index 100% rename from ports/esp32/boards/GENERIC_C3/sdkconfig.c3usb rename to ports/esp32/boards/ESP32_GENERIC_C3/sdkconfig.c3usb diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/ESP32_GENERIC_S2/board.json similarity index 100% rename from ports/esp32/boards/GENERIC_S2/board.json rename to ports/esp32/boards/ESP32_GENERIC_S2/board.json diff --git a/ports/esp32/boards/GENERIC_S2/board.md b/ports/esp32/boards/ESP32_GENERIC_S2/board.md similarity index 100% rename from ports/esp32/boards/GENERIC_S2/board.md rename to ports/esp32/boards/ESP32_GENERIC_S2/board.md diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.cmake similarity index 100% rename from ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake rename to ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.cmake diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.h similarity index 100% rename from ports/esp32/boards/GENERIC_S2/mpconfigboard.h rename to ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.h diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/ESP32_GENERIC_S3/board.json similarity index 100% rename from ports/esp32/boards/GENERIC_S3/board.json rename to ports/esp32/boards/ESP32_GENERIC_S3/board.json diff --git a/ports/esp32/boards/GENERIC_S3/board.md b/ports/esp32/boards/ESP32_GENERIC_S3/board.md similarity index 100% rename from ports/esp32/boards/GENERIC_S3/board.md rename to ports/esp32/boards/ESP32_GENERIC_S3/board.md diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake similarity index 91% rename from ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake rename to ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake index 29974aaba4..36b4fe5624 100644 --- a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake +++ b/ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake @@ -5,7 +5,7 @@ set(SDKCONFIG_DEFAULTS boards/sdkconfig.usb boards/sdkconfig.ble boards/sdkconfig.spiram_sx - boards/GENERIC_S3/sdkconfig.board + boards/ESP32_GENERIC_S3/sdkconfig.board ) if(MICROPY_BOARD_VARIANT STREQUAL "SPIRAM_OCT") diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.h similarity index 100% rename from ports/esp32/boards/GENERIC_S3/mpconfigboard.h rename to ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.h diff --git a/ports/esp32/boards/GENERIC_S3/sdkconfig.board b/ports/esp32/boards/ESP32_GENERIC_S3/sdkconfig.board similarity index 100% rename from ports/esp32/boards/GENERIC_S3/sdkconfig.board rename to ports/esp32/boards/ESP32_GENERIC_S3/sdkconfig.board diff --git a/tools/ci.sh b/tools/ci.sh index b9bfb7eef8..55e90dc4a8 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -129,9 +129,9 @@ function ci_esp32_build { make ${MAKEOPTS} -C ports/esp32 \ USER_C_MODULES=../../../examples/usercmodule/micropython.cmake \ FROZEN_MANIFEST=$(pwd)/ports/esp32/boards/manifest_test.py - make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_C3 - make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S2 - make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S3 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C3 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_S2 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_S3 # Test building native .mpy with xtensawin architecture. ci_native_mpy_modules_build xtensawin From ef03ca8bf2e06d3d8b753aafdf13e1399dc26847 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 16 Aug 2023 00:51:37 +1000 Subject: [PATCH 063/121] esp8266: Add board variant support. This merges the existing GENERIC, GENERIC_1M, and GENERIC_512k boards into variants of the new ESP8266_GENERIC board (renamed from GENERIC so as not to clash with other ports). Also moves the generation of the "OTA" variant (previously generated by autobuild/build-esp8266-latest.sh) into the variant. Following the convention established for the WEACTSTUDIO rp2 board, the names of the variants are FLASH_1M and FLASH_512K (but rename the .ld files to use MiB and kiB). Updates autobuild to build esp8266 firmware the same way as other ports. This requires renaming the output from firmware-combined.bin to just firmware.bin. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp8266/Makefile | 32 +++++++--- ports/esp8266/README.md | 43 +++++++------ ports/esp8266/boards/ESP8266_GENERIC/_boot.py | 6 ++ .../{GENERIC => ESP8266_GENERIC}/board.json | 6 +- .../{GENERIC => ESP8266_GENERIC}/board.md | 13 +++- .../manifest_2MiB.py} | 0 .../manifest_512kiB.py} | 0 .../boards/ESP8266_GENERIC/mpconfigboard.h | 52 ++++++++++++++++ .../boards/ESP8266_GENERIC/mpconfigboard.mk | 50 +++++++++++++++ ports/esp8266/boards/GENERIC/mpconfigboard.h | 14 ----- ports/esp8266/boards/GENERIC/mpconfigboard.mk | 8 --- ports/esp8266/boards/GENERIC_1M/board.json | 16 ----- ports/esp8266/boards/GENERIC_1M/board.md | 5 -- .../esp8266/boards/GENERIC_1M/mpconfigboard.h | 17 ------ .../boards/GENERIC_1M/mpconfigboard.mk | 5 -- ports/esp8266/boards/GENERIC_512K/_boot.py | 3 - ports/esp8266/boards/GENERIC_512K/board.json | 16 ----- ports/esp8266/boards/GENERIC_512K/board.md | 3 - .../boards/GENERIC_512K/mpconfigboard.h | 13 ---- .../boards/GENERIC_512K/mpconfigboard.mk | 3 - .../boards/{esp8266_1m.ld => esp8266_1MiB.ld} | 0 .../boards/{esp8266_2m.ld => esp8266_2MiB.ld} | 0 .../{esp8266_512k.ld => esp8266_512kiB.ld} | 0 pyproject.toml | 2 +- tools/autobuild/autobuild.sh | 2 +- tools/autobuild/build-boards.sh | 4 ++ tools/autobuild/build-esp8266-latest.sh | 61 ------------------- tools/ci.sh | 6 +- 28 files changed, 179 insertions(+), 201 deletions(-) create mode 100644 ports/esp8266/boards/ESP8266_GENERIC/_boot.py rename ports/esp8266/boards/{GENERIC => ESP8266_GENERIC}/board.json (70%) rename ports/esp8266/boards/{GENERIC => ESP8266_GENERIC}/board.md (58%) rename ports/esp8266/boards/{GENERIC/manifest.py => ESP8266_GENERIC/manifest_2MiB.py} (100%) rename ports/esp8266/boards/{GENERIC_512K/manifest.py => ESP8266_GENERIC/manifest_512kiB.py} (100%) create mode 100644 ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h create mode 100644 ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.mk delete mode 100644 ports/esp8266/boards/GENERIC/mpconfigboard.h delete mode 100644 ports/esp8266/boards/GENERIC/mpconfigboard.mk delete mode 100644 ports/esp8266/boards/GENERIC_1M/board.json delete mode 100644 ports/esp8266/boards/GENERIC_1M/board.md delete mode 100644 ports/esp8266/boards/GENERIC_1M/mpconfigboard.h delete mode 100644 ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk delete mode 100644 ports/esp8266/boards/GENERIC_512K/_boot.py delete mode 100644 ports/esp8266/boards/GENERIC_512K/board.json delete mode 100644 ports/esp8266/boards/GENERIC_512K/board.md delete mode 100644 ports/esp8266/boards/GENERIC_512K/mpconfigboard.h delete mode 100644 ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk rename ports/esp8266/boards/{esp8266_1m.ld => esp8266_1MiB.ld} (100%) rename ports/esp8266/boards/{esp8266_2m.ld => esp8266_2MiB.ld} (100%) rename ports/esp8266/boards/{esp8266_512k.ld => esp8266_512kiB.ld} (100%) delete mode 100755 tools/autobuild/build-esp8266-latest.sh diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 1cdcafa031..e4c907c57a 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -4,17 +4,25 @@ ifdef BOARD_DIR # the path as the board name. BOARD ?= $(notdir $(BOARD_DIR:/=)) else -# If not given on the command line, then default to GENERIC. -BOARD ?= GENERIC +# If not given on the command line, then default to ESP8266_GENERIC. +BOARD ?= ESP8266_GENERIC BOARD_DIR ?= boards/$(BOARD) endif ifeq ($(wildcard $(BOARD_DIR)/.),) +ifeq ($(findstring boards/GENERIC,$(BOARD_DIR)),boards/GENERIC) +$(warning The GENERIC* boards have been renamed to ESP8266_GENERIC) +endif $(error Invalid BOARD specified: $(BOARD_DIR)) endif -# If the build directory is not given, make it reflect the board name. +# If the build directory is not given, make it reflect the board name (and +# optionally the board variant). +ifneq ($(BOARD_VARIANT),) +BUILD ?= build-$(BOARD)-$(BOARD_VARIANT) +else BUILD ?= build-$(BOARD) +endif include ../../py/mkenv.mk @@ -40,7 +48,7 @@ include $(TOP)/extmod/extmod.mk GIT_SUBMODULES += lib/axtls lib/berkeley-db-1.xx -FWBIN = $(BUILD)/firmware-combined.bin +FWBIN = $(BUILD)/firmware.bin PORT ?= /dev/ttyACM0 BAUD ?= 115200 FLASH_MODE ?= qio @@ -202,7 +210,7 @@ FROZEN_EXTRA_DEPS = $(CONFVARS_FILE) .PHONY: deploy -deploy: $(BUILD)/firmware-combined.bin +deploy: $(FWBIN) $(ECHO) "Writing $< to the board" $(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=$(FLASH_SIZE) --flash_mode=$(FLASH_MODE) 0 $< @@ -213,20 +221,26 @@ erase: reset: echo -e "\r\nimport machine; machine.reset()\r\n" >$(PORT) +ifeq ($(BOARD_VARIANT),OTA) +$(FWBIN): $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)esptool.py elf2image $^ + $(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x[0-5][1-f]000.bin $(BUILD)/firmware-ota.bin + + $(Q)cat $(YAOTA8266)/yaota8266.bin $(BUILD)/firmware-ota.bin > $@ + $(Q)$(PYTHON) $(YAOTA8266)/ota-client/ota_client.py sign $@ +else $(FWBIN): $(BUILD)/firmware.elf $(ECHO) "Create $@" $(Q)esptool.py elf2image $^ $(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x[0-5][1-f]000.bin $@ +endif $(BUILD)/firmware.elf: $(OBJ) $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ -ota: - rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin - $(MAKE) LD_FILES=boards/esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin - include $(TOP)/py/mkrules.mk clean-modules: diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md index 1e0cae2139..561c771403 100644 --- a/ports/esp8266/README.md +++ b/ports/esp8266/README.md @@ -23,6 +23,9 @@ Supported features include: Documentation is available at http://docs.micropython.org/en/latest/esp8266/quickref.html. +The default build requires a 2MiB flash chip, but see below for support for +1MiB and 512kiB options. + Build instructions ------------------ @@ -67,10 +70,10 @@ Then to compile the ESP8266 firmware: ``` $ cd ports/esp8266 -$ docker run --rm -v $HOME:$HOME -u $UID -w $PWD larsks/esp-open-sdk make -j BOARD=GENERIC +$ docker run --rm -v $HOME:$HOME -u $UID -w $PWD larsks/esp-open-sdk make -j BOARD=ESP8266_GENERIC ``` -This will produce binary images in the `build-GENERIC/` subdirectory. +This will produce binary images in the `build-ESP8266_GENERIC/` subdirectory. Substitute the board for whichever board you're using. __Building with a local toolchain__ @@ -106,10 +109,10 @@ Then to compile the ESP8266 firmware: ``` $ cd ports/esp8266 -$ make -j BOARD=GENERIC +$ make -j BOARD=ESP8266_GENERIC ``` -This will produce binary images in the `build-GENERIC/` subdirectory. +This will produce binary images in the `build-ESP8266_GENERIC/` subdirectory. Substitute the board for whichever board you're using. @@ -149,26 +152,30 @@ $ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=32m deploy (note that flash size is in megabits) If you want to flash manually using `esptool.py` directly, the image produced is -`build-GENERIC/firmware-combined.bin`, to be flashed at 0x00000. +`build-ESP8266_GENERIC/firmware.bin`, to be flashed at 0x00000. -The default board definition is the directory `boards/GENERIC`. +The default board definition is the directory `boards/ESP8266_GENERIC`. For a custom configuration you can define your own board in the directory `boards/`. -The `BOARD` variable can be set on the make command line, for example: +__Reduced FlashROM variants__ + +The normal build described above requires modules with at least 2MiB of +FlashROM onboard. There's a special configuration for 512kiB modules, which can +be built with the `FLASH_512K` variant. This configuration is highly limited, +lacks filesystem support, WebREPL, and has many other features disabled. It's +mostly suitable for advanced users who are interested to fine-tune options to +achieve a required setup. If you are an end user, please consider using a +module with at least 2MiB of FlashROM. + +A variant is also provided for 1MiB modules which just lacks the included +micropython-lib packages. + +The variant can be set on the make command line, for example: ```bash -$ make BOARD=GENERIC_512K +$ make BOARD=ESP8266_GENERIC BOARD_VARIANT=FLASH_512K +$ make BOARD=ESP8266_GENERIC BOARD_VARIANT=FLASH_1M ``` -__512KB FlashROM version__ - -The normal build described above requires modules with at least 1MB of FlashROM -onboard. There's a special configuration for 512KB modules, which can be -built with `make BOARD=GENERIC_512K`. This configuration is highly limited, lacks -filesystem support, WebREPL, and has many other features disabled. It's mostly -suitable for advanced users who are interested to fine-tune options to achieve a -required setup. If you are an end user, please consider using a module with at -least 1MB of FlashROM. - First start ----------- diff --git a/ports/esp8266/boards/ESP8266_GENERIC/_boot.py b/ports/esp8266/boards/ESP8266_GENERIC/_boot.py new file mode 100644 index 0000000000..16da8bc4c3 --- /dev/null +++ b/ports/esp8266/boards/ESP8266_GENERIC/_boot.py @@ -0,0 +1,6 @@ +# Minimal _boot.py for the 512kiB variant. Does not set up a block device or +# filesystem. Other variants use esp8266/modules/_boot.py. + +import gc + +gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4) diff --git a/ports/esp8266/boards/GENERIC/board.json b/ports/esp8266/boards/ESP8266_GENERIC/board.json similarity index 70% rename from ports/esp8266/boards/GENERIC/board.json rename to ports/esp8266/boards/ESP8266_GENERIC/board.json index dffe6d2711..1fca10c5f0 100644 --- a/ports/esp8266/boards/GENERIC/board.json +++ b/ports/esp8266/boards/ESP8266_GENERIC/board.json @@ -9,11 +9,13 @@ ], "images": [], "mcu": "esp8266", - "product": "ESP8266 with 2MiB+ flash", + "product": "ESP8266", "thumbnail": "", "url": "https://www.espressif.com/en/products/modules", "variants": { - "ota": "OTA compatible" + "OTA": "OTA compatible", + "FLASH_1M": "1MiB flash", + "FLASH_512K": "512kiB flash" }, "vendor": "Espressif" } diff --git a/ports/esp8266/boards/GENERIC/board.md b/ports/esp8266/boards/ESP8266_GENERIC/board.md similarity index 58% rename from ports/esp8266/boards/GENERIC/board.md rename to ports/esp8266/boards/ESP8266_GENERIC/board.md index fa0cf410d6..96fbab617a 100644 --- a/ports/esp8266/boards/GENERIC/board.md +++ b/ports/esp8266/boards/ESP8266_GENERIC/board.md @@ -1,6 +1,13 @@ -The following are daily builds of the ESP8266 firmware for boards with at -least 2MiB of flash. They have the latest features and bug fixes, WebREPL is -not automatically started, and debugging is enabled by default. +The following are daily builds of the ESP8266 firmware. This will work on +boards with at least 2MiB of flash. They have the latest features and bug +fixes, WebREPL is not automatically started, and debugging is enabled by +default. + +For boards with 1MiB or 512kiB of flash, two variants are provided with reduced +functionality. The 1MiB variant removes asyncio and FAT-filesystem support as +well as some modules from micropython-lib. The 512kiB variant further removes +all filesystem support, as well as framebuffer support, some Python language +features, and has less detailed error messages. Note: v1.12-334 and newer (including v1.13) require an ESP8266 module with 2MiB of flash or more, and use littlefs as the filesystem by default. When diff --git a/ports/esp8266/boards/GENERIC/manifest.py b/ports/esp8266/boards/ESP8266_GENERIC/manifest_2MiB.py similarity index 100% rename from ports/esp8266/boards/GENERIC/manifest.py rename to ports/esp8266/boards/ESP8266_GENERIC/manifest_2MiB.py diff --git a/ports/esp8266/boards/GENERIC_512K/manifest.py b/ports/esp8266/boards/ESP8266_GENERIC/manifest_512kiB.py similarity index 100% rename from ports/esp8266/boards/GENERIC_512K/manifest.py rename to ports/esp8266/boards/ESP8266_GENERIC/manifest_512kiB.py diff --git a/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h b/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h new file mode 100644 index 0000000000..3a9c40e795 --- /dev/null +++ b/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h @@ -0,0 +1,52 @@ +#if defined(MICROPY_ESP8266_2M) + +#define MICROPY_HW_BOARD_NAME "ESP module" +#define MICROPY_HW_MCU_NAME "ESP8266" + +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_EMIT_XTENSA (1) +#define MICROPY_EMIT_INLINE_XTENSA (1) + +#define MICROPY_DEBUG_PRINTERS (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) + +#define MICROPY_READER_VFS (MICROPY_VFS) +#define MICROPY_VFS (1) + +#define MICROPY_PY_CRYPTOLIB (1) + +#elif defined(MICROPY_ESP8266_1M) + +#define MICROPY_HW_BOARD_NAME "ESP module (1M)" +#define MICROPY_HW_MCU_NAME "ESP8266" + +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_EMIT_XTENSA (1) +#define MICROPY_EMIT_INLINE_XTENSA (1) + +#define MICROPY_DEBUG_PRINTERS (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) + +#define MICROPY_READER_VFS (MICROPY_VFS) +#define MICROPY_VFS (1) + + +#define MICROPY_PY_CRYPTOLIB (1) + +#elif defined(MICROPY_ESP8266_512K) + +#define MICROPY_HW_BOARD_NAME "ESP module (512K)" +#define MICROPY_HW_MCU_NAME "ESP8266" + +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) + +#define MICROPY_PY_FSTRINGS (0) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) +#define MICROPY_PY_ALL_SPECIAL_METHODS (0) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0) +#define MICROPY_PY_SYS_STDIO_BUFFER (0) +#define MICROPY_PY_ASYNCIO (0) +#define MICROPY_PY_RE_SUB (0) +#define MICROPY_PY_FRAMEBUF (0) + +#endif diff --git a/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.mk b/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.mk new file mode 100644 index 0000000000..2eb78d7e85 --- /dev/null +++ b/ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.mk @@ -0,0 +1,50 @@ +ifeq ($(BOARD_VARIANT),) +LD_FILES = boards/esp8266_2MiB.ld + +MICROPY_ESPNOW ?= 1 +MICROPY_PY_BTREE ?= 1 +MICROPY_VFS_FAT ?= 1 +MICROPY_VFS_LFS2 ?= 1 + +# Add asyncio and extra micropython-lib packages (in addition to the port manifest). +FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest_2MiB.py + +# Configure mpconfigboard.h. +CFLAGS += -DMICROPY_ESP8266_2M +endif + +ifeq ($(BOARD_VARIANT),FLASH_1M) +LD_FILES = boards/esp8266_1MiB.ld + +MICROPY_ESPNOW ?= 1 +MICROPY_PY_BTREE ?= 1 +MICROPY_VFS_LFS2 ?= 1 + +# Note: Implicitly uses the port manifest. + +# Configure mpconfigboard.h. +CFLAGS += -DMICROPY_ESP8266_1M +endif + +ifeq ($(BOARD_VARIANT),OTA) +LD_FILES = boards/esp8266_ota.ld + +MICROPY_ESPNOW ?= 1 +MICROPY_PY_BTREE ?= 1 +MICROPY_VFS_LFS2 ?= 1 + +# Note: Implicitly uses the port manifest. + +# Configure mpconfigboard.h. +CFLAGS += -DMICROPY_ESP8266_1M +endif + +ifeq ($(BOARD_VARIANT),FLASH_512K) +LD_FILES = boards/esp8266_512kiB.ld + +# Note: Use the minimal manifest.py. +FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest_512kiB.py + +# Configure mpconfigboard.h. +CFLAGS += -DMICROPY_ESP8266_512K +endif diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.h b/ports/esp8266/boards/GENERIC/mpconfigboard.h deleted file mode 100644 index 52c93f83a3..0000000000 --- a/ports/esp8266/boards/GENERIC/mpconfigboard.h +++ /dev/null @@ -1,14 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP module" -#define MICROPY_HW_MCU_NAME "ESP8266" - -#define MICROPY_PERSISTENT_CODE_LOAD (1) -#define MICROPY_EMIT_XTENSA (1) -#define MICROPY_EMIT_INLINE_XTENSA (1) - -#define MICROPY_DEBUG_PRINTERS (1) -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) - -#define MICROPY_READER_VFS (MICROPY_VFS) -#define MICROPY_VFS (1) - -#define MICROPY_PY_CRYPTOLIB (1) diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.mk b/ports/esp8266/boards/GENERIC/mpconfigboard.mk deleted file mode 100644 index 8d7babdc84..0000000000 --- a/ports/esp8266/boards/GENERIC/mpconfigboard.mk +++ /dev/null @@ -1,8 +0,0 @@ -LD_FILES = boards/esp8266_2m.ld - -MICROPY_ESPNOW ?= 1 -MICROPY_PY_BTREE ?= 1 -MICROPY_VFS_FAT ?= 1 -MICROPY_VFS_LFS2 ?= 1 - -FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py diff --git a/ports/esp8266/boards/GENERIC_1M/board.json b/ports/esp8266/boards/GENERIC_1M/board.json deleted file mode 100644 index 4ab5c79df0..0000000000 --- a/ports/esp8266/boards/GENERIC_1M/board.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "deploy": [ - "../deploy.md" - ], - "docs": "", - "features": [ - "External Flash", - "WiFi" - ], - "images": [], - "mcu": "esp8266", - "product": "ESP8266 with 1MiB flash", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp8266/boards/GENERIC_1M/board.md b/ports/esp8266/boards/GENERIC_1M/board.md deleted file mode 100644 index 17cc6e3a6b..0000000000 --- a/ports/esp8266/boards/GENERIC_1M/board.md +++ /dev/null @@ -1,5 +0,0 @@ -The following are daily builds of the ESP8266 firmware tailored for modules with -only 1MiB of flash. This firmware uses littlefs as the filesystem. -When upgrading from older firmware that uses a FAT filesystem please backup your files -first, and either erase all flash before upgrading, or after upgrading execute -`os.VfsLfs2.mkfs(bdev)`. diff --git a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.h b/ports/esp8266/boards/GENERIC_1M/mpconfigboard.h deleted file mode 100644 index 41752e692b..0000000000 --- a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.h +++ /dev/null @@ -1,17 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP module (1M)" -#define MICROPY_HW_MCU_NAME "ESP8266" - -#define MICROPY_PERSISTENT_CODE_LOAD (1) -#define MICROPY_EMIT_XTENSA (1) -#define MICROPY_EMIT_INLINE_XTENSA (1) - -#define MICROPY_DEBUG_PRINTERS (1) -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) - -#define MICROPY_READER_VFS (MICROPY_VFS) -#define MICROPY_VFS (1) - -#define MICROPY_PY_FSTRINGS (0) -#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0) -#define MICROPY_PY_ASYNCIO (0) -#define MICROPY_PY_CRYPTOLIB (1) diff --git a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk b/ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk deleted file mode 100644 index adc31702e0..0000000000 --- a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk +++ /dev/null @@ -1,5 +0,0 @@ -LD_FILES = boards/esp8266_1m.ld - -MICROPY_ESPNOW ?= 1 -MICROPY_PY_BTREE ?= 1 -MICROPY_VFS_LFS2 ?= 1 diff --git a/ports/esp8266/boards/GENERIC_512K/_boot.py b/ports/esp8266/boards/GENERIC_512K/_boot.py deleted file mode 100644 index 1a55cfd36c..0000000000 --- a/ports/esp8266/boards/GENERIC_512K/_boot.py +++ /dev/null @@ -1,3 +0,0 @@ -import gc - -gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4) diff --git a/ports/esp8266/boards/GENERIC_512K/board.json b/ports/esp8266/boards/GENERIC_512K/board.json deleted file mode 100644 index e035562be7..0000000000 --- a/ports/esp8266/boards/GENERIC_512K/board.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "deploy": [ - "../deploy.md" - ], - "docs": "", - "features": [ - "External Flash", - "WiFi" - ], - "images": [], - "mcu": "esp8266", - "product": "ESP8266 with 512kiB flash", - "thumbnail": "", - "url": "https://www.espressif.com/en/products/modules", - "vendor": "Espressif" -} diff --git a/ports/esp8266/boards/GENERIC_512K/board.md b/ports/esp8266/boards/GENERIC_512K/board.md deleted file mode 100644 index 1f6e2c7907..0000000000 --- a/ports/esp8266/boards/GENERIC_512K/board.md +++ /dev/null @@ -1,3 +0,0 @@ -The following are daily builds of the ESP8266 firmware tailored for modules with -only 512kiB of flash. Certain features are disabled to get the firmware down -to this size. diff --git a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h deleted file mode 100644 index c29e23d5ad..0000000000 --- a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h +++ /dev/null @@ -1,13 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "ESP module (512K)" -#define MICROPY_HW_MCU_NAME "ESP8266" - -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) - -#define MICROPY_PY_FSTRINGS (0) -#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) -#define MICROPY_PY_ALL_SPECIAL_METHODS (0) -#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0) -#define MICROPY_PY_SYS_STDIO_BUFFER (0) -#define MICROPY_PY_ASYNCIO (0) -#define MICROPY_PY_RE_SUB (0) -#define MICROPY_PY_FRAMEBUF (0) diff --git a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk deleted file mode 100644 index 120351909b..0000000000 --- a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.mk +++ /dev/null @@ -1,3 +0,0 @@ -LD_FILES = boards/esp8266_512k.ld - -FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py diff --git a/ports/esp8266/boards/esp8266_1m.ld b/ports/esp8266/boards/esp8266_1MiB.ld similarity index 100% rename from ports/esp8266/boards/esp8266_1m.ld rename to ports/esp8266/boards/esp8266_1MiB.ld diff --git a/ports/esp8266/boards/esp8266_2m.ld b/ports/esp8266/boards/esp8266_2MiB.ld similarity index 100% rename from ports/esp8266/boards/esp8266_2m.ld rename to ports/esp8266/boards/esp8266_2MiB.ld diff --git a/ports/esp8266/boards/esp8266_512k.ld b/ports/esp8266/boards/esp8266_512kiB.ld similarity index 100% rename from ports/esp8266/boards/esp8266_512k.ld rename to ports/esp8266/boards/esp8266_512kiB.ld diff --git a/pyproject.toml b/pyproject.toml index a05abf887e..e3d70385c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,4 +48,4 @@ max-complexity = 40 # manifest.py files are evaluated with some global names pre-defined "**/manifest.py" = ["F821"] -"ports/**/boards/manifest*.py" = ["F821"] +"ports/**/boards/**/manifest_*.py" = ["F821"] diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh index 999a42c0ed..12ac230dfb 100755 --- a/tools/autobuild/autobuild.sh +++ b/tools/autobuild/autobuild.sh @@ -62,7 +62,7 @@ FW_TAG="-$FW_DATE-unstable-$FW_GIT" cd ports/cc3200 ${AUTODIR}/build-cc3200-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} cd ../esp8266 -${AUTODIR}/build-esp8266-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} +build_esp8266_boards ${FW_TAG} ${LOCAL_FIRMWARE} cd ../esp32 (source ${IDF_PATH_V50}/export.sh && build_esp32_boards ${FW_TAG} ${LOCAL_FIRMWARE}) cd ../mimxrt diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh index 82d7f36057..6f3f938096 100755 --- a/tools/autobuild/build-boards.sh +++ b/tools/autobuild/build-boards.sh @@ -92,6 +92,10 @@ function build_esp32_boards { build_boards modesp32.c $1 $2 bin elf map uf2 app-bin } +function build_esp8266_boards { + build_boards modesp.c $1 $2 bin elf map +} + function build_mimxrt_boards { build_boards modmimxrt.c $1 $2 bin hex } diff --git a/tools/autobuild/build-esp8266-latest.sh b/tools/autobuild/build-esp8266-latest.sh deleted file mode 100755 index 1972e85fcd..0000000000 --- a/tools/autobuild/build-esp8266-latest.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -PYTHON3=python3 -yaota8266=$HOME/yaota8266 - -# for debugging -#exec &> /tmp/esp-log-$$.txt - -# function for building firmware -function do_build() { - descr=$1 - board=$2 - shift - shift - echo "building $descr $board" - build_dir=/tmp/esp8266-build-$board - $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1 - mv $build_dir/firmware-combined.bin $dest_dir/$descr$fw_tag.bin - mv $build_dir/firmware.elf $dest_dir/$descr$fw_tag.elf - mv $build_dir/firmware.map $dest_dir/$descr$fw_tag.map - rm -rf $build_dir -} - -function do_build_ota() { - descr=$1 - board=$2 - shift - shift - echo "building $descr $board" - build_dir=/tmp/esp8266-build-$board - $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1 - cat $yaota8266/yaota8266.bin $build_dir/firmware-ota.bin > $dest_dir/$descr$fw_tag.bin - pushd $yaota8266/ota-client - $PYTHON3 ota_client.py sign $build_dir/firmware-ota.bin - popd - mv $build_dir/firmware-ota.bin.ota $dest_dir/$descr$fw_tag.ota - mv $build_dir/firmware.elf $dest_dir/$descr$fw_tag.elf - mv $build_dir/firmware.map $dest_dir/$descr$fw_tag.map - rm -rf $build_dir -} - -# check/get parameters -if [ $# != 2 ]; then - echo "usage: $0 " - exit 1 -fi - -fw_tag=$1 -dest_dir=$2 - -# check we are in the correct directory -if [ ! -r boards/esp8266_common.ld ]; then - echo "must be in esp8266 directory" - exit 1 -fi - -# build the versions -do_build esp8266 GENERIC -do_build esp8266-512k GENERIC_512K -do_build esp8266-1m GENERIC_1M -do_build_ota esp8266-ota GENERIC_1M ota diff --git a/tools/ci.sh b/tools/ci.sh index 55e90dc4a8..f60ba0fd51 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -155,9 +155,9 @@ function ci_esp8266_path { function ci_esp8266_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/esp8266 submodules - make ${MAKEOPTS} -C ports/esp8266 - make ${MAKEOPTS} -C ports/esp8266 BOARD=GENERIC_512K - make ${MAKEOPTS} -C ports/esp8266 BOARD=GENERIC_1M + make ${MAKEOPTS} -C ports/esp8266 BOARD=ESP8266_GENERIC + make ${MAKEOPTS} -C ports/esp8266 BOARD=ESP8266_GENERIC BOARD_VARIANT=FLASH_512K + make ${MAKEOPTS} -C ports/esp8266 BOARD=ESP8266_GENERIC BOARD_VARIANT=FLASH_1M } ######################################################################################## From 873bd00ad48b0c4a2b3addb95964ac0ecbb918f2 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 16 Aug 2023 13:13:01 +1000 Subject: [PATCH 064/121] rp2: Rename PICO, PICO_W to RPI_PICO, RPI_PICO_W. PICO might not always be a unique name across all ports, and the convention generally for other boards is to do VENDOR_BOARD. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/rp2/CMakeLists.txt | 2 +- ports/rp2/Makefile | 7 +++++-- ports/rp2/boards/{PICO => RPI_PICO}/board.json | 0 ports/rp2/boards/{PICO => RPI_PICO}/mpconfigboard.cmake | 1 + ports/rp2/boards/{PICO => RPI_PICO}/mpconfigboard.h | 0 ports/rp2/boards/{PICO => RPI_PICO}/pins.csv | 0 ports/rp2/boards/{PICO_W => RPI_PICO_W}/board.json | 0 ports/rp2/boards/{PICO_W => RPI_PICO_W}/manifest.py | 0 .../rp2/boards/{PICO_W => RPI_PICO_W}/mpconfigboard.cmake | 2 ++ ports/rp2/boards/{PICO_W => RPI_PICO_W}/mpconfigboard.h | 0 ports/rp2/boards/{PICO_W => RPI_PICO_W}/pins.csv | 0 tools/ci.sh | 4 ++-- 12 files changed, 11 insertions(+), 5 deletions(-) rename ports/rp2/boards/{PICO => RPI_PICO}/board.json (100%) rename ports/rp2/boards/{PICO => RPI_PICO}/mpconfigboard.cmake (60%) rename ports/rp2/boards/{PICO => RPI_PICO}/mpconfigboard.h (100%) rename ports/rp2/boards/{PICO => RPI_PICO}/pins.csv (100%) rename ports/rp2/boards/{PICO_W => RPI_PICO_W}/board.json (100%) rename ports/rp2/boards/{PICO_W => RPI_PICO_W}/manifest.py (100%) rename ports/rp2/boards/{PICO_W => RPI_PICO_W}/mpconfigboard.cmake (93%) rename ports/rp2/boards/{PICO_W => RPI_PICO_W}/mpconfigboard.h (100%) rename ports/rp2/boards/{PICO_W => RPI_PICO_W}/pins.csv (100%) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 4334a0aba9..7718697b43 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -26,7 +26,7 @@ set(MICROPY_PORT_DIR ${CMAKE_CURRENT_LIST_DIR}) # Set the board if it's not already set. if(NOT MICROPY_BOARD) - set(MICROPY_BOARD PICO) + set(MICROPY_BOARD RPI_PICO) endif() # Set the board directory and check that it exists. diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index fdca11d11e..8399b9e98a 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -8,12 +8,15 @@ ifdef BOARD_DIR # the path as the board name. BOARD ?= $(notdir $(BOARD_DIR:/=)) else -# If not given on the command line, then default to PICO. -BOARD ?= PICO +# If not given on the command line, then default to RPI_PICO. +BOARD ?= RPI_PICO BOARD_DIR ?= boards/$(BOARD) endif ifeq ($(wildcard $(BOARD_DIR)/.),) +ifeq ($(findstring boards/PICO,$(BOARD_DIR)),boards/PICO) +$(warning The PICO* boards have been renamed to RPI_PICO*) +endif $(error Invalid BOARD specified: $(BOARD_DIR)) endif diff --git a/ports/rp2/boards/PICO/board.json b/ports/rp2/boards/RPI_PICO/board.json similarity index 100% rename from ports/rp2/boards/PICO/board.json rename to ports/rp2/boards/RPI_PICO/board.json diff --git a/ports/rp2/boards/PICO/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake similarity index 60% rename from ports/rp2/boards/PICO/mpconfigboard.cmake rename to ports/rp2/boards/RPI_PICO/mpconfigboard.cmake index 3a40ca2871..13269e81e5 100644 --- a/ports/rp2/boards/PICO/mpconfigboard.cmake +++ b/ports/rp2/boards/RPI_PICO/mpconfigboard.cmake @@ -1 +1,2 @@ # cmake file for Raspberry Pi Pico +set(PICO_BOARD "pico") diff --git a/ports/rp2/boards/PICO/mpconfigboard.h b/ports/rp2/boards/RPI_PICO/mpconfigboard.h similarity index 100% rename from ports/rp2/boards/PICO/mpconfigboard.h rename to ports/rp2/boards/RPI_PICO/mpconfigboard.h diff --git a/ports/rp2/boards/PICO/pins.csv b/ports/rp2/boards/RPI_PICO/pins.csv similarity index 100% rename from ports/rp2/boards/PICO/pins.csv rename to ports/rp2/boards/RPI_PICO/pins.csv diff --git a/ports/rp2/boards/PICO_W/board.json b/ports/rp2/boards/RPI_PICO_W/board.json similarity index 100% rename from ports/rp2/boards/PICO_W/board.json rename to ports/rp2/boards/RPI_PICO_W/board.json diff --git a/ports/rp2/boards/PICO_W/manifest.py b/ports/rp2/boards/RPI_PICO_W/manifest.py similarity index 100% rename from ports/rp2/boards/PICO_W/manifest.py rename to ports/rp2/boards/RPI_PICO_W/manifest.py diff --git a/ports/rp2/boards/PICO_W/mpconfigboard.cmake b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.cmake similarity index 93% rename from ports/rp2/boards/PICO_W/mpconfigboard.cmake rename to ports/rp2/boards/RPI_PICO_W/mpconfigboard.cmake index e6db8dda6a..5610c313e6 100644 --- a/ports/rp2/boards/PICO_W/mpconfigboard.cmake +++ b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.cmake @@ -1,5 +1,7 @@ # cmake file for Raspberry Pi Pico W +set(PICO_BOARD "pico_w") + # The C malloc is needed by cyw43-driver Bluetooth set(MICROPY_C_HEAP_SIZE 4096) diff --git a/ports/rp2/boards/PICO_W/mpconfigboard.h b/ports/rp2/boards/RPI_PICO_W/mpconfigboard.h similarity index 100% rename from ports/rp2/boards/PICO_W/mpconfigboard.h rename to ports/rp2/boards/RPI_PICO_W/mpconfigboard.h diff --git a/ports/rp2/boards/PICO_W/pins.csv b/ports/rp2/boards/RPI_PICO_W/pins.csv similarity index 100% rename from ports/rp2/boards/PICO_W/pins.csv rename to ports/rp2/boards/RPI_PICO_W/pins.csv diff --git a/tools/ci.sh b/tools/ci.sh index f60ba0fd51..33dc58d6b8 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -272,8 +272,8 @@ function ci_rp2_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/rp2 submodules make ${MAKEOPTS} -C ports/rp2 - make ${MAKEOPTS} -C ports/rp2 BOARD=PICO_W submodules - make ${MAKEOPTS} -C ports/rp2 BOARD=PICO_W USER_C_MODULES=../../examples/usercmodule/micropython.cmake + make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO_W submodules + make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO_W USER_C_MODULES=../../examples/usercmodule/micropython.cmake make ${MAKEOPTS} -C ports/rp2 BOARD=W5100S_EVB_PICO submodules make ${MAKEOPTS} -C ports/rp2 BOARD=W5100S_EVB_PICO From 326dfd2a8579828c4159d965c6a41883a2a90029 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 21 Aug 2023 13:25:15 +1000 Subject: [PATCH 065/121] esp32/boards/ESP32_GENERIC_C3: Enable UART REPL. This should have been added in 4815af75bc0bc21e1e66b958fd4ee4e90c24ba10 when the variants were combined. The original non-USB variant got this implicitly, and therefore was not in mpconfigvariant.h Signed-off-by: Jim Mussared --- ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h index d403e70e46..42e77ecb1a 100644 --- a/ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h +++ b/ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h @@ -6,3 +6,6 @@ #define MICROPY_HW_ENABLE_SDCARD (0) #define MICROPY_PY_MACHINE_DAC (0) #define MICROPY_PY_MACHINE_I2S (0) + +// Enable UART REPL for modules that have an external USB-UART and don't use native USB. +#define MICROPY_HW_ENABLE_UART_REPL (1) From bc1af5ab7f9f28d0bfd882a7f00027b146feb11e Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 24 Aug 2023 15:44:16 +1000 Subject: [PATCH 066/121] cc3200/Makefile: Build firmware.zip. This allows the cc3200 port to be build with the standard autobuild script rather than the custom build-cc3200-latest.sh (which is now removed). This also fixes the path inside the zip file (by using the `-j` flag to zip). This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/cc3200/Makefile | 2 ++ ports/cc3200/application.mk | 6 ++++- py/mkenv.mk | 1 + tools/autobuild/autobuild.sh | 2 +- tools/autobuild/build-boards.sh | 4 ++++ tools/autobuild/build-cc3200-latest.sh | 32 -------------------------- 6 files changed, 13 insertions(+), 34 deletions(-) delete mode 100755 tools/autobuild/build-cc3200-latest.sh diff --git a/ports/cc3200/Makefile b/ports/cc3200/Makefile index 61af0bfd98..f89a927c0e 100644 --- a/ports/cc3200/Makefile +++ b/ports/cc3200/Makefile @@ -7,6 +7,8 @@ endif # Make 'release' the default build type BTYPE ?= release +# Make the 'application' by default ('bootloader' can be built explicitly) +BTARGET ?= application # Port for flashing firmware PORT ?= /dev/ttyUSB1 diff --git a/ports/cc3200/application.mk b/ports/cc3200/application.mk index 5021e4ff3c..f4487d69d4 100644 --- a/ports/cc3200/application.mk +++ b/ports/cc3200/application.mk @@ -198,7 +198,7 @@ WIPY_IP ?= '192.168.1.1' WIPY_USER ?= 'micro' WIPY_PWD ?= 'python' -all: $(BUILD)/mcuimg.bin +all: $(BUILD)/firmware.zip .PHONY: deploy-ota @@ -219,6 +219,10 @@ $(BUILD)/mcuimg.bin: $(BUILD)/application.bin $(ECHO) "Create $@" $(Q)$(SHELL) $(APP_SIGN) $(BUILD) +$(BUILD)/firmware.zip: $(BUILD)/mcuimg.bin + $(ECHO) "Create $@" + $(Q)$(ZIP) -j $@ $< + MAKE_PINS = boards/make-pins.py BOARD_PINS = boards/$(BOARD)/pins.csv AF_FILE = boards/cc3200_af.csv diff --git a/py/mkenv.mk b/py/mkenv.mk index 5368279e29..d3dddcc32d 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -42,6 +42,7 @@ SED = sed CAT = cat TOUCH = touch PYTHON = python3 +ZIP = zip AS = $(CROSS_COMPILE)as CC = $(CROSS_COMPILE)gcc diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh index 12ac230dfb..e1f2287ee5 100755 --- a/tools/autobuild/autobuild.sh +++ b/tools/autobuild/autobuild.sh @@ -60,7 +60,7 @@ FW_TAG="-$FW_DATE-unstable-$FW_GIT" # build new firmware cd ports/cc3200 -${AUTODIR}/build-cc3200-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} +build_cc3200_boards ${FW_TAG} ${LOCAL_FIRMWARE} cd ../esp8266 build_esp8266_boards ${FW_TAG} ${LOCAL_FIRMWARE} cd ../esp32 diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh index 6f3f938096..2b323ba9b0 100755 --- a/tools/autobuild/build-boards.sh +++ b/tools/autobuild/build-boards.sh @@ -88,6 +88,10 @@ function build_boards { done } +function build_cc3200_boards { + build_boards hal/cc3200_hal.c $1 $2 zip +} + function build_esp32_boards { build_boards modesp32.c $1 $2 bin elf map uf2 app-bin } diff --git a/tools/autobuild/build-cc3200-latest.sh b/tools/autobuild/build-cc3200-latest.sh deleted file mode 100755 index 0cbdb9c428..0000000000 --- a/tools/autobuild/build-cc3200-latest.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# function for building firmware -function do_build() { - descr=$1 - board=$2 - shift - shift - echo "building $descr $board" - build_dir=/tmp/cc3200-build-$board - $MICROPY_AUTOBUILD_MAKE $@ BTARGET=application BOARD=$board BUILD=$build_dir || exit 1 - zip $dest_dir/$descr$fw_tag.zip $build_dir/mcuimg.bin - rm -rf $build_dir -} - -# check/get parameters -if [ $# != 2 ]; then - echo "usage: $0 " - exit 1 -fi - -fw_tag=$1 -dest_dir=$2 - -# check we are in the correct directory -if [ ! -r application.mk ]; then - echo "must be in cc3200 directory" - exit 1 -fi - -# build the versions -do_build wipy WIPY From 1dedb65e645f72afbd614431435208d687e16992 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 24 Aug 2023 17:15:32 +1000 Subject: [PATCH 067/121] esp8266/boards/ESP8266_GENERIC: Add image filename. This image is now in micropython-media. Signed-off-by: Damien George --- ports/esp8266/boards/ESP8266_GENERIC/board.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/esp8266/boards/ESP8266_GENERIC/board.json b/ports/esp8266/boards/ESP8266_GENERIC/board.json index 1fca10c5f0..2b3a6b5507 100644 --- a/ports/esp8266/boards/ESP8266_GENERIC/board.json +++ b/ports/esp8266/boards/ESP8266_GENERIC/board.json @@ -7,7 +7,9 @@ "External Flash", "WiFi" ], - "images": [], + "images": [ + "esp8266.jpg" + ], "mcu": "esp8266", "product": "ESP8266", "thumbnail": "", From 4a3fdc0e76c640d550099cecaa41f8c3e1489562 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 23 Aug 2023 13:13:59 +1000 Subject: [PATCH 068/121] tests/misc/sys_settrace_features.py: Fix to run on newer CPython. This test was failing on CPython 3.11 as it now emits `0` as the line number for the "call" event corresponding to import, where as in 3.6 it had `1` as the line number. We maintain the old behavior, but in order to make this test pass on both CPython versions, the trace handler now converts the `0` to a `1`. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- tests/misc/sys_settrace_features.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/misc/sys_settrace_features.py b/tests/misc/sys_settrace_features.py index 8a38b7534f..84cf875a86 100644 --- a/tests/misc/sys_settrace_features.py +++ b/tests/misc/sys_settrace_features.py @@ -22,7 +22,9 @@ def print_stacktrace(frame, level=0): frame.f_code.co_name, # Keep just the filename. "sys_settrace_" + frame.f_code.co_filename.split("sys_settrace_")[-1], - frame.f_lineno, + max( + 1, frame.f_lineno + ), # CPython 3.11 emits `0` where CPython 3.6 emits `1` for the "call" event corresponding to import. ) ) From b2b5bcce28016c16f9c25772195ebe89576c17de Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 23 Aug 2023 13:30:20 +1000 Subject: [PATCH 069/121] py/profile: Remove the requirement to disable MICROPY_COMP_CONST. The only reason that const had to be disabled was to make the test output match CPython when const was involved. Instead, this commit fixes the test to handle the lines where const is used. Also: - remove the special handling for MICROPY_PERSISTENT_CODE_SAVE in unix/mpconfigport.h, and make this automatic. - move the check for MICROPY_PERSISTENT_CODE_SAVE to where it's used (like we do for other similar checks) and add a comment explaining it. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/unix/mpconfigport.h | 6 ------ py/mpconfig.h | 16 ++++------------ py/profile.c | 6 ++++++ tests/misc/sys_settrace_features.py | 5 +++++ .../sys_settrace_subdir/sys_settrace_importme.py | 10 ++++++++-- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index c20aff1683..2de05a0a6c 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -134,12 +134,6 @@ typedef long mp_off_t; #define MICROPY_STACKLESS_STRICT (0) #endif -// If settrace is enabled then we need code saving. -#if MICROPY_PY_SYS_SETTRACE -#define MICROPY_PERSISTENT_CODE_SAVE (1) -#define MICROPY_COMP_CONST (0) -#endif - // Unix-specific configuration of machine.mem*. #define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr #define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr diff --git a/py/mpconfig.h b/py/mpconfig.h index de4a89206b..46c62913cc 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -312,9 +312,11 @@ #define MICROPY_PERSISTENT_CODE_LOAD (0) #endif -// Whether to support saving of persistent code +// Whether to support saving of persistent code, i.e. for mpy-cross to +// generate .mpy files. Enabling this enables additional metadata on raw code +// objects which is also required for sys.settrace. #ifndef MICROPY_PERSISTENT_CODE_SAVE -#define MICROPY_PERSISTENT_CODE_SAVE (0) +#define MICROPY_PERSISTENT_CODE_SAVE (MICROPY_PY_SYS_SETTRACE) #endif // Whether to support saving persistent code to a file via mp_raw_code_save_file @@ -2013,14 +2015,4 @@ typedef double mp_float_t; #define MP_WARN_CAT(x) (NULL) #endif -// Feature dependency check. -#if MICROPY_PY_SYS_SETTRACE -#if !MICROPY_PERSISTENT_CODE_SAVE -#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_PERSISTENT_CODE_SAVE to be enabled" -#endif -#if MICROPY_COMP_CONST -#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_COMP_CONST to be disabled" -#endif -#endif - #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/py/profile.c b/py/profile.c index 89af8640a0..274089d702 100644 --- a/py/profile.c +++ b/py/profile.c @@ -31,6 +31,12 @@ #if MICROPY_PY_SYS_SETTRACE +#if !MICROPY_PERSISTENT_CODE_SAVE +// The settrace feature requires that we maintain additional metadata on the raw +// code object which is normally only done when writing .mpy files. +#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_PERSISTENT_CODE_SAVE to be enabled" +#endif + #define prof_trace_cb MP_STATE_THREAD(prof_trace_callback) #define QSTR_MAP(context, idx) (context->constants.qstr_table[idx]) diff --git a/tests/misc/sys_settrace_features.py b/tests/misc/sys_settrace_features.py index 84cf875a86..8ca6b382e3 100644 --- a/tests/misc/sys_settrace_features.py +++ b/tests/misc/sys_settrace_features.py @@ -67,6 +67,11 @@ def trace_tick_handler(frame, event, arg): if any(name in frame_name for name in to_ignore): return + # Lines 4,5,7 create the `const` lambda, and line `15` is a `_X = const()` which + # MicroPython will not see as it's optimised out. + if "sys_settrace_importme" in frame.f_code.co_filename and frame.f_lineno in (4, 5, 7, 15): + return trace_tick_handler + print("### trace_handler::main event:", event) __prof__.trace_tick(frame, event, arg) diff --git a/tests/misc/sys_settrace_subdir/sys_settrace_importme.py b/tests/misc/sys_settrace_subdir/sys_settrace_importme.py index de561ef217..fdfa06134e 100644 --- a/tests/misc/sys_settrace_subdir/sys_settrace_importme.py +++ b/tests/misc/sys_settrace_subdir/sys_settrace_importme.py @@ -3,12 +3,18 @@ print("Yep, I got imported.") try: x = const(1) except NameError: - print("const not defined") + # Either running on CPython or MICROPY_COMP_CONST disabled. + const = lambda x: x -const = lambda x: x +# No const optimisation. _CNT01 = "CONST01" + +# Const assigned to an underscore name. Invisible to MicroPython with +# MICROPY_COMP_CONST enabled. _CNT02 = const(123) + +# Consts assigned to regular name, executed normally. A123 = const(123) a123 = const(123) From f3eccb154c32213860cd6226fd42c5006920f2ff Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 23 Aug 2023 13:37:06 +1000 Subject: [PATCH 070/121] py/mpconfig: Enable SSL finalizers if finalizers are enabled. The rp2 port was enabling SSL and had finalizers enabled via the "extra features" level, but missed explicitly enabling `MICROPY_PY_SSL_FINALISER` (like esp32, stm32, and mimxrt did). This commit makes `MICROPY_PY_SSL_FINALISER` default to enabled if finalizers are enabled, and removes the explicit setting of this for esp32, stm32, mimxrt (because they all use the "extra features" level). This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/esp32/mpconfigport.h | 1 - ports/mimxrt/mpconfigport.h | 2 -- ports/stm32/mpconfigport.h | 1 - py/mpconfig.h | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 55035b5f86..ae73e02e41 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -139,7 +139,6 @@ #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (esp_rom_get_cpu_ticks_per_us() * 1000000 / 200) // roughly #define MICROPY_PY_SSL (1) #define MICROPY_SSL_MBEDTLS (1) -#define MICROPY_PY_SSL_FINALISER (1) #define MICROPY_PY_WEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_ONEWIRE (1) diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 52054c5d4d..cd69151ed8 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -67,7 +67,6 @@ uint32_t trng_random_u32(void); // Extended modules #define MICROPY_EPOCH_IS_1970 (1) -#define MICROPY_PY_SSL_FINALISER (MICROPY_PY_SSL) #define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1) #define MICROPY_PY_TIME_TIME_TIME_NS (1) #define MICROPY_PY_TIME_INCLUDEFILE "ports/mimxrt/modtime.c" @@ -110,7 +109,6 @@ uint32_t trng_random_u32(void); #define MICROPY_PY_WEBSOCKET (MICROPY_PY_LWIP) #define MICROPY_PY_WEBREPL (MICROPY_PY_LWIP) #define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP) -#define MICROPY_PY_SSL_FINALISER (MICROPY_PY_SSL) // #define MICROPY_PY_HASHLIB_MD5 (MICROPY_PY_SSL) #define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL) // #define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 37165b1589..2d2d81486b 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -92,7 +92,6 @@ #endif // extended modules -#define MICROPY_PY_SSL_FINALISER (MICROPY_PY_SSL) #define MICROPY_PY_HASHLIB_MD5 (MICROPY_PY_SSL) #define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL) #define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL) diff --git a/py/mpconfig.h b/py/mpconfig.h index 46c62913cc..433d6e50de 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1718,7 +1718,7 @@ typedef double mp_float_t; // Whether to add finaliser code to ssl objects #ifndef MICROPY_PY_SSL_FINALISER -#define MICROPY_PY_SSL_FINALISER (0) +#define MICROPY_PY_SSL_FINALISER (MICROPY_ENABLE_FINALISER) #endif #ifndef MICROPY_PY_WEBSOCKET From 313068a5b34597ce1ea315b1a3b198349d92c9eb Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 30 Aug 2023 13:52:31 +1000 Subject: [PATCH 071/121] extmod/modssl_mbedtls: Clear sock member if error creating SSLSocket. Otherwise if/when the finaliser runs for this newly created SSLSocket the mbedtls state will be freed again. Signed-off-by: Damien George --- extmod/modssl_mbedtls.c | 1 + 1 file changed, 1 insertion(+) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index b02b77b76f..445978e0c3 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -394,6 +394,7 @@ STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t return MP_OBJ_FROM_PTR(o); cleanup: + o->sock = MP_OBJ_NULL; mbedtls_ssl_free(&o->ssl); mbedtls_raise_error(ret); } From 6b407d5600620dfd6670304b77008d92fd19388b Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 2 May 2023 12:34:12 +0200 Subject: [PATCH 072/121] mimxrt/machine_pin: Extend pin configuration functions. Add portable pin config macros to mphalport.h. And add a function to configure pins with more pin options such as alt function, pull, speed, drive, interrupt mode, etc. Note: this new `machine_pin_config()` function can replace `machine_pin_set_mode()`, but the latter is left as-is to avoid breaking anything. Signed-off-by: iabdalkader --- ports/mimxrt/machine_pin.c | 54 ++++++++++++++++++++++++++++++++++++++ ports/mimxrt/mphalport.h | 19 ++++++++++++++ ports/mimxrt/pin.h | 9 +++++++ 3 files changed, 82 insertions(+) diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c index c66718e976..5dfb2b72e2 100644 --- a/ports/mimxrt/machine_pin.c +++ b/ports/mimxrt/machine_pin.c @@ -187,6 +187,60 @@ void machine_pin_set_mode(const machine_pin_obj_t *self, uint8_t mode) { GPIO_PinInit(self->gpio, self->pin, &pin_config); } +void machine_pin_config(const machine_pin_obj_t *self, uint8_t mode, + uint8_t pull, uint8_t drive, uint8_t speed, uint8_t alt) { + (void)speed; + gpio_pin_config_t pin_config = {0}; + + if (IS_GPIO_IT_MODE(mode)) { + if (mode == PIN_MODE_IT_FALLING) { + pin_config.interruptMode = kGPIO_IntFallingEdge; + } else if (mode == PIN_MODE_IT_RISING) { + pin_config.interruptMode = kGPIO_IntRisingEdge; + } else if (mode == PIN_MODE_IT_BOTH) { + pin_config.interruptMode = kGPIO_IntRisingOrFallingEdge; + } + // Set pad config mode to input. + mode = PIN_MODE_IN; + } + + if (mode == PIN_MODE_IN) { + pin_config.direction = kGPIO_DigitalInput; + } else { + pin_config.direction = kGPIO_DigitalOutput; + } + + if (mode != PIN_MODE_ALT) { + // GPIO is always ALT5 + alt = PIN_AF_MODE_ALT5; + } + + const machine_pin_af_obj_t *af = pin_find_af(self, alt); + if (af == NULL) { + return; + } + + // Configure the pad. + uint32_t pad_config = pin_generate_config(pull, mode, drive, self->configRegister); + IOMUXC_SetPinMux(self->muxRegister, alt, af->input_register, af->input_daisy, self->configRegister, 0U); + IOMUXC_SetPinConfig(self->muxRegister, alt, af->input_register, af->input_daisy, self->configRegister, pad_config); + + // Initialize the pin. + GPIO_PinInit(self->gpio, self->pin, &pin_config); + + // Configure interrupt (if enabled). + if (pin_config.interruptMode != kGPIO_NoIntmode) { + uint32_t gpio_nr = GPIO_get_instance(self->gpio); + uint32_t irq_num = self->pin < 16 ? GPIO_combined_low_irqs[gpio_nr] : GPIO_combined_high_irqs[gpio_nr]; + + GPIO_PortEnableInterrupts(self->gpio, 1U << self->pin); + GPIO_PortClearInterruptFlags(self->gpio, ~0); + + NVIC_SetPriority(irq_num, IRQ_PRI_EXTINT); + EnableIRQ(irq_num); + } +} + STATIC mp_obj_t machine_pin_obj_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); machine_pin_obj_t *self = self_in; diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h index ba7e1cfa94..1813a9834b 100644 --- a/ports/mimxrt/mphalport.h +++ b/ports/mimxrt/mphalport.h @@ -38,6 +38,25 @@ #define MICROPY_HW_USB_CDC_TX_TIMEOUT (500) #define MP_HAL_PIN_FMT "%q" +#define MP_HAL_PIN_MODE_INPUT PIN_MODE_IN +#define MP_HAL_PIN_MODE_OUTPUT PIN_MODE_OUT +#define MP_HAL_PIN_MODE_ALT PIN_MODE_ALT +#define MP_HAL_PIN_MODE_OPEN_DRAIN PIN_MODE_OPEN_DRAIN + +#define MP_HAL_PIN_PULL_NONE PIN_PULL_DISABLED +#define MP_HAL_PIN_PULL_UP PIN_PULL_UP_100K +#define MP_HAL_PIN_PULL_DOWN PIN_PULL_DOWN_100K + +#define MP_HAL_PIN_SPEED_LOW (0) +#define MP_HAL_PIN_SPEED_MEDIUM (1) +#define MP_HAL_PIN_SPEED_HIGH (2) +#define MP_HAL_PIN_SPEED_VERY_HIGH (3) + +#define MP_HAL_PIN_TRIGGER_NONE kGPIO_NoIntmode +#define MP_HAL_PIN_TRIGGER_FALL kGPIO_IntFallingEdge +#define MP_HAL_PIN_TRIGGER_RISE kGPIO_IntRisingEdge +#define MP_HAL_PIN_TRIGGER_RISE_FALL kGPIO_IntRisingOrFallingEdge + extern ringbuf_t stdin_ringbuf; // Define an alias for systick_ms, because the shared softtimer.c uses diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h index 63db55f8a7..aa86f05e82 100644 --- a/ports/mimxrt/pin.h +++ b/ports/mimxrt/pin.h @@ -39,6 +39,10 @@ ((MODE) == PIN_MODE_OPEN_DRAIN) || \ ((MODE) == PIN_MODE_ALT)) +#define IS_GPIO_IT_MODE(MODE) (((MODE) == PIN_MODE_IT_RISING) || \ + ((MODE) == PIN_MODE_IT_FALLING) || \ + ((MODE) == PIN_MODE_IT_BOTH)) + #define IS_GPIO_DRIVE(DRIVE) (((DRIVE) == PIN_DRIVE_OFF) || \ ((DRIVE) == PIN_DRIVE_0) || \ ((DRIVE) == PIN_DRIVE_1) || \ @@ -56,6 +60,9 @@ enum { PIN_MODE_OPEN_DRAIN, PIN_MODE_ALT, PIN_MODE_SKIP, + PIN_MODE_IT_RISING, + PIN_MODE_IT_FALLING, + PIN_MODE_IT_BOTH, }; enum { @@ -161,6 +168,8 @@ const machine_pin_af_obj_t *pin_find_af(const machine_pin_obj_t *pin, uint8_t fn const machine_pin_af_obj_t *pin_find_af_by_index(const machine_pin_obj_t *pin, mp_uint_t af_idx); const machine_pin_af_obj_t *pin_find_af_by_name(const machine_pin_obj_t *pin, const char *name); void machine_pin_set_mode(const machine_pin_obj_t *pin, uint8_t mode); +void machine_pin_config(const machine_pin_obj_t *self, uint8_t mode, + uint8_t pull, uint8_t drive, uint8_t speed, uint8_t alt); uint32_t pin_generate_config(const uint32_t pull, const uint32_t mode, const uint32_t drive, uint32_t config_register); #endif // MICROPY_INCLUDED_MIMXRT_PIN_H From 46d83d97484790c163d4276e2472fc925aaaf8ff Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 2 May 2023 12:44:46 +0200 Subject: [PATCH 073/121] mimxrt/sdio: Add SDIO driver. This is a basic SDIO driver for the mimxrt port, that was added mainly to support the CYW43 WiFi driver, and as such it only supports the commands required by the CYW43 driver (but more commands can be added easily). The driver performs non-blocking DMA transfers, and can detect and recover from errors. Note: because the mimxrt port is missing static alternate functions, named pins and other pin related functions, currently the alternate functions for USDHC 1 and 2 are hard-coded in the driver. Signed-off-by: iabdalkader --- ports/mimxrt/Makefile | 1 + ports/mimxrt/sdio.c | 334 ++++++++++++++++++++++++++++++++++++++++++ ports/mimxrt/sdio.h | 40 +++++ 3 files changed, 375 insertions(+) create mode 100644 ports/mimxrt/sdio.c create mode 100644 ports/mimxrt/sdio.h diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 8cb46245ae..f74e957c31 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -216,6 +216,7 @@ SRC_C += \ pendsv.c \ pin.c \ sdcard.c \ + sdio.c \ systick.c \ ticks.c \ tusb_port.c \ diff --git a/ports/mimxrt/sdio.c b/ports/mimxrt/sdio.c new file mode 100644 index 0000000000..771a01e3d9 --- /dev/null +++ b/ports/mimxrt/sdio.c @@ -0,0 +1,334 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Ibrahim Abdelkader + * + * 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 +#include "py/mperrno.h" +#include "py/mphal.h" +#include "pin.h" +#include "pendsv.h" + +#include "fsl_usdhc.h" +#include "fsl_iomuxc.h" + +#if MICROPY_PY_NETWORK_CYW43 + +#if MICROPY_HW_SDIO_SDMMC == 1 +#define SDMMC USDHC1 +#define SDMMC_IRQn USDHC1_IRQn +#define SDMMC_CLOCK_DIV kCLOCK_Usdhc1Div +#define SDMMC_CLOCK_MUX kCLOCK_Usdhc1Mux +#ifndef MICROPY_HW_SDIO_CLK_ALT +#define MICROPY_HW_SDIO_CMD_ALT (0) +#define MICROPY_HW_SDIO_CLK_ALT (0) +#define MICROPY_HW_SDIO_D0_ALT (0) +#define MICROPY_HW_SDIO_D1_ALT (0) +#define MICROPY_HW_SDIO_D2_ALT (0) +#define MICROPY_HW_SDIO_D3_ALT (0) +#endif +#else +#define SDMMC USDHC2 +#define SDMMC_IRQn USDHC2_IRQn +#define SDMMC_CLOCK_DIV kCLOCK_Usdhc2Div +#define SDMMC_CLOCK_MUX kCLOCK_Usdhc2Mux +#ifndef MICROPY_HW_SDIO_CLK_ALT +#define MICROPY_HW_SDIO_CMD_ALT (6) +#define MICROPY_HW_SDIO_CLK_ALT (6) +#define MICROPY_HW_SDIO_D0_ALT (6) +#define MICROPY_HW_SDIO_D1_ALT (6) +#define MICROPY_HW_SDIO_D2_ALT (6) +#define MICROPY_HW_SDIO_D3_ALT (6) +#endif +#endif + +#define SDMMC_CLOCK_400KHZ (400000U) +#define SDMMC_CLOCK_25MHZ (25000000U) +#define SDMMC_CLOCK_50MHZ (50000000U) + +#if SDIO_DEBUG +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#else +#define debug_printf(...) +#endif + +#define DMA_DESCRIPTOR_BUFFER_SIZE (32U) +AT_NONCACHEABLE_SECTION_ALIGN( + static uint32_t sdio_adma_descriptor_table[DMA_DESCRIPTOR_BUFFER_SIZE], USDHC_ADMA2_ADDRESS_ALIGN); + +typedef struct _mimxrt_sdmmc_t { + USDHC_Type *inst; + usdhc_handle_t handle; + volatile uint32_t xfer_flags; + volatile uint32_t xfer_error; +} mimxrt_sdmmc_t; + +static mimxrt_sdmmc_t sdmmc = { + .inst = SDMMC, +}; + +typedef enum { + SDIO_TRANSFER_DATA_COMPLETE = (1 << 0), + SDIO_TRANSFER_CMD_COMPLETE = (1 << 1), + SDIO_TRANSFER_ERROR = (1 << 2), +} sdio_xfer_flags_t; + +static uint32_t sdio_base_clk(void) { + return CLOCK_GetSysPfdFreq(kCLOCK_Pfd0) / (CLOCK_GetDiv(kCLOCK_Usdhc1Div) + 1U); +} + +static uint32_t sdio_response_type(uint32_t cmd) { + switch (cmd) { + case 3: + return kCARD_ResponseTypeR6; + case 5: + return kCARD_ResponseTypeR4; + case 7: + return kCARD_ResponseTypeR1; + case 52: + return kCARD_ResponseTypeR5; + default: + return kCARD_ResponseTypeNone; + } +} + +static void sdio_transfer_callback(USDHC_Type *base, + usdhc_handle_t *handle, status_t status, void *userData) { + if (status == kStatus_USDHC_TransferDataComplete) { + sdmmc.xfer_flags |= SDIO_TRANSFER_DATA_COMPLETE; + } else if (status == kStatus_USDHC_SendCommandSuccess) { + sdmmc.xfer_flags |= SDIO_TRANSFER_CMD_COMPLETE; + } else if (status != kStatus_USDHC_BusyTransferring) { + sdmmc.xfer_error = status; + sdmmc.xfer_flags |= SDIO_TRANSFER_ERROR; + } +} + +static void sdio_interrupt_callback(USDHC_Type *base, void *userData) { + extern void (*cyw43_poll)(void); + + USDHC_DisableInterruptSignal(base, kUSDHC_CardInterruptFlag); + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CardInterruptFlag); + + if (cyw43_poll) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } +} + +void sdio_init(uint32_t irq_pri) { + machine_pin_config(MICROPY_HW_SDIO_CMD, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_CMD_ALT); + machine_pin_config(MICROPY_HW_SDIO_CLK, PIN_MODE_ALT, PIN_PULL_DISABLED, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_CLK_ALT); + machine_pin_config(MICROPY_HW_SDIO_D0, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D0_ALT); + machine_pin_config(MICROPY_HW_SDIO_D1, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D1_ALT); + machine_pin_config(MICROPY_HW_SDIO_D2, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D2_ALT); + machine_pin_config(MICROPY_HW_SDIO_D3, PIN_MODE_ALT, PIN_PULL_UP_100K, PIN_DRIVE_6, 0, MICROPY_HW_SDIO_D3_ALT); + + // Configure PFD0 of PLL2 (system PLL) fractional divider to 24 resulting in: + // with PFD0_clk = PLL2_clk * 18 / N + // PFD0_clk = 528MHz * 18 / 24 = 396MHz + CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U); + CLOCK_SetDiv(SDMMC_CLOCK_DIV, 1U); // USDHC_input_clk = PFD0_clk / 2 + CLOCK_SetMux(SDMMC_CLOCK_MUX, 1U); // Select PFD0 as clock input for USDHC + + // Initialize USDHC + const usdhc_config_t config = { + .endianMode = kUSDHC_EndianModeLittle, + .dataTimeout = 0xFU, + .readBurstLen = 0, + .writeBurstLen = 0, + .readWatermarkLevel = 128U, + .writeWatermarkLevel = 128U, + }; + + USDHC_Init(sdmmc.inst, &config); + USDHC_Reset(SDMMC, kUSDHC_ResetAll, 1000U); + USDHC_DisableInterruptSignal(SDMMC, kUSDHC_AllInterruptFlags); + USDHC_SetSdClock(sdmmc.inst, sdio_base_clk(), SDMMC_CLOCK_25MHZ); + USDHC_SetDataBusWidth(sdmmc.inst, kUSDHC_DataBusWidth1Bit); + + mp_hal_delay_ms(10); + + NVIC_SetPriority(SDMMC_IRQn, irq_pri); + EnableIRQ(SDMMC_IRQn); + + usdhc_transfer_callback_t callbacks = { + .SdioInterrupt = sdio_interrupt_callback, + .TransferComplete = sdio_transfer_callback, + }; + USDHC_TransferCreateHandle(sdmmc.inst, &sdmmc.handle, &callbacks, NULL); +} + +void sdio_deinit(void) { +} + +void sdio_reenable(void) { +} + +void sdio_enable_irq(bool enable) { + if (enable) { + USDHC_ClearInterruptStatusFlags(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_EnableInterruptStatus(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_EnableInterruptSignal(sdmmc.inst, kUSDHC_CardInterruptFlag); + } else { + USDHC_DisableInterruptStatus(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_ClearInterruptStatusFlags(sdmmc.inst, kUSDHC_CardInterruptFlag); + USDHC_DisableInterruptSignal(sdmmc.inst, kUSDHC_CardInterruptFlag); + } +} + +void sdio_enable_high_speed_4bit(void) { + USDHC_SetSdClock(sdmmc.inst, sdio_base_clk(), SDMMC_CLOCK_50MHZ); + USDHC_SetDataBusWidth(sdmmc.inst, kUSDHC_DataBusWidth4Bit); +} + +static status_t sdio_transfer_dma(USDHC_Type *base, + usdhc_handle_t *handle, usdhc_transfer_t *transfer, uint32_t timeout_ms) { + status_t status; + usdhc_adma_config_t dma_config = { + .dmaMode = kUSDHC_DmaModeAdma2, + #if !FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN + .burstLen = kUSDHC_EnBurstLenForINCR, + #endif + .admaTable = sdio_adma_descriptor_table, + .admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE, + }; + + sdmmc.xfer_flags = 0; + sdmmc.xfer_error = 0; + + uint32_t xfer_flags = SDIO_TRANSFER_CMD_COMPLETE; + if (transfer->data != NULL) { + xfer_flags |= SDIO_TRANSFER_DATA_COMPLETE; + } + + status = USDHC_TransferNonBlocking(base, handle, &dma_config, transfer); + if (status != kStatus_Success) { + debug_printf("sdio_transfer_dma failed to start transfer error: %lu\n", status); + return status; + } + + uint32_t start = mp_hal_ticks_ms(); + while ((sdmmc.xfer_flags != xfer_flags) && + !(sdmmc.xfer_flags & SDIO_TRANSFER_ERROR) && + (mp_hal_ticks_ms() - start) < timeout_ms) { + MICROPY_EVENT_POLL_HOOK; + } + + if (sdmmc.xfer_flags == 0) { + debug_printf("sdio_transfer_dma transfer timeout.\n"); + return kStatus_Timeout; + } else if (sdmmc.xfer_flags != xfer_flags) { + debug_printf("sdio_transfer_dma transfer failed: %lu\n", sdmmc.xfer_error); + USDHC_Reset(base, kUSDHC_ResetCommand, 100); + if (xfer_flags & SDIO_TRANSFER_DATA_COMPLETE) { + USDHC_Reset(base, kUSDHC_ResetData, 100); + } + return sdmmc.xfer_error; + } + + return kStatus_Success; +} + +int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { + status_t status; + usdhc_command_t command = { + .index = cmd, + .argument = arg, + .type = kCARD_CommandTypeNormal, + .responseType = sdio_response_type(cmd), + .responseErrorFlags = 0 + }; + + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdio_transfer_dma(sdmmc.inst, &sdmmc.handle, &transfer, 5000); + + if (status != kStatus_Success) { + debug_printf("sdio_transfer failed!\n"); + return -MP_EIO; + } + + if (resp != NULL) { + *resp = command.response[0]; + } + + return 0; +} + +int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf) { + usdhc_data_t data = { + .enableAutoCommand12 = false, + .enableAutoCommand23 = false, + .enableIgnoreError = false, + .dataType = kUSDHC_TransferDataNormal, + }; + + usdhc_command_t command = { + .index = 53, + .argument = arg, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR5, + .responseErrorFlags = 0 + }; + + usdhc_transfer_t transfer = { + .data = &data, + .command = &command, + }; + + if (write) { + data.rxData = NULL; + data.txData = (uint32_t *)buf; + } else { + data.txData = NULL; + data.rxData = (uint32_t *)buf; + } + + if (arg & (1 << 27)) { + // SDIO_BLOCK_MODE + data.blockSize = block_size; + data.blockCount = len / block_size; + } else { + // SDIO_BYTE_MODE + data.blockSize = block_size; + data.blockCount = 1; + } + + debug_printf("cmd53 rw: %d addr 0x%p blocksize %u blockcount %lu total %lu len %d\n", + write, buf, data.blockSize, data.blockCount, data.blockSize * data.blockCount, len); + + status_t status = sdio_transfer_dma(sdmmc.inst, &sdmmc.handle, &transfer, 5000); + + if (status != kStatus_Success) { + debug_printf("sdio_transfer_cmd53 failed!\n"); + return -1; + } + + return 0; +} + +#endif diff --git a/ports/mimxrt/sdio.h b/ports/mimxrt/sdio.h new file mode 100644 index 0000000000..f8d6f498b6 --- /dev/null +++ b/ports/mimxrt/sdio.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Ibrahim Abdelkader + * + * 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. + */ +#ifndef MICROPY_INCLUDED_MIMXRT_SDIO_H +#define MICROPY_INCLUDED_MIMXRT_SDIO_H + +#include +#include + +void sdio_init(uint32_t irq_pri); +void sdio_deinit(void); +void sdio_reenable(void); +void sdio_enable_irq(bool enable); +void sdio_enable_high_speed_4bit(void); +int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp); +int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf); + +#endif // MICROPY_INCLUDED_MIMXRT_SDIO_H From 772a36098f1b30ce1a5988c84471c7caec98b119 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 2 May 2023 12:44:05 +0200 Subject: [PATCH 074/121] mimxrt: Integrate support for WiFi via the CYW43 driver. This commit adds the necessary configuration and hooks to get the CYW43 driver working with the mimxrt port. Signed-off-by: iabdalkader --- ports/mimxrt/board_init.c | 1 + ports/mimxrt/cyw43_configport.h | 155 ++++++++++++++++++++++++++++++++ ports/mimxrt/machine_pin.c | 13 +++ ports/mimxrt/main.c | 14 +++ ports/mimxrt/mpconfigport.h | 8 ++ ports/mimxrt/mpnetworkport.c | 15 ++++ ports/mimxrt/pendsv.h | 3 + 7 files changed, 209 insertions(+) create mode 100644 ports/mimxrt/cyw43_configport.h diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 78001862f0..9222b302b2 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -63,6 +63,7 @@ void board_init(void) { // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)); // USB0 usb_phy0_init(0b0111, 0b0110, 0b0110); // Configure nominal values for D_CAL and TXCAL45DP/DN diff --git a/ports/mimxrt/cyw43_configport.h b/ports/mimxrt/cyw43_configport.h new file mode 100644 index 0000000000..5f96856474 --- /dev/null +++ b/ports/mimxrt/cyw43_configport.h @@ -0,0 +1,155 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Damien P. George + * Copyright (c) 2022 Jim Mussared + * + * 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. + */ +#ifndef MICROPY_INCLUDED_STM32_CYW43_CONFIGPORT_H +#define MICROPY_INCLUDED_STM32_CYW43_CONFIGPORT_H + +// The board-level config will be included here, so it can set some CYW43 values. +#include "py/mpconfig.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/modnetwork.h" +#include "pendsv.h" +#include "sdio.h" + +#define CYW43_USE_SPI (0) +#define CYW43_LWIP (1) +#define CYW43_USE_STATS (0) + +#ifndef CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE +#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "lib/cyw43-driver/firmware/w4343WA1_7_45_98_50_combined.h" +#endif + +#ifndef CYW43_WIFI_NVRAM_INCLUDE_FILE +#define CYW43_WIFI_NVRAM_INCLUDE_FILE "lib/cyw43-driver/firmware/wifi_nvram_1dx.h" +#endif + +#define CYW43_IOCTL_TIMEOUT_US (1000000) +#define CYW43_SLEEP_MAX (50) +#define CYW43_NETUTILS (1) +#define CYW43_CLEAR_SDIO_INT (1) + +#define CYW43_EPERM MP_EPERM // Operation not permitted +#define CYW43_EIO MP_EIO // I/O error +#define CYW43_EINVAL MP_EINVAL // Invalid argument +#define CYW43_ETIMEDOUT MP_ETIMEDOUT // Connection timed out + +#define CYW43_THREAD_ENTER MICROPY_PY_LWIP_ENTER +#define CYW43_THREAD_EXIT MICROPY_PY_LWIP_EXIT +#define CYW43_THREAD_LOCK_CHECK + +#define CYW43_HOST_NAME mod_network_hostname + +#define CYW43_SDPCM_SEND_COMMON_WAIT __WFI(); +#define CYW43_DO_IOCTL_WAIT __WFI(); + +#define CYW43_ARRAY_SIZE(a) MP_ARRAY_SIZE(a) + +#define CYW43_HAL_PIN_MODE_INPUT MP_HAL_PIN_MODE_INPUT +#define CYW43_HAL_PIN_MODE_OUTPUT MP_HAL_PIN_MODE_OUTPUT +#define CYW43_HAL_PIN_PULL_NONE MP_HAL_PIN_PULL_NONE +#define CYW43_HAL_PIN_PULL_UP MP_HAL_PIN_PULL_UP +#define CYW43_HAL_PIN_PULL_DOWN MP_HAL_PIN_PULL_DOWN + +#define CYW43_HAL_MAC_WLAN0 MP_HAL_MAC_WLAN0 + +#define cyw43_hal_ticks_us mp_hal_ticks_us +#define cyw43_hal_ticks_ms mp_hal_ticks_ms + +#define cyw43_hal_pin_obj_t mp_hal_pin_obj_t +#define cyw43_hal_pin_read mp_hal_pin_read +#define cyw43_hal_pin_low mp_hal_pin_low +#define cyw43_hal_pin_high mp_hal_pin_high + +#define cyw43_hal_get_mac mp_hal_get_mac +#define cyw43_hal_get_mac_ascii mp_hal_get_mac_ascii +#define cyw43_hal_generate_laa_mac mp_hal_generate_laa_mac + +#define cyw43_delay_us mp_hal_delay_us +#define cyw43_delay_ms mp_hal_delay_ms + +#define CYW43_PIN_WL_REG_ON MICROPY_HW_WL_REG_ON +#define CYW43_PIN_WL_HOST_WAKE MICROPY_HW_WL_HOST_WAKE +#define CYW43_PIN_WL_SDIO_1 MICROPY_HW_SDIO_D1 + +#define CYW43_PIN_BT_REG_ON MICROPY_HW_BT_REG_ON +#ifdef MICROPY_HW_BT_HOST_WAKE +#define CYW43_PIN_BT_HOST_WAKE MICROPY_HW_BT_HOST_WAKE +#endif +#ifdef MICROPY_HW_BT_DEV_WAKE +#define CYW43_PIN_BT_DEV_WAKE MICROPY_HW_BT_DEV_WAKE +#endif +#ifdef MICROPY_HW_BT_CTS +#define CYW43_PIN_BT_CTS MICROPY_HW_BT_CTS +#endif + +#if MICROPY_HW_ENABLE_RF_SWITCH +#define CYW43_PIN_WL_RFSW_VDD pin_WL_RFSW_VDD +#endif + +#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func) + +static inline void cyw43_hal_pin_config(cyw43_hal_pin_obj_t pin, uint8_t mode, uint8_t pull, uint8_t alt) { + machine_pin_set_mode(pin, mode); +} + +static inline void cyw43_hal_pin_config_irq_falling(cyw43_hal_pin_obj_t pin, int enable) { + if (enable) { + machine_pin_config(pin, PIN_MODE_IT_FALLING, PIN_PULL_UP_100K, 0, 0, PIN_AF_MODE_ALT5); + } +} + +static inline void cyw43_sdio_init(void) { + sdio_init(NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0)); +} + +static inline void cyw43_sdio_reinit(void) { + sdio_reenable(); +} + +static inline void cyw43_sdio_deinit(void) { + sdio_deinit(); +} + +static inline void cyw43_sdio_set_irq(bool enable) { + sdio_enable_irq(enable); +} + +static inline void cyw43_sdio_enable_high_speed_4bit(void) { + sdio_enable_high_speed_4bit(); +} + +static inline int cyw43_sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp) { + return sdio_transfer(cmd, arg, resp); +} + +static inline int cyw43_sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t len, uint8_t *buf) { + return sdio_transfer_cmd53(write, block_size, arg, len, buf); +} + +#define CYW43_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK + +#endif // MICROPY_INCLUDED_STM32_CYW43_CONFIGPORT_H diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c index 5dfb2b72e2..3ebccb1755 100644 --- a/ports/mimxrt/machine_pin.c +++ b/ports/mimxrt/machine_pin.c @@ -34,6 +34,9 @@ #include "shared/runtime/mpirq.h" #include "extmod/virtpin.h" #include "pin.h" +#if MICROPY_PY_NETWORK_CYW43 +#include "pendsv.h" +#endif // Local functions STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); @@ -98,6 +101,16 @@ void call_handler(GPIO_Type *gpio, int gpio_nr, int pin) { if (isr & mask) { gpio->ISR = mask; // clear the ISR flag int index = GET_PIN_IRQ_INDEX(gpio_nr, pin); + #if MICROPY_PY_NETWORK_CYW43 + extern void (*cyw43_poll)(void); + const machine_pin_obj_t *pin = MICROPY_HW_WL_HOST_WAKE; + if (pin->gpio == gpio && pin->pin == (index % 32)) { + if (cyw43_poll) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } + return; + } + #endif machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[index]); if (irq != NULL) { irq->flags = irq->trigger; diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 2d0760964c..8deaa54275 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -43,6 +43,9 @@ #if MICROPY_PY_LWIP #include "lwip/init.h" #include "lwip/apps/mdns.h" +#if MICROPY_PY_NETWORK_CYW43 +#include "lib/cyw43-driver/src/cyw43.h" +#endif #endif #include "systick.h" #include "extmod/modnetwork.h" @@ -69,6 +72,17 @@ int main(void) { systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif + #if MICROPY_PY_NETWORK_CYW43 + { + cyw43_init(&cyw43_state); + uint8_t buf[8]; + memcpy(&buf[0], "PYBD", 4); + mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 8, 4, (char *)&buf[4]); + cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf); + cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"pybd0123"); + } + #endif + for (;;) { #if defined(MICROPY_HW_LED1) led_init(); diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index cd69151ed8..eb5c3450b3 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -170,12 +170,20 @@ extern const struct _mp_obj_type_t network_lan_type; #define MICROPY_HW_NIC_ETH #endif +#if MICROPY_PY_NETWORK_CYW43 +extern const struct _mp_obj_type_t mp_network_cyw43_type; +#define MICROPY_HW_NIC_CYW43 { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) }, +#else +#define MICROPY_HW_NIC_CYW43 +#endif + #ifndef MICROPY_BOARD_NETWORK_INTERFACES #define MICROPY_BOARD_NETWORK_INTERFACES #endif #define MICROPY_PORT_NETWORK_INTERFACES \ MICROPY_HW_NIC_ETH \ + MICROPY_HW_NIC_CYW43 \ MICROPY_BOARD_NETWORK_INTERFACES \ #ifndef MICROPY_BOARD_ROOT_POINTERS diff --git a/ports/mimxrt/mpnetworkport.c b/ports/mimxrt/mpnetworkport.c index 2e6a49b90e..2ca3426197 100644 --- a/ports/mimxrt/mpnetworkport.c +++ b/ports/mimxrt/mpnetworkport.c @@ -43,6 +43,11 @@ #include "lwip/dhcp.h" #include "lwip/apps/mdns.h" +#if MICROPY_PY_NETWORK_CYW43 +#include "extmod/network_cyw43.h" +#include "lib/cyw43-driver/src/cyw43.h" +#endif + // Poll lwIP every 128ms #define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) @@ -59,6 +64,16 @@ void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) { if (LWIP_TICK(ticks_ms)) { pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll); } + + #if MICROPY_PY_NETWORK_CYW43 + if (cyw43_poll) { + if (cyw43_sleep != 0) { + if (--cyw43_sleep == 0) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll); + } + } + } + #endif } #endif // MICROPY_PY_LWIP diff --git a/ports/mimxrt/pendsv.h b/ports/mimxrt/pendsv.h index e68f487fb4..f3369b07fe 100644 --- a/ports/mimxrt/pendsv.h +++ b/ports/mimxrt/pendsv.h @@ -31,6 +31,9 @@ enum { #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP PENDSV_DISPATCH_LWIP, #endif + #if MICROPY_PY_NETWORK_CYW43 + PENDSV_DISPATCH_CYW43, + #endif MICROPY_BOARD_PENDSV_ENTRIES PENDSV_DISPATCH_MAX }; From fc495240a6c63a9839c8112f8c2bcbb6a0f168d0 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 9 May 2023 17:06:57 +0200 Subject: [PATCH 075/121] mimxrt: Integrate Bluetooth support with NimBLE bindings. This commit adds the necessary functions to get NimBLE working with the mimxrt port. Signed-off-by: iabdalkader --- ports/mimxrt/Makefile | 9 ++ ports/mimxrt/main.c | 12 +++ ports/mimxrt/mpbthciport.c | 196 ++++++++++++++++++++++++++++++++++++ ports/mimxrt/mpbthciport.h | 42 ++++++++ ports/mimxrt/mpconfigport.h | 9 ++ ports/mimxrt/mpnimbleport.c | 78 ++++++++++++++ ports/mimxrt/mpnimbleport.h | 30 ++++++ 7 files changed, 376 insertions(+) create mode 100644 ports/mimxrt/mpbthciport.c create mode 100644 ports/mimxrt/mpbthciport.h create mode 100644 ports/mimxrt/mpnimbleport.c create mode 100644 ports/mimxrt/mpnimbleport.h diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index f74e957c31..ead206e5e2 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -264,6 +264,14 @@ else SRC_HAL_C += hal/$(FLEXSPI_FLASH_TYPE)_config.c endif +ifeq ($(MICROPY_PY_BLUETOOTH),1) +SRC_C += mpbthciport.c +endif # MICROPY_PY_BLUETOOTH + +ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) +SRC_C += mpnimbleport.c +endif + # Math library source files ifeq ($(MICROPY_FLOAT_IMPL),double) LIBM_SRC_C += $(addprefix lib/libm_dbl/,\ @@ -449,6 +457,7 @@ OBJ += $(PY_O) OBJ += $(LIBM_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_SS:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_TINYUSB_C:.c=.o)) diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 8deaa54275..993e598185 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -47,6 +47,12 @@ #include "lib/cyw43-driver/src/cyw43.h" #endif #endif + +#if MICROPY_PY_BLUETOOTH +#include "mpbthciport.h" +#include "extmod/modbluetooth.h" +#endif + #include "systick.h" #include "extmod/modnetwork.h" @@ -71,6 +77,9 @@ int main(void) { systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_hci_init(); + #endif #if MICROPY_PY_NETWORK_CYW43 { @@ -135,6 +144,9 @@ int main(void) { #if MICROPY_PY_MACHINE_I2S machine_i2s_deinit_all(); #endif + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_deinit(); + #endif #if MICROPY_PY_NETWORK mod_network_deinit(); #endif diff --git a/ports/mimxrt/mpbthciport.c b/ports/mimxrt/mpbthciport.c new file mode 100644 index 0000000000..c83c765871 --- /dev/null +++ b/ports/mimxrt/mpbthciport.c @@ -0,0 +1,196 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2021 Damien P. George + * Copyright (c) 2023 Ibrahim Abdelkader + * + * 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 "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/modbluetooth.h" +#include "extmod/mpbthci.h" +#include "shared/runtime/softtimer.h" +#include "modmachine.h" +#include "mpbthciport.h" + +#include "fsl_lpuart.h" +#include CLOCK_CONFIG_H + +#if MICROPY_PY_BLUETOOTH + +#define DEBUG_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) +#define ERROR_printf(...) mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) + +uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; + +STATIC mp_sched_node_t mp_bluetooth_hci_sched_node; +STATIC soft_timer_entry_t mp_bluetooth_hci_soft_timer; + +STATIC void mp_bluetooth_hci_soft_timer_callback(soft_timer_entry_t *self) { + mp_bluetooth_hci_poll_now(); +} + +void mp_bluetooth_hci_init(void) { + soft_timer_static_init( + &mp_bluetooth_hci_soft_timer, + SOFT_TIMER_MODE_ONE_SHOT, + 0, + mp_bluetooth_hci_soft_timer_callback + ); +} + +STATIC void mp_bluetooth_hci_start_polling(void) { + mp_bluetooth_hci_poll_now(); +} + +void mp_bluetooth_hci_poll_in_ms(uint32_t ms) { + soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms); +} + +// For synchronous mode, we run all BLE stack code inside a scheduled task. +STATIC void run_events_scheduled_task(mp_sched_node_t *node) { + // This will process all buffered HCI UART data, and run any callouts or events. + mp_bluetooth_hci_poll(); +} + +// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to +// request that processing happens ASAP in the scheduler. +void mp_bluetooth_hci_poll_now(void) { + mp_sched_schedule_node(&mp_bluetooth_hci_sched_node, run_events_scheduled_task); +} + +mp_obj_t mp_bthci_uart; + +int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { + DEBUG_printf("mp_bluetooth_hci_uart_init\n"); + + mp_obj_t args[] = { + MP_OBJ_NEW_SMALL_INT(port), + MP_OBJ_NEW_QSTR(MP_QSTR_baudrate), MP_OBJ_NEW_SMALL_INT(baudrate), + MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_OBJ_NEW_SMALL_INT(200), + MP_OBJ_NEW_QSTR(MP_QSTR_timeout_char), MP_OBJ_NEW_SMALL_INT(200), + MP_OBJ_NEW_QSTR(MP_QSTR_txbuf), MP_OBJ_NEW_SMALL_INT(768), + MP_OBJ_NEW_QSTR(MP_QSTR_rxbuf), MP_OBJ_NEW_SMALL_INT(768), + }; + + mp_bthci_uart = MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, make_new)((mp_obj_t)&machine_uart_type, 1, 5, args); + MP_STATE_PORT(mp_bthci_uart) = mp_bthci_uart; + + // Start the HCI polling to process any initial events/packets. + mp_bluetooth_hci_start_polling(); + return 0; +} + +int mp_bluetooth_hci_uart_deinit(void) { + DEBUG_printf("mp_bluetooth_hci_uart_deinit\n"); + mp_bthci_uart = MP_OBJ_NULL; + return 0; +} + +int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { + DEBUG_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate); + if (mp_bthci_uart != MP_OBJ_NULL) { + // This struct is not public, so we use the base defined in board config files. + // machine_uart_obj_t uart = (machine_uart_obj_t *) MP_PTR_FROM_OBJ(mp_bthci_uart); + LPUART_SetBaudRate(MICROPY_HW_BLE_UART_BASE, baudrate, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT); + } + return 0; +} + +int mp_bluetooth_hci_uart_any(void) { + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + + mp_uint_t ret = proto->ioctl(mp_bthci_uart, MP_STREAM_POLL, MP_STREAM_POLL_RD, &errcode); + if (errcode != 0) { + ERROR_printf("Uart ioctl failed to poll UART %d\n", errcode); + return -1; + } + return ret & MP_STREAM_POLL_RD; +} + +int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { + DEBUG_printf("mp_bluetooth_hci_uart_write\n"); + + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + + mp_bluetooth_hci_controller_wakeup(); + + if (proto->write(mp_bthci_uart, (void *)buf, len, &errcode) < 0) { + ERROR_printf("mp_bluetooth_hci_uart_write: failed to write to UART %d\n", errcode); + } + return 0; +} + +// This function expects the controller to be in the wake state via a previous call +// to mp_bluetooth_hci_controller_woken. +int mp_bluetooth_hci_uart_readchar(void) { + DEBUG_printf("mp_bluetooth_hci_uart_readchar\n"); + if (mp_bluetooth_hci_uart_any()) { + int errcode = 0; + uint8_t buf = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + if (proto->read(mp_bthci_uart, (void *)&buf, 1, &errcode) < 0) { + ERROR_printf("mp_bluetooth_hci_uart_readchar: failed to read UART %d\n", errcode); + return -1; + } + return buf; + } else { + DEBUG_printf("mp_bluetooth_hci_uart_readchar: not ready\n"); + return -1; + } +} + +// Default (weak) implementation of the HCI controller interface. +// A driver (e.g. cywbt43.c) can override these for controller-specific +// functionality (i.e. power management). +MP_WEAK int mp_bluetooth_hci_controller_init(void) { + DEBUG_printf("mp_bluetooth_hci_controller_init (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_deinit(void) { + DEBUG_printf("mp_bluetooth_hci_controller_deinit (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_sleep_maybe(void) { + DEBUG_printf("mp_bluetooth_hci_controller_sleep_maybe (default)\n"); + return 0; +} + +MP_WEAK bool mp_bluetooth_hci_controller_woken(void) { + DEBUG_printf("mp_bluetooth_hci_controller_woken (default)\n"); + return true; +} + +MP_WEAK int mp_bluetooth_hci_controller_wakeup(void) { + DEBUG_printf("mp_bluetooth_hci_controller_wakeup (default)\n"); + return 0; +} + +MP_REGISTER_ROOT_POINTER(mp_obj_t mp_bthci_uart); + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/mimxrt/mpbthciport.h b/ports/mimxrt/mpbthciport.h new file mode 100644 index 0000000000..124c85dae5 --- /dev/null +++ b/ports/mimxrt/mpbthciport.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2021 Damien P. George + * + * 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. + */ +#ifndef MICROPY_INCLUDED_MIMXRT_MPBTHCIPORT_H +#define MICROPY_INCLUDED_MIMXRT_MPBTHCIPORT_H + +// Initialise the HCI subsystem (should be called once, early on). +void mp_bluetooth_hci_init(void); + +// Poll the HCI now, or after a certain timeout. +void mp_bluetooth_hci_poll_now(void); +void mp_bluetooth_hci_poll_in_ms(uint32_t ms); + +// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c). +// Request new data from the uart and pass to the stack, and run pending events/callouts. +// This is a low-level function and should not be called directly, use +// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead. +void mp_bluetooth_hci_poll(void); + +#endif // MICROPY_INCLUDED_MIMXRT_MPBTHCIPORT_H diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index eb5c3450b3..9dccebc1fe 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -59,6 +59,7 @@ uint32_t trng_random_u32(void); #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_SCHEDULER_DEPTH (8) +#define MICROPY_SCHEDULER_STATIC_NODES (1) #define MICROPY_VFS (1) // Control over Python builtins @@ -118,6 +119,14 @@ uint32_t trng_random_u32(void); #define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER #define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1) +#endif + +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS +#define MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS (MICROPY_BLUETOOTH_NIMBLE) +#endif + #ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT #define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-mimxrt" #endif diff --git a/ports/mimxrt/mpnimbleport.c b/ports/mimxrt/mpnimbleport.c new file mode 100644 index 0000000000..e2d39e271c --- /dev/null +++ b/ports/mimxrt/mpnimbleport.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * Copyright (c) 2020 Damien P. George + * + * 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 "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#define DEBUG_printf(...) // printf("mpnimbleport.c: " __VA_ARGS__) + +#include "host/ble_hs.h" +#include "nimble/nimble_npl.h" + +#include "extmod/mpbthci.h" +#include "extmod/modbluetooth.h" +#include "extmod/nimble/modbluetooth_nimble.h" +#include "extmod/nimble/hal/hal_uart.h" +#include "mpbthciport.h" + +// Get any pending data from the UART and send it to NimBLE's HCI buffers. +// Any further processing by NimBLE will be run via its event queue. +void mp_bluetooth_hci_poll(void) { + if (mp_bluetooth_nimble_ble_state >= MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC) { + // DEBUG_printf("mp_bluetooth_hci_poll_uart %d\n", mp_bluetooth_nimble_ble_state); + + // Run any timers. + mp_bluetooth_nimble_os_callout_process(); + + // Process incoming UART data, and run events as they are generated. + mp_bluetooth_nimble_hci_uart_process(true); + + // Run any remaining events (e.g. if there was no UART data). + mp_bluetooth_nimble_os_eventq_run_all(); + } + + if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { + // Call this function again in 128ms to check for new events. + // TODO: improve this by only calling back when needed. + mp_bluetooth_hci_poll_in_ms(128); + } +} + +// --- Port-specific helpers for the generic NimBLE bindings. ----------------- + +void mp_bluetooth_nimble_hci_uart_wfi(void) { + __WFI(); + + // This is called while NimBLE is waiting in ble_npl_sem_pend, i.e. waiting for an HCI ACK. + // Do not need to run events here (it must not invoke Python code), only processing incoming HCI data. + mp_bluetooth_nimble_hci_uart_process(false); +} + +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/mimxrt/mpnimbleport.h b/ports/mimxrt/mpnimbleport.h new file mode 100644 index 0000000000..78f4fc9b00 --- /dev/null +++ b/ports/mimxrt/mpnimbleport.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_MIMXRT_NIMBLE_PORT_H +#define MICROPY_INCLUDED_MIMXRT_NIMBLE_PORT_H + +#endif // MICROPY_INCLUDED_MIMXRT_NIMBLE_PORT_H From a453b4f31d3b5928eeb48f50ce1d6314612538c1 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 10 May 2023 15:59:15 +0200 Subject: [PATCH 076/121] drivers/cyw43: Make the CYW43 Bluetooth HCI driver more portable. This commit allows other ports to reuse the CYW43 HCI driver, by replacing all Bluetooth UART and control named pins with defines in config files and using `mpbthci` abstract functions (i.e. `mp_bluetooth_hci_*`) instead of the STM32 specific UART functions. Note: the function `cywbt_wait_cts_low` does not need to switch the CTS pin from alternate function to GPIO to read it. At least on stm32, mimxrt it's possible to just read the pin input. For example, see the STM32F7 RM0410 section 6.3.11, and the `SION` for IMXRT. So this function can also be available for other ports if the pin mode switching is removed. Signed-off-by: iabdalkader --- drivers/cyw43/cywbt.c | 99 ++++++++++++++++++++-------------- ports/stm32/cyw43_configport.h | 7 +++ 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/drivers/cyw43/cywbt.c b/drivers/cyw43/cywbt.c index 006fd28e90..bc6674ea2e 100644 --- a/drivers/cyw43/cywbt.c +++ b/drivers/cyw43/cywbt.c @@ -29,8 +29,6 @@ #include "py/runtime.h" #include "py/mphal.h" -#include "pin_static_af.h" -#include "uart.h" #include "extmod/mpbthci.h" #if MICROPY_PY_NETWORK_CYW43 @@ -38,33 +36,41 @@ #include "lib/cyw43-driver/src/cyw43_config.h" #include "lib/cyw43-driver/firmware/cyw43_btfw_4343A1.h" -// Provided by the port. -extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj; - // Provided by the port, and also possibly shared with the stack. extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; /******************************************************************************/ // CYW BT HCI low-level driver +#ifdef CYW43_PIN_BT_CTS +// This code is not portable and currently only builds on stm32 port. + +#include "pin_static_af.h" +#include "uart.h" + +// Provided by the port. +extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj; + STATIC void cywbt_wait_cts_low(void) { - mp_hal_pin_config(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + mp_hal_pin_config(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); for (int i = 0; i < 200; ++i) { - if (mp_hal_pin_read(pyb_pin_BT_CTS) == 0) { + if (mp_hal_pin_read(CYW43_PIN_BT_CTS) == 0) { break; } mp_hal_delay_ms(1); } - mp_hal_pin_config_alt(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id); + mp_hal_pin_config_alt(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_ALT, + MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id); } +#endif STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { - uart_tx_strn(&mp_bluetooth_hci_uart_obj, (void*)buf, len); - for (int i = 0; i < 6; ++i) { - while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) { + mp_bluetooth_hci_uart_write((void *)buf, len); + for (int c, i = 0; i < 6; ++i) { + while ((c = mp_bluetooth_hci_uart_readchar()) == -1) { MICROPY_EVENT_POLL_HOOK } - buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj); + buf[i] = c; } // expect a command complete event (event 0x0e) @@ -80,11 +86,11 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { */ int sz = buf[2] - 3; - for (int i = 0; i < sz; ++i) { - while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) { + for (int c, i = 0; i < sz; ++i) { + while ((c = mp_bluetooth_hci_uart_readchar()) == -1) { MICROPY_EVENT_POLL_HOOK } - buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj); + buf[i] = c; } return 0; @@ -150,12 +156,15 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) { // RF switch must select high path during BT patch boot #if MICROPY_HW_ENABLE_RF_SWITCH - mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); + mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); #endif mp_hal_delay_ms(10); // give some time for CTS to go high + #ifdef CYW43_PIN_BT_CTS cywbt_wait_cts_low(); + #endif #if MICROPY_HW_ENABLE_RF_SWITCH - mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); // Select chip antenna (could also select external) + // Select chip antenna (could also select external) + mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); #endif mp_bluetooth_hci_uart_set_baudrate(115200); @@ -168,25 +177,33 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) { int mp_bluetooth_hci_controller_init(void) { // This is called immediately after the UART is initialised during stack initialisation. - mp_hal_pin_output(pyb_pin_BT_REG_ON); - mp_hal_pin_low(pyb_pin_BT_REG_ON); - mp_hal_pin_input(pyb_pin_BT_HOST_WAKE); - mp_hal_pin_output(pyb_pin_BT_DEV_WAKE); - mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); + mp_hal_pin_output(CYW43_PIN_BT_REG_ON); + mp_hal_pin_low(CYW43_PIN_BT_REG_ON); + #ifdef CYW43_PIN_BT_HOST_WAKE + mp_hal_pin_input(CYW43_PIN_BT_HOST_WAKE); + #endif + #ifdef CYW43_PIN_BT_DEV_WAKE + mp_hal_pin_output(CYW43_PIN_BT_DEV_WAKE); + mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE); + #endif #if MICROPY_HW_ENABLE_RF_SWITCH // TODO don't select antenna if wifi is enabled - mp_hal_pin_config(pyb_pin_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power - mp_hal_pin_high(pyb_pin_WL_GPIO_4); // Turn the RF-switch on + mp_hal_pin_config(CYW43_PIN_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power + mp_hal_pin_high(CYW43_PIN_WL_GPIO_4); // Turn the RF-switch on #endif uint8_t buf[256]; - mp_hal_pin_low(pyb_pin_BT_REG_ON); + mp_hal_pin_low(CYW43_PIN_BT_REG_ON); mp_bluetooth_hci_uart_set_baudrate(115200); mp_hal_delay_ms(100); - mp_hal_pin_high(pyb_pin_BT_REG_ON); + mp_hal_pin_high(CYW43_PIN_BT_REG_ON); + #ifdef CYW43_PIN_BT_CTS cywbt_wait_cts_low(); + #else + mp_hal_delay_ms(100); + #endif // Reset cywbt_hci_cmd(0x03, 0x0003, 0, NULL); @@ -197,7 +214,7 @@ int mp_bluetooth_hci_controller_init(void) { mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE); #endif - cywbt_download_firmware((const uint8_t*)&cyw43_btfw_4343A1[0]); + cywbt_download_firmware((const uint8_t *)&cyw43_btfw_4343A1[0]); // Reset cywbt_hci_cmd(0x03, 0x0003, 0, NULL); @@ -219,31 +236,33 @@ int mp_bluetooth_hci_controller_init(void) { // cywbt_hci_cmd(0x03, 0x0013, 248, buf); // Configure sleep mode - cywbt_hci_cmd(0x3f, 0x27, 12, (const uint8_t*)"\x01\x02\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00"); + cywbt_hci_cmd(0x3f, 0x27, 12, (const uint8_t *)"\x01\x02\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00"); // HCI_Write_LE_Host_Support - cywbt_hci_cmd(3, 109, 2, (const uint8_t*)"\x01\x00"); + cywbt_hci_cmd(3, 109, 2, (const uint8_t *)"\x01\x00"); - mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep + #ifdef CYW43_PIN_BT_DEV_WAKE + mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep + #endif return 0; } int mp_bluetooth_hci_controller_deinit(void) { - mp_hal_pin_low(pyb_pin_BT_REG_ON); + mp_hal_pin_low(CYW43_PIN_BT_REG_ON); return 0; } -#ifdef pyb_pin_BT_DEV_WAKE +#ifdef CYW43_PIN_BT_DEV_WAKE STATIC uint32_t bt_sleep_ticks; #endif int mp_bluetooth_hci_controller_sleep_maybe(void) { - #ifdef pyb_pin_BT_DEV_WAKE - if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 0) { + #ifdef CYW43_PIN_BT_DEV_WAKE + if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 0) { if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) { - mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep + mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep } } #endif @@ -251,8 +270,8 @@ int mp_bluetooth_hci_controller_sleep_maybe(void) { } bool mp_bluetooth_hci_controller_woken(void) { - #ifdef pyb_pin_BT_HOST_WAKE - bool host_wake = mp_hal_pin_read(pyb_pin_BT_HOST_WAKE); + #ifdef CYW43_PIN_BT_HOST_WAKE + bool host_wake = mp_hal_pin_read(CYW43_PIN_BT_HOST_WAKE); /* // this is just for info/tracing purposes static bool last_host_wake = false; @@ -268,11 +287,11 @@ bool mp_bluetooth_hci_controller_woken(void) { } int mp_bluetooth_hci_controller_wakeup(void) { - #ifdef pyb_pin_BT_DEV_WAKE + #ifdef CYW43_PIN_BT_DEV_WAKE bt_sleep_ticks = mp_hal_ticks_ms(); - if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) { - mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up + if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 1) { + mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE); // wake up // Use delay_us rather than delay_ms to prevent running the scheduler (which // might result in more BLE operations). mp_hal_delay_us(5000); // can't go lower than this diff --git a/ports/stm32/cyw43_configport.h b/ports/stm32/cyw43_configport.h index 4b6dde3c43..f2a880603a 100644 --- a/ports/stm32/cyw43_configport.h +++ b/ports/stm32/cyw43_configport.h @@ -93,6 +93,13 @@ #define CYW43_PIN_WL_REG_ON pyb_pin_WL_REG_ON #define CYW43_PIN_WL_HOST_WAKE pyb_pin_WL_HOST_WAKE #define CYW43_PIN_WL_SDIO_1 pyb_pin_WL_SDIO_1 +#define CYW43_PIN_WL_GPIO_1 pyb_pin_WL_GPIO_1 +#define CYW43_PIN_WL_GPIO_4 pyb_pin_WL_GPIO_4 + +#define CYW43_PIN_BT_REG_ON pyb_pin_BT_REG_ON +#define CYW43_PIN_BT_HOST_WAKE pyb_pin_BT_HOST_WAKE +#define CYW43_PIN_BT_DEV_WAKE pyb_pin_BT_DEV_WAKE +#define CYW43_PIN_BT_CTS pyb_pin_BT_CTS #if MICROPY_HW_ENABLE_RF_SWITCH #define CYW43_PIN_WL_RFSW_VDD pyb_pin_WL_RFSW_VDD From 3f5976e14a1e0f94f9af414bd99789ebf30a865d Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 11 May 2023 18:56:56 +0200 Subject: [PATCH 077/121] mimxrt/irq: Move all IRQ related definitions to dedicated header. Following other ports, IRQ priorities and related functions are moved to their own header, to simplify mpconfigport.h. Signed-off-by: iabdalkader --- ports/mimxrt/board_init.c | 3 +- ports/mimxrt/irq.h | 80 +++++++++++++++++++++++++++++++++++++ ports/mimxrt/mpconfigport.h | 17 -------- ports/mimxrt/mphalport.h | 1 + ports/mimxrt/pendsv.c | 4 +- 5 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 ports/mimxrt/irq.h diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 9222b302b2..88de27ea77 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -39,6 +39,7 @@ #include CLOCK_CONFIG_H #include "modmachine.h" +#include "irq.h" const uint8_t dcd_data[] = { 0x00 }; @@ -63,7 +64,7 @@ void board_init(void) { // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); - NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)); + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK); // USB0 usb_phy0_init(0b0111, 0b0110, 0b0110); // Configure nominal values for D_CAL and TXCAL45DP/DN diff --git a/ports/mimxrt/irq.h b/ports/mimxrt/irq.h new file mode 100644 index 0000000000..b83eb49ffa --- /dev/null +++ b/ports/mimxrt/irq.h @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Damien P. George + * + * 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. + */ +#ifndef MICROPY_INCLUDED_MIMXRT_IRQ_H +#define MICROPY_INCLUDED_MIMXRT_IRQ_H + +#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003) + +static inline uint32_t query_irq(void) { + return __get_PRIMASK(); +} + +static inline uint32_t raise_irq_pri(uint32_t pri) { + uint32_t basepri = __get_BASEPRI(); + // If non-zero, the processor does not process any exception with a + // priority value greater than or equal to BASEPRI. + // When writing to BASEPRI_MAX the write goes to BASEPRI only if either: + // - Rn is non-zero and the current BASEPRI value is 0 + // - Rn is non-zero and less than the current BASEPRI value + pri <<= (8 - __NVIC_PRIO_BITS); + __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); + return basepri; +} + +// "basepri" should be the value returned from raise_irq_pri +static inline void restore_irq_pri(uint32_t basepri) { + __set_BASEPRI(basepri); +} + +// IRQ priority definitions. +// +// Lower number implies higher interrupt priority. +// +// The default priority grouping used in this port is NVIC_PRIORITYGROUP_4. +// This corresponds to 4 bits for the priority field and 0 bits for the +// sub-priority field (which means that for all intents and purposes the +// sub-priorities below are ignored). +// +// While a given interrupt is being processed, only higher priority (lower number) +// interrupts will preempt a given interrupt. If sub-priorities are active +// then the sub-priority determines the order that pending interrupts of +// a given priority are executed. This is only meaningful if 2 or more +// interrupts of the same priority are pending at the same time. +// +// The following interrupts are arranged from highest priority to lowest +// priority to make it a bit easier to figure out. + +#define IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) + +#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) + +#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0) + +// PENDSV should be at the lowst priority so that other interrupts complete +// before exception is raised. +#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) + +#endif // MICROPY_INCLUDED_MIMXRT_IRQ_H diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 9dccebc1fe..fb4acede59 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -152,23 +152,6 @@ __attribute__((always_inline)) static inline uint32_t disable_irq(void) { return state; } -static inline uint32_t raise_irq_pri(uint32_t pri) { - uint32_t basepri = __get_BASEPRI(); - // If non-zero, the processor does not process any exception with a - // priority value greater than or equal to BASEPRI. - // When writing to BASEPRI_MAX the write goes to BASEPRI only if either: - // - Rn is non-zero and the current BASEPRI value is 0 - // - Rn is non-zero and less than the current BASEPRI value - pri <<= (8 - __NVIC_PRIO_BITS); - __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); - return basepri; -} - -// "basepri" should be the value returned from raise_irq_pri -static inline void restore_irq_pri(uint32_t basepri) { - __set_BASEPRI(basepri); -} - #define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() #define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h index 1813a9834b..36eb387798 100644 --- a/ports/mimxrt/mphalport.h +++ b/ports/mimxrt/mphalport.h @@ -31,6 +31,7 @@ #include "ticks.h" #include "py/ringbuf.h" #include "pin.h" +#include "irq.h" #include "fsl_clock.h" #define MICROPY_HAL_VERSION "2.8.0" diff --git a/ports/mimxrt/pendsv.c b/ports/mimxrt/pendsv.c index 11f2ef5e1c..46d13a5aca 100644 --- a/ports/mimxrt/pendsv.c +++ b/ports/mimxrt/pendsv.c @@ -28,9 +28,7 @@ #include "py/runtime.h" #include "pendsv.h" - -#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003) -#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +#include "irq.h" #if defined(PENDSV_DISPATCH_NUM_SLOTS) pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; From ce38784fa8e8abc57f7d99ce10739c4f1b577565 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 16 Aug 2023 16:00:43 +0200 Subject: [PATCH 078/121] mimxrt/machine_uart: Fix and complete UART.deinit and uart_deinit_all. The code did not check at deinit whether a UART was initialized. That did not matter for all MCU's except MIMXRT1176, which crashes at the second soft reset in a row. But since it is a general problem to use UART methods of a UART which has been deinitialized, checks were added to all applicable methods for a clear response instead of e.g. a crash. Deinitialize UART using software reset. It resets the UART but keeps it accessible for software, avoiding an exception when UART registers are accessed after a DeInit. Signed-off-by: robert-hh --- ports/mimxrt/machine_uart.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c index 17d789886c..02e00c899a 100644 --- a/ports/mimxrt/machine_uart.c +++ b/ports/mimxrt/machine_uart.c @@ -146,6 +146,12 @@ void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t st } } +static void machine_uart_ensure_active(machine_uart_obj_t *uart) { + if (uart->lpuart->CTRL == 0) { + mp_raise_OSError(EIO); + } +} + STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, flow=%s, " @@ -351,13 +357,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init); // uart.deinit() STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - LPUART_Deinit(self->lpuart); + LPUART_SoftwareReset(self->lpuart); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit); STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + machine_uart_ensure_active(self); size_t count = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle); return MP_OBJ_NEW_SMALL_INT(count); } @@ -365,6 +372,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any); STATIC mp_obj_t machine_uart_sendbreak(mp_obj_t self_in) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + machine_uart_ensure_active(self); self->lpuart->CTRL |= 1 << LPUART_CTRL_SBK_SHIFT; // Set SBK bit self->lpuart->CTRL &= ~LPUART_CTRL_SBK_MASK; // Clear SBK bit return mp_const_none; @@ -382,11 +390,11 @@ STATIC mp_obj_t machine_uart_txdone(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone); -// Deinitialize all defined UARTs +// Reset all defined UARTs void machine_uart_deinit_all(void) { - for (int i = 0; i < sizeof(uart_index_table); i++) { + for (int i = 0; i < MICROPY_HW_UART_NUM; i++) { if (uart_index_table[i] != 0) { - LPUART_Deinit(uart_base_ptr_table[uart_index_table[i]]); + LPUART_SoftwareReset(uart_base_ptr_table[uart_index_table[i]]); } } } @@ -424,6 +432,8 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz size_t avail; size_t nget; + machine_uart_ensure_active(self); + for (size_t received = 0; received < size;) { // Wait for the first/next character. while ((avail = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle)) <= 0) { @@ -456,6 +466,8 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin size_t offset = 0; uint8_t fifo_size = FSL_FEATURE_LPUART_FIFO_SIZEn(0); + machine_uart_ensure_active(self); + // First check if a previous transfer is still ongoing, // then wait at least the number of remaining character times. t = ticks_us64() + (uint64_t)(self->handle.txDataSize + fifo_size) * (13000000 / self->config.baudRate_Bps + 1000); @@ -510,6 +522,7 @@ STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint machine_uart_obj_t *self = self_in; mp_uint_t ret; if (request == MP_STREAM_POLL) { + machine_uart_ensure_active(self); uintptr_t flags = arg; ret = 0; if (flags & MP_STREAM_POLL_RD) { From c86b9ec8bd11dbd665e2af29f2e8b6b6f1ce449a Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 30 Aug 2023 16:21:41 +0200 Subject: [PATCH 079/121] mimxrt/boards: Fix use of MICROPY_HW_SDRAM_AVAIL in MIMXRT1176.ld. MICROPY_HW_SDRAM_AVAIL is always defined. Thanks to Ibrahim Abdakader for noticing. Signed-off-by: robert-hh --- ports/mimxrt/boards/MIMXRT1176.ld | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/mimxrt/boards/MIMXRT1176.ld b/ports/mimxrt/boards/MIMXRT1176.ld index 2408977b94..d66c86a046 100644 --- a/ports/mimxrt/boards/MIMXRT1176.ld +++ b/ports/mimxrt/boards/MIMXRT1176.ld @@ -39,7 +39,7 @@ dtcm_size = 0x00020000; ocrm_start = 0x20240000; ocrm_size = 0x00100000; -#ifdef MICROPY_HW_SDRAM_AVAIL +#if MICROPY_HW_SDRAM_AVAIL sdram_start = 0x80000000; sdram_size = MICROPY_HW_SDRAM_SIZE; #endif @@ -49,7 +49,7 @@ __stack_size__ = 0x8000; _estack = __StackTop; _sstack = __StackLimit; -#ifdef MICROPY_HW_SDRAM_AVAIL +#if MICROPY_HW_SDRAM_AVAIL _gc_heap_start = ORIGIN(m_sdram); _gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); #else From 81c19d93bc687e2bd953af16c9d779a97e822e5f Mon Sep 17 00:00:00 2001 From: robert-hh Date: Thu, 31 Aug 2023 08:02:32 +0200 Subject: [PATCH 080/121] mimxrt/machine_uart: Support slow baud rates for UART. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Down to 50 baud (in reverence to Jean-Maurice-Émile Baudot). Implemented for the MIMXRT10xx MCU's only. The MIMXRT1176 runs down to 300 baud. Signed-off-by: robert-hh --- ports/mimxrt/machine_uart.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c index 02e00c899a..ab5d13e083 100644 --- a/ports/mimxrt/machine_uart.c +++ b/ports/mimxrt/machine_uart.c @@ -288,7 +288,18 @@ STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args self->timeout_char = min_timeout_char; } - LPUART_Init(self->lpuart, &self->config, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT); + #if defined(MIMXRT117x_SERIES) + // Use the Lpuart1 clock value, which is set for All UART devices. + LPUART_Init(self->lpuart, &self->config, CLOCK_GetRootClockFreq(kCLOCK_Root_Lpuart1)); + #else + // For baud rates < 1000000 divide the clock by 10, supporting baud rates down to 50 baud. + if (self->config.baudRate_Bps > 1000000) { + CLOCK_SetDiv(kCLOCK_UartDiv, 0); + } else { + CLOCK_SetDiv(kCLOCK_UartDiv, 9); + } + LPUART_Init(self->lpuart, &self->config, CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot)); + #endif LPUART_TransferCreateHandle(self->lpuart, &self->handle, LPUART_UserCallback, self); uint8_t *buffer = m_new(uint8_t, rxbuf_len + 1); LPUART_TransferStartRingBuffer(self->lpuart, &self->handle, buffer, rxbuf_len); From 32db4c58f7aebc18e425f67e9f2585a79d34febf Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 31 Aug 2023 14:29:49 +1000 Subject: [PATCH 081/121] extmod/moddeflate: Change default window size. The primary purpose of this commit is to make decompress default to wbits=15 when the format is gzip (or auto format with gzip detected). The idea is that someone decompressing a gzip stream should be able to use the default `deflate.DeflateIO(f)` and it will "just work" for any input stream, even though it uses a lot of memory. This is done by making uzlib report gzip files as having wbits set to 15 in their header (where it previously only set the wbits out parameter for zlib files), and then fixing up the logic in `deflateio_init_read`. Updates the documentation to match. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- docs/library/deflate.rst | 79 +++++++++++++++++++++------------------- extmod/moddeflate.c | 33 +++++++++++------ lib/uzlib/header.c | 4 ++ 3 files changed, 68 insertions(+), 48 deletions(-) diff --git a/docs/library/deflate.rst b/docs/library/deflate.rst index 9752af5925..fad5778705 100644 --- a/docs/library/deflate.rst +++ b/docs/library/deflate.rst @@ -41,9 +41,15 @@ Classes to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to window sizes of 32 to 32k bytes). - If *wbits* is set to ``0`` (the default), then a window size of 256 bytes - will be used (corresponding to *wbits* set to ``8``), except when - :ref:`decompressing a zlib stream `. + If *wbits* is set to ``0`` (the default), then for compression a window size + of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it + depends on the format: + + * ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8). + * ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib + header. + * ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes + (corresponding to *wbits* set to 15). See the :ref:`window size ` notes below for more information about the window size, zlib, and gzip streams. @@ -134,44 +140,43 @@ Deflate window size ------------------- The window size limits how far back in the stream the (de)compressor can -reference. Increasing the window size will improve compression, but will -require more memory. +reference. Increasing the window size will improve compression, but will require +more memory and make the compressor slower. -However, just because a given window size is used for compression, this does not -mean that the stream will require the same size window for decompression, as -the stream may not reference data as far back as the window allows (for example, -if the length of the input is smaller than the window size). +If an input stream was compressed a given window size, then `DeflateIO` +using a smaller window size will fail mid-way during decompression with +:exc:`OSError`, but only if a back-reference actually refers back further +than the decompressor's window size. This means it may be possible to decompress +with a smaller window size. For example, this would trivially be the case if the +original uncompressed data is shorter than the window size. -If the decompressor uses a smaller window size than necessary for the input data -stream, it will fail mid-way through decompression with :exc:`OSError`. +Decompression +~~~~~~~~~~~~~ -.. _deflate_wbits_zlib: +The zlib format includes a header which specifies the window size that was used +to compress the data. This indicates the maximum window size required to +decompress this stream. If this header value is less than the specified *wbits* +value (or if *wbits* is unset), then the header value will be used. -The zlib format includes a header which specifies the window size used to -compress the data (which due to the above, may be larger than the size required -for the decompressor). +The gzip format does not include the window size in the header, and assumes that +all gzip compressors (e.g. the ``gzip`` utility, or CPython's implementation of +:class:`gzip.GzipFile`) use the maximum window size of 32kiB. For this reason, +if the *wbits* parameter is not set, the decompressor will use a 32 kiB window +size (corresponding to *wbits* set to 15). This means that to be able to +decompress an arbitrary gzip stream, you must have at least this much RAM +available. If you control the source data, consider instead using the zlib +format with a smaller window size. -If this header value is lower than the specified *wbits* value, then the header -value will be used instead in order to reduce the memory allocation size. If -the *wbits* parameter is zero (the default), then the header value will only be -used if it is less than the maximum value of ``15`` (which is default value -used by most compressors [#f1]_). +The raw format has no header and therefore does not include any information +about the window size. If *wbits* is not set, then it will default to a window +size of 256 bytes, which may not be large enough for a given stream. Therefore +it is recommended that you should always explicitly set *wbits* if using the raw +format. -In other words, if the source zlib stream has been compressed with a custom window -size (i.e. less than ``15``), then using the default *wbits* parameter of zero -will decompress any such stream. +Compression +~~~~~~~~~~~ -The gzip file format does not include the window size in the header. -Additionally, most compressor libraries (including CPython's implementation -of :class:`gzip.GzipFile`) will default to the maximum possible window size. -This makes it difficult to decompress most gzip streams on MicroPython unless -your board has a lot of free RAM. - -If you control the source of the compressed data, then prefer to use the zlib -format, with a window size that is suitable for your target device. - -.. rubric:: Footnotes - -.. [#f1] The assumption here is that if the header value is the default used by - most compressors, then nothing is known about the likely required window - size and we should ignore it. +For compression, MicroPython will default to a window size of 256 bytes for all +formats. This provides a reasonable amount of compression with minimal memory +usage and fast compression time, and will generate output that will work with +any decompressor. diff --git a/extmod/moddeflate.c b/extmod/moddeflate.c index 1d8a8acf73..560ee3f0ab 100644 --- a/extmod/moddeflate.c +++ b/extmod/moddeflate.c @@ -54,6 +54,8 @@ typedef enum { DEFLATEIO_FORMAT_MAX = DEFLATEIO_FORMAT_GZIP, } deflateio_format_t; +// This is used when the wbits is unset in the DeflateIO constructor. Default +// to the smallest window size (faster compression, less RAM usage, etc). const int DEFLATEIO_DEFAULT_WBITS = 8; typedef struct { @@ -114,24 +116,32 @@ STATIC bool deflateio_init_read(mp_obj_deflateio_t *self) { // Don't modify self->window_bits as it may also be used for write. int wbits = self->window_bits; - // Parse the header if we're in NONE/ZLIB/GZIP modes. - if (self->format != DEFLATEIO_FORMAT_RAW) { - int header_wbits = wbits; + if (self->format == DEFLATEIO_FORMAT_RAW) { + if (wbits == 0) { + // The docs recommends always setting wbits explicitly when using + // RAW, but we still allow a default. + wbits = DEFLATEIO_DEFAULT_WBITS; + } + } else { + // Parse the header if we're in NONE/ZLIB/GZIP modes. + int header_wbits; int header_type = uzlib_parse_zlib_gzip_header(&self->read->decomp, &header_wbits); - if ((self->format == DEFLATEIO_FORMAT_ZLIB && header_type != UZLIB_HEADER_ZLIB) || (self->format == DEFLATEIO_FORMAT_GZIP && header_type != UZLIB_HEADER_GZIP)) { + if (header_type < 0) { + // Stream header was invalid. return false; } - if (wbits == 0 && header_wbits < 15) { - // If the header specified something lower than the default, then - // use that instead. + if ((self->format == DEFLATEIO_FORMAT_ZLIB && header_type != UZLIB_HEADER_ZLIB) || (self->format == DEFLATEIO_FORMAT_GZIP && header_type != UZLIB_HEADER_GZIP)) { + // Not what we expected. + return false; + } + // header_wbits will either be 15 (gzip) or 8-15 (zlib). + if (wbits == 0 || header_wbits < wbits) { + // If the header specified something lower, then use that instead. + // No point doing a bigger allocation than we need to. wbits = header_wbits; } } - if (wbits == 0) { - wbits = DEFLATEIO_DEFAULT_WBITS; - } - size_t window_len = 1 << wbits; self->read->window = m_new(uint8_t, window_len); @@ -163,6 +173,7 @@ STATIC bool deflateio_init_write(mp_obj_deflateio_t *self) { int wbits = self->window_bits; if (wbits == 0) { + // Same default wbits for all formats. wbits = DEFLATEIO_DEFAULT_WBITS; } size_t window_len = 1 << wbits; diff --git a/lib/uzlib/header.c b/lib/uzlib/header.c index edd2b08ab5..9c48d91391 100644 --- a/lib/uzlib/header.c +++ b/lib/uzlib/header.c @@ -108,6 +108,10 @@ int uzlib_parse_zlib_gzip_header(uzlib_uncomp_t *d, int *wbits) d->checksum_type = UZLIB_CHKSUM_CRC; d->checksum = ~0; + /* gzip does not include the window size in the header, as it is expected that a + compressor will use wbits=15 (32kiB).*/ + *wbits = 15; + return UZLIB_HEADER_GZIP; } else { /* check checksum */ From a175f98a65173e254d4185e51f49b11cab20ffac Mon Sep 17 00:00:00 2001 From: Oliver Joos Date: Fri, 25 Aug 2023 00:09:27 +0200 Subject: [PATCH 082/121] stm32/mboot: Fix fwupdate by replacing zlib with new deflate module. Since commit 3533924c36ae85ce6e8bf8598dd71cf16bbdb10b the zlib module has been replaced by the new deflate module. This commit updates the script fwupdate.py to use the new deflate module. Signed-off-by: Oliver Joos --- ports/stm32/mboot/fwupdate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/stm32/mboot/fwupdate.py b/ports/stm32/mboot/fwupdate.py index 78a8d73658..47ceb19ba5 100644 --- a/ports/stm32/mboot/fwupdate.py +++ b/ports/stm32/mboot/fwupdate.py @@ -3,7 +3,7 @@ from micropython import const import struct, time -import zlib, machine, stm +import deflate, machine, stm # Constants to be used with update_mpy VFS_FAT = 1 @@ -36,7 +36,7 @@ def dfu_read(filename): if hdr == b"Dfu": pass elif hdr == b"\x1f\x8b\x08": - f = zlib.DecompIO(f, 16 + 15) + f = deflate.DeflateIO(f, deflate.GZIP) else: print("Invalid firmware", filename) return None @@ -231,7 +231,7 @@ def update_app_elements( # Check firmware is of .dfu or .dfu.gz type try: with open(filename, "rb") as f: - hdr = zlib.DecompIO(f, 16 + 15).read(6) + hdr = deflate.DeflateIO(f, deflate.GZIP).read(6) except Exception: with open(filename, "rb") as f: hdr = f.read(6) From 141750ff7924cbf4b023e8b0c5715c5d7ae970b7 Mon Sep 17 00:00:00 2001 From: Yuuki NAGAO Date: Sat, 1 Jul 2023 15:07:18 +0900 Subject: [PATCH 083/121] stm32/uart: Fix UART timeout issue with low baudrate on G4 MCUs. With using UART FIFO, the timeout should be long enough that FIFO becomes empty. Since previous data transfer may be ongoing, the timeout must be timeout_char multiplied by FIFO size + 1. Signed-off-by: Yuuki NAGAO --- ports/stm32/uart.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index e477c5c16c..7a2a3a9580 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -1052,12 +1052,20 @@ size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_chars, // the overall timeout rather than the character timeout. timeout = self->timeout; } else { + #if defined(STM32G4) + // With using UART FIFO, the timeout should be long enough that FIFO becomes empty. + // Since previous data transfer may be ongoing, the timeout must be multiplied + // timeout_char by FIFO size + 1. + // STM32G4 has 8 words FIFO. + timeout = (8 + 1) * self->timeout_char; + #else // The timeout specified here is for waiting for the TX data register to // become empty (ie between chars), as well as for the final char to be // completely transferred. The default value for timeout_char is long // enough for 1 char, but we need to double it to wait for the last char // to be transferred to the data register, and then to be transmitted. timeout = 2 * self->timeout_char; + #endif } const uint8_t *src = (const uint8_t *)src_in; From 845d0c79ff798b4524c463be78c769b96528d01c Mon Sep 17 00:00:00 2001 From: Andy Piper Date: Sun, 18 Jun 2023 22:10:13 +0100 Subject: [PATCH 084/121] docs/library/neopixel: Change link to a micropython-lib reference. Signed-off-by: Andy Piper --- docs/library/neopixel.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/library/neopixel.rst b/docs/library/neopixel.rst index 543f258812..edcbc9345c 100644 --- a/docs/library/neopixel.rst +++ b/docs/library/neopixel.rst @@ -9,9 +9,7 @@ This module provides a driver for WS2818 / NeoPixel LEDs. .. note:: This module is only included by default on the ESP8266, ESP32 and RP2 ports. On STM32 / Pyboard and others, you can either install the ``neopixel`` package using :term:`mip`, or you can download the module - directly from - `_ - and copy it to the filesystem. + directly from :term:`micropython-lib` and copy it to the filesystem. class NeoPixel -------------- From b94ab6a2ef56fce3f8db2f84b26e3ac0f4b3b155 Mon Sep 17 00:00:00 2001 From: Alexander Wilde Date: Tue, 20 Jun 2023 11:07:45 +0100 Subject: [PATCH 085/121] examples/bluetooth: Raise ValueError when advertising data is too large. Signed-off-by: Alexander Wilde --- examples/bluetooth/ble_advertising.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/bluetooth/ble_advertising.py b/examples/bluetooth/ble_advertising.py index eed527f55d..6dc78c5e3d 100644 --- a/examples/bluetooth/ble_advertising.py +++ b/examples/bluetooth/ble_advertising.py @@ -19,6 +19,8 @@ _ADV_TYPE_UUID32_MORE = const(0x4) _ADV_TYPE_UUID128_MORE = const(0x6) _ADV_TYPE_APPEARANCE = const(0x19) +_ADV_MAX_PAYLOAD = const(31) + # Generate a payload to be passed to gap_advertise(adv_data=...). def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0): @@ -50,6 +52,9 @@ def advertising_payload(limited_disc=False, br_edr=False, name=None, services=No if appearance: _append(_ADV_TYPE_APPEARANCE, struct.pack(" _ADV_MAX_PAYLOAD: + raise ValueError("advertising payload too large") + return payload From f4a6fc2c8e7250db3be540e91321299205383ec4 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 24 Aug 2023 23:28:53 +1000 Subject: [PATCH 086/121] examples/bluetooth: Link to aioble in BLE examples. Signed-off-by: Jim Mussared --- examples/bluetooth/ble_advertising.py | 4 ++++ examples/bluetooth/ble_bonding_peripheral.py | 5 +++++ examples/bluetooth/ble_simple_central.py | 5 +++++ examples/bluetooth/ble_simple_peripheral.py | 5 +++++ examples/bluetooth/ble_temperature.py | 6 ++++++ examples/bluetooth/ble_temperature_central.py | 6 ++++++ examples/bluetooth/ble_uart_peripheral.py | 5 +++++ 7 files changed, 36 insertions(+) diff --git a/examples/bluetooth/ble_advertising.py b/examples/bluetooth/ble_advertising.py index 6dc78c5e3d..2fe17d640b 100644 --- a/examples/bluetooth/ble_advertising.py +++ b/examples/bluetooth/ble_advertising.py @@ -1,5 +1,9 @@ # Helpers for generating BLE advertising payloads. +# A more fully-featured (and easier to use) version of this is implemented in +# aioble. This code is provided just as a basic example. See +# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble + from micropython import const import struct import bluetooth diff --git a/examples/bluetooth/ble_bonding_peripheral.py b/examples/bluetooth/ble_bonding_peripheral.py index bd7596dbcb..c3ae5f262a 100644 --- a/examples/bluetooth/ble_bonding_peripheral.py +++ b/examples/bluetooth/ble_bonding_peripheral.py @@ -4,6 +4,11 @@ # any connected central every 10 seconds. # # Work-in-progress demo of implementing bonding and passkey auth. +# +# This example demonstrates the low-level bluetooth module. For most +# applications, we recommend using the higher-level aioble library, which +# includes an implementation of the secret store. See +# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble import bluetooth import random diff --git a/examples/bluetooth/ble_simple_central.py b/examples/bluetooth/ble_simple_central.py index 3c0cf2a0d4..caf6333472 100644 --- a/examples/bluetooth/ble_simple_central.py +++ b/examples/bluetooth/ble_simple_central.py @@ -1,6 +1,11 @@ # This example finds and connects to a peripheral running the # UART service (e.g. ble_simple_peripheral.py). +# This example demonstrates the low-level bluetooth module. For most +# applications, we recommend using the higher-level aioble library which takes +# care of all IRQ handling and connection management. See +# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble + import bluetooth import random import struct diff --git a/examples/bluetooth/ble_simple_peripheral.py b/examples/bluetooth/ble_simple_peripheral.py index 0ebe431764..bdb5ed88c7 100644 --- a/examples/bluetooth/ble_simple_peripheral.py +++ b/examples/bluetooth/ble_simple_peripheral.py @@ -1,5 +1,10 @@ # This example demonstrates a UART periperhal. +# This example demonstrates the low-level bluetooth module. For most +# applications, we recommend using the higher-level aioble library which takes +# care of all IRQ handling and connection management. See +# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble + import bluetooth import random import struct diff --git a/examples/bluetooth/ble_temperature.py b/examples/bluetooth/ble_temperature.py index e6378ebee7..acd77127ad 100644 --- a/examples/bluetooth/ble_temperature.py +++ b/examples/bluetooth/ble_temperature.py @@ -3,6 +3,12 @@ # The sensor's local value updates every second, and it will notify # any connected central every 10 seconds. +# This example demonstrates the low-level bluetooth module. For most +# applications, we recommend using the higher-level aioble library which takes +# care of all IRQ handling and connection management. See +# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble +# and in particular the temp_sensor.py example included with aioble. + import bluetooth import random import struct diff --git a/examples/bluetooth/ble_temperature_central.py b/examples/bluetooth/ble_temperature_central.py index afa914672c..fe1c70636f 100644 --- a/examples/bluetooth/ble_temperature_central.py +++ b/examples/bluetooth/ble_temperature_central.py @@ -1,5 +1,11 @@ # This example finds and connects to a BLE temperature sensor (e.g. the one in ble_temperature.py). +# This example demonstrates the low-level bluetooth module. For most +# applications, we recommend using the higher-level aioble library which takes +# care of all IRQ handling and connection management. See +# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble +# and in particular the temp_client.py example included with aioble. + import bluetooth import random import struct diff --git a/examples/bluetooth/ble_uart_peripheral.py b/examples/bluetooth/ble_uart_peripheral.py index b4e352be9f..0de4fe2ed4 100644 --- a/examples/bluetooth/ble_uart_peripheral.py +++ b/examples/bluetooth/ble_uart_peripheral.py @@ -1,5 +1,10 @@ # This example demonstrates a peripheral implementing the Nordic UART Service (NUS). +# This example demonstrates the low-level bluetooth module. For most +# applications, we recommend using the higher-level aioble library which takes +# care of all IRQ handling and connection management. See +# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble + import bluetooth from ble_advertising import advertising_payload From 83f2f36b9e5fea90a947aada5e1c8065468c0e70 Mon Sep 17 00:00:00 2001 From: stijn Date: Wed, 23 Aug 2023 15:57:23 +0200 Subject: [PATCH 087/121] tests/unix/mod_os: Make os.system() test work on windows. The "true" command by default is unavailable on windows so use an equivalent which works on both unix and windows. Signed-off-by: stijn --- tests/unix/mod_os.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unix/mod_os.py b/tests/unix/mod_os.py index 17554d9375..f69fa45b2b 100644 --- a/tests/unix/mod_os.py +++ b/tests/unix/mod_os.py @@ -12,7 +12,7 @@ os.unsetenv("TEST_VARIABLE") print(os.getenv("TEST_VARIABLE")) print(os.getenv("TEST_VARIABLE", "TEST_DEFAULT_VALUE")) -print(os.system("true")) +print(os.system("exit 0")) rand = os.urandom(4) print(type(rand) is bytes, len(rand)) From e0a148060025a75f4051e5009d9dc3728cb2bc75 Mon Sep 17 00:00:00 2001 From: mcskatkat Date: Tue, 11 Jul 2023 00:50:33 +0300 Subject: [PATCH 088/121] py/objstr: Fix `str % {}` edge case. Eliminate `TypeError` when format string contains no named conversions. This matches CPython behavior. Signed-off-by: mcskatkat --- py/objstr.c | 4 +++- tests/basics/string_format_modulo.py | 11 ++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index b966a70169..5dfe94ac4f 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -1645,7 +1645,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ } } - if (arg_i != n_args) { + if (dict == MP_OBJ_NULL && arg_i != n_args) { + // NOTE: if `dict` exists, then `n_args` is 1 and the dict is always consumed; either + // positionally, or as a map of named args, even if none were actually referenced. mp_raise_TypeError(MP_ERROR_TEXT("format string didn't convert all arguments")); } diff --git a/tests/basics/string_format_modulo.py b/tests/basics/string_format_modulo.py index 14b4a6a484..7bddd96750 100644 --- a/tests/basics/string_format_modulo.py +++ b/tests/basics/string_format_modulo.py @@ -51,8 +51,9 @@ print('%c' % True) # Should be able to print dicts; in this case they aren't used # to lookup keywords in formats like %(foo)s -print('%s' % {}) -print('%s' % ({},)) +print('%s' % {}) # dict treated as the single (positional) arg to % +print('%s' % ({},)) # dict is the first (and only) arg in the positional arg tuple +print('foo' % {}) # no error, dict treated as an empty map of named args # Cases when "*" used and there's not enough values total try: @@ -65,7 +66,11 @@ except TypeError: print("TypeError") print("%(foo)s" % {"foo": "bar", "baz": False}) -print("%s %(foo)s %(foo)s" % {"foo": 1}) +print("%s %(foo)s %(foo)s" % {"foo": 1}) # dict consumed positionally, then used as map - ok +try: + print("%(foo)s %s %(foo)s" % {"foo": 1}) # used as map, then positionally - not enough args +except TypeError: + print("TypeError") try: print("%(foo)s" % {}) except KeyError: From d1f288c041c85793de17da9f8b38ff20af2a6f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20de=20Giessen?= Date: Wed, 23 Nov 2022 14:26:26 +0100 Subject: [PATCH 089/121] py/modstruct: Support pad bytes in struct format. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for the x format code in struct.pack and struct.unpack. The primary use case for this is ignoring bytes while unpacking. When interfacing with existing systems, it may often happen that you either have fields in a struct that aren't properly specified or you simply don't care about them. Being able to easily skip them is useful. Signed-off-by: Daniël van de Giessen --- py/modstruct.c | 13 ++++++++++--- tests/basics/struct1.py | 9 +++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/py/modstruct.c b/py/modstruct.c index 42f91b282c..b3edc96328 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -92,7 +92,9 @@ STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) { cnt = get_fmt_num(&fmt); } - if (*fmt == 's') { + if (*fmt == 'x') { + size += cnt; + } else if (*fmt == 's') { total_cnt += 1; size += cnt; } else { @@ -159,7 +161,9 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { cnt = get_fmt_num(&fmt); } mp_obj_t item; - if (*fmt == 's') { + if (*fmt == 'x') { + p += cnt; + } else if (*fmt == 's') { item = mp_obj_new_bytes(p, cnt); p += cnt; res->items[i++] = item; @@ -192,7 +196,10 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c cnt = get_fmt_num(&fmt); } - if (*fmt == 's') { + if (*fmt == 'x') { + memset(p, 0, cnt); + p += cnt; + } else if (*fmt == 's') { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[i++], &bufinfo, MP_BUFFER_READ); mp_uint_t to_copy = cnt; diff --git a/tests/basics/struct1.py b/tests/basics/struct1.py index a18655517b..e473ffcc11 100644 --- a/tests/basics/struct1.py +++ b/tests/basics/struct1.py @@ -20,6 +20,8 @@ print(struct.pack("h", 1)) print(struct.pack("b", 1)) +print(struct.pack("x")) print(struct.pack("bI", -128, 256)) @@ -29,6 +31,13 @@ print(struct.calcsize("97sI")) print(struct.unpack("<6sH", b"foo\0\0\0\x12\x34")) print(struct.pack("<6sH", b"foo", 10000)) +print(struct.calcsize("7xx")) +print(struct.pack("7xx")) + +print(struct.calcsize(">bxI3xH")) +print(struct.pack(">bxI3xH", 1, 2, 3)) +print(struct.unpack(">bxI3xH", b"\x01\0\0\0\0\x02\0\0\0\0\x03")) + s = struct.pack("BHBI", 10, 100, 200, 300) v = struct.unpack("BHBI", s) print(v == (10, 100, 200, 300)) From 4837ec336a8047a1707534315f6b4b8aeac3f891 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sun, 30 Jul 2023 15:40:39 +0200 Subject: [PATCH 090/121] tools/mpy_ld.py: Support more complex rodata sections. Sections sometimes named .rodata.str1.1 etc, instead of just .rodata. Avoid crashing in that case. Instead treat it like any other RO section. Fix thanks to @phlash. Fixes issue #8783. Signed-off-by: Jon Nordby --- tools/mpy_ld.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 60fa41ce1f..dd7b352b69 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -972,7 +972,7 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): for base, addr, kind in env.mpy_relocs: if isinstance(kind, str) and kind.startswith(".text"): kind = 0 - elif kind in (".rodata", ".data.rel.ro"): + elif isinstance(kind, str) and kind.startswith((".rodata", ".data.rel.ro")): if env.arch.separate_rodata: kind = rodata_const_table_idx else: From a64f2fdca09eb00fa4a6c0e96cd783f3ee772e57 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 25 Aug 2023 15:43:50 +1000 Subject: [PATCH 091/121] py/dynruntime.h: Implement MP_OBJ_NEW_QSTR. Because mpy_ld.py doesn't know the target object representation, it emits instances of `MP_OBJ_NEW_QSTR(MP_QSTR_Foo)` as const string objects, rather than qstrs. However this doesn't work for map keys (e.g. for a locals dict) because the map has all_keys_are_qstrs flag is set (and also auto-complete requires the map keys to be qstrs). Instead, emit them as regular qstrs, and make a functioning MP_OBJ_NEW_QSTR function available (via `native_to_obj`, also used for e.g. making integers). Remove the code from mpy_ld.py to emit qstrs as constant strings, but leave behind the scaffold to emit constant objects in case we want to do use this in the future. Strictly this should be a .mpy sub-version bump, even though the function table isn't changing, it does lead to a change in behavior for a new .mpy running against old MicroPython. `mp_native_to_obj` will incorrectly return the qstr value directly as an `mp_obj_t`, leading to unexpected results. But given that it's broken at the moment, it seems unlikely that anyone is relying on this, so it's not work the other downsides of a sub-version bump (i.e. breaking pure-Python modules that use @native). The opposite case of running an old .mpy on new MicroPython is unchanged, and remains broken in exactly the same way. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- py/dynruntime.h | 2 +- py/nativeglue.c | 2 + py/runtime0.h | 3 ++ tests/micropython/import_mpy_native_gc.py | 4 ++ tools/mpy_ld.py | 55 ++++++----------------- 5 files changed, 24 insertions(+), 42 deletions(-) diff --git a/py/dynruntime.h b/py/dynruntime.h index 8564715c0b..90c401ab4b 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -79,7 +79,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) { /******************************************************************************/ // Types and objects -#define MP_OBJ_NEW_QSTR(x) MP_OBJ_NEW_QSTR_##x +#define MP_OBJ_NEW_QSTR(x) (mp_fun_table.native_to_obj(x, MP_NATIVE_TYPE_QSTR)) #define mp_type_type (*mp_fun_table.type_type) #define mp_type_NoneType (*mp_obj_get_type(mp_const_none)) diff --git a/py/nativeglue.c b/py/nativeglue.c index 743ff38ccb..d92d815abd 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -104,6 +104,8 @@ mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { return mp_obj_new_int(val); case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val); + case MP_NATIVE_TYPE_QSTR: + return MP_OBJ_NEW_QSTR(val); default: // a pointer // we return just the value of the pointer as an integer return mp_obj_new_int_from_uint(val); diff --git a/py/runtime0.h b/py/runtime0.h index 6ef2d727c1..69af38ddcb 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -50,6 +50,9 @@ #define MP_NATIVE_TYPE_PTR16 (0x06) #define MP_NATIVE_TYPE_PTR32 (0x07) +// Not use for viper, but for dynamic native modules +#define MP_NATIVE_TYPE_QSTR (0x08) + // Bytecode and runtime boundaries for unary ops #define MP_UNARY_OP_NUM_BYTECODE (MP_UNARY_OP_NOT + 1) #define MP_UNARY_OP_NUM_RUNTIME (MP_UNARY_OP_SIZEOF + 1) diff --git a/tests/micropython/import_mpy_native_gc.py b/tests/micropython/import_mpy_native_gc.py index 5a3855dc7d..5f2a2a6f45 100644 --- a/tests/micropython/import_mpy_native_gc.py +++ b/tests/micropython/import_mpy_native_gc.py @@ -47,6 +47,10 @@ class UserFS: # Pre-compiled examples/natmod/features0 example for various architectures, keyed # by the required value of sys.implementation._mpy (without sub-version). +# cd examples/natmod/features0 +# make clean +# make ARCH=x64 # or ARCH=armv6m +# cat features0.mpy | python -c 'import sys; print(sys.stdin.buffer.read())' features0_file_contents = { # -march=x64 0x806: b'M\x06\x09\x1f\x02\x004build/features0.native.mpy\x00\x12factorial\x00\x8a\x02\xe9/\x00\x00\x00SH\x8b\x1d\x83\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dQ\x00\x00\x00H\x8bG\x08L\x8bc(H\x8bx\x08A\xff\xd4H\x8d5+\x00\x00\x00H\x89\xc5H\x8b\x059\x00\x00\x00\x0f\xb7x\x02\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x11$\r&\xa3 \x01"\xff', diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index dd7b352b69..7f0fcbca22 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -232,34 +232,20 @@ def extract_qstrs(source_files): def read_qstrs(f): with open(f) as f: vals = set() - objs = set() for line in f: - while line: - m = re.search(r"MP_OBJ_NEW_QSTR\((MP_QSTR_[A-Za-z0-9_]*)\)", line) - if m: - objs.add(m.group(1)) - else: - m = re.search(r"MP_QSTR_[A-Za-z0-9_]*", line) - if m: - vals.add(m.group()) - if m: - s = m.span() - line = line[: s[0]] + line[s[1] :] - else: - line = "" - return vals, objs + for m in re.finditer(r"MP_QSTR_[A-Za-z0-9_]*", line): + vals.add(m.group()) + return vals static_qstrs = ["MP_QSTR_" + qstrutil.qstr_escape(q) for q in qstrutil.static_qstr_list] qstr_vals = set() - qstr_objs = set() for f in source_files: - vals, objs = read_qstrs(f) + vals = read_qstrs(f) qstr_vals.update(vals) - qstr_objs.update(objs) qstr_vals.difference_update(static_qstrs) - return static_qstrs, qstr_vals, qstr_objs + return static_qstrs, qstr_vals ################################################################################ @@ -730,7 +716,7 @@ def load_object_file(env, felf): env.unresolved_syms.append(sym) -def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): +def link_objects(env, native_qstr_vals_len): # Build GOT information if env.arch.name == "EM_XTENSA": build_got_xtensa(env) @@ -761,7 +747,7 @@ def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): # Create section to contain mp_native_obj_table env.obj_table_section = Section( ".external.obj_table", - bytearray(native_qstr_objs_len * env.arch.word_size), + bytearray(0 * env.arch.word_size), # currently empty env.arch.word_size, ) @@ -899,7 +885,7 @@ class MPYOutput: self.write_uint(n) -def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): +def build_mpy(env, entry_offset, fmpy, native_qstr_vals): # Write jump instruction to start of text jump = env.arch.asm_jump(entry_offset) env.full_text[: len(jump)] = jump @@ -927,7 +913,7 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): out.write_uint(1 + len(native_qstr_vals)) # MPY: n_obj - out.write_uint(len(native_qstr_objs)) + out.write_uint(0) # MPY: qstr table out.write_qstr(fmpy) # filename @@ -935,10 +921,7 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): out.write_qstr(q) # MPY: object table - for q in native_qstr_objs: - out.write_bytes(bytearray([MP_PERSISTENT_OBJ_STR])) - out.write_uint(len(q)) - out.write_bytes(bytes(q, "utf8") + b"\x00") + # # MPY: kind/len out.write_uint(len(env.full_text) << 3 | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE)) @@ -965,6 +948,7 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): out.write_bytes(env.full_rodata) # MPY: relocation information + # See py/persistentcode.c:mp_native_relocate for meaning of the `kind` integer values. prev_kind = None prev_base = None prev_offset = None @@ -1016,7 +1000,7 @@ def do_preprocess(args): if args.output is None: assert args.files[0].endswith(".c") args.output = args.files[0][:-1] + "config.h" - static_qstrs, qstr_vals, qstr_objs = extract_qstrs(args.files) + static_qstrs, qstr_vals = extract_qstrs(args.files) with open(args.output, "w") as f: print( "#include \n" @@ -1029,11 +1013,6 @@ def do_preprocess(args): print("#define %s (%u)" % (q, i + 1), file=f) for i, q in enumerate(sorted(qstr_vals)): print("#define %s (mp_native_qstr_table[%d])" % (q, i + 1), file=f) - for i, q in enumerate(sorted(qstr_objs)): - print( - "#define MP_OBJ_NEW_QSTR_%s ((mp_obj_t)mp_native_obj_table[%d])" % (q, i), - file=f, - ) print("extern const uint16_t mp_native_qstr_table[];", file=f) print("extern const mp_uint_t mp_native_obj_table[];", file=f) @@ -1043,25 +1022,19 @@ def do_link(args): assert args.files[0].endswith(".o") args.output = args.files[0][:-1] + "mpy" native_qstr_vals = [] - native_qstr_objs = [] if args.qstrs is not None: with open(args.qstrs) as f: for l in f: m = re.match(r"#define MP_QSTR_([A-Za-z0-9_]*) \(mp_native_", l) if m: native_qstr_vals.append(m.group(1)) - else: - m = re.match(r"#define MP_OBJ_NEW_QSTR_MP_QSTR_([A-Za-z0-9_]*)", l) - if m: - native_qstr_objs.append(m.group(1)) log(LOG_LEVEL_2, "qstr vals: " + ", ".join(native_qstr_vals)) - log(LOG_LEVEL_2, "qstr objs: " + ", ".join(native_qstr_objs)) env = LinkEnv(args.arch) try: for file in args.files: load_object_file(env, file) - link_objects(env, len(native_qstr_vals), len(native_qstr_objs)) - build_mpy(env, env.find_addr("mpy_init"), args.output, native_qstr_vals, native_qstr_objs) + link_objects(env, len(native_qstr_vals)) + build_mpy(env, env.find_addr("mpy_init"), args.output, native_qstr_vals) except LinkError as er: print("LinkError:", er.args[0]) sys.exit(1) From 633599cdd500d3a2c99193f2c4340ac823d1a8a8 Mon Sep 17 00:00:00 2001 From: stephanelsmith Date: Wed, 26 Jul 2023 02:52:56 +0000 Subject: [PATCH 092/121] tests/run-tests.py: Capture output of stderr when running on CPython. Signed-off-by: stephanelsmith --- tests/run-tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-tests.py b/tests/run-tests.py index 019b30189f..de886b8ae7 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -709,7 +709,9 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # run CPython to work out expected output try: output_expected = subprocess.check_output( - CPYTHON3_CMD + [os.path.abspath(test_file)], cwd=os.path.dirname(test_file) + CPYTHON3_CMD + [os.path.abspath(test_file)], + cwd=os.path.dirname(test_file), + stderr=subprocess.STDOUT, ) if args.write_exp: with open(test_file_expected, "wb") as f: From 1c047742a273382241e8cfddb12a1d8b4f7f59ab Mon Sep 17 00:00:00 2001 From: stephanelsmith Date: Wed, 26 Jul 2023 02:52:56 +0000 Subject: [PATCH 093/121] extmod/vfs_posix_file: Fix flush handling on macOS. On macOS, if running micropython from subprocess.check_output, then a stdout.flush() raises error 45. Here's a test case. This will run fine on linux, but crashes on macOS with error 45. import sys import subprocess import tempfile with tempfile.NamedTemporaryFile('w') as fp: fp.write(''' import sys sys.stdout.write('hello world') sys.stdout.flush() print('') ''') fp.flush() print('py3') o = subprocess.check_output(f'python3 {fp.name}'.split()) print(o) print('upy') o = subprocess.check_output(f'micropython {fp.name}'.split()) print(o) On macOS: py3 b'hello world\n' upy Traceback (most recent call last): File "...", line 4, in OSError: 45 On unix: py3 b'hello world\n' upy b'hello world\n' Signed-off-by: stephanelsmith --- extmod/vfs_posix_file.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index d70bc4738e..cce7a79af7 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -153,12 +153,17 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ switch (request) { case MP_STREAM_FLUSH: { int ret; + // fsync(stdin/stdout/stderr) may fail with EINVAL (or ENOTSUP on macos), + // but don't propagate that error out. Because data is not buffered by + // us, and stdin/out/err.flush() should just be a no-op. + #ifdef __APPLE__ + #define VFS_POSIX_STREAM_STDIO_ERR_CATCH (err == EINVAL || err == ENOTSUP) + #else + #define VFS_POSIX_STREAM_STDIO_ERR_CATCH (err == EINVAL) + #endif MP_HAL_RETRY_SYSCALL(ret, fsync(o->fd), { - if (err == EINVAL + if (VFS_POSIX_STREAM_STDIO_ERR_CATCH && (o->fd == STDIN_FILENO || o->fd == STDOUT_FILENO || o->fd == STDERR_FILENO)) { - // fsync(stdin/stdout/stderr) may fail with EINVAL, but don't propagate that - // error out. Because data is not buffered by us, and stdin/out/err.flush() - // should just be a no-op. return 0; } *errcode = err; From db06041d59ef8d5524340c4d2c4490c8e770591f Mon Sep 17 00:00:00 2001 From: stephanelsmith Date: Wed, 26 Jul 2023 02:52:56 +0000 Subject: [PATCH 094/121] extmod/vfs_posix_file: Implement sys.std*.buffer objects. Add the buffer attribute to sys.stdin, sys.stdout and sys.stderr. This provides raw access to underlying stdio streams for the unix port (and others that use VfsPosix). Signed-off-by: stephanelsmith --- extmod/vfs_posix_file.c | 46 +++++++++++++++++++++++++++++ tests/io/file_stdio.py | 1 + tests/io/file_stdio2.py | 65 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 tests/io/file_stdio2.py diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index cce7a79af7..488593230c 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -274,12 +274,58 @@ STATIC const mp_stream_p_t vfs_posix_textio_stream_p = { .is_text = true, }; +#if MICROPY_PY_SYS_STDIO_BUFFER + +const mp_obj_vfs_posix_file_t mp_sys_stdin_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDIN_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stdout_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDOUT_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stderr_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDERR_FILENO}; + +// Forward declarations. +const mp_obj_vfs_posix_file_t mp_sys_stdin_obj; +const mp_obj_vfs_posix_file_t mp_sys_stdout_obj; +const mp_obj_vfs_posix_file_t mp_sys_stderr_obj; + +STATIC void vfs_posix_textio_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // These objects are read-only. + return; + } + + if (attr == MP_QSTR_buffer) { + // Implement the `buffer` attribute only on std{in,out,err} instances. + if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stdin_obj) { + dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stdin_buffer_obj); + return; + } + if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stdout_obj) { + dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stdout_buffer_obj); + return; + } + if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stderr_obj) { + dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stderr_buffer_obj); + return; + } + } + + // Any other attribute - forward to locals dict. + dest[1] = MP_OBJ_SENTINEL; +}; + +#define VFS_POSIX_TEXTIO_TYPE_ATTR attr, vfs_posix_textio_attr, + +#else + +#define VFS_POSIX_TEXTIO_TYPE_ATTR + +#endif // MICROPY_PY_SYS_STDIO_BUFFER + MP_DEFINE_CONST_OBJ_TYPE( mp_type_vfs_posix_textio, MP_QSTR_TextIOWrapper, MP_TYPE_FLAG_ITER_IS_STREAM, print, vfs_posix_file_print, protocol, &vfs_posix_textio_stream_p, + VFS_POSIX_TEXTIO_TYPE_ATTR locals_dict, &vfs_posix_rawfile_locals_dict ); diff --git a/tests/io/file_stdio.py b/tests/io/file_stdio.py index cbdb070163..d714bffd4d 100644 --- a/tests/io/file_stdio.py +++ b/tests/io/file_stdio.py @@ -2,3 +2,4 @@ import sys print(sys.stdin.fileno()) print(sys.stdout.fileno()) +print(sys.stderr.fileno()) diff --git a/tests/io/file_stdio2.py b/tests/io/file_stdio2.py new file mode 100644 index 0000000000..5b8a5a7692 --- /dev/null +++ b/tests/io/file_stdio2.py @@ -0,0 +1,65 @@ +# Test sys.std*.buffer objects. + +import sys + +try: + sys.stdout.buffer + sys.stdin.buffer + sys.stderr.buffer +except AttributeError: + print("SKIP") + raise SystemExit + + +# force cpython to flush after every print +# this is to sequence stdout and stderr +def print_flush(*args, **kwargs): + try: + print(*args, **kwargs, flush=True) + except TypeError: + print(*args, **kwargs) + + +print_flush("==stdin==") +print_flush(sys.stdin.buffer.fileno()) + + +print_flush("==stdout==") +print_flush(sys.stdout.buffer.fileno()) +n_text = sys.stdout.write("The quick brown fox jumps over the lazy dog\n") +sys.stdout.flush() +n_binary = sys.stdout.buffer.write("The quick brown fox jumps over the lazy dog\n".encode("utf-8")) +sys.stdout.buffer.flush() +print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) + +# temporarily disabling unicode tests until future PR which fixes unicode write character count +# n_text = sys.stdout.write("🚀") +# sys.stdout.flush() +# n_binary = sys.stdout.buffer.write("🚀".encode("utf-8")) +# sys.stdout.buffer.flush() +# print_flush("") +# print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) +# n_text = sys.stdout.write("1🚀2a3α4b5β6c7γ8d9δ0ぁ1🙐") +# sys.stdout.flush() +# n_binary = sys.stdout.buffer.write("1🚀2a3α4b5β6c7γ8d9δ0ぁ1🙐".encode("utf-8")) +# sys.stdout.buffer.flush() +# print_flush("") +# print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) + + +print_flush("==stderr==") +print_flush(sys.stderr.buffer.fileno()) +n_text = sys.stderr.write("The quick brown fox jumps over the lazy dog\n") +sys.stderr.flush() +n_binary = sys.stderr.buffer.write("The quick brown fox jumps over the lazy dog\n".encode("utf-8")) +sys.stderr.buffer.flush() +print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) + +# temporarily disabling unicode tests until future PR which fixes unicode write character count +# n_text = sys.stderr.write("🚀") +# sys.stderr.flush() +# n_binary = sys.stderr.buffer.write("🚀".encode("utf-8")) +# sys.stderr.buffer.flush() +# print_flush("") +# print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) +# print_flush("") From 25b89cbe946a198734f29b05c3e6730d6b949979 Mon Sep 17 00:00:00 2001 From: Wang Xuancong Date: Mon, 19 Jun 2023 10:09:59 +0800 Subject: [PATCH 095/121] extmod/{modlwip,modsocket}: Add support for SO_BROADCAST socket option. Signed-off-by: Wang Xuancong --- extmod/modlwip.c | 4 +++- extmod/modnetwork.h | 1 + extmod/modsocket.c | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 0d4c03c68a..c881f0df6a 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1377,7 +1377,8 @@ STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) { switch (opt) { // level: SOL_SOCKET - case SOF_REUSEADDR: { + case SOF_REUSEADDR: + case SOF_BROADCAST: { mp_int_t val = mp_obj_get_int(args[3]); // Options are common for UDP and TCP pcb's. if (val) { @@ -1786,6 +1787,7 @@ STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SOF_REUSEADDR) }, + { MP_ROM_QSTR(MP_QSTR_SO_BROADCAST), MP_ROM_INT(SOF_BROADCAST) }, { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) }, diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h index 4786596e9b..e775612fe7 100644 --- a/extmod/modnetwork.h +++ b/extmod/modnetwork.h @@ -43,6 +43,7 @@ // Common option flags per-socket. #define MOD_NETWORK_SO_REUSEADDR (0x0004) +#define MOD_NETWORK_SO_BROADCAST (0x0020) #define MOD_NETWORK_SO_KEEPALIVE (0x0008) #define MOD_NETWORK_SO_SNDTIMEO (0x1005) #define MOD_NETWORK_SO_RCVTIMEO (0x1006) diff --git a/extmod/modsocket.c b/extmod/modsocket.c index 488b6d1712..72a32e3cba 100644 --- a/extmod/modsocket.c +++ b/extmod/modsocket.c @@ -631,6 +631,7 @@ STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(MOD_NETWORK_SOL_SOCKET) }, { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(MOD_NETWORK_SO_REUSEADDR) }, + { MP_ROM_QSTR(MP_QSTR_SO_BROADCAST), MP_ROM_INT(MOD_NETWORK_SO_BROADCAST) }, { MP_ROM_QSTR(MP_QSTR_SO_KEEPALIVE), MP_ROM_INT(MOD_NETWORK_SO_KEEPALIVE) }, { MP_ROM_QSTR(MP_QSTR_SO_SNDTIMEO), MP_ROM_INT(MOD_NETWORK_SO_SNDTIMEO) }, { MP_ROM_QSTR(MP_QSTR_SO_RCVTIMEO), MP_ROM_INT(MOD_NETWORK_SO_RCVTIMEO) }, From 56e5a21312150793a846ce93103f3ea6fec29c68 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Sep 2023 18:33:58 +1000 Subject: [PATCH 096/121] esp32/modsocket: Add support for SO_BROADCAST socket option. Signed-off-by: Damien George --- ports/esp32/modsocket.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index ba1fe096f6..e5a370641f 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -386,7 +386,8 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { switch (opt) { // level: SOL_SOCKET - case SO_REUSEADDR: { + case SO_REUSEADDR: + case SO_BROADCAST: { int val = mp_obj_get_int(args[3]); int ret = lwip_setsockopt(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); if (ret != 0) { @@ -858,6 +859,7 @@ STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(IPPROTO_IP) }, { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) }, { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) }, + { MP_ROM_QSTR(MP_QSTR_SO_BROADCAST), MP_ROM_INT(SO_BROADCAST) }, { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) }, }; From ba8aad3d1dbc25a397c9b23b1428018c5a7be505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20de=20Giessen?= Date: Tue, 4 Jul 2023 15:36:37 +0200 Subject: [PATCH 097/121] esp32/modnetwork: Add support for SO_BINDTODEVICE socket option. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements support for SO_BINDTODEVICE, which allows telling a socket to use a specific interface instead of lwIP automatically selecting one. This allows devices that have multiple connections (for example cellular over PPP in addition to WLAN) to explicitly choose which data is send over which connection, which may have different reliability and or (mobile data) costs associated with using them. The used lwIP network stack already has support for this, so all that was needed was to expose this functionality in MicroPython. This commit exposes a new constant SO_BINDTODEVICE which can be set as an socket option. As a value it expects the name of the interface to bind to. These names can be retrieved using `.config('ifname')` implemented on each interface type (including adding in this commit a `.config()` method to PPP, which it didn't have before), which returns a string with the interface name: >>> import machine >>> import network >>> network.WLAN(network.AP_IF).config('ifname') 'lo0' >>> wlan = network.WLAN(network.AP_IF) >>> wlan.active(True) and wlan.config('ifname') 'ap1' >>> wlan = network.WLAN(network.STA_IF) >>> wlan.active(True) and wlan.config('ifname') 'st1' >>> ppp = network.PPP(machine.UART(0)) >>> ppp.active(True) and ppp.config('ifname') 'pp1' >>> ppp = network.PPP(machine.UART(0)) >>> ppp.active(True) and ppp.config('ifname') 'pp2' >>> ppp = network.PPP(machine.UART(0)) >>> ppp.active(True) and ppp.config('ifname') 'pp3' Note that lo0 seems to be returned by lwIP if the interface is not yet active. The method can also return None in the case of PPP where the entire lwIP interface doesn't yet exist before being activated. Currently no effort is made to unify those cases; it is expected that whatever we receive from lwIP is valid. When the socket option is set, this forces using a specific device: import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, 'st1') setsockopt will throw (OSError: [Errno 19] ENODEV) if the specified interface does not exist. Tested with LAN, WLAN, and PPP; can specify which interface should be used and when testing with, for example, HTTP requests to ifconfig.co the returned IP address confirms a specific interface was used. Signed-off-by: Daniël van de Giessen --- ports/esp32/modnetwork.h | 2 ++ ports/esp32/modsocket.c | 13 +++++++++++ ports/esp32/network_common.c | 10 ++++++++ ports/esp32/network_lan.c | 4 ++++ ports/esp32/network_ppp.c | 45 ++++++++++++++++++++++++++++++++++++ ports/esp32/network_wlan.c | 4 ++++ 6 files changed, 78 insertions(+) diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h index 79bf9973ca..e57b80657f 100644 --- a/ports/esp32/modnetwork.h +++ b/ports/esp32/modnetwork.h @@ -57,6 +57,8 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_ifconfig_obj); MP_DECLARE_CONST_FUN_OBJ_KW(esp_network_config_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_phy_mode_obj); +mp_obj_t esp_ifname(esp_netif_t *netif); + NORETURN void esp_exceptions_helper(esp_err_t e); static inline void esp_exceptions(esp_err_t e) { diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index e5a370641f..fe76b5f760 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -396,6 +396,18 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { break; } + case SO_BINDTODEVICE: { + size_t len; + const char *val = mp_obj_str_get_data(args[3], &len); + char ifname[NETIF_NAMESIZE] = {0}; + memcpy(&ifname, val, len); + int ret = lwip_setsockopt(self->fd, SOL_SOCKET, opt, &ifname, NETIF_NAMESIZE); + if (ret != 0) { + mp_raise_OSError(errno); + } + break; + } + #if MICROPY_PY_SOCKET_EVENTS // level: SOL_SOCKET // special "register callback" option @@ -860,6 +872,7 @@ STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) }, { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) }, { MP_ROM_QSTR(MP_QSTR_SO_BROADCAST), MP_ROM_INT(SO_BROADCAST) }, + { MP_ROM_QSTR(MP_QSTR_SO_BINDTODEVICE), MP_ROM_INT(SO_BINDTODEVICE) }, { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) }, }; diff --git a/ports/esp32/network_common.c b/ports/esp32/network_common.c index 082943e2ae..ca07f3c06b 100644 --- a/ports/esp32/network_common.c +++ b/ports/esp32/network_common.c @@ -41,6 +41,7 @@ #include "esp_log.h" #include "esp_netif.h" #include "esp_wifi.h" +#include "lwip/sockets.h" // #include "lwip/dns.h" NORETURN void esp_exceptions_helper(esp_err_t e) { @@ -153,6 +154,15 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_ifconfig_obj, 1, 2, esp_ifconfig); +mp_obj_t esp_ifname(esp_netif_t *netif) { + char ifname[NETIF_NAMESIZE + 1] = {0}; + mp_obj_t ret = mp_const_none; + if (esp_netif_get_netif_impl_name(netif, ifname) == ESP_OK && ifname[0] != 0) { + ret = mp_obj_new_str((char *)ifname, strlen(ifname)); + } + return ret; +} + STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) { return mp_const_none; } diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index fe3ff6f772..8557700446 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -393,6 +393,10 @@ STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs esp_eth_ioctl(self->eth_handle, ETH_CMD_G_MAC_ADDR, mac); return mp_obj_new_bytes(mac, sizeof(mac)); } + case MP_QSTR_ifname: { + val = esp_ifname(self->base.netif); + break; + } default: mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); } diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index caad7eb48b..8ab502426b 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -266,11 +266,56 @@ STATIC mp_obj_t ppp_isconnected(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(ppp_isconnected_obj, ppp_isconnected); +STATIC mp_obj_t ppp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + if (n_args != 1 && kwargs->used != 0) { + mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed")); + } + ppp_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (kwargs->used != 0) { + for (size_t i = 0; i < kwargs->alloc; i++) { + if (mp_map_slot_is_filled(kwargs, i)) { + switch (mp_obj_str_get_qstr(kwargs->table[i].key)) { + default: + break; + } + } + } + return mp_const_none; + } + + if (n_args != 2) { + mp_raise_TypeError(MP_ERROR_TEXT("can query only one param")); + } + + mp_obj_t val = mp_const_none; + + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_ifname: { + if (self->pcb != NULL) { + struct netif *pppif = ppp_netif(self->pcb); + char ifname[NETIF_NAMESIZE + 1] = {0}; + netif_index_to_name(netif_get_index(pppif), ifname); + if (ifname[0] != 0) { + val = mp_obj_new_str((char *)ifname, strlen(ifname)); + } + } + break; + } + default: + mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); + } + + return val; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ppp_config_obj, 1, ppp_config); + STATIC const mp_rom_map_elem_t ppp_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&ppp_active_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&ppp_connect_obj) }, { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&ppp_isconnected_obj) }, { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&ppp_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&ppp_config_obj) }, { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&ppp_ifconfig_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ppp_delete_obj) }, { MP_ROM_QSTR(MP_QSTR_AUTH_NONE), MP_ROM_INT(PPPAUTHTYPE_NONE) }, diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index 8287731c31..58af9f3bc3 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -622,6 +622,10 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_ val = MP_OBJ_NEW_SMALL_INT(channel); break; } + case MP_QSTR_ifname: { + val = esp_ifname(self->netif); + break; + } case MP_QSTR_hostname: case MP_QSTR_dhcp_hostname: { // TODO: Deprecated. Use network.hostname() instead. From f8bd6778c85322b33008d749ae4021cafa067044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20de=20Giessen?= Date: Thu, 29 Jun 2023 14:55:34 +0200 Subject: [PATCH 098/121] esp32: Support JTAG console, free up UART. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_USB_OTG_SUPPORTED is automatically set by the ESP-IDF when the chip supports USB-OTG, which is the case for the ESP32-S2 and ESP32-S3. When trying to use the JTAG console with these chips, it would not work because our USB implementation will take over control over the USB port, breaking the JTAG console in the process. Thus, when the board is configured to use the JTAG console, we should not enable our USB console support. Additionally, this change also frees up UART0 when an USB-based console is configured, since there's no reason to prevent (re)configuration of UART0 for other uses in that case. Signed-off-by: Daniël van de Giessen --- ports/esp32/machine_uart.c | 7 ++++++- ports/esp32/main.c | 6 +++--- ports/esp32/mphalport.c | 6 +++--- ports/esp32/uart.c | 10 +++++++--- ports/esp32/uart.h | 6 +++++- ports/esp32/usb.c | 4 ++-- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index e7b2b8376b..541d7ccc55 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -153,9 +153,11 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co if (args[ARG_txbuf].u_int >= 0 || args[ARG_rxbuf].u_int >= 0) { // must reinitialise driver to change the tx/rx buffer size + #if MICROPY_HW_ENABLE_UART_REPL if (self->uart_num == MICROPY_HW_UART_REPL) { mp_raise_ValueError(MP_ERROR_TEXT("UART buffer size is fixed")); } + #endif if (args[ARG_txbuf].u_int >= 0) { self->txbuf = args[ARG_txbuf].u_int; @@ -353,8 +355,11 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, #endif } + #if MICROPY_HW_ENABLE_UART_REPL // Only reset the driver if it's not the REPL UART. - if (uart_num != MICROPY_HW_UART_REPL) { + if (uart_num != MICROPY_HW_UART_REPL) + #endif + { // Remove any existing configuration uart_driver_delete(self->uart_num); diff --git a/ports/esp32/main.c b/ports/esp32/main.c index a6346b027a..1420dd579c 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -89,10 +89,10 @@ void mp_task(void *pvParameter) { #if MICROPY_PY_THREAD mp_thread_init(pxTaskGetStackStart(NULL), MP_TASK_STACK_SIZE / sizeof(uintptr_t)); #endif - #if CONFIG_USB_OTG_SUPPORTED - usb_init(); - #elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + #if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG usb_serial_jtag_init(); + #elif CONFIG_USB_OTG_SUPPORTED + usb_init(); #endif #if MICROPY_HW_ENABLE_UART_REPL uart_stdout_init(); diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 63a674c24b..d7003a1437 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -111,10 +111,10 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) { if (release_gil) { MP_THREAD_GIL_EXIT(); } - #if CONFIG_USB_OTG_SUPPORTED - usb_tx_strn(str, len); - #elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + #if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG usb_serial_jtag_tx_strn(str, len); + #elif CONFIG_USB_OTG_SUPPORTED + usb_tx_strn(str, len); #endif #if MICROPY_HW_ENABLE_UART_REPL uart_stdout_tx_strn(str, len); diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c index 358d434709..fc69e279e3 100644 --- a/ports/esp32/uart.c +++ b/ports/esp32/uart.c @@ -26,14 +26,16 @@ * THE SOFTWARE. */ -#include - -#include "hal/uart_hal.h" #include "py/runtime.h" #include "py/mphal.h" #include "uart.h" +#if MICROPY_HW_ENABLE_UART_REPL + +#include +#include "hal/uart_hal.h" + // Backwards compatibility for when MICROPY_HW_UART_REPL was a ESP-IDF UART // driver enum. Only UART_NUM_0 was supported with that version of the driver. #define UART_NUM_0 0 @@ -118,3 +120,5 @@ STATIC void IRAM_ATTR uart_irq_handler(void *arg) { } } } + +#endif // MICROPY_HW_ENABLE_UART_REPL diff --git a/ports/esp32/uart.h b/ports/esp32/uart.h index 6410db24c9..3d88eed825 100644 --- a/ports/esp32/uart.h +++ b/ports/esp32/uart.h @@ -30,9 +30,11 @@ // Whether to enable the REPL on a UART. #ifndef MICROPY_HW_ENABLE_UART_REPL -#define MICROPY_HW_ENABLE_UART_REPL (!CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) +#define MICROPY_HW_ENABLE_UART_REPL (!CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_CDC && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) #endif +#if MICROPY_HW_ENABLE_UART_REPL + #ifndef MICROPY_HW_UART_REPL #define MICROPY_HW_UART_REPL (0) #endif @@ -44,4 +46,6 @@ void uart_stdout_init(void); int uart_stdout_tx_strn(const char *str, size_t len); +#endif // MICROPY_HW_ENABLE_UART_REPL + #endif // MICROPY_INCLUDED_ESP32_UART_H diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c index b9d99676d3..2e417755c9 100644 --- a/ports/esp32/usb.c +++ b/ports/esp32/usb.c @@ -28,7 +28,7 @@ #include "py/mphal.h" #include "usb.h" -#if CONFIG_USB_OTG_SUPPORTED +#if CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_CDC && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG #include "esp_timer.h" #ifndef NO_QSTR @@ -97,4 +97,4 @@ void usb_tx_strn(const char *str, size_t len) { } } -#endif // CONFIG_USB_OTG_SUPPORTED +#endif // CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_CDC && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG From 3cc3e4e032edd912dd3a55b8df65927e48217f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20de=20Giessen?= Date: Wed, 23 Nov 2022 14:20:58 +0100 Subject: [PATCH 099/121] esp32/machine_uart: Release GIL for blocking reads. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we're reading from an UART with a non-zero timeout, we can release the GIL so that other threads/tasks may run while we are sleeping waiting for data to arrive. Signed-off-by: Daniël van de Giessen --- ports/esp32/machine_uart.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index 541d7ccc55..0b4f5890ba 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -472,8 +472,17 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz time_to_wait = pdMS_TO_TICKS(self->timeout); } + bool release_gil = time_to_wait > 0; + if (release_gil) { + MP_THREAD_GIL_EXIT(); + } + int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait); + if (release_gil) { + MP_THREAD_GIL_ENTER(); + } + if (bytes_read <= 0) { *errcode = MP_EAGAIN; return MP_STREAM_ERROR; From f52a2cd55afb3f487801aaa62e15328134eb73a4 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Wed, 16 Aug 2023 15:08:50 +1000 Subject: [PATCH 100/121] samd/modules/_boot.py: Add /lib to sys.path. Needed for mip to find a default location to install to. Like esp32, samd uses "/" as the mount point for the flash. Make _boot.py add the entry after successfully mounting. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- ports/samd/modules/_boot.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/samd/modules/_boot.py b/ports/samd/modules/_boot.py index 1ff51de598..93522e2ea3 100644 --- a/ports/samd/modules/_boot.py +++ b/ports/samd/modules/_boot.py @@ -1,6 +1,7 @@ import gc import os import samd +import sys bdev = samd.Flash() @@ -13,7 +14,8 @@ except: fs_type.mkfs(bdev, progsize=256) vfs = fs_type(bdev, progsize=256) os.mount(vfs, "/") +sys.path.append("/lib") -del vfs, fs_type, bdev, os, samd +del vfs, fs_type, bdev, os, samd, sys gc.collect() del gc From 607548f32d98d955775bc02d4fc2b33a79e860ee Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 29 May 2023 16:56:38 +1000 Subject: [PATCH 101/121] examples/natmod: Add features4 as a class definition example. Also provide a basic README.md for dynamic native modules. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- examples/natmod/README.md | 74 +++++++++++++++++++++++++++ examples/natmod/features4/Makefile | 14 +++++ examples/natmod/features4/features4.c | 73 ++++++++++++++++++++++++++ tools/ci.sh | 1 + 4 files changed, 162 insertions(+) create mode 100644 examples/natmod/README.md create mode 100644 examples/natmod/features4/Makefile create mode 100644 examples/natmod/features4/features4.c diff --git a/examples/natmod/README.md b/examples/natmod/README.md new file mode 100644 index 0000000000..0cc4010ef4 --- /dev/null +++ b/examples/natmod/README.md @@ -0,0 +1,74 @@ +# Dynamic Native Modules + +Dynamic Native Modules are .mpy files that contain native machine code from a +language other than Python. For more info see [the documentation] +(https://docs.micropython.org/en/latest/develop/natmod.html). + +This should not be confused with [User C Modules] +(https://docs.micropython.org/en/latest/develop/cmodules.html) which are a +mechanism to add additional out-of-tree modules into the firmware build. + +## Examples + +This directory contains several examples of writing dynamic native modules, in +two main categories: + +1. Feature examples. + + * `features0` - A module containing a single "factorial" function which + demonstrates working with integers. + + * `features1` - A module that demonstrates some common tasks: + - defining simple functions exposed to Python + - defining local, helper C functions + - defining constant integers and strings exposed to Python + - getting and creating integer objects + - creating Python lists + - raising exceptions + - allocating memory + - BSS and constant data (rodata) + - relocated pointers in rodata + + * `features2` - This is a hybrid module containing both Python and C code, + and additionally the C code is spread over multiple files. It also + demonstrates using floating point (only when the target supports + hardware floating point). + + * `features3` - A module that shows how to use types, constant objects, + and creating dictionary instances. + + * `features4` - A module that demonstrates how to define a class. + +2. Dynamic version of existing built-ins. + + This provides a way to add missing functionality to firmware that doesn't + include certain built-in modules. See the `heapq`, `random`, `re`, + `deflate`, `btree`, and `framebuf` directories. + + So for example, if your firmware was compiled with `MICROPY_PY_FRAMEBUF` + disabled (e.g. to save flash space), then it would not include the + `framebuf` module. The `framebuf` native module provides a way to add the + `framebuf` module dynamically. + + The way these work is they define a dynamic native module which + `#include`'s the original module and then does the necessary + initialisation of the module's globals dict. + +## Build instructions + +To compile an example, you need to have the same toolchain available as +required for your target port. e.g. `arm-none-eabi-gcc` for any ARM Cortex M +target. See the port instructions for details. + +You also need to have the `pyelftools` Python package available, either via +your system package manager or installed from PyPI in a virtual environment +with `pip`. + +Each example provides a Makefile. You should specify the `ARCH` argument to +make (one of x86, x64, armv6m, armv7m, xtensa, xtensawin): + +``` +$ cd features0 +$ make ARCH=armv7m +$ mpremote cp features0.mpy : +``` diff --git a/examples/natmod/features4/Makefile b/examples/natmod/features4/Makefile new file mode 100644 index 0000000000..f76a31a7cc --- /dev/null +++ b/examples/natmod/features4/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features4 + +# Source files (.c or .py) +SRC = features4.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features4/features4.c b/examples/natmod/features4/features4.c new file mode 100644 index 0000000000..336f4ecf64 --- /dev/null +++ b/examples/natmod/features4/features4.c @@ -0,0 +1,73 @@ +/* + This example extends on features0 but demonstrates how to define a class. + + The Factorial class constructor takes an integer, and then the calculate + method can be called to get the factorial. + + >>> import features4 + >>> f = features4.Factorial(4) + >>> f.calculate() + 24 +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// This is type(Factorial) +mp_obj_full_type_t mp_type_factorial; + +// This is the internal state of a Factorial instance. +typedef struct { + mp_obj_base_t base; + mp_int_t n; +} mp_obj_factorial_t; + +// Essentially Factorial.__new__ (but also kind of __init__). +// Takes a single argument (the number to find the factorial of) +STATIC mp_obj_t factorial_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_obj_factorial_t *o = mp_obj_malloc(mp_obj_factorial_t, type); + o->n = mp_obj_get_int(args_in[0]); + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); +} + +// Implements Factorial.calculate() +STATIC mp_obj_t factorial_calculate(mp_obj_t self_in) { + mp_obj_factorial_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(factorial_helper(self->n)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate); + +// Locals dict for the Factorial type (will have a single method, calculate, +// added in mpy_init). +mp_map_elem_t factorial_locals_dict_table[1]; +STATIC MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Initialise the type. + mp_type_factorial.base.type = (void*)&mp_type_type; + mp_type_factorial.flags = MP_TYPE_FLAG_NONE; + mp_type_factorial.name = MP_QSTR_Factorial; + MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, make_new, factorial_make_new, 0); + factorial_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_calculate), MP_OBJ_FROM_PTR(&factorial_calculate_obj) }; + MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, locals_dict, (void*)&factorial_locals_dict, 1); + + // Make the Factorial type available on the module. + mp_store_global(MP_QSTR_Factorial, MP_OBJ_FROM_PTR(&mp_type_factorial)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/tools/ci.sh b/tools/ci.sh index 33dc58d6b8..5ce742b01b 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -425,6 +425,7 @@ function ci_native_mpy_modules_build { make -C examples/natmod/features1 ARCH=$arch make -C examples/natmod/features2 ARCH=$arch make -C examples/natmod/features3 ARCH=$arch + make -C examples/natmod/features4 ARCH=$arch make -C examples/natmod/btree ARCH=$arch make -C examples/natmod/deflate ARCH=$arch make -C examples/natmod/framebuf ARCH=$arch From 6aa404ca53e3ebd1f234a8d62259a1e660a4132c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 2 Sep 2023 00:37:45 +1000 Subject: [PATCH 102/121] tools/metrics.py: Fix nrf and rp2 board names after renaming. Signed-off-by: Damien George --- tools/metrics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/metrics.py b/tools/metrics.py index 13161e9b9a..95156e3012 100755 --- a/tools/metrics.py +++ b/tools/metrics.py @@ -68,8 +68,8 @@ port_data = { "3": PortData("esp32", "esp32", "build-GENERIC/micropython.elf"), "x": PortData("mimxrt", "mimxrt", "build-TEENSY40/firmware.elf"), "e": PortData("renesas-ra", "renesas-ra", "build-EK_RA6M2/firmware.elf"), - "r": PortData("nrf", "nrf", "build-pca10040/firmware.elf"), - "p": PortData("rp2", "rp2", "build-PICO/firmware.elf"), + "r": PortData("nrf", "nrf", "build-PCA10040/firmware.elf"), + "p": PortData("rp2", "rp2", "build-RPI_PICO/firmware.elf"), "d": PortData("samd", "samd", "build-ADAFRUIT_ITSYBITSY_M4_EXPRESS/firmware.elf"), } From 9f1576f2ade989d10c9504450f69779d48f9674c Mon Sep 17 00:00:00 2001 From: robert-hh Date: Sat, 17 Jun 2023 16:07:58 +0200 Subject: [PATCH 103/121] rp2/machine_timer: Fix printing of timer period. Showing the period alway as microsecond quantities, since tick_hz is assumed as 1_000_000 if the period is given by freq=xxx. If the period is larger than 0xffffffff, the value is divided by 1000 and "000" is appended in the display. That works for periods up to about 50 days. Signed-off-by: robert-hh --- ports/rp2/machine_timer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/rp2/machine_timer.c b/ports/rp2/machine_timer.c index e4fbb03af4..f0df541e6b 100644 --- a/ports/rp2/machine_timer.c +++ b/ports/rp2/machine_timer.c @@ -57,7 +57,12 @@ STATIC int64_t alarm_callback(alarm_id_t id, void *user_data) { STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); qstr mode = self->mode == TIMER_MODE_ONE_SHOT ? MP_QSTR_ONE_SHOT : MP_QSTR_PERIODIC; - mp_printf(print, "Timer(mode=%q, period=%u, tick_hz=1000000)", mode, self->delta_us); + mp_printf(print, "Timer(mode=%q, tick_hz=1000000, period=", mode); + if (self->delta_us <= 0xffffffff) { + mp_printf(print, "%u)", (uint32_t)self->delta_us); + } else { + mp_printf(print, "%u000)", (uint32_t)(self->delta_us / 1000)); + } } STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { From 6ec2e8f6437017d72ea1b777aa3941ec7fbaee96 Mon Sep 17 00:00:00 2001 From: Seon Rozenblum Date: Thu, 3 Aug 2023 20:23:50 +1000 Subject: [PATCH 104/121] esp32/boards: Add pins.csv to UM boards and other minor changes. Signed-off-by: Seon Rozenblum --- ports/esp32/boards/UM_FEATHERS2/pins.csv | 12 ++++++++++++ ports/esp32/boards/UM_FEATHERS2/sdkconfig.board | 2 ++ ports/esp32/boards/UM_FEATHERS2NEO/pins.csv | 14 ++++++++++++++ ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h | 3 +++ ports/esp32/boards/UM_FEATHERS3/pins.csv | 15 +++++++++++++++ ports/esp32/boards/UM_FEATHERS3/sdkconfig.board | 1 + ports/esp32/boards/UM_PROS3/pins.csv | 12 ++++++++++++ ports/esp32/boards/UM_PROS3/sdkconfig.board | 1 + ports/esp32/boards/UM_TINYPICO/pins.csv | 12 ++++++++++++ ports/esp32/boards/UM_TINYS2/pins.csv | 12 ++++++++++++ ports/esp32/boards/UM_TINYS3/pins.csv | 12 ++++++++++++ ports/esp32/boards/UM_TINYS3/sdkconfig.board | 1 + 12 files changed, 97 insertions(+) create mode 100644 ports/esp32/boards/UM_FEATHERS2/pins.csv create mode 100644 ports/esp32/boards/UM_FEATHERS2NEO/pins.csv create mode 100644 ports/esp32/boards/UM_FEATHERS3/pins.csv create mode 100644 ports/esp32/boards/UM_PROS3/pins.csv create mode 100644 ports/esp32/boards/UM_TINYPICO/pins.csv create mode 100644 ports/esp32/boards/UM_TINYS2/pins.csv create mode 100644 ports/esp32/boards/UM_TINYS3/pins.csv diff --git a/ports/esp32/boards/UM_FEATHERS2/pins.csv b/ports/esp32/boards/UM_FEATHERS2/pins.csv new file mode 100644 index 0000000000..edb7273f32 --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2/pins.csv @@ -0,0 +1,12 @@ +AMB_LIGHT,GPIO4 +I2C_SCL,GPIO8 +I2C_SDA,GPIO9 +LDO2_PWR,GPIO21 +LED_BLUE,GPIO13 +RGB_DATA,GPIO40 +RGB_CLK,GPIO45 +SPI_MOSI,GPIO35 +SPI_SCK,GPIO36 +SPI_MISO,GPIO37 +UART0_TX,GPIO43 +UART0_RX,GPIO44 diff --git a/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board index b23755dea7..c2e1c2b3d3 100644 --- a/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board +++ b/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board @@ -2,6 +2,8 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y CONFIG_ESPTOOLPY_AFTER_NORESET=y +CONFIG_SPIRAM_MEMTEST= + CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y CONFIG_PARTITION_TABLE_CUSTOM=y diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/pins.csv b/ports/esp32/boards/UM_FEATHERS2NEO/pins.csv new file mode 100644 index 0000000000..48e933dc95 --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/pins.csv @@ -0,0 +1,14 @@ +I2C_SCL,GPIO8 +I2C_SDA,GPIO9 +LED_BLUE,GPIO13 +RGB_DATA,GPIO40 +RGB_PWR,GPIO39 +RGB_MATRIX_DATA,GPIO21 +RGB_MATRIX_DATA,GPIO4 +SPI_MOSI,GPIO35 +SPI_SCK,GPIO36 +SPI_MISO,GPIO37 +UART0_TX,GPIO43 +UART0_RX,GPIO44 +VBAT_SENSE,GPIO2 +VBUS_SENSE,GPIO34 diff --git a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h index 91ea5056d1..488a588442 100644 --- a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h +++ b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h @@ -7,6 +7,9 @@ #define MICROPY_HW_I2C0_SCL (9) #define MICROPY_HW_I2C0_SDA (8) +#define MICROPY_HW_I2C1_SCL (15) +#define MICROPY_HW_I2C1_SDA (16) + #define MICROPY_HW_SPI1_MOSI (35) #define MICROPY_HW_SPI1_MISO (37) #define MICROPY_HW_SPI1_SCK (36) diff --git a/ports/esp32/boards/UM_FEATHERS3/pins.csv b/ports/esp32/boards/UM_FEATHERS3/pins.csv new file mode 100644 index 0000000000..83f889fb2a --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS3/pins.csv @@ -0,0 +1,15 @@ +AMB_LIGHT,GPIO4 +I2C_SCL,GPIO8 +I2C_SDA,GPIO9 +I2C_SCL2,GPIO15 +I2C_SDA2,GPIO16 +LDO2_PWR,GPIO39 +LED_BLUE,GPIO13 +SPI_MOSI,GPIO35 +SPI_SCK,GPIO36 +SPI_MISO,GPIO37 +RGB_DATA,GPIO40 +UART0_TX,GPIO43 +UART0_RX,GPIO44 +VBAT_SENSE,GPIO2 +VBUS_SENSE,GPIO34 diff --git a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board index 804944ab24..3c8df5e2a8 100644 --- a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board +++ b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board @@ -5,6 +5,7 @@ CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB= CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_SPIRAM_MEMTEST= CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv" diff --git a/ports/esp32/boards/UM_PROS3/pins.csv b/ports/esp32/boards/UM_PROS3/pins.csv new file mode 100644 index 0000000000..c0d4149d75 --- /dev/null +++ b/ports/esp32/boards/UM_PROS3/pins.csv @@ -0,0 +1,12 @@ +I2C_SCL,GPIO8 +I2C_SDA,GPIO9 +VBAT_SENSE,GPIO10 +LDO2_PWR,GPIO17 +RGB_DATA,GPIO18 +VBUS_SENSE,GPIO33 +SPI_SS,GPIO34 +SPI_MOSI,GPIO35 +SPI_SCK,GPIO36 +SPI_MISO,GPIO37 +UART0_TX,GPIO43 +UART0_RX,GPIO44 diff --git a/ports/esp32/boards/UM_PROS3/sdkconfig.board b/ports/esp32/boards/UM_PROS3/sdkconfig.board index 71511e3c52..5d1ac0f684 100644 --- a/ports/esp32/boards/UM_PROS3/sdkconfig.board +++ b/ports/esp32/boards/UM_PROS3/sdkconfig.board @@ -5,6 +5,7 @@ CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB= CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_SPIRAM_MEMTEST= CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv" diff --git a/ports/esp32/boards/UM_TINYPICO/pins.csv b/ports/esp32/boards/UM_TINYPICO/pins.csv new file mode 100644 index 0000000000..a8ab074cce --- /dev/null +++ b/ports/esp32/boards/UM_TINYPICO/pins.csv @@ -0,0 +1,12 @@ +I2C_SCL,GPIO22 +I2C_SDA,GPIO21 +RGB_DATA,GPIO2 +RGB_CLK,GPIO12 +RGB_PWR,GPIO13 +SPI_SS,GPIO5 +SPI_MOSI,GPIO23 +SPI_SCK,GPIO18 +SPI_MISO,GPIO19 +VBAT_SENSE,GPIO35 +VBAT_CHRG,GPIO34 +VBUS_SENSE,GPIO9 diff --git a/ports/esp32/boards/UM_TINYS2/pins.csv b/ports/esp32/boards/UM_TINYS2/pins.csv new file mode 100644 index 0000000000..1ef7b2ecc8 --- /dev/null +++ b/ports/esp32/boards/UM_TINYS2/pins.csv @@ -0,0 +1,12 @@ +I2C_SCL,GPIO8 +I2C_SDA,GPIO9 +RGB_DATA,GPIO1 +RGB_PWR,GPIO2 +SPI_SS,GPIO14 +SPI_MOSI,GPIO35 +SPI_SCK,GPIO36 +SPI_MISO,GPIO37 +UART0_TX,GPIO43 +UART0_RX,GPIO44 +VBAT_SENSE,GPIO3 +VBUS_SENSE,GPIO21 diff --git a/ports/esp32/boards/UM_TINYS3/pins.csv b/ports/esp32/boards/UM_TINYS3/pins.csv new file mode 100644 index 0000000000..1fad949a44 --- /dev/null +++ b/ports/esp32/boards/UM_TINYS3/pins.csv @@ -0,0 +1,12 @@ +I2C_SCL,GPIO8 +I2C_SDA,GPIO9 +RGB_DATA,GPIO18 +RGB_PWR,GPIO19 +SPI_SS,GPIO34 +SPI_MOSI,GPIO35 +SPI_SCK,GPIO36 +SPI_MISO,GPIO37 +UART0_TX,GPIO43 +UART0_RX,GPIO44 +VBAT_SENSE,GPIO10 +VBUS_SENSE,GPIO33 diff --git a/ports/esp32/boards/UM_TINYS3/sdkconfig.board b/ports/esp32/boards/UM_TINYS3/sdkconfig.board index c22e78eaea..7b913a565f 100644 --- a/ports/esp32/boards/UM_TINYS3/sdkconfig.board +++ b/ports/esp32/boards/UM_TINYS3/sdkconfig.board @@ -5,6 +5,7 @@ CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y CONFIG_ESPTOOLPY_FLASHSIZE_16MB= +CONFIG_SPIRAM_MEMTEST= CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv" From 6bd1404225a53bd85b75480146f6fbd1fd438ab9 Mon Sep 17 00:00:00 2001 From: Seon Rozenblum Date: Thu, 3 Aug 2023 20:21:51 +1000 Subject: [PATCH 105/121] esp32/boards/UM_NANOS3: Add new UM NanoS3 board. Signed-off-by: Seon Rozenblum --- ports/esp32/boards/UM_NANOS3/board.json | 25 +++++++++ ports/esp32/boards/UM_NANOS3/board.md | 1 + ports/esp32/boards/UM_NANOS3/deploy.md | 52 +++++++++++++++++++ ports/esp32/boards/UM_NANOS3/manifest.py | 2 + .../esp32/boards/UM_NANOS3/modules/nanos3.py | 46 ++++++++++++++++ .../boards/UM_NANOS3/mpconfigboard.cmake | 12 +++++ ports/esp32/boards/UM_NANOS3/mpconfigboard.h | 12 +++++ ports/esp32/boards/UM_NANOS3/pins.csv | 10 ++++ ports/esp32/boards/UM_NANOS3/sdkconfig.board | 19 +++++++ 9 files changed, 179 insertions(+) create mode 100644 ports/esp32/boards/UM_NANOS3/board.json create mode 100644 ports/esp32/boards/UM_NANOS3/board.md create mode 100644 ports/esp32/boards/UM_NANOS3/deploy.md create mode 100644 ports/esp32/boards/UM_NANOS3/manifest.py create mode 100644 ports/esp32/boards/UM_NANOS3/modules/nanos3.py create mode 100644 ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake create mode 100644 ports/esp32/boards/UM_NANOS3/mpconfigboard.h create mode 100644 ports/esp32/boards/UM_NANOS3/pins.csv create mode 100644 ports/esp32/boards/UM_NANOS3/sdkconfig.board diff --git a/ports/esp32/boards/UM_NANOS3/board.json b/ports/esp32/boards/UM_NANOS3/board.json new file mode 100644 index 0000000000..2eb40ac3c9 --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/board.json @@ -0,0 +1,25 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "RGB LED", + "SPIRAM", + "WiFi", + "BLE" + ], + "features_non_filterable": [ + "TinyPICO Nano Compatible" + ], + "id": "nanos3", + "images": [ + "unexpectedmaker_nanos3.jpg" + ], + "mcu": "esp32s3", + "product": "NanoS3", + "thumbnail": "", + "url": "https://nanos3.io", + "vendor": "Unexpected Maker" +} diff --git a/ports/esp32/boards/UM_NANOS3/board.md b/ports/esp32/boards/UM_NANOS3/board.md new file mode 100644 index 0000000000..9cb5310f63 --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/board.md @@ -0,0 +1 @@ +The following files are firmware for the NanoS3. diff --git a/ports/esp32/boards/UM_NANOS3/deploy.md b/ports/esp32/boards/UM_NANOS3/deploy.md new file mode 100644 index 0000000000..725cff4946 --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/deploy.md @@ -0,0 +1,52 @@ +Program your board using the latest version of the esptool.py program, found [here](https://github.com/espressif/esptool). + +To flash or erase your NanoS3, you have to first put it into download mode. +To do this, follow these steps: + +- Press and hold the [BOOT] button +- Press and release the [RESET] button +- Release the [BOOT] button + +Now the board is in download mode and the native USB will have enumerated as a serial device. + +If you are putting MicroPython on your board for the first time then you should +first erase the entire flash using: + +### Linux +```bash +esptool.py --chip esp32s3 --port /dev/ttyACM0 erase_flash +``` + +### Mac +Please do a `ls /dev/cu.usbm*` to determine the port your board has enumerated as. +```bash +esptool.py --chip esp32s3 --port /dev/cu.usbmodem01 erase_flash +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s3 --port COM(X) erase_flash +``` + +Now download the version of the firmware you would like to install from the options below, +then use the following command to program the firmware starting at address 0x0, +remembering to replace `nanos3-micropython-firmware-version.bin` with the name of +the firmware you just downloaded: + +### Linux +```bash +esptool.py --chip esp32s3 --port /dev/ttyACM0 write_flash -z 0x0 nanos3-micropython-firmware-version.bin +``` + +### Mac +Please do a `ls /dev/cu.usbm*` to determine the port your board has enumerated as. +```bash +esptool.py --chip esp32s3 --port /dev/cu.usbmodem01 write_flash -z 0x0 nanos3-micropython-firmware-version.bin +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s3 --port COM(X) write_flash -z 0x0 nanos3-micropython-firmware-version.bin +``` diff --git a/ports/esp32/boards/UM_NANOS3/manifest.py b/ports/esp32/boards/UM_NANOS3/manifest.py new file mode 100644 index 0000000000..7ae2ed15d9 --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/manifest.py @@ -0,0 +1,2 @@ +include("$(PORT_DIR)/boards/manifest.py") +freeze("modules") diff --git a/ports/esp32/boards/UM_NANOS3/modules/nanos3.py b/ports/esp32/boards/UM_NANOS3/modules/nanos3.py new file mode 100644 index 0000000000..b3d57f121a --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/modules/nanos3.py @@ -0,0 +1,46 @@ +# NanoS3 Helper Library +# MIT license; Copyright (c) 2023 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://nanos3.io + +# Import required libraries +from micropython import const +from machine import Pin, ADC +import time + +# TinyS3 Hardware Pin Assignments + +# RGB LED Pins +RGB_DATA = const(41) +RGB_PWR = const(42) + +# SPI +SPI_MOSI = const(35) +SPI_MISO = const(37) +SPI_CLK = const(36) + +# I2C +I2C_SDA = const(8) +I2C_SCL = const(9) + + +# Helper functions +def set_pixel_power(state): + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + Pin(RGB_PWR, Pin.OUT).value(state) + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 diff --git a/ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake b/ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake new file mode 100644 index 0000000000..6c7f34009e --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake @@ -0,0 +1,12 @@ +set(IDF_TARGET esp32s3) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.usb + boards/sdkconfig.ble + boards/sdkconfig.240mhz + boards/sdkconfig.spiram_sx + boards/UM_TINYS3/sdkconfig.board +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) diff --git a/ports/esp32/boards/UM_NANOS3/mpconfigboard.h b/ports/esp32/boards/UM_NANOS3/mpconfigboard.h new file mode 100644 index 0000000000..1c2782bfb7 --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/mpconfigboard.h @@ -0,0 +1,12 @@ +#define MICROPY_HW_BOARD_NAME "NanoS3" +#define MICROPY_HW_MCU_NAME "ESP32-S3-FN8" +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "NanoS3" + +#define MICROPY_PY_MACHINE_DAC (0) + +#define MICROPY_HW_I2C0_SCL (9) +#define MICROPY_HW_I2C0_SDA (8) + +#define MICROPY_HW_SPI1_MOSI (35) +#define MICROPY_HW_SPI1_MISO (37) +#define MICROPY_HW_SPI1_SCK (36) diff --git a/ports/esp32/boards/UM_NANOS3/pins.csv b/ports/esp32/boards/UM_NANOS3/pins.csv new file mode 100644 index 0000000000..44880f82ba --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/pins.csv @@ -0,0 +1,10 @@ +I2C_SCL,GPIO8 +I2C_SDA,GPIO9 +SPI_SS,GPIO34 +SPI_MOSI,GPIO35 +SPI_SCK,GPIO36 +SPI_MISO,GPIO37 +RGB_DATA,GPIO41 +RGB_PWR,GPIO42 +UART0_TX,GPIO43 +UART0_RX,GPIO44 diff --git a/ports/esp32/boards/UM_NANOS3/sdkconfig.board b/ports/esp32/boards/UM_NANOS3/sdkconfig.board new file mode 100644 index 0000000000..969bbc5be7 --- /dev/null +++ b/ports/esp32/boards/UM_NANOS3/sdkconfig.board @@ -0,0 +1,19 @@ +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_ESPTOOLPY_AFTER_NORESET=y + +CONFIG_ESPTOOLPY_FLASHSIZE_4MB= +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB= +CONFIG_SPIRAM_MEMTEST= +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv" + +CONFIG_LWIP_LOCAL_HOSTNAME="UMNanoS3" + +CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A +CONFIG_TINYUSB_DESC_CUSTOM_PID=0x817A +CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100 +CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker" +CONFIG_TINYUSB_DESC_PRODUCT_STRING="NanoS3" +CONFIG_TINYUSB_DESC_SERIAL_STRING="_ns3_" From c0d4c604e6a140c0f2967e1b43fd94d0b029c73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20de=20Giessen?= Date: Tue, 15 Aug 2023 11:34:23 +0200 Subject: [PATCH 106/121] esp32/network_ppp: Block after deleting task. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When calling ppp.active(False) we could get a crash due to immediately returning after asking FreeRTOS to delete the current task. This commit adds a simple blocking loop, the same as used in all other places where we call vTaskDelete(NULL). Signed-off-by: Daniël van de Giessen --- ports/esp32/network_ppp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c index 8ab502426b..ea0dd1706e 100644 --- a/ports/esp32/network_ppp.c +++ b/ports/esp32/network_ppp.c @@ -114,6 +114,8 @@ static void pppos_client_task(void *self_in) { self->client_task_handle = NULL; vTaskDelete(NULL); + for (;;) { + } } STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { From ffb43b2dd37f10f48612d369b5cad9731c2a0597 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 3 Aug 2023 15:20:30 -0500 Subject: [PATCH 107/121] py/modthread: Return thread id from start_new_thread(). In CPython, `_thread.start_new_thread()` returns an ID that is the same ID that is returned by `_thread.get_ident()`. The current MicroPython implementation of `_thread.start_new_thread()` always returns `None`. This modifies the required functions to return a value. The native thread id is returned since this can be used for interop with other functions, for example, `pthread_kill()` on *nix. `_thread.get_ident()` is also modified to return the native thread id so that the values match and avoids the need for a separate `native_id` attribute. Fixes issue #12153. Signed-off-by: David Lechner --- ports/cc3200/mpthreadport.c | 9 ++++++++- ports/esp32/mpthreadport.c | 12 +++++++++--- ports/renesas-ra/mpthreadport.c | 8 +++++++- ports/rp2/mpthreadport.c | 10 +++++++++- ports/stm32/mpthreadport.c | 8 +++++++- ports/unix/mpthreadport.c | 9 +++++++-- py/modthread.c | 6 ++---- py/mpthread.h | 3 ++- tests/thread/thread_ident1.py | 9 +++++++-- 9 files changed, 58 insertions(+), 16 deletions(-) diff --git a/ports/cc3200/mpthreadport.c b/ports/cc3200/mpthreadport.c index 4b6f27d578..5b4771f395 100644 --- a/ports/cc3200/mpthreadport.c +++ b/ports/cc3200/mpthreadport.c @@ -89,6 +89,10 @@ void mp_thread_set_state(mp_state_thread_t *state) { vTaskSetThreadLocalStoragePointer(NULL, 0, state); } +mp_uint_t mp_thread_get_id(void) { + return (mp_uint_t)xTaskGetCurrentTaskHandle(); +} + void mp_thread_start(void) { mp_thread_mutex_lock(&thread_mutex, 1); for (mp_thread_t *th = thread; th != NULL; th = th->next) { @@ -111,7 +115,7 @@ STATIC void freertos_entry(void *arg) { } } -void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { +mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // store thread entry function into a global variable so we can access it ext_thread_entry = entry; @@ -148,6 +152,9 @@ void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // adjust stack_size to provide room to recover from hitting the limit *stack_size -= 512; + + MP_STATIC_ASSERT(sizeof(mp_uint_t) >= sizeof(TaskHandle_t)); + return (mp_uint_t)id; } void mp_thread_finish(void) { diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index e6c7e9bc80..74dbc14797 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -98,6 +98,10 @@ void mp_thread_set_state(mp_state_thread_t *state) { vTaskSetThreadLocalStoragePointer(NULL, 1, state); } +mp_uint_t mp_thread_get_id(void) { + return (mp_uint_t)xTaskGetCurrentTaskHandle(); +} + void mp_thread_start(void) { mp_thread_mutex_lock(&thread_mutex, 1); for (mp_thread_t *th = thread; th != NULL; th = th->next) { @@ -120,7 +124,7 @@ STATIC void freertos_entry(void *arg) { } } -void mp_thread_create_ex(void *(*entry)(void *), void *arg, size_t *stack_size, int priority, char *name) { +mp_uint_t mp_thread_create_ex(void *(*entry)(void *), void *arg, size_t *stack_size, int priority, char *name) { // store thread entry function into a global variable so we can access it ext_thread_entry = entry; @@ -154,10 +158,12 @@ void mp_thread_create_ex(void *(*entry)(void *), void *arg, size_t *stack_size, *stack_size -= 1024; mp_thread_mutex_unlock(&thread_mutex); + + return (mp_uint_t)th->id; } -void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { - mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread"); +mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { + return mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread"); } void mp_thread_finish(void) { diff --git a/ports/renesas-ra/mpthreadport.c b/ports/renesas-ra/mpthreadport.c index ecdb268468..a7d85cfe32 100644 --- a/ports/renesas-ra/mpthreadport.c +++ b/ports/renesas-ra/mpthreadport.c @@ -54,7 +54,11 @@ void mp_thread_gc_others(void) { mp_thread_mutex_unlock(&thread_mutex); } -void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { +mp_uint_t mp_thread_get_id(void) { + return (uint32_t)pyb_thread_cur; +} + +mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { if (*stack_size == 0) { *stack_size = 4096; // default stack size } else if (*stack_size < 2048) { @@ -82,6 +86,8 @@ void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // adjust stack_size to provide room to recover from hitting the limit *stack_size -= 1024; + + return id; } void mp_thread_start(void) { diff --git a/ports/rp2/mpthreadport.c b/ports/rp2/mpthreadport.c index 33dc698305..ed9e338da7 100644 --- a/ports/rp2/mpthreadport.c +++ b/ports/rp2/mpthreadport.c @@ -116,7 +116,13 @@ STATIC void core1_entry_wrapper(void) { // returning from here will loop the core forever (WFI) } -void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { +mp_uint_t mp_thread_get_id(void) { + // On RP2, there are only two threads, one for each core, so the thread id + // is the core number. + return get_core_num(); +} + +mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // Check if core1 is already in use. if (core1_entry != NULL) { mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("core1 in use")); @@ -144,6 +150,8 @@ void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // Adjust stack_size to provide room to recover from hitting the limit. *stack_size -= 512; + + return 1; } void mp_thread_start(void) { diff --git a/ports/stm32/mpthreadport.c b/ports/stm32/mpthreadport.c index ecdb268468..a7d85cfe32 100644 --- a/ports/stm32/mpthreadport.c +++ b/ports/stm32/mpthreadport.c @@ -54,7 +54,11 @@ void mp_thread_gc_others(void) { mp_thread_mutex_unlock(&thread_mutex); } -void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { +mp_uint_t mp_thread_get_id(void) { + return (uint32_t)pyb_thread_cur; +} + +mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { if (*stack_size == 0) { *stack_size = 4096; // default stack size } else if (*stack_size < 2048) { @@ -82,6 +86,8 @@ void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // adjust stack_size to provide room to recover from hitting the limit *stack_size -= 1024; + + return id; } void mp_thread_start(void) { diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 6a267e7236..2190bf4ad1 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -191,6 +191,10 @@ void mp_thread_set_state(mp_state_thread_t *state) { pthread_setspecific(tls_key, state); } +mp_uint_t mp_thread_get_id(void) { + return (mp_uint_t)pthread_self(); +} + void mp_thread_start(void) { // enable realtime priority if `-X realtime` command line parameter was set #if defined(__APPLE__) @@ -210,7 +214,7 @@ void mp_thread_start(void) { mp_thread_unix_end_atomic_section(); } -void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { +mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { // default stack size is 8k machine-words if (*stack_size == 0) { *stack_size = 8192 * sizeof(void *); @@ -265,7 +269,8 @@ void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { mp_thread_unix_end_atomic_section(); - return; + MP_STATIC_ASSERT(sizeof(mp_uint_t) >= sizeof(pthread_t)); + return (mp_uint_t)id; er: mp_raise_OSError(ret); diff --git a/py/modthread.c b/py/modthread.c index 51d63e4703..6b75474904 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -129,7 +129,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( STATIC size_t thread_stack_size = 0; STATIC mp_obj_t mod_thread_get_ident(void) { - return mp_obj_new_int_from_uint((uintptr_t)mp_thread_get_state()); + return mp_obj_new_int_from_uint(mp_thread_get_id()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_get_ident_obj, mod_thread_get_ident); @@ -268,9 +268,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) th_args->fun = args[0]; // spawn the thread! - mp_thread_create(thread_entry, th_args, &th_args->stack_size); - - return mp_const_none; + return mp_obj_new_int_from_uint(mp_thread_create(thread_entry, th_args, &th_args->stack_size)); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread); diff --git a/py/mpthread.h b/py/mpthread.h index e611ef4c11..f335cc0291 100644 --- a/py/mpthread.h +++ b/py/mpthread.h @@ -40,7 +40,8 @@ struct _mp_state_thread_t; struct _mp_state_thread_t *mp_thread_get_state(void); void mp_thread_set_state(struct _mp_state_thread_t *state); -void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size); +mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size); +mp_uint_t mp_thread_get_id(void); void mp_thread_start(void); void mp_thread_finish(void); void mp_thread_mutex_init(mp_thread_mutex_t *mutex); diff --git a/tests/thread/thread_ident1.py b/tests/thread/thread_ident1.py index 390193accc..8e106cd317 100644 --- a/tests/thread/thread_ident1.py +++ b/tests/thread/thread_ident1.py @@ -5,7 +5,11 @@ import _thread +tid = None + + def thread_entry(): + global tid tid = _thread.get_ident() print("thread", type(tid) == int, tid != 0, tid != tid_main) global finished @@ -16,8 +20,9 @@ tid_main = _thread.get_ident() print("main", type(tid_main) == int, tid_main != 0) finished = False -_thread.start_new_thread(thread_entry, ()) +new_tid = _thread.start_new_thread(thread_entry, ()) while not finished: pass -print("done") + +print("done", type(new_tid) == int, new_tid == tid) From 1b03518e379208d4ee37362ee68ec6696c366efa Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Tue, 1 Aug 2023 09:53:14 +0000 Subject: [PATCH 108/121] extmod/modssl_mbedtls: Call func psa_crypto_init if PSA is used. Whenever the PSA interface is used (if MBEDTLS_PSA_CRYPTO is defined), psa_crypto_init() needs to be called to initialise the global PSA data struct, before any PSA related operations. TLSv1.3 depends on the PSA interface, TLSv1.2 only uses the PSA stack if MBEDTLS_USE_PSA_CRYPTO is defined. Without psa_crypto_init() every PSA related call will result in -0x6C00/-27648 which translates to "SSL - Internal error (eg, unexpected failure in lower-level module)". The error is misleading, especially since mbedtls in its docs itself advices "to return #PSA_ERROR_BAD_STATE or some other applicable error.". Signed-off-by: Mirko Vogt --- extmod/modssl_mbedtls.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 445978e0c3..98baf572e4 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -168,6 +168,12 @@ STATIC mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args mbedtls_debug_set_threshold(3); #endif + // Whenever the PSA interface is used (if MBEDTLS_PSA_CRYPTO), psa_crypto_init() needs to be called before any TLS related operations. + // TLSv1.3 depends on the PSA interface, TLSv1.2 only uses the PSA stack if MBEDTLS_USE_PSA_CRYPTO is defined. + #if defined(MBEDTLS_SSL_PROTO_TLS1_3) || defined(MBEDTLS_USE_PSA_CRYPTO) + psa_crypto_init(); + #endif + const byte seed[] = "upy"; int ret = mbedtls_ctr_drbg_seed(&self->ctr_drbg, mbedtls_entropy_func, &self->entropy, seed, sizeof(seed)); if (ret != 0) { From 65f0cb11afb92cc9c333158ea467667f2127c9a2 Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Tue, 1 Aug 2023 09:59:30 +0000 Subject: [PATCH 109/121] extmod/modssl_mbedtls: Ignore err ERR_SSL_RECEIVED_NEW_SESSION_TICKET. It appears a new session ticket being issued by the server right after completed handshake is not uncommon and shouldn't be treated as fatal. mbedtls itself states "This error code is experimental and may be changed or removed without notice." Signed-off-by: Mirko Vogt --- extmod/modssl_mbedtls.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 98baf572e4..449952594c 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -443,6 +443,14 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc // renegotiation. ret = MP_EWOULDBLOCK; o->poll_mask = MP_STREAM_POLL_WR; + #if defined(MBEDTLS_SSL_PROTO_TLS1_3) + } else if (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) { + // It appears a new session ticket being issued by the server right after + // completed handshake is not uncommon and shouldn't be treated as fatal. + // mbedtls itself states "This error code is experimental and may be + // changed or removed without notice." + ret = MP_EWOULDBLOCK; + #endif } else { o->last_error = ret; } From 545b94a8f50ee8a708d387563a4a400e11ba1aff Mon Sep 17 00:00:00 2001 From: David Yang Date: Tue, 8 Aug 2023 05:35:58 +0800 Subject: [PATCH 110/121] unix/modjni: Fix build errors with type definitions and error strings. - Superfluous comments in MP_DEFINE_CONST_OBJ_TYPE stop correct macro expanding. - MP_ERROR_TEXT now gives mp_rom_error_text_t, but we want plain const char *. Signed-off-by: David Yang --- ports/unix/modjni.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index 10622f588f..a1cfca8149 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -329,8 +329,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( unary_op, jobject_unary_op, attr, jobject_attr, subscr, jobject_subscr, - iter, subscr_getiter, - // .locals_dict = &jobject_locals_dict, + iter, subscr_getiter ); STATIC mp_obj_t new_jobject(jobject jo) { @@ -574,9 +573,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_jmethod, MP_TYPE_FLAG_NONE, print, jmethod_print, - call, jmethod_call, - // .attr = jobject_attr, - // .locals_dict = &jobject_locals_dict, + call, jmethod_call ); #ifdef __ANDROID__ @@ -615,26 +612,26 @@ STATIC void create_jvm(void) { jclass Object_class = JJ(FindClass, "java/lang/Object"); Object_toString_mid = JJ(GetMethodID, Object_class, "toString", - MP_ERROR_TEXT("()Ljava/lang/String;")); + MP_COMPRESSED_ROM_TEXT("()Ljava/lang/String;")); Class_getName_mid = (*env)->GetMethodID(env, Class_class, "getName", - MP_ERROR_TEXT("()Ljava/lang/String;")); + MP_COMPRESSED_ROM_TEXT("()Ljava/lang/String;")); Class_getField_mid = (*env)->GetMethodID(env, Class_class, "getField", - MP_ERROR_TEXT("(Ljava/lang/String;)Ljava/lang/reflect/Field;")); + MP_COMPRESSED_ROM_TEXT("(Ljava/lang/String;)Ljava/lang/reflect/Field;")); Class_getMethods_mid = (*env)->GetMethodID(env, Class_class, "getMethods", - MP_ERROR_TEXT("()[Ljava/lang/reflect/Method;")); + MP_COMPRESSED_ROM_TEXT("()[Ljava/lang/reflect/Method;")); Class_getConstructors_mid = (*env)->GetMethodID(env, Class_class, "getConstructors", - MP_ERROR_TEXT("()[Ljava/lang/reflect/Constructor;")); + MP_COMPRESSED_ROM_TEXT("()[Ljava/lang/reflect/Constructor;")); Method_getName_mid = (*env)->GetMethodID(env, method_class, "getName", - MP_ERROR_TEXT("()Ljava/lang/String;")); + MP_COMPRESSED_ROM_TEXT("()Ljava/lang/String;")); List_class = JJ(FindClass, "java/util/List"); List_get_mid = JJ(GetMethodID, List_class, "get", - MP_ERROR_TEXT("(I)Ljava/lang/Object;")); + MP_COMPRESSED_ROM_TEXT("(I)Ljava/lang/Object;")); List_set_mid = JJ(GetMethodID, List_class, "set", - MP_ERROR_TEXT("(ILjava/lang/Object;)Ljava/lang/Object;")); + MP_COMPRESSED_ROM_TEXT("(ILjava/lang/Object;)Ljava/lang/Object;")); List_size_mid = JJ(GetMethodID, List_class, "size", - MP_ERROR_TEXT("()I")); + MP_COMPRESSED_ROM_TEXT("()I")); IndexException_class = JJ(FindClass, "java/lang/IndexOutOfBoundsException"); } From 6e79b55dc86dd443d50fe2bbf5d03456c2ae54a0 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Sun, 3 Sep 2023 19:07:51 +0300 Subject: [PATCH 111/121] py/malloc: Fix DEBUG_print() args in m_realloc_maybe. Signed-off-by: Ihor Nehrutsa --- py/malloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/malloc.c b/py/malloc.c index efdff75396..ddf139e386 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -185,7 +185,7 @@ void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) #if MICROPY_MALLOC_USES_ALLOCATED_SIZE DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); #else - DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, new_num_bytes, new_ptr); + DEBUG_printf("realloc %p, %d : %p\n", ptr, new_num_bytes, new_ptr); #endif return new_ptr; } From bf35eefc625b35aa301aefbc743dcf1395829865 Mon Sep 17 00:00:00 2001 From: Sebastian Romero Date: Thu, 31 Aug 2023 13:16:17 +0200 Subject: [PATCH 112/121] esp32/boards/ARDUINO_NANO_ESP32: Clarify recovery instructions. Signed-off-by: Sebastian Romero --- ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md b/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md index b600a55b64..bb32ba7559 100644 --- a/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md +++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md @@ -4,5 +4,10 @@ This board can programmed via DFU bootloader, using e.g. [dfu-util](http://dfu-u To enter the DFU bootloader, double tap the reset (blue) button, or you can use `machine.bootloader()` from the MicroPython REPL. ```bash -dfu-util -d 0x2341:0x0070 -R -D build-ARDUINO_NANO_ESP32/micropython.bin +dfu-util -d 0x2341:0x0070 -R -D build-ARDUINO_NANO_ESP32/micropython.app-bin ``` + +Please note that the DFU bootloader comes factory flashed. Should you for any reason erase the +entire flash, the DFU bootloader will have to be re-installed. Please follow the instructions +[here](https://support.arduino.cc/hc/en-us/articles/9810414060188-Reset-the-Arduino-bootloader-on-the-Nano-ESP32) +to do so. From d00105494fda537b42a73843260920bba8eb1bb8 Mon Sep 17 00:00:00 2001 From: Francis Dela Cruz Date: Mon, 21 Aug 2023 12:32:20 +0930 Subject: [PATCH 113/121] docs/library/platform: Add docs for the platform library. Signed-off-by: Francis Dela Cruz --- docs/library/index.rst | 1 + docs/library/platform.rst | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 docs/library/platform.rst diff --git a/docs/library/index.rst b/docs/library/index.rst index ae5d3e7d71..4a7f78ecf3 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -71,6 +71,7 @@ library. json.rst math.rst os.rst + platform.rst random.rst re.rst select.rst diff --git a/docs/library/platform.rst b/docs/library/platform.rst new file mode 100644 index 0000000000..c091477d84 --- /dev/null +++ b/docs/library/platform.rst @@ -0,0 +1,38 @@ +:mod:`platform` -- access to underlying platform’s identifying data +=================================================================== + +.. module:: platform + :synopsis: access to underlying platform’s identifying data + +|see_cpython_module| :mod:`python:platform`. + +This module tries to retrieve as much platform-identifying data as possible. It +makes this information available via function APIs. + +Functions +--------- + +.. function:: platform() + + Returns a string identifying the underlying platform. This string is composed + of several substrings in the following order, delimited by dashes (``-``): + + - the name of the platform system (e.g. Unix, Windows or MicroPython) + - the MicroPython version + - the architecture of the platform + - the version of the underlying platform + - the concatenation of the name of the libc that MicroPython is linked to + and its corresponding version. + + For example, this could be + ``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``. + +.. function:: python_compiler() + + Returns a string identifying the compiler used for compiling MicroPython. + +.. function:: libc_ver() + + Returns a tuple of strings *(lib, version)*, where *lib* is the name of the + libc that MicroPython is linked to, and *version* the corresponding version + of this libc. From 304f13a74ee5909321a67cf538d3a50d85de1e82 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Mon, 4 Sep 2023 12:50:59 +1000 Subject: [PATCH 114/121] docs/library/network: Clarify network.hostname() behaviour. This must be called before the interface connects. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared --- docs/library/network.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/library/network.rst b/docs/library/network.rst index b13c84123c..a14d6192ea 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -171,8 +171,8 @@ The following are functions available in the network module. .. function:: hostname([name]) - Get or set the hostname that will identify this device on the network. It is - applied to all interfaces. + Get or set the hostname that will identify this device on the network. It will + be used by all interfaces. This hostname is used for: * Sending to the DHCP server in the client request. (If using DHCP) @@ -182,6 +182,12 @@ The following are functions available in the network module. If the function is called without parameters, it returns the current hostname. + A change in hostname is typically only applied during connection. For DHCP + this is because the hostname is part of the DHCP client request, and the + implementation of mDNS in most ports only initialises the hostname once + during connection. For this reason, you must set the hostname before + activating/connecting your network interfaces. + The default hostname is typically the name of the board. .. function:: phy_mode([mode]) From 1a5bfa502471c07f44997d05e242aae93687dfe9 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Fri, 1 Sep 2023 18:50:17 +0300 Subject: [PATCH 115/121] docs/esp32/tutorial: Add example for pin access via registers. Synchronous access to pins directly via registers. Signed-off-by: Ihor Nehrutsa --- docs/esp32/tutorial/img/mem32_gpio_output.jpg | Bin 0 -> 204577 bytes docs/esp32/tutorial/peripheral_access.rst | 80 ++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100755 docs/esp32/tutorial/img/mem32_gpio_output.jpg diff --git a/docs/esp32/tutorial/img/mem32_gpio_output.jpg b/docs/esp32/tutorial/img/mem32_gpio_output.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5544202871eb7f5ce19fa6c660d7cbdec83d3335 GIT binary patch literal 204577 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 literal 0 HcmV?d00001 diff --git a/docs/esp32/tutorial/peripheral_access.rst b/docs/esp32/tutorial/peripheral_access.rst index 3304c341de..ecdec101f7 100644 --- a/docs/esp32/tutorial/peripheral_access.rst +++ b/docs/esp32/tutorial/peripheral_access.rst @@ -42,3 +42,83 @@ for this: The MCPWM0 peripheral is in bit position 17 of the above two registers, hence the value of ``DPORT_PWM0_CLK_EN``. + +Synchronous access to pins directly via registers +------------------------------------------------- + +The following code shows how to access pins directly via registers. It has been +tested on a generic ESP32 board. It configures pins 16, 17, 32 and 33 in output +mode via registers, and switches pin output values via registers. Pins 16 and +17 are switched simultaneously. + +.. code-block:: python3 + + from micropython import const + from machine import mem32, Pin + + GPIO_OUT_REG = const(0x3FF44004) # GPIO 0-31 output register + GPIO_OUT1_REG = const(0x3FF44010) # GPIO 32-39 output register + + GPIO_ENABLE_REG = const(0x3FF44020) # GPIO 0-31 output enable register + GPIO_ENABLE1_REG = const(0x3FF4402C) # GPIO 32-39 output enable register + + M16 = 1 << 16 # Pin(16) bit mask + M17 = 1 << 17 # Pin(17) bit mask + + M32 = 1 << (32-32) # Pin(32) bit mask + M33 = 1 << (33-32) # Pin(33) bit mask + + # Enable pin output mode like + # p16 = Pin(16, mode=Pin.OUT) + # p17 = Pin(17, mode=Pin.OUT) + # p32 = Pin(32, mode=Pin.OUT) + # p33 = Pin(33, mode=Pin.OUT) + mem32[GPIO_ENABLE_REG] = mem32[GPIO_ENABLE_REG] | M16 | M17 + mem32[GPIO_ENABLE1_REG] = mem32[GPIO_ENABLE1_REG] | M32 | M33 + + print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG])) + + # Set outputs to 1 like + # p16(1) + # p17(1) + # p32(1) + # p33(1) + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17 + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33 + + print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG])) + + # Set outputs to 0 like + # p16(0) + # p17(0) + # p32(0) + # p33(0) + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17) + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33) + + print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG])) + + while True: + # Set outputs to 1 + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17 + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33 + + # Set outputs to 0 + mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17) + mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33) + + +Output is:: + + 0x0 0x0 + 0x30000 0x3 + 0x0 0x0 + +Pins 16 and 17 are switched synchronously: + +.. image:: img/mem32_gpio_output.jpg + +Same image on pins 32 and 33. + +Note that pins 34-36 and 39 are inputs only. Also pins 1 and 3 are Tx, Rx of the REPL UART, +pins 6-11 are connected to the built-in SPI flash. From 8bd2494c9527a27710d15749dc4034515b473874 Mon Sep 17 00:00:00 2001 From: Seon Rozenblum Date: Mon, 4 Sep 2023 18:28:32 +1000 Subject: [PATCH 116/121] esp32/boards/UM_FEATHERS3: Fix I2C pins in pins.csv. Signed-off-by: Seon Rozenblum --- ports/esp32/boards/UM_FEATHERS3/pins.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/esp32/boards/UM_FEATHERS3/pins.csv b/ports/esp32/boards/UM_FEATHERS3/pins.csv index 83f889fb2a..38240bc33e 100644 --- a/ports/esp32/boards/UM_FEATHERS3/pins.csv +++ b/ports/esp32/boards/UM_FEATHERS3/pins.csv @@ -1,6 +1,6 @@ AMB_LIGHT,GPIO4 -I2C_SCL,GPIO8 -I2C_SDA,GPIO9 +I2C_SCL,GPIO9 +I2C_SDA,GPIO8 I2C_SCL2,GPIO15 I2C_SDA2,GPIO16 LDO2_PWR,GPIO39 From 297892c4f465c1c6991e6bed0649771bbe1374f6 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Fri, 1 Sep 2023 09:01:23 +0200 Subject: [PATCH 117/121] mimxrt/machine_uart: Add a helper function to change the baudrate. And use it in the Bluetooth bindings instead of setting the baudrate by a call to the NXP lib. Also fixes machine_uart.c to work with a baud rate of 921600. Signed-off-by: robert-hh --- ports/mimxrt/machine_uart.c | 32 +++++++++++++++++++++++++------- ports/mimxrt/modmachine.h | 2 ++ ports/mimxrt/mpbthciport.c | 7 +------ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c index ab5d13e083..fba2b7fe30 100644 --- a/ports/mimxrt/machine_uart.c +++ b/ports/mimxrt/machine_uart.c @@ -33,6 +33,7 @@ #include "fsl_lpuart.h" #include "fsl_iomuxc.h" #include CLOCK_CONFIG_H +#include "modmachine.h" #include "pin.h" #define DEFAULT_UART_BAUDRATE (115200) @@ -146,12 +147,34 @@ void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t st } } -static void machine_uart_ensure_active(machine_uart_obj_t *uart) { +static void machine_uart_ensure_active(machine_uart_obj_t *uart) { if (uart->lpuart->CTRL == 0) { mp_raise_OSError(EIO); } } +#if !defined(MIMXRT117x_SERIES) +static inline void uart_set_clock_divider(uint32_t baudrate) { + // For baud rates < 460800 divide the clock by 10, supporting baud rates down to 50 baud. + if (baudrate >= 460800) { + CLOCK_SetDiv(kCLOCK_UartDiv, 0); + } else { + CLOCK_SetDiv(kCLOCK_UartDiv, 9); + } +} +#endif + +void machine_uart_set_baudrate(mp_obj_t uart_in, uint32_t baudrate) { + machine_uart_obj_t *uart = MP_OBJ_TO_PTR(uart_in); + #if defined(MIMXRT117x_SERIES) + // Use the Lpuart1 clock value, which is set for All UART devices. + LPUART_SetBaudRate(uart->lpuart, baudrate, CLOCK_GetRootClockFreq(kCLOCK_Root_Lpuart1)); + #else + uart_set_clock_divider(baudrate); + LPUART_SetBaudRate(uart->lpuart, baudrate, CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot)); + #endif +} + STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, flow=%s, " @@ -292,12 +315,7 @@ STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args // Use the Lpuart1 clock value, which is set for All UART devices. LPUART_Init(self->lpuart, &self->config, CLOCK_GetRootClockFreq(kCLOCK_Root_Lpuart1)); #else - // For baud rates < 1000000 divide the clock by 10, supporting baud rates down to 50 baud. - if (self->config.baudRate_Bps > 1000000) { - CLOCK_SetDiv(kCLOCK_UartDiv, 0); - } else { - CLOCK_SetDiv(kCLOCK_UartDiv, 9); - } + uart_set_clock_divider(self->config.baudRate_Bps); LPUART_Init(self->lpuart, &self->config, CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot)); #endif LPUART_TransferCreateHandle(self->lpuart, &self->handle, LPUART_UserCallback, self); diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h index 1f669af09e..904419df2c 100644 --- a/ports/mimxrt/modmachine.h +++ b/ports/mimxrt/modmachine.h @@ -51,4 +51,6 @@ void machine_i2s_init0(); void machine_i2s_deinit_all(void); void machine_rtc_start(void); +void machine_uart_set_baudrate(mp_obj_t uart, uint32_t baudrate); + #endif // MICROPY_INCLUDED_MIMXRT_MODMACHINE_H diff --git a/ports/mimxrt/mpbthciport.c b/ports/mimxrt/mpbthciport.c index c83c765871..d8b3841364 100644 --- a/ports/mimxrt/mpbthciport.c +++ b/ports/mimxrt/mpbthciport.c @@ -34,9 +34,6 @@ #include "modmachine.h" #include "mpbthciport.h" -#include "fsl_lpuart.h" -#include CLOCK_CONFIG_H - #if MICROPY_PY_BLUETOOTH #define DEBUG_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) @@ -111,9 +108,7 @@ int mp_bluetooth_hci_uart_deinit(void) { int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { DEBUG_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate); if (mp_bthci_uart != MP_OBJ_NULL) { - // This struct is not public, so we use the base defined in board config files. - // machine_uart_obj_t uart = (machine_uart_obj_t *) MP_PTR_FROM_OBJ(mp_bthci_uart); - LPUART_SetBaudRate(MICROPY_HW_BLE_UART_BASE, baudrate, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT); + machine_uart_set_baudrate(mp_bthci_uart, baudrate); } return 0; } From 671b38f9440511b45fe2b93e15272f53135422d3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Sep 2023 11:03:08 +1000 Subject: [PATCH 118/121] mimxrt/sdio: Move config guard so headers are only included if used. Otherwise it's a build error on certain MCU series. Signed-off-by: Damien George --- ports/mimxrt/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/mimxrt/sdio.c b/ports/mimxrt/sdio.c index 771a01e3d9..d97fef9e51 100644 --- a/ports/mimxrt/sdio.c +++ b/ports/mimxrt/sdio.c @@ -30,11 +30,11 @@ #include "pin.h" #include "pendsv.h" +#if MICROPY_PY_NETWORK_CYW43 + #include "fsl_usdhc.h" #include "fsl_iomuxc.h" -#if MICROPY_PY_NETWORK_CYW43 - #if MICROPY_HW_SDIO_SDMMC == 1 #define SDMMC USDHC1 #define SDMMC_IRQn USDHC1_IRQn From 5e50593738d064267f0d527a0a79d91d928e9686 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 19:42:14 +0000 Subject: [PATCH 119/121] github/workflows: Bump actions/checkout from 3 to 4. Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/code_formatting.yml | 4 ++-- .github/workflows/code_size.yml | 2 +- .github/workflows/commit_formatting.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/examples.yml | 2 +- .github/workflows/mpremote.yml | 2 +- .github/workflows/mpy_format.yml | 2 +- .github/workflows/ports.yml | 2 +- .github/workflows/ports_cc3200.yml | 2 +- .github/workflows/ports_esp32.yml | 2 +- .github/workflows/ports_esp8266.yml | 2 +- .github/workflows/ports_mimxrt.yml | 2 +- .github/workflows/ports_nrf.yml | 2 +- .github/workflows/ports_powerpc.yml | 2 +- .github/workflows/ports_qemu-arm.yml | 2 +- .github/workflows/ports_renesas-ra.yml | 2 +- .github/workflows/ports_rp2.yml | 2 +- .github/workflows/ports_samd.yml | 2 +- .github/workflows/ports_stm32.yml | 4 ++-- .github/workflows/ports_teensy.yml | 2 +- .github/workflows/ports_unix.yml | 28 ++++++++++++------------- .github/workflows/ports_webassembly.yml | 2 +- .github/workflows/ports_windows.yml | 2 +- .github/workflows/ports_zephyr.yml | 2 +- .github/workflows/ruff.yml | 2 +- 25 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/code_formatting.yml b/.github/workflows/code_formatting.yml index 81a2715f1b..cab0ae55b2 100644 --- a/.github/workflows/code_formatting.yml +++ b/.github/workflows/code_formatting.yml @@ -10,7 +10,7 @@ jobs: code-formatting: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 - name: Install packages run: source tools/ci.sh && ci_code_formatting_setup @@ -22,7 +22,7 @@ jobs: code-spelling: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 - name: Install packages run: source tools/ci.sh && ci_code_spell_setup diff --git a/.github/workflows/code_size.yml b/.github/workflows/code_size.yml index 5d955703b6..56097a6d3e 100644 --- a/.github/workflows/code_size.yml +++ b/.github/workflows/code_size.yml @@ -20,7 +20,7 @@ jobs: build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 100 - name: Install packages diff --git a/.github/workflows/commit_formatting.yml b/.github/workflows/commit_formatting.yml index 0b27038f2d..a651f8a13a 100644 --- a/.github/workflows/commit_formatting.yml +++ b/.github/workflows/commit_formatting.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: '100' - uses: actions/setup-python@v4 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e9b1700747..afc3166f3d 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 - name: Install Python packages run: pip install Sphinx diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 450805a6bd..6613f10662 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -18,7 +18,7 @@ jobs: embedding: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding - name: Run diff --git a/.github/workflows/mpremote.yml b/.github/workflows/mpremote.yml index 14aef03e07..5b9465d7fe 100644 --- a/.github/workflows/mpremote.yml +++ b/.github/workflows/mpremote.yml @@ -11,7 +11,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # Setting this to zero means fetch all history and tags, # which hatch-vcs can use to discover the version tag. diff --git a/.github/workflows/mpy_format.yml b/.github/workflows/mpy_format.yml index 66abb19b81..baa02ce08d 100644 --- a/.github/workflows/mpy_format.yml +++ b/.github/workflows/mpy_format.yml @@ -17,7 +17,7 @@ jobs: test: runs-on: ubuntu-20.04 # use 20.04 to get python2 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_mpy_format_setup - name: Test mpy-tool.py diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml index fb574ad981..1f262b0ba4 100644 --- a/.github/workflows/ports.yml +++ b/.github/workflows/ports.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build ports download metadata run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards diff --git a/.github/workflows/ports_cc3200.yml b/.github/workflows/ports_cc3200.yml index b58bc24b58..f178a14058 100644 --- a/.github/workflows/ports_cc3200.yml +++ b/.github/workflows/ports_cc3200.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_cc3200_setup - name: Build diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml index 2cc9f592bf..9403aa656b 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -21,7 +21,7 @@ jobs: build_idf50: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_esp32_idf50_setup - name: Build diff --git a/.github/workflows/ports_esp8266.yml b/.github/workflows/ports_esp8266.yml index ba89d5e952..5236edf40b 100644 --- a/.github/workflows/ports_esp8266.yml +++ b/.github/workflows/ports_esp8266.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_esp8266_setup && ci_esp8266_path >> $GITHUB_PATH - name: Build diff --git a/.github/workflows/ports_mimxrt.yml b/.github/workflows/ports_mimxrt.yml index d915625341..614d745807 100644 --- a/.github/workflows/ports_mimxrt.yml +++ b/.github/workflows/ports_mimxrt.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_mimxrt_setup - name: Build diff --git a/.github/workflows/ports_nrf.yml b/.github/workflows/ports_nrf.yml index 8921121780..d9cffb9778 100644 --- a/.github/workflows/ports_nrf.yml +++ b/.github/workflows/ports_nrf.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_nrf_setup - name: Build diff --git a/.github/workflows/ports_powerpc.yml b/.github/workflows/ports_powerpc.yml index a15c4da97f..c41b13e5dd 100644 --- a/.github/workflows/ports_powerpc.yml +++ b/.github/workflows/ports_powerpc.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_powerpc_setup - name: Build diff --git a/.github/workflows/ports_qemu-arm.yml b/.github/workflows/ports_qemu-arm.yml index 93ec4da767..db3cd7871d 100644 --- a/.github/workflows/ports_qemu-arm.yml +++ b/.github/workflows/ports_qemu-arm.yml @@ -22,7 +22,7 @@ jobs: build_and_test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_qemu_arm_setup - name: Build and run test suite diff --git a/.github/workflows/ports_renesas-ra.yml b/.github/workflows/ports_renesas-ra.yml index 33e17a385a..b1a30c2f11 100644 --- a/.github/workflows/ports_renesas-ra.yml +++ b/.github/workflows/ports_renesas-ra.yml @@ -21,7 +21,7 @@ jobs: build_renesas_ra_board: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_renesas_ra_setup - name: Build diff --git a/.github/workflows/ports_rp2.yml b/.github/workflows/ports_rp2.yml index f042ff1151..5741b75d2a 100644 --- a/.github/workflows/ports_rp2.yml +++ b/.github/workflows/ports_rp2.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_rp2_setup - name: Build diff --git a/.github/workflows/ports_samd.yml b/.github/workflows/ports_samd.yml index 9833a2fae2..5bf1826cd1 100644 --- a/.github/workflows/ports_samd.yml +++ b/.github/workflows/ports_samd.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_samd_setup - name: Build diff --git a/.github/workflows/ports_stm32.yml b/.github/workflows/ports_stm32.yml index b278ea862c..0b781a93c1 100644 --- a/.github/workflows/ports_stm32.yml +++ b/.github/workflows/ports_stm32.yml @@ -21,7 +21,7 @@ jobs: build_pyb: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_stm32_setup - name: Build @@ -30,7 +30,7 @@ jobs: build_nucleo: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_stm32_setup - name: Build diff --git a/.github/workflows/ports_teensy.yml b/.github/workflows/ports_teensy.yml index f129960325..291c8e303c 100644 --- a/.github/workflows/ports_teensy.yml +++ b/.github/workflows/ports_teensy.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_teensy_setup - name: Build diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml index 87c58055b9..04dfd78525 100644 --- a/.github/workflows/ports_unix.yml +++ b/.github/workflows/ports_unix.yml @@ -23,7 +23,7 @@ jobs: minimal: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_minimal_build - name: Run main test suite @@ -35,7 +35,7 @@ jobs: reproducible: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build with reproducible date run: source tools/ci.sh && ci_unix_minimal_build env: @@ -46,7 +46,7 @@ jobs: standard: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_standard_build - name: Run main test suite @@ -58,7 +58,7 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_coverage_setup - name: Build @@ -87,7 +87,7 @@ jobs: coverage_32bit: runs-on: ubuntu-20.04 # use 20.04 to get libffi-dev:i386 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_32bit_setup - name: Build @@ -105,7 +105,7 @@ jobs: nanbox: runs-on: ubuntu-20.04 # use 20.04 to get python2, and libffi-dev:i386 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_32bit_setup - name: Build @@ -119,7 +119,7 @@ jobs: float: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_float_build - name: Run main test suite @@ -131,7 +131,7 @@ jobs: stackless_clang: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_clang_setup - name: Build @@ -145,7 +145,7 @@ jobs: float_clang: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_clang_setup - name: Build @@ -159,7 +159,7 @@ jobs: settrace: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_settrace_build - name: Run main test suite @@ -171,7 +171,7 @@ jobs: settrace_stackless: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: source tools/ci.sh && ci_unix_settrace_stackless_build - name: Run main test suite @@ -183,7 +183,7 @@ jobs: macos: runs-on: macos-11.0 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.8' @@ -198,7 +198,7 @@ jobs: qemu_mips: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_qemu_mips_setup - name: Build @@ -212,7 +212,7 @@ jobs: qemu_arm: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_unix_qemu_arm_setup - name: Build diff --git a/.github/workflows/ports_webassembly.yml b/.github/workflows/ports_webassembly.yml index 2e0865662f..880f15ab34 100644 --- a/.github/workflows/ports_webassembly.yml +++ b/.github/workflows/ports_webassembly.yml @@ -20,7 +20,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_webassembly_setup - name: Build diff --git a/.github/workflows/ports_windows.yml b/.github/workflows/ports_windows.yml index b31718c591..4b1f4ea791 100644 --- a/.github/workflows/ports_windows.yml +++ b/.github/workflows/ports_windows.yml @@ -21,7 +21,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_windows_setup - name: Build diff --git a/.github/workflows/ports_zephyr.yml b/.github/workflows/ports_zephyr.yml index f64401b316..f6f328c927 100644 --- a/.github/workflows/ports_zephyr.yml +++ b/.github/workflows/ports_zephyr.yml @@ -20,7 +20,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install packages run: source tools/ci.sh && ci_zephyr_setup - name: Install Zephyr diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index b8e43dc78f..806d95e895 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -5,6 +5,6 @@ jobs: ruff: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: pip install --user ruff - run: ruff --format=github . From 0bafdaf5f0f44295597cf2db8c36447675183339 Mon Sep 17 00:00:00 2001 From: Glenn Moloney Date: Thu, 17 Aug 2023 13:24:25 +1000 Subject: [PATCH 120/121] esp32: Skip validation of image on boot from deepsleep. sdkconfig.base: Add CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y. This reduces time to boot from deepsleep by at least 200ms and can provide significant power savings for deepsleep-based battery applications. docs/library/esp32.rst: Add note cautioning not to enter deepsleep after changing the boot partition, without first performing a hard reset. Signed-off-by: Glenn Moloney --- docs/library/esp32.rst | 5 +++++ ports/esp32/boards/sdkconfig.base | 1 + 2 files changed, 6 insertions(+) diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index 856d9aef8d..d6b4051a2f 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -114,6 +114,11 @@ methods to enable over-the-air (OTA) updates. Sets the partition as the boot partition. + .. note:: Do not enter :func:`deepsleep` after changing + the OTA boot partition, without first performing a hard + :func:`reset` or power cycle. This ensures the bootloader + will validate the new image before booting. + .. method:: Partition.get_next_update() Gets the next update partition after this one, and returns a new Partition object. diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 7443b34aa7..4b7c852332 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -13,6 +13,7 @@ CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y # Bootloader config CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y # Change default log level to "ERROR" (instead of "INFO") CONFIG_LOG_DEFAULT_LEVEL_INFO=n From 3637252b7bc3e85ea92038161e008a550991d1f4 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 5 Sep 2023 10:53:30 +0200 Subject: [PATCH 121/121] tests/multi_net: Increase asyncio tests timeouts. Increase asyncio tests timeouts to account for different WiFi modules and CPU clocks on different boards. Signed-off-by: iabdalkader --- tests/multi_net/asyncio_tcp_close_write.py | 2 +- tests/multi_net/asyncio_tcp_readall.py | 4 ++-- tests/multi_net/asyncio_tcp_readexactly.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/multi_net/asyncio_tcp_close_write.py b/tests/multi_net/asyncio_tcp_close_write.py index d1892fe895..ea206c9219 100644 --- a/tests/multi_net/asyncio_tcp_close_write.py +++ b/tests/multi_net/asyncio_tcp_close_write.py @@ -33,7 +33,7 @@ async def tcp_server(): print("server running") multitest.next() async with server: - await asyncio.wait_for(ev.wait(), 5) + await asyncio.wait_for(ev.wait(), 10) async def tcp_client(): diff --git a/tests/multi_net/asyncio_tcp_readall.py b/tests/multi_net/asyncio_tcp_readall.py index 66ad97549c..45eac229d2 100644 --- a/tests/multi_net/asyncio_tcp_readall.py +++ b/tests/multi_net/asyncio_tcp_readall.py @@ -14,7 +14,7 @@ async def handle_connection(reader, writer): await writer.drain() # Split the first 2 bytes up so the client must wait for the second one - await asyncio.sleep(0.1) + await asyncio.sleep(1) writer.write(b"b") await writer.drain() @@ -37,7 +37,7 @@ async def tcp_server(): print("server running") multitest.next() async with server: - await asyncio.wait_for(ev.wait(), 2) + await asyncio.wait_for(ev.wait(), 10) async def tcp_client(): diff --git a/tests/multi_net/asyncio_tcp_readexactly.py b/tests/multi_net/asyncio_tcp_readexactly.py index 2c8df1f30a..4024e23fed 100644 --- a/tests/multi_net/asyncio_tcp_readexactly.py +++ b/tests/multi_net/asyncio_tcp_readexactly.py @@ -14,7 +14,7 @@ async def handle_connection(reader, writer): await writer.drain() # Split the first 2 bytes up so the client must wait for the second one - await asyncio.sleep(0.1) + await asyncio.sleep(1) writer.write(b"b") await writer.drain()