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(発光ダイオード)、固定抵抗など実験に使う部品を準備します。
部 品 名 | 規 格 | 数 量 | 取扱い店(参考) |
LED | 5mm 赤色 | 1 | 電子工作ステーション |
LED | 5mm 緑色 | 1 | 電子工作ステーション |
LED | 5mm 青色 | 1 | 電子工作ステーション |
カーボン抵抗 | 1/4W 330Ω | 3 | 電子工作ステーション |
ブレッドボード | 830穴 (訳アリ品を除く) | 1 | 電子工作ステーション |
ジャンパーワイヤ | オス-メス(約20cm) | 1 | 電子工作ステーション |
配線
GPIOピン(以下 GPピン)に接続された2つのLEDを、PIOを使って交互に点灯、消灯させるプログラムをC/C++で作成します。
配線リスト
ラズパイPicoWのGPピンと抵抗を通して、LEDを接続します。
ラズパイPicoW | 部 品 | 部 品 |
GP26 | カーボン抵抗 R1 | LED1 アノード(足の長い方) |
GP27 | カーボン抵抗 R2 | LED2 アノード(足の長い方) |
GP16 | カーボン抵抗 R3 | LED3 アノード(足の長い方) |
GND | LED1 カソード(足の短い方) | ー |
GND | LED2 カソード(足の短い方) | ー |
GND | LED3 カソード(足の短い方) | ー |
配線図

ライセンス
プロジェクトのビルドに必要なソースファイル、ソースコードをビルドするための設定ファイル等は、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」を選択します。

以下のように設定します。
項 目 | 説 明 |
Name | pio_led_toggl |
Board type | Pico W |
Location | 任意(全角文字、半角カタカナが含まれていないこと。) ※自身のユーザ内に任意のファルダを作成します。 |
Select Pico SDK version | v2.1.1 |
Features | PIO interface :✔ |
Stdio support | Console over UART :✔ |
保存するフォルダ内のファイル作成者の信頼についての、ダイアログが表示される場合がありますので、「はい、作成者を信頼します」をクリックします。

プロジェクトが読み込まれます。
「自動補完システム」が準備完了になるまで待ち、準備完了マーク({})が表示された後、「エクスプローラー」を選択します。
「build」を開き、「build.ninja」が存在していることを確認します。
2つのソースコード、「pio_led_toggle.c」と、「blink.pio」が作成されています、
pio_led_toggle.cを選択すると、ソースコードがエディタエリアに表示されます。

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

プロジェクトの作成
作成したプロジェクト・フォーマットに、ソースコードを入力またはコピーして、プロジェクトを作成します。
▶️pio_led_toggle.cの作成
- 「エクスプローラー」アイコンをクリックして、「pio_led_toggle.c」を表示します
- 現在、VSCodeに表示されている内容をすべて削除します
- 下記「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の作成
- 「エクスプローラー」に表示されている「blink.pio」の名前を、右クリックして「mypio1.pio」に変更します
- 現在、VSCodeに表示されている「mypio1.pio」の内容をすべて削除します
- 下記「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の変更
- 「エクスプローラー」に表示されている「CMakeLists.txt」をクリックすると、エディタエリアに内容が表示されます。
- 「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)のディジタル信号出力機能を確認することができました。
おすすめの一冊