ラズピコ PIO ~Lチカ コーディング編~

  • 2023.03.10
  • PIO
ラズピコ PIO ~Lチカ コーディング編~

皆さん こんにちは。
今回は PIO を使ってLチカしてみます。

開発環境は C/C++ SDK です。

環境構築やプロジェクトのつくり方

環境構築やプロジェクトのつくり方、VSCodeの起動については、このブログの一番最初の記事に書きました。

環境構築してみたい方は こちら をご覧になってください。

プロジェクトジェネレーターの”Library Option”で “PIO interface” にチェックを入れてプロジェクトを構成しても足りないファイルがあるなど不完全です。

そこでSDKに含まれているサンプルプロジェクトのソースを流用しながらPIOプログラムをコーディングすることで全体的な流れをつかんでみようと思います。

プロジェクトの作成

以下の設定でプロジェクトを作成します。

Project Name: picoPioBlink

Library Options の PIO interface をチェックする
Console Options の Console over UART をチェックする
IDE Options の Create VSCode project をチェックする
Debugger: は PicoProbe を選択する

VSCodeを起動する

起動後、何かファイルが開いてたら File – Close Folder で閉じた後、File – Open Folder から picoPioBlink のフォルダーを辿って選択します。

こちらの環境では C:\Users\m3925\Documents\Pico\pico-project-generator\picoPioBlink です。

m3925の部分は皆さんのユーザー名に置き換えてください。

vscode関連の json ファイルは前回作成済のプロジェクトのものをドラッグ&ドロップでコピー&ペーストすると楽です。

コードの編集

CMakeLists.txtを編集する

PIOでプログラムする場合、アセンブラを書くファイルが必要になり、その拡張子は pio になります。

今回のプロジェクト名は picoPioBlink ですから後で picoPioBlink.pio というファイルを作成します。

C/C++ SDK の環境では コンパイルする際にこのファイルをヘッダーファイルとして取り込むことになります。

picoPioBlink.c では冒頭に

#incldue "picoPioBlink.pio.h"

と記述することで、アセンブラのファイルをCのヘッダーファイルとして取り込むことができます。

CMakeLists.txtでもこのファイルの存在を知らせてあげる必要があり、その部分は編集して追加します。

(この部分はコードジェネレーターが対応してくれないので不足分を追加する必要があります)

CMakeLists.txtの add_executable()の後あたりに以下の1行を追加します。

pico_generate_pio_header(picoPioBlink ${CMAKE_CURRENT_LIST_DIR}/picoPioBlink.pio)

picoPioBlink.pioを編集する

以下のコードを書いて、picoPioBlink.pio で保存し、picoPioBlink.c と同じフォルダにコピーしておきます。

; 以降はアセンブラにコメント解説を入れておきました。
// 以降はCのコメント解説です。

.program picoPioBlink
    pull block      ; TX FIFOからOSRに32ビット値を読み込みます
    out y, 32       ; OSRからyに32ビット分シフトします(コピーと同意)
; ループ処理を書かなくても ".wrap_target" から ".wrap" までを無限にループするしくみになっています
.wrap_target
    mov x, y        ; yの値をxにコピーします
    set pins, 1     ; 指定されたピンを "high" にします
lp1:
    jmp x-- lp1     ; xが0になるまでループします
    mov x, y        ; yの値をxにコピーします
    set pins, 0     ; 指定されたピンを "low" にします
lp2:
    jmp x-- lp2     ; xが0になるまでループします
.wrap               ; .wrap_target にジャンプします


% c-sdk {
void picoPioBlink_program_init(PIO pio, uint sm, uint offset, uint pin) {

    // 与えられたPIOからの出力を使用するためGPIOをセットアップします
    pio_gpio_init(pio, pin);

    // SMを使用してPIOの連続する複数のピンに同じピン方向を設定します
    pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);

    // offsetからデフォルト設定を得ます
    pio_sm_config c = picoPioBlink_program_get_default_config(offset);

    // SM構成で'set'ピンを設定する。
    sm_config_set_set_pins(&c, pin, 1);

    // SMをリセットし、コンフィグレーションを行う。
    pio_sm_init(pio, sm, offset, &c);
}
%}

前半にアセンブラのコードを書きます。

% c-sdk { (1) %} の(1)の部分はC言語のヘッダーファイルに出力されます。
初期化処理等をここに書いておきます。
ヘッダファイルになるので、関数の実態を記述する場合には static inline を指定します。

picoPioBlink.cを編集する

#include <stdio.h>
#include "hardware/clocks.h"
#include "hardware/pio.h"
#include "pico/stdlib.h"
#include "picoPioBlink.pio.h"

#define LED_PIN 25

void blink_pin_forever(PIO pio, uint sm, uint offset, uint pin, uint freq);

int main() {
    // UARTのセットアップです
    setup_default_uart();

    // 使うPIOを選択します
    PIO pio = pio0;

    // 命令用のメモリーにアセンブラのプログラムを登録します
    // 第2引数には picoPioBlink.pioファイルで書いたアセンブラコードの ".program
    // の後の名前に & をつけます"
    uint offset = pio_add_program(pio, &picoPioBlink_program);

    // UARTの出力です
    printf("Loaded program at %d\n", offset);

    // 下の関数を呼びます
    blink_pin_forever(pio, 0, offset, LED_PIN, 1);
}

void blink_pin_forever(PIO pio, uint sm, uint offset, uint pin, uint freq) {
    // 初期化関数を呼びます。picoPioBlink.pio に記述している関数です
    picoPioBlink_program_init(pio, sm, offset, pin);

    // SMを有効にします
    pio_sm_set_enabled(pio, sm, true);

    // UARTの出力です
    printf("Blinking pin %d at %d Hz\n", pin, freq);

    // TX FIFO に遅延時間をセットします
    pio->txf[sm] = (clock_get_hz(clk_sys) / (2 * freq)) - 3;
}

コードの解説

適時コメントを入れましたので参考になさってください。

この部分は TX FIFO のレジスタに直接値を書きこんでいます。
おそらくここの freq は1秒間のLチカする回数になると思います。

pio->txf[sm] = (clock_get_hz(clk_sys) / (2 * freq)) - 3;

この部分はさほど大切なことではなく、その他の初期化や設定用のAPIやアセンブラの使い方について理解していくのが良いと思います。

PC側の準備

動作確認用として Tera Term を使います。
API関数がうまく動作したか否かなどの結果をUARTのputs()やprintf()でログ出力するようにしてみました。

Tera Termをお持ちでない方は こちら からダウンロードしてお使いください。

インストール後、 Tera Term を起動し、シリアルポートでPicoprobeのCOMポートを選択します。

もしCOMポートが複数ある場合には、Picoprobe以外の通信ケーブルをはずしてデバイスマネージャーでCOMポート番号を確認しておきます。

起動後、設定メニューのシリアルポートから以下の設定を行います。

スピート : 115200
データ : 8 bit
パリティ : なし
ストップビット : 1
フロー制御 : none

(設定値からスピードだけ変更すれば良いはずです)

動作させてみる

それでは F5キーを押してプログラムを動作させてみます。

Cのプログラムは停止しますがアセンブラは動作し続けLチカすれば成功です。

いかがでしたか?
皆さんはうまくPIOでLチカできましたか?

GitHub に picoPioBlink のコードをアップしましたのでご自由にお使いください。
(ただし当方では動作の保証は行っていません)

お疲れさまでした。

PIOカテゴリの最新記事