この記事はRust Advent Calender 2025の4日目の記事です。
先日開催された技術書典19で「Rust × Raspberry Pi Pico 2Wで組込み開発を深く学ぶ ― PC/Androidから操作できるIoT入門」という本を頒布したので、その中から即効性のある部分を抜粋して技術記事として公開しておきます。
技術書典のイベント自体は終了しましたが、こちらは電子書籍なのでいつでもお買い求めいただけます。
この記事のテーマ
この記事では以下の内容を扱います。
- Raspberry Pi Pico 無印→2での変更
- RP2350ではboot2が不要に
- Raspberry Pi Pico W系のちょっと変わった構造
- 内蔵LEDがCYW43439に直結されている
- Raspberry Pi Pico 2WのRust実装
embassyクレートの使い方・考え方
RP2040からRP2350での変更点
Raspberry Pi Picoの無印にはRP2040というチップが搭載されていましたが、Raspberry Pi Pico 2にはRP2350という次世代チップに置き換わりました。これらの違いを簡単にまとめたものが以下の表です。
| 項目 | RP2040 | RP2350 | RP2350での変更点 |
| メインCPU | Dual-core Arm Cortex M0+ | Dual-core Arm Cortex M33 / Dual-core RISC-V Hazard3 | Core0, Core1 それぞ れでアーキテクチャを選択可能 |
| 最大クロック | 133MHz | 150MHz | 動作周波数の向上 |
| オンチップSRAM | 264KB(6バンク) | 520KB(10バンク) | バンク構成拡張 |
| PIO | 2ブロック、8ステートマシン | 3ブロック、12ステートマシン | PIO数の増加 |
| DMA | 12チャネル、割り込み数2 | 16チャネル、割り込み数4 | 転送機能強化 |
つまり、CPUコアにRISC-Vが追加され、様々な機能が強化されました。
こうしたスペック上の改良に加え、プログラムを書くのに便利な変更もありました。RP2040ではXIP(Execute in place:外部フラッシュメモリに記録されたプログラムが、内部メモリ=SRAM上に存在するように実行する機能)の初期化のために、外部フラッシュメモリの先頭にboot2領域を確保する必要がありました。

そのため、RP2040を動かす際に、チップのメモリ配置を定義するmemory.xファイルは以下のように記述していました。
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}
EXTERN(BOOT2_FIRMWARE)
SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;
⼀⽅、RP2350 ではブートROM(電源リセット時に実行される初期化プログラム)がXIP初期化まで⾯倒を⾒てくれるのでboot2は不要です。よってmemory.xに.boot2を置く必要はなくなりました。
Raspberry Pi Pico W系の構造

Raspberry Pi PicoのWというシリーズでは、WiFiやBluetoothを使用した無線通信が可能です。この機能はCYW43439によって提供されています。つまり、無印ではRP2040、2ではRP2350にこのCYW43439が接続され、それぞれのチップによって制御されています。

ここで、1つ特殊な構造があります。Raspberry Pi Picoシリーズには動作確認用のボード内蔵LEDが搭載されているのですが、Wでない型はLEDがRP2040またはRP2350に直結されているのに対し(図(a))、W系ではCYW43439に接続されています(図(b))。
そのため、W系で内蔵LEDを光らせるためには、CYW43439経由でこれを操作する必要があります。つまり、単純なLチカコードのように無線通信を使用しない場合でも、CYW43439を動作させる必要があります。
Raspberry Pi Pico 2WのRust実装
Raspberry Pi Pico 2Wで無線通信を実行する際はもちろんのこと、上記のように内蔵LEDをチカチカさせるだけでもCYW43439を制御するコードを書く必要があります。これはCPUで様々な作業をしながら同時にCYW43439の動作状態を維持するということです。
組込みRustのembassyクレートは、これを実現するための非同期処理を提供します。通常CPUは同時に1つの処理しか実行できませんが、embassyが複数のタスクを定義し、それらを適切なスケジュールでCPUに割り当てることで、擬似的な並列処理を実現します。
たとえばRaspberry Pi Pico 2Wで内蔵LEDを点滅させる場合だと、以下の処理を実行する必要があります。
- RP2350・CYW43439の初期設定
- CYW43439の動作状態を維持
- 内蔵LEDをチカチカさせる
これを、以下のコードのようなタスクに分解します。
#[embassy_executor::task]
async fn cyw43_task(
runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>,
) -> ! {
runner.run().await
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
/* 初期設定 */
let (_net_device, mut control, runner) = cyw43::new(/* 引数省略 */).await;
spawner.spawn(cyw43_task(runner)).unwrap();
/* 中略 */
loop {
control.gpio_set(0, true).await;
Timer::after(duration).await;
control.gpio_set(0, false).await;
Timer::after(duration).await;
}
embassy使用すると、#[embassy_executor::main]がプログラムの実行点になります。これをメインタスクと呼ぶことにします。Lチカ(リスト3.)は初期設定(リスト1.)の後に実行するため、これらは直列的にまとめてメインタスク内に記述します。
これらの処理と同時に、CYW43439の動作状態を維持する必要があります。これはサブタスク(#[embassy_executor::task])として切り出します。メインタスク内のspawner.spawnという関数によって、メインタスクから分離され、独立したタスクとしてCPUに割り当て・実行されることになります。メインタスクを幹とすると、そこからサブタスクという枝を生やすイメージです。
Raspberry Pi Pico 2Wでの有線・無線通信
Lチカでのタスク分離は少しイメージしにくかったかもしれませんが、Raspberry Pi Pico 2Wで有線・無線通信を行う場合は非同期処理が非常に重要になります。
たとえばRaspberry Pi Pico 2WがUSBデバイスとしてPCとシリアル通信を行いつつ、Lチカを実行する場合は
- RP2350・CYW43439の初期設定
- CYW43439の動作状態を維持
- USBデバイスの通信状態を維持
- USBデバイスとして情報を入出力
- 内蔵LEDをチカチカさせる
という処理を同時に実行する必要があります。また、BLE(省電力のBluetooth)通信を実行しながらLチカを実行する場合は
- RP2350・CYW43439の初期設定
- CYW43439の動作状態を維持
- BLEの送受信項目の設定
- BLEを動作させつつ情報を入出力
- 内蔵LEDをチカチカさせる
の処理を同時に実行しなければなりません。それぞれのサンプルコードは以下のリポジトリで公開しています。
電子書籍の紹介
「Rust × Raspberry Pi Pico 2Wで組込み開発を深く学ぶ ― PC/Androidから操作できるIoT入門」では、このサンプルコードを使用して以下の内容を解説しています。
- 組込みRustのための基礎知識
- 外部フラッシュメモリ・SRAM・ブートROM
- CPU
- ペリフェラル(GPIO, PIO, DMA)
- メモリ空間とその定義・確認方法
- Raspberry Pi Pico 2WをUSBデバイスとして使用し、PCからLチカを制御
- PC上で動作するGUIアプリもRustで作成
- PCからLチカの速度を変更・履歴をPC上にグラフ表示
- Raspberry Pi Pico 2WをBLEデバイスとして使用し、AndroidスマートフォンからLチカを制御
- AndroidアプリはFlutterで作成
- AndroidスマートフォンからLチカの速度を変更・現在値をアプリに表示



コメント