前回に引き続き、今回も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を使って実現できないか模索していきたいと思います。

おすすめの記事