STM32F107 ボードのプログラミングとデバッグに同じツール チェーンを使用しています。以下は、このツールチェーンで STM32Fxxx チップをプログラムおよびデバッグするための私の観察です。
最初の出発点
したがって、この時点で、OpenOCD から ARM-USB-OCD への接続が機能しているので、これですべての設定が完了するはずです。現在、Eclipse/Zylin/Yagarto GDB の組み合わせを取得して、OpenOCD/Olimex 接続を介して STM32Fxxx と適切に通信する作業が行われています。覚えておくべきことの 1 つは、発行するすべての OpenOCD コマンドが実行モードコマンドであることです。OpenOCD サーバーを呼び出すための構成スクリプトとコマンドライン オプションは、構成モードコマンドです。initコマンドを発行すると、サーバーは実行モードに入り、次に必要な一連のコマンドが開きます。おそらく別の場所でそれを行ったことがあるでしょうが、私は OpenOCD サーバーを次のように呼び出すときに「-c "init"」オプションを追加します。
openocd -f /path to scripts/olimex-arm-usb-ocd-h.cfg -f /path to targets/stm32f107.cfg -c "init"
次に発行する次のコマンドは、Eclipse Debug Configurationsダイアログによって実行されます。[ Zylin Embedded debug (Native)]セクションで、新しい構成を作成し、名前、プロジェクト (オプション)、およびプログラムするバイナリへの絶対パスを指定します。[Debugger] タブで、デバッガーをEmbedded GDBに設定し、Yagarto GDB バイナリ パスをポイントし、GDB コマンド ファイルを設定せず、GDB コマンドをStandardに設定し、プロトコルをmiに設定します。
コマンドタブ - GDB を OpenOCD に接続
次のタブはCommandsタブで、ここに問題の核心があります。InitializeとRunの 2 つのスペースがあります。GDBの呼び出し前と呼び出し後に発生することを推測することを除いて、違いが何であるか正確にはわかりません。いずれにせよ、コマンドの実行方法の違いに気づいていません。
とにかく、ネットで見つけた例に従って、初期化ボックスに次のコマンドを入力しました。
set remote hardware-breakpoint limit 6
set remote hardware-watchoint-limit 4
target remote localhost:3333
monitor halt
monitor poll
最初の 2 行は、ブレークポイントとウォッチポイントの数を GDB に伝えます。Open OCD Manual セクション 20.3には、GDB はその情報を照会できないと書かれているので、自分で言います。次の行は、ポート 3333 経由で localhost のリモート ターゲットに接続するように GDB に命令します。最後の行は、GDB に何のアクションも実行せずにターゲットにコマンドを渡すように指示する監視コマンドです。この場合、ターゲットは OpenOCD であり、コマンドhaltを与えています。その後、OpenOCD に非同期モードの操作に切り替えるように指示します。次の操作の一部には時間がかかるため、OpenOCD をブロックせずにすべての操作を待機させると便利です。
補足事項#1: GDB または OpenOCD の状態について疑問がある場合は、このデバッグ構成を呼び出した後、Eclipse デバッグ コンソールを使用して (GDB モニター コマンドを介して) GDB または OpenOCD にコマンドを送信できます。
コマンドタブ - ユーザーフラッシュの設定
次に、実行コマンド セクションで指定するコマンドを示します。
monitor flash probe 0
monitor flash protect 0 0 127 off
monitor reset halt
monitor stm32x mass_erase 0
monitor flash write_image STM3210CTest/test_rom.elf
monitor flash protect 0 0 127 on
disconnect
target remote localhost:3333
monitor soft_reset_halt
次のセクションで説明します...
ユーザーフラッシュメモリへのアクセス設定
まず、OpenOCD クエリを発行して、フラッシュ モジュールを見つけて適切なアドレスを報告できるかどうかを確認します。アドレス 0x08000000 にフラッシュが見つかったと応答する場合は、問題ありません。末尾の 0 は、フラッシュ バンク 0 に関する情報を取得することを指定します。
補足#2: STM32Fxxx のパーツ固有のデータシートには、セクション 4 にメモリ マップがあります。チップを操作するときに手元に置いておくと非常に便利です。また、すべてがメモリアドレスとしてアクセスされるため、少しのプログラミング時間でこのレイアウトを手の甲のように理解できるようになります!
そのため、フラッシュが適切に構成されていることを確認した後、フラッシュ バンクへの書き込み保護をオフにするコマンドを呼び出します。PM0075フラッシュ メモリのプログラミングについて知っておく必要があるすべてのことを説明します。このコマンドで知っておく必要があるのは、フラッシュ バンク、開始セクタ、終了セクタ、および書き込み保護を有効にするか無効にするかです。フラッシュ バンクは、OpenOCD に渡した構成ファイルで定義されており、前のコマンドで確認されています。フラッシュ スペース全体の保護を無効にしたいので、セクター 0 から 127 を指定します。PM0075 は、フラッシュ メモリが私の (およびあなたの) デバイスの 2KB ページにどのように編成されているかを示しているため、その番号をどのように取得したかを説明しています。私のデバイスには 256KB のフラッシュが搭載されているため、128 ページあることになります。お使いのデバイスには 512KB のフラッシュが搭載されているため、256 ページになります。デバイスの書き込み保護が適切に無効になっていることを確認するには、OpenOCD コマンドを使用してアドレス 0x40022020 の FLASH_WRPR レジスタをチェックします。
monitor mdw 0x40022020
出力される結果の単語は 0xffffffff になります。これは、すべてのページで書き込み保護が無効になっていることを意味します。0x00000000 は、すべてのページで書き込み保護が有効になっていることを意味します。
補足 #3:メモリ コマンドに関しては、アドレス 0x1ffff800 から始まるブロックのオプション バイトをいじっていたため、チップを 2 回ブリックしました。最初にフラッシュに読み取り保護を設定しました(それを行うと何をしているのか理解するのが難しいです)、2回目はハードウェアウォッチドッグを設定しました。OpenOCD メモリ アクセス コマンドを使用して修正しました。この話の教訓は次のとおりです。大いなる力には大いなる責任が伴います。あるいは、自分の足を撃ったとしても、JTAG を介して問題を解決できるという見方もあります。
補足 #4:保護されたフラッシュ メモリに書き込もうとすると、FLASH_SR:WRPRTERR ビットがセットされます。OpenOCD は、よりユーザーフレンドリーなエラー メッセージを報告します。
フラッシュを消去する
したがって、書き込み保護を無効にした後、プログラムするメモリを消去する必要があります。私はすべてを消去する一括消去を行います。セクターまたはアドレスごとに消去するオプションもあります(私は思う)。どちらの方法でも、書き込みを許可する前にハードウェアが最初に消去をチェックするため、プログラミングする前に最初に消去する必要があります。FLASH_SR:PGERR ビット (0x4002200c) がプログラミング中に設定された場合、そのメモリのチャンクをまだ消去していないことがわかります。
補足 #5:フラッシュ メモリのビットを消去することは、それを 1 に設定することを意味します。
バイナリのプログラミング
消去後の次の 2 行は、バイナリ イメージをフラッシュに書き込み、書き込み保護を再度有効にします。PM0075 でカバーされていないことは言うまでもありません。基本的に、フラッシュ write_imageを発行したときに発生するエラーは、おそらくフラッシュ保護が無効になっていないことに関連しています。おそらくOpenOCDではありませんが、興味がある場合は、デバッグ出力を有効にして、その動作に従うことができます。
GDB のデバッグ
最後に、プログラミングの後、GDB をリモート接続から切断してターゲットに再接続し、ソフト リセットを実行すると、GDB をデバッグする準備が整います。この最後の部分は、プログラミング後、リセット後に GDB が main() で適切に停止しない理由を理解しようとしていたときに、昨夜見つけたばかりです。それは雑草の中に消えていき、爆発し続けました。
私の現在の考えと、OpenOCD および GDB のマニュアルを読んだことから、リモート接続は、何よりもまず、GDB と、既に構成され実行されているターゲットとの間で使用されることを意図しているということです。実行前に GDB を使用して構成しているので、プログラミング中にシンボル テーブルやその他の重要な情報が台無しになると思います。OpenOCD のマニュアルによると、サーバーは GDB の接続時にメモリとシンボルを自動的に報告しますが、チップがプログラムされるとその情報はすべて無効になる可能性があります。切断して再接続すると、GDB が適切にデバッグするために必要な情報が更新されると思います。そのため、別のデバッグ構成を作成することにしました。これは、GDB を使用するたびにチップをプログラムする必要がないため、ターゲットを接続してリセットするだけです。
うわー!終わり!ちょっと長いですが、これを理解するのに3週末かかりましたので、それほど悪くはないと思います...
最後の補足:デバッグ中に、OpenOCD のデバッグ出力は、OpenOCD が内部で何を行っているかを理解する上で非常に貴重であることがわかりました。STM32x チップをプログラムするには、フラッシュ レジスタのロックを解除し、正しいビットを反転する必要があり、一度にハーフワードしか書き込めません。しばらくの間、OpenOCD がこれを適切に実行しているか疑問に思っていましたが、OpenOCD のデバッグ出力を調べて PM0075 命令と比較したところ、実際に各操作を実行するための適切な手順に従っていることを確認できました。また、OpenOCD が既に実行していた手順を複製していることもわかったので、役に立たなかった指示を切り取ることができました。話の教訓: デバッグ出力はあなたの友達です!