前回で開発環境が構築できましたので、早速例題を実行してみたいと思います。
Picoの一番の見所はPIO(プログラマブルI/O)と思いますので、まずはPIOを学習したいと思います。
PIOの例題は、いろいろありますが、まずはじめは「hello_pio」から行きたいと思います。
「hello_pio」は基板上のLEDを0.5秒ごとに点滅させるプログラムですが、0.5秒の時間稼ぎはメインCPUが担当して、[1]or[0]の書き込みだけをpioが担当しています。
例題のサンプルプログラムはpicoフォルダーの直下のpico-examplesフォルダーの中に収められています。
フォルダー構造は次のようになっています。(hello_pioの例です)
pico-examples
|-pio
| |−hello_pio >> ソースプログラム hello.c など
|
|−build
|−pio
|−hello_pio >> ここでmakeを実行すると、実行ファイルが
生成される
まず、編集するためのエディタを立ち上げます。同じ名前で保存するので、上書き保存ができればなんでもOKです。
ソースファイルは、
~/pico/pico-examples/pio/hello_pio/hello.c
ですが、原本を修正するので、念の為、原本のバックアップを取っておきます。
ここでは hello.c.orgとしました。
$ cp ~/pico/pico-examples/pio/hello_pio/hello.c ~/pico/pico-examples/pio/hello_pio/hello.c.org
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」が最後に表示されたら端末を最小化しておきます。
また、端末を1つ開きます。コンパイルするために「make」を実行します。
ソースを編集するごとに「make]を実行するので、端末は開いたままにし、エディタで上書き保存したら、makeします。
$ cd ${PICO_SDK_PATH}/../pico-examples
$ cd build/pio/hello_pio
$ make
makeしたら、実行ファイルが生成されているのでgdbで書き込み実行します。
ソースを編集することに実行ファイルを読み込むので、gdbは終了せず、端末は開いたままにします。
$ cd ${PICO_SDK_PATH}/../pico-examples
$ cd build/pio/hello_pio
$ gdb-multiarch hello_pio.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
プログラムの確認は次のようになります。
1、ソースプログラムを編集、上書き保存
2、makeを実行し、実行ファイルを作成
3、GDBで、loadで実行ファイル読み込み、monitor reset initでリセット、
cで実機プログラム実行、Ctrl+cで停止、GDBコマンドでいろいろ確認
4、納得のいくまで、1から繰り返し!
hell.cでわかったこと
1、PIO pio = pio0; pioは2グループあるので、pio0及びpio1が指定可能
一つのpioには4つのステートマシーン(sm)がある。
2、hello_program_init(pio, sm, offset, 22);
最後の引数は、GPIOの指定なので、GP番号を指定すると、出力端子を変
えることができる。上の例では、GP22(29pin)に下記のようにLEDを接
続することで点滅することができる。
GP22(29pin)−抵抗1KΩ−(アノード)LED(カソード)−GND
3、sleep_ms(500);
点滅周期を変えられる。単位はmS、上記は500ms
4、pio_sm_put_blocking(pio, sm, 1);
pio_sm_put_blocking(pio, sm, 0);
指定のpioの指定のステートマシーン(sm)のFIFOに「1」or「0」を
送る。
いっぽう、hello.pio(pioアセンブラ)では、
loop:
pull
out pins, 1
jmp loop
となっており、pio_sm_put_blockingからおくられたデータはFIFO(Tx)に保存されているので、pull命令で、FIFO(Tx)からOUTシフトレジスタに転送される。
out pins, 1でOUTシフトレジスタの1bitだけをGPIOピンに出力する。
その繰り返しで、システムクロックでFIFOから1bitだけGPIOへ出力する。
このhello.cとhello.pioでは、まだPIOの真価が発揮されていませんね。
pio_blinkでは、pioで時間稼ぎしているので、メインCPUは、時間稼ぎのプログラムを呼ぶ必要がなくなり、CPUの使用効率が上がります。
次回は、pio_blinkを見てみたいと思います。