諸君、私はprintfデバッグが好きだ。
でネタを書こうと思ったんけど、元ネタがとても長かったので、改変するのも面倒でやめた。
今どきのARMのマイコンの開発であれば、JTAGを使ってIDE上からデバッグができて、printfなど使わなくても変数の中身は見られるし、ブレークポイントははれるし、ステップ実行もできるのだろう。
しかし、私はJTAGを持っていない。fm3マイコンがもう一枚とか、NXPの安いボードを持っていれば、Open OCDを使ってデバッグができるのだろうが、私は持っていない。
そこで、printfデバッグの出番ですよ!となるのだが、printfの出力をどうやって受けるか?と言う問題がある。
雑誌の付録のfm3マイコンは、USBが2ポートと、多数のマルチファンクションシリアルがあるが、マルチファンクションシリアルはレベル変換をしてあげないと通常のPCのシリアルとは繋げないし、そもそも今どきのPCにはシリアルポートがないので、USB-シリアル変換ケーブルなんぞが必要になる。これも個人では持っていない。
よろしい、ならばUSBだ!(改変を諦めたとか言いながら引きずってる)
基板にあるミニUSBは、FLASH Programmerで書き込みをした後は電源供給にしか役に立っていない。
これを使わない手はないだろうと思って調べてみたところ、さすがUSB、通常のシリアルのように、RxDとTxDだけ押さえれば良いと言うような簡単なものではない。端子の抜き差しから、相手とのネゴシエーション、通信まで全部面倒見てやらないといけないらしい。
とりあえず、USBデバイスにはUSBメモリやHDDみたいなmass storageや、USBオーディオのようなクラスと呼ばれるものがあり、シリアル通信を行うものは CDC と言うらしい。
当然、そこら辺にミドルウェアが転がっているよね?と調べてみたが、open sourceの実装は見つけられず。
Keil MDKの場合は、Proを買うとUSB Deviceのミドルウェアが付いてくるが、試用版では当然使えない。
そして、IAR Embedded Workbenchには、Virtual COM Portと言うCDCのサンプル(相手からのデータをエコーバックするもの)が入っていることを発見。
このサンプルが前回作ったgccでビルドできれば、USB経由で夢のprintfデバッグができるようになるのだ。
試行錯誤ののち、なんとか動くようになったので、いつものようにgithubに上げてある。(fm3/sample3 at master · false-git/fm3>
今回のはまりポイントは、以下。
その過程で調べた、Virtual COM PortのSystemInit()でやっているUSBクロックの初期化について簡単に書いておこう。
基本は、ペリフェラルマニュアルの通信マクロ編である。
書いてて自分で何を言ってるのかさっぱりわからないけど。
でネタを書こうと思ったんけど、元ネタがとても長かったので、改変するのも面倒でやめた。
今どきのARMのマイコンの開発であれば、JTAGを使ってIDE上からデバッグができて、printfなど使わなくても変数の中身は見られるし、ブレークポイントははれるし、ステップ実行もできるのだろう。
しかし、私はJTAGを持っていない。fm3マイコンがもう一枚とか、NXPの安いボードを持っていれば、Open OCDを使ってデバッグができるのだろうが、私は持っていない。
そこで、printfデバッグの出番ですよ!となるのだが、printfの出力をどうやって受けるか?と言う問題がある。
雑誌の付録のfm3マイコンは、USBが2ポートと、多数のマルチファンクションシリアルがあるが、マルチファンクションシリアルはレベル変換をしてあげないと通常のPCのシリアルとは繋げないし、そもそも今どきのPCにはシリアルポートがないので、USB-シリアル変換ケーブルなんぞが必要になる。これも個人では持っていない。
よろしい、ならばUSBだ!(改変を諦めたとか言いながら引きずってる)
基板にあるミニUSBは、FLASH Programmerで書き込みをした後は電源供給にしか役に立っていない。
これを使わない手はないだろうと思って調べてみたところ、さすがUSB、通常のシリアルのように、RxDとTxDだけ押さえれば良いと言うような簡単なものではない。端子の抜き差しから、相手とのネゴシエーション、通信まで全部面倒見てやらないといけないらしい。
とりあえず、USBデバイスにはUSBメモリやHDDみたいなmass storageや、USBオーディオのようなクラスと呼ばれるものがあり、シリアル通信を行うものは CDC と言うらしい。
当然、そこら辺にミドルウェアが転がっているよね?と調べてみたが、open sourceの実装は見つけられず。
Keil MDKの場合は、Proを買うとUSB Deviceのミドルウェアが付いてくるが、試用版では当然使えない。
そして、IAR Embedded Workbenchには、Virtual COM Portと言うCDCのサンプル(相手からのデータをエコーバックするもの)が入っていることを発見。
このサンプルが前回作ったgccでビルドできれば、USB経由で夢のprintfデバッグができるようになるのだ。
試行錯誤ののち、なんとか動くようになったので、いつものようにgithubに上げてある。(fm3/sample3 at master · false-git/fm3>
今回のはまりポイントは、以下。
- intrinsics.h
IAR EW のヘッダファイルには、intrinsics.hと言うものがあるが、MDKにもgccにも該当するファイルはない。このため、空のファイルを作って、アドホックなdefineを入れてみた。 - startup_ARMCM3.S
gccに入っていた startup_ARMCM3.Sだと、isr_vectorが少なくて、今回使うようなUSB関連の割り込みベクタの設定がない。そこで、startup_mb9bf61x.s を参考に、不足している割り込みベクタを補完した。 - Makefile
今回ビルドしたコードには、for(int i = ...)みたいなコードがあり、gccのデフォルトだと怒られるので、--std=c99オプションを追加した。 - arm_comm.h
これは、IAR EWのプロジェクトに含まれるヘッダなのだが、CriticalSecCntrと言う変数の型が、このヘッダとmain.cで違うためエラーになっていたので型を揃えた。
また、中にinlineなメソッドがあるのだが、そのままビルドすると何故かリンク時に Undefined Referenceになるので、staticをつけた。
インラインアセンブラの記述に、asm()を使っていたので、gccで通るように__asm__()にした。(上述のintrinsics.hでdefine)
ArmV7以前とV7の分岐があったので、V7用のコードがコンパイルされるように、__CORE__を7にdefineした(上述のintrinsics.h) - system_mb9bf61x.[ch]
最初、sample2と同じくSysTickのサンプルから持ってきていたのだが、このコードだと SystemInit()の中でUSB/Etherのクロック設定が行われない。
そこで、Virtual COM Portのサンプルから持ってきたら動いた。
SysTickサンプルではなく、Spansionからダウンロードできるtemplateも見てみたが、バージョンは新しいのにUSBクロックの初期化コードや、UCCR等のレジスタのdefineもなかった。
その過程で調べた、Virtual COM PortのSystemInit()でやっているUSBクロックの初期化について簡単に書いておこう。
基本は、ペリフェラルマニュアルの通信マクロ編である。
- UCCRレジスタに0を入れて、UCCRの読出しが0になるまで待つ
UCCRレジスタに0を入れるということは、USB/Etherのクロック出力を停止していると思えば良い。 - UPCR1レジスタに0を入れる
これは、USB-PLLの発振停止 - UPCR2〜UPCR7のレジスタを初期化
細かく書かないけど、今回大事なのはUPCR6のUSBRに2を入れて、PLLCLKの3分周をUSBのクロックとして使用すると言うこと。 - UPCR1レジスタに1を入れ、読出しが1になるまで待つ。
USP-PLLの発振開始。 - UCCRレジスタに0x3Dを入れる
これも細かいことは割愛するけど、USBのクロックとしてCLKPLLを使うと言う設定。 - USBコントローラをonにする前に、5cycleクロック供給
- USBEN0/1レジスタに1を入れる
USBコントローラを有効にする。
書いてて自分で何を言ってるのかさっぱりわからないけど。
カテゴリ
Hardwareトラックバック(0)
このブログ記事を参照しているブログ一覧: fm3マイコンで遊ぶ(4)
このブログ記事に対するトラックバックURL: https://www.wizard-limit.net/cgi-bin/mt/mt-tb.cgi/3163
コメントする