2010年07月26日

OpenOCD: lpc1768 + JTAG + Eclipse + GDB Debug 設定

OpenOCD: lpc1768 + JTAG + Eclipse + GDB Debug 設定

*Synopsis(概要)
*lpc1768/Eclipse側 設定
*lpc1768/OpenOCD側 設定
* lpc1768/ reset-initイベントハンドラ
*その他の設定(lpc1768)
*「soft_reset_halt」がキモだった(lpc1768)
*ベクタ・チェックサムについて(lpc1768)
*soft_reset_haltの位置(lpc1768)
*soft_reset_haltの位置(lpc1768) (2)

*Synopsis(概要)
やりたいことは
lpc1768ボードにJTAGアダプタつないでEclipseで
デバッグ(ステップ実行、etc)したい。

具体的には、
Eclipseで「デバッグ・ボタン」押したら、
実行ファイル(ELFファイル)をlpc1768にロードしたあと
「main()関数の先頭」にbreakで
停止するところまでやってほしいのだ。

ここに書いてない設定は他の人のページを参考にした。

諸条件:
Eclipse galileo 
OpenOcd v0.4.0
lpc1768ボードは汎用品(以前のブログに書いたもの)。
JTAGアダプタ(oocdlink-s互換品)。

で、
「キモ」の設定。

*lpc1768/Eclipse側 設定

赤丸の部分。
lpc1768-eclipse-gdb.gif
最初の1行目はみんな同じなので、
残り「たったの4行」を設定するのに

どどどどっと、大変だった。

何故なら、そもそも「lpc1768用」の設定例がWebで見つけられなかった。
のと。「他のをまねしてみても」ダメだったのだ。 orz
でも、
動いてみればlpc1768固有の設定項目はない風に見える (^^;

実は上の赤丸部分の「書き方」が多数存在し混乱気味なので、
なるべく上のように「CPUボードやCPUに依存しない書き方」が
望ましいといえる。

もし固有の設定があるなら「reset-initハンドラ内」或いは関数一つに内包する
ような記述にしたほうが良いだろう。
(まぁ、ケースバイケースかもしれないが)

と、いいますのも、
Eclipse(gdb)側の設定を複雑にしてしまうと
「難易度がさらに」上がってしまうと思うのです。

(爆

*lpc1768/OpenOCD側 設定

実のところ、こっちもWeb上に
「OpenOCD+lpc1768 + Eclipse + gdb」でデバッグ出来た設定例はなかった。

「JTAGのTAP情報が読み出せた」までの例は見つかるが
「デバッグ出来た設定例」はなかった。

別にWebに書く義務はないわけだけど (^^; (^^;
書いてあると助かるなぁ〜〜って思うわけです (オイ

考えられるのは
1,すごく簡単な設定で誰でもわかるので「書くまでもない」か、
2,トライする人が非常に少ないか、
3,設定できなくて挫折したか、
4,特に興味がないか、 (オイ
5,そんなのは某月刊誌や書籍に載ってる。
の、どれかかなぁ。(爆

一番気になるのが「2,」だ。
まえから気になっていたが「mbed」のおかげで
せっかくlpc1768使用者が増えたのに、JTAGがつながらないので

OpenOCD+JTAG+lpc1768使用者が世界的に増えていないのだ。

と予想する。(当然、趣味の世界の話だけど)

* lpc1768/ reset-initイベントハンドラ
「*.cfg」ファイルにある「reset-initイベントハンドラ」がキモなのだ。
このreset-initハンドラは「いつ呼ばれるか」。

1,Eclipse上で「デバッグ開始ボタン」を押す。
2,上の「gdb」設定の「monitor reset init」コマンドが実行される。
3,ハードウエアリセット等(JTAG関連も)が発生。
4,リセット系のイベントハンドラ群が呼ばれる。
5,最後から2番目に「reset-start」ハンドラが呼ばれる。
6,最後に「reset-init」ハンドラが呼ばれる。

で、多分「5.」の直前あたりで「CPUはHALT状態」になっている。
少なくとも「reset-init」ハンドラが呼ばれる前に「CPUはHALT状態」になっている。

「6,」の後、
上の赤丸部分で言うと「load」の直前でCPUはHALTで停止していることになります。

以下が「キモ」になる「reset-init イベントハンドラ」設定。
(soft_reset_haltをあとから追加しました。後述。)
$_TARGETNAME configure -event reset-init {
    echo "--- reset-init" 
    global _r

    # The VTOR indicates the offset of the vector table base address from 
    # memory address.
    # 0: Specify code region.
    mwb $_r(VTOR)    0x00

    # 1: User mode. The on-chip Flash memory is mapped to address 0.
    mwb $_r(MEMMAP)  0x01   

    soft_reset_halt     
}
(注: "_r"やレジスタ名は独自に定義したもの) コメント等々を省けば以下のようになる。
$_TARGETNAME configure -event reset-init {
    mwb $_r(VTOR)     0x00
    mwb $_r(MEMMAP)   0x01
    soft_reset_halt        
}
さらにレジスタ名定義をやめれば、
$_TARGETNAME configure -event reset-init {
    mwb 0xE000ED08    0x00  ; # VTOR
    mwb 0xE01FC040    0x01  ; # MEMMAP 
    soft_reset_halt    
}
と簡単に書ける。 2番目の「MEMMAP設定」が必要な理由は以下の文書にある。 lpc2300系からlpc1768への移行時のノート AN10878 Migrating to the LPC1700 series http://ics.nxp.com/support/documents/microcontrollers/pdf/an10878.pdf 以下抜粋、
8.1.6   Boot ROM re-mapping 
...
 However, if execution is halted immediately after reset by a 
debugger, the debugger should correct the mapping for the user by using the MEMMAP 
register which allows portion of the Boot ROM to be mapped to address 0 or flash 
memory is mapped to address 0. This is normally transparent to the user and important 
for tool vendors to be aware of. 
最初の「VTOR設定」が必要な理由は謎だが、 「VTOR設定」をすることで動いたというWeb上の情報を採用した。 *その他の設定(lpc1768) 以下については上側のデフォルトでいいような気がするが 下側の設定に変えてある。理由はせっかく回路は個別にあるのに 分離しないともったいない。(オイ lpc1768.cfg:
# LPC2000 & LPC1700 -> SRST causes TRST
#reset_config srst_pulls_trst
reset_config trst_and_srst separate
上はデフォルトに戻すかも。 lpc1768.cfg:
flash bank $_FLASHNAME lpc2000 0x0 0x80000 0 0 $_TARGETNAME \
	lpc1700 $_CCLK calc_checksum
上のようにチェックサムのチェックは無視しています。 現在は有効にしてあります。(調査中) そうすると以下のようにデバッグできたのだった。 eclipse-lpc1768-debug.gif (2010/08) *「soft_reset_halt」がキモだった(lpc1768) 上の設定には追加済みだけど、 「soft_reset_halt」コマンドを入れないと「sprintf/printf系」の 浮動小数表示がうまくいかないことが発覚した。 ねむいさんや、irukaさんに試してもらったら大丈夫とのこと。 実験してもらって感謝です。m(__)m 「soft_reset_halt」コマンドを当初から無視していたのが良くなかった ようだ。 無視した理由は「reset init」コマンドを実行してあるのに 「さらに何で?」と単純な疑問。 なるべく「おまじない的」な記述は避けたかったが、 無視したコマンドが「最大のキモ」だった。 orz reset initはリセット後にCPUをHALTさせるだけで 内部的なブートシーケンスの残骸が残ったままのようだ。 それをsoft_reset_haltで修正する感じでしょうか。 詳細は不明だが以下わかったこと、 1,「soft_reset_halt」コマンドを実行しない場合、スタックポインタ(SP)の   初期値が正しく設定されない。   (それでもスタック領域は約8kバイト確保されている) 2,「soft_reset_halt」コマンドを実行しない場合にsprintfの浮動小数変換を   実行しても、「8kバイトのスタックがあふれる訳ではない」が、   sprintfは正しく動作しない。   (malloc()系のsbrk()で約3k弱のヒープメモリを消費するがスタック破壊まで   5kバイト以上余裕があった。) *「soft_reset_halt」コマンドを実行する位置 Eclipse側のgdb設定なら「monitor reset init」の直後に入れればOKだった。 さらに「load」コマンドの直後でも大丈夫だった。 最終的には上記の様にOpenOCD設定ファイルの「reset-initイベントハンドラ」の 最後に追加した。 理由はInsightでデバッグする時の初期設定に複数のコマンドを書くと エラーになるのでOpenOCD側で済ませることにした。 *ベクタ・チェックサムについて(lpc1768) NXPはどうしてこんな機能を付けたのか。 理由が書いてないので不明だが何かの虫よけになるのかなぁ。 それより、「プログラムがブートしない!」って悲鳴が 世界的に増えるだけのような気がする。 (^^; これミスると痛い目に合う。十分注意したほうが良い。 で、 「OpenOCDはflashコマンドにcalc_checksum」を付けるとflash書込み時に 自動でベクタ・チェックサムを計算して書き込んでくれる。 だからソースコード内のチェックサム記述を気にしなくて良い。 が、しかし、 このcalc_checksumが動作するのは「flashコマンド」を使った時だけで gdb のloadコマンドの時には効果がないことが分かった。 デバッグは普通にできるけどJTAGを切り離してリセットかけると 「ギャッ!!」 orz やっぱり悲鳴だった。 従って ソースコードにちゃんとベクタ・チェックサムを記述することにした。 (OpenOCD v0.4.0) そこでチェックサムを簡単表示するEasy Checksum"を作った。 あと、Flashコマンドで書き込んだ後、gdbにシンボル情報だけロードする手も あるような気がする。(2010/11) * ブートシーケンスとの関係 実はリセット直後の内部ブートシーケンスの中に「ベクタ・チェックサム」の チェックも入っていて、 1,チェックサムが合わないときISPモードに移行する。 2,チェックサムが合えばユーザコードを実行。 という部分がある。 デバッガが介入すると「1.」の場合でも無理矢理「ユーザコード」を 実行するのだ。(ISPモードの残骸処理が必要) ここまでの状況から 「soft_reset_halt」が必須なのは「1.」の状態を無視して デバッグする場合だけの予感もするが もーめんどくさいので確認は省略。(オイ (2010/10) *soft_reset_haltの位置(lpc1768) ふと思った。 soft_reset_haltの位置はもっと前の方が良いかもしれない。 と、考えが変わるのは「soft_reset_halt」が実際何をどこまでやっているのか 不明なので想像になってしまうのだ。(そのうち調べよう) 現状では以下のように
$_TARGETNAME configure -event reset-init {
    soft_reset_halt
    mwb $_r(VTOR)     0x00
    mwb $_r(MEMMAP)   0x01
}
「VTOR」、「MEMMAP」設定の前の方が良い気がする。
(2010/11) *soft_reset_haltの位置(lpc1768) (2) 上の様にsoft_reset_haltを「reset-initハンドラ」の最初に持って来るのは 全然ダメなことが発覚しました。 気づくまでにかなりの時間がかかりました。orz ということで現状は以下、
$_TARGETNAME configure -event reset-init {

    mwb $_r(VTOR)     0x00
    mwb $_r(MEMMAP)   0x01
    soft_reset_halt
    
    jtag_clock_up_khz 1500
}
「jtag_clock_up_khz」はPLLを100MHzにアップした後JTAGクロックを 1.5MHzにアップする自作ルーチン。 LPC1768のPLLのクロックアップ方法についてはgitで取得した最新版の ソースコードの openocd\tcl\board\mcb1700.cfg というファイルがそのものズバリになります。
posted by Copyright (C) avrin All Rights Reserved. at 23:15| Comment(2) | OpenOCD | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
ねむいです。こんにちは。
現在数少ないLPC176"9"の使用者のうちの一人です。
mbedやLPCXpressoが流行っていますが、Jtagkey2+OpenOCD+Insightで
開発するのも乙なものだとおもいます!(not負け惜しみ)

自身のブログにも言及していますが、私はスタートアップに決め打ちで
checksum-validationを書いているので、audinさんと同じように
calc_checksumはOFFにしてます。
Posted by ねむい at 2010年08月02日 12:46
こんばんわ
いつも激しく参考にさせていただいてます。

Insightを少しやって見ましたが設定が簡単であっという間に動きました。
思わずブブゼラが鳴りやんだ感じです。
一部異常終了する場面がありますが近々ブログに
掲載したいと思います。
Posted by audin at 2010年08月02日 23:18
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。