前回に引き続き、今回もPIOの例題を実行してみます。
今回は、「pio_blink」を確認してみたいと思います。
「pio_blink」はメインのCPUでの時間稼ぎをせずにPIOにて時間稼ぎを行っています。
この「pio_blink」を一部修正して、同時に3つのLEDの周期の異なる点滅を行いつつ、メインCPUでは、キー入力をエコーバックするプログラムにしました。
LEDは、基板上のLEDのGP25のほか、前回接続したGP22(22pin)と新たにGP17(22pin)を使用しました。
GP22(29pin)−抵抗1KΩ−(アノード)LED(カソード)−GND
GP17(22pin)−抵抗1KΩ−(アノード)LED(カソード)−GND
また、シリアル通信は、デフォルトのUART0Tx(GP0,1pin)とUART0Rx(GP1,2pin)を使用しました。
OpenOCD用PICOアダプタとターゲット用PICOは下記のように接続します。
OpenOCD用pico ターゲット用pico
GND(38pin) ---> GED(38pin)
VSYS(39pin) ---> VSYS(39pin)(5V)
GP4(6pin)Tx ---> Rx(GP1-2pin)
GP5(7pin)Rx ---> Tx(GP0-1pin)
GP2(4pin) ---> SWCLK
GP3(5pin) ---> SWDIO
フォルダー位置は次のようになっています。
pico-examples
|-pio
| |−pio_blink >> ソースプログラム blink.c など
|
|−build
|−pio
|−pio_blink >> ここでmakeを実行すると、実行ファイルが
生成される
「pio_blink」のblink.cのバックアップを取ります。
$ cd ${PICO_SDK_PATH}/../pico-examples
$ cd pio/pio_blink
$ cp blink.c blink.c.org
blink_pin_forever文の変更と、新たにwhile文でキー入力のエコーバックを追加しました。
blink_pin_foreverでは
1、pio0のsm0でGP25に対して、1秒周期に
2、pio0のsm1でGP17に対して、1/2秒周期に
3、pio0のsm2でGP22に対して、1/3秒周期に
while文では
1、シリアル経由の1文字受信をそのまま送信
main()文の中で上記になるよう変更と追加を行いました
int main(){
unsigned char ch; //追加
略
// blink_pin_forever(pio, 0, offset, 0, 3);
blink_pin_forever(pio, 0, offset, 25, 1); //変更
blink_pin_forever(pio, 1, offset, 17, 2); //変更
blink_pin_forever(pio, 2, offset, 22, 3); //変更
while(1){ //追加
while((unsigned char ch = getchar()) != EOF){ //追加
printf("Input Char : %c\n", ch); //追加
}
}
}
お好みのエディタで変更、追記した後、上書き保存します。
OpenOCD(SWD経由)で書き込みデバックするので、OpenOCD用picoをターゲット用picoに接続し、RaspberryPiにUSBで接続しておきます。
端末を1つ開き、OpenOCDを起動します。
$ cd ${PICO_SDK_PATH}/../openocd
$ src/openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -s tcl
「Info : Listening on port 3333 for gdb connections」が最後に表示されたら端末を最小化しておきます。
シリアル通信用のminicomを新規の端末で開きます。
minicomがインストールされていない場合は「$ sudo apt-get install minicom」でインストールします。
$ minicom -b 115200 -o -D /dev/ttyACM0
minicomの端末は開いたままにします。
makeのための端末を開きます。ソースを編集するごとに「make]を実行するので、端末は開いたままにします。
$ cd ${PICO_SDK_PATH}/../pico-examples
$ cd build/pio/pio_blink
$ make
gdbのための端末を開きます。ソースを編集することに実行ファイルを読み込むので、gdbは終了せず、端末は開いたままにします。
$ cd ${PICO_SDK_PATH}/../pico-examples
$ cd build/pio/pio_blink
$ gdb-multiarch pio_blink.elf
gdbで最初にOpenOCDに接続します。
(gdb) target remote localhost:3333
実行ファイルを読み込みます。
(gdb) load
picoをリセットし、実行します。
(gdb) monitor reset init
(gdb) c
実行を停止します。
Ctrlキーを押しながらcキーを押します。
終了するには、detachしたのち、quitします。
(gdb) detach
(gdb) quit
minicomの端末画面には下記のようにメーセージが出力され、キーを叩くごとに、入力された文字をエコーバックします。
Loaded program at 24
Blinking pin 25 at freq 1
Blinking pin 17 at freq 2
Blinking pin 22 at freq 3
Input Char : \u00ff
Input Char : a
Input Char : b
Input Char : c
picoに接続されたLEDは設定された周期で点滅します。
blink.pioの内容を見てみます。
1、pull block で TxFIFOに書き込みされたデータをOutputShiftRegisterに
書き込みします。
2、一時記憶のYレジスタにOutputShiftRegisterから32bit転送します。
3、.wrap_targetから .wrapの間を無限ループします。
4、一時記憶のXレジスタにYレジスタの内容をを転送します。
5、pinsで指定されたGPn(ここでは GP25/GP17/GP22のいずれか)に1をセット(LED点灯)
6、Xレジスタの内容が0になるまで減算ループする。
ここでpioでの時間稼ぎ、1秒だと X=24000000が0になるまで減算ループ
7、一時記憶のXレジスタにYレジスタの内容をを転送します。
8、pinsで指定されたGPn(ここでは GP25/GP17/GP22のいずれか)に0をセット(LED消灯)
9、Xレジスタの内容が0になるまで減算ループする。
ここでpioでの時間稼ぎ、1秒だと X=24000000が0になるまで減算ループ
10、4に戻る。(無限ループ)
最初のTxFIFOへの書き込みは、blink.cの中のpio->txf[sm]=設定値でpioの指定とsmの指定をしている。
ここでは、pio=0で、smは0/1/2の3つのステートマシーンを指定している。
設定値は、内部クロック 24000000Hzを指定することで1秒の時間稼ぎを行ってる。
メインCPUでは、PIOをセットしたあとは、PIOの動作と無関係でシリアル通信を行っている。
次回からは、eZ80のZDIをpicoを使って実現できないか模索していきたいと思います。