📡

Rust + Raspberry Pi Pico :“cargo run”一発でLチカプログラムを書き込むまで

に公開

目標

  • 開発環境を整えること
    • なるべく楽に開発を進められるように
    • 将来性を加味してEmbassyの活用を行う
  • Lチカまで行う

TL;DR

MacにRustクロスコンパイル環境を入れ、cargo generate でEmbassyテンプレートを作成。
.cargo/config.toml のrunnerをelf2uf2-rs -dに設定。

cargo run --release

ラズパイのボリュームにドラッグ&ドロップなどが必要なくなって、プロジェクトの作成から、ラズパイの書き込みまで、快適に開発が続けられます。

環境構築

構成

  • Mac OS 15.5
    • Homebrew
  • Rust
    • Rustup
    • cargo-generate
    • elf2uf2-rs
  • Rustターゲット
    • thumbv6m-none-eabi (RP2040 用)
  • Raspberry Pi Pico H

ツールチェーンの導入

ツールチェーンとは、Rustでいうビルドやコンパイルなどに必要な諸々すべてを指すらしい。

# Rust + cross コマンド
brew install rustup                                  # 既に入っていればスキップ
rustup default stable
rustup target add thumbv6m-none-eabi                # Cortex-M0+ 用 :contentReference[oaicite:1]{index=1}

# プロジェクト生成と転送ツール
cargo install cargo-generate
cargo install elf2uf2-rs                   # UF2 自動転送

諸々ちゃんと入っているかの確認。私の環境では下記の様な感じになります。

# Rustのコンパイラ
% rustc --version
rustc 1.87.0 (17067e9ac 2025-05-09)

# ビルドターゲット Picoの開発は`thumbv6m-none-eabi`があればOK
% rustup target list --installed                   
aarch64-apple-darwin
thumbv6m-none-eabi

% cargo install --list
cargo-generate v0.23.3:
    cargo-generate
elf2uf2-rs v2.1.1:
    elf2uf2-rs

プロジェクトの作成からLチカ

プロジェクト作成

lulfというembassy関連のテンプレートを頻繁に更新している方のリポジトリからクローンします。不プロジェクト名は自由に変えてください。

cargo generate --git https://github.com/lulf/embassy-template.git --name pico_blink

そうすると下記のようなフォルダ構成になります。

pico_blink/
├─ .cargo/
│  └─ config.toml          ← ★runner を差し替える
├─ src/
│  └─ main.rs              ← ★点滅サンプルが入っている
├─ Cargo.toml
├─ memory.x                (2 MB Flash / 264 kB RAM の Pico 標準)
├─ rust-toolchain.toml     (nightly-embedded 最新が pin 済み)
├─ build.rs
└─ README.md

今回はcargo run --releaseコマンド一発で書き込みまで進めてもらうことが目的なので、.cargo/config.toml を修正します。

# ==== Runner ====
[target.thumbv6m-none-eabi]
runner = "elf2uf2-rs -d"        # ← probe-rs から置き換え

# ==== Build target ====
[build]
target = "thumbv6m-none-eabi"

# ==== defmt ログ ====
[env]
DEFMT_LOG = "info"

テンプレではrunner = "probe-rs run --chip {{ probe_chip }}"になっていますが、
いまのところデバッグプローブ無しで十分なので、UF2直転送に。詳細はまたどこかで。

Lチカするプログラム

src/main.rsを各。プログラムの本体はこんな感じ。

src/main.rs
#![no_std]          // 標準ライブラリ(std)をリンクしない ── 組み込みではメモリ節約の定番
#![no_main]         // 通常の main() を使わず、独自のエントリポイントを用意

// --- 依存クレートの導入(use)-----------------------------------------------
use {
    embassy_executor::Spawner,                 // 非同期タスクを起動するためのハンドラ
    embassy_rp::gpio::{Level, Output},         // RP2040 の GPIO 周り(LED 制御)
    embassy_time::{Duration, Timer},           // 非同期タイマー
    defmt_rtt as _,                            // ログ用(RTT経由)※ 下線は「未使用警告を抑止」
    panic_probe as _,                          // パニック時に最小限の情報を出力
};

// --- エントリポイント ---------------------------------------------------------
#[embassy_executor::main]     // 「async main」を生成し、RTOS 風にスケジューリングするマクロ
async fn main(_spawner: Spawner) {
    // ① RP2040 ペリフェラル初期化(クロック / GPIO など)
    let p = embassy_rp::init(Default::default());

    // ② ボード上のユーザー LED(GP25)を出力 Low で初期化
    let mut led = Output::new(p.PIN_25, Level::Low);

    // ③ メインループ(async/await でノンブロッキング)
    loop {
        led.set_high();                                  // 点灯
        Timer::after(Duration::from_millis(500)).await;  // 0.5 秒スリープ
        led.set_low();                                   // 消灯
        Timer::after(Duration::from_millis(500)).await;  // 0.5 秒スリープ
    }
}

Rust初心者向けポイント解説

個人的にわからなかったことをメモ。

  • #![no_std] / #![no_main] – 裸メタル環境の定番。OS もヒープも使わない極小バイナリを生成します。
  • embassy_executor::main – async fn main をタスク化し、簡易 RTOS のようにスケジューリングしてくれるマクロ。
  • embassy_rp::init() – ボード固有のクロック・GPIO 初期化を一括で実行。
  • Output::new() – GPIO を出力モードへ。第 2 引数は起動時レベル(High/Low)。
  • Timer::after(...).await – 非同期で遅延。await 中は CPU を他タスクに譲るためブロッキングしません。
  • defmt_rtt & panic_probe – println! の代わりに RTT 経由でログを吐き、パニック時も極小サイズで情報を取得可能。

ラズパイに書き込む

ここまで来ると、シンプルにコマンド一発で書き込める。

  1. BOOTSEL ボタンを押しながら Pico H を接続(初回のみ)
  2. ここからはコマンド一発
cargo run --release
#elf2uf2-rs が pico_blink.uf2 を生成
#/Volumes/RPI-RP2 または /Volumes/NO NAME を探して自動コピー
#コピー完了後 Pico が再起動 → LED 点滅 → 成功

これでRaspberry Pi Picoに内蔵されているLED(25Pin)が点滅する。

おまけ

今回は後段で楽をしたいので、コマンド一発で書き込めるようにしました。一方で下記が一般的な書き込みのプロセスらしい。

手順 コマンド/操作
cargo build --release で UF2 を生成
target/thumbv6m-none-eabi/release/<APP>.uf2 を確認
Pico を BOOTSEL 接続 → RPI-RP2 ドライブ出現
UF2 ファイルを ドラッグ&ドロップ
自動でドライブが Eject され、Pico がリセットしてプログラムが動作

次回は「音を出そう①:PWMで音を出す + デバッグプローブを使ってみる」を学びながら書いていきます。

Discussion