MicroPython v1.24
RP2350 lands, RISC-V grows up, ESP32-C6 arrives, and TinyUSB CDC code is unified across five ports.
Released October 26, 2024
RP2350 & ESP32-C6
v1.24 brings up two important new chips. RP2350 is the headline: Raspberry Pi's successor to the RP2040, with both ARM and RISC-V cores on the same die, in 30- and 48-pin variants. ESP32-C6 is Espressif's RISC-V chip with WiFi 6 and 802.15.4 (Thread / Zigbee).
@micropython.native → Thumb v1@micropython.asm_thumbThe RP2350 ships with both an ARM Cortex-M33 and a RISC-V Hazard3 core pair on the same die. The bootrom selects which cores to wake at startup, controlled by the firmware build. v1.24 lands MicroPython support for both modes.
ESP32-C6
RISC-V + WiFi 6
Espressif's RISC-V SoC with WiFi 6 and 802.15.4 (Thread / Zigbee). v1.24
enables the RV32IMC native emitter on both C3 and C6, so
@micropython.native-decorated functions compile to tight RISC-V
machine code on these chips.
RP2350 details
pico-sdk v2.0.0- 30- and 48-pin variants — both supported.
- IPv6 enabled by default on the rp2 port.
- USB stays active during
machine.lightsleep(). - Optional
network.PPP— lwIP-based, opt-in. - RP2040 still fully supported — same firmware family, just a new board.
RISC-V 32-bit Native Emitter
MicroPython has had native code generation for ARM, Thumb, Xtensa and x86/x64
for years. v1.24 adds RV32IMC: @micropython.native
now compiles directly to RISC-V machine code, no interpretation. Decorated
functions land in .mpy files (and can be frozen) just like other
architectures. v1.24 also adds RISC-V NLR and GC register-scanning, plus
semihosting for testing under qemu.
RV32 native emitter port support
import micropython @micropython.native def crc16(data, init=0xffff): crc = init for b in data: crc ^= b for _ in range(8): crc = (crc >> 1) ^ 0xa001 if crc & 1 else crc >> 1 return crc & 0xffff # On RP2350 (RV mode) and ESP32-C3/C6, this compiles to RV32IMC. # On RP2040 / RP2350 (ARM mode), it compiles to Thumb. # On Xtensa esp32 / S2 / S3, Xtensa LX6 / LX7.
qemu-arm port has been renamed to just qemu and now
supports both ARM and RISC-V. It runs tests via a pty serial port —
emulating bare-metal targets — which makes architecture-portable testing
much more practical.
micropython.RingIO — Thread-Safe Ring Buffer
A new built-in class providing an efficient, byte-oriented ring buffer with a stream interface. Thread-safe, fixed allocation, no GC pressure at runtime — ideal for producer/consumer patterns between an ISR and the main loop, between cores, or between the REPL and a background task. Try it below in your browser.
RingIO is a stream — you can read(),
write(), and readinto() just like a file. The
buffer is fixed-size and FIFO; reads block (in a real port) when empty.
In a real-world MicroPython program, RingIO shines in scenarios
where one side runs in an interrupt handler (a hard IRQ, even). The fixed
allocation means no heap pressure, and the implementation is reentrant on
every supported port.
network.ipconfig() — IPv6-aware Network Config
v1.24 introduces network.ipconfig() at module level and
nic.ipconfig() on individual interfaces. The new API supports
IPv4 and IPv6 with much more control than the legacy
nic.ifconfig(). The old API still works (backwards compatibility),
but new code should prefer ipconfig().
ifconfig() — IPv4 onlyimport network nic = network.WLAN(network.STA_IF) nic.active(True) nic.connect("ssid", "pw") # Tuple shape: (ip, mask, gw, dns) nic.ifconfig(( "192.168.1.50", "255.255.255.0", "192.168.1.1", "8.8.8.8", )) print(nic.ifconfig())
ipconfig() — v1.24+, IPv4 + IPv6import network nic = network.WLAN(network.STA_IF) nic.active(True) nic.connect("ssid", "pw") # Keyword args; pick what you need nic.ipconfig( addr4=("192.168.1.50", "255.255.255.0"), gw4="192.168.1.1", dhcp4=False, ) network.ipconfig(dns="2606:4700:4700::1111") # IPv6 DNS print(nic.ipconfig("addr4")) print(nic.ipconfig("addr6"))
network.PPP class based on lwIP is also available in v1.24.
Not enabled by default, but boards that already use bare-metal lwIP can opt in
— the rp2 port already exposes it as an option, and stm32 follows.
TinyUSB CDC unification & portable UART IRQ API
Five ports that previously each had their own TinyUSB integration now share common helper code for CDC serial. As a side effect, the REPL banner and initial prompt are buffered until host connection — so the first thing you see when you connect is the banner, not silence.
Most ports also gain a portable UART IRQ API. Register Python
callbacks for IRQ_RX, IRQ_RXIDLE,
IRQ_TXIDLE and IRQ_BREAK with consistent semantics
across the family.
Unified TinyUSB CDC
Portable UART.irq()
from machine import UART uart = UART(0, baudrate=115200) def on_rx(u): print("got", u.read()) uart.irq(handler=on_rx, trigger=UART.IRQ_RX | UART.IRQ_RXIDLE)
Python language tweaks
Three core-language changes in v1.24, including a breaking change
to sys.exit(). Pick one from the dropdown to load the example,
then run it live.
await a
Task or Event at module top level. This means a
<script type="mpy"> block can do
result = await some_task() directly, with no
asyncio.run() wrapping. PyScript also gained
JsProxy identity reuse, attribute lookup without existence checks,
and JS iterable proxying.
Highlights
Other notable improvements in v1.24.
esp32 firmware shrank by 53 kB
The IDF v5.0.5 -> v5.2.2 update plus internal cleanup gives back over 50 kB of flash on every esp32 build (-3.10%). Big win for memory-constrained boards.
mpremote hash-based recursive copy
New mpremote sha256sum command, plus recursive copy that
first hashes and only updates files that differ. Large-app sync becomes
fast.
SoftSPI LSB mode
machine.SoftSPI now supports least-significant-bit-first
ordering, in addition to MSB.
sys.exit() — breaking change
Now triggers a soft reset of the device instead of just dropping to the REPL. Brings bare-metal in line with the unix port. May impact applications that relied on the old behaviour.
STM32H7 OctoSPI
OctoSPI memory-mapped flash support on STM32H7 MCUs. New
ARDUINO_OPTA stm32 board.
stm32: code in RAM for UART REPL
Build option places IRQ + flash + UART code in RAM, enabled on boards with a UART REPL so filesystem operations don't drop characters during flashing (e.g. when copying files via mpremote).
Arduino + NXP SE05x secure element
ARDUINO_PORTENTA_H7 and ARDUINO_NICLA_VISION gain
SE05x integration via mbedTLS — hardware-backed crypto.
zephyr v3.7 + threading
Zephyr port updated to v3.7.0; threading via _thread is now
implemented. REPL is non-blocking. _thread tests now pass.
Big-int support enabled.
zephyr device-tree object construction
Construct machine objects (Pin, I2C, SPI…) directly
from device-tree node labels, no more hard-coded peripheral indices.
qemu: ARM + RISC-V, with REPL
The qemu port runs both architectures via a pty-based REPL, mirroring how real bare-metal tests work. Tests that previously needed a board can now run in CI.
esp32: TCP socket cap
Hard limit on active TCP sockets prevents resource exhaustion when applications open sockets in quick succession.
webassembly FFI improvements
JsProxy gains iterable-protocol proxying, identity reuse, no-existence-test attribute lookup, and configurable pystack size. Top-level await of Task / Event (covered in the language section above).
New Boards
10 new board definitions, weighted heavily toward ESP32-C6 and RP2350-class boards.
esp32
rp2
stm32
By the Numbers
v1.24 in numbers. esp32 firmware actually shrank by 53 kB after the ESP-IDF cleanup — the only port-shrink across the five recent releases.