Raspberry Pi PICOのPIOをArduino IDEを使って書く方法のメモです。
PIOでLチカっぽいことをする方法
まず、PIOのアセンブラを書きます。この時、PIOに関するCのコードを併記しておくと、設定の修正があった時、1つのファイルにまとまって情報があって楽になります。
test_signal.pioと言う名前で以下のコードを書きました。
.program test_signal
// ここから、PIOアセンブラコード
loop: // ループの起点。解説書だと.wrapとも書いてある。
wait 1, gpio 0 // GPIO0がHIGHになるまで待つ
set pins, 0 [10] // set pinとして設定した名前pinsのピンを0にして、10遅延(その状態を維持する)
set pins, 0 [10]
set pins, 0 [10]
set pins, 0 [6]
set pins, 1 [10]
set pins, 0 [7]
set pins, 1 [3]
set pins, 0 [5]
set pins, 1 [11]
wait 0, gpio 0
// ここまで
% c-sdk {
// 初期化関数
static inline void test_signal_program_init(PIO pio, uint sm, uint offset, uint pin) {
pio_sm_config c = test_signal_program_get_default_config(offset);
// Set pinをセット
sm_config_set_set_pins(&c, pin, 1);
// GPIOを初期化
pio_gpio_init(pio, pin);
// pinの方向を決める。set pinで設定したら出力に決まっているが、設定した方がよいみたい
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
// state machineを初期化
pio_sm_init(pio, sm, offset, &c);
// state machine起動
pio_sm_set_enabled(pio, sm, true);
}
%}
遅延と書いたのは、その状態をクロック数分維持するという意味です。PICOのシステムクロックの速度に依存します。PIOのstate machineをシステムクロックの何分の一で動かすのかは、
sm_config_set_clkdiv(&c, 6.25);
と、初期化関数の中で記載します。上記では6.25分の1で動かします。
このコードをpioasm Onlineのページの左の枠にコピペします。即座にアセンブルされ、右の枠に出力されます。また、% c-sdk { %}で囲った範囲はCのコードとして扱われて、やはり成形されて一緒に出力されます。
Cコード部分に以下の情報が付加されます。
static const struct pio_program test_signal_program = {
.instructions = test_signal_program_instructions,
.length = 9,
.origin = -1,
};
PIO
アセンブラコードの起点originと長さlengthの情報です。
static inline pio_sm_config test_signal_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + test_signal_wrap_target, offset + test_signal_wrap);
return c;
}
PIOのループwrapの定義です。
右の枠に出たアセンブラコードとCのコードを例えば、test_signal.pio.hとしてinoファイルのあるフォルダに保存します。
ここまで来たら、Arduino IDEのコード、例えばtest_signal.inoを書きます。
// Our assembled program:
#include "test_signal.pio.h"
void setup() {
PIO pio = pio0;
uint offset = pio_add_program(pio, &test_signal_program);
// 使っていないstate machineの番号を得る。0番号が明白なら、sm = 0;とか書いてもよい。
uint sm = pio_claim_unused_sm(pio, true);
// test_signal.pio.hに書かれている通り、最後の引数はset pinに割り当てるGPIOの番号
test_signal_program_init(pio, sm, offset, 15);
while (true) {
}
}
setup()関数内で、test_signal_program_init()に具体的なピン番号を渡すだけです。
loop()で何か処理をするなら、setup()内のwhileを消し忘れないようにしましょう。
お勧め参考書
参考書として有名なのはインターフェース2021年8月号がありますが、その後に出版された「
ラズベリーパイ Pico/Pico W攻略本」の方がサンプルコード(特にUART)が整理されていて、自分としては読みやすかったし、得るものが多かったです。
MicroPythonやCircuitPythonでもPIOのコードを書けますが、
SDKのCの関数を知らないと混乱します。今回に限って言えば、敷居が低いのは
SDK(または
Arduino IDE))です。
Set pinとOut pin
上記書籍のUARTのサンプルコードにはっきり書いてありますが、Set pinとOut pinは同一ピンに割り当てられます。UARTでは、Set pinでスタートビットを出力して、その後、Out pinでデータを送るコードになっています。
Set pin、Out pinを定義するには、初期化関数の引数に加えるだけです。例えば、上記の例の初期化関数の定義のところで
test_signal_program_init(PIO pio, uint sm, uint offset, uint set_pins, uint out_pins)などと修正して、
sm_config_set_set_pins(&c, set_pins, 1);
sm_config_set_oput_pins(&c, out_pins, 1);
とするだけです。inoファイルのsetup()内でset_pinsとout_pinsに同じGPIO番号を割り当てれば、両方使えるピンになります。GPIO15番を割り当てるなら以下のようなこんな感じです。
test_signal_program_init(pio, sm, offset, 15, 15);