Pico WのPIOの出力機能を3つのLEDの点灯・消灯で確認しよう。

2025年3月22日

【 当サイトには広告リンクが含まれています。 】


Raspberry Pi Pico W(以下 PicoW)にはメインプロセッサとは独立して動作する、Programmable Input/Output(以下 PIO)と呼ばれる2機のプロセッサがあります。

それぞれのPIOにはステートマシンと呼ばれる、4個の独立して動作する処理ユニットがあり、PIO用のアセンブラ(以下 PIOASM)を使ってGPIOを制御できます。

センサー等の電子部品をPicoWに複数接続して処理する場合、一部の電子部品の制御に処理時間を取られ、別の電子部品の処理に支障をきたす場合があります。

たとえば、LEDとスイッチをPicoWに接続し、LEDの制御に時間を取られた場合、スイッチからの入力を検知できないことが考えられます。

PIOでスイッチ等の一部の電子部品を制御することで、この問題を解決することができます。

このようにPIOはI/Oに特化したプロセッサと言えます。

詳細はRP2040 Datasheet: A microcontroller by Raspberry Piを参照してください。

この記事では、GPIOピン(以下 GPピン)に赤、緑、青の3つのLEDを接続し、PIOを使って赤と緑のLEDを500ms間隔で交互に点灯、消灯させながら、メインの処理で青のLEDを1000ms間隔で点灯、消灯させるプログラムをC/C++で作成します。


実験準備

実験に必要な機器と部品を準備します。

機器

「Windows PCとC/C++でRaspberry Pi Pico Wの開発を始めよう。」記事で書きましたラズパイPicoWと、Visual Studio Code(以下 VSCode)をインストールしたWindows PCを準備します。


使う部品

LED(発光ダイオード)、固定抵抗など実験に使う部品を準備します。

部 品 名規 格数 量取扱い店(参考)
LED5mm 赤色1電子工作ステーション
LED5mm 緑色1電子工作ステーション
LED5mm 青色1電子工作ステーション
カーボン抵抗1/4W 330Ω3電子工作ステーション
ブレッドボード830穴
(訳アリ品を除く)
1電子工作ステーション
ジャンパーワイヤオス-メス(約20cm)1電子工作ステーション


配線

GPIOピン(以下 GPピン)に接続された2つのLEDを、PIOを使って交互に点灯、消灯させるプログラムをC/C++で作成します。

配線リスト

ラズパイPicoWのGPピンと抵抗を通して、LEDを接続します。

ラズパイPicoW部 品部 品
GP26カーボン抵抗 R1LED1 アノード(足の長い方)
GP27カーボン抵抗 R2LED2 アノード(足の長い方)
GP16カーボン抵抗 R3LED3 アノード(足の長い方)
GNDLED1 カソード(足の短い方)
GNDLED2 カソード(足の短い方)
GNDLED3 カソード(足の短い方)


配線図



ライセンス

プロジェクトのビルドに必要なソースファイル、ソースコードをビルドするための設定ファイル等は、3条項BSDライセンスのもとで配布します。

3条項BSDライセンスの概要(意訳)は次のとおりです。

  • サンプルファイルのソースコードまたはバイナリ形式の再配布時には、著作権表示とライセンス条文を記載(SPDX-License-Identifier: BSD-3-Clauseなど)してください。

  • サンプルファイルはコピー/配布/変更/変更後の配布/商用利用/有料販売など、自由に使うことができます。

  • 書面による許可なしに、サンプルファイルから派生した製品の宣伝や販促に、本ライセンス記載の組織や貢献者(ラズパイ実験室)の名前を使うことはできません。

  • サンプルファイルにはなんの保証もついていません。
    サンプルファイルを利用し、なにか問題が発生した場合でも、作者(ラズパイ実験室)は一切の責任を負いませんので、使用に伴うリスクを理解し、自己責任で利用してください。


プロジェクト

GPIOに接続した2つのLEDを交互に点灯・消灯させるプロジェクト(pio_led_toggle)をVSCodeのC/C++を使って作成します。

pio_led_toggleプロジェクトは、コンパイルに必要な、ソースファイル(pio_led_toggle.c)、ソースコードをビルドするための設定ファイル(CMakeLists.txt)、PicoのSDKインポート用のファイル(pico_sdk_import.cmake)で構成されています。

ソースコードをVSCodeにコピーしてビルドします。

プロジェクト・フォーマットの作成

プロジェクト作成のためのフォーマットを作成します。

VSCodeを起動し、「Rasoberry Pi Pico Project」アイコンをクリックし、「New C/C++ Project」をクリックします。


Raspberry Pi Pico ダイアログが表示されますので、「Basic Setting」を選択します。


以下のように設定します。

項 目説 明
Namepio_led_toggl
Board typePico W
Location任意(全角文字、半角カタカナが含まれていないこと。)
※自身のユーザ内に任意のファルダを作成します。
Select Pico SDK versionv2.1.1
FeaturesPIO interface :✔
Stdio supportConsole over UART :✔


保存するフォルダ内のファイル作成者の信頼についての、ダイアログが表示される場合がありますので、「はい、作成者を信頼します」をクリックします。


プロジェクトが読み込まれます。

「自動補完システム」が準備完了になるまで待ち、準備完了マーク({})が表示された後、「エクスプローラー」を選択します。

「build」を開き、「build.ninja」が存在していることを確認します。

2つのソースコード、「pio_led_toggle.c」と、「blink.pio」が作成されています、

pio_led_toggle.cを選択すると、ソースコードがエディタエリアに表示されます。


blink.pioを選択すると、ソースコードがエディタエリアに表示されます。


プロジェクトの作成

作成したプロジェクト・フォーマットに、ソースコードを入力またはコピーして、プロジェクトを作成します。

▶️pio_led_toggle.cの作成

  1. 「エクスプローラー」アイコンをクリックして、「pio_led_toggle.c」を表示します

  2. 現在、VSCodeに表示されている内容をすべて削除します

  3. 下記「pio_led_toggle.c」のソースコードを入力またはコピー/貼り付けし保存します


pio_led_toggle.c

//
// Copyright (c) 2025 ラズパイ実験室
//
// SPDX-License-Identifier: BSD-3-Clause
//

//********************************
//
//PIO機能でLEDを交互に点灯・消灯
//
//********************************

#include <stdio.h>
#include <stdbool.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "mypio1.pio.h"

//LED接続 GPIOピン基準番号
#define OUT_PIN_BASE 26

//LED接続 GPIOピン数
#define NUM_OUT_PIN 2

//クロック分周値(125000000Hz / 62500 = 2000Hz)
#define CLOCK_DIV 62500

//点滅間隔(ms)
#define BLINK_INTERVAL 500

//メイン処理GPIOピン
#define LED_PIN 16


int main()
{
    stdio_init_all();

    //メイン処理LEDピン 初期化
    gpio_init(LED_PIN);

    //メイン処理LEDピンを出力ピンに設定
    gpio_set_dir(LED_PIN, GPIO_OUT);    

    //使用するPIO番号を指定
    PIO pio = pio0;
    
    //使用するステートマシン番号を指定
    uint state_machine_id = 0;

    //指定したPIOの命令モリにプログラムをロードする
    uint offset = pio_add_program(pio, &mypio1_program);
    
    //PIOプログラムの呼び出しと起動
    mypio1_program_init(pio, state_machine_id, offset, OUT_PIN_BASE, NUM_OUT_PIN, CLOCK_DIV);

    //TX FIFOに点滅間隔(ms)を設定
    //PIOのカウンタ・プログラムは、設定した点滅間隔よりも合計で3サイクル多くかかるので-3する
    pio->txf[state_machine_id] = BLINK_INTERVAL - 3;
   
    
    //メイン処理
    while (true) {
        //LED点灯
        gpio_put(LED_PIN, 1);
        sleep_ms(1000);
        //LED消灯
        gpio_put(LED_PIN, 0);
        sleep_ms(1000);
    }
}


▶️ mypio1.pioの作成

  1. 「エクスプローラー」に表示されている「blink.pio」の名前を、右クリックして「mypio1.pio」に変更します
  2. 現在、VSCodeに表示されている「mypio1.pio」の内容をすべて削除します

  3. 下記「mypio1.pio」のソースコードを入力またはコピー/貼り付けし保存します



mypio1.pio

;
; Copyright (c) 2025 ラズパイ実験室
; 
; SPDX-License-Identifier: BSD-3-Clause
;

.program mypio1

    //TX FIFOから32bitのデータ(点滅間隔(ms))をOSR(OUTシフトレジスタ)に移動
    pull block

    //OSRから32ビット、スクラッチレジスタyへデータを移動
    out y, 32

//.wrap_target?.wrap間の処理を繰り返し実行
.wrap_target

  //スクラッチレジスタyをスクラッチレジスタxにコピー    
    mov x, y        ; 1サイクル遅延

    //指定したGPIOピン26をHigh、27をLowに設定
    set pins, 0b01     ; 1サイクル遅延


lp1:
    //Xレジスタが0でなければXレジスタの内容を減算し、lp1にジャンプする。(0ならば次の処理へ)
    jmp x-- lp1     ; x+1サイクル遅延

    //スクラッチレジスタyをスクラッチレジスタxにコピー    
    mov x, y        ; 1サイクル遅延

    //指定したGPIOピン26をLow、27をHighに設定
    set pins, 0b10     ; 1サイクル遅延

lp2:
    jmp x-- lp2     ; x+1サイクル遅延

.wrap               ; 点滅を繰り返す


% c-sdk {

//GPIO出力を設定して、SMが指定されたピンに出力するように設定
 static inline void mypio1_program_init(PIO pio, uint sm, uint offset, uint ouT_pin, uint out_pin_num, float clkdiv){
   
    //指定したPIOステートマシンの初期設定情報をメモリに格納する
    pio_sm_config config = mypio1_program_get_default_config(offset);

    
    //ステートマシンのクロック分周値を設定する。125000000Hz / clkdiv(62500) = 2000Hz
    sm_config_set_clkdiv(&config, clkdiv);


    //LEDピン(GPIO26、GPIO27GPIO27)設定
    {
        int     i;

        for (i = 0; i < out_pin_num; i++){

                //GPIOをPIOに割り当てる
                pio_gpio_init(pio, ouT_pin + i);

                //指定したPIOで使用するステートマシンのGPIOピンの方向を出力に設定する
                pio_sm_set_consecutive_pindirs(pio, sm, ouT_pin + i, 1, true);

        }

        //ステートマシンの「set」ピンを設定する
        sm_config_set_set_pins(&config, ouT_pin, out_pin_num);

    }


    //指定したPIOで使用するステートマシンにメモリに格納された初期設定情報を適用する
    pio_sm_init(pio, sm, offset, &config);


    //指定したPIOで使用するステートマシンを起動する
    pio_sm_set_enabled(pio, sm, true);
 
}
%}


▶️ CMakeLists.txtの変更

  1. 「エクスプローラー」に表示されている「CMakeLists.txt」をクリックすると、エディタエリアに内容が表示されます。

  2. 「Generate PIO header」のフィル名を、「blink.pio」から「mypio1.pio」に変更し、保存します。

# Generate PIO header
pico_generate_pio_header(pio_led_toggle ${CMAKE_CURRENT_LIST_DIR}/blink.pio)

pico_generate_pio_header(pio_led_toggle ${CMAKE_CURRENT_LIST_DIR}/mypio1.pio)


プログラムの実行

Raspberry Pi Pico Wに接続されているUSBケーブルを外し、「BOOTSEL」ボタンを押しながら、USBケーブルを差し込みます。

「F5」キーを押して実行すると、途中、Temporary breakpointsで一時停止します。


もう一度、「F5」キーを押して続行します。

赤LEDと緑LEDが500ms間隔で交互に点灯・消灯し、青LEDが1000ms間隔で点灯・消灯します。




確認後、「Shift + F5」キーを押して、停止します。


まとめ

GPピンに赤、緑、青の3つのLEDを接続し、PIOを使って赤と緑のLEDを500ms間隔で交互に点灯、消灯させながら、メインの処理で青のLEDを1000ms間隔で点灯、消灯させました。

3つのLEDがスムーズに点灯・消灯することで、メインプロセッサとは独立して動作する、Programmable Input/Output(PIO)のディジタル信号出力機能を確認することができました。


おすすめの一冊

本書を読むのにプログラム言語の知識は一切不要です。もっとも親しみやすいC言語の入門書として、現代の環境に合わせてアップデートされた、安心して勉強を始められる一冊です。