先人の情報を参考に、普通にNUCLEO_F401REとしてビルドしてみる。使った環境は、WSL上のUbuntu
$ uname -a Linux DESKTOP-TRNV8F8 5.10.16.3-microsoft-standard-WSL2 #1 SMP Fri Apr 2 22:23:49 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux sudo apt-get install libffi-dev gcc-arm-none-eabi cd ~/lang/up/stm32/src git clone https://github.com/micropython/micropython cd micropython make -C mpy-cross cd ports/stm32 make BOARD=NUCLEO_F401RE
なぜか分からないがエラーになった。HAL_Driverが無いと怒られているような。。
LINK build-NUCLEO_F401RE/firmware.elf arm-none-eabi-ld: cannot find build-NUCLEO_F401RE/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.o: No such file or directory arm-none-eabi-ld: cannot find build-NUCLEO_F401RE/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.o: No such file or directory arm-none-eabi-ld: cannot find build-NUCLEO_F401RE/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.o: No such file or directory arm-none-eabi-ld: cannot find build-NUCLEO_F401RE/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.o: No such file or directory 略
同じコマンドをもう一度実行したらHALのライブラリ?をコンパイルして、ビルドまで終わった。
$ make BOARD=NUCLEO_F401RE *略* LINK build-NUCLEO_F401RE/firmware.elf text data bss dec hex filename 301872 12 37408 339292 52d5c build-NUCLEO_F401RE/firmware.elf GEN build-NUCLEO_F401RE/firmware0.bin GEN build-NUCLEO_F401RE/firmware1.bin GEN build-NUCLEO_F401RE/firmware.dfu GEN build-NUCLEO_F401RE/firmware.hex
本来なら、ST-LINK等で、dfuかbinを焼くのだろう。。が、、UARTのポートが違ってるので修正が必要。
boards/NUCLEO_F401CCのディレクトリを作って、mpconfigboard.hを修正
$ diff ../NUCLEO_F401RE/mpconfigboard.h ./mpconfigboard.h 23a24,25 > #define MICROPY_HW_UART1_TX (pin_A9) > #define MICROPY_HW_UART1_RX (pin_A10) 26,30c28,29 < #define MICROPY_HW_UART6_TX (pin_C6) < #define MICROPY_HW_UART6_RX (pin_C7) < // UART 2 connects to the STM32F103 (STLINK) on the Nucleo board < // and this is exposed as a USB Serial port. < #define MICROPY_HW_UART_REPL PYB_UART_2 --- > > #define MICROPY_HW_UART_REPL PYB_UART_1
いけるかどうかわからないけど、以下でビルドしてみる
$ make BOARD=NUCLEO_F401CC
$ make BOARD=NUCLEO_F401CC *略* LINK build-NUCLEO_F401CC/firmware.elf text data bss dec hex filename 301900 12 37408 339320 52d78 build-NUCLEO_F401CC/firmware.elf GEN build-NUCLEO_F401CC/firmware0.bin GEN build-NUCLEO_F401CC/firmware1.bin GEN build-NUCLEO_F401CC/firmware.dfu GEN build-NUCLEO_F401CC/firmware.hex
エラー出ずにビルドできた。次はST-Linkを使って上記ファームを焼く
かつて、ST-Linkを使ってgdbとか動かしていたが、細かいことを忘れたので、ST-Link Utilityを使ってみる。
http://tri-s.world.coocan.jp/tri_S_Reference/ST_LINK/HowToUse_ST_LINK.pdf
STSW-LINK004|デザイン/サポート|STM32, STM8ファミリはSTの32bit/8bit汎用マイクロコントローラ製品
ST-Link Utilityを使って ST-Link経由でSTVAL-DRONE01上のSTM32F401CCにファームを焼こうとしたら、サイズがでかすぎると怒られた
20:43:48 : ST-LINK SN : 1847000000000000000 20:43:48 : V2J29S7 20:43:48 : Connected via SWD. 20:43:48 : SWD Frequency = 4,0 MHz. 20:43:48 : Connection mode : Normal. 20:43:48 : Debug in Low Power mode enabled. 20:43:48 : Device ID:0x423 20:43:48 : Device flash Size : 256KBytes 20:43:48 : Device family :STM32F401xB/C 20:46:51 : [firmware.hex] opened successfully. Address Ranges [0x08000000 0x080039D0] [0x08020000 0x08066188] 20:46:51 : [firmware.hex] checksum : 0x01BD7F18 20:47:43 : File size is bigger than the flash memory size.
Flashサイズが256KBなのだが、MicroPythonファームが294KBであった。はみ出ている。
機能削減して減らすか、最適化コンパイルして減らせられないものだろうか。。
ポーティングしているボードにはリソースの小さいのもあり、STM32L073RZT6の場合、flashメモリが192KBらしい。
NUCLEO_L073RZ/mpconfigboard.h
この場合、以下の機能が外されている。
#define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_OPT_COMPUTED_GOTO (0) #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_GENERATOR_PEND_THROW (0) #define MICROPY_PY_MATH (0) #define MICROPY_PY_FRAMEBUF (0) #define MICROPY_PY_USOCKET (0) #define MICROPY_PY_NETWORK (0) #define MICROPY_PY_ONEWIRE (0) #define MICROPY_PY_STM (0) #define MICROPY_PY_PYB_LEGACY (0) #define MICROPY_PY_UHEAPQ (0) #define MICROPY_PY_UTIMEQ (0) #define MICROPY_PY_MACHINE_BITSTREAM (0) #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) #define MICROPY_HW_ENABLE_ADC (0)
上記を参考にmpconfigboard.hを定義すればサイズが縮小化されるのでは?と期待
サイズ確認のため普通にビルドしてみる
make BOARD=NUCLEO_L073RZ
以下の通り、201KBに収まっているように思える。
$ make BOARD=NUCLEO_L073RZ *略* LINK build-NUCLEO_L073RZ/firmware.elf text data bss dec hex filename 194784 68 11748 206600 32708 build-NUCLEO_L073RZ/firmware.elf GEN build-NUCLEO_L073RZ/firmware.bin GEN build-NUCLEO_L073RZ/firmware.dfu GEN build-NUCLEO_L073RZ/firmware.hex
このファームだとエラーなく焼くことができた。(が、MicroPythonのREPL用のUARTポートが違っているのでこのままではPCとつながらない)
そのままdisable定義をCopyするだけだとビルド中にundefineシンボルとかでエラーになる。ソースは変更したくないので、エラーになった場合はenableに戻しながらコンパイルを通した。結果、以下のサイズにしかならず、これではサイズがでかいのでファームが焼けない。
$ make BOARD=NUCLEO_F401CC LINK build-NUCLEO_F401CC/firmware.elf text data bss dec hex filename 256088 8 37140 293236 47974 build-NUCLEO_F401CC/firmware.elf GEN build-NUCLEO_F401CC/firmware0.bin GEN build-NUCLEO_F401CC/firmware1.bin GEN build-NUCLEO_F401CC/firmware.dfu GEN build-NUCLEO_F401CC/firmware.hex
というわけで、build-NUCLEO_L073RZをベースにUARTのポートだけを書き換えてビルドしてみる
しかし、このやり方はSTM32のマイコンシリーズの系統を無視したビルドで、本来は以下のように定義されているL072/L073シリーズ用のピンマッピング情報やライブラリを無理にF401に適用している。だから??ピンアサイン(ピン多重化された機能の定義)とか無茶苦茶になっている可能性がある。
MCU_SERIES = l0 CMSIS_MCU = STM32L073xx AF_FILE = boards/stm32l072_af.csv LD_FILES = boards/stm32l072xz.ld boards/common_basic.ld
REPL用UARTの定義だけ修正してビルドした。先ほどのビルドと同様にFlashに乗りそうなサイズに収まった。
$ make BOARD=NUCLEO_L073RZ_KAI LINK build-NUCLEO_L073RZ_KAI/firmware.elf text data bss dec hex filename 194784 68 11748 206600 32708 build-NUCLEO_L073RZ_KAI/firmware.elf GEN build-NUCLEO_L073RZ_KAI/firmware.bin GEN build-NUCLEO_L073RZ_KAI/firmware.dfu GEN build-NUCLEO_L073RZ_KAI/firmware.hex
フラッシュは焼けた。あとは、、MicroPythonが正しく動いているかどうか。ST-Link + OpenOCDの組み合わせでデバッグもできるので、あまりビビる必要はないけど。。
コネクタP7からREPLのシリアルが出ているはずなのだが、応答がない。というわけで、、デバッグ
昔の記事と手元のメモを読み返しながら、、openocdを起動、ST-Link経由でターゲットと接続
$ ./bin-x64/openocd.exe -f ./scripts/interface/stlink-v2.cfg -f ./scripts/target/stm32f4x.cfg Open On-Chip Debugger 0.10.0 Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "hla_swd". To override u se 'transport select <transport>'. Info : The selected transport took over low-level target control. The results mi ght differ compared to plain JTAG/SWD adapter speed: 2000 kHz adapter_nsrst_delay: 100 none separate Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : clock speed 1800 kHz Info : STLINK v2 JTAG v29 API v2 SWIM v7 VID 0x0483 PID 0x3748 Info : using stlink api v2 Info : Target voltage: 3.152424 Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
$ ./arm-none-eabi-gdb.exe (gdb) target remote localhost:3333 Remote debugging using localhost:3333 0x00000000 in ?? () (gdb) monitor reset halt Unable to match requested speed 2000 kHz, using 1800 kHz Unable to match requested speed 2000 kHz, using 1800 kHz adapter speed: 1800 kHz target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x0802296c msp: 0x20004ff8 (gdb) info register r0 0x0 0 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x0 0x0 lr 0x0 0 pc 0x0 0x0 xPSR 0x0 0
読み取れる値が0ばっかりなのだが、、ターゲットとの接続エラーになっている??
OpenOCD側のログ
target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x0802296c msp: 0x20004ff8
gdbからもう一度haltをしてみる
(gdb) monitor reset halt Unable to match requested speed 2000 kHz, using 1800 kHz Unable to match requested speed 2000 kHz, using 1800 kHz adapter speed: 1800 kHz target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x0802296c msp: 0x20004ff8 (gdb) x/32w 0 0x0: 0x020004ff8 0x0802296d 0x0801dc01 0x0801dbf1 0x10: 0x00000000 0x00000000 0x00000000 0x00000000 0x20: 0x00000000 0x00000000 0x00000000 0x0801dc03 0x30: 0x00000000 0x00000000 0x0801df01 0x0801df31 0x40: 0x08022871 0x0801dc05 0x0801dc11 0x08022871 0x50: 0x08022871 0x0801dc65 0x0801dc75 0x0801dc85 0x60: 0x08022871 0x0801facd 0x0801fae1 0x0801fb01 0x70: 0x08022871 0x08022871 0x0801dcd3 0x0801dc97 (gdb) info register r0 0x20004ff8 536891384 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20004ff8 0x20004ff8 lr 0xffffffff -1 pc 0x8022972 0x8022972 xPSR 0x1000000 16777216 (gdb) x/32w $pc 0x8022972: 0x4a0c490c 0xe0034b0d 0x31046808 0x32046010 0x8022982: 0xd3f9429a 0x49092000 0xe0014a0a 0x31046008 0x8022992: 0xd3fb4291 0xff6df7ff 0xf7fa4620 0x4ff8ff7a 0x80229a2: 0xf8e02000 0x00000802 0x00442000 0x00442000 0x80229b2: 0x06282000 0x60042000 0x60866045 0x464160c7 0x80229c2: 0x46496101 0x46516141 0x46596181 0x466161c1 0x80229d2: 0x46696201 0x46686241 0xb4024770 0x08494671 0x80229e2: 0x56090049 0x448e0049 0x4770bc02 0xb40246c0
ぱっと見た目にはそれらしいコードを実行しようとしているように思えるのだが・・Flashをダンプ、逆アセンブルしている段階で、シンボルがないしソースもないので、これだけでは分からん。シンボル情報のロードが必要か。
(gdb) disas $pc,+32 Dump of assembler code from 0x8022972 to 0x8022992: => 0x08022972: ldr r1, [pc, #48] ; (0x80229a4) 0x08022974: ldr r2, [pc, #48] ; (0x80229a8) 0x08022976: ldr r3, [pc, #52] ; (0x80229ac) 0x08022978: b.n 0x8022982 0x0802297a: ldr r0, [r1, #0] 0x0802297c: adds r1, #4 0x0802297e: str r0, [r2, #0] 0x08022980: adds r2, #4 0x08022982: cmp r2, r3 0x08022984: bcc.n 0x802297a 0x08022986: movs r0, #0 0x08022988: ldr r1, [pc, #36] ; (0x80229b0) 0x0802298a: ldr r2, [pc, #40] ; (0x80229b4) 0x0802298c: b.n 0x8022992 0x0802298e: str r0, [r1, #0] 0x08022990: adds r1, #4 End of assembler dump.
continueでしばらく実行してCtrl-Cでスタックを確認するとどうもおかしい。暴走しているのか?
(gdb) cont Continuing. The target is not running when halt was requested, stopping GDB. Program received signal SIGINT, Interrupt. 0x0802297a in ?? () => 0x0802297a: 00 00 movs r0, r0 (gdb) where #0 0x0802297a in ?? () #1 0xffffffff in ?? () #2 0xffffffff in ?? () Backtrace stopped: previous frame identical to this frame (corrupt stack?)
ロードからもう一度やり直す(デバイスビジネス開拓団様の記事を参考)
$ /usr/local/GNUToolsARMEmbedded/4.8_2013q4/bin/arm-none-eabi-gdb.exe firmware.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.6.0.20131129-cvs Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=i586-mingw32 --target=arm-none-eabi". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from C:\cygwin64\home\<user_name>\lang\up\stm32\src\micropython\ports\s tm32\build-NUCLEO_L073RZ_KAI\firmware.elf...done. (gdb) target remote localhost:3333 Remote debugging using localhost:3333 0x0802296c in Reset_Handler () (gdb) monitor reset halt Unable to match requested speed 2000 kHz, using 1800 kHz Unable to match requested speed 2000 kHz, using 1800 kHz adapter speed: 1800 kHz target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x0802296c msp: 0x20004ff8, semihosting (gdb) i r r0 0x0 0 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20004ff8 0x20004ff8 lr 0xffffffff -1 pc 0x802296c 0x802296c <Reset_Handler> xPSR 0x1000000 16777216 (gdb) load Loading section .isr_vector, size 0xc0 lma 0x8000000 Loading section .text, size 0x2f818 lma 0x80000c0 Loading section .ARM, size 0x8 lma 0x802f8d8 Loading section .data, size 0x44 lma 0x802f8e0 Start address 0x802296c, load size 194852 Transfer rate: 28 KB/sec, 10255 bytes/write. (gdb) hbreak main Function "main" not defined. Make hw breakpoint pending on future shared library load? (y or [n]) y Hardware assisted breakpoint 1 (main) pending. (gdb) where #0 0x0802296c in Reset_Handler () (gdb) cont Continuing. The target is not running when halt was requested, stopping GDB. Program received signal SIGINT, Interrupt. 0x0802296c in Reset_Handler () (gdb) where #0 0x0802296c in Reset_Handler () (gdb)
ビルドの情報を詳細に表示するためと、デバッグ情報を付け加えるために、以下でビルド
make BOARD=NUCLEO_L073RZ_KAI V=1 DEBUG=1
なお、、リンカオプションもL073RZのままだとメモリマップもおかしいので、configを作り直した。
■参考URL
micropythonをはじめよう(STM32F401編) - 寝台急行はまなす
ARM Mbed その5 OpenOCD+GDB | デバイスビジネス開拓団