Can't build on x64 for use with RP2040
Hi! The issue linked in the README blocking use on RP2040 looks to be resolved as a few weeks ago, but the deployment artifact is from last summer. I'm super interested on trying this project out on an RP2040, so I tried building it myself but ran into problems:
(.venv) devon@ESO-3-DEV-VM:~/Documents/bray_airways/noreaster/lib_source/emlearn-micropython$ make dist ARCH=armv6m MPY_DIR=/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython
make -C src/emlearn_trees/ ARCH=armv6m MPY_DIR=/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython V=1 clean dist
make[1]: Entering directory '/home/devon/Documents/bray_airways/noreaster/lib_source/emlearn-micropython/src/emlearn_trees'
/usr/lib/gcc/arm-none-eabi/6.3.1/thumb/v6-m/libgcc.a
/bin/rm -rf build _arm_cmpsf2.o lesf2.o _arm_fixsfsi.o fixsfsi.o eqsf2.o gesf2.o _arm_addsubsf3.o _arm_muldivsf3.o addsf3.o _clzsi2.o _udivsi3.o floatsisf.o divsf3.o _thumb1_case_uqi.o
/bin/mkdir -p build/
arm-none-eabi-ar -x /usr/lib/gcc/arm-none-eabi/6.3.1/thumb/v6-m/libgcc.a _arm_cmpsf2.o lesf2.o _arm_fixsfsi.o fixsfsi.o eqsf2.o gesf2.o _arm_addsubsf3.o _arm_muldivsf3.o addsf3.o _clzsi2.o _udivsi3.o floatsisf.o divsf3.o _thumb1_case_uqi.o
GEN build/emlearn_trees.config.h
python3 /home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py '-vvv' --arch armv6m --preprocess -o build/emlearn_trees.config.h trees.c trees.py
CC trees.c
arm-none-eabi-gcc -I. -I/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython -std=c99 -Os -Wall -Werror -DNDEBUG -DNO_QSTR -DMICROPY_ENABLE_DYNRUNTIME -DMP_CONFIGFILE='<build/emlearn_trees.config.h>' -fpic -fno-common -U _FORTIFY_SOURCE -mthumb -mcpu=cortex-m0 -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_NONE -I/home/devon/Documents/bray_airways/noreaster/.venv/lib/python3.10/site-packages/emlearn -o build/trees.o -c trees.c
LINK _arm_cmpsf2.o
python3 /home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py '-vvv' --arch armv6m --qstrs build/emlearn_trees.config.h -o build/emlearn_trees.native.mpy _arm_cmpsf2.o lesf2.o _arm_fixsfsi.o fixsfsi.o eqsf2.o gesf2.o _arm_addsubsf3.o _arm_muldivsf3.o addsf3.o _clzsi2.o _udivsi3.o floatsisf.o divsf3.o _thumb1_case_uqi.o build/trees.o
qstr vals: __del__, addleaf, addnode, addroot, emltrees, new, predict, setdata
sections:
00000008 .text size=116
0000007c .text size=132
00000100 .text size=64
00000140 .text size=76
0000018c .text size=128
0000020c .text size=16
0000021c .text size=804
00000540 .text size=60
0000057c .text size=276
00000690 .text size=160
00000730 .text size=656
000009c0 .rodata size=128
00000a40 .text size=20
00000a54 .text size=1488
00000000 .bss size=112
00001024 .data.rel.ro size=80
00001074 .data.rel.ro.local size=40
0000109c .rodata.str1.1 size=236
00001188 GOT size=20
GOT: 00001188
00000000 mp_fun_table -> .external+00000000
00000004 mp_native_qstr_table -> .external.qstr_table+00000000
00000008 eml_error_strs -> .data.rel.ro.local+00001084
0000000c trees_builder_type -> .bss+00000030
00000010 trees_locals_dict_table -> .bss+00000000
_arm_cmpsf2.o: .text relocations via .rel.text:
00000012 __lesf2 -> 0000007d
00000022 __eqsf2 -> 00000141
0000002e __lesf2 -> 0000007d
00000042 __lesf2 -> 0000007d
00000056 __gesf2 -> 0000018d
0000006a __gesf2 -> 0000018d
_arm_addsubsf3.o: .text relocations via .rel.text:
00000214 __aeabi_fadd -> 0000021d
addsf3.o: .text relocations via .rel.text:
0000026c __clzsi2 -> 00000541
_udivsi3.o: .text relocations via .rel.text:
00000680 __aeabi_idiv0 -> 00000f45
floatsisf.o: .text relocations via .rel.text:
000006a0 __clzsi2 -> 00000541
divsf3.o: .text relocations via .rel.text:
00000814 __clzsi2 -> 00000541
0000082c __clzsi2 -> 00000541
Traceback (most recent call last):
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 1093, in <module>
main()
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 1089, in main
do_link(args)
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 1060, in do_link
link_objects(env, len(native_qstr_vals))
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 850, in link_objects
do_relocation_text(env, sec.addr, r)
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 595, in do_relocation_text
assert 0, r_info_type
AssertionError: 2
/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/py/dynruntime.mk:149: recipe for target 'build/emlearn_trees.native.mpy' failed
make[1]: *** [build/emlearn_trees.native.mpy] Error 1
make[1]: Leaving directory '/home/devon/Documents/bray_airways/noreaster/lib_source/emlearn-micropython/src/emlearn_trees'
Makefile:14: recipe for target 'dist/armv6m_6.3/emlearn_trees.mpy' failed
make: *** [dist/armv6m_6.3/emlearn_trees.mpy] Error 2
The micropython version is the lastest, so that being out of date isn't the problem (I don't think)...
I modified mpy_ld.py to log some more info. In that function do_relocation_text:
env.arch.name = EM_ARM
r_info_type = 2
The ELF constant for 2 is R_386_PC32. Is the issue that I'm trying to build the armv6m version on an x86 box?
Best, Devon
Hi @esologic and thank you for the report.
There are built versions for armv6m (RP2040 and other ARM Cortex M0+), for MicroPython 1.23 available at https://github.com/emlearn/emlearn-micropython/tree/gh-pages/builds/master/armv6m_6.3 - the latest modules are those with emlearn_ in the name.
The exception you get is likely it is what is tracked in https://github.com/micropython/micropython/issues/14430 I currently use a fork of MicroPython with the fix provided there as a patch. See https://github.com/jonnor/micropython/commit/2cecbb531a3a5844eae2344167c0fd8a53ad4c61 So that is needed to build emlearn-micropython for ARM, at the moment. I will try to get that upstream.
Btw, branch for updating to MicroPython 1.24 is here: #21
Thanks so much -- I'll be giving this a shot maybe Friday/Sat of this week and I'll follow up.
I tried running the examples and tests with MicroPython 1.24 on RP2040 now, using the prebuilt .mpy files for armv6m on master. At the moment they are hanging when calling the emlearn-micropython C modules. It happens both for har_trees (using emlearn_trees) and soundlevel_iir (using emlearn_arrayutils and emlearn_iir). This problem does not appear on ESP32, so there seems to be an architecture specific problem.
However, I am unable to debug this right now, due to some other deadlines.
Took another stab at building tonight. To summarize
- I checked out
emlearn-micropythonto the commit referenced above,350191838f38dfa9992648f3c2a9f68fed7e4174. - I updated my micropython version to the
v1.24.0tag,f212bbe837489f297c9d25d608bdb7b8c3da988d. - I updated my ARM build toolchain from
6.3.1->13.3.1. It actually turns out the version in ARM's PPA is very outdated, and one needs to download and symlink the prebuilt executables to get access them.
No dice, I get a very similar error to the original:
(.venv) devon@ESO-3-DEV-VM:~/Documents/bray_airways/noreaster/lib_source/emlearn-micropython$ make dist ARCH=armv6m MPY_DIR=/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython V=2
make -C src/emlearn_trees/ ARCH=armv6m MPY_DIR=/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython V=1 clean dist
make[1]: Entering directory '/home/devon/Documents/bray_airways/noreaster/lib_source/emlearn-micropython/src/emlearn_trees'
/opt/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/thumb/v6-m/nofp/libgcc.a
/bin/rm -rf build _arm_cmpsf2.o lesf2.o _arm_fixsfsi.o fixsfsi.o eqsf2.o gesf2.o _arm_addsubsf3.o _arm_muldivsf3.o addsf3.o _clzsi2.o _udivsi3.o floatsisf.o divsf3.o _thumb1_case_uqi.o
/bin/mkdir -p build/
arm-none-eabi-ar -x /opt/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.3.1/thumb/v6-m/nofp/libgcc.a _arm_cmpsf2.o lesf2.o _arm_fixsfsi.o fixsfsi.o eqsf2.o gesf2.o _arm_addsubsf3.o _arm_muldivsf3.o addsf3.o _clzsi2.o _udivsi3.o floatsisf.o divsf3.o _thumb1_case_uqi.o
GEN build/emlearn_trees.config.h
python3 /home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py '-vvv' --arch armv6m --preprocess -o build/emlearn_trees.config.h trees.c trees.py
CC trees.c
arm-none-eabi-gcc -I. -I/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython -std=c99 -Os -Wall -Werror -DNDEBUG -DNO_QSTR -DMICROPY_ENABLE_DYNRUNTIME -DMP_CONFIGFILE='<build/emlearn_trees.config.h>' -fpic -fno-common -U _FORTIFY_SOURCE -mthumb -mcpu=cortex-m0 -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_NONE -I/home/devon/Documents/bray_airways/noreaster/.venv/lib/python3.10/site-packages/emlearn -o build/trees.o -c trees.c
LINK _arm_cmpsf2.o
python3 /home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py '-vvv' --arch armv6m --qstrs build/emlearn_trees.config.h -o build/emlearn_trees.native.mpy _arm_cmpsf2.o lesf2.o _arm_fixsfsi.o fixsfsi.o eqsf2.o gesf2.o _arm_addsubsf3.o _arm_muldivsf3.o addsf3.o _clzsi2.o _udivsi3.o floatsisf.o divsf3.o _thumb1_case_uqi.o build/trees.o
qstr vals: __del__, addleaf, addnode, addroot, emltrees, new, predict, setdata
sections:
00000008 .text size=116
0000007c .text.__lesf2 size=144
0000010c .text.__aeabi_f2iz size=64
0000014c .text.__eqsf2 size=80
0000019c .text.__gesf2 size=148
00000230 .text size=16
00000240 .text.__aeabi_fadd size=832
00000580 .text size=60
000005bc .text size=276
000006d0 .text.__aeabi_i2f size=148
00000764 .text.__aeabi_fdiv size=548
00000988 .rodata.__aeabi_fdiv size=124
00000a04 .text size=20
00000a18 .text size=1428
00000000 .bss size=112
00000fac .rodata.str1.1 size=236
00001098 .data.rel.ro size=80
000010e8 .data.rel.ro.local size=40
00001110 GOT size=20
GOT: 00001110
00000000 mp_fun_table -> .external+00000000
00000004 mp_native_qstr_table -> .external.qstr_table+00000000
00000008 eml_error_strs -> .data.rel.ro.local+000010f8
0000000c trees_builder_type -> .bss+00000030
00000010 trees_locals_dict_table -> .bss+00000000
_arm_cmpsf2.o: .text relocations via .rel.text:
00000012 __lesf2 -> 0000007d
00000022 __eqsf2 -> 0000014d
0000002e __lesf2 -> 0000007d
00000042 __lesf2 -> 0000007d
00000056 __gesf2 -> 0000019d
0000006a __gesf2 -> 0000019d
_arm_addsubsf3.o: .text relocations via .rel.text:
00000238 __aeabi_fadd -> 00000241
addsf3.o: .text.__aeabi_fadd relocations via .rel.text.__aeabi_fadd:
000002fe __clzsi2 -> 00000581
_udivsi3.o: .text relocations via .rel.text:
000006c0 __aeabi_idiv0 -> 00000ed1
floatsisf.o: .text.__aeabi_i2f relocations via .rel.text.__aeabi_i2f:
000006e0 __clzsi2 -> 00000581
divsf3.o: .text.__aeabi_fdiv relocations via .rel.text.__aeabi_fdiv:
0000084a __clzsi2 -> 00000581
0000086c __clzsi2 -> 00000581
Traceback (most recent call last):
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 1093, in <module>
main()
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 1089, in main
do_link(args)
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 1060, in do_link
link_objects(env, len(native_qstr_vals))
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 850, in link_objects
do_relocation_text(env, sec.addr, r)
File "/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/tools/mpy_ld.py", line 595, in do_relocation_text
assert 0, r_info_type
AssertionError: 2
/home/devon/Documents/bray_airways/noreaster/micropython_firmware/micropython/py/dynruntime.mk:149: recipe for target 'build/emlearn_trees.native.mpy' failed
make[1]: *** [build/emlearn_trees.native.mpy] Error 1
make[1]: Leaving directory '/home/devon/Documents/bray_airways/noreaster/lib_source/emlearn-micropython/src/emlearn_trees'
Makefile:14: recipe for target 'dist/armv6m_6.3/emlearn_trees.mpy' failed
make: *** [dist/armv6m_6.3/emlearn_trees.mpy] Error 2
I also tried building on an ARM system to see if this yielded any other info, and the error is very similar there as well.
As for the prebuilt .mpy files not working -- if there's anything I can try on my end let me know.
The (proposed) fix for the ARM relocation is not in 1.24.0, so the patch still needs to be applied separately. The branch I use can be found here, https://github.com/jonnor/micropython/tree/emlearn-micropython-v1.24-1 Without this, it is expected to get the linker error you see. However, it is an open question whether this patch is actually correct... There are both comments in https://github.com/micropython/micropython/issues/14430 indicating that it worked, but also one that it hangs the device.
So the hanging observed on RP2040 may (or may not) be related to this patch. One probably needs to dig out a debugger to see what goes wrong. And maybe try to compare with module code which does not create this type of relocation.
Ahh I see, my bad for misreading.
I tried again using the branch you linked and I was able to build emlearn_trees.mpy which is great.
However I did run into the same hanging behavior when running through the xor example:
.venv) devon@studio-nuc:~/Documents/noreaster$ mpremote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] or Ctrl-x to exit this shell
>>> import os
>>> os.listdir("./")
['assumptions_check.py', 'deploy.py', 'emlearn_trees.mpy', 'main.py', 'main_prod.py', 'main_test.py', 'noreaster', 'setup.py', 'tesla_cooler', 'xor_model.csv']
>>> import emlearn_trees
>>> import array
>>> model = emlearn_trees.new(5, 30, 2)
>>> # Load a CSV file with the model
>>> with open('xor_model.csv', 'r') as f:
... emlearn_trees.load_model(model, f)
...
>>> max_val = (2**15-1) # 1.0 as int16
>>> examples = [
... array.array('h', [0, 0]),
... array.array('h', [max_val, max_val]),
... array.array('h', [0, max_val]),
... array.array('h', [max_val, 0]),
... ]
>>>
>>> for ex in examples:
... result = model.predict(ex)
... print(ex, result)
...
I tried building the firmware.uf2 for the RP2 port and flashing it from your branch as well to see if it changed the behavior. It also hangs at the same place, after the .predict call.
I'll watch: https://github.com/micropython/micropython/issues/14430 for updates.
Happy new year @jonnor -- I'm getting back into this related project, are there any experiments and tests I could try to answer questions you have related to this issue?
Hi @esologic - happy new year. There are no ready experiements at this point. What we need to create is some minimal reproducing module code and build, which we can provide on the MicroPython issue, so that the people there can help out in creating a proper patch. I will try to do this in the coming weeks.
Seems that getting soft-float for native modules to work on Cortex M0+ etc is quite difficult, ref https://github.com/micropython/micropython/issues/14430#issuecomment-2744431299
So it looks like RP2040 will not really work as native modules. Instead, we like need to support building into the firmware using the user C module instead #18
We now have basic support for external module build, and I have given this some very quick testing on RP2040.
For anyone wanting to test, there is a pre-built binary for RP2040 for the RPI Pico here https://github.com/emlearn/emlearn-micropython/tree/gh-pages/builds/master/ports/rp2/RPI_PICO The .uf2 can be dropped onto USB drive, and then one can import emlearn_trees and other modules, and run the examples (in git).
Initial documentation on how to build with external modules can be found at https://emlearn-micropython.readthedocs.io/en/latest/external_modules.html This is a more complicated way of installing, but unfortunately there is no support for in MicroPython for relocations on arm6vm, so we are stuck with this for the time being.
There is now an MR for natmod linking support for armv6m. https://github.com/micropython/micropython/pull/17377 It works for me with some brief testing. Reopening since natmods is what this project is designed for
Above MR was merged in MicroPython. We now use it for the CI builds of emlearn-micropython (https://github.com/emlearn/emlearn-micropython/pull/44). So now there are .mpy files for armv6m available. Example: https://emlearn.github.io/emlearn-micropython/builds/master/armv6m_6.3/emlearn_trees.mpy
Testing would be appreciated!