Sourcery CodeBenchLite2012.03-56コンパイラとgdbスイートをtexanegdbサーバーで使用しています。
今日、安価なSTM32VLDISCOVERYボードのFreeRTOSデモの例を試してみたかったのですが、必要なすべてのソースファイルをコピーし、エラーなしでコンパイルしましたが、例は機能しませんでした。デバッガーを起動し、GPIOレジスターへのポインターを逆参照しようとすると、例が失敗することに気付きました。GPIOレジスタへのポインタを含むグローバル配列変数:
GPIO_TypeDef* GPIO_PORT[LEDn] = {LED3_GPIO_PORT, LED4_GPIO_PORT};
正しく初期化されておらず、いくつかのランダムな値で埋められていました。プリプロセッサがLED3_GPIO_PORTとLED3_GPIO_PORTを定義していることを確認しましたが、それらは有効でした。
問題がどこにあるのかを調査した後、CMSISlibにあるtrueSTUDIO用に提供されているスタートアップファイルを調べました。元のstartup_stm32f10x_md_vl.Sファイル:
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
...
デバッグ中に、最初の命令movs r1、#0によってレジスタr1がゼロに初期化されないことに気付きました。レジスタr1はループ内のカウンタとして使用されるため、実行がループLoopCopyDataInitに達すると、レジスタr1には前の実行からのガベージデータがロードされるため、ループに入ることはありません。この結果、スタートアップコードが.dataセクションを初期化することはありません。
movs r1、#0命令の前に2つのnop命令を配置すると、レジスタr1が0に初期化され、例が機能し始めました。
startup_stm32f10x_md_vl.Sファイルの変更された部分:
/* Copy the data segment initializers from flash to SRAM */
nop
nop
movs r1, #0
b LoopCopyDataInit
これは、最終的なコードの関連部分の逆アセンブルです。
Disassembly of section .isr_vector:
08000000 <g_pfnVectors>:
8000000: 20002000 andcs r2, r0, r0
8000004: 08000961 stmdaeq r0, {r0, r5, r6, r8, fp}
...
Disassembly of section .text:
...
8000960 <Reset_Handler>:
8000960: 2100 movs r1, #0
8000962: f000 b804 b.w 800096e <LoopCopyDataInit>
08000966 <CopyDataInit>:
8000966: 4b0d ldr r3, [pc, #52] ; (800099c <LoopFillZerobss+0x16>)
8000968: 585b ldr r3, [r3, r1]
800096a: 5043 str r3, [r0, r1]
800096c: 3104 adds r1, #4
ご覧のとおり、ISRベクトルテーブルはReset_Handlerアドレスを適切に指しています。それで、何が起こっているのですか?最初の命令movsr1、#0が元の起動コードで実行されなかったのはなぜですか?
編集:
ボードの電源をオフにしてから再度オンにすると、元のコードが機能します。MCUを複数回リセットでき、動作します。gdb-serverを起動すると、リセットした後でもコードが機能しません。動作させるには、もう一度電源を入れ直す必要があります。これは、デバッガーの奇妙なことが起こっていることだと思います。
ノート:
他の人がこのMCUで使用しているスタートアップコードを調べました。割り込みを無効にするか、どちらの場合も冗長なリンカー定義値を使用してSPレジスタをロードします。彼らがこの奇妙な行動に見舞われた場合、彼らはそれに気付かないでしょう。