Skip to content

Commit 2134c36

Browse files
authored
Merge pull request #4 from Baker-link-Lab/copilot/enhance-example-code-rp2040
Add comprehensive RP2040 embedded Rust examples: rp2040-hal peripherals + Embassy async
2 parents f5e470f + 55df889 commit 2134c36

11 files changed

Lines changed: 760 additions & 1 deletion

Cargo.toml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,33 @@ edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

8+
[features]
9+
default = []
10+
embassy = [
11+
"dep:embassy-executor",
12+
"dep:embassy-time",
13+
"dep:embassy-rp",
14+
"dep:embassy-sync",
15+
]
16+
817
[dependencies]
918
cortex-m = "0.7"
1019
cortex-m-rt = "0.7"
1120
embedded-hal = { version = "1.0.0" }
21+
embedded_hal_0_2 = { package = "embedded-hal", version = "0.2.5", features = ["unproven"] }
1222
defmt = "0.3"
1323
defmt-rtt = "0.4"
1424
panic-probe = { version = "0.3", features = ["print-defmt"] }
1525
rp2040-hal = { version = "0.10", features = ["rt", "critical-section-impl"] }
1626
rp2040-boot2 = "0.3"
1727
critical-section = "1.0.0"
28+
fugit = "0.3"
29+
30+
# Embassy dependencies (optional, enabled via "embassy" feature)
31+
embassy-executor = { version = "0.10", features = ["platform-cortex-m", "executor-thread", "defmt"], optional = true }
32+
embassy-time = { version = "0.5", features = ["defmt"], optional = true }
33+
embassy-rp = { version = "0.10", features = ["defmt", "rp2040", "time-driver", "critical-section-impl", "boot2-generic-03h"], optional = true }
34+
embassy-sync = { version = "0.8", features = ["defmt"], optional = true }
1835

1936
[dev-dependencies]
2037
defmt-test = "0.3"
@@ -23,6 +40,19 @@ defmt-test = "0.3"
2340
name = "example_test"
2441
harness = false
2542

43+
# Embassy examples (require "embassy" feature)
44+
[[example]]
45+
name = "embassy_blinky"
46+
required-features = ["embassy"]
47+
48+
[[example]]
49+
name = "embassy_button"
50+
required-features = ["embassy"]
51+
52+
[[example]]
53+
name = "embassy_multitask"
54+
required-features = ["embassy"]
55+
2656
# cargo build/run
2757
[profile.dev]
2858
codegen-units = 1

examples/adc_read.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// adc_read.rs - ADCによるアナログ値の読み取り
2+
//
3+
// ADC(アナログ-デジタル変換器)を使ってアナログセンサーの値を読み取ります。
4+
// GPIO26(ADC0)に接続されたセンサーの値と、内蔵温度センサーの値を読み取ります。
5+
//
6+
// 実行方法: cargo run --example adc_read
7+
8+
#![no_std]
9+
#![no_main]
10+
11+
use defmt::*;
12+
use defmt_rtt as _;
13+
use panic_probe as _;
14+
use rp2040_hal as hal;
15+
16+
use hal::pac;
17+
18+
use embedded_hal::delay::DelayNs;
19+
20+
// rp2040-hal のADCは embedded-hal 0.2 の OneShot トレイトを使用
21+
use embedded_hal_0_2::adc::OneShot;
22+
23+
#[link_section = ".boot2"]
24+
#[used]
25+
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
26+
27+
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
28+
29+
#[rp2040_hal::entry]
30+
fn main() -> ! {
31+
info!("ADC read start!");
32+
33+
let mut pac = pac::Peripherals::take().unwrap();
34+
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
35+
36+
let clocks = hal::clocks::init_clocks_and_plls(
37+
XTAL_FREQ_HZ,
38+
pac.XOSC,
39+
pac.CLOCKS,
40+
pac.PLL_SYS,
41+
pac.PLL_USB,
42+
&mut pac.RESETS,
43+
&mut watchdog,
44+
)
45+
.ok()
46+
.unwrap();
47+
48+
let mut timer = rp2040_hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);
49+
50+
let sio = hal::Sio::new(pac.SIO);
51+
let pins = hal::gpio::Pins::new(
52+
pac.IO_BANK0,
53+
pac.PADS_BANK0,
54+
sio.gpio_bank0,
55+
&mut pac.RESETS,
56+
);
57+
58+
// ADCの初期化
59+
let mut adc = hal::Adc::new(pac.ADC, &mut pac.RESETS);
60+
61+
// GPIO26をADC入力(ADC0チャンネル)として設定
62+
let mut adc_pin_0 = hal::adc::AdcPin::new(pins.gpio26.into_floating_input()).unwrap();
63+
64+
// 内蔵温度センサーを有効化
65+
let mut temperature_sensor = adc.take_temp_sensor().unwrap();
66+
67+
loop {
68+
// ADC0チャンネルの値を読み取り(12ビット: 0-4095)
69+
let adc_value: u16 = adc.read(&mut adc_pin_0).unwrap();
70+
// 電圧に変換(基準電圧3.3V、12ビット分解能)
71+
let voltage_mv = (adc_value as u32) * 3300 / 4096;
72+
info!("ADC0: raw={}, voltage={} mV", adc_value, voltage_mv);
73+
74+
// 内蔵温度センサーの値を読み取り
75+
let temp_value: u16 = adc.read(&mut temperature_sensor).unwrap();
76+
// 温度に変換(データシートの式に基づく: T = 27 - (V - 0.706) / 0.001721)
77+
// 整数演算で近似: temp_mC = 27000 - (voltage_uV - 706000) * 1000 / 1721
78+
let temp_voltage_uv = (temp_value as i32) * 3_300_000 / 4096;
79+
let temp_mc = 27_000 - (temp_voltage_uv - 706_000) * 1000 / 1721;
80+
info!("Temperature: {}.{} deg C (raw={})", temp_mc / 1000, (temp_mc % 1000) / 100, temp_value);
81+
82+
timer.delay_ms(1000);
83+
}
84+
}

examples/blinky.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// blinky.rs - 最もシンプルなLED点滅の例
2+
//
3+
// 組み込みRustの基本を学ぶための最小限の例です。
4+
// GPIO22に接続されたLEDを1秒間隔で点滅させます。
5+
//
6+
// 実行方法: cargo run --example blinky
7+
8+
#![no_std]
9+
#![no_main]
10+
11+
use defmt::*;
12+
use defmt_rtt as _;
13+
use panic_probe as _;
14+
use rp2040_hal as hal;
15+
16+
use hal::pac;
17+
18+
use embedded_hal::delay::DelayNs;
19+
use embedded_hal::digital::OutputPin;
20+
21+
#[link_section = ".boot2"]
22+
#[used]
23+
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
24+
25+
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
26+
27+
#[rp2040_hal::entry]
28+
fn main() -> ! {
29+
info!("Blinky start!");
30+
31+
let mut pac = pac::Peripherals::take().unwrap();
32+
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
33+
34+
let clocks = hal::clocks::init_clocks_and_plls(
35+
XTAL_FREQ_HZ,
36+
pac.XOSC,
37+
pac.CLOCKS,
38+
pac.PLL_SYS,
39+
pac.PLL_USB,
40+
&mut pac.RESETS,
41+
&mut watchdog,
42+
)
43+
.ok()
44+
.unwrap();
45+
46+
let mut timer = rp2040_hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);
47+
48+
let sio = hal::Sio::new(pac.SIO);
49+
let pins = hal::gpio::Pins::new(
50+
pac.IO_BANK0,
51+
pac.PADS_BANK0,
52+
sio.gpio_bank0,
53+
&mut pac.RESETS,
54+
);
55+
56+
let mut led = pins.gpio22.into_push_pull_output();
57+
58+
loop {
59+
info!("LED ON");
60+
led.set_high().unwrap();
61+
timer.delay_ms(1000);
62+
63+
info!("LED OFF");
64+
led.set_low().unwrap();
65+
timer.delay_ms(1000);
66+
}
67+
}

examples/embassy_blinky.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// embassy_blinky.rs - Embassyを使った非同期LED点滅
2+
//
3+
// Embassy非同期フレームワークを使ったLED点滅の基本例です。
4+
// async/awaitにより、ブロッキングなしでタイマーを待機できます。
5+
//
6+
// 実行方法: cargo run --example embassy_blinky --features embassy
7+
8+
#![no_std]
9+
#![no_main]
10+
11+
use defmt::*;
12+
use defmt_rtt as _;
13+
use embassy_executor::Spawner;
14+
use embassy_rp::gpio::{Level, Output};
15+
use embassy_time::Timer;
16+
use panic_probe as _;
17+
18+
#[embassy_executor::main]
19+
async fn main(_spawner: Spawner) {
20+
info!("Embassy blinky start!");
21+
22+
let p = embassy_rp::init(Default::default());
23+
24+
// GPIO22をプッシュプル出力に設定
25+
let mut led = Output::new(p.PIN_22, Level::Low);
26+
27+
loop {
28+
info!("LED ON");
29+
led.set_high();
30+
Timer::after_millis(1000).await;
31+
32+
info!("LED OFF");
33+
led.set_low();
34+
Timer::after_millis(1000).await;
35+
}
36+
}

examples/embassy_button.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// embassy_button.rs - Embassyを使った非同期ボタン入力
2+
//
3+
// Embassyの非同期GPIO割り込みを使ってボタン入力を処理する例です。
4+
// ポーリングの代わりにasync/awaitでエッジ検出を待機するため、
5+
// CPU使用率を最小限に抑えられます。
6+
//
7+
// ピン配置:
8+
// - GPIO22: Green LED
9+
// - GPIO20: Red LED
10+
// - GPIO23: Button(プルアップ、押すとLOW)
11+
//
12+
// 実行方法: cargo run --example embassy_button --features embassy
13+
14+
#![no_std]
15+
#![no_main]
16+
17+
use defmt::*;
18+
use defmt_rtt as _;
19+
use embassy_executor::Spawner;
20+
use embassy_rp::gpio::{Input, Level, Output, Pull};
21+
use embassy_time::Timer;
22+
use panic_probe as _;
23+
24+
#[embassy_executor::main]
25+
async fn main(_spawner: Spawner) {
26+
info!("Embassy button example start!");
27+
28+
let p = embassy_rp::init(Default::default());
29+
30+
let mut green_led = Output::new(p.PIN_22, Level::Low);
31+
let mut red_led = Output::new(p.PIN_20, Level::High);
32+
let mut button = Input::new(p.PIN_23, Pull::Up);
33+
34+
info!("Waiting for button press...");
35+
36+
loop {
37+
// ボタンが押される(立ち下がりエッジ)まで非同期で待機
38+
button.wait_for_falling_edge().await;
39+
info!("Button pressed!");
40+
41+
// 赤LED OFF → 緑LED ON
42+
red_led.set_low();
43+
green_led.set_high();
44+
Timer::after_millis(2000).await;
45+
46+
// 緑LED OFF
47+
green_led.set_low();
48+
49+
// 赤LED ON に戻す
50+
red_led.set_high();
51+
52+
// デバウンス用の短い待機
53+
Timer::after_millis(200).await;
54+
55+
info!("Ready for next press");
56+
}
57+
}

examples/embassy_multitask.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// embassy_multitask.rs - Embassyを使った複数タスクの並行実行
2+
//
3+
// Embassyの非同期タスク機能を使って、複数のタスクを並行実行する例です。
4+
// 各タスクは独立して動作し、async/awaitにより協調的にスケジューリングされます。
5+
//
6+
// タスク構成:
7+
// - green_led_task: GPIO22の緑LEDを1秒間隔で点滅
8+
// - red_led_task: GPIO20の赤LEDを2秒間隔で点滅
9+
// - logger_task: 5秒ごとにステータスをログ出力
10+
//
11+
// 実行方法: cargo run --example embassy_multitask --features embassy
12+
13+
#![no_std]
14+
#![no_main]
15+
16+
use defmt::*;
17+
use defmt_rtt as _;
18+
use embassy_executor::Spawner;
19+
use embassy_rp::gpio::{Level, Output};
20+
use embassy_time::Timer;
21+
use panic_probe as _;
22+
23+
#[embassy_executor::task]
24+
async fn green_led_task(mut led: Output<'static>) {
25+
info!("Green LED task started (1s interval)");
26+
loop {
27+
led.set_high();
28+
Timer::after_millis(1000).await;
29+
led.set_low();
30+
Timer::after_millis(1000).await;
31+
}
32+
}
33+
34+
#[embassy_executor::task]
35+
async fn red_led_task(mut led: Output<'static>) {
36+
info!("Red LED task started (2s interval)");
37+
loop {
38+
led.set_high();
39+
Timer::after_millis(2000).await;
40+
led.set_low();
41+
Timer::after_millis(2000).await;
42+
}
43+
}
44+
45+
#[embassy_executor::task]
46+
async fn logger_task() {
47+
info!("Logger task started (5s interval)");
48+
let mut count: u32 = 0;
49+
loop {
50+
Timer::after_secs(5).await;
51+
count += 1;
52+
info!("System running... uptime: {}s", count * 5);
53+
}
54+
}
55+
56+
#[embassy_executor::main]
57+
async fn main(spawner: Spawner) {
58+
info!("Embassy multitask example start!");
59+
60+
let p = embassy_rp::init(Default::default());
61+
62+
// GPIO出力の初期化
63+
let green_led = Output::new(p.PIN_22, Level::Low);
64+
let red_led = Output::new(p.PIN_20, Level::Low);
65+
66+
// 各タスクを生成(spawn)
67+
spawner.spawn(green_led_task(green_led).unwrap());
68+
spawner.spawn(red_led_task(red_led).unwrap());
69+
spawner.spawn(logger_task().unwrap());
70+
71+
info!("All tasks spawned! Main task going idle.");
72+
73+
// メインタスクは何もしない(他のタスクが動作)
74+
loop {
75+
Timer::after_secs(3600).await;
76+
}
77+
}

0 commit comments

Comments
 (0)