Skip to content

pkg/micropython: incorporate port#22350

Open
basilfx wants to merge 7 commits into
RIOT-OS:masterfrom
basilfx:feature/micropython_port
Open

pkg/micropython: incorporate port#22350
basilfx wants to merge 7 commits into
RIOT-OS:masterfrom
basilfx:feature/micropython_port

Conversation

@basilfx

@basilfx basilfx commented Jun 5, 2026

Copy link
Copy Markdown
Member

Contribution description

The MicroPython version was contributed by @kaspar030 in 2019. It is based on ~v1.11 of MicroPython. The latest version available is v1.28, which was release April 2026.

I chatted with @kaspar030 about this port, but he isn't going to update/maintain his version anymore. It was once created with the goal to upstream it (see micropython/micropython#1249). That PR got closed, where the maintainers stated that this port can better live inside RIOT-OS (or, at least not in MicroPython) for maintainability reasons.

This PR basically takes the existing port, upgrades it to be compatible with v1.28, stripped parts that have built-in alternatives nowadays and polished up the documentation. No upstream patches necessary (anymore). No new features have been added/enabled.

Most files did not have the proper copyright and doxygen headers. Files without copyright headers have the default LGPL 2.1 license added (discussed with @kaspar030). @bergzand contributed ADC and SPI support, and I got his permission to relicense it from MIT (MicroPython's default license) to LGPL 2.1. That leaves a few files that have started off as copies from other ports, but changed so significantly that I replaced these licenses with LGPL 2.1 too (modmachine.c, machine_adc.c and mpconfigport.h).

My ultimate use-case is embedding MicroPython into my KNX actors, as a 'logic engine'. Whether that will work out or not: the current state is old and won't see any updates. This PR makes it at least more vanilla to work on.

Testing procedure

Compile make -C examples/lang_support/community/micropython, then run the test with make -C examples/lang_support/community/micropython test.

I have yet to test on actual hardware, but so far so good.

Test output
/home/basilfx/source/RIOT/RIOT_micropython/examples/lang_support/community/micropython/bin/native64/micropython.elf  tap0
RIOT native interrupts/signals initialized.
TZ not set, setting UTC
RIOT native64 board initialized.
RIOT native hardware initialization complete.

main(): This is RIOT! (Version: 2026.07-devel-299-gef4bcd-RIOT_micropython_v1.28)
-- Executing boot.py
boot.py: MicroPython says hello!
-- boot.py exited. Starting REPL..
MicroPython v1.28.0 on 2026-06-05; riot-native64 with native
Type "help()" for more information.
>>> print("echo this! " * 4)
print("echo this! " * 4)
echo this! echo this! echo this! echo this!
>>> help()
help()
Welcome to the MicroPython RIOT port!

Quick overview of commands for the board:
  (none so far)

Control commands:
  CTRL-A        -- on a blank line, enter raw REPL mode
  CTRL-B        -- on a blank line, enter normal REPL mode
  CTRL-C        -- interrupt a running program
  CTRL-D        -- on a blank line, do a soft reset of the board
 (all probably not working in this initial port)

For further help on a specific object, type help(obj)
>>> import riot
print(riot.thread_getpid())
import riot
>>> print(riot.thread_getpid())
2
>>> import time
import time
mp_import_stat() stub
mp_import_stat() stub
>>> time.ticks_ms()
time.ticks_ms()
3302
>>> time.sleep_ms(0)
time.sleep_ms(0)
>>> time.ticks_ms()
time.ticks_ms()
3405
>>> test_sleep(0, 1000): slept 103ms
time.ticks_ms()
time.ticks_ms()
3456
>>> time.sleep_ms(50)
time.sleep_ms(50)
>>> time.ticks_ms()
time.ticks_ms()
3608
>>> test_sleep(50, 113): slept 152ms
time.ticks_ms()
time.ticks_ms()
3659
>>> time.sleep_ms(250)
time.sleep_ms(250)
>>> time.ticks_ms()
time.ticks_ms()
4011
>>> test_sleep(250, 113): slept 352ms
time.ticks_ms()
time.ticks_ms()
4062
>>> time.sleep_ms(500)
time.sleep_ms(500)
>>> time.ticks_ms()
time.ticks_ms()
4664
>>> test_sleep(500, 113): slept 602ms
import xtimer
import xtimer
>>> a = 0
a = 0
>>> def inc_a(): global a; a+=1
def inc_a(): global a; a+=1
...

>>> t = xtimer.xtimer(inc_a)
t = xtimer.xtimer(inc_a)
>>> time.ticks_ms()
time.ticks_ms()
4969
>>> t.set(500000)
t.set(500000)
>>> while a==0: pass
while a==0: pass
...

>>> time.ticks_ms()
time.ticks_ms()
5571
>>> [TEST PASSED]

Issues/PRs references

#22306 highlighted an issue when trying to compile the MicroPython example. MicroPython was still compiled with -std=gnu99, which does not support static_assert(..). This assertion was added to check CONFIG_* values in headers. This triggered me to get started on this.

Declaration of AI-Tools / LLMs usage:

AI-Tools / LLMs that were used are:

  • Claude Code for upgrading the old version to MicroPython v1.28
  • Claude Code for assessing the differences in upstreamed ports and this one

@github-actions github-actions Bot added Area: doc Area: Documentation Area: pkg Area: External package ports Area: examples Area: Example Applications labels Jun 5, 2026
@bergzand

bergzand commented Jun 5, 2026

Copy link
Copy Markdown
Member

@bergzand contributed ADC and SPI support, and I got his permission to relicense it from MIT (MicroPython's default license) to LGPL 2.1.

Confirmation from my side on the relicense!

@crasbe crasbe added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: update This issue suggests updateable parts / The PR updates parts of the codebase/packages labels Jun 5, 2026
@riot-ci

riot-ci commented Jun 5, 2026

Copy link
Copy Markdown

Murdock results

FAILED

aaea3a3 fixup! pkg/micropython: incorporate port

Success Failures Total Runtime
11116 1 11122 09m:53s
Build failures (1)
Application Target Toolchain Runtime (s) Worker
examples/lang_support/community/micropython samr21-xpro llvm 10.68 mobi3

Artifacts

Comment thread pkg/micropython/doc.md Outdated
Comment thread pkg/micropython/doc.md Outdated
Comment thread pkg/micropython/doc.md Outdated
Comment thread pkg/micropython/include/micropython.h Outdated
Comment thread pkg/micropython/include/micropython.h Outdated
Comment thread pkg/micropython/contrib/machine_hw_spi.c Outdated
Comment thread pkg/micropython/contrib/machine_hw_spi.c Outdated
Comment thread pkg/micropython/contrib/machine_adc.c Outdated
Comment thread pkg/micropython/contrib/machine_adc.c Outdated
Comment thread pkg/micropython/Makefile
@basilfx

basilfx commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

@crasbe Thanks again for the review, I will process it tonight and start testing on actual hardware.

basilfx added 6 commits June 18, 2026 01:09
This is version c7e947df88cf5b05f9e20dbeb10d5b4a9eae65a6 from
https://github.com/kaspar030/micropython, upgraded to work with v1.28.
Then, the code was modified to use built-in alternatives, that are now
possible.

License headers were added where missing. MIT licenses have been
replaced with LGPL versions: these files started off as copies of
existing ports, but they are significantly modified for RIOT-OS and
they are not part of (a potential upstream of) RIOT-OS to
MicroPython.

Assisted-by: Claude Code Opus 4.8
- Replace mp_do_str with built-in alternative
- Fix and extens tests
@basilfx basilfx force-pushed the feature/micropython_port branch from 413d637 to a6f6032 Compare June 17, 2026 23:10
@basilfx

basilfx commented Jun 17, 2026

Copy link
Copy Markdown
Member Author

I was able to run the MicroPython test suite on the board, and it is looking promising. I could even remove the patch to slow down the serial communication, probably due to the stdin module that is now used.

24 tests failed: basics/builtin_enumerate.py basics/builtin_range.py basics/class_store_class.py basics/fun_callstardblstar.py basics/lexer.py basics/list_compare.py basics/list_slice_3arg.py basics/list_slice_assign.py basics/namedtuple1.py basics/string_crlf_conversion.py basics/struct_endian.py basics/tuple_compare.py extmod/machine_spi_rate.py extmod/marshal_stress.py micropython/heapalloc_exc_compressed.py micropython/heapalloc_exc_compressed_emg_exc.py micropython/heapalloc_fail_bytearray.py micropython/heapalloc_fail_memoryview.py micropython/heapalloc_slice.py misc/non_compliant.py stress/gc_trace.py stress/list_sort.py stress/qstr_limit.py stress/recursive_iternext.py

(out of 469 tests).

For comparison, the official MicroPython port for the Raspberry Pi Pico had 9 failing tests (out of 925 tests - more hardware related tests).

Will look into what I can fix in this PR, given that the previous version wasn't perfect either.

@basilfx

basilfx commented Jun 17, 2026

Copy link
Copy Markdown
Member Author

@crasbe I still have to deal with all the defines and includes. Not sure how to handle that neatly, yet.

@basilfx

basilfx commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

Down to only 2 failed tests, and even more additional tests enabled.

I did have to enable additional modules to make the basic set of tests pass. I'll find a balance between code size and feature parity.

#endif
#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new
#ifdef CONFIG_NETWORKING
#define MICROPY_PY_UERRNO (1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define MICROPY_PY_UERRNO (1)
# define MICROPY_PY_UERRNO (1)

Comment thread pkg/micropython/doc.md
Comment thread pkg/micropython/doc.md
Comment thread pkg/micropython/doc.md
Comment on lines +50 to +53
## MicroPython modules

Currently, the port enables only a subset of the available MicroPython
modules. See `contrib/mpconfigport.h` for details.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you activated more modules, this can probably be more specific 🤔

Comment thread pkg/micropython/doc.md
Comment on lines +62 to +63
You can import these modules and then use `help(<module name>)` to get more
information.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>>> import riot
import riot
>>> help(riot)
help(riot)
object <module 'riot'> is of type module
  __name__ -- riot
  thread_getpid -- <function>
>>> import xtimer
import xtimer
>>> help(xtimer)
help(xtimer)
object <module 'xtimer'> is of type module
  __name__ -- xtimer
  xtimer -- <class 'xtimer'>

Is that how it's supposed to work? Not super helpful 👀

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added __doc__, but it will still be limited.

>>> help(xtimer)
object <module 'xtimer'> is of type module
  __name__ -- xtimer
  __doc__ -- RIOT xtimer module - microsecond hardware timers
  xtimer -- <class 'xtimer'>

>>> help(machine)
object <module 'umachine'> is of type module
  __name__ -- umachine
  __doc__ -- RIOT machine module - low-level hardware access (reset, Pin, SPI, ADC)
  reset -- <function>
  reset_cause -- <function>
  Pin -- <class 'Pin'>
  SPI -- <class 'SPI'>
  ADC -- <class 'ADC'>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For comparison:

>>> help(math)
object <module 'math'> is of type module
  __name__ -- math
  e -- 2.7182818
  pi -- 3.1415928
  sqrt -- <function>
  ...
  trunc -- <function>
  radians -- <function>
  degrees -- <function>

Comment thread pkg/micropython/Makefile
Comment on lines +14 to +15
# Ensure the directory exists before any other package compiles with this INCLUDES
$(shell mkdir -p $(BINDIR)/pkg-build/micropython)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should live in the pkg/micropython/Makefile, not the pkg/micropython/Makefile.include 🤔

@basilfx

basilfx commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

MicroPython's own README.md stick with a minimum of 256 KiB and 16 KiB of RAM. Current builds for Cortex M0-4 range somewhere between 160-190 KiB. Original port tried to squeeze it in 128 KiB, but that was some years ago.

I favor for a good first impression. MicroPython's own test suite is quite broad, but I can now pass almost all tests.

Maybe in a follow-up version, we can do something like LWIP does, to more selectively enable/disable MicroPython modules. Then it should definitely be possible to shave many kilobytes off.

@basilfx

basilfx commented Jun 20, 2026

Copy link
Copy Markdown
Member Author

I hit a small roadblock: the ISR part.

The original port mentioned that xtimer callbacks (e.g. x = xtimer.xtimer(func); x.set(5 sec)) would be handled in ISR space. That has changed since version 1.11, rendering the current implementation not working. Also, doing anything in ISR space will basically freeze it up.

The 'fix' is using the scheduling module. The ISR schedules work, so the main loop handles this later. This is a bit problematic: the main loop in REPL mode will block on reading from stdin. During regular byte code execution, work is automatically picked up.

For the REPL mode, I need to set a read timeout, then handle the work, and continue. But I hope I can make this somewhat smarter.

Oh, and then there is the (synchronous) sleep methods too, which have to deal with interrupts too (or not).

@basilfx basilfx added the AI: Helped PR/Issue uses AI sparingly, e.g. code inline assistant, debugging with AI, etc. label Jul 6, 2026
@crasbe crasbe added the State: waiting for other PR State: The PR requires another PR to be merged first label Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Helped PR/Issue uses AI sparingly, e.g. code inline assistant, debugging with AI, etc. Area: doc Area: Documentation Area: examples Area: Example Applications Area: pkg Area: External package ports CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR State: waiting for other PR State: The PR requires another PR to be merged first Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Type: update This issue suggests updateable parts / The PR updates parts of the codebase/packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants