diff --git a/docs/conf.py b/docs/conf.py index dd6cc31fb..53cbf9bae 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,7 @@ copyright = '2014-2021, Damien P. George, Paul Sokolovsky, and contributors' # # We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags" # breakdown, so use the same version identifier for both to avoid confusion. -version = release = '1.14' +version = release = '1.15' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index 2db1f65f2..346b3e031 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -18,7 +18,11 @@ If however you're targeting obscure or proprietary systems it may make more sense to keep this external to the main MicroPython repository. This chapter describes how to compile such external modules into the -MicroPython executable or firmware image. +MicroPython executable or firmware image. Both Make and CMake build +tools are supported, and when writing an external module it's a good idea to +add the build files for both of these tools so the module can be used on all +ports. But when compiling a particular port you will only need to use one +method of building, either Make or CMake. An alternative approach is to use :ref:`natmod` which allows writing custom C code that is placed in a .mpy file, which can be imported dynamically in to @@ -53,6 +57,30 @@ A MicroPython user C module is a directory with the following files: for header files), these should be added to ``CFLAGS_USERMOD`` for C code and to ``CXXFLAGS_USERMOD`` for C++ code. +* ``micropython.cmake`` contains the CMake configuration for this module. + + In ``micropython.cmake``, you may use ``${CMAKE_CURRENT_LIST_DIR}`` as the path to + the current module. + + Your ``micropython.cmake`` should define an ``INTERFACE`` library and associate + your source files, compile definitions and include directories with it. + The library should then be linked to the ``usermod`` target. + + .. code-block:: cmake + + add_library(usermod_cexample INTERFACE) + + target_sources(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c + ) + + target_include_directories(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ) + + target_link_libraries(usermod INTERFACE usermod_cexample) + + See below for full usage example. @@ -70,9 +98,11 @@ and has a source file and a Makefile fragment with content as descibed above:: └──usercmodule/ └──cexample/ ├── examplemodule.c - └── micropython.mk + ├── micropython.mk + └── micropython.cmake -Refer to the comments in these 2 files for additional explanation. + +Refer to the comments in these files for additional explanation. Next to the ``cexample`` module there's also ``cppexample`` which works in the same way but shows one way of mixing C and C++ code in MicroPython. @@ -85,78 +115,140 @@ To build such a module, compile MicroPython (see `getting started `_), applying 2 modifications: -- an extra ``make`` flag named ``USER_C_MODULES`` set to the directory - containing all modules you want included (not to the module itself). - For building the example modules which come with MicroPython, - set ``USER_C_MODULES`` to the ``examples/usercmodule`` directory. - For your own projects it's more convenient to keep custom code out of - the main source tree so a typical project directory structure will look - like this:: +1. Set the build-time flag ``USER_C_MODULES`` to point to the modules + you want to include. For ports that use Make this variable should be a + directory which is searched automatically for modules. For ports that + use CMake this variable should be a file which includes the modules to + build. See below for details. - my_project/ - ├── modules/ - │ └──example1/ - │ ├──example1.c - │ └──micropython.mk - │ └──example2/ - │ ├──example2.c - │ └──micropython.mk - └── micropython/ - ├──ports/ - ... ├──stm32/ - ... +2. Enable the modules by setting the corresponding C preprocessor macro to + 1. This is only needed if the modules you are building are not + automatically enabled. +For building the example modules which come with MicroPython, +set ``USER_C_MODULES`` to the ``examples/usercmodule`` directory for Make, +or to ``examples/usercmodule/micropython.cmake`` for CMake. - with ``USER_C_MODULES`` set to the ``my_project/modules`` directory. - -- all modules found in this directory will be compiled, but only those - which are explicitly enabled will be availabe for importing. Enabling a - module is done by setting the preprocessor define from its module - registration to 1. For example if the source code defines the module with - - .. code-block:: c - - MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED); - - - then ``MODULE_CEXAMPLE_ENABLED`` has to be set to 1 to make the module available. - This can be done by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1`` to - the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h`` - to add - - .. code-block:: c - - #define MODULE_CEXAMPLE_ENABLED (1) - - - Note that the exact method depends on the port as they have different - structures. If not done correctly it will compile but importing will - fail to find the module. - -To sum up, here's how the ``cexample`` module from the ``examples/usercmodule`` -directory can be built for the unix port: +For example, here's how the to build the unix port with the example modules: .. code-block:: bash cd micropython/ports/unix - make USER_C_MODULES=../../examples/usercmodule CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1 all + make USER_C_MODULES=../../examples/usercmodule -The build output will show the modules found:: +You may need to run ``make clean`` once at the start when including new +user modules in the build. The build output will show the modules found:: ... Including User C Module from ../../examples/usercmodule/cexample Including User C Module from ../../examples/usercmodule/cppexample ... +For a CMake-based port such as rp2, this will look a little different (note +that CMake is actually invoked by ``make``): -Or for your own project with a directory structure as shown above, -including both modules and building the stm32 port for example: +.. code-block:: bash + + cd micropython/ports/rp2 + make USER_C_MODULES=../../examples/usercmodule/micropython.cmake + +Again, you may need to run ``make clean`` first for CMake to pick up the +user modules. The CMake build output lists the modules by name:: + + ... + Including User C Module(s) from ../../examples/usercmodule/micropython.cmake + Found User C Module(s): usermod_cexample, usermod_cppexample + ... + +The contents of the top-level ``micropython.cmake`` can be used to control which +modules are enabled. + +For your own projects it's more convenient to keep custom code out of the main +MicroPython source tree, so a typical project directory structure will look +like this:: + + my_project/ + ├── modules/ + │ ├── example1/ + │ │ ├── example1.c + │ │ ├── micropython.mk + │ │ └── micropython.cmake + │ ├── example2/ + │ │ ├── example2.c + │ │ ├── micropython.mk + │ │ └── micropython.cmake + │ └── micropython.cmake + └── micropython/ + ├──ports/ + ... ├──stm32/ + ... + +When building with Make set ``USER_C_MODULES`` to the ``my_project/modules`` +directory. For example, building the stm32 port: .. code-block:: bash cd my_project/micropython/ports/stm32 - make USER_C_MODULES=../../../modules \ - CFLAGS_EXTRA="-DMODULE_EXAMPLE1_ENABLED=1 -DMODULE_EXAMPLE2_ENABLED=1" all + make USER_C_MODULES=../../../modules + +When building with CMake the top level ``micropython.cmake`` -- found directly +in the ``my_project/modules`` directory -- should ``include`` all of the modules +you want to have available: + + .. code-block:: cmake + + include(${CMAKE_CURRENT_LIST_DIR}/example1/micropython.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/example2/micropython.cmake) + +Then build with: + +.. code-block:: bash + + cd my_project/micropython/ports/esp32 + make USER_C_MODULES=../../../../modules/micropython.cmake + +Note that the esp32 port needs the extra ``..`` for relative paths due to the +location of its main ``CMakeLists.txt`` file. You can also specify absolute +paths to ``USER_C_MODULES``. + +All modules specified by the ``USER_C_MODULES`` variable (either found in this +directory when using Make, or added via ``include`` when using CMake) will be +compiled, but only those which are enabled will be available for importing. +User modules are usually enabled by default (this is decided by the developer +of the module), in which case there is nothing more to do than set ``USER_C_MODULES`` +as described above. + +If a module is not enabled by default then the corresponding C preprocessor macro +must be enabled. This macro name can be found by searching for the ``MP_REGISTER_MODULE`` +line in the module's source code (it usually appears at the end of the main source file). +The third argument to ``MP_REGISTER_MODULE`` is the macro name, and this must be set +to 1 using ``CFLAGS_EXTRA`` to make the module available. If the third argument is just +the number 1 then the module is enabled by default. + +For example, the ``examples/usercmodule/cexample`` module is enabled by default so +has the following line in its source code: + + .. code-block:: c + + MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1); + +Alternatively, to make this module disabled by default but selectable through +a preprocessor configuration option, it would be: + + .. code-block:: c + + MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED); + +In this case the module is enabled by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1`` +to the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h`` to add + + .. code-block:: c + + #define MODULE_CEXAMPLE_ENABLED (1) + +Note that the exact method depends on the port as they have different +structures. If not done correctly it will compile but importing will +fail to find the module. Module usage in MicroPython diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib index 0e388332e..00def493d 100644 --- a/examples/embedding/Makefile.upylib +++ b/examples/embedding/Makefile.upylib @@ -21,6 +21,9 @@ CWARN = -Wall -Werror CWARN += -Wpointer-arith -Wuninitialized CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) +# Some systems (eg MacOS) need -fno-common so that mp_state_ctx is placed in the BSS. +CFLAGS += -fno-common + # Debugging/Optimization ifdef DEBUG CFLAGS += -g @@ -133,7 +136,6 @@ SRC_C = $(addprefix ports/unix/,\ gccollect.c \ unix_mphal.c \ input.c \ - file.c \ modmachine.c \ modos.c \ moduselect.c \ @@ -146,6 +148,7 @@ SRC_C = $(addprefix ports/unix/,\ LIB_SRC_C = $(addprefix lib/,\ $(LIB_SRC_C_EXTRA) \ utils/printf.c \ + utils/gchelper_generic.c \ timeutils/timeutils.c \ ) diff --git a/examples/rp2/pio_uart_rx.py b/examples/rp2/pio_uart_rx.py index 41dfde3da..080b6bd63 100644 --- a/examples/rp2/pio_uart_rx.py +++ b/examples/rp2/pio_uart_rx.py @@ -22,6 +22,7 @@ PIO_RX_PIN = Pin(3, Pin.IN, Pin.PULL_UP) autopush=True, push_thresh=8, in_shiftdir=rp2.PIO.SHIFT_RIGHT, + fifo_join=PIO.JOIN_RX, ) def uart_rx_mini(): # fmt: off diff --git a/examples/usercmodule/cexample/examplemodule.c b/examples/usercmodule/cexample/examplemodule.c index f608823c9..49ebc7aaa 100644 --- a/examples/usercmodule/cexample/examplemodule.c +++ b/examples/usercmodule/cexample/examplemodule.c @@ -31,4 +31,7 @@ const mp_obj_module_t example_user_cmodule = { }; // Register the module to make it available in Python. -MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED); +// Note: the "1" in the third argument means this module is always enabled. +// This "1" can be optionally replaced with a macro like MODULE_CEXAMPLE_ENABLED +// which can then be used to conditionally enable this module. +MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1); diff --git a/examples/usercmodule/cexample/micropython.cmake b/examples/usercmodule/cexample/micropython.cmake new file mode 100644 index 000000000..ba076a16b --- /dev/null +++ b/examples/usercmodule/cexample/micropython.cmake @@ -0,0 +1,15 @@ +# Create an INTERFACE library for our C module. +add_library(usermod_cexample INTERFACE) + +# Add our source files to the lib +target_sources(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c +) + +# Add the current directory as an include directory. +target_include_directories(usermod_cexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +# Link our INTERFACE library to the usermod target. +target_link_libraries(usermod INTERFACE usermod_cexample) diff --git a/examples/usercmodule/cppexample/examplemodule.c b/examples/usercmodule/cppexample/examplemodule.c index ceb588bef..dfb785683 100644 --- a/examples/usercmodule/cppexample/examplemodule.c +++ b/examples/usercmodule/cppexample/examplemodule.c @@ -22,4 +22,7 @@ const mp_obj_module_t cppexample_user_cmodule = { }; // Register the module to make it available in Python. -MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule, MODULE_CPPEXAMPLE_ENABLED); +// Note: the "1" in the third argument means this module is always enabled. +// This "1" can be optionally replaced with a macro like MODULE_CPPEXAMPLE_ENABLED +// which can then be used to conditionally enable this module. +MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule, 1); diff --git a/examples/usercmodule/cppexample/micropython.cmake b/examples/usercmodule/cppexample/micropython.cmake new file mode 100644 index 000000000..6da972c94 --- /dev/null +++ b/examples/usercmodule/cppexample/micropython.cmake @@ -0,0 +1,16 @@ +# Create an INTERFACE library for our CPP module. +add_library(usermod_cppexample INTERFACE) + +# Add our source files to the library. +target_sources(usermod_cppexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/example.cpp + ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c +) + +# Add the current directory as an include directory. +target_include_directories(usermod_cppexample INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +# Link our INTERFACE library to the usermod target. +target_link_libraries(usermod INTERFACE usermod_cppexample) diff --git a/examples/usercmodule/micropython.cmake b/examples/usercmodule/micropython.cmake new file mode 100644 index 000000000..ad88d7780 --- /dev/null +++ b/examples/usercmodule/micropython.cmake @@ -0,0 +1,11 @@ +# This top-level micropython.cmake is responsible for listing +# the individual modules we want to include. +# Paths are absolute, and ${CMAKE_CURRENT_LIST_DIR} can be +# used to prefix subdirectories. + +# Add the C example. +include(${CMAKE_CURRENT_LIST_DIR}/cexample/micropython.cmake) + +# Add the CPP example. +include(${CMAKE_CURRENT_LIST_DIR}/cppexample/micropython.cmake) + diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake index 691c3ce9b..a54047519 100644 --- a/extmod/extmod.cmake +++ b/extmod/extmod.cmake @@ -4,6 +4,8 @@ set(MICROPY_EXTMOD_DIR "${MICROPY_DIR}/extmod") set(MICROPY_OOFATFS_DIR "${MICROPY_DIR}/lib/oofatfs") set(MICROPY_SOURCE_EXTMOD + ${MICROPY_DIR}/lib/embed/abort_.c + ${MICROPY_DIR}/lib/utils/printf.c ${MICROPY_EXTMOD_DIR}/machine_i2c.c ${MICROPY_EXTMOD_DIR}/machine_mem.c ${MICROPY_EXTMOD_DIR}/machine_pulse.c @@ -43,3 +45,49 @@ set(MICROPY_SOURCE_EXTMOD ${MICROPY_EXTMOD_DIR}/virtpin.c ${MICROPY_EXTMOD_DIR}/nimble/modbluetooth_nimble.c ) + +# Library for btree module and associated code + +set(MICROPY_LIB_BERKELEY_DIR "${MICROPY_DIR}/lib/berkeley-db-1.xx") + +if(EXISTS "${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c") + 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_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. + + list(APPEND MICROPY_INC_CORE + "${MICROPY_LIB_BERKELEY_DIR}/PORT/include" + ) + + list(APPEND MICROPY_DEF_CORE + __DBINTERFACE_PRIVATE=1 + "virt_fd_t=void*" + ) +endif() diff --git a/extmod/re1.5/compilecode.c b/extmod/re1.5/compilecode.c index c4d12af87..add4f6ac2 100644 --- a/extmod/re1.5/compilecode.c +++ b/extmod/re1.5/compilecode.c @@ -8,11 +8,20 @@ ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num) #define REL(at, to) (to - at - 2) #define EMIT(at, byte) (code ? (code[at] = byte) : (at)) +#define EMIT_CHECKED(at, byte) (_emit_checked(at, code, byte, &err)) #define PC (prog->bytelen) +static void _emit_checked(int at, char *code, int val, bool *err) { + *err |= val != (int8_t)val; + if (code) { + code[at] = val; + } +} + static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) { char *code = sizecode ? NULL : prog->insts; + bool err = false; int start = PC; int term = PC; int alt_label = 0; @@ -64,7 +73,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } EMIT(PC++, *re); } - EMIT(term + 1, cnt); + EMIT_CHECKED(term + 1, cnt); break; } case '(': { @@ -75,7 +84,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) if (capture) { sub = ++prog->sub; EMIT(PC++, Save); - EMIT(PC++, 2 * sub); + EMIT_CHECKED(PC++, 2 * sub); prog->len++; } else { re += 2; @@ -86,7 +95,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) if (capture) { EMIT(PC++, Save); - EMIT(PC++, 2 * sub + 1); + EMIT_CHECKED(PC++, 2 * sub + 1); prog->len++; } @@ -101,7 +110,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } else { EMIT(term, Split); } - EMIT(term + 1, REL(term, PC)); + EMIT_CHECKED(term + 1, REL(term, PC)); prog->len++; term = PC; break; @@ -109,7 +118,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) if (PC == term) return NULL; // nothing to repeat INSERT_CODE(term, 2, PC); EMIT(PC, Jmp); - EMIT(PC + 1, REL(PC, term)); + EMIT_CHECKED(PC + 1, REL(PC, term)); PC += 2; if (re[1] == '?') { EMIT(term, RSplit); @@ -117,7 +126,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } else { EMIT(term, Split); } - EMIT(term + 1, REL(term, PC)); + EMIT_CHECKED(term + 1, REL(term, PC)); prog->len += 2; term = PC; break; @@ -129,20 +138,20 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } else { EMIT(PC, RSplit); } - EMIT(PC + 1, REL(PC, term)); + EMIT_CHECKED(PC + 1, REL(PC, term)); PC += 2; prog->len++; term = PC; break; case '|': if (alt_label) { - EMIT(alt_label, REL(alt_label, PC) + 1); + EMIT_CHECKED(alt_label, REL(alt_label, PC) + 1); } INSERT_CODE(start, 2, PC); EMIT(PC++, Jmp); alt_label = PC++; EMIT(start, Split); - EMIT(start + 1, REL(start, PC)); + EMIT_CHECKED(start + 1, REL(start, PC)); prog->len += 2; term = PC; break; @@ -160,9 +169,9 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) } if (alt_label) { - EMIT(alt_label, REL(alt_label, PC) + 1); + EMIT_CHECKED(alt_label, REL(alt_label, PC) + 1); } - return re; + return err ? NULL : re; } int re1_5_sizecode(const char *re) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 9a3a15d6e..39b740ffa 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -18,7 +18,13 @@ GIT_SUBMODULES = lib/berkeley-db-1.xx .PHONY: all clean deploy erase submodules FORCE -IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) +CMAKE_ARGS = + +ifdef USER_C_MODULES + CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} +endif + +IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) $(CMAKE_ARGS) all: idf.py $(IDFPY_FLAGS) build diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake new file mode 100644 index 000000000..23d52e8b9 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S2/mpconfigboard.cmake @@ -0,0 +1,8 @@ +set(IDF_TARGET esp32s2) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.usb +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) diff --git a/ports/esp32/boards/GENERIC_S2/mpconfigboard.h b/ports/esp32/boards/GENERIC_S2/mpconfigboard.h new file mode 100644 index 000000000..01ac2ce58 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S2/mpconfigboard.h @@ -0,0 +1,5 @@ +#define MICROPY_HW_BOARD_NAME "ESP32S2 module" +#define MICROPY_HW_MCU_NAME "ESP32S2" + +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_HW_ENABLE_SDCARD (0) diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 5870e2df6..52b05a9d3 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -1,7 +1,6 @@ # MicroPython on ESP32, ESP IDF configuration # The following options override the defaults -CONFIG_IDF_TARGET="esp32" CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 # Compiler options: use -Os to reduce size, but keep full assertions diff --git a/ports/esp32/boards/sdkconfig.usb b/ports/esp32/boards/sdkconfig.usb new file mode 100644 index 000000000..657edbc58 --- /dev/null +++ b/ports/esp32/boards/sdkconfig.usb @@ -0,0 +1,4 @@ +CONFIG_USB_ENABLED=y +CONFIG_USB_CDC_ENABLED=y +CONFIG_USB_CDC_RX_BUFSIZE=256 +CONFIG_USB_CDC_TX_BUFSIZE=256 diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c index 50244cdf2..8e4ce9c5a 100644 --- a/ports/esp32/esp32_ulp.c +++ b/ports/esp32/esp32_ulp.c @@ -26,6 +26,8 @@ #include "py/runtime.h" +#if CONFIG_IDF_TARGET_ESP32 + #include "esp32/ulp.h" #include "esp_err.h" @@ -95,3 +97,5 @@ const mp_obj_type_t esp32_ulp_type = { .make_new = esp32_ulp_make_new, .locals_dict = (mp_obj_t)&esp32_ulp_locals_dict, }; + +#endif // CONFIG_IDF_TARGET_ESP32 diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c index 811a208e6..4c19d5992 100644 --- a/ports/esp32/machine_adc.c +++ b/ports/esp32/machine_adc.c @@ -60,7 +60,11 @@ STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n static int initialized = 0; if (!initialized) { - adc1_config_width(ADC_WIDTH_12Bit); + #if CONFIG_IDF_TARGET_ESP32S2 + adc1_config_width(ADC_WIDTH_BIT_13); + #else + adc1_config_width(ADC_WIDTH_BIT_12); + #endif adc_bit_width = 12; initialized = 1; } @@ -128,6 +132,7 @@ STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { mp_raise_ValueError(MP_ERROR_TEXT("parameter error")); } switch (width) { + #if CONFIG_IDF_TARGET_ESP32 case ADC_WIDTH_9Bit: adc_bit_width = 9; break; @@ -140,6 +145,11 @@ STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { case ADC_WIDTH_12Bit: adc_bit_width = 12; break; + #elif CONFIG_IDF_TARGET_ESP32S2 + case ADC_WIDTH_BIT_13: + adc_bit_width = 13; + break; + #endif default: break; } @@ -160,10 +170,14 @@ STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_ATTN_6DB), MP_ROM_INT(ADC_ATTEN_6db) }, { MP_ROM_QSTR(MP_QSTR_ATTN_11DB), MP_ROM_INT(ADC_ATTEN_11db) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_WIDTH_9BIT), MP_ROM_INT(ADC_WIDTH_9Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) }, + #elif CONFIG_IDF_TARGET_ESP32S2 + { MP_ROM_QSTR(MP_QSTR_WIDTH_13BIT), MP_ROM_INT(ADC_WIDTH_BIT_13) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(madc_locals_dict, madc_locals_dict_table); diff --git a/ports/esp32/machine_dac.c b/ports/esp32/machine_dac.c index 02855fcf8..146ef60aa 100644 --- a/ports/esp32/machine_dac.c +++ b/ports/esp32/machine_dac.c @@ -43,8 +43,13 @@ typedef struct _mdac_obj_t { } mdac_obj_t; STATIC const mdac_obj_t mdac_obj[] = { + #if CONFIG_IDF_TARGET_ESP32 {{&machine_dac_type}, GPIO_NUM_25, DAC_CHANNEL_1}, {{&machine_dac_type}, GPIO_NUM_26, DAC_CHANNEL_2}, + #else + {{&machine_dac_type}, GPIO_NUM_17, DAC_CHANNEL_1}, + {{&machine_dac_type}, GPIO_NUM_18, DAC_CHANNEL_2}, + #endif }; STATIC mp_obj_t mdac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index d59f2c750..a49a58035 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -184,8 +184,12 @@ STATIC void machine_hw_spi_init_internal( changed = true; } - if (self->host != HSPI_HOST && self->host != VSPI_HOST) { - mp_raise_ValueError(MP_ERROR_TEXT("SPI ID must be either HSPI(1) or VSPI(2)")); + if (self->host != HSPI_HOST + #ifdef VSPI_HOST + && self->host != VSPI_HOST + #endif + ) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), self->host); } if (changed) { @@ -220,8 +224,10 @@ STATIC void machine_hw_spi_init_internal( int dma_chan = 0; if (self->host == HSPI_HOST) { dma_chan = 1; + #ifdef VSPI_HOST } else if (self->host == VSPI_HOST) { dma_chan = 2; + #endif } ret = spi_bus_initialize(self->host, &buscfg, dma_chan); diff --git a/ports/esp32/machine_i2c.c b/ports/esp32/machine_i2c.c index 3993c7b52..fd5180b8d 100644 --- a/ports/esp32/machine_i2c.c +++ b/ports/esp32/machine_i2c.c @@ -34,8 +34,13 @@ #define I2C_0_DEFAULT_SCL (GPIO_NUM_18) #define I2C_0_DEFAULT_SDA (GPIO_NUM_19) +#if CONFIG_IDF_TARGET_ESP32 #define I2C_1_DEFAULT_SCL (GPIO_NUM_25) #define I2C_1_DEFAULT_SDA (GPIO_NUM_26) +#else +#define I2C_1_DEFAULT_SCL (GPIO_NUM_9) +#define I2C_1_DEFAULT_SDA (GPIO_NUM_8) +#endif #define I2C_DEFAULT_TIMEOUT_US (10000) // 10ms diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index dcdd53be9..8dbdd1984 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -30,6 +30,7 @@ #include #include "driver/gpio.h" +#include "driver/rtc_io.h" #include "py/runtime.h" #include "py/mphal.h" @@ -77,10 +78,17 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = { {{&machine_pin_type}, GPIO_NUM_19}, {{NULL}, -1}, {{&machine_pin_type}, GPIO_NUM_21}, + #if CONFIG_IDF_TARGET_ESP32 {{&machine_pin_type}, GPIO_NUM_22}, {{&machine_pin_type}, GPIO_NUM_23}, {{NULL}, -1}, {{&machine_pin_type}, GPIO_NUM_25}, + #else + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + #endif {{&machine_pin_type}, GPIO_NUM_26}, {{&machine_pin_type}, GPIO_NUM_27}, {{NULL}, -1}, @@ -150,9 +158,11 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - // reset the pin first if this is a mode-setting init (grab it back from ADC) + // reset the pin to digital if this is a mode-setting init (grab it back from ADC) if (args[ARG_mode].u_obj != mp_const_none) { - gpio_reset_pin(self->id); + if (rtc_gpio_is_valid_gpio(self->id)) { + rtc_gpio_deinit(self->id); + } } // configure the pin for gpio @@ -411,10 +421,17 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { {{&machine_pin_irq_type}, GPIO_NUM_19}, {{NULL}, -1}, {{&machine_pin_irq_type}, GPIO_NUM_21}, + #if CONFIG_IDF_TARGET_ESP32 {{&machine_pin_irq_type}, GPIO_NUM_22}, {{&machine_pin_irq_type}, GPIO_NUM_23}, {{NULL}, -1}, {{&machine_pin_irq_type}, GPIO_NUM_25}, + #else + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + #endif {{&machine_pin_irq_type}, GPIO_NUM_26}, {{&machine_pin_irq_type}, GPIO_NUM_27}, {{NULL}, -1}, diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 7592f243b..a7d7d29df 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -50,7 +50,11 @@ STATIC int chan_gpio[LEDC_CHANNEL_MAX]; // 5khz #define PWFREQ (5000) // High speed mode +#if CONFIG_IDF_TARGET_ESP32 #define PWMODE (LEDC_HIGH_SPEED_MODE) +#else +#define PWMODE (LEDC_LOW_SPEED_MODE) +#endif // 10-bit resolution (compatible with esp8266 PWM) #define PWRES (LEDC_TIMER_10_BIT) // Timer 1 diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 40686508a..c9a9face7 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -31,6 +31,8 @@ #include "py/mperrno.h" #include "extmod/vfs_fat.h" +#if MICROPY_HW_ENABLE_SDCARD + #include "driver/sdmmc_host.h" #include "driver/sdspi_host.h" #include "sdmmc_cmd.h" @@ -50,10 +52,6 @@ // Hosts are de-inited in __del__. Slots do not need de-initing. // -// Currently the ESP32 Library doesn't support MMC cards, so -// we don't enable on MICROPY_HW_ENABLE_MMCARD. -#if MICROPY_HW_ENABLE_SDCARD - // Forward declaration const mp_obj_type_t machine_sdcard_type; diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index 6e5824094..696127af7 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -30,12 +30,17 @@ #include #include -#include "driver/timer.h" #include "py/obj.h" #include "py/runtime.h" #include "modmachine.h" #include "mphalport.h" +#include "driver/timer.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 1) +#include "hal/timer_ll.h" +#define HAVE_TIMER_LL (1) +#endif + #define TIMER_INTR_SEL TIMER_INTR_LEVEL #define TIMER_DIVIDER 8 @@ -127,6 +132,18 @@ STATIC void machine_timer_isr(void *self_in) { machine_timer_obj_t *self = self_in; timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0); + #if HAVE_TIMER_LL + + #if CONFIG_IDF_TARGET_ESP32 + device->hw_timer[self->index].update = 1; + #else + device->hw_timer[self->index].update.update = 1; + #endif + timer_ll_clear_intr_status(device, self->index); + timer_ll_set_alarm_enable(device, self->index, self->repeat); + + #else + device->hw_timer[self->index].update = 1; if (self->index) { device->int_clr_timers.t1 = 1; @@ -135,6 +152,8 @@ STATIC void machine_timer_isr(void *self_in) { } device->hw_timer[self->index].config.alarm_en = self->repeat; + #endif + mp_sched_schedule(self->callback, self); mp_hal_wake_main_task_from_isr(); } diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index 44efac375..335157b15 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -24,18 +24,15 @@ * THE SOFTWARE. */ - -#include - -#include "esp_log.h" - -#include "driver/gpio.h" -#include "driver/touch_pad.h" - #include "py/runtime.h" #include "py/mphal.h" #include "modmachine.h" +#if CONFIG_IDF_TARGET_ESP32 + +#include "driver/gpio.h" +#include "driver/touch_pad.h" + typedef struct _mtp_obj_t { mp_obj_base_t base; gpio_num_t gpio_id; @@ -120,3 +117,5 @@ const mp_obj_type_t machine_touchpad_type = { .make_new = mtp_make_new, .locals_dict = (mp_obj_t)&mtp_locals_dict, }; + +#endif // CONFIG_IDF_TARGET_ESP32 diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index 7fce83f2c..e256b9be4 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -307,10 +307,12 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, self->rx = 9; self->tx = 10; break; + #if SOC_UART_NUM > 2 case UART_NUM_2: self->rx = 16; self->tx = 17; break; + #endif } // Remove any existing configuration diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 7a3ec4dde..b0c8a30bf 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -37,7 +37,12 @@ #include "esp_task.h" #include "soc/cpu.h" #include "esp_log.h" + +#if CONFIG_IDF_TARGET_ESP32 #include "esp32/spiram.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/spiram.h" +#endif #include "py/stackctrl.h" #include "py/nlr.h" @@ -50,6 +55,7 @@ #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "uart.h" +#include "usb.h" #include "modmachine.h" #include "modnetwork.h" #include "mpthreadport.h" @@ -72,7 +78,11 @@ 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_ENABLED + usb_init(); + #else uart_init(); + #endif machine_init(); // TODO: CONFIG_SPIRAM_SUPPORT is for 3.3 compatibility, remove after move to 4.0. diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 6c5f5e60f..fe616c878 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -3,7 +3,11 @@ get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE) # Include core source components. include(${MICROPY_DIR}/py/py.cmake) -include(${MICROPY_DIR}/extmod/extmod.cmake) + +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + include(${MICROPY_DIR}/py/usermod.cmake) + include(${MICROPY_DIR}/extmod/extmod.cmake) +endif() set(MICROPY_QSTRDEFS_PORT ${PROJECT_DIR}/qstrdefsport.h @@ -21,7 +25,6 @@ set(MICROPY_SOURCE_LIB ${MICROPY_DIR}/lib/oofatfs/ffunicode.c ${MICROPY_DIR}/lib/timeutils/timeutils.c ${MICROPY_DIR}/lib/utils/interrupt_char.c - ${MICROPY_DIR}/lib/utils/stdout_helpers.c ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c ${MICROPY_DIR}/lib/utils/pyexec.c ) @@ -34,6 +37,7 @@ set(MICROPY_SOURCE_DRIVERS set(MICROPY_SOURCE_PORT ${PROJECT_DIR}/main.c ${PROJECT_DIR}/uart.c + ${PROJECT_DIR}/usb.c ${PROJECT_DIR}/gccollect.c ${PROJECT_DIR}/mphalport.c ${PROJECT_DIR}/fatfs_port.c @@ -74,6 +78,7 @@ include(${MICROPY_DIR}/lib/lv_bindings/mkrules.cmake) set(MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_PY} ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_USERMOD} ${MICROPY_SOURCE_LIB} ${MICROPY_SOURCE_PORT} ${LV_SRC} @@ -84,7 +89,6 @@ set(IDF_COMPONENTS bootloader_support bt driver - esp32 esp_common esp_eth esp_event @@ -126,6 +130,13 @@ if(IDF_VERSION_MINOR GREATER_EQUAL 3) list(APPEND IDF_COMPONENTS hal) endif() +if(IDF_TARGET STREQUAL "esp32") + list(APPEND IDF_COMPONENTS esp32) +elseif(IDF_TARGET STREQUAL "esp32s2") + list(APPEND IDF_COMPONENTS esp32s2) + list(APPEND IDF_COMPONENTS tinyusb) +endif() + # Register the main IDF component. idf_component_register( SRCS @@ -136,7 +147,8 @@ idf_component_register( ${MICROPY_SOURCE_PORT} ${LV_SRC} INCLUDE_DIRS - ${MICROPY_DIR} + ${MICROPY_INC_CORE} + ${MICROPY_INC_USERMOD} ${MICROPY_PORT_DIR} ${MICROPY_BOARD_DIR} ${CMAKE_BINARY_DIR} @@ -153,6 +165,7 @@ set(MICROPY_CROSS_FLAGS -march=xtensawin) # Set compile options for this port. target_compile_definitions(${MICROPY_TARGET} PUBLIC + ${MICROPY_DEF_CORE} MICROPY_ESP_IDF_4=1 MICROPY_VFS_FAT=1 MICROPY_VFS_LFS2=1 @@ -169,24 +182,14 @@ target_compile_options(${MICROPY_TARGET} PUBLIC -Wno-missing-field-initializers ) +# Add additional extmod and usermod components. +target_link_libraries(${MICROPY_TARGET} micropy_extmod_btree) +target_link_libraries(${MICROPY_TARGET} usermod) + + # Collect all of the include directories and compile definitions for the IDF components. foreach(comp ${IDF_COMPONENTS}) - get_target_property(type __idf_${comp} TYPE) - set(_inc OFF) - set(_def OFF) - if(${type} STREQUAL STATIC_LIBRARY) - get_target_property(_inc __idf_${comp} INCLUDE_DIRECTORIES) - get_target_property(_def __idf_${comp} COMPILE_DEFINITIONS) - elseif(${type} STREQUAL INTERFACE_LIBRARY) - get_target_property(_inc __idf_${comp} INTERFACE_INCLUDE_DIRECTORIES) - get_target_property(_def __idf_${comp} INTERFACE_COMPILE_DEFINITIONS) - endif() - if(_inc) - list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) - endif() - if(_def) - list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) - endif() + micropy_gather_target_properties(__idf_${comp}) endforeach() if(IDF_VERSION_MINOR GREATER_EQUAL 2) @@ -194,6 +197,10 @@ if(IDF_VERSION_MINOR GREATER_EQUAL 2) # so add them explicitly. list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/${IDF_TARGET}/include) list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/include) + if(IDF_VERSION_MINOR GREATER_EQUAL 3) + list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/additions/include) + list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/tinyusb/src) + endif() endif() # Include the main MicroPython cmake rules. diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 53ca7fdc6..3ed534338 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -132,6 +132,8 @@ STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_m } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1); +#if CONFIG_IDF_TARGET_ESP32 + STATIC mp_obj_t esp32_raw_temperature(void) { SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 10, SENS_TSENS_CLK_DIV_S); @@ -154,6 +156,8 @@ STATIC mp_obj_t esp32_hall_sensor(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_hall_sensor_obj, esp32_hall_sensor); +#endif + STATIC mp_obj_t esp32_idf_heap_info(const mp_obj_t cap_in) { mp_int_t cap = mp_obj_get_int(cap_in); multi_heap_info_t info; @@ -182,14 +186,18 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_wake_on_touch), MP_ROM_PTR(&esp32_wake_on_touch_obj) }, { MP_ROM_QSTR(MP_QSTR_wake_on_ext0), MP_ROM_PTR(&esp32_wake_on_ext0_obj) }, { MP_ROM_QSTR(MP_QSTR_wake_on_ext1), MP_ROM_PTR(&esp32_wake_on_ext1_obj) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) }, { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_idf_heap_info), MP_ROM_PTR(&esp32_idf_heap_info_obj) }, { MP_ROM_QSTR(MP_QSTR_NVS), MP_ROM_PTR(&esp32_nvs_type) }, { MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) }, { MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_FALSE }, { MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_TRUE }, diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 3925bcb64..2eb5cd2fe 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -32,12 +32,18 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp32/rom/rtc.h" -#include "esp32/clk.h" #include "esp_sleep.h" #include "esp_pm.h" #include "driver/touch_pad.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/rtc.h" +#include "esp32/clk.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#include "esp32s2/clk.h" +#endif + #include "py/obj.h" #include "py/runtime.h" #include "lib/utils/pyexec.h" @@ -71,7 +77,11 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (freq != 20 && freq != 40 && freq != 80 && freq != 160 && freq != 240) { mp_raise_ValueError(MP_ERROR_TEXT("frequency must be 20MHz, 40MHz, 80Mhz, 160MHz or 240MHz")); } + #if CONFIG_IDF_TARGET_ESP32 esp_pm_config_esp32_t pm; + #elif CONFIG_IDF_TARGET_ESP32S2 + esp_pm_config_esp32s2_t pm; + #endif pm.max_freq_mhz = freq; pm.min_freq_mhz = freq; pm.light_sleep_enable = false; @@ -260,7 +270,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + #if CONFIG_IDF_TARGET_ESP32 { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_hw_i2c_type) }, diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 5135e3163..67b1d7d6f 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -59,13 +59,19 @@ #define MDNS_QUERY_TIMEOUT_MS (5000) #define MDNS_LOCAL_SUFFIX ".local" +enum { + SOCKET_STATE_NEW, + SOCKET_STATE_CONNECTED, + SOCKET_STATE_PEER_CLOSED, +}; + typedef struct _socket_obj_t { mp_obj_base_t base; int fd; uint8_t domain; uint8_t type; uint8_t proto; - bool peer_closed; + uint8_t state; unsigned int retries; #if MICROPY_PY_USOCKET_EVENTS mp_obj_t events_callback; @@ -254,7 +260,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz sock->domain = AF_INET; sock->type = SOCK_STREAM; sock->proto = 0; - sock->peer_closed = false; if (n_args > 0) { sock->domain = mp_obj_get_int(args[0]); if (n_args > 1) { @@ -265,6 +270,8 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, siz } } + sock->state = sock->type == SOCK_STREAM ? SOCKET_STATE_NEW : SOCKET_STATE_CONNECTED; + sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); if (sock->fd < 0) { mp_raise_OSError(errno); @@ -278,6 +285,7 @@ STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) { socket_obj_t *self = MP_OBJ_TO_PTR(arg0); struct addrinfo *res; _socket_getaddrinfo(arg1, &res); + self->state = SOCKET_STATE_CONNECTED; int r = lwip_bind(self->fd, res->ai_addr, res->ai_addrlen); lwip_freeaddrinfo(res); if (r < 0) { @@ -290,6 +298,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) { socket_obj_t *self = MP_OBJ_TO_PTR(arg0); int backlog = mp_obj_get_int(arg1); + self->state = SOCKET_STATE_CONNECTED; int r = lwip_listen(self->fd, backlog); if (r < 0) { mp_raise_OSError(errno); @@ -332,7 +341,7 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { sock->domain = self->domain; sock->type = self->type; sock->proto = self->proto; - sock->peer_closed = false; + sock->state = SOCKET_STATE_CONNECTED; _socket_settimeout(sock, UINT64_MAX); // make the return value @@ -351,6 +360,7 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) { struct addrinfo *res; _socket_getaddrinfo(arg1, &res); MP_THREAD_GIL_EXIT(); + self->state = SOCKET_STATE_CONNECTED; int r = lwip_connect(self->fd, res->ai_addr, res->ai_addrlen); MP_THREAD_GIL_ENTER(); lwip_freeaddrinfo(res); @@ -471,11 +481,17 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, struct sockaddr *from, socklen_t *from_len, int *errcode) { socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); + // A new socket cannot be read from. + if (sock->state == SOCKET_STATE_NEW) { + *errcode = MP_ENOTCONN; + return MP_STREAM_ERROR; + } + // If the peer closed the connection then the lwIP socket API will only return "0" once // from lwip_recvfrom and then block on subsequent calls. To emulate POSIX behaviour, // which continues to return "0" for each call on a closed socket, we set a flag when // the peer closed the socket. - if (sock->peer_closed) { + if (sock->state == SOCKET_STATE_PEER_CLOSED) { return 0; } @@ -500,7 +516,7 @@ STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, MP_THREAD_GIL_ENTER(); } if (r == 0) { - sock->peer_closed = true; + sock->state = SOCKET_STATE_PEER_CLOSED; } if (r >= 0) { return r; @@ -702,6 +718,12 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt if (FD_ISSET(socket->fd, &efds)) { ret |= MP_STREAM_POLL_HUP; } + + // New (unconnected) sockets are writable and have HUP set. + if (socket->state == SOCKET_STATE_NEW) { + ret |= (arg & MP_STREAM_POLL_WR) | MP_STREAM_POLL_HUP; + } + return ret; } else if (request == MP_STREAM_CLOSE) { if (socket->fd >= 0) { diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 759770605..716ceca25 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -153,7 +153,9 @@ #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) +#ifndef MICROPY_HW_ENABLE_SDCARD #define MICROPY_HW_ENABLE_SDCARD (1) +#endif #define MICROPY_HW_SOFTSPI_MIN_DELAY (0) #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly #define MICROPY_PY_USSL (1) @@ -162,6 +164,7 @@ #define MICROPY_PY_UWEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_BTREE (1) #define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1) #define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32") diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 65fa88e4d..cf668216d 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -43,10 +43,11 @@ #include "lib/timeutils/timeutils.h" #include "lib/utils/pyexec.h" #include "mphalport.h" +#include "usb.h" TaskHandle_t mp_main_task_handle; -STATIC uint8_t stdin_ringbuf_array[256]; +STATIC uint8_t stdin_ringbuf_array[260]; ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; // Check the ESP-IDF error code and raise an OSError if it's not ESP_OK. @@ -110,9 +111,13 @@ void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { if (release_gil) { MP_THREAD_GIL_EXIT(); } + #if CONFIG_USB_ENABLED + usb_tx_strn(str, len); + #else for (uint32_t i = 0; i < len; ++i) { uart_tx_one_char(str[i]); } + #endif if (release_gil) { MP_THREAD_GIL_ENTER(); } diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c index c837c8dcf..bd3eea9f6 100644 --- a/ports/esp32/uart.c +++ b/ports/esp32/uart.c @@ -49,7 +49,11 @@ STATIC void IRAM_ATTR uart_irq_handler(void *arg) { uart->int_clr.frm_err = 1; uart->int_clr.rxfifo_tout = 1; while (uart->status.rxfifo_cnt) { + #if CONFIG_IDF_TARGET_ESP32 uint8_t c = uart->fifo.rw_byte; + #elif CONFIG_IDF_TARGET_ESP32S2 + uint8_t c = READ_PERI_REG(UART_FIFO_AHB_REG(0)); // UART0 + #endif if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } else { diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c new file mode 100644 index 000000000..aa76321a7 --- /dev/null +++ b/ports/esp32/usb.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 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. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "usb.h" + +#if CONFIG_USB_ENABLED + +#include "tinyusb.h" +#include "tusb_cdc_acm.h" + +#define CDC_ITF TINYUSB_CDC_ACM_0 + +static uint8_t usb_rx_buf[CONFIG_USB_CDC_RX_BUFSIZE]; + +static void usb_callback_rx(int itf, cdcacm_event_t *event) { + // TODO: what happens if more chars come in during this function, are they lost? + for (;;) { + size_t len = 0; + esp_err_t ret = tinyusb_cdcacm_read(itf, usb_rx_buf, sizeof(usb_rx_buf), &len); + if (ret != ESP_OK) { + break; + } + if (len == 0) { + break; + } + for (size_t i = 0; i < len; ++i) { + if (usb_rx_buf[i] == mp_interrupt_char) { + mp_keyboard_interrupt(); + } else { + ringbuf_put(&stdin_ringbuf, usb_rx_buf[i]); + } + } + } +} + +void usb_init(void) { + // Initialise the USB with defaults. + tinyusb_config_t tusb_cfg = {0}; + ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); + + // Initialise the USB serial interface. + tinyusb_config_cdcacm_t amc_cfg = { + .usb_dev = TINYUSB_USBDEV_0, + .cdc_port = CDC_ITF, + .rx_unread_buf_sz = 256, + .callback_rx = &usb_callback_rx, + .callback_rx_wanted_char = NULL, + .callback_line_state_changed = NULL, + .callback_line_coding_changed = NULL + }; + ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg)); +} + +void usb_tx_strn(const char *str, size_t len) { + while (len) { + size_t l = len; + if (l > CONFIG_USB_CDC_TX_BUFSIZE) { + l = CONFIG_USB_CDC_TX_BUFSIZE; + } + tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, l); + tinyusb_cdcacm_write_flush(CDC_ITF, pdMS_TO_TICKS(1000)); + str += l; + len -= l; + } +} + +#endif // CONFIG_USB_ENABLED diff --git a/ports/esp32/usb.h b/ports/esp32/usb.h new file mode 100644 index 000000000..a10378033 --- /dev/null +++ b/ports/esp32/usb.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 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_ESP32_USB_H +#define MICROPY_INCLUDED_ESP32_USB_H + +void usb_init(void); +void usb_tx_strn(const char *str, size_t len); + +#endif // MICROPY_INCLUDED_ESP32_USB_H diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 68c7a8942..65b91675a 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -46,11 +46,9 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) -#define MICROPY_CPYTHON_COMPAT (0) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) // Control over Python builtins -#define MICROPY_PY_ASYNC_AWAIT (0) #define MICROPY_PY_BUILTINS_STR_COUNT (0) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_SET (1) @@ -63,7 +61,6 @@ #define MICROPY_PY___FILE__ (0) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) -#define MICROPY_PY_ATTRTUPLE (0) #define MICROPY_PY_COLLECTIONS (0) #define MICROPY_PY_SYS_MAXSIZE (1) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 3968194dc..bd3eb7438 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -17,6 +17,30 @@ endif() # Use the local tinyusb instead of the one in pico-sdk set(PICO_TINYUSB_PATH ${MICROPY_DIR}/lib/tinyusb) +# Set the location of this port's directory. +set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR}) + +# Set the board if it's not already set. +if(NOT MICROPY_BOARD) + set(MICROPY_BOARD PICO) +endif() + +# Set the PICO_BOARD if it's not already set. +if(NOT PICO_BOARD) + string(TOLOWER ${MICROPY_BOARD} PICO_BOARD) +endif() + +# Set the board directory and check that it exists. +if(NOT MICROPY_BOARD_DIR) + set(MICROPY_BOARD_DIR ${MICROPY_PORT_DIR}/boards/${MICROPY_BOARD}) +endif() +if(NOT EXISTS ${MICROPY_BOARD_DIR}/mpconfigboard.cmake) + message(FATAL_ERROR "Invalid MICROPY_BOARD specified: ${MICROPY_BOARD}") +endif() + +# Include board config +include(${MICROPY_BOARD_DIR}/mpconfigboard.cmake) + # Include component cmake fragments include(${MICROPY_DIR}/py/py.cmake) include(${MICROPY_DIR}/extmod/extmod.cmake) @@ -27,6 +51,8 @@ project(${MICROPY_TARGET}) pico_sdk_init() +include(${MICROPY_DIR}/py/usermod.cmake) + add_executable(${MICROPY_TARGET}) set(MICROPY_QSTRDEFS_PORT @@ -80,6 +106,7 @@ set(MICROPY_SOURCE_PORT set(MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_PY} ${MICROPY_SOURCE_EXTMOD} + ${MICROPY_SOURCE_USERMOD} ${MICROPY_DIR}/lib/utils/mpirq.c ${MICROPY_DIR}/lib/utils/sys_stdio_mphal.c ${PROJECT_SOURCE_DIR}/machine_adc.c @@ -142,9 +169,13 @@ target_sources(${MICROPY_TARGET} PRIVATE ${MICROPY_SOURCE_PORT} ) +target_link_libraries(${MICROPY_TARGET} usermod) + target_include_directories(${MICROPY_TARGET} PRIVATE + ${MICROPY_INC_CORE} + ${MICROPY_INC_USERMOD} + ${MICROPY_BOARD_DIR} "${PROJECT_SOURCE_DIR}" - "${MICROPY_DIR}" "${CMAKE_BINARY_DIR}" ) @@ -164,6 +195,7 @@ target_compile_definitions(${MICROPY_TARGET} PRIVATE PICO_NO_PROGRAM_VERSION_STRING=1 # do it ourselves in main.c MICROPY_BUILD_TYPE="${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} ${CMAKE_BUILD_TYPE}" PICO_NO_BI_STDIO_UART=1 # we call it UART REPL + PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1 ) target_link_libraries(${MICROPY_TARGET} @@ -186,29 +218,9 @@ add_custom_command(TARGET ${MICROPY_TARGET} ) # Collect all the include directories and compile definitions for the pico-sdk components. -macro(_process_target targ) - if(TARGET ${targ}) - get_target_property(type ${targ} TYPE) - set(_inc OFF) - set(_def OFF) - if(${type} STREQUAL STATIC_LIBRARY) - get_target_property(_inc ${targ} INCLUDE_DIRECTORIES) - get_target_property(_def ${targ} COMPILE_DEFINITIONS) - elseif(${type} STREQUAL INTERFACE_LIBRARY) - get_target_property(_inc ${targ} INTERFACE_INCLUDE_DIRECTORIES) - get_target_property(_def ${targ} INTERFACE_COMPILE_DEFINITIONS) - endif() - if(_inc) - list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) - endif() - if(_def) - list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) - endif() - endif() -endmacro() foreach(comp ${PICO_SDK_COMPONENTS}) - _process_target(${comp}) - _process_target(${comp}_headers) + micropy_gather_target_properties(${comp}) + micropy_gather_target_properties(${comp}_headers) endforeach() # Include the main MicroPython cmake rules. diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile index 08cd53dcc..246f29dd0 100644 --- a/ports/rp2/Makefile +++ b/ports/rp2/Makefile @@ -2,12 +2,20 @@ # # This is a simple wrapper around cmake -BUILD = build +BOARD ?= PICO + +BUILD ?= build-$(BOARD) $(VERBOSE)MAKESILENT = -s +CMAKE_ARGS = -DMICROPY_BOARD=$(BOARD) + +ifdef USER_C_MODULES +CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES} +endif + all: - [ -d $(BUILD) ] || cmake -S . -B $(BUILD) -DPICO_BUILD_DOCS=0 + [ -d $(BUILD) ] || cmake -S . -B $(BUILD) -DPICO_BUILD_DOCS=0 ${CMAKE_ARGS} $(MAKE) $(MAKESILENT) -C $(BUILD) clean: diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.cmake b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.cmake new file mode 100644 index 000000000..877efa6ab --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.cmake @@ -0,0 +1 @@ +# cmake file for Adafruit Feather RP2040 diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h new file mode 100644 index 000000000..5068d3554 --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/mpconfigboard.h @@ -0,0 +1,3 @@ +// Board and hardware specific configuration +#define MICROPY_HW_BOARD_NAME "Adafruit Feather RP2040" +#define MICROPY_HW_FLASH_STORAGE_BYTES (3072 * 1024) diff --git a/ports/rp2/boards/PICO/mpconfigboard.cmake b/ports/rp2/boards/PICO/mpconfigboard.cmake new file mode 100644 index 000000000..3a40ca287 --- /dev/null +++ b/ports/rp2/boards/PICO/mpconfigboard.cmake @@ -0,0 +1 @@ +# cmake file for Raspberry Pi Pico diff --git a/ports/rp2/boards/PICO/mpconfigboard.h b/ports/rp2/boards/PICO/mpconfigboard.h new file mode 100644 index 000000000..e6623374d --- /dev/null +++ b/ports/rp2/boards/PICO/mpconfigboard.h @@ -0,0 +1,3 @@ +// Board and hardware specific configuration +#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico" +#define MICROPY_HW_FLASH_STORAGE_BYTES (1408 * 1024) diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index 936b9a93e..2da3ab41f 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -28,9 +28,12 @@ #include "py/stream.h" #include "py/mphal.h" #include "py/mperrno.h" +#include "py/ringbuf.h" #include "modmachine.h" +#include "hardware/irq.h" #include "hardware/uart.h" +#include "hardware/regs/uart.h" #define DEFAULT_UART_BAUDRATE (115200) #define DEFAULT_UART_BITS (8) @@ -39,6 +42,9 @@ #define DEFAULT_UART0_RX (1) #define DEFAULT_UART1_TX (4) #define DEFAULT_UART1_RX (5) +#define DEFAULT_BUFFER_SIZE (256) +#define MIN_BUFFER_SIZE (32) +#define MAX_BUFFER_SIZE (32766) #define IS_VALID_PERIPH(uart, pin) (((((pin) + 4) & 8) >> 3) == (uart)) #define IS_VALID_TX(uart, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(uart, pin)) @@ -61,28 +67,81 @@ typedef struct _machine_uart_obj_t { uint16_t timeout; // timeout waiting for first char (in ms) uint16_t timeout_char; // timeout waiting between chars (in ms) uint8_t invert; + ringbuf_t read_buffer; + bool read_lock; + ringbuf_t write_buffer; + bool write_lock; } machine_uart_obj_t; STATIC machine_uart_obj_t machine_uart_obj[] = { - {{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART0_TX, DEFAULT_UART0_RX, 0, 0, 0}, - {{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, DEFAULT_UART1_TX, DEFAULT_UART1_RX, 0, 0, 0}, + {{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, + DEFAULT_UART0_TX, DEFAULT_UART0_RX, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0}, + {{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP, + DEFAULT_UART1_TX, DEFAULT_UART1_RX, 0, 0, 0, {NULL, 1, 0, 0}, 0, {NULL, 1, 0, 0}, 0,}, }; STATIC const char *_parity_name[] = {"None", "0", "1"}; STATIC const char *_invert_name[] = {"None", "INV_TX", "INV_RX", "INV_TX|INV_RX"}; +/******************************************************************************/ +// IRQ and buffer handling + +// take all bytes from the fifo and store them, if possible, in the buffer +STATIC void uart_drain_rx_fifo(machine_uart_obj_t *self) { + while (uart_is_readable(self->uart)) { + // try to write the data, ignore the fail + ringbuf_put(&(self->read_buffer), uart_get_hw(self->uart)->dr); + } +} + +// take bytes from the buffer and put them into the UART FIFO +STATIC void uart_fill_tx_fifo(machine_uart_obj_t *self) { + while (uart_is_writable(self->uart) && ringbuf_avail(&self->write_buffer) > 0) { + // get a byte from the buffer and put it into the uart + uart_get_hw(self->uart)->dr = ringbuf_get(&(self->write_buffer)); + } +} + +STATIC inline void uart_service_interrupt(machine_uart_obj_t *self) { + if (uart_get_hw(self->uart)->mis & UART_UARTMIS_RXMIS_BITS) { // rx interrupt? + // clear all interrupt bits but tx + uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & (~UART_UARTICR_TXIC_BITS); + if (!self->read_lock) { + uart_drain_rx_fifo(self); + } + } + if (uart_get_hw(self->uart)->mis & UART_UARTMIS_TXMIS_BITS) { // tx interrupt? + // clear all interrupt bits but rx + uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & (~UART_UARTICR_RXIC_BITS); + if (!self->write_lock) { + uart_fill_tx_fifo(self); + } + } +} + +STATIC void uart0_irq_handler(void) { + uart_service_interrupt(&machine_uart_obj[0]); +} + +STATIC void uart1_irq_handler(void) { + uart_service_interrupt(&machine_uart_obj[1]); +} + /******************************************************************************/ // MicroPython bindings for UART 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, tx=%d, rx=%d, timeout=%u, timeout_char=%u, invert=%s)", + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, " + "txbuf=%d, rxbuf=%d, timeout=%u, timeout_char=%u, invert=%s)", self->uart_id, self->baudrate, self->bits, _parity_name[self->parity], - self->stop, self->tx, self->rx, self->timeout, self->timeout_char, _invert_name[self->invert]); + self->stop, self->tx, self->rx, self->write_buffer.size - 1, self->read_buffer.size - 1, + self->timeout, self->timeout_char, _invert_name[self->invert]); } STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_timeout, ARG_timeout_char, ARG_invert }; + enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, + ARG_timeout, ARG_timeout_char, ARG_invert, ARG_txbuf, ARG_rxbuf}; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, @@ -94,6 +153,8 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, { 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} }, + { MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; // Parse args. @@ -169,6 +230,30 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, self->invert = args[ARG_invert].u_int; } + self->read_lock = false; + + // Set the RX buffer size if configured. + size_t rxbuf_len = DEFAULT_BUFFER_SIZE; + if (args[ARG_rxbuf].u_int > 0) { + rxbuf_len = args[ARG_rxbuf].u_int; + if (rxbuf_len < MIN_BUFFER_SIZE) { + rxbuf_len = MIN_BUFFER_SIZE; + } else if (rxbuf_len > MAX_BUFFER_SIZE) { + mp_raise_ValueError(MP_ERROR_TEXT("rxbuf too large")); + } + } + + // Set the TX buffer size if configured. + size_t txbuf_len = DEFAULT_BUFFER_SIZE; + if (args[ARG_txbuf].u_int > 0) { + txbuf_len = args[ARG_txbuf].u_int; + if (txbuf_len < MIN_BUFFER_SIZE) { + txbuf_len = MIN_BUFFER_SIZE; + } else if (txbuf_len > MAX_BUFFER_SIZE) { + mp_raise_ValueError(MP_ERROR_TEXT("txbuf too large")); + } + } + // Initialise the UART peripheral if any arguments given, or it was not initialised previously. if (n_args > 1 || n_kw > 0 || self->baudrate == 0) { if (self->baudrate == 0) { @@ -192,6 +277,25 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, if (self->invert & UART_INVERT_TX) { gpio_set_outover(self->tx, GPIO_OVERRIDE_INVERT); } + + // Allocate the RX/TX buffers. + ringbuf_alloc(&(self->read_buffer), rxbuf_len + 1); + MP_STATE_PORT(rp2_uart_rx_buffer[uart_id]) = self->read_buffer.buf; + + ringbuf_alloc(&(self->write_buffer), txbuf_len + 1); + MP_STATE_PORT(rp2_uart_tx_buffer[uart_id]) = self->write_buffer.buf; + + // Set the irq handler. + if (self->uart_id == 0) { + irq_set_exclusive_handler(UART0_IRQ, uart0_irq_handler); + irq_set_enabled(UART0_IRQ, true); + } else { + irq_set_exclusive_handler(UART1_IRQ, uart1_irq_handler); + irq_set_enabled(UART1_IRQ, true); + } + + // Enable the uart irq; this macro sets the rx irq level to 4. + uart_set_irq_enables(self->uart, true, true); } return MP_OBJ_FROM_PTR(self); @@ -199,7 +303,11 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(uart_is_readable(self->uart)); + // get all bytes from the fifo first + self->read_lock = true; + uart_drain_rx_fifo(self); + self->read_lock = false; + return MP_OBJ_NEW_SMALL_INT(ringbuf_avail(&self->read_buffer)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any); @@ -236,7 +344,7 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz for (size_t i = 0; i < size; i++) { // Wait for the first/next character - while (!uart_is_readable(self->uart)) { + while (ringbuf_avail(&self->read_buffer) == 0) { if (time_us_64() > t) { // timed out if (i <= 0) { *errcode = MP_EAGAIN; @@ -246,8 +354,12 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz } } MICROPY_EVENT_POLL_HOOK + // Force a few incoming bytes to the buffer + self->read_lock = true; + uart_drain_rx_fifo(self); + self->read_lock = false; } - *dest++ = uart_get_hw(self->uart)->dr; + *dest++ = ringbuf_get(&(self->read_buffer)); t = time_us_64() + timeout_char_us; } return size; @@ -258,10 +370,23 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin uint64_t t = time_us_64() + (uint64_t)self->timeout * 1000; uint64_t timeout_char_us = (uint64_t)self->timeout_char * 1000; const uint8_t *src = buf_in; + size_t i = 0; - for (size_t i = 0; i < size; i++) { - // wait for the first/next character - while (!uart_is_writable(self->uart)) { + // Put as many bytes as possible into the transmit buffer. + while (i < size && ringbuf_free(&(self->write_buffer)) > 0) { + ringbuf_put(&(self->write_buffer), *src++); + ++i; + } + + // Kickstart the UART transmit. + self->write_lock = true; + uart_fill_tx_fifo(self); + self->write_lock = false; + + // Send the next characters while busy waiting. + while (i < size) { + // Wait for the first/next character to be sent. + while (ringbuf_free(&(self->write_buffer)) == 0) { if (time_us_64() > t) { // timed out if (i <= 0) { *errcode = MP_EAGAIN; @@ -272,9 +397,15 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin } MICROPY_EVENT_POLL_HOOK } - uart_get_hw(self->uart)->dr = *src++; + ringbuf_put(&(self->write_buffer), *src++); + ++i; t = time_us_64() + timeout_char_us; + self->write_lock = true; + uart_fill_tx_fifo(self); + self->write_lock = false; } + + // Just in case the fifo was drained during refill of the ringbuf. return size; } @@ -284,10 +415,10 @@ STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint if (request == MP_STREAM_POLL) { uintptr_t flags = arg; ret = 0; - if ((flags & MP_STREAM_POLL_RD) && uart_is_readable(self->uart)) { + if ((flags & MP_STREAM_POLL_RD) && ringbuf_avail(&self->read_buffer) > 0) { ret |= MP_STREAM_POLL_RD; } - if ((flags & MP_STREAM_POLL_WR) && uart_is_writable(self->uart)) { + if ((flags & MP_STREAM_POLL_WR) && ringbuf_free(&self->write_buffer) > 0) { ret |= MP_STREAM_POLL_WR; } } else { diff --git a/ports/rp2/main.c b/ports/rp2/main.c index 64218f97c..8fddeaa56 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -30,6 +30,7 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/mperrno.h" +#include "py/mphal.h" #include "py/stackctrl.h" #include "lib/mp-readline/readline.h" #include "lib/utils/gchelper.h" @@ -168,10 +169,21 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c } #endif +#define POLY (0xD5) + +uint8_t rosc_random_u8(size_t cycles) { + static uint8_t r; + for (size_t i = 0; i < cycles; ++i) { + r = ((r << 1) | rosc_hw->randombit) ^ (r & 0x80 ? POLY : 0); + mp_hal_delay_us_fast(1); + } + return r; +} + uint32_t rosc_random_u32(void) { uint32_t value = 0; - for (size_t i = 0; i < 32; ++i) { - value = value << 1 | rosc_hw->randombit; + for (size_t i = 0; i < 4; ++i) { + value = value << 8 | rosc_random_u8(32); } return value; } diff --git a/ports/rp2/modules/rp2.py b/ports/rp2/modules/rp2.py index a3adcdc51..c7e4d1fdd 100644 --- a/ports/rp2/modules/rp2.py +++ b/ports/rp2/modules/rp2.py @@ -31,14 +31,18 @@ class PIOASMEmit: autopush=False, autopull=False, push_thresh=32, - pull_thresh=32 + pull_thresh=32, + fifo_join=0 ): - from array import array + # uarray is a built-in module so importing it here won't require + # scanning the filesystem. + from uarray import array self.labels = {} execctrl = 0 shiftctrl = ( - (pull_thresh & 0x1F) << 25 + fifo_join << 30 + | (pull_thresh & 0x1F) << 25 | (push_thresh & 0x1F) << 20 | out_shiftdir << 19 | in_shiftdir << 18 diff --git a/ports/rp2/moduos.c b/ports/rp2/moduos.c index 7ee662b5a..02f34eb96 100644 --- a/ports/rp2/moduos.c +++ b/ports/rp2/moduos.c @@ -31,6 +31,8 @@ #include "extmod/vfs_lfs.h" #include "genhdr/mpversion.h" +uint8_t rosc_random_u8(size_t cycles); + STATIC const qstr os_uname_info_fields[] = { MP_QSTR_sysname, MP_QSTR_nodename, MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine @@ -57,10 +59,22 @@ STATIC mp_obj_t os_uname(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + for (int i = 0; i < n; i++) { + vstr.buf[i] = rosc_random_u8(8); + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, #if MICROPY_VFS { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index 13db589ec..218cd7275 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -31,8 +31,9 @@ #include "hardware/sync.h" #include "pico/binary_info.h" +#include "mpconfigboard.h" + // Board and hardware specific configuration -#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico" #define MICROPY_HW_MCU_NAME "RP2040" #define MICROPY_HW_ENABLE_UART_REPL (0) // useful if there is no USB #define MICROPY_HW_ENABLE_USBDEV (1) @@ -174,6 +175,8 @@ extern const struct _mp_obj_module_t mp_module_utime; void *machine_pin_irq_obj[30]; \ void *rp2_pio_irq_obj[2]; \ void *rp2_state_machine_irq_obj[8]; \ + void *rp2_uart_rx_buffer[2]; \ + void *rp2_uart_tx_buffer[2]; \ #define MP_STATE_PORT MP_STATE_VM diff --git a/ports/rp2/mpthreadport.h b/ports/rp2/mpthreadport.h index 4583f6f53..5eb0bff39 100644 --- a/ports/rp2/mpthreadport.h +++ b/ports/rp2/mpthreadport.h @@ -41,7 +41,7 @@ static inline void mp_thread_set_state(struct _mp_state_thread_t *state) { } static inline struct _mp_state_thread_t *mp_thread_get_state(void) { - return core_state[get_core_num()]; + return (struct _mp_state_thread_t *)core_state[get_core_num()]; } static inline void mp_thread_mutex_init(mp_thread_mutex_t *m) { diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 9786e569d..44928c0a8 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -66,6 +66,7 @@ typedef struct _rp2_state_machine_irq_obj_t { } rp2_state_machine_irq_obj_t; STATIC const rp2_state_machine_obj_t rp2_state_machine_obj[8]; +STATIC uint8_t rp2_state_machine_initial_pc[8]; STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); @@ -359,6 +360,10 @@ STATIC const mp_rom_map_elem_t rp2_pio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_SHIFT_LEFT), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_SHIFT_RIGHT), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_JOIN_NONE), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_JOIN_TX), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_JOIN_RX), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_SM0), MP_ROM_INT(0x100) }, { MP_ROM_QSTR(MP_QSTR_IRQ_SM1), MP_ROM_INT(0x200) }, { MP_ROM_QSTR(MP_QSTR_IRQ_SM2), MP_ROM_INT(0x400) }, @@ -459,16 +464,28 @@ STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel if (offset < 0) { rp2_pio_add_program(&rp2_pio_obj[PIO_NUM(self->pio)], args[ARG_prog].u_obj); offset = mp_obj_get_int(prog[PROG_OFFSET_PIO0 + PIO_NUM(self->pio)]); + rp2_state_machine_initial_pc[self->id] = offset; } // Compute the clock divider. - float div; + uint16_t clkdiv_int; + uint8_t clkdiv_frac; if (args[ARG_freq].u_int < 0) { - div = 1; + // Default: run at CPU frequency. + clkdiv_int = 1; + clkdiv_frac = 0; } else if (args[ARG_freq].u_int == 0) { - div = 0; + // Special case of 0: set clkdiv to 0. + clkdiv_int = 0; + clkdiv_frac = 0; } else { - div = (float)clock_get_hz(clk_sys) / (float)args[ARG_freq].u_int; + // Frequency given in Hz, compute clkdiv from it. + uint64_t div = (uint64_t)clock_get_hz(clk_sys) * 256ULL / (uint64_t)args[ARG_freq].u_int; + if (!(div >= 1 * 256 && div <= 65536 * 256)) { + mp_raise_ValueError(MP_ERROR_TEXT("freq out of range")); + } + clkdiv_int = div / 256; + clkdiv_frac = div & 0xff; } // Disable and reset the state machine. @@ -476,7 +493,7 @@ STATIC mp_obj_t rp2_state_machine_init_helper(const rp2_state_machine_obj_t *sel // Build the state machine config. pio_sm_config config = pio_get_default_sm_config(); - sm_config_set_clkdiv(&config, div); + sm_config_set_clkdiv_int_frac(&config, clkdiv_int, clkdiv_frac); config.execctrl = mp_obj_get_int_truncated(prog[PROG_EXECCTRL]); config.shiftctrl = mp_obj_get_int_truncated(prog[PROG_SHIFTCTRL]); @@ -581,6 +598,15 @@ STATIC mp_obj_t rp2_state_machine_active(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_state_machine_active_obj, 1, 2, rp2_state_machine_active); +// StateMachine.restart() +STATIC mp_obj_t rp2_state_machine_restart(mp_obj_t self_in) { + rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); + pio_sm_restart(self->pio, self->sm); + pio_sm_exec(self->pio, self->sm, pio_encode_jmp(rp2_state_machine_initial_pc[self->id])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(rp2_state_machine_restart_obj, rp2_state_machine_restart); + // StateMachine.exec(instr) STATIC mp_obj_t rp2_state_machine_exec(mp_obj_t self_in, mp_obj_t instr_in) { rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -689,6 +715,20 @@ STATIC mp_obj_t rp2_state_machine_put(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_state_machine_put_obj, 2, 3, rp2_state_machine_put); +// StateMachine.rx_fifo() +STATIC mp_obj_t rp2_state_machine_rx_fifo(mp_obj_t self_in) { + rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(pio_sm_get_rx_fifo_level(self->pio, self->sm)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(rp2_state_machine_rx_fifo_obj, rp2_state_machine_rx_fifo); + +// StateMachine.tx_fifo() +STATIC mp_obj_t rp2_state_machine_tx_fifo(mp_obj_t self_in) { + rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(pio_sm_get_tx_fifo_level(self->pio, self->sm)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(rp2_state_machine_tx_fifo_obj, rp2_state_machine_tx_fifo); + // StateMachine.irq(handler=None, trigger=0|1, hard=False) STATIC mp_obj_t rp2_state_machine_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_handler, ARG_trigger, ARG_hard }; @@ -748,9 +788,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(rp2_state_machine_irq_obj, 1, rp2_state_machin STATIC const mp_rom_map_elem_t rp2_state_machine_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&rp2_state_machine_init_obj) }, { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&rp2_state_machine_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&rp2_state_machine_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_exec), MP_ROM_PTR(&rp2_state_machine_exec_obj) }, { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&rp2_state_machine_get_obj) }, { MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&rp2_state_machine_put_obj) }, + { MP_ROM_QSTR(MP_QSTR_rx_fifo), MP_ROM_PTR(&rp2_state_machine_rx_fifo_obj) }, + { MP_ROM_QSTR(MP_QSTR_tx_fifo), MP_ROM_PTR(&rp2_state_machine_tx_fifo_obj) }, { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&rp2_state_machine_irq_obj) }, }; STATIC MP_DEFINE_CONST_DICT(rp2_state_machine_locals_dict, rp2_state_machine_locals_dict_table); diff --git a/ports/rp2/tusb_port.c b/ports/rp2/tusb_port.c index afb566bdb..94856ab45 100644 --- a/ports/rp2/tusb_port.c +++ b/ports/rp2/tusb_port.c @@ -68,7 +68,7 @@ static const tusb_desc_device_t usbd_desc_device = { static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN, - TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA), + 0, USBD_MAX_POWER_MA), TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE), diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index ad7866f5c..e6d039571 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -658,7 +658,7 @@ TEXT0_ADDR ?= 0x08000000 ifeq ($(TEXT1_ADDR),) # No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location -TEXT0_SECTIONS ?= .isr_vector .text .data +TEXT0_SECTIONS ?= .isr_vector .text .data .ARM deploy-stlink: $(BUILD)/firmware.bin $(call RUN_STLINK,$^,$(TEXT0_ADDR)) @@ -676,7 +676,7 @@ else # TEXT0_ADDR and TEXT1_ADDR are specified so split firmware between these locations TEXT0_SECTIONS ?= .isr_vector -TEXT1_SECTIONS ?= .text .data +TEXT1_SECTIONS ?= .text .data .ARM deploy-stlink: $(BUILD)/firmware0.bin $(BUILD)/firmware1.bin $(call RUN_STLINK,$(word 1,$^),$(TEXT0_ADDR)) @@ -765,7 +765,7 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h modmachine.c: $(GEN_PLLFREQTABLE_HDR) $(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD) $(ECHO) "GEN $@" - $(Q)$(PYTHON) $(PLLVALUES) -c -m $(MCU_SERIES) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ + $(Q)$(PYTHON) $(PLLVALUES) -c -m $(CMSIS_MCU_LOWER) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ $(BUILD)/modstm.o: $(GEN_STMCONST_HDR) # Use a pattern rule here so that make will only call make-stmconst.py once to diff --git a/ports/stm32/boardctrl.c b/ports/stm32/boardctrl.c index 188068d70..c82fefa97 100644 --- a/ports/stm32/boardctrl.c +++ b/ports/stm32/boardctrl.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include "py/runtime.h" #include "py/mphal.h" #include "lib/utils/pyexec.h" #include "boardctrl.h" @@ -140,13 +141,21 @@ void boardctrl_top_soft_reset_loop(boardctrl_state_t *state) { led_state(4, 0); } -void boardctrl_before_boot_py(boardctrl_state_t *state) { - state->run_boot_py = state->reset_mode == 1 || state->reset_mode == 3; -} +int boardctrl_run_boot_py(boardctrl_state_t *state) { + bool run_boot_py = state->reset_mode == 1 || state->reset_mode == 3; -void boardctrl_after_boot_py(boardctrl_state_t *state) { - if (state->run_boot_py && !state->last_ret) { - flash_error(4); + if (run_boot_py) { + // Run boot.py, if it exists. + const char *boot_py = "boot.py"; + int ret = pyexec_file_if_exists(boot_py); + + // Take action based on the execution result. + if (ret & PYEXEC_FORCED_EXIT) { + return BOARDCTRL_GOTO_SOFT_RESET_EXIT; + } + if (!ret) { + flash_error(4); + } } // Turn boot-up LEDs off @@ -160,17 +169,34 @@ void boardctrl_after_boot_py(boardctrl_state_t *state) { led_state(2, 0); led_state(3, 0); led_state(4, 0); + + return BOARDCTRL_CONTINUE; } -void boardctrl_before_main_py(boardctrl_state_t *state) { - state->run_main_py = (state->reset_mode == 1 || state->reset_mode == 3) +int boardctrl_run_main_py(boardctrl_state_t *state) { + bool run_main_py = (state->reset_mode == 1 || state->reset_mode == 3) && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL; -} -void boardctrl_after_main_py(boardctrl_state_t *state) { - if (state->run_main_py && !state->last_ret) { - flash_error(3); + if (run_main_py) { + // Run main.py (or what it was configured to be), if it exists. + const char *main_py; + if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) { + main_py = "main.py"; + } else { + main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); + } + int ret = pyexec_file_if_exists(main_py); + + // Take action based on the execution result. + if (ret & PYEXEC_FORCED_EXIT) { + return BOARDCTRL_GOTO_SOFT_RESET_EXIT; + } + if (!ret) { + flash_error(3); + } } + + return BOARDCTRL_CONTINUE; } void boardctrl_start_soft_reset(boardctrl_state_t *state) { diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h index f1cbc3b95..33e71b65c 100644 --- a/ports/stm32/boardctrl.h +++ b/ports/stm32/boardctrl.h @@ -44,20 +44,12 @@ #define MICROPY_BOARD_TOP_SOFT_RESET_LOOP boardctrl_top_soft_reset_loop #endif -#ifndef MICROPY_BOARD_BEFORE_BOOT_PY -#define MICROPY_BOARD_BEFORE_BOOT_PY boardctrl_before_boot_py +#ifndef MICROPY_BOARD_RUN_BOOT_PY +#define MICROPY_BOARD_RUN_BOOT_PY boardctrl_run_boot_py #endif -#ifndef MICROPY_BOARD_AFTER_BOOT_PY -#define MICROPY_BOARD_AFTER_BOOT_PY boardctrl_after_boot_py -#endif - -#ifndef MICROPY_BOARD_BEFORE_MAIN_PY -#define MICROPY_BOARD_BEFORE_MAIN_PY boardctrl_before_main_py -#endif - -#ifndef MICROPY_BOARD_AFTER_MAIN_PY -#define MICROPY_BOARD_AFTER_MAIN_PY boardctrl_after_main_py +#ifndef MICROPY_BOARD_RUN_MAIN_PY +#define MICROPY_BOARD_RUN_MAIN_PY boardctrl_run_main_py #endif #ifndef MICROPY_BOARD_START_SOFT_RESET @@ -68,20 +60,20 @@ #define MICROPY_BOARD_END_SOFT_RESET boardctrl_end_soft_reset #endif +enum { + BOARDCTRL_CONTINUE, + BOARDCTRL_GOTO_SOFT_RESET_EXIT, +}; + typedef struct _boardctrl_state_t { uint8_t reset_mode; - bool run_boot_py; - bool run_main_py; bool log_soft_reset; - int last_ret; } boardctrl_state_t; void boardctrl_before_soft_reset_loop(boardctrl_state_t *state); void boardctrl_top_soft_reset_loop(boardctrl_state_t *state); -void boardctrl_before_boot_py(boardctrl_state_t *state); -void boardctrl_after_boot_py(boardctrl_state_t *state); -void boardctrl_before_main_py(boardctrl_state_t *state); -void boardctrl_after_main_py(boardctrl_state_t *state); +int boardctrl_run_boot_py(boardctrl_state_t *state); +int boardctrl_run_main_py(boardctrl_state_t *state); void boardctrl_start_soft_reset(boardctrl_state_t *state); void boardctrl_end_soft_reset(boardctrl_state_t *state); diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h index 00b033006..2899a97ac 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -9,45 +9,64 @@ #define MICROPY_HW_ENABLE_DAC (1) // MSI is used and is 4MHz -#define MICROPY_HW_CLK_PLLM (1) -#define MICROPY_HW_CLK_PLLN (40) -#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) -#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) -#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 // The board has an external 32kHz crystal #define MICROPY_HW_RTC_USE_LSE (1) -// UART config -#define MICROPY_HW_UART2_TX (pin_A2) -#define MICROPY_HW_UART2_RX (pin_A3) - +// USART1 config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +// USART2 config. Connected to ST-Link +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +// USART3 config +#define MICROPY_HW_UART3_TX (pin_C4) +#define MICROPY_HW_UART3_RX (pin_C5) +#define MICROPY_HW_UART3_RTS (pin_B14) +#define MICROPY_HW_UART3_CTS (pin_B13) +// UART4 config +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +// UART5 config +#define MICROPY_HW_UART5_TX (pin_C12) +#define MICROPY_HW_UART5_RX (pin_D2) +// LPUART config +#define MICROPY_HW_LPUART1_TX (pin_C1) +#define MICROPY_HW_LPUART1_RX (pin_C0) +// USART2 is connected to the virtual com port on the ST-Link #define MICROPY_HW_UART_REPL PYB_UART_2 #define MICROPY_HW_UART_REPL_BAUD 115200 -#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 - // I2C busses -#define MICROPY_HW_I2C1_SCL (pin_B8) -#define MICROPY_HW_I2C1_SDA (pin_B9) -#define MICROPY_HW_I2C2_SCL (pin_B10) -#define MICROPY_HW_I2C2_SDA (pin_B11) -#define MICROPY_HW_I2C3_SCL (pin_C0) -#define MICROPY_HW_I2C3_SDA (pin_C1) +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) +#define MICROPY_HW_I2C3_SCL (pin_C0) +#define MICROPY_HW_I2C3_SDA (pin_C1) // SPI busses -#define MICROPY_HW_SPI1_NSS (pin_A4) -#define MICROPY_HW_SPI1_SCK (pin_B3) -#define MICROPY_HW_SPI1_MISO (pin_B4) -#define MICROPY_HW_SPI1_MOSI (pin_B5) -#define MICROPY_HW_SPI2_NSS (pin_B12) -#define MICROPY_HW_SPI2_SCK (pin_B13) -#define MICROPY_HW_SPI2_MISO (pin_B14) -#define MICROPY_HW_SPI2_MOSI (pin_B15) +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_B3) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) // CAN bus -#define MICROPY_HW_CAN1_TX (pin_A12) -#define MICROPY_HW_CAN1_RX (pin_A11) +#define MICROPY_HW_CAN1_TX (pin_A12) +#define MICROPY_HW_CAN1_RX (pin_A11) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) @@ -61,4 +80,4 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config -#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk index ead8bb8c0..9917aa2c5 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.mk @@ -6,7 +6,7 @@ AF_FILE = boards/stm32f722_af.csv LD_FILES = boards/PYBD_SF2/f722_qspi.ld TEXT0_ADDR = 0x08008000 TEXT1_ADDR = 0x90000000 -TEXT0_SECTIONS = .isr_vector .text .data +TEXT0_SECTIONS = .isr_vector .text .data .ARM TEXT1_SECTIONS = .text_ext # MicroPython settings diff --git a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk index abe3dcd86..6bcc68f4b 100644 --- a/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBD_SF3/mpconfigboard.mk @@ -6,7 +6,7 @@ AF_FILE = boards/stm32f722_af.csv LD_FILES = boards/PYBD_SF2/f722_qspi.ld TEXT0_ADDR = 0x08008000 TEXT1_ADDR = 0x90000000 -TEXT0_SECTIONS = .isr_vector .text .data +TEXT0_SECTIONS = .isr_vector .text .data .ARM TEXT1_SECTIONS = .text_ext # MicroPython settings diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 81add8c88..5d3d11a79 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -22,7 +22,7 @@ ifeq ($(USE_QSPI_XIP),1) LD_FILES = boards/STM32F769DISC/f769_qspi.ld TEXT0_ADDR = 0x08020000 TEXT1_ADDR = 0x90000000 -TEXT0_SECTIONS = .isr_vector .text .data +TEXT0_SECTIONS = .isr_vector .text .data .ARM TEXT1_SECTIONS = .text_qspi else diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py index 59d660364..619146cd4 100644 --- a/ports/stm32/boards/pllvalues.py +++ b/ports/stm32/boards/pllvalues.py @@ -240,7 +240,7 @@ def main(): argv = sys.argv[1:] c_table = False - mcu_series = "f4" + mcu_series = "stm32f4" hse = None hsi = None @@ -271,13 +271,13 @@ def main(): hse = int(argv[0]) # Select MCU parameters - if mcu_series == "h7": + if mcu_series.startswith("stm32h7"): mcu = mcu_h7 else: mcu = mcu_default - # Relax constraight on PLLQ being 48MHz on F7 and H7 MCUs, which have separate PLLs for 48MHz - relax_pll48 = mcu_series in ("f7", "h7") + # Relax constraint on PLLQ being 48MHz on MCUs which have separate PLLs for 48MHz + relax_pll48 = mcu_series.startswith(("stm32f413", "stm32f7", "stm32h7")) hse_valid_plls = compute_pll_table(hse, relax_pll48) if hsi is not None: diff --git a/ports/stm32/boards/stm32l072_af.csv b/ports/stm32/boards/stm32l072_af.csv index 0b1115b16..c9155bd44 100644 --- a/ports/stm32/boards/stm32l072_af.csv +++ b/ports/stm32/boards/stm32l072_af.csv @@ -1,7 +1,7 @@ Port,Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,, ,,SPI1/SPI2/I2S2/USART1/2/LPUART1/USB/LPTIM1/TSC/TIM2/21/22/EVENTOUT/SYS_AF,SPI1/SPI2/I2S2/I2C1/TIM2/21,SPI1/SPI2/I2S2/LPUART1/USART5/USB/LPTIM1/TIM2/3/EVENTOUT/SYS_AF,I2C1/TSC/EVENTOUT,I2C1/USART1/2/LPUART1/TIM3/22/EVENTOUT,SPI2/I2S2/I2C2/USART1/TIM2/21/22,I2C1/2/LPUART1/USART4/UASRT5/TIM21/EVENTOUT,I2C3/LPUART1/COMP1/2/TIM3,,ADC PortA,PA0,,,TIM2_CH1,TSC_G1_IO1,USART2_CTS,TIM2_ETR,USART4_TX,COMP1_OUT,,ADC_IN0 -PortA,PA1,EVENTOUT,,TIM2_CH2,TSC_G1_IO2,USART2_RTS_DE,TIM21_ETR,USART4_RX,,,ADC_IN1 +PortA,PA1,EVENTOUT,,TIM2_CH2,TSC_G1_IO2,USART2_RTS/USART2_DE,TIM21_ETR,USART4_RX,,,ADC_IN1 PortA,PA2,TIM21_CH1,,TIM2_CH3,TSC_G1_IO3,USART2_TX,,LPUART1_TX,COMP2_OUT,,ADC_IN2 PortA,PA3,TIM21_CH2,,TIM2_CH4,TSC_G1_IO4,USART2_RX,,LPUART1_RX,,,ADC_IN3 PortA,PA4,SPI1_NSS,,,TSC_G2_IO1,USART2_CK,TIM22_ETR,,,,ADC_IN4 @@ -12,25 +12,25 @@ PortA,PA8,MCO,,USB_CRS_SYNC,EVENTOUT,USART1_CK,,,I2C3_SCL,, PortA,PA9,MCO,,,TSC_G4_IO1,USART1_TX,,I2C1_SCL,I2C3_SMBA,, PortA,PA10,,,,TSC_G4_IO2,USART1_RX,,I2C1_SDA,,, PortA,PA11,SPI1_MISO,,EVENTOUT,TSC_G4_IO3,USART1_CTS,,,COMP1_OUT,, -PortA,PA12,SPI1_MOSI,,EVENTOUT,TSC_G4_IO4,USART1_RTS_DE,,,COMP2_OUT,, +PortA,PA12,SPI1_MOSI,,EVENTOUT,TSC_G4_IO4,USART1_RTS/USART1_DE,,,COMP2_OUT,, PortA,PA13,SWDIO,,USB_NOE,,,,LPUART1_RX,,, PortA,PA14,SWCLK,,,,USART2_TX,,LPUART1_TX,,, -PortA,PA15,SPI1_NSS,,TIM2_ETR,EVENTOUT,USART2_RX,TIM2_CH1,USART4_RTS_DE,,, +PortA,PA15,SPI1_NSS,,TIM2_ETR,EVENTOUT,USART2_RX,TIM2_CH1,USART4_RTS/USART4_DE,,, PortB,PB0,EVENTOUT,,TIM3_CH3,TSC_G3_IO2,,,,,,ADC_IN8 -PortB,PB1,,,TIM3_CH4,TSC_G3_IO3,LPUART1_RTS_DE,,,,,ADC_IN9 +PortB,PB1,,,TIM3_CH4,TSC_G3_IO3,LPUART1_RTS/LPUART1_DE,,,,,ADC_IN9 PortB,PB2,,,LPTIM1_OUT,TSC_G3_IO4,,,,I2C3_SMBA,, -PortB,PB3,SPI1_SCK,,TIM2_CH2,TSC_G5_IO1,EVENTOUT,USART1_RTS_DE,USART5_TX,,, +PortB,PB3,SPI1_SCK,,TIM2_CH2,TSC_G5_IO1,EVENTOUT,USART1_RTS/USART1_DE,USART5_TX,,, PortB,PB4,SPI1_MISO,,TIM3_CH1,TSC_G5_IO2,TIM22_CH1,USART1_CTS,USART5_RX,I2C3_SDA,, -PortB,PB5,SPI1_MOSI,,LPTIM1_IN1,I2C1_SMBA,TIM3_CH2/TIM22_CH2,USART1_CK,USART5_CK/USART5_RTS_DE,,, +PortB,PB5,SPI1_MOSI,,LPTIM1_IN1,I2C1_SMBA,TIM3_CH2/TIM22_CH2,USART1_CK,USART5_CK/USART5_RTS/USART5_DE,,, PortB,PB6,USART1_TX,I2C1_SCL,LPTIM1_ETR,TSC_G5_IO3,,,,,, PortB,PB7,USART1_RX,I2C1_SDA,LPTIM1_IN2,TSC_G5_IO4,,,USART4_CTS,,, PortB,PB8,,,,TSC_SYNC,I2C1_SCL,,,,, PortB,PB9,,,EVENTOUT,,I2C1_SDA,SPI2_NSS/I2S2_WS,,,, PortB,PB10,,,TIM2_CH3,TSC_SYNC,LPUART1_TX,SPI2_SCK,I2C2_SCL,LPUART1_RX,, PortB,PB11,EVENTOUT,,TIM2_CH4,TSC_G6_IO1,LPUART1_RX,,I2C2_SDA,LPUART1_TX,, -PortB,PB12,SPI2_NSS/I2S2_WS,,LPUART1_RTS_DE,TSC_G6_IO2,I2C2_SMBA,,EVENTOUT,,, +PortB,PB12,SPI2_NSS/I2S2_WS,,LPUART1_RTS/LPUART1_DE,TSC_G6_IO2,I2C2_SMBA,,EVENTOUT,,, PortB,PB13,SPI2_SCK/I2S2_CK,,MCO,TSC_G6_IO3,LPUART1_CTS,I2C2_SCL,TIM21_CH1,,, -PortB,PB14,SPI2_MISO/I2S2_MCK,,RTC_OUT,TSC_G6_IO4,LPUART1_RTS_DE,I2C2_SDA,TIM21_CH2,,, +PortB,PB14,SPI2_MISO/I2S2_MCK,,RTC_OUT,TSC_G6_IO4,LPUART1_RTS/LPUART1_DE,I2C2_SDA,TIM21_CH2,,, PortB,PB15,SPI2_MOSI/I2S2_SD,,RTC_REFIN,,,,,,, PortC,PC0,LPTIM1_IN1,,EVENTOUT,TSC_G7_IO1,,,LPUART1_RX,I2C3_SCL,,ADC_IN10 PortC,PC1,LPTIM1_OUT,,EVENTOUT,TSC_G7_IO2,,,LPUART1_TX,I2C3_SDA,,ADC_IN11 @@ -50,9 +50,9 @@ PortC,PC14,,,,,,,,,, PortC,PC15,,,,,,,,,, PortD,PD0,TIM21_CH1,SPI2_NSS/I2S2_WS,,,,,,,, PortD,PD1,,SPI2_SCK/I2S2_CK,,,,,,,, -PortD,PD2,LPUART1_RTS_DE,,TIM3_ETR,,,,USART5_RX,,, +PortD,PD2,LPUART1_RTS/LPUART1_DE,,TIM3_ETR,,,,USART5_RX,,, PortD,PD3,USART2_CTS,,SPI2_MISO/I2S2_MCK,,,,,,, -PortD,PD4,USART2_RTS_DE,SPI2_MOSI/I2S2_SD,,,,,,,, +PortD,PD4,USART2_RTS/USART2_DE,SPI2_MOSI/I2S2_SD,,,,,,,, PortD,PD5,USART2_TX,,,,,,,,, PortD,PD6,USART2_RX,,,,,,,,, PortD,PD7,USART2_CK,TIM21_CH2,,,,,,,, @@ -60,7 +60,7 @@ PortD,PD8,LPUART1_TX,,,,,,,,, PortD,PD9,LPUART1_RX,,,,,,,,, PortD,PD10,,,,,,,,,, PortD,PD11,LPUART1_CTS,,,,,,,,, -PortD,PD12,LPUART1_RTS_DE,,,,,,,,, +PortD,PD12,LPUART1_RTS/LPUART1_DE,,,,,,,,, PortD,PD13,,,,,,,,,, PortD,PD14,,,,,,,,,, PortD,PD15,USB_CRS_SYNC,,,,,,,,, @@ -71,7 +71,7 @@ PortE,PE3,TIM22_CH1,,TIM3_CH1,,,,,,, PortE,PE4,TIM22_CH2,,TIM3_CH2,,,,,,, PortE,PE5,TIM21_CH1,,TIM3_CH3,,,,,,, PortE,PE6,TIM21_CH2,,TIM3_CH4,,,,,,, -PortE,PE7,,,,,,,USART5_CK/USART5_RTS_DE,,, +PortE,PE7,,,,,,,USART5_CK/USART5_RTS/USART5_DE,,, PortE,PE8,,,,,,,USART4_TX,,, PortE,PE9,TIM2_CH1,,TIM2_ETR,,,,USART4_RX,,, PortE,PE10,TIM2_CH2,,,,,,USART5_TX,,, diff --git a/ports/stm32/boards/stm32l452_af.csv b/ports/stm32/boards/stm32l452_af.csv index f7170d1c6..1de5c211d 100644 --- a/ports/stm32/boards/stm32l452_af.csv +++ b/ports/stm32/boards/stm32l452_af.csv @@ -30,7 +30,7 @@ PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,,USART3_TX,LPUART1_RX,TSC_SYNC, PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,,USART3_RX,LPUART1_TX,,QUADSPI_NCS,,COMP2_OUT,,,EVENTOUT,,, PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,CAN1_RX,,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN1_TX,,,SAI1_SCK_A,TIM15_CH1N,EVENTOUT,,, -PortB,PB14,,TIM1_CH2N,,,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,,,SAI1_MCLK_A,TIM15_CH1,EVENTOUT,,, +PortB,PB14,,TIM1_CH2N,,,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,,,SAI1_MCLK_A,TIM15_CH1,EVENTOUT,,, PortB,PB15,RTC_REFIN,TIM1_CH3N,,,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,,,SAI1_SD_A,TIM15_CH2,EVENTOUT,,, PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,,,LPUART1_RX,,,,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,, PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,,I2C3_SDA,,,,LPUART1_TX,,,,,,,EVENTOUT,ADC123_IN2,, diff --git a/ports/stm32/boards/stm32l476_af.csv b/ports/stm32/boards/stm32l476_af.csv index 01db89572..df824ed70 100644 --- a/ports/stm32/boards/stm32l476_af.csv +++ b/ports/stm32/boards/stm32l476_af.csv @@ -30,7 +30,7 @@ PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUAD PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,, PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,, PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,DFSDM_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1, PortC,PC1,,LPTIM1_OUT,,,I2C3_SDA,,DFSDM_CKIN4,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN2, diff --git a/ports/stm32/boards/stm32wb55_af.csv b/ports/stm32/boards/stm32wb55_af.csv index 074c33089..d6e1c3f77 100644 --- a/ports/stm32/boards/stm32wb55_af.csv +++ b/ports/stm32/boards/stm32wb55_af.csv @@ -12,14 +12,14 @@ PortA,PA8,MCO,TIM1_CH1,,SAI1_PDM_CK2,,,,USART1_CK,,,,LCD_COM0,,SAI1_SCK_A,LPTIM2 PortA,PA9,,TIM1_CH2,,SAI1_PDM_DI2,I2C1_SCL,SPI2_SCK,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,,EVENTOUT,ADC1_IN16 PortA,PA10,,TIM1_CH3,,SAI1_PDM_DI1,I2C1_SDA,,,USART1_RX,,,USB_CRS_SYNC,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT, PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,,USB_DM,,TIM1_BKIN2,,,EVENTOUT, -PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS_DE,LPUART1_RX,,USB_DP,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS/USART1_DE,LPUART1_RX,,USB_DP,,,,,EVENTOUT, PortA,PA13,JTMS/SWDIO,,,,,,,,IR_OUT,,USB_NOE,,,SAI1_SD_B,,EVENTOUT, PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,LCD_SEG5,,SAI1_FS_B,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,,,,TSC_G3_IO1,,LCD_SEG17,,,,EVENTOUT, PortB,PB0,,,,,,,EXT_PA_TX,,,,,,COMP1_OUT,,,EVENTOUT, -PortB,PB1,,,,,,,,,LPUART1_RTS_DE,,,,,,LPTIM2_IN1,EVENTOUT, +PortB,PB1,,,,,,,,,LPUART1_RTS/LPUART1_DE,,,,,,LPTIM2_IN1,EVENTOUT, PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,SPI1_NSS,,,,,,LCD_VLCD,,SAI1_EXTCLK,,EVENTOUT, -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,,USART1_RTS/USART1_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT, PortB,PB4,NJTRST,,,,I2C3_SDA,SPI1_MISO,,USART1_CTS,,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT, PortB,PB5,,LPTIM1_IN1,,,I2C1_SMBA,SPI1_MOSI,,USART1_CK,LPUART1_TX,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT, PortB,PB6,MCO,LPTIM1_ETR,,,I2C1_SCL,,,USART1_TX,,TSC_G2_IO3,,LCD_SEG6,,SAI1_FS_B,TIM16_CH1N,EVENTOUT, diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 888b20513..bc8e6f069 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -469,9 +469,7 @@ void stm32_main(uint32_t reset_mode) { boardctrl_state_t state; state.reset_mode = reset_mode; - state.run_boot_py = false; - state.run_main_py = false; - state.last_ret = 0; + state.log_soft_reset = false; MICROPY_BOARD_BEFORE_SOFT_RESET_LOOP(&state); @@ -566,20 +564,11 @@ soft_reset: // reset config variables; they should be set by boot.py MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL; - MICROPY_BOARD_BEFORE_BOOT_PY(&state); - - // run boot.py, if it exists - // TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py - if (state.run_boot_py) { - const char *boot_py = "boot.py"; - state.last_ret = pyexec_file_if_exists(boot_py); - if (state.last_ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; - } + // Run boot.py (or whatever else a board configures at this stage). + if (MICROPY_BOARD_RUN_BOOT_PY(&state) == BOARDCTRL_GOTO_SOFT_RESET_EXIT) { + goto soft_reset_exit; } - MICROPY_BOARD_AFTER_BOOT_PY(&state); - // Now we initialise sub-systems that need configuration from boot.py, // or whose initialisation can be safely deferred until after running // boot.py. @@ -613,24 +602,11 @@ soft_reset: // At this point everything is fully configured and initialised. - MICROPY_BOARD_BEFORE_MAIN_PY(&state); - - // Run the main script from the current directory. - if (state.run_main_py) { - const char *main_py; - if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) { - main_py = "main.py"; - } else { - main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); - } - state.last_ret = pyexec_file_if_exists(main_py); - if (state.last_ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; - } + // Run main.py (or whatever else a board configures at this stage). + if (MICROPY_BOARD_RUN_MAIN_PY(&state) == BOARDCTRL_GOTO_SOFT_RESET_EXIT) { + goto soft_reset_exit; } - MICROPY_BOARD_AFTER_MAIN_PY(&state); - #if MICROPY_ENABLE_COMPILER // Main script is finished, so now go into REPL mode. // The REPL mode can change, or it can request a soft reset. diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 948897b21..6fb9289e0 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -310,6 +310,25 @@ #endif #endif +// Configure the default bus clock divider values +#ifndef MICROPY_HW_CLK_AHB_DIV +#if defined(STM32H7) +#define MICROPY_HW_CLK_AHB_DIV (RCC_HCLK_DIV2) +#define MICROPY_HW_CLK_APB1_DIV (RCC_APB1_DIV2) +#define MICROPY_HW_CLK_APB2_DIV (RCC_APB2_DIV2) +#define MICROPY_HW_CLK_APB3_DIV (RCC_APB3_DIV2) +#define MICROPY_HW_CLK_APB4_DIV (RCC_APB4_DIV2) +#elif defined(STM32L4) +#define MICROPY_HW_CLK_AHB_DIV (RCC_SYSCLK_DIV1) +#define MICROPY_HW_CLK_APB1_DIV (RCC_HCLK_DIV1) +#define MICROPY_HW_CLK_APB2_DIV (RCC_HCLK_DIV1) +#else +#define MICROPY_HW_CLK_AHB_DIV (RCC_SYSCLK_DIV1) +#define MICROPY_HW_CLK_APB1_DIV (RCC_HCLK_DIV4) +#define MICROPY_HW_CLK_APB2_DIV (RCC_HCLK_DIV2) +#endif +#endif + // If disabled then try normal (non-bypass) LSE first, with fallback to LSI. // If enabled first try LSE in bypass mode. If that fails to start, try non-bypass mode, with fallback to LSI. #ifndef MICROPY_HW_RTC_USE_BYPASS diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 776e54ebc..b9b5ea80b 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -399,6 +399,10 @@ struct _mp_bluetooth_btstack_root_pointers_t; #define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_BTSTACK #endif +#ifndef MICROPY_BOARD_ROOT_POINTERS +#define MICROPY_BOARD_ROOT_POINTERS +#endif + #define MICROPY_PORT_ROOT_POINTERS \ LV_ROOTS \ void *mp_lv_user_data; \ @@ -433,9 +437,13 @@ struct _mp_bluetooth_btstack_root_pointers_t; /* list of registered NICs */ \ mp_obj_list_t mod_network_nic_list; \ \ + /* root pointers for sub-systems */ \ MICROPY_PORT_ROOT_POINTER_MBEDTLS \ MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE \ - MICROPY_PORT_ROOT_POINTER_BLUETOOTH_BTSTACK \ + MICROPY_PORT_ROOT_POINTER_BLUETOOTH_BTSTACK \ + \ + /* root pointers defined by a board */ \ + MICROPY_BOARD_ROOT_POINTERS \ // type definitions for the specific machine diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index a579713b6..573844063 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -50,6 +50,22 @@ #define RCC_SR_RMVF RCC_CSR_RMVF #endif +// Whether this MCU has an independent PLL which can generate 48MHz for USB. +#if defined(STM32F413xx) +// STM32F413 uses PLLI2S as secondary PLL. +#define HAVE_PLL48 1 +#define RCC_CR_PLL48_ON RCC_CR_PLLI2SON +#define RCC_CR_PLL48_RDY RCC_CR_PLLI2SRDY +#elif defined(STM32F7) +// STM32F7 uses PLLSAI as secondary PLL. +#define HAVE_PLL48 1 +#define RCC_CR_PLL48_ON RCC_CR_PLLSAION +#define RCC_CR_PLL48_RDY RCC_CR_PLLSAIRDY +#else +// MCU does not have a secondary PLL. +#define HAVE_PLL48 0 +#endif + // Location in RAM of bootloader state (just after the top of the stack) extern uint32_t _estack[]; #define BL_STATE ((uint32_t *)&_estack) @@ -141,13 +157,24 @@ STATIC int powerctrl_config_vos(uint32_t sysclk_mhz) { } // Assumes that PLL is used as the SYSCLK source -int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) { +int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pll48) { uint32_t flash_latency; - #if defined(STM32F7) - if (need_pllsai) { - // Configure PLLSAI at 48MHz for those peripherals that need this freq - // (calculation assumes it can get an integral value of PLLSAIN) + #if HAVE_PLL48 + if (need_pll48) { + // Configure secondary PLL at 48MHz for those peripherals that need this freq + // (the calculation assumes it can get an integral value of PLL-N). + + #if defined(STM32F413xx) + const uint32_t plli2sm = HSE_VALUE / 1000000; + const uint32_t plli2sq = 2; + const uint32_t plli2sr = 2; + const uint32_t plli2sn = 48 * plli2sq; + RCC->PLLI2SCFGR = plli2sr << RCC_PLLI2SCFGR_PLLI2SR_Pos + | plli2sq << RCC_PLLI2SCFGR_PLLI2SQ_Pos + | plli2sn << RCC_PLLI2SCFGR_PLLI2SN_Pos + | plli2sm << RCC_PLLI2SCFGR_PLLI2SM_Pos; + #else const uint32_t pllm = (RCC->PLLCFGR >> RCC_PLLCFGR_PLLM_Pos) & 0x3f; const uint32_t pllsaip = 4; const uint32_t pllsaiq = 2; @@ -155,13 +182,18 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk RCC->PLLSAICFGR = pllsaiq << RCC_PLLSAICFGR_PLLSAIQ_Pos | (pllsaip / 2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos | pllsain << RCC_PLLSAICFGR_PLLSAIN_Pos; - RCC->CR |= RCC_CR_PLLSAION; + #endif + + // Turn on the PLL and wait for it to be ready. + RCC->CR |= RCC_CR_PLL48_ON; uint32_t ticks = mp_hal_ticks_ms(); - while (!(RCC->CR & RCC_CR_PLLSAIRDY)) { + while (!(RCC->CR & RCC_CR_PLL48_RDY)) { if (mp_hal_ticks_ms() - ticks > 200) { return -MP_ETIMEDOUT; } } + + // Select the alternate 48MHz source. RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL; } #endif @@ -317,7 +349,7 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t // Default PLL parameters that give 48MHz on PLL48CK uint32_t m = MICROPY_HW_CLK_VALUE / 1000000, n = 336, p = 2, q = 7; uint32_t sysclk_source; - bool need_pllsai = false; + bool need_pll48 = false; // Search for a valid PLL configuration that keeps USB at 48MHz uint32_t sysclk_mhz = sysclk / 1000000; @@ -338,8 +370,8 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t uint32_t vco_out = sys * p; n = vco_out * m / (MICROPY_HW_CLK_VALUE / 1000000); q = vco_out / 48; - #if defined(STM32F7) - need_pllsai = vco_out % 48 != 0; + #if HAVE_PLL48 + need_pll48 = vco_out % 48 != 0; #endif } goto set_clk; @@ -377,8 +409,8 @@ set_clk: RCC_ClkInitStruct.APB2CLKDivider = calc_apb2_div(ahb / apb2); #if defined(STM32H7) RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; - RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + RCC_ClkInitStruct.APB3CLKDivider = MICROPY_HW_CLK_APB3_DIV; + RCC_ClkInitStruct.APB4CLKDivider = MICROPY_HW_CLK_APB4_DIV; #endif #if MICROPY_HW_CLK_LAST_FREQ @@ -393,11 +425,11 @@ set_clk: return -MP_EIO; } - #if defined(STM32F7) + #if HAVE_PLL48 // Deselect PLLSAI as 48MHz source if we were using it RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_CK48MSEL; // Turn PLLSAI off because we are changing PLLM (which drives PLLSAI) - RCC->CR &= ~RCC_CR_PLLSAION; + RCC->CR &= ~RCC_CR_PLL48_ON; #endif // Re-configure PLL @@ -440,7 +472,7 @@ set_clk: // Set PLL as system clock source if wanted if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; - int ret = powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai); + int ret = powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pll48); if (ret != 0) { return ret; } @@ -607,11 +639,11 @@ void powerctrl_enter_stop_mode(void) { powerctrl_disable_hsi_if_unused(); - #if defined(STM32F7) + #if HAVE_PLL48 if (RCC->DCKCFGR2 & RCC_DCKCFGR2_CK48MSEL) { // Enable PLLSAI if it is selected as 48MHz source - RCC->CR |= RCC_CR_PLLSAION; - while (!(RCC->CR & RCC_CR_PLLSAIRDY)) { + RCC->CR |= RCC_CR_PLL48_ON; + while (!(RCC->CR & RCC_CR_PLL48_RDY)) { } } #endif diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c index 55fc229dd..049f6bdc1 100644 --- a/ports/stm32/rfcore.c +++ b/ports/stm32/rfcore.c @@ -417,6 +417,12 @@ STATIC void tl_process_msg(volatile tl_list_node_t *head, unsigned int ch, parse // If this node is allocated from the memmgr event pool, then place it into the free buffer. if ((uint8_t *)cur >= ipcc_membuf_memmgr_evt_pool && (uint8_t *)cur < ipcc_membuf_memmgr_evt_pool + sizeof(ipcc_membuf_memmgr_evt_pool)) { + // Wait for C2 to indicate that it has finished using the free buffer, + // so that we can link the newly-freed memory in to this buffer. + // If waiting is needed then it is typically between 5 and 20 microseconds. + while (LL_C1_IPCC_IsActiveFlag_CHx(IPCC, IPCC_CH_MM)) { + } + // Place memory back in free pool. tl_list_append(&ipcc_mem_memmgr_free_buf_queue, cur); added_to_free_queue = true; @@ -604,6 +610,24 @@ void rfcore_ble_hci_cmd(size_t len, const uint8_t *src) { tl_list_node_t *n; uint32_t ch; if (src[0] == HCI_KIND_BT_CMD) { + // The STM32WB has a problem when address resolution is enabled: under certain + // conditions the MCU can get into a state where it draws an additional 10mA + // or so and eventually ends up with a broken BLE RX path in the silicon. A + // simple way to reproduce this is to enable address resolution (which is the + // default for NimBLE) and start the device advertising. If there is enough + // BLE activity in the vicinity then the device will at some point enter the + // bad state and, if left long enough, will have permanent BLE RX damage. + // + // STMicroelectronics are aware of this issue. The only known workaround at + // this stage is to not enable address resolution. We do that here by + // intercepting any command that enables address resolution and convert it + // into a command that disables address resolution. + // + // OGF=0x08 OCF=0x002d HCI_LE_Set_Address_Resolution_Enable + if (len == 5 && memcmp(src + 1, "\x2d\x20\x01\x01", 4) == 0) { + src = (const uint8_t *)"\x01\x2d\x20\x01\x00"; + } + n = (tl_list_node_t *)&ipcc_membuf_ble_cmd_buf[0]; ch = IPCC_CH_BLE; } else if (src[0] == HCI_KIND_BT_ACL) { diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index e8892b574..2791df277 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -73,7 +73,9 @@ bool sdram_init(void) { mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNRAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNRAS); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_SDNWE, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_SDNWE); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_BA0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_BA0); + #ifdef MICROPY_HW_FMC_BA1 mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_BA1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_BA1); + #endif mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL0); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_NBL1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_NBL1); #ifdef MICROPY_HW_FMC_NBL2 @@ -91,7 +93,9 @@ bool sdram_init(void) { mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A8); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A9); mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A10); + #ifdef MICROPY_HW_FMC_A11 mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A11); + #endif #ifdef MICROPY_HW_FMC_A12 mp_hal_pin_config_alt_static_speed(MICROPY_HW_FMC_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_VERY_HIGH, STATIC_AF_FMC_A12); #endif diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 2160e0ac9..4e89204bf 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -272,9 +272,9 @@ void SystemClock_Config(void) { n = MICROPY_HW_CLK_PLLN; p = MICROPY_HW_CLK_PLLP; q = MICROPY_HW_CLK_PLLQ; - h = RCC_SYSCLK_DIV1; - b1 = RCC_HCLK_DIV4; - b2 = RCC_HCLK_DIV2; + h = MICROPY_HW_CLK_AHB_DIV; + b1 = MICROPY_HW_CLK_APB1_DIV; + b2 = MICROPY_HW_CLK_APB2_DIV; } else { h <<= 4; b1 <<= 10; @@ -285,9 +285,9 @@ void SystemClock_Config(void) { RCC_OscInitStruct.PLL.PLLP = p; // MICROPY_HW_CLK_PLLP; RCC_OscInitStruct.PLL.PLLQ = q; // MICROPY_HW_CLK_PLLQ; - RCC_ClkInitStruct.AHBCLKDivider = h; // RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = b1; // RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = b2; // RCC_HCLK_DIV2; + RCC_ClkInitStruct.AHBCLKDivider = h; + RCC_ClkInitStruct.APB1CLKDivider = b1; + RCC_ClkInitStruct.APB2CLKDivider = b2; #else // defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM; RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; @@ -304,20 +304,20 @@ void SystemClock_Config(void) { #endif #if defined(STM32F4) || defined(STM32F7) - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.AHBCLKDivider = MICROPY_HW_CLK_AHB_DIV; + RCC_ClkInitStruct.APB1CLKDivider = MICROPY_HW_CLK_APB1_DIV; + RCC_ClkInitStruct.APB2CLKDivider = MICROPY_HW_CLK_APB2_DIV; #elif defined(STM32L4) - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.AHBCLKDivider = MICROPY_HW_CLK_AHB_DIV; + RCC_ClkInitStruct.APB1CLKDivider = MICROPY_HW_CLK_APB1_DIV; + RCC_ClkInitStruct.APB2CLKDivider = MICROPY_HW_CLK_APB2_DIV; #elif defined(STM32H7) RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; - RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; - RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; - RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; - RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + RCC_ClkInitStruct.AHBCLKDivider = MICROPY_HW_CLK_AHB_DIV; + RCC_ClkInitStruct.APB3CLKDivider = MICROPY_HW_CLK_APB3_DIV; + RCC_ClkInitStruct.APB1CLKDivider = MICROPY_HW_CLK_APB1_DIV; + RCC_ClkInitStruct.APB2CLKDivider = MICROPY_HW_CLK_APB2_DIV; + RCC_ClkInitStruct.APB4CLKDivider = MICROPY_HW_CLK_APB4_DIV; #endif #endif @@ -351,8 +351,8 @@ void SystemClock_Config(void) { uint32_t vco_out = RCC_OscInitStruct.PLL.PLLN * (MICROPY_HW_CLK_VALUE / 1000000) / RCC_OscInitStruct.PLL.PLLM; uint32_t sysclk_mhz = vco_out / RCC_OscInitStruct.PLL.PLLP; - bool need_pllsai = vco_out % 48 != 0; - if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai) != 0) { + bool need_pll48 = vco_out % 48 != 0; + if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pll48) != 0) { __fatal_error("HAL_RCC_ClockConfig"); } diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index d40a883c5..36c59cee4 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -711,16 +711,11 @@ uint32_t uart_get_source_freq(pyb_uart_obj_t *self) { } uint32_t uart_get_baudrate(pyb_uart_obj_t *self) { - // This formula assumes UART_OVERSAMPLING_16 - uint32_t source_freq = uart_get_source_freq(self); - #if defined(LPUART1) - if (self->uart_id == PYB_LPUART_1) { - return source_freq / (self->uartx->BRR >> 8); - } else - #endif - { - return source_freq / self->uartx->BRR; - } + return LL_USART_GetBaudRate(self->uartx, uart_get_source_freq(self), + #if defined(STM32H7) || defined(STM32WB) + self->uartx->PRESC, + #endif + LL_USART_OVERSAMPLING_16); } void uart_set_baudrate(pyb_uart_obj_t *self, uint32_t baudrate) { diff --git a/ports/unix/main.c b/ports/unix/main.c index 07db8d22c..e33c1742d 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -341,6 +341,9 @@ STATIC int invalid_args(void) { STATIC void pre_process_options(int argc, char **argv) { for (int a = 1; a < argc; a++) { if (argv[a][0] == '-') { + if (strcmp(argv[a], "-c") == 0 || strcmp(argv[a], "-m") == 0) { + break; // Everything after this is a command/module and arguments for it + } if (strcmp(argv[a], "-h") == 0) { print_help(argv); exit(0); @@ -400,6 +403,8 @@ STATIC void pre_process_options(int argc, char **argv) { } a++; } + } else { + break; // Not an option but a file } } } @@ -568,11 +573,10 @@ MP_NOINLINE int main_(int argc, char **argv) { if (a + 1 >= argc) { return invalid_args(); } + set_sys_argv(argv, a + 1, a); // The -c becomes first item of sys.argv, as in CPython + set_sys_argv(argv, argc, a + 2); // Then what comes after the command ret = do_str(argv[a + 1]); - if (ret & FORCED_EXIT) { - break; - } - a += 1; + break; } else if (strcmp(argv[a], "-m") == 0) { if (a + 1 >= argc) { return invalid_args(); @@ -592,7 +596,12 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_obj_t mod; nlr_buf_t nlr; - bool subpkg_tried = false; + + // Allocating subpkg_tried on the stack can lead to compiler warnings about this + // variable being clobbered when nlr is implemented using setjmp/longjmp. Its + // value must be preserved across calls to setjmp/longjmp. + static bool subpkg_tried; + subpkg_tried = false; reimport: if (nlr_push(&nlr) == 0) { diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index ef81975d9..fac8c0d27 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -7,8 +7,7 @@ CFLAGS += \ -fprofile-arcs -ftest-coverage \ -Wformat -Wmissing-declarations -Wmissing-prototypes \ -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ - -DMICROPY_UNIX_COVERAGE \ - -DMODULE_CEXAMPLE_ENABLED=1 -DMODULE_CPPEXAMPLE_ENABLED=1 + -DMICROPY_UNIX_COVERAGE LDFLAGS += -fprofile-arcs -ftest-coverage diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt index 08868d716..716642979 100644 --- a/ports/zephyr/CMakeLists.txt +++ b/ports/zephyr/CMakeLists.txt @@ -85,7 +85,7 @@ set(MICROPY_CPP_FLAGS_EXTRA ${includes} ${system_includes} ${definitions} ${opti zephyr_library_named(${MICROPY_TARGET}) zephyr_library_include_directories( - ${MICROPY_DIR} + ${MICROPY_INC_CORE} ${MICROPY_PORT_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 9c4c4afab..f20240c62 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -69,7 +69,7 @@ add_custom_command( # it was last run, but it looks like it's not possible to specify that with cmake. add_custom_command( OUTPUT ${MICROPY_QSTRDEFS_LAST} - COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py pp ${CMAKE_C_COMPILER} -E output ${MICROPY_GENHDR_DIR}/qstr.i.last cflags ${MICROPY_CPP_FLAGS} -DNO_QSTR sources ${MICROPY_SOURCE_QSTR} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py pp ${CMAKE_C_COMPILER} -E output ${MICROPY_GENHDR_DIR}/qstr.i.last cflags ${MICROPY_CPP_FLAGS} -DNO_QSTR cxxflags ${MICROPY_CPP_FLAGS} -DNO_QSTR sources ${MICROPY_SOURCE_QSTR} DEPENDS ${MICROPY_MODULEDEFS} ${MICROPY_SOURCE_QSTR} VERBATIM diff --git a/py/mpconfig.h b/py/mpconfig.h index 454fc12b7..3dd83a34a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -28,7 +28,7 @@ // Current version of MicroPython #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 14 +#define MICROPY_VERSION_MINOR 15 #define MICROPY_VERSION_MICRO 0 // Combined version as a 32-bit number for convenience @@ -229,6 +229,11 @@ #define MICROPY_MODULE_DICT_SIZE (1) #endif +// Initial size of sys.modules dict +#ifndef MICROPY_LOADED_MODULES_DICT_SIZE +#define MICROPY_LOADED_MODULES_DICT_SIZE (3) +#endif + // Whether realloc/free should be passed allocated memory region size // You must enable this if MICROPY_MEM_STATS is enabled #ifndef MICROPY_MALLOC_USES_ALLOCATED_SIZE diff --git a/py/profile.c b/py/profile.c index 863b0068a..9cf8c4b7b 100644 --- a/py/profile.c +++ b/py/profile.c @@ -172,7 +172,7 @@ STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } } -const mp_obj_type_t mp_type_code = { +const mp_obj_type_t mp_type_settrace_codeobj = { { &mp_type_type }, .name = MP_QSTR_code, .print = code_print, @@ -185,7 +185,7 @@ mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc) { if (o == NULL) { return MP_OBJ_NULL; } - o->base.type = &mp_type_code; + o->base.type = &mp_type_settrace_codeobj; o->rc = rc; o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly? o->lnotab = MP_OBJ_NULL; diff --git a/py/py.cmake b/py/py.cmake index 52baaa8ef..2b5d437b5 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -2,6 +2,8 @@ set(MICROPY_PY_DIR "${MICROPY_DIR}/py") +list(APPEND MICROPY_INC_CORE "${MICROPY_DIR}") + # All py/ source files set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/argcheck.c @@ -122,3 +124,25 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/vstr.c ${MICROPY_PY_DIR}/warning.c ) + +# Helper macro to collect include directories and compile definitions for qstr processing. +macro(micropy_gather_target_properties targ) + if(TARGET ${targ}) + get_target_property(type ${targ} TYPE) + set(_inc OFF) + set(_def OFF) + if(${type} STREQUAL STATIC_LIBRARY) + get_target_property(_inc ${targ} INCLUDE_DIRECTORIES) + get_target_property(_def ${targ} COMPILE_DEFINITIONS) + elseif(${type} STREQUAL INTERFACE_LIBRARY) + get_target_property(_inc ${targ} INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(_def ${targ} INTERFACE_COMPILE_DEFINITIONS) + endif() + if(_inc) + list(APPEND MICROPY_CPP_INC_EXTRA ${_inc}) + endif() + if(_def) + list(APPEND MICROPY_CPP_DEF_EXTRA ${_def}) + endif() + endif() +endmacro() diff --git a/py/runtime.c b/py/runtime.c index 5d476a276..0ce685473 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -91,7 +91,7 @@ void mp_init(void) { #endif // init global module dict - mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); + mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), MICROPY_LOADED_MODULES_DICT_SIZE); // initialise the __main__ module mp_obj_dict_init(&MP_STATE_VM(dict_main), 1); diff --git a/py/usermod.cmake b/py/usermod.cmake new file mode 100644 index 000000000..853276283 --- /dev/null +++ b/py/usermod.cmake @@ -0,0 +1,52 @@ +# Create a target for all user modules to link against. +add_library(usermod INTERFACE) + +function(usermod_gather_sources SOURCES_VARNAME INCLUDE_DIRECTORIES_VARNAME INCLUDED_VARNAME LIB) + if (NOT ${LIB} IN_LIST ${INCLUDED_VARNAME}) + list(APPEND ${INCLUDED_VARNAME} ${LIB}) + + # Gather library sources + get_target_property(lib_sources ${LIB} INTERFACE_SOURCES) + if (lib_sources) + list(APPEND ${SOURCES_VARNAME} ${lib_sources}) + endif() + + # Gather library includes + get_target_property(lib_include_directories ${LIB} INTERFACE_INCLUDE_DIRECTORIES) + if (lib_include_directories) + list(APPEND ${INCLUDE_DIRECTORIES_VARNAME} ${lib_include_directories}) + endif() + + # Recurse linked libraries + get_target_property(trans_depend ${LIB} INTERFACE_LINK_LIBRARIES) + if (trans_depend) + foreach(SUB_LIB ${trans_depend}) + usermod_gather_sources( + ${SOURCES_VARNAME} + ${INCLUDE_DIRECTORIES_VARNAME} + ${INCLUDED_VARNAME} + ${SUB_LIB}) + endforeach() + endif() + + set(${SOURCES_VARNAME} ${${SOURCES_VARNAME}} PARENT_SCOPE) + set(${INCLUDE_DIRECTORIES_VARNAME} ${${INCLUDE_DIRECTORIES_VARNAME}} PARENT_SCOPE) + set(${INCLUDED_VARNAME} ${${INCLUDED_VARNAME}} PARENT_SCOPE) + endif() +endfunction() + +# Include CMake files for user modules. +if (USER_C_MODULES) + foreach(USER_C_MODULE_PATH ${USER_C_MODULES}) + message("Including User C Module(s) from ${USER_C_MODULE_PATH}") + include(${USER_C_MODULE_PATH}) + endforeach() +endif() + +# Recursively gather sources for QSTR scanning - doesn't support generator expressions. +usermod_gather_sources(MICROPY_SOURCE_USERMOD MICROPY_INC_USERMOD found_modules usermod) + +# Report found modules. +list(REMOVE_ITEM found_modules "usermod") +list(JOIN found_modules ", " found_modules) +message("Found User C Module(s): ${found_modules}") diff --git a/tests/cmdline/repl_inspect.py b/tests/cmdline/repl_inspect.py index 5a7564a3c..8c86f287d 100644 --- a/tests/cmdline/repl_inspect.py +++ b/tests/cmdline/repl_inspect.py @@ -1,2 +1,2 @@ -# cmdline: -c print("test") -i +# cmdline: -i -c print("test") # -c option combined with -i option results in REPL diff --git a/tests/cmdline/repl_inspect.py.exp b/tests/cmdline/repl_inspect.py.exp index 59f734b2f..051acfd15 100644 --- a/tests/cmdline/repl_inspect.py.exp +++ b/tests/cmdline/repl_inspect.py.exp @@ -1,6 +1,6 @@ test MicroPython \.\+ version Use \.\+ ->>> # cmdline: -c print("test") -i +>>> # cmdline: -i -c print("test") >>> # -c option combined with -i option results in REPL >>> diff --git a/tests/extmod/ure_limit.py b/tests/extmod/ure_limit.py new file mode 100644 index 000000000..99c6a818e --- /dev/null +++ b/tests/extmod/ure_limit.py @@ -0,0 +1,34 @@ +# Test overflow in ure.compile output code. + +try: + import ure as re +except ImportError: + print("SKIP") + raise SystemExit + + +def test_re(r): + try: + re.compile(r) + except: + print("Error") + + +# too many chars in [] +test_re("[" + "a" * 256 + "]") + +# too many groups +test_re("(a)" * 256) + +# jump too big for ? +test_re("(" + "a" * 62 + ")?") + +# jump too big for * +test_re("(" + "a" * 60 + ".)*") +test_re("(" + "a" * 60 + "..)*") + +# jump too big for + +test_re("(" + "a" * 62 + ")+") + +# jump too big for | +test_re("b" * 63 + "|a") diff --git a/tests/extmod/ure_limit.py.exp b/tests/extmod/ure_limit.py.exp new file mode 100644 index 000000000..8353be536 --- /dev/null +++ b/tests/extmod/ure_limit.py.exp @@ -0,0 +1,7 @@ +Error +Error +Error +Error +Error +Error +Error diff --git a/tests/feature_check/async_check.py b/tests/feature_check/async_check.py index 0f6361cd1..727b7136a 100644 --- a/tests/feature_check/async_check.py +++ b/tests/feature_check/async_check.py @@ -1,3 +1,6 @@ # check if async/await keywords are supported async def foo(): await 1 + + +print("async") diff --git a/tests/feature_check/const.py b/tests/feature_check/const.py index db32e8c69..e5928f6d7 100644 --- a/tests/feature_check/const.py +++ b/tests/feature_check/const.py @@ -1 +1,2 @@ x = const(1) +print(x) diff --git a/tests/feature_check/native_check.py b/tests/feature_check/native_check.py index 3971d1355..4dc9754d0 100644 --- a/tests/feature_check/native_check.py +++ b/tests/feature_check/native_check.py @@ -2,3 +2,7 @@ @micropython.native def f(): pass + + +f() +print("native") diff --git a/tests/feature_check/set_check.py b/tests/feature_check/set_check.py index ec186cc5b..0c7612843 100644 --- a/tests/feature_check/set_check.py +++ b/tests/feature_check/set_check.py @@ -1,2 +1,2 @@ # check if set literal syntax is supported -{1} +print({1}) diff --git a/tests/net_inet/uasyncio_tcp_read_headers.py.exp b/tests/net_inet/uasyncio_tcp_read_headers.py.exp index c200238dc..932d2674c 100644 --- a/tests/net_inet/uasyncio_tcp_read_headers.py.exp +++ b/tests/net_inet/uasyncio_tcp_read_headers.py.exp @@ -5,6 +5,7 @@ b'Content-Length: 54' b'Connection: close' b'Vary: Accept-Encoding' b'ETag: "54306c85-36"' +b'Strict-Transport-Security: max-age=15768000' b'Accept-Ranges: bytes' close done diff --git a/tests/run-tests.py b/tests/run-tests.py index ae63f9a29..a5a9b6063 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -279,7 +279,7 @@ def run_tests(pyb, tests, args, result_dir): # Check if micropython.native is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "native_check.py") - if output == b"CRASH": + if output != b"native\n": skip_native = True # Check if arbitrary-precision integers are supported, and skip such tests if it's not @@ -294,7 +294,7 @@ def run_tests(pyb, tests, args, result_dir): # Check if set type (and set literals) is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "set_check.py") - if output == b"CRASH": + if output != b"{1}\n": skip_set_type = True # Check if slice is supported, and skip such tests if it's not @@ -304,12 +304,12 @@ def run_tests(pyb, tests, args, result_dir): # Check if async/await keywords are supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "async_check.py") - if output == b"CRASH": + if output != b"async\n": skip_async = True # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not output = run_feature_check(pyb, args, base_path, "const.py") - if output == b"CRASH": + if output != b"1\n": skip_const = True # Check if __rOP__ special methods are supported, and skip such tests if it's not @@ -334,10 +334,10 @@ def run_tests(pyb, tests, args, result_dir): upy_byteorder = run_feature_check(pyb, args, base_path, "byteorder.py") upy_float_precision = run_feature_check(pyb, args, base_path, "float.py") - if upy_float_precision == b"CRASH": - upy_float_precision = 0 - else: + try: upy_float_precision = int(upy_float_precision) + except ValueError: + upy_float_precision = 0 has_complex = run_feature_check(pyb, args, base_path, "complex.py") == b"complex\n" has_coverage = run_feature_check(pyb, args, base_path, "coverage.py") == b"coverage\n" cpy_byteorder = subprocess.check_output( diff --git a/tools/ci.sh b/tools/ci.sh index 53cf7f878..c018b5500 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -82,24 +82,37 @@ function ci_cc3200_build { ######################################################################################## # ports/esp32 -function ci_esp32_setup { +function ci_esp32_setup_helper { git clone https://github.com/espressif/esp-idf.git - git -C esp-idf checkout v4.0.2 + git -C esp-idf checkout $1 git -C esp-idf submodule update --init \ components/bt/controller/lib \ components/bt/host/nimble/nimble \ - components/esp_wifi/lib_esp32 \ + components/esp_wifi \ components/esptool_py/esptool \ components/lwip/lwip \ components/mbedtls/mbedtls ./esp-idf/install.sh } +function ci_esp32_idf402_setup { + ci_esp32_setup_helper v4.0.2 +} + +function ci_esp32_idf43_setup { + ci_esp32_setup_helper v4.3-beta2 +} + function ci_esp32_build { source esp-idf/export.sh make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/esp32 submodules make ${MAKEOPTS} -C ports/esp32 + make ${MAKEOPTS} -C ports/esp32 clean + make ${MAKEOPTS} -C ports/esp32 USER_C_MODULES=../../../examples/usercmodule/micropython.cmake + if [ -d $IDF_PATH/components/esp32s2 ]; then + make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S2 + fi } ######################################################################################## @@ -181,6 +194,8 @@ function ci_rp2_build { make ${MAKEOPTS} -C mpy-cross git submodule update --init lib/pico-sdk lib/tinyusb make ${MAKEOPTS} -C ports/rp2 + make ${MAKEOPTS} -C ports/rp2 clean + make ${MAKEOPTS} -C ports/rp2 USER_C_MODULES=../../examples/usercmodule/micropython.cmake } ######################################################################################## @@ -207,7 +222,7 @@ function ci_stm32_pyb_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 submodules git submodule update --init lib/btstack - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 USER_C_MODULES=../../examples/usercmodule CFLAGS_EXTRA="-DMODULE_CEXAMPLE_ENABLED=1 -DMODULE_CPPEXAMPLE_ENABLED=1" + make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 USER_C_MODULES=../../examples/usercmodule make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF6 NANBOX=1 MICROPY_BLUETOOTH_NIMBLE=0 MICROPY_BLUETOOTH_BTSTACK=1 make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBV10 CFLAGS_EXTRA='-DMBOOT_FSLOAD=1 -DMBOOT_VFS_LFS2=1' diff --git a/tools/metrics.py b/tools/metrics.py index 25acb30f5..98291e25a 100755 --- a/tools/metrics.py +++ b/tools/metrics.py @@ -65,7 +65,7 @@ port_data = { "s": PortData("stm32", "stm32", "build-PYBV10/firmware.elf", "BOARD=PYBV10"), "c": PortData("cc3200", "cc3200", "build/WIPY/release/application.axf", "BTARGET=application"), "8": PortData("esp8266", "esp8266", "build-GENERIC/firmware.elf"), - "3": PortData("esp32", "esp32", "build-GENERIC/application.elf"), + "3": PortData("esp32", "esp32", "build-GENERIC/micropython.elf"), "r": PortData("nrf", "nrf", "build-pca10040/firmware.elf"), "d": PortData("samd", "samd", "build-ADAFRUIT_ITSYBITSY_M4_EXPRESS/firmware.elf"), }