EZ-USB FX3のGPIOを動かしてみる
FX3はソフトウェア開発環境すごく良くできていて、CypressのSDKにはRTOSがすでに組み込まれています。SDKにはGCCやEclipse、各種ライブラリがあらかじめ同梱されています。
ユーザがEZ-USB FX3用に作るプログラムはRTOSの1つのスレッドとして動かすべきんのようです。
そんな大仏の手のひらのような環境の元で、FX3のGPIOの実力を試そうと、GPIOをカチカチしてみました。
APIマニュアルを読むと、CyU3PGpioSimpleSetValueという関数があるので、例えばGPIO(21)をH/Lしたい場合には、
CyU3PGpioSimpleSetValue(21,CyTrue);
CyU3PGpioSimpleSetValue(21,CyFalse);
とやればよいのだろうなと想像しました。
しかし、1bitの遷移で600nsくらいかかっています。200MHzで動作するCPUなのにこれじゃ遅すぎると思って、APIマニュアルやその他マニュアルを読んでも、メモリマップI/Oのどの番地を叩けばGPIOがアクセスできるのか、書いていません。(見つけられませんでした)
つまり、EZ-USB FX3のGPIOを操作するには、CyU3PGpioSimpleSetValueやCyU3PGpioSetValueといった既成のAPI関数を呼ばなければいけないようです。
それじゃつまらないので、objdumpしてCyU3PGpioSimpleSetValueの中がどうなっているのか調べてみました。
4000cab0 <CyU3PGpioSimpleSetValue>:
4000cab0: e1a03000 mov r3, r0
4000cab4: e59f0598 ldr r0, [pc, #1432] ; 4000d054 <CyU3PGpioComplexWaitForCompletion+0x104>
4000cab8: e5900000 ldr r0, [r0]
4000cabc: e3500000 cmp r0, #0
4000cac0: 1a000001 bne 4000cacc <CyU3PGpioSimpleSetValue+0x1c>
4000cac4: e3a00042 mov r0, #66 ; 0x42
4000cac8: e12fff1e bx lr
4000cacc: e353003d cmp r3, #61 ; 0x3d
4000cad0: da000001 ble 4000cadc <CyU3PGpioSimpleSetValue+0x2c>
4000cad4: e3a00040 mov r0, #64 ; 0x40
4000cad8: eafffffa b 4000cac8 <CyU3PGpioSimpleSetValue+0x18>
4000cadc: e59f0598 ldr r0, [pc, #1432] ; 4000d07c <CyU3PGpioComplexWaitForCompletion+0x12c>
4000cae0: e7900103 ldr r0, [r0, r3, lsl #2]
4000cae4: e3c02342 bic r2, r0, #134217729 ; 0x8000001
4000cae8: e3510000 cmp r1, #0
4000caec: 0a000000 beq 4000caf4 <CyU3PGpioSimpleSetValue+0x44>
4000caf0: e3822001 orr r2, r2, #1
4000caf4: e59f0580 ldr r0, [pc, #1408] ; 4000d07c <CyU3PGpioComplexWaitForCompletion+0x12c>
4000caf8: e7802103 str r2, [r0, r3, lsl #2]
4000cafc: e3a00000 mov r0, #0
4000cb00: eafffff0 b 4000cac8 <CyU3PGpioSimpleSetValue+0x18>
CyU3PGpioSimpleSetValueという関数は、呼び出されるとまず[CyU3PGpioComplexWaitForCompletion+0x104]番地の内容を調べます。この値が0でなければ、66という戻り値でリターンします。おそらくCY_U3P_ERROR_NOT_STARTEDというエラーの値なので、GPIOが起動しているかどうかがこの番地に書かれているのだと思われます。
それから、引数の値が61以下であることを確認し、そうなっていなければCY_U3P_ERROR_BAD_ARGUMENTエラーを返します。その後、NULLポインタチェックを行うなどしています。
ひととおりのエラーチェックが終わったら、4000d07c番地[CyU3PGpioComplexWaitForCompletion+0x12c]の内容を読んで、r3の内容を左に2ビットシフトしたものを足して、その番地の内容をr0に読み出し、ビットクリアやビットセットを行ったものを計算して、書き戻しています。
4000d07c番地には0xe0001100が書かれているので、つまり、
[0xe0001100 + 4*GPIO番号]番地が、GPIOのポートのアドレスだろうと推測されます。
そして、読んだ値を書き戻す際に、LSBにポートから出力する値をセットする。ただし、28bit目を0にしなければならない、ということではないかと思われます。
まぁ、このような感じでGPIOにアクセスするためのレジスタの番地はわかったのですが、CyU3PGpioSimpleSetValueをコールしてもそれほど速くはならないでしょう。CyU3PGpioSimpleSetValueは16~20ステップ程度で実行できるはずなのです。
マニュアルを斜め読みしたところでは、このCPUは19.2MHzの源発振からPLLで403.2MHzのクロックを作って、それを2分周したものをシステムクロックにするようです。200MHz動作のCPUならば10MHzくらいの速さでGPIOを操作できてもいいのですが、その速度には到底及びません。もしかするとCPUのクロックがもっと遅いか、GPIOのクロックがとても遅いのではないかと推測できます。
続きはまた明日
| 固定リンク
コメント