No. 981 eng-blog gh-rel-micropython 75
PWM on alif and stm32, new machine.CAN API, t-strings and weakref module
This release of MicroPython sees machine.PWM support finally added to the stm32 port, as well as the alif port. This rounds out PWM support to all Tier 1 and Tier 2 microcontroller-based ports, making it easy to create and control PWM outputs in a consistent way. A new…
embedded iot diy
15 min read open original ↗
This release of MicroPython sees machine.PWM support finally added to the stm32 port, as well as the alif port. This rounds out PWM support to all Tier 1 and Tier 2 microcontroller-based ports, making it easy to create and control PWM outputs in a consistent way.
A new machine.CAN class that has been in development for a couple of years has now been finalised in this release, with added documentation, a common set of bindings, comprehensive tests, and an implementation for the stm32 port. This is a big step forward for a consistent way to use CAN across all of the ports, and implementations for other ports will follow soon.
This release also sees the addition of template strings as per PEP 750 https://peps.python.org/pep-0750/. Template strings (or t-strings) are similar to f-strings, allowing expressions within the string literal. But unlike f-strings, t-strings do not concatenate the pieces of the literal, rather they remain as separate components within a Template object. MicroPython's t-strings match CPython almost exactly, except for a few minor differences (the a/ascii conversion specifier and space after a conversion specifier are not supported). Template strings are enabled at the "full feature" level, which includes the alif, mimxrt, samd (SAMD51 only) and webassembly (pyscript variant) ports.
The t-string parsing code is an extension of the existing f-string parser, and in order to support nested t-string, f-strings now also support nested f-strings: f-strings within expressions within f-string literals.
Another Python feature added in this release is the weakref module with weakref.ref and weakref.finalize classes. These classes allow registering a callback to be called when an object is reclaimed by the garbage collector. The semantics of this follow very closely the weakref semantics in CPython (except for the fact that MicroPython does not use reference counting). Due to the memory and garbage collector overhead, this module is currently only enabled on the webassembly pyscript variant, although it can be manually enabled on any port if needed.
An outline of MicroPython's design values has been added to the main README. This aims to put into words some of the more intangible aspects of the project, in the hope that it will help strengthen and maintain those values moving forward. All MicroPython users and developers are encouraged to read these values, which can be found at https://github.com/micropython/micropython/blob/master/README.md#micropython-design-values
In the native emitter component, the RISC-V 32-bit emitter has a new architecture flag "zcmp" which can be enabled for RV32 targets that support compressed instructions. When this flag is enabled, Zcmp opcodes are used for function prologues and epilogues. There have also been some optimisations to generated native code, as well as added support for inline Xtensa assembler on windowed cores (like the esp32). Furthermore, it's now possible to configure MicroPython (at build time) to be able to load native code from .mpy files without having the native emitter enabled.
As usual, work has continued on the test suite, making it more robust to target failures, better able to skip tests that can't run on a target, and run consistently across a broader range of targets. All these things help maintain the high quality of the MicroPython code base.
ROM filesystem support and the VfsRom class have been enabled on a few more ports, namely: mimxrt, nrf, renesas-ra and samd (both SAMD21 and SAMD51).
The alif port sees the alif_ensemble-cmsis-dfp library updated to v1.3.4, support to put external flash to sleep, and improved support for deepsleep power saving modes, with wake-up from deepsleep via a falling GPIO or RTC alarm (the latter is available by the standard timeout_ms argument to machine.deepsleep()). As mentioned above, this port now has PWM support via the standard machine.PWM interface, and provides the freq(), duty_u16() and duty_ns() methods as well as the invert keyword argument in the PWM constructor. There are 11 independent timers with 22 PWM outputs.
The esp32 port adds a new LDO driver, and enables Zcmp opcodes, both for ESP32-P4 SoCs. os.dupterm() reading has been improved (it's no longer necessary to call os.dupterm_notify()) and various bugs have been fixed. Support for ESP-IDF from v5.3 and up to v5.5.1 has been consolidated, and support for IDF below v5.3 has now been dropped.
The mimxrt port now implements the standard machine.Counter and machine.Encoder classes, and adds a few new features such as: min/max counter values, index, reset and match pins, support for cycle counting and support for IRQ callbacks. The general documentation and mimxrt quick reference has been updated to describe these additions. This port has also updated the nxp_driver SDK to MCUX_2.16.100, added PSRAM support, added support for DP83867 PHY Ethernet, and increased the resolution of the RTC from 1 second to 1/32768 seconds.
The rp2 port has updated pico-sdk to its 2.2.0 release, and as part of this switched all RNG sources from ROSC to the new pico_rand component. This port has also enabled Zcmp opcodes for RP2350 in RV32 mode.
As mentioned above, the stm32 port now has the standard machine.PWM class available, which works across all 14 MCU families supported by this port. The freq(), duty_u16() and duty_ns() methods are available, as well as output inversion. A heuristic is used to statically assign a TIM and channel to each pin that can support PWM, and the heuristic is chosen to maximise the number of independent PWM outputs. The new machine.CAN implementation is available on MCUs with either a bxCAN or FD-CAN peripheral, although flexible data-rates are not yet supported.
New boards added in this release are:
esp32 port: SPARKFUN_THINGPLUS_ESP32C5 and SEEED_XIAO_ESP32C6;
mimxrt port: PHYBOARD_RT1170;
rp2 port: CYTRON_NANOXRP_CONTROLLER, CYTRON_MOTION_2350_PRO, WAVESHARE_RP2350B_CORE, WAVESHARE_RP2040_LCD_0_96, WAVESHARE_RP2040_PLUS, WAVESHARE_RP2040_ZERO and SEEED_XIAO_RP2040;
stm32 port: NUCLEO_H753ZI and WEACTSTUDIO_MINI_STM32U585.
The change in code size since the previous release for select builds of various ports is (absolute and percentage change in the text section):
bare-arm: -52 -0.092%
minimal x86: -321 -0.173%
unix x64: -104 -0.012% (standard variant)
stm32: +7028 +1.782% (PYBV10 board)
esp32: +844 +0.048% (ESP32_GENERIC board)
mimxrt: +10072 +2.685% (TEENSY40 board)
renesas-ra: +1816 +0.289% (EK_RA6M2 board)
nrf: +1788 +0.947% (PCA10040 board)
rp2: +356 +0.104% (RPI_PICO board)
rp2: -1552 -0.172% (RPI_PICO2_W board)
samd: +3492 +1.288% (ADAFRUIT_ITSYBITSY_M4_EXPRESS board)
The leading causes of these changes in code size are:
bare-arm, minimal x86, unix x64: make some tuple and list helper- functions inline
stm32: add new machine.PWM and machine.CAN classes
esp32: use detailed error strings for TLS sockets, various small port-specific fixes
mimxrt: support for VfsRom filesystem, support for t-strings, add new machine.Counter and machine.Encoder classes
renesas-ra: support for VfsRom filesystem
nrf: support for VfsRom filesystem
rp2: switch RNG source to pico_rand, reduce footprint of pin structures
samd: support for VfsRom filesystem, support for t-strings
Thanks to everyone who contributed to this release: Alessandro Gatti, Algy Tynan, Alon Bar-Lev, Andrew Leech, Angus Gratton, Anson Mansfield, Antonio Galea, Artem Makarov, Chris Webb, Damien George, Daniël van de Giessen, Didier C, Dryw Wade, Elvis Pfutzenreuter, EngWill, FH, Fin Maaß, iabdalkader, Jack Whitham, Jacob Williams, Jeff Epler, jetpax, Jos Verlinde, Koudai Aono, Kwabena W. Agyeman, Matt Trentini, Matthias Urlichs, mdaeron, Michel Le Bihan, Ned Konz, Oliver Joos, Paul Grayson, Peter Harper, Phil Howard, robert-hh, stijn, sync-on-luma, Thomas Kiss, Thomas Propst, Yuuki NAGAO.
MicroPython is a global Open Source project, and contributions were made from the following timezones: -0800, -0700, -0600, -0500, -0400, -0300, +0000, +0100, +0200, +0300, +0800, +0900, +1000, +1100.
The work done in this release was funded in part through GitHub Sponsors, and in part by George Robotics, Espressif, Arduino, OpenMV, and Planet Innovation.
What follows is a detailed list of changes, generated from the git commit history, and organised into sections.
Main components
all:
fix spelling of Micropython -> MicroPython
use enum instead of bool argument to mp_handle_pending
remove warning about the project being in beta stage
add a section describing MicroPython's values
py core:
misc: remove unused mp_check function
emitnative: optimise register clearing
asmrv32: reserve a flag for the Zcmp RV32 CPU extension
asmrv32: use Zcmp opcodes for function prologues and epilogues
persistentcode: decouple native code loading from emitters' presence
persistentcode: detect the target architecture from compiler defines
emitglue: flush caches when loading native code without emitters
misc: add byte-swapping macros
emitglue: check for bytecode with MICROPY_PY_FUNCTION_ATTRS_CODE
mpconfig: enable MICROPY_PY_FUNCTION_ATTRS_CODE when marshal enabled
persistentcode: support saving functions with children
objfun: support code on functions with children
vstr: make vstr_ins_byte/char functions inline to reduce code size
vstr: add vstr_ins_strn helper function
vstr: don't check for byte_len>0 in vstr_ins_blank_bytes
lexer: use null char as lexer EOF sentinel
lexer: add support for nested f-strings within f-strings
lexer: move f-string completion code to more logical location
runtime: make import-all support non-modules via dict/all
runtime: reorder mp_handle_pending_behaviour_t enum
runtime: rename mp_handle_pending_internal to mp_handle_pending
misc: remove unused CHECKBUF macros
objmodule: move decl of mp_obj_module_get_globals to objmodule.h
objfun: move decl of mp_obj_fun_get_name to objfun.h
objfun: rename mp_obj_fun_get_name to mp_obj_fun_bc_get_name
objlist: move all list helper declarations to objlist.h
objlist: make three list helper functions inline
objtuple: move all tuple helper declarations to objtuple.h
objtuple: make mp_obj_tuple_get an inline function
emitinlinextensa: refactor handling of selected opcodes
objarray: avoid double zero init on sized bytearrays
objstr: avoid double zero init on sized bytes
stream: use detailed error strings for TLS sockets
objzip: adjust zip iter code to not use mp_obj_tuple_del
objtuple: remove unused mp_obj_tulpe_del function
gc: trace all marked heads in debug log
gc: differentiate between root and subtree pointers for debug log
misc: fix truncating cast to char
emitinlinextensa: add inline assembler support for windowed cores
emitinlinextensa: refactor handling of selected narrow opcodes
asmthumb: do not clobber index register on viper load/store
asmrv32: do not clobber index register on viper load/store
objtype: expose mp_native_base_init_wrapper_obj
objexcept: check for incompletely constructed exceptions
objstr: factor code with a helper function to create empty str/bytes
objstr: fix b"".hex() so it returns an empty str object
lexer: fix parsing of f'{{'
add support for PEP 750's t-strings
objlist: add helpers for creating/ensuring list args
objtemplate: correctly cast qstr literals when printing
modweakref: implement weakref module with ref and finalize classes
emitglue: fix macro logic that selects cache flushing code
extmod:
modopenamp: rework trace buffer setup procedure
modselect: handle pending events before entering poll
modlwip: fix latent bug with partially created socket object
modlwip: adjust logic for determining a listening socket
modlwip: narrow error_lookup_table type to int8_t
modlwip: keep TCP data on remote RST
modmarshal: support marshal.dumps of functions with children
ensure stream ioctl's are a no-op for unknown requests
modlwip: always set the lwip_socket_ioctl() return value
vfs_reader: process pending events during file reads
modos: raise an error at a negative argument of os.urandom()
mbedtls: factor out mbedtls_hardware_poll() to common code
keep LWIP timer running if lwip poll_sockets() is called
add generic machine.CAN helpers & docs
machine_pwm: fix use of object when pointer is needed
nimble/modbluetooth_nimble: handle port init failures
modlwip: ensure socket is finalisable if error during creation
modlwip: call user callback on newly-received UDP or RAW packet
shared:
readline: handle \r and \n correctly as a newline
drivers: no changes specific to this component/port
mpy-cross:
mpconfigport: explicitly disable native code loading
enable t-strings
lib:
nxp_driver: update mimxrt SDK to MCUX_2.16.100
pico-sdk: update pico-sdk to 2.2.0 release
libhydrogen: update to latest release
alif_ensemble-cmsis-dfp: update to v1.3.4
micropython-lib: update submodule to latest
cyw43-driver: update driver to latest version v1.1.1
Support components
docs:
library/network.WLAN: fix typo for ESP32 protocol constants
library: document that sleep(0)/sleep_ms(0) run the scheduler
mimxrt: add docs for mimxrt.Flash
library/network.PPP: document the optional poll() argument
develop/writingtests: document parameters of run_test.py
add documentation for the mimxrt Encoder/Counter class
library: document string.templatelib module
esp32: replace 'esptool.py' by 'esptool' in command line example
library/re: document non-capturing grouping
add generic machine.CAN helpers & docs
library/machine.PWM: add alif,stm32 to list of ports with invert
library/machine.PWM: document hardware PWM layout
update copyright year range to include 2026
reference/speed_python: update native emitter limitations
library/weakref: add documentation for weakref module
examples: no changes specific to this component/port
tests:
ports/esp32/check_err_str.py: preallocate global variable
basics/string_fstring.py: test fstring nested replacement fields
run-tests.py: skip list sort stress test for ESP8266
extmod/vfs_blockdev_invalid.py: handle low memory conditions
target_wiring: provide an ESP8266 target wiring module
run-tests.py: discover RV32 extension inlineasm tests
run-natmodtests.py: explicitly open prelude file
basics/try_finally: fix try/finally flow tests under CPython 3.14
float/math_fun: fix domain error tests with CPython 3.14
float/complex1.py: fix CPython 3.14 deprecation
run-tests.py: re-add stress_schedule.py for GitHub Actions
thread/stress_schedule.py: decrease backoff time
micropython: add new schedule_sleep.py test
run-tests.py: re-enable some asyncio tests for the native emitter
thread/stress_schedule.py: remove decorator/inaccurate comment
multi_net/tcp_client_rst.py: improve and extend test
factor out common helper functions to separate Python module
multi_net: skip all ssl/tls tests on axTLS
multi_net: use random.getrandbits instead of random.randrange
extmod/machine_spi_rate.py: use target wiring for SPI instances
target_wiring: add SPI instance for mimxrt, nrf, renesas-ra, samd
target_wiring/README: add README describing target_wiring specs
run-tests.py: exit with error code 2 if test runner fails
test_utils.py: abort test if serial port fails at start
run-tests.py: abort test run if enter_raw_repl fails many times
run-tests.py: broaden the check for raw REPL failure
micropython: add a test for checking viper value clobbering
extmod/os_urandom.py: add test for os.urandom
micropython: add a test for throwing incomplete exception
cpydiff: add a section for throwing incomplete exceptions
run-tests.py: add an argument for showing which tests would run
run-tests.py: make skip logic work irregardless of test path
run-tests.py: use normal discovery if tests dir passed explicitly
cmdline: make tests succeed irregardless of invocation path
run-tests.py: output consistent test file paths
run-multitests.py: improve error handling for communication error
net_inet: use the letsencrypt TLS root cert for all tests
run-internalbench.py: add option for running against CPython
extmod_hardware/machine_pwm.py: add alif pin config
basics/builtin_str_hex.py: remove corresponding .exp file
extmod_hardware/machine_encoder.py: add a MIMXRT configuration
extmod_hardware/machine_encoder.py: separate the connection test
extmod_hardware/machine_counter.py: separate the connection test
add full feature and coverage tests for PEP 750 template strings
run-tests.py: ignore known-flaky test failures
ports/stm32/can: update pyb.CAN tests for FDCAN
extmod_hardware/machine_pwm.py: round expected timing calculation
extmod_hardware/machine_pwm.py: add pin settings for stm32 port
extmod_hardware/machine_pwm.py: convert test to use target_wiring
basics: add tests for weakref.ref and weakref.finalize
basics: add test for weakref having exception in callback
feature_check/tstring.py: remove check for string.templatelib
tools:
mpy_ld.py: fix R_RISCV_GOT32_PCREL handling
mpy_ld.py: fix handling of R_RISCV_TLSDESC_LOAD_LO12
mpy_ld.py: add RV64 natmod support
ci.sh: run natmod tests as part of CI for Unix/RV64
ci.sh: put embedding build rules in ci.sh
ci.sh: update Unix/MIPS target to Ubuntu 24.04 LTS
ci.sh: update Unix/Arm target to Ubuntu 24.04 LTS
ci.sh: use CPython 3.11 for Unix/RV64
ci.sh: update Unix/x86 target to Ubuntu 24.04 LTS
mpy_ld.py: optimise MPY trampoline sizes if possible
mpy_ld.py: write architecture flags to output natmod if needed
codeformat.py: use input files when formatting python code
ci.sh: increase qemu_arm test run timeout
CI:
workflows: bump actions/upload-artifact from 4 to 6
workflows: bump actions/cache from 4 to 5
workflows: introduce and use ci_esp32_idf_ver helper
workflows: add esp32 to code size report
workflows: use same Ubuntu for code_size as ports_esp32
workflows: bump actions/cache from 4 to 5
workflows: add check for misspelling of "MicroPython"
install Python 3.11 for Windows CI runs
workflows: bump actions/upload-artifact from 6 to 7
add a Generative AI Usage declaration to the PR template
revert "Run esp32&zephyr daily to keep mstr branch caches hot"
build oldest & newest ESP-IDF versions in CI
The ports
all ports:
remove incorrect and unnecessary mp_handle_pending declaration
refactor os.urandom()
don't pass -nostdlib in CFLAGS
alif port:
Makefile: do not hardcode the python interpreter name
Makefile: enable job server support on Ubuntu LTS
ospi_flash: remove workaround for P10_7 OSPI pinmux issue
boards/OPENMV_AE3: update romfs partition size
boards/OPENMV_AE3: make JTAG pins controllable as GPIOs
fix ALIF_TOOLS to use $(TOP) and remove unused ALIF_CONFIG
modmachine: disable IRQs before going to sleep
ospi_flash: add ospi_flash_sleep helper function
boards/OPENMV_AE3: save power upon deepsleep
boards/OPENMV_AE3: allow user button to wake from sleep
boards/ALIF_ENSEMBLE: add all SW1 pins and enable pull-ups on them
boards/ALIF_ENSEMBLE: add an off-profile
machine_rtc: factor out RTC helper functions
modmachine: implement timeout_ms argument to deepsleep
boards/OPENMV_AE3: configure sensor interrupts as GPIO input
machine_pwm: implement machine.PWM
irq: add missing IRQ priorities
bare-arm port: no changes specific to this component/port
cc3200 port:
mods/pybpin: reduce footprint of AF pin structures
embed port: no changes specific to this component/port
esp8266 port:
boards/ESP8266_GENERIC: remove OTA board variant
modesp: allocate executable memory when needed
esp32 port:
boards/ESP32_GENERIC_S3: reinstate old FLASH_4M variant
machine_sdcard: fix SDMMC slot assignment for non-default slots
mpconfigport: enable Zcmp opcodes for ESP32P4
machine_pin: rename legacy CONFIG_ESP32_SPIRAM_SUPPORT option
machine_uart: change default UART(1) pins on ESP32 with SPIRAM
esp32_rmt: update FIXME on RMT module
modesp32: update available RTC pins for ESP32C6
add LDO driver for ESP32-P4
mphalport: actually read from dupterm in mp_hal_stdin_rx_chr()
increase minimum CMake version to 3.16
fix linker errors with CMake <3.25 and libbtree
esp32_rmt: release GIL while waiting for TX done
only check the lockfile currently used by the build
drop support for ESP-IDF