MicroPython on Zephyr - i.MXRT1060
Not having looked at the MicroPython "port" for the Zephyr operating system, I decided to check the current state of it. Having an MIMXRT1060-EVK on my desk, I decided to try it on this platform.
After updating the git repositories for MicroPython and Zephyr, I
tried building the port this board. This is as easy as entering the
ports/zephyr
directory and building the Zephyr application in this directory:
dzu@krikkit:/opt/src/git/micropython (master)$ cd ports/zephyr
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (master)$ west build -b mimxrt1060_evk/mimxrt1062/qspi
-- west build: generating a build system
Loading Zephyr default modules (Zephyr base).
-- Application: /opt/src/git/micropython/ports/zephyr
-- CMake version: 3.31.5
-- Found Python3: /usr/bin/python3 (found suitable version "3.13.1", minimum required is "3.10") found components: Interpreter
-- Cache files will be written to: /home/dzu/.cache/zephyr
-- Zephyr version: 4.0.99 (/opt/src/git/zephyrproject/zephyr)
-- Found west (found suitable version "1.3.0", minimum required is "0.14.0")
-- Board: mimxrt1060_evk, Revision: A, qualifiers: mimxrt1062/qspi
-- Found host-tools: zephyr 0.16.8 (/opt/zephyr-sdk-0.16.8)
-- Found toolchain: zephyr 0.16.8 (/opt/zephyr-sdk-0.16.8)
-- Found Dtc: /opt/zephyr-sdk-0.16.8/sysroots/x86_64-pokysdk-linux/usr/bin/dtc (found suitable version "1.6.0", minimum required is "1.4.6")
-- Found BOARD.dts: /opt/src/git/zephyrproject/zephyr/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi.dts
-- Generated zephyr.dts: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/zephyr.dts
-- Generated pickled edt: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/edt.pickle
-- Generated devicetree_generated.h: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/include/generated/zephyr/devicetree_generated.h
-- Including generated dts.cmake file: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/dts.cmake
/opt/src/git/micropython/ports/zephyr/prj.conf:32: warning: attempt to assign the value 'n' to the undefined symbol NET_SOCKETS_POSIX_NAMES
Parsing /opt/src/git/micropython/ports/zephyr/Kconfig
Loaded configuration '/opt/src/git/zephyrproject/zephyr/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_defconfig'
Merged configuration '/opt/src/git/micropython/ports/zephyr/prj.conf'
error: Aborting due to Kconfig warnings
CMake Error at /opt/src/git/zephyrproject/zephyr/cmake/modules/kconfig.cmake:396 (message):
command failed with return code: 1
Call Stack (most recent call first):
/opt/src/git/zephyrproject/zephyr/cmake/modules/zephyr_default.cmake:133 (include)
/opt/src/git/zephyrproject/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:66 (include)
/opt/src/git/zephyrproject/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:92 (include_boilerplate)
CMakeLists.txt:27 (find_package)
-- Configuring incomplete, errors occurred!
FATAL ERROR: command exited with status 1: /usr/bin/cmake -DWEST_PYTHON=/usr/bin/python3 -B/opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi -GNinja -DBOARD=mimxrt1060_evk/mimxrt1062/qspi -S/opt/src/git/micropython/ports/zephyr
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (master)$
Ok, so obviously things do not run out of the box, but looking at the problems, I think they are caused by changes for Zephyr v4.0. Luckily, the required changes are small and so I committed them to the fixes-for-zephyr-4.0 branch in my fork of the MicroPython repository. Retrying with that looks much better:
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$ west build -b mimxrt1060_evk/mimxrt1062/qspi
-- west build: generating a build system
Loading Zephyr default modules (Zephyr base (cached)).
-- Application: /opt/src/git/micropython/ports/zephyr
-- CMake version: 3.31.5
-- Cache files will be written to: /home/dzu/.cache/zephyr
-- Zephyr version: 4.0.99 (/opt/src/git/zephyrproject/zephyr)
-- Found west (found suitable version "1.3.0", minimum required is "0.14.0")
-- Board: mimxrt1060_evk, Revision: A, qualifiers: mimxrt1062/qspi
-- Found host-tools: zephyr 0.16.8 (/opt/zephyr-sdk-0.16.8)
-- Found toolchain: zephyr 0.16.8 (/opt/zephyr-sdk-0.16.8)
-- Found BOARD.dts: /opt/src/git/zephyrproject/zephyr/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi.dts
-- Generated zephyr.dts: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/zephyr.dts
-- Generated pickled edt: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/edt.pickle
-- Generated devicetree_generated.h: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/include/generated/zephyr/devicetree_generated.h
-- Including generated dts.cmake file: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/dts.cmake
Parsing /opt/src/git/micropython/ports/zephyr/Kconfig
Loaded configuration '/opt/src/git/zephyrproject/zephyr/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_defconfig'
Merged configuration '/opt/src/git/micropython/ports/zephyr/prj.conf'
Configuration saved to '/opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/.config'
Kconfig header saved to '/opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/include/generated/zephyr/autoconf.h'
-- Found GnuLd: /opt/zephyr-sdk-0.16.8/arm-zephyr-eabi/arm-zephyr-eabi/bin/ld.bfd (found version "2.38")
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- The ASM compiler identification is GNU
-- Found assembler: /opt/zephyr-sdk-0.16.8/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
Load components for MIMXRT1062:
driver_common component is included.
driver_reset component is included.
device_CMSIS component is included.
CMSIS_Include_core_cm component is included.
device_system component is included.
driver_trng component is included.
driver_enet component is included.
driver_lpuart component is included.
driver_igpio component is included.
driver_cache_armv7_m7 component is included.
driver_ocotp component is included.
-- Using ccache: /usr/bin/ccache
-- Found Python3: /usr/bin/python3 (found version "3.13.1") found components: Interpreter
-- Configuring done (32.0s)
-- Generating done (0.4s)
-- Build files have been written to: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi
-- west build: building application
[1/439] Preparing syscall dependency handling
[3/439] cd /opt/src/git/micropython/ports/zephyr/buil...ild/mimxrt1060_evk/mimxrt1062/qspi/genhdr/mpversion.h
GEN /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/genhdr/mpversion.h
[4/439] Generating include/generated/zephyr/version.h
-- Zephyr version: 4.0.99 (/opt/src/git/zephyrproject/zephyr), build: v4.0.0-3656-g8394f623665d
[206/439] Generating genhdr/moduledefs.collected
Module registrations updated
[207/439] Generating genhdr/qstrdefs.collected.h
QSTR updated
[208/439] Generating genhdr/root_pointers.collected
Root pointer registrations updated
[406/439] Building C object CMakeFiles/micropython.dir/opt/src/git/micropython/lib/littlefs/lfs2.c.obj
/opt/src/git/micropython/lib/littlefs/lfs2.c:495:13: warning: 'lfs2_mlist_isopen' defined but not used [-Wunused-function]
495 | static bool lfs2_mlist_isopen(struct lfs2_mlist *head,
| ^~~~~~~~~~~~~~~~~
[439/439] Linking C executable zephyr/zephyr.elf
Memory region Used Size Region Size %age Used
FLASH: 295868 B 8 MB 3.53%
RAM: 97304 B 32 MB 0.29%
ITCM: 0 GB 128 KB 0.00%
DTCM: 13952 B 128 KB 10.64%
OCRAM: 0 GB 256 KB 0.00%
OCRAM2: 0 GB 512 KB 0.00%
IDT_LIST: 0 GB 32 KB 0.00%
Generating files from /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/zephyr.elf for board: mimxrt1060_evk
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$
Flashing the binary onto our target is easy with the PyOCD runner:
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$ west flash -d build/mimxrt1060_evk/mimxrt1062/qspi/ -r pyocd
-- west flash: rebuilding
[1/207] cd /opt/src/git/micropython/ports/zephyr/buil...ild/mimxrt1060_evk/mimxrt1062/qspi/genhdr/mpversion.h
-- west flash: using runner pyocd
-- runners.pyocd: Flashing file: build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/zephyr.hex
0001711 I Loading /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/zephyr.hex at 0x60000000 [load_cmd]
[==================================================] 100%
0044527 I Erased 327680 bytes (5 sectors), programmed 295936 bytes (1156 pages), skipped 0 bytes (0 pages) at 6.80 kB/s [loader]
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$
Looking at the console connection shows MicroPython is coming up:
*** Booting Zephyr OS build v4.0.0-3656-g8394f623665d ***
MicroPython v1.25.0-preview.298.gf87e8b35b on 2025-02-11; zephyr-mimxrt1060_evk with mimxrt1062
Type "help()" for more information.
>>> help()
Welcome to MicroPython!
For online docs please visit http://docs.micropython.org/
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
CTRL-E -- on a blank line, enter paste mode
For further help on a specific object, type help(obj)
>>>
Lighting LEDs
So having a REPL is nice, but of course we want to see something
happening on the board. The first thing usually is to light LEDs on
the board. Indeed the EVK has a green LED hooked up to the gpio1
controller at pin number 9, as can be seen from this device tree
excerpt:
dzu@krikkit:/opt/src/git/zephyrproject/zephyr (main)$ grep -A 4 green_led: boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dtsi
green_led: led-1 {
gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
label = "User LED1";
};
};
dzu@krikkit:/opt/src/git/zephyrproject/zephyr (main)$
Toggling it from MicroPython is done by using the Pin
class:
>>> from machine import Pin
>>> led = Pin(("gpio1", 9), Pin.OUT)
>>> led.value(1)
>>> led.value(0)
>>> led.value(1)
And indeed, the LED is low active, so it lights up after
led.value(0)
and turns off again after led.value(1)
.
PyBoard Tooling
The MicroPython project has its own tool pyboard.py
to interact with
a MicroPyhton board. So let's link that tool to a directory in our
path and try it out. Note that linking will relieve us from updating
the copy when pyboard.py
changes in the repository. Be sure to
close the connection to the serial port first.
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$ ln -s /opt/src/git/micropython/tools/pyboard.py ~/bin
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$ cd
dzu@krikkit:~$ pyboard.py -h
usage: pyboard.py [-h] [-d DEVICE] [-b BAUDRATE] [-u USER] [-p PASSWORD] [-c COMMAND] [-w WAIT]
[--soft-reset | --no-soft-reset] [--follow | --no-follow] [--exclusive | --no-exclusive]
[-f]
[files ...]
Run scripts on the pyboard.
positional arguments:
files input files
options:
-h, --help show this help message and exit
-d, --device DEVICE the serial device or the IP address of the pyboard
-b, --baudrate BAUDRATE
the baud rate of the serial device
-u, --user USER the telnet login username
-p, --password PASSWORD
the telnet login password
-c, --command COMMAND
program passed in as string
-w, --wait WAIT seconds to wait for USB connected board to become available
--soft-reset Whether to perform a soft reset when connecting to the board [default]
--no-soft-reset
--follow follow the output after running the scripts [default if no scripts given]
--no-follow
--exclusive Open the serial device for exclusive access [default]
--no-exclusive
-f, --filesystem perform a filesystem action: cp local :device | cp :device local | cat path | ls
[path] | rm path | mkdir path | rmdir path
dzu@krikkit:~$ pyboard.py -d /dev/ttyACM0 -c "help()"
Welcome to MicroPython!
For online docs please visit http://docs.micropython.org/
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
CTRL-E -- on a blank line, enter paste mode
For further help on a specific object, type help(obj)
dzu@krikkit:~$
Ok, so we can run programs without the need to use a serial terminal
program. That's good. pyboard.py
also has tools to manage files on
our board:
dzu@krikkit:~$ pyboard.py -d /dev/ttyACM0 -f ls
ls :
dzu@krikkit:~$
There are no files, but checking the situation, this is understandable, as neither SD card nor flash map support is enabled. Let's try to use an SD card.
Using SD Cards
The evalkit has an SD card slot populated, so all that is needed is to
enable the support in Zephyr. Luckily, all required options are
inferred if we set only CONFIG_DISK_ACCESS
to yes. As I am lazy, I
inject this directly into the build procedure:
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$ west build -p -b mimxrt1060_evk/mimxrt1062/qspi \
-- -DCONFIG_DISK_ACCESS=y
-- west build: generating a build system
Loading Zephyr default modules (Zephyr base).
-- Application: /opt/src/git/micropython/ports/zephyr
-- CMake version: 3.31.5
-- Found Python3: /usr/bin/python3 (found suitable version "3.13.1", minimum required is "3.10") found components: Interpreter
-- Cache files will be written to: /home/dzu/.cache/zephyr
-- Zephyr version: 4.0.99 (/opt/src/git/zephyrproject/zephyr)
-- Found west (found suitable version "1.3.0", minimum required is "0.14.0")
-- Board: mimxrt1060_evk, Revision: C, qualifiers: mimxrt1062/qspi
-- Found host-tools: zephyr 0.16.8 (/opt/zephyr-sdk-0.16.8)
-- Found toolchain: zephyr 0.16.8 (/opt/zephyr-sdk-0.16.8)
-- Found Dtc: /opt/zephyr-sdk-0.16.8/sysroots/x86_64-pokysdk-linux/usr/bin/dtc (found suitable version "1.6.0", minimum required is "1.4.6")
-- Found BOARD.dts: /opt/src/git/zephyrproject/zephyr/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi.dts
-- Found devicetree overlay: /opt/src/git/zephyrproject/zephyr/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_C.overlay
-- Generated zephyr.dts: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/zephyr.dts
-- Generated pickled edt: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/edt.pickle
-- Generated devicetree_generated.h: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/include/generated/zephyr/devicetree_generated.h
-- Including generated dts.cmake file: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/dts.cmake
Parsing /opt/src/git/micropython/ports/zephyr/Kconfig
Loaded configuration '/opt/src/git/zephyrproject/zephyr/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi_defconfig'
Merged configuration '/opt/src/git/micropython/ports/zephyr/prj.conf'
Merged configuration '/opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/misc/generated/extra_kconfig_options.conf'
Configuration saved to '/opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/.config'
Kconfig header saved to '/opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/include/generated/zephyr/autoconf.h'
-- Found GnuLd: /opt/zephyr-sdk-0.16.8/arm-zephyr-eabi/arm-zephyr-eabi/bin/ld.bfd (found version "2.38")
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- The ASM compiler identification is GNU
-- Found assembler: /opt/zephyr-sdk-0.16.8/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
Load components for MIMXRT1062:
driver_common component is included.
driver_reset component is included.
device_CMSIS component is included.
CMSIS_Include_core_cm component is included.
device_system component is included.
driver_trng component is included.
driver_enet component is included.
driver_lpuart component is included.
driver_igpio component is included.
driver_usdhc component is included.
driver_cache_armv7_m7 component is included.
driver_ocotp component is included.
-- Using ccache: /usr/bin/ccache
-- Found Python3: /usr/bin/python3 (found version "3.13.1") found components: Interpreter
-- Configuring done (7.5s)
-- Generating done (0.2s)
-- Build files have been written to: /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi
-- west build: building application
[1/450] Preparing syscall dependency handling
[3/450] Generating include/generated/zephyr/version.h
-- Zephyr version: 4.0.99 (/opt/src/git/zephyrproject/zephyr), build: v4.0.0-5122-gcb772b0f60c3
[4/450] cd /opt/src/git/micropython/ports/zephyr/buil...ild/mimxrt1060_evk/mimxrt1062/qspi/genhdr/mpversion.h
GEN /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/genhdr/mpversion.h
[5/450] Generating ../build_info.yml
-- Found Python3: /usr/bin/python (found suitable version "3.13.1", minimum required is "3.10") found components: Interpreter
-- Cache files will be written to: /home/dzu/.cache/zephyr
[215/450] Generating genhdr/moduledefs.collected
Module registrations updated
[218/450] Generating genhdr/root_pointers.collected
Root pointer registrations updated
[221/450] Generating genhdr/qstrdefs.collected.h
QSTR updated
[418/450] Building C object CMakeFiles/micropython.dir/opt/src/git/micropython/lib/littlefs/lfs2.c.obj
/opt/src/git/micropython/lib/littlefs/lfs2.c:495:13: warning: 'lfs2_mlist_isopen' defined but not used [-Wunused-function]
495 | static bool lfs2_mlist_isopen(struct lfs2_mlist *head,
| ^~~~~~~~~~~~~~~~~
[450/450] Linking C executable zephyr/zephyr.elf
Memory region Used Size Region Size %age Used
FLASH: 308268 B 8 MB 3.67%
RAM: 99096 B 32 MB 0.30%
ITCM: 0 GB 128 KB 0.00%
DTCM: 13952 B 128 KB 10.64%
OCRAM: 0 GB 256 KB 0.00%
OCRAM2: 0 GB 512 KB 0.00%
IDT_LIST: 0 GB 32 KB 0.00%
Generating files from /opt/src/git/micropython/ports/zephyr/build/mimxrt1060_evk/mimxrt1062/qspi/zephyr/zephyr.elf for board: mimxrt1060_evk
dzu@krikkit:/opt/src/git/micropython/ports/zephyr (fixes-for-zephyr-4.0)$
With a newly formatted SD card in the slot, we flash the new binary
and check on the console that we again get a prompt. I noticed that
the boot process now takes significantly longer. The "Booting Zephyr"
string appears only after 9 seconds and the prompt takes another 3-4
seconds to appear. I used a 2 GiB card, maybe the mounting of the
file system takes that long? But having the prompt, we can redo the
test with pyboard.py
(after disconnecting from the console):
zu@krikkit:~$ pyboard.py --device /dev/ttyACM0 -f ls /
ls :/
0 sd/
dzu@krikkit:~$
Indeed, we now see an sd
sub directory corresponding to the SD card
and we can transfer files easily with pyboard.py
. The file
main.py
is scanned at boot time and if found, its content will be
executed. So let's test this:
dzu@krikkit:~$ cat > /tmp/main.py
print("Hello world from main.py!")
dzu@krikkit:~$ pyboard.py --device /dev/ttyACM0 -f cp /tmp/main.py :/sd/
cp /tmp/main.py :/sd/
dzu@krikkit:~$ pyboard.py --device /dev/ttyACM0 -f cat /sd/main.py
cat :/sd/main.py
print("Hello world from main.py!")
dzu@krikkit:~$
Connecting to the console again and rebooting the board yields:
*** Booting Zephyr OS build v4.0.0-5122-gcb772b0f60c3 ***
Hello world from main.py!
MicroPython v1.25.0-preview.298.gf87e8b35b on 2025-02-12; zephyr-mimxrt1060_evk with mimxrt1062
Type "help()" for more information.
>>>
Hooray, this means we can now store a python script on the board and it will be automatically executed at boot time.
Of course long time Pythonistas will know this, but here is how you can check the file system from the board itself:
>>> import os
>>> os.listdir('/')
['sd']
>>> os.listdir('/sd')
['main.py']
>>> f=open('/sd/main.py')
>>> f.read()
'print("Hello world from main.py!")\n'
>>>
More info on the storage support is available at the MicroPython website.
Summary
MicroPython runs more or less out of the box on a randomly selected target of the supported Zephyr boards. Also file storage seems to work just fine on the Zephyr abstractions on the board I looked at. I would expect that this should work for other boards also.
Comments
Comments powered by Disqus