Raspberry Pi PicoをRustで動かす(Lチカ)

対あり技術部(技術系)

この記事では、Raspberry Pi Pico を使って Rust で組み込みプログラミングを始めるためのステップについて解説します。

Raspberry Pi Pico は、ARM Cortex-M0+ プロセッサを搭載した小型で低価格なマイコンボードで、GPIO ピンやインターフェースも豊富なため、初心者から上級者まで幅広く利用されています。

Rust は、メモリ安全性と高パフォーマンスを特徴とするシステムプログラミング言語で、特に組み込みシステム開発において信頼性と効率性を提供します。

この記事を通じて、Rust の開発環境構築から、簡単な LED の点灯プログラム、ビルド方法、ファームウェアの書き込みまでの流れを学ぶことができます。

Rustインストール

以下のサイトに行き、画像の赤い部分のボタンをクリックしてインストーラをダウンロードします

Rust をインストール
効率的で信頼性のあるソフトウェアを書く力を与える言語

「eustup-init.exe」をクリックします

黒い画面がでるので、「1」を押してエンターキーを押します

以下の画面が出たらインストール成功です

thumbv6m-none-eabiインストール

thumbv6m-none-eabiは、Rust で組み込みシステム向けのプログラムを開発する際に使用するターゲット triple (ターゲットの識別子) で、特に ARM Cortex-M0+ プロセッサなど、ARMv6-M アーキテクチャを使用するマイクロコントローラ向けに設計されています。

rustup target add thumbv6m-none-eabi

flip-link

flip-linkは、Rust の組み込み開発向けに作られたツールで、組み込みデバイス向けのプログラムにおいてスタックオーバーフロー検出機能を追加するリンカです。

cargo install flip-link

elf2uf2-rs

elf2uf2-rsは、Rust で書かれたツールで、組み込みシステム開発で生成される ELF ファイルを、Raspberry Pi Pico などの RP2040 マイコン向けに書き込むための UF2 ファイルに変換します。

cargo install elf2uf2-rs

プロジェクト作成

以下のコマンドでRustのプロジェクトを作成することができます。

cargo new <プロジェクト名> --bin

.cargo

プロジェクトのconfigファイルを作成します

プロジェクトフォルダの直下に「.cargo」フォルダを作成して、「config.toml」を生成します。

「config.toml」には以下の内容を入れます。

[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "elf2uf2-rs -d"

rustflags = [
  "-C", "linker=flip-link",
  "-C", "link-arg=--nmagic",
  "-C", "link-arg=-Tlink.x",
  "-C", "link-arg=-Tdefmt.x",
]

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

Config.toml

プロジェクトの直下のフォルダにある「Config.toml」に以下の内容を反映します

[package]
name = "sample"
version = "0.1.0"
edition = "2021"

[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
embedded-hal = { version = "1.0.0" }

defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }

# We're using a Pico by default on this template
rp-pico = "0.9"

main.rs

main.rsには、rp2040-project-templateのmain.rsをそのまま利用します

//! Blinks the LED on a Pico board
//!
//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED.
#![no_std]
#![no_main]

use bsp::entry;
use defmt::*;
use defmt_rtt as _;
use embedded_hal::digital::OutputPin;
use panic_probe as _;

// Provide an alias for our BSP so we can switch targets quickly.
// Uncomment the BSP you included in Cargo.toml, the rest of the code does not need to change.
use rp_pico as bsp;
// use sparkfun_pro_micro_rp2040 as bsp;

use bsp::hal::{
    clocks::{init_clocks_and_plls, Clock},
    pac,
    sio::Sio,
    watchdog::Watchdog,
};

#[entry]
fn main() -> ! {
    info!("Program start");
    let mut pac = pac::Peripherals::take().unwrap();
    let core = pac::CorePeripherals::take().unwrap();
    let mut watchdog = Watchdog::new(pac.WATCHDOG);
    let sio = Sio::new(pac.SIO);

    // External high-speed crystal on the pico board is 12Mhz
    let external_xtal_freq_hz = 12_000_000u32;
    let clocks = init_clocks_and_plls(
        external_xtal_freq_hz,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());

    let pins = bsp::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );

    // This is the correct pin on the Raspberry Pico board. On other boards, even if they have an
    // on-board LED, it might need to be changed.
    //
    // Notably, on the Pico W, the LED is not connected to any of the RP2040 GPIOs but to the cyw43 module instead.
    // One way to do that is by using [embassy](https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/wifi_blinky.rs)
    //
    // If you have a Pico W and want to toggle a LED with a simple GPIO output pin, you can connect an external
    // LED to one of the GPIO pins, and reference that pin here. Don't forget adding an appropriate resistor
    // in series with the LED.
    let mut led_pin = pins.led.into_push_pull_output();

    loop {
        info!("on!");
        led_pin.set_high().unwrap();
        delay.delay_ms(500);
        info!("off!");
        led_pin.set_low().unwrap();
        delay.delay_ms(500);
    }
}

memory.x

プロジェクトのチェッカに「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;

memory.xは、Rust で組み込みシステム向けのプログラムを開発する際に使われるリンカスクリプトで、マイクロコントローラのメモリレイアウトを定義します。

ビルド

① Raspberry Pi PicoをPCに接続します

②コマンドプロンプトなどのターミナルから「cargo run」を実行

③ビルドが成功すると自動的に、Raspberry Pi Picoにプログラムが反映されます

今回のプログラムはLEDが点滅すれば成功です。

> cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
     Running `elf2uf2-rs -d target\thumbv6m-none-eabi\debug\sample`
Found pico uf2 disk E:\
Transfering program to pico
92.00 KB / 92.00 KB [======================================================] 100.00 % 97.02 KB/s 

エラーが出る場合

> cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s
     Running `elf2uf2-rs -d target\thumbv6m-none-eabi\debug\sample`
Error: "Unable to find mounted pico"
error: process didn't exit successfully: `elf2uf2-rs -d target\thumbv6m-none-eabi\debug\sample` (exit code: 1)

このようなエラーが出る場合は、Raspberry Pi PicoがWindows等にマウントされていない可能性があります。

①一度ケーブルをRaspberry Pi Picoから取り外す

②Raspberry Pi Picoのボタンを押しながらケーブルを接続

③Windowsのエクスプローラーが立ち上がり、ドライブがマウントされていたら完了

この状態でもう一度、「cargo run」をするとプログラムがRaspberry Pi Picoに転送されると思います。

コメント

タイトルとURLをコピーしました