フォト
無料ブログはココログ

MyList

« 修理(2) | トップページ | 「自分」の壁 »

2014年7月30日 (水)

STM32F0-Discovery + OpenOCD

講義で使おうとSTM32F0-Discoveryを購入したら、主催者側がまとめて買ったとかで出番がなくなった。

Stm32f0discovery0000

でに、いつものように、ねむいさんの置場から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)の設定 → 実行 してくれる。

Stm32f0discovery0000←リンク先に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のアドレス

で良さそうだ。

« 修理(2) | トップページ | 「自分」の壁 »

JTAG」カテゴリの記事

CPUボード」カテゴリの記事

コメント

コメントを書く

コメントは記事投稿者が公開するまで表示されません。

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: STM32F0-Discovery + OpenOCD:

« 修理(2) | トップページ | 「自分」の壁 »