embassy-nrf — Crate 詳細
embassy-nrf
Nordic Semiconductor nRF シリーズ向けの Embassy HAL。GPIO、UART/UARTE、SPI/SPIM、I2C/TWIM、ADC/SAADC、PWM、Timer、Radio など多くのペリフェラルに対して、blocking API と async API を提供します。
Embassy Hardware Abstraction Layer (HAL) for Nordic Semiconductor nRF series microcontrollers, providing blocking and async APIs for many peripherals.
embassy-nrf は Nordic Semiconductor の nRF 系 MCU 向け Embassy HAL です。生のレジスタ操作を直接書かずに、Rust らしい型安全な API で GPIO、通信ペリフェラル、Timer、ADC、PWM、Radio などを扱うための基盤になります。Embassy の特徴である async/await と相性がよく、I/O 完了待ちや割り込み処理を HAL 側に任せながら、アプリケーション側は async fn と Timer、GPIO wait などで読みやすく記述できます。
この crate は blocking API と async API の両方を提供します。GPIO の単純な出力などは blocking API で十分ですが、UART/SPI/I2C の転送待ち、ボタン入力待ち、タイマ待ちなどは async API を使うことで、待機中に他タスクを進めたり低消費電力待機に入りやすくなります。
nRF 系で特に注意すべき点は EasyDMA です。SPIM、UARTE、TWIM など DMA を使うペリフェラルでは、DMA 対象バッファが RAM 上にある必要があります。固定リテラル配列は Flash に配置される可能性があるため、write_from_ram 系 API では BufferNotInRAM のようなエラーになり得ます。転送データはローカル配列や static mut 管理された RAM バッファなど、RAM 上に存在する形で渡す設計が重要です。
対象 MCU は nRF51 / nRF52 / nRF53 / nRF91 など広範囲ですが、利用可能なペリフェラルはチップファミリごとに異なります。実プロジェクトでは、使用する MCU に対応した feature を有効化し、docs.embassy.dev の上部メニューで対象 flavor を選んで API を確認してください。
コード例
embassy_nrf::init() で HAL を初期化し、GPIO 入力の async 待ち受けと Timer による LED 点滅を行う最小例です。ピン番号は使用ボードに合わせて変更してください。
#![no_std]#![no_main]
use defmt::*;use embassy_executor::Spawner;use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};use embassy_time::Timer;use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default());
// ボードに合わせて LED / Button のピンは変更してください。 // 例: nRF52 系ボードの P0_13 を LED、P0_11 をボタンとして使う例。 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); let mut button = Input::new(p.P0_11, Pull::Up);
loop { button.wait_for_low().await; info!("button pressed");
led.set_high(); Timer::after_millis(150).await; led.set_low(); Timer::after_millis(150).await;
button.wait_for_high().await; info!("button released"); }}nRF の EasyDMA は RAM 上のバッファを要求します。リテラル配列は Flash に置かれる場合があるため、ローカル変数など RAM 上の配列を渡す設計にします。
#![no_std]
// 概念例: SPIM/UARTE/TWIM など EasyDMA を使うペリフェラルでは、// 送受信バッファが RAM 上にある必要があります。//// NG になり得る例:// spim.write_from_ram(&[1, 2, 3]).await?;//// OK になりやすい例:// let tx = [1_u8, 2, 3];// spim.write_from_ram(&tx).await?;