PIOプログラミング
PIO自体は必要十分な機能をシンプルに纏めていて良く出来ていると思いますが、マニュアル類(RP2040 Datasheet、Pico C/C++ SDK)が分かりにくいというか、説明がちょっと下手で??となることが多かったです。
- PIOはCPUとGPIOの間に入り、ある程度のGPIOの処理を行ってくれる(全てCPUのプログラムで動かさなくて良いように)
- PIOの動作はPIO Assemblerにて予めプログラム出来る(CPUのプログラムとは独立して)
- PIOが管理するGPIOピンのモード(動作)を設定する必要がある
- OUT:FIFOレジスタからのGPIOピンへシフト出力
- IN:GPIOピンの状態(High/Low)をFIFOへシフト入力
- SET:GPIOピンに直値を出力する
- さらにSIDEという設定があり、メインのデータをやり取りするGPIOピンに同期させるピンを指定できるが、SIDEピンにはSET(直値の出力)しか出来ない=よってSIDE-SETと表現されている
特に3, 4がパッとはわかりにくく、さらにPIO制御のためにCから使えるAPIがSDKに用意されているのですが、この名前付けがまた混乱を招くものになっています。例えば、
sm_config_set_set_pins()
とか。これは、PIOで管理するGPIOピンをSETコマンドの出力先としてステートマシンに設定する、なのですがもうちょっと直感的に分かりやすいネーミングは無かったのでしょうか。。
閑話休題。PICマイコンのICSPCLK/ICSPDATにPIOを使用するには、ICSPDATをメインのPIO管理ピンに据えFIFO(シフトレジスタ)経由でデータの入出力を行いICSPCLKをSIDE-SETとしてICSPDATに同期させて動かす、とイメージすると分かりやすいです。さらにICSPDATはOUT/SET/INの全てを行う必要があるため、pic_command_init()関数にて下記のように設定しています。
70 71 72 73 |
sm_config_set_out_pins(&sm_config, icspdat_pin, 1); sm_config_set_set_pins (&sm_config, icspdat_pin, 1); sm_config_set_in_pins (&sm_config, icspdat_pin); sm_config_set_sideset_pins(&sm_config, icspclk_pin); |
なんとも美しくないというか落ち着かない感じのコードですが、このように設定しないと実際に動作しませんでした。
PIO Assemblerは1ステップ=1Clockで動作させることが出来るのでシステムクロック125MHzでは8nsec単位で動かせますが、PIC16F1823の制御としてはICSPCLKが最小期間ですので、
78 |
sm_config_set_clkdiv(&sm_config, 13); // 8nsec(125MHz) *13 = 104nsec /inst. |
として、1ステップ=104nsecで動作させます。SIDE-SETを0-1とセットすることで208nsec周期のクロックを簡単に作れ便利です。
PICマイコンの制御コマンドには、下記3パターンがあります。
- 書込み:コマンド(6bit, RP2040→PIC)+書込むデータ(16bit, RP2040→PIC)
- 読込み:コマンド(6bit, RP2040→PIC)+読込むデータ(16bit, PIC→RP2040)
- コマンドのみ:コマンド(6bit, RP2040→PIC)
これらの処理分けを行うためにPIOに渡すFIFO(32bit幅)に置くデータの構造を下記のようにしています。
MSB | — | LSB | |||||||||||||||||||||||||||||
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
n/a | 0 | data | 0 | type | command | ||||||||||||||||||||||||||
all 0 | 0 | 14bit | 0 | 2bit | 6bit |
この32bitデータをPIO FIFOに置き、シフトレジスタから最初の6bitはICSPDATとして出力します(PICへのコマンド)。次の2bitはピンへは出力せず、scratch register Xへ読込んでコマンドパターンの処理分け用フラグに使用します。コマンドとデータの間はTDLYとして1μsecのウェイトが入りますので、その間にtype分けを行いさらにウェイトを追加して次のデータ出力までが1μsec程度になるように調整します。
※コマンドの例:PIC16F1823 Memory Programming Specificationより抜粋
あとはオシロで実波形を見ながらタイミングを調整すればPIOプログラミングは完了です。
LOAD CONFIGURATION ( DATA: 0x2AAA )
INCREMENT ADDRESS
READ DATA FROM PROGRAM MEMORY
コメント