STM32F0-Discovery + OpenOCD
講義で使おうとSTM32F0-Discoveryを購入したら、主催者側がまとめて買ったとかで出番がなくなった。
でに、いつものように、ねむいさんの置場からOpenOCDの最新版をDL。(ねむいさんありがとうございます)説明を見ると。
-OpenOCD OpenOCD 0.9.0-dev-00098-ge03eb89(built on 20140711) Windows 32bit Binary Nemuisan's Special Version SupportedOS ->WindowsXP(x86),Windows7(x86/x64) SupportedHardware ->JTAGKey,JTAGkey2 and many FT2232 Devices(LibUSBK or WinUSB or LibUSB) ->JLink(LibUSBK or WinUSB or LibUSB) ->JLink On LPCLink2(LibUSBK or WinUSB or LibUSB) ->ULink(LibUSB) (untested) ->RLink(LibUSB) (untested) ->STLink/V2(STMicro's Distributed USB-Driver/WinUSB) ->Versaloon(LibUSBK or WinUSB) ->TI-LCDI(TI's Distributed USB-Driver/WinUSB) ->CMSIS-DAP(Generic USB-HID/Mbed VCP Driver) ->STLink/V2-1(STM32-Nucleo Drivers/WinUSB) |
CMSIS-DAPをサポートしたんだと思ったら、0.8.0で既にサポートされていた。
テストプログラムは、同じく置場のkick startをDLした。
このテストプログラムは Lチカ+シリアル でFlashに書かないでRAMで動かす。
OpenOCDを起動して
openocd.exe -s ./tcl -s ./image -f board/stm32f0discovery.cfg |
telnetでlocalhost:4444に接続。RAMにロードして動かすコマンドは
> reset halt target halted due to debug-request , current mode: Thread xPSR: 0xc1000000 pc: 0x0800087c msp: 0x20000408 > load_image lchika.elf 4356 bytes written at address 0x20000000 download 4356 bytes in 0.090000s (47.266 KiB/s) > mww 0x40010000 3 > mdw 0x20000000 2 0x20000000: 20002000 20000e25 > reg sp 0x20002000 sp (/32): 0x20002000 > reg pc 0x20000E25 pc (/32): 0x20000E25 > resume |
set sp 0x20002000, set pc 0x20000E25は間違い
reg sp 0x20002000, reg pc 0x20000E25が正しい
(2015/11/29)
<<stm32f0_ram_exec.tcl>>
proc load_elf { loadfile } { # vector table address set vbr 0x40010000 # (top of SRAM) set mode 3 # reset and halt reset halt # set vector table address mww $vbr $mode # load ELF file onto SRAM(0x20000000-) load_image $loadfile return } proc run_sram { } { # vector address (top of SRAM) set vectaddr 0x20000000 # get initial SP and reset handler mem2array vect 32 $vectaddr 2 # display top of vector 4 elements mdw $vectaddr 4 # set initial SP into SP reg sp $vect(0) # set reset handler int PC reg pc $vect(1) # execute now resume return } proc load_run { loadfile } { load_elf $loadfile run_sram return } |
こんなスクリプトを作っておいて
openocd.exe -s ./tcl -s ./image -f board/stm32f0discovery.cfg -f stm32f0_ram_exec.tcl -c "init" -c "load_run lchika.elf" |
で CPUの停止 → バイナリ―のロード → レジスタ(SP,SP)の設定 → 実行 してくれる。
←リンク先にAVI(792.5k)
置場を見ていると、STM32VL-Discoveryのサンプル(TFT/OLED Module Control Sample with ChaN's FatFs(STM32VL-MMC Driver))があったので、STM32F0DiscoveryのテストプログラムをSTM32VLDiscovery用に作ってみた。
main.cはインクルードするヘッダファイルを除いてほぼ同じだ。以前作ったテストプログラムは、機能を削ってようやく8KのRAMの収まるくらいだったが、コンパイルすると、4.5kに収まった。
ところが、RAMにロードして動かそうとするとうまく動かない。LEDは点灯するだけで点滅せずシリアルにメッセージも送信されない。
ソースを見ても分からないのでデバッガで追ってみた。こんなことならInsightを入れとけばよかったと思ったが、gdbでシコシコ
実行する度に暴走する場所が異なる。メインから全てステップで追ってみるとxprintf()の中でgdbが返事をしなくなる。ところがxprintf()にブレークポイントを張って実行すると、ブレークポイントにたどり着く前にどこかへ行ってしまう。挙動不審だ。
LチカでSysTickを使っているのだが int TimingDelayの値がデクリメントされていないことに気がつた。そこで、SysTick_Handlerにブレークポイントを張ってちゃんと割り込みが掛かっているか確認すると、SysTic_Handlerに飛んでこない。
割り込みべタはRAMに設定しているのに??
悩むこと半日とうとう見付けた
src/hw_config.c
/************************************************************************** #ifdef VECT_TAB_RAM /* vector-offset (TBLOFF) from bottom of SRAM. defined in linker script */ extern uint32_t _isr_vectorsram_offs; #endif void NVIC_Configuration(void) { /* 20090429Nemui */ #ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x20000000 + _isr_vectorsram_offs */ NVIC_SetVectorTable(NVIC_VectTab_RAM, (uint32_t)&_isr_vectorsram_offs); #else /* VECT_TAB_FLASH */ /* Set the Vector Table base address at 0x08000000 */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0000); #endif /* 20090429Nemui */ ( ) |
NVIC_SetVectorTable()は
lib/STM32F10x_SetPeriph_Driver/src/misc.c
/** * @brief Sets the vector table location and Offset. * @param NVIC_VectTab: specifies if the vector table is in RAM or FLASH memor. * This parameter can be one of the following values: * @arg NVIC_VectTab_RAM * @arg NVIC_VectTab_FLASH * @param Offset: Vector Table base offset field. This value must be a multipl * of 0x200. * @retval None */ void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset) { /* Check the parameters */ assert_param(IS_NVIC_VECTTAB(NVIC_VectTab)); assert_param(IS_NVIC_OFFSET(Offset)); SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80); } |
この関数で VTOR(Vector Table Offset Register)を設定して割り込みベクタをリマップしている。
VECT_TAB_RAM/ VECT_TAB_FLASHはmakefieでコンパイル時に -DVECT_TAB_FLASHが宣言されている。
OpenOCDでバイナリをRAMにロードして、実行する前に割り込みベクタ・テーブルをRAMに設定しているのだが(mww 0xE000ED08 0x20000000) main()の先頭で呼ばれるSet_System()関数から Set_System() -> NVIC_Conviguration() -> NVIC_SetVectorTable() の順で呼ばれて割り込みベクタをFLASHの先頭に戻していたようだ。
コメントを見ると、/* 20090429Nemu */のシグネチャがある。
ねむいさんはプログラム中で割り込みベクタ・テーブルをリマップするというお考えだったらしい。それに気が付かないで自分で設定していたのが原因だった。
でもね、STM32F0DiscoveryのKickStartではベクタテーブルのリマップしてないんだよね。^^)尤も、cortex-M0にはVTORはないんだけどね。
cortex-M0にはVTROはなくても、ベクタテーブルのリマップ関数はあるのではと思い、探してみるとちゃんとあった。
/lib/STM32F0xx_StdPeriph_Driver/src/stm32f0xx_syscfg.c
/** * @brief Configures the memory mapping at address 0x00000000. * @param SYSCFG_MemoryRemap: selects the memory remapping. * This parameter can be one of the following values: * @arg SYSCFG_MemoryRemap_Flash: Main Flash memory mapped at 0x00000000 * @arg SYSCFG_MemoryRemap_SystemMemory: System Flash memory mapped at 0x00000000 * @arg SYSCFG_MemoryRemap_SRAM: Embedded SRAM mapped at 0x00000000 * @retval None */ void SYSCFG_MemoryRemapConfig(uint32_t SYSCFG_MemoryRemap) { uint32_t tmpctrl = 0; /* Check the parameter */ assert_param(IS_SYSCFG_MEMORY_REMAP(SYSCFG_MemoryRemap)); /* Get CFGR1 register value */ tmpctrl = SYSCFG->CFGR1; /* Clear MEM_MODE bits */ tmpctrl &= (uint32_t) (~SYSCFG_CFGR1_MEM_MODE); /* Set the new MEM_MODE bits value */ tmpctrl |= (uint32_t) SYSCFG_MemoryRemap; /* Set CFGR1 register with the new memory remap configuration */ SYSCFG->CFGR1 = tmpctrl; } |
MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM); をmainの頭で呼んでやればよさそうだ。
ついでに、スタートアップルーチン("lib/CMSIS/Device/ST/STM32F0xx/Source/Templates/gcc_ride7/startup_stm32f0xx.s)も調べてみると、Reset_Handlerの先頭でスタックの設定も行っていることが分かった。
つまり、OpenOCDのコマンドは
> reset halt > load_image main.elf > reg pc Reset_Handlerのアドレス |
で良さそうだ。
最近のコメント