From b1ea90a87e5ce6b16bbc155ad30d6d3473a998bb Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 8 Jul 2024 13:32:23 +0200 Subject: [PATCH 001/210] Add H755 examples --- examples/stm32h755cm4/.cargo/config.toml | 8 +++ examples/stm32h755cm4/Cargo.toml | 75 ++++++++++++++++++++++++ examples/stm32h755cm4/build.rs | 35 +++++++++++ examples/stm32h755cm4/memory.x | 14 +++++ examples/stm32h755cm4/src/bin/blinky.rs | 26 ++++++++ examples/stm32h755cm7/.cargo/config.toml | 8 +++ examples/stm32h755cm7/Cargo.toml | 75 ++++++++++++++++++++++++ examples/stm32h755cm7/build.rs | 35 +++++++++++ examples/stm32h755cm7/memory.x | 14 +++++ examples/stm32h755cm7/src/bin/blinky.rs | 48 +++++++++++++++ 10 files changed, 338 insertions(+) create mode 100644 examples/stm32h755cm4/.cargo/config.toml create mode 100644 examples/stm32h755cm4/Cargo.toml create mode 100644 examples/stm32h755cm4/build.rs create mode 100644 examples/stm32h755cm4/memory.x create mode 100644 examples/stm32h755cm4/src/bin/blinky.rs create mode 100644 examples/stm32h755cm7/.cargo/config.toml create mode 100644 examples/stm32h755cm7/Cargo.toml create mode 100644 examples/stm32h755cm7/build.rs create mode 100644 examples/stm32h755cm7/memory.x create mode 100644 examples/stm32h755cm7/src/bin/blinky.rs diff --git a/examples/stm32h755cm4/.cargo/config.toml b/examples/stm32h755cm4/.cargo/config.toml new file mode 100644 index 000000000..f9ae6f2e7 --- /dev/null +++ b/examples/stm32h755cm4/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.thumbv7em-none-eabihf] +runner = 'probe-rs run --chip STM32H755ZITx' + +[build] +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml new file mode 100644 index 000000000..c366bc3d2 --- /dev/null +++ b/examples/stm32h755cm4/Cargo.toml @@ -0,0 +1,75 @@ +[package] +edition = "2021" +name = "embassy-stm32h7-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32h755zi-cm4 to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = { version = "0.7.1" } +embedded-io-async = { version = "0.6.1" } +panic-probe = { version = "0.3", features = ["print-defmt"] } +heapless = { version = "0.8", default-features = false } +rand_core = "0.6.3" +critical-section = "1.1" +micromath = "2.0.0" +stm32-fmc = "0.3.0" +embedded-storage = "0.3.1" +static_cell = "2" +chrono = { version = "^0.4", default-features = false } +grounded = "0.2.0" + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/examples/stm32h755cm4/build.rs b/examples/stm32h755cm4/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/stm32h755cm4/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32h755cm4/memory.x b/examples/stm32h755cm4/memory.x new file mode 100644 index 000000000..f946b6210 --- /dev/null +++ b/examples/stm32h755cm4/memory.x @@ -0,0 +1,14 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08100000, LENGTH = 1024K /* BANK_2 */ + RAM : ORIGIN = 0x30000000, LENGTH = 128K /* SRAM1 */ + RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */ +} + +SECTIONS +{ + .ram_d3 : + { + *(.ram_d3) + } > RAM_D3 +} \ No newline at end of file diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs new file mode 100644 index 000000000..765be5ba1 --- /dev/null +++ b/examples/stm32h755cm4/src/bin/blinky.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PE1, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(500).await; + + info!("low"); + led.set_low(); + Timer::after_millis(500).await; + } +} diff --git a/examples/stm32h755cm7/.cargo/config.toml b/examples/stm32h755cm7/.cargo/config.toml new file mode 100644 index 000000000..f9ae6f2e7 --- /dev/null +++ b/examples/stm32h755cm7/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.thumbv7em-none-eabihf] +runner = 'probe-rs run --chip STM32H755ZITx' + +[build] +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml new file mode 100644 index 000000000..a97a8a5c5 --- /dev/null +++ b/examples/stm32h755cm7/Cargo.toml @@ -0,0 +1,75 @@ +[package] +edition = "2021" +name = "embassy-stm32h7-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32h743bi to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = { version = "0.7.1" } +embedded-io-async = { version = "0.6.1" } +panic-probe = { version = "0.3", features = ["print-defmt"] } +heapless = { version = "0.8", default-features = false } +rand_core = "0.6.3" +critical-section = "1.1" +micromath = "2.0.0" +stm32-fmc = "0.3.0" +embedded-storage = "0.3.1" +static_cell = "2" +chrono = { version = "^0.4", default-features = false } +grounded = "0.2.0" + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/examples/stm32h755cm7/build.rs b/examples/stm32h755cm7/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/stm32h755cm7/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32h755cm7/memory.x b/examples/stm32h755cm7/memory.x new file mode 100644 index 000000000..ab2afc216 --- /dev/null +++ b/examples/stm32h755cm7/memory.x @@ -0,0 +1,14 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 1024K /* BANK_1 */ + RAM : ORIGIN = 0x24000000, LENGTH = 512K /* AXIRAM */ + RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */ +} + +SECTIONS +{ + .ram_d3 : + { + *(.ram_d3) + } > RAM_D3 +} \ No newline at end of file diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs new file mode 100644 index 000000000..396b8c718 --- /dev/null +++ b/examples/stm32h755cm7/src/bin/blinky.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_stm32::Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // 100mhz + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.supply_config = SupplyConfig::DirectSMPS; + } + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut led = Output::new(p.PB14, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(500).await; + + info!("low"); + led.set_low(); + Timer::after_millis(500).await; + } +} From 203297b56912c05d2dd6a009ffeb433fb2ffbea6 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 8 Jul 2024 16:54:06 +0200 Subject: [PATCH 002/210] Make clocks repr C. Add shared data. Modify freq functions to use shared data. Modify examples to use new init/ --- embassy-stm32/Cargo.toml | 123 ++++++++++++----------- embassy-stm32/build.rs | 7 +- embassy-stm32/src/lib.rs | 116 +++++++++++++++++++++ embassy-stm32/src/rcc/mod.rs | 27 +++++ embassy-stm32/src/rtc/mod.rs | 2 +- embassy-stm32/src/time.rs | 36 +++++++ examples/stm32h755cm4/.cargo/config.toml | 2 +- examples/stm32h755cm4/memory.x | 2 +- examples/stm32h755cm4/src/bin/blinky.rs | 16 ++- examples/stm32h755cm7/.cargo/config.toml | 2 +- examples/stm32h755cm7/src/bin/blinky.rs | 12 ++- 11 files changed, 272 insertions(+), 73 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 523bacb11..a72a1a667 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -181,6 +181,9 @@ split-pc3 = ["_split-pins-enabled"] ## internal use only _split-pins-enabled = [] +## internal use only +_dual-core = [] + #! ## Chip-selection features #! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`. #! Check the `Cargo.toml` for the latest list of supported chips. @@ -1004,40 +1007,40 @@ stm32h743xg = [ "stm32-metapac/stm32h743xg" ] stm32h743xi = [ "stm32-metapac/stm32h743xi" ] stm32h743zg = [ "stm32-metapac/stm32h743zg" ] stm32h743zi = [ "stm32-metapac/stm32h743zi" ] -stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ] -stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ] -stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ] -stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ] -stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ] -stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ] -stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ] -stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ] -stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ] -stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ] -stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ] -stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ] -stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ] -stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ] -stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ] -stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ] -stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ] -stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ] -stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ] -stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ] -stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ] -stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ] -stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ] -stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ] -stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ] -stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ] -stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ] -stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ] -stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ] -stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ] -stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ] -stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ] -stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ] -stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ] +stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "_dual-core" ] +stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "_dual-core" ] +stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "_dual-core" ] +stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "_dual-core" ] +stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "_dual-core" ] +stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "_dual-core" ] +stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "_dual-core" ] +stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "_dual-core" ] +stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "_dual-core" ] +stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "_dual-core" ] +stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "_dual-core" ] +stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "_dual-core" ] +stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "_dual-core" ] +stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "_dual-core" ] +stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "_dual-core" ] +stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "_dual-core" ] +stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "_dual-core" ] +stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "_dual-core" ] +stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "_dual-core" ] +stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "_dual-core" ] +stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "_dual-core" ] +stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "_dual-core" ] +stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "_dual-core" ] +stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "_dual-core" ] +stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "_dual-core" ] +stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "_dual-core" ] +stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "_dual-core" ] +stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "_dual-core" ] +stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "_dual-core" ] +stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "_dual-core" ] +stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "_dual-core" ] +stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "_dual-core" ] +stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "_dual-core" ] +stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "_dual-core" ] stm32h750ib = [ "stm32-metapac/stm32h750ib" ] stm32h750vb = [ "stm32-metapac/stm32h750vb" ] stm32h750xb = [ "stm32-metapac/stm32h750xb" ] @@ -1048,24 +1051,24 @@ stm32h753ii = [ "stm32-metapac/stm32h753ii" ] stm32h753vi = [ "stm32-metapac/stm32h753vi" ] stm32h753xi = [ "stm32-metapac/stm32h753xi" ] stm32h753zi = [ "stm32-metapac/stm32h753zi" ] -stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ] -stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ] -stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ] -stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ] -stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ] -stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ] -stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ] -stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ] -stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ] -stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ] -stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ] -stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ] -stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ] -stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ] -stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ] -stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ] -stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ] -stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ] +stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "_dual-core" ] +stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "_dual-core" ] +stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "_dual-core" ] +stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "_dual-core" ] +stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "_dual-core" ] +stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "_dual-core" ] +stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "_dual-core" ] +stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "_dual-core" ] +stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "_dual-core" ] +stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "_dual-core" ] +stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "_dual-core" ] +stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "_dual-core" ] +stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "_dual-core" ] +stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "_dual-core" ] +stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "_dual-core" ] +stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "_dual-core" ] +stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "_dual-core" ] +stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "_dual-core" ] stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] @@ -1598,14 +1601,14 @@ stm32wba55he = [ "stm32-metapac/stm32wba55he" ] stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ] stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ] stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ] -stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ] -stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ] -stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ] -stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p" ] -stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4" ] -stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p" ] -stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4" ] -stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p" ] +stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core" ] +stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core" ] +stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core" ] +stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p", "_dual-core" ] +stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4", "_dual-core" ] +stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p", "_dual-core" ] +stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4", "_dual-core" ] +stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p", "_dual-core" ] stm32wle4c8 = [ "stm32-metapac/stm32wle4c8" ] stm32wle4cb = [ "stm32-metapac/stm32wle4cb" ] stm32wle4cc = [ "stm32-metapac/stm32wle4cc" ] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 8457e3a13..d8a7ea0e6 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -480,7 +480,7 @@ fn main() { self.clock_names.insert(name.to_ascii_lowercase()); quote!(unsafe { unwrap!( - crate::rcc::get_freqs().#clock_name, + crate::rcc::get_freqs().#clock_name.to_hertz(), "peripheral '{}' is configured to use the '{}' clock, which is not running. \ Either enable it in 'config.rcc' or change 'config.rcc.mux' to use another clock", #peripheral, @@ -713,9 +713,10 @@ fn main() { g.extend(quote! { #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[repr(C)] pub struct Clocks { #( - pub #clock_idents: Option, + pub #clock_idents: crate::time::MaybeHertz, )* } }); @@ -732,7 +733,7 @@ fn main() { $($(#[$m])* $k: $v,)* }; crate::rcc::set_freqs(crate::rcc::Clocks { - #( #clock_idents: all.#clock_idents, )* + #( #clock_idents: all.#clock_idents.into(), )* }); } }; diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 95f59360a..8f001f03b 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -273,7 +273,123 @@ impl Default for Config { /// This returns the peripheral singletons that can be used for creating drivers. /// /// This should only be called once at startup, otherwise it panics. +#[cfg(not(feature = "_dual-core"))] pub fn init(config: Config) -> Peripherals { + init_hw(config) +} + +#[cfg(feature = "_dual-core")] +mod dual_core { + use rcc::Clocks; + + use super::*; + use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicUsize, Ordering}, + }; + + /// Object containing data that embassy needs to share between cores. + /// + /// It cannot be initialized by the user. The intended use is: + /// + /// ``` + /// #[link_section = ".ram_d3"] + /// static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + /// + /// init_secondary(&SHARED_DATA); + /// ``` + /// + /// This static must be placed in the same position for both cores. How and where this is done is left to the user. + pub struct SharedData { + init_flag: AtomicUsize, + clocks: MaybeUninit, + } + + const INIT_DONE_FLAG: usize = 0xca11ab1e; + + /// Initialize the `embassy-stm32` HAL with the provided configuration. + /// This function does the actual initialization of the hardware, in contrast to [init_secondary] or [try_init_secondary]. + /// Any core can do the init, but it's important only one core does it. + /// + /// This returns the peripheral singletons that can be used for creating drivers. + /// + /// This should only be called once at startup, otherwise it panics. + /// + /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs + /// for more information on its requirements. + pub fn init_primary(config: Config, shared_data: &'static MaybeUninit) -> Peripherals { + let shared_data = unsafe { shared_data.assume_init_ref() }; + + rcc::set_freqs_ptr(&shared_data.clocks); + let p = init_hw(config); + + shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst); + + p + } + + /// Try to initialize the `embassy-stm32` HAL based on the init done by the other core using [init_primary]. + /// + /// This returns the peripheral singletons that can be used for creating drivers if the other core is done with its init. + /// If the other core is not done yet, this will return `None`. + /// + /// This should only be called once at startup, otherwise it may panic. + /// + /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs + /// for more information on its requirements. + pub fn try_init_secondary(shared_data: &'static MaybeUninit) -> Option { + let shared_data = unsafe { shared_data.assume_init_ref() }; + + if shared_data + .init_flag + .compare_exchange(INIT_DONE_FLAG, 0, Ordering::SeqCst, Ordering::SeqCst) + .is_err() + { + return None; + } + + Some(init_secondary_hw(shared_data)) + } + + /// Initialize the `embassy-stm32` HAL based on the init done by the other core using [init_primary]. + /// + /// This returns the peripheral singletons that can be used for creating drivers when the other core is done with its init. + /// If the other core is not done yet, this will spinloop wait on it. + /// + /// This should only be called once at startup, otherwise it may panic. + /// + /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs + /// for more information on its requirements. + pub fn init_secondary(shared_data: &'static MaybeUninit) -> Peripherals { + let shared_data = unsafe { shared_data.assume_init_ref() }; + + while shared_data + .init_flag + .compare_exchange(INIT_DONE_FLAG, 0, Ordering::SeqCst, Ordering::SeqCst) + .is_err() + {} + + init_secondary_hw(shared_data) + } + + fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals { + rcc::set_freqs_ptr(&shared_data.clocks); + + // We use different timers on the different cores, so we have to still initialize one here + critical_section::with(|cs| { + // must be after rcc init + #[cfg(feature = "_time-driver")] + time_driver::init(cs); + }); + + Peripherals::take() + } +} + +#[cfg(feature = "_dual-core")] +pub use dual_core::*; + +fn init_hw(config: Config) -> Peripherals { critical_section::with(|cs| { let p = Peripherals::take_with_cs(cs); diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 024c63cf5..587231b0c 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -48,11 +48,22 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0; /// May be read without a critical section pub(crate) static mut REFCOUNT_STOP2: u32 = 0; +#[cfg(not(feature = "_dual-core"))] /// Frozen clock frequencies /// /// The existence of this value indicates that the clock configuration can no longer be changed static mut CLOCK_FREQS: MaybeUninit = MaybeUninit::uninit(); +#[cfg(feature = "_dual-core")] +static CLOCK_FREQS_PTR: core::sync::atomic::AtomicPtr> = + core::sync::atomic::AtomicPtr::new(core::ptr::null_mut()); + +#[cfg(feature = "_dual-core")] +pub(crate) fn set_freqs_ptr(freqs: &'static MaybeUninit) { + CLOCK_FREQS_PTR.store(freqs as *const _ as *mut _, core::sync::atomic::Ordering::SeqCst); +} + +#[cfg(not(feature = "_dual-core"))] /// Sets the clock frequencies /// /// Safety: Sets a mutable global. @@ -61,11 +72,27 @@ pub(crate) unsafe fn set_freqs(freqs: Clocks) { CLOCK_FREQS = MaybeUninit::new(freqs); } +#[cfg(feature = "_dual-core")] +/// Sets the clock frequencies +/// +/// Safety: Sets a mutable global. +pub(crate) unsafe fn set_freqs(freqs: Clocks) { + debug!("rcc: {:?}", freqs); + CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).write(MaybeUninit::new(freqs)); +} + +#[cfg(not(feature = "_dual-core"))] /// Safety: Reads a mutable global. pub(crate) unsafe fn get_freqs() -> &'static Clocks { CLOCK_FREQS.assume_init_ref() } +#[cfg(feature = "_dual-core")] +/// Safety: Reads a mutable global. +pub(crate) unsafe fn get_freqs() -> &'static Clocks { + unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref() +} + pub(crate) trait SealedRccPeripheral { fn frequency() -> Hertz; const RCC_INFO: RccInfo; diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a7f70b153..fe57cfe66 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -168,7 +168,7 @@ impl Rtc { fn frequency() -> Hertz { let freqs = unsafe { crate::rcc::get_freqs() }; - freqs.rtc.unwrap() + freqs.rtc.to_hertz().unwrap() } /// Acquire a [`RtcTimeProvider`] instance. diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index 17690aefc..d7337191d 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -87,3 +87,39 @@ impl Div for Hertz { self.0 / rhs.0 } } + +#[repr(C)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// A variant on [Hertz] that acts as an `Option` that is smaller and repr C. +/// +/// An `Option` can be `.into()`'d into this type and back. +/// The only restriction is that that [Hertz] cannot have the value 0 since that's +/// seen as the `None` variant. +pub struct MaybeHertz(u32); + +impl MaybeHertz { + /// Same as calling the `.into()` function, but without type inference. + pub fn to_hertz(self) -> Option { + self.into() + } +} + +impl From> for MaybeHertz { + fn from(value: Option) -> Self { + match value { + Some(Hertz(0)) => panic!("Hertz cannot be 0"), + Some(Hertz(val)) => Self(val), + None => Self(0), + } + } +} + +impl From for Option { + fn from(value: MaybeHertz) -> Self { + match value { + MaybeHertz(0) => None, + MaybeHertz(val) => Some(Hertz(val)), + } + } +} diff --git a/examples/stm32h755cm4/.cargo/config.toml b/examples/stm32h755cm4/.cargo/config.toml index f9ae6f2e7..193e6bbc3 100644 --- a/examples/stm32h755cm4/.cargo/config.toml +++ b/examples/stm32h755cm4/.cargo/config.toml @@ -1,5 +1,5 @@ [target.thumbv7em-none-eabihf] -runner = 'probe-rs run --chip STM32H755ZITx' +runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace' [build] target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) diff --git a/examples/stm32h755cm4/memory.x b/examples/stm32h755cm4/memory.x index f946b6210..538bac586 100644 --- a/examples/stm32h755cm4/memory.x +++ b/examples/stm32h755cm4/memory.x @@ -1,7 +1,7 @@ MEMORY { FLASH : ORIGIN = 0x08100000, LENGTH = 1024K /* BANK_2 */ - RAM : ORIGIN = 0x30000000, LENGTH = 128K /* SRAM1 */ + RAM : ORIGIN = 0x10000000, LENGTH = 128K /* SRAM1 */ RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */ } diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs index 765be5ba1..52db326b0 100644 --- a/examples/stm32h755cm4/src/bin/blinky.rs +++ b/examples/stm32h755cm4/src/bin/blinky.rs @@ -1,15 +1,23 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::{ + gpio::{Level, Output, Speed}, + SharedData, +}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; +#[link_section = ".ram_d3"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init_secondary(&SHARED_DATA); info!("Hello World!"); let mut led = Output::new(p.PE1, Level::High, Speed::Low); @@ -17,10 +25,10 @@ async fn main(_spawner: Spawner) { loop { info!("high"); led.set_high(); - Timer::after_millis(500).await; + Timer::after_millis(250).await; info!("low"); led.set_low(); - Timer::after_millis(500).await; + Timer::after_millis(250).await; } } diff --git a/examples/stm32h755cm7/.cargo/config.toml b/examples/stm32h755cm7/.cargo/config.toml index f9ae6f2e7..193e6bbc3 100644 --- a/examples/stm32h755cm7/.cargo/config.toml +++ b/examples/stm32h755cm7/.cargo/config.toml @@ -1,5 +1,5 @@ [target.thumbv7em-none-eabihf] -runner = 'probe-rs run --chip STM32H755ZITx' +runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace' [build] target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs index 396b8c718..f76395326 100644 --- a/examples/stm32h755cm7/src/bin/blinky.rs +++ b/examples/stm32h755cm7/src/bin/blinky.rs @@ -1,12 +1,20 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::{ + gpio::{Level, Output, Speed}, + SharedData, +}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; +#[link_section = ".ram_d3"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); @@ -31,7 +39,7 @@ async fn main(_spawner: Spawner) { config.rcc.voltage_scale = VoltageScale::Scale1; config.rcc.supply_config = SupplyConfig::DirectSMPS; } - let p = embassy_stm32::init(config); + let p = embassy_stm32::init_primary(config, &SHARED_DATA); info!("Hello World!"); let mut led = Output::new(p.PB14, Level::High, Speed::Low); From f6f312270f9b2c42b0112545ac356cd6f595505b Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 9 Jul 2024 09:37:49 +0200 Subject: [PATCH 003/210] fmt --- embassy-stm32/src/lib.rs | 21 ++++++++++----------- embassy-stm32/src/rcc/mod.rs | 4 +++- embassy-stm32/src/time.rs | 2 +- examples/stm32h755cm4/src/bin/blinky.rs | 6 ++---- examples/stm32h755cm7/src/bin/blinky.rs | 6 ++---- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 8f001f03b..88683bfe4 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -280,25 +280,24 @@ pub fn init(config: Config) -> Peripherals { #[cfg(feature = "_dual-core")] mod dual_core { + use core::mem::MaybeUninit; + use core::sync::atomic::{AtomicUsize, Ordering}; + use rcc::Clocks; use super::*; - use core::{ - mem::MaybeUninit, - sync::atomic::{AtomicUsize, Ordering}, - }; /// Object containing data that embassy needs to share between cores. - /// + /// /// It cannot be initialized by the user. The intended use is: - /// + /// /// ``` /// #[link_section = ".ram_d3"] /// static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); - /// + /// /// init_secondary(&SHARED_DATA); /// ``` - /// + /// /// This static must be placed in the same position for both cores. How and where this is done is left to the user. pub struct SharedData { init_flag: AtomicUsize, @@ -314,7 +313,7 @@ mod dual_core { /// This returns the peripheral singletons that can be used for creating drivers. /// /// This should only be called once at startup, otherwise it panics. - /// + /// /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs /// for more information on its requirements. pub fn init_primary(config: Config, shared_data: &'static MaybeUninit) -> Peripherals { @@ -334,7 +333,7 @@ mod dual_core { /// If the other core is not done yet, this will return `None`. /// /// This should only be called once at startup, otherwise it may panic. - /// + /// /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs /// for more information on its requirements. pub fn try_init_secondary(shared_data: &'static MaybeUninit) -> Option { @@ -357,7 +356,7 @@ mod dual_core { /// If the other core is not done yet, this will spinloop wait on it. /// /// This should only be called once at startup, otherwise it may panic. - /// + /// /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs /// for more information on its requirements. pub fn init_secondary(shared_data: &'static MaybeUninit) -> Peripherals { diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 587231b0c..0656619b1 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -78,7 +78,9 @@ pub(crate) unsafe fn set_freqs(freqs: Clocks) { /// Safety: Sets a mutable global. pub(crate) unsafe fn set_freqs(freqs: Clocks) { debug!("rcc: {:?}", freqs); - CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).write(MaybeUninit::new(freqs)); + CLOCK_FREQS_PTR + .load(core::sync::atomic::Ordering::SeqCst) + .write(MaybeUninit::new(freqs)); } #[cfg(not(feature = "_dual-core"))] diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index d7337191d..802ff41ce 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -92,7 +92,7 @@ impl Div for Hertz { #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// A variant on [Hertz] that acts as an `Option` that is smaller and repr C. -/// +/// /// An `Option` can be `.into()`'d into this type and back. /// The only restriction is that that [Hertz] cannot have the value 0 since that's /// seen as the `None` variant. diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs index 52db326b0..f750c5db6 100644 --- a/examples/stm32h755cm4/src/bin/blinky.rs +++ b/examples/stm32h755cm4/src/bin/blinky.rs @@ -5,10 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::{ - gpio::{Level, Output, Speed}, - SharedData, -}; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs index f76395326..f76a136aa 100644 --- a/examples/stm32h755cm7/src/bin/blinky.rs +++ b/examples/stm32h755cm7/src/bin/blinky.rs @@ -5,10 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::{ - gpio::{Level, Output, Speed}, - SharedData, -}; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; From 6db0daf79b5d3316b101f057702b62312c5d2986 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 9 Jul 2024 09:53:01 +0200 Subject: [PATCH 004/210] Fix errors --- embassy-stm32/src/adc/mod.rs | 2 +- embassy-stm32/src/dsihost.rs | 2 +- embassy-stm32/src/rtc/low_power.rs | 2 +- embassy-stm32/src/usb/usb.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 7a7d7cd8e..f20585ec3 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -77,7 +77,7 @@ pub(crate) fn blocking_delay_us(us: u32) { embassy_time::block_for(embassy_time::Duration::from_micros(us as u64)); #[cfg(not(feature = "time"))] { - let freq = unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 as u64; + let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; let us = us as u64; let cycles = freq * us / 1_000_000; cortex_m::asm::delay(cycles as u32); diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs index 51f124542..77c3d95c3 100644 --- a/embassy-stm32/src/dsihost.rs +++ b/embassy-stm32/src/dsihost.rs @@ -14,7 +14,7 @@ pub fn blocking_delay_ms(ms: u32) { #[cfg(feature = "time")] embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); #[cfg(not(feature = "time"))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1_000 * ms); + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms); } /// PacketTypes extracted from CubeMX diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index a4ff1acbc..b9aaa63b9 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -132,7 +132,7 @@ impl Rtc { // Panic if the rcc mod knows we're not using low-power rtc #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); + unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap(); let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); let rtc_hz = Self::frequency().0 as u64; diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 1d9d19a73..9384c8688 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -270,7 +270,7 @@ impl<'d, T: Instance> Driver<'d, T> { #[cfg(feature = "time")] embassy_time::block_for(embassy_time::Duration::from_millis(100)); #[cfg(not(feature = "time"))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10); + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 10); #[cfg(not(usb_v4))] regs.btable().write(|w| w.set_btable(0)); From e39e93ead4f1da2504435e653a8d3e404c511c9e Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 9 Jul 2024 09:56:15 +0200 Subject: [PATCH 005/210] Improve use of CS --- embassy-stm32/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 88683bfe4..03c0eda1d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -375,9 +375,9 @@ mod dual_core { rcc::set_freqs_ptr(&shared_data.clocks); // We use different timers on the different cores, so we have to still initialize one here + #[cfg(feature = "_time-driver")] critical_section::with(|cs| { // must be after rcc init - #[cfg(feature = "_time-driver")] time_driver::init(cs); }); From 4972dbd91b6d0b6b55d15078c1c2cc171a933678 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 9 Jul 2024 11:49:16 +0200 Subject: [PATCH 006/210] Add function to get the active HSEM interrupt --- embassy-stm32/src/hsem/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs index b77a3415b..06ab7a9bc 100644 --- a/embassy-stm32/src/hsem/mod.rs +++ b/embassy-stm32/src/hsem/mod.rs @@ -158,6 +158,11 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> { .modify(|w| w.set_ise(sem_x, enable)); } + /// Gets the interrupt flag for the semaphore. + pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool { + T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x) + } + /// Clears the interrupt flag for the semaphore. pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { T::regs() From f01ffbcc12c40c68a57bc2daffdfad697bc28921 Mon Sep 17 00:00:00 2001 From: Chen Yuheng <1016867898@qq.com> Date: Thu, 11 Jul 2024 10:33:43 +0800 Subject: [PATCH 007/210] Add oversampling and differential for g4 --- embassy-stm32/src/adc/g4.rs | 60 ++++++++++++++++++++ embassy-stm32/src/adc/mod.rs | 1 + examples/stm32g4/src/bin/adc_differential.rs | 47 +++++++++++++++ examples/stm32g4/src/bin/adc_oversampling.rs | 57 +++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 examples/stm32g4/src/bin/adc_differential.rs create mode 100644 examples/stm32g4/src/bin/adc_oversampling.rs diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index c1e584f59..896a70578 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -1,4 +1,8 @@ #[allow(unused)] + +#[cfg(stm32g4)] +use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; +#[cfg(stm32h7)] use pac::adc::vals::{Adcaldif, Difsel, Exten}; use pac::adccommon::vals::Presc; @@ -228,6 +232,62 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat {} } + /// Enable differential channel. + /// Caution: + /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i] + /// is connected to another channel. As a consequence, this channel is no longer usable in + /// single-ended mode or in differential mode and must never be configured to be converted. + /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the + /// channel on the other ADC unusable. The only exception is when ADC master and the slave + /// operate in interleaved mode. + #[cfg(stm32g4)] + pub fn set_differential_channel(&mut self, ch: usize ,enable: bool) { + T::regs().cr().modify(|w| w.set_aden(false)); // disable adc + T::regs().difsel().modify(|w| { + w.set_difsel(ch, if enable { Difsel::DIFFERENTIAL } else { Difsel::SINGLEENDED }); + }); + T::regs().cr().modify(|w| w.set_aden(true)); + } + + #[cfg(stm32g4)] + pub fn set_differential(&mut self, channel: &mut impl AdcChannel, enable: bool) { + self.set_differential_channel(channel.channel() as usize, enable); + } + + /// Set oversampling shift. + #[cfg(stm32g4)] + pub fn set_oversampling_shift(&mut self, shift: u8) { + T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); + } + + /// Set oversampling ratio. + #[cfg(stm32g4)] + pub fn set_oversampling_ratio(&mut self, ratio: u8) { + T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); + } + + /// Enable oversampling in regular mode. + #[cfg(stm32g4)] + pub fn enable_regular_oversampling_mode(&mut self,mode:Rovsm,trig_mode:Trovs, enable: bool) { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + } + + // Reads that are not implemented as INJECTED in "blocking_read" + // #[cfg(stm32g4)] + // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) { + // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); + // } + + // #[cfg(stm32g4)] + // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) { + // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored), + // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); + // } + + /// Set the ADC sample time. pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 7a7d7cd8e..b530bb4c8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -26,6 +26,7 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(adc_f1, adc_f3_v2)))] pub use crate::pac::adc::vals::Res as Resolution; pub use crate::pac::adc::vals::SampleTime; +pub use crate::pac::adc::vals ; use crate::peripherals; dma_trait!(RxDma, Instance); diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs new file mode 100644 index 000000000..78d071d45 --- /dev/null +++ b/examples/stm32g4/src/bin/adc_differential.rs @@ -0,0 +1,47 @@ +//! adc differential mode example +//! +//! This example uses adc1 in differential mode +//! p:pa0 n:pa1 + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } + let mut p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1); + adc.set_sample_time(SampleTime::CYCLES247_5); + adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1 + + // can also use + // adc.set_differential_channel(1, true); + info!("adc initialized"); + loop { + let measured = adc.blocking_read(&mut p.PA0); + info!("data: {}", measured); + Timer::after_millis(500).await; + } +} diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs new file mode 100644 index 000000000..d31eb20f8 --- /dev/null +++ b/examples/stm32g4/src/bin/adc_oversampling.rs @@ -0,0 +1,57 @@ +//! adc oversampling example +//! +//! This example uses adc oversampling to achieve 16bit data + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::vals::{Rovsm, Trovs}; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } + let mut p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1); + adc.set_sample_time(SampleTime::CYCLES6_5); + // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + // page652 Oversampler + // Table 172. Maximum output results vs N and M. Grayed values indicates truncation + // 0x00 oversampling ratio X2 + // 0x01 oversampling ratio X4 + // 0x02 oversampling ratio X8 + // 0x03 oversampling ratio X16 + // 0x04 oversampling ratio X32 + // 0x05 oversampling ratio X64 + // 0x06 oversampling ratio X128 + // 0x07 oversampling ratio X256 + adc.set_oversampling_ratio(0x03); // ratio X3 + adc.set_oversampling_shift(0b0000); // no shift + adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true); + + loop { + let measured = adc.blocking_read(&mut p.PA0); + info!("data: 0x{:X}", measured); //max 0xFFF0 -> 65520 + Timer::after_millis(500).await; + } +} From fd5501d455f2e2e6aab9f09767599fcb16d33937 Mon Sep 17 00:00:00 2001 From: Chen Yuheng <1016867898@qq.com> Date: Thu, 11 Jul 2024 15:34:34 +0800 Subject: [PATCH 008/210] delete unused "info!" and fmt --- embassy-stm32/src/adc/g4.rs | 22 ++++++++++++++-------- embassy-stm32/src/adc/mod.rs | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 896a70578..3e9ba8ae2 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -1,9 +1,9 @@ #[allow(unused)] - -#[cfg(stm32g4)] -use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; #[cfg(stm32h7)] use pac::adc::vals::{Adcaldif, Difsel, Exten}; +#[allow(unused)] +#[cfg(stm32g4)] +use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; use pac::adccommon::vals::Presc; use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; @@ -241,10 +241,17 @@ impl<'d, T: Instance> Adc<'d, T> { /// channel on the other ADC unusable. The only exception is when ADC master and the slave /// operate in interleaved mode. #[cfg(stm32g4)] - pub fn set_differential_channel(&mut self, ch: usize ,enable: bool) { + pub fn set_differential_channel(&mut self, ch: usize, enable: bool) { T::regs().cr().modify(|w| w.set_aden(false)); // disable adc T::regs().difsel().modify(|w| { - w.set_difsel(ch, if enable { Difsel::DIFFERENTIAL } else { Difsel::SINGLEENDED }); + w.set_difsel( + ch, + if enable { + Difsel::DIFFERENTIAL + } else { + Difsel::SINGLEENDED + }, + ); }); T::regs().cr().modify(|w| w.set_aden(true)); } @@ -268,8 +275,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// Enable oversampling in regular mode. #[cfg(stm32g4)] - pub fn enable_regular_oversampling_mode(&mut self,mode:Rovsm,trig_mode:Trovs, enable: bool) { - T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); } @@ -287,7 +294,6 @@ impl<'d, T: Instance> Adc<'d, T> { // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); // } - /// Set the ADC sample time. pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index b530bb4c8..30f7de09b 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -23,10 +23,10 @@ pub use _version::*; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; +pub use crate::pac::adc::vals; #[cfg(not(any(adc_f1, adc_f3_v2)))] pub use crate::pac::adc::vals::Res as Resolution; pub use crate::pac::adc::vals::SampleTime; -pub use crate::pac::adc::vals ; use crate::peripherals; dma_trait!(RxDma, Instance); From 32019ed9b788adb4572437713ff5a233d2218adf Mon Sep 17 00:00:00 2001 From: David Haig Date: Wed, 17 Jul 2024 15:37:56 +0100 Subject: [PATCH 009/210] Allow cmd buffer to be passed in for dma memory --- embassy-stm32/src/sdmmc/mod.rs | 91 +++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ee5539518..2490db4c6 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -94,6 +94,34 @@ impl DerefMut for DataBlock { } } +/// Command Block buffer for SDMMC command transfers. +/// +/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct CmdBlock(pub [u32; 16]); + +impl CmdBlock { + /// Creates a new instance of CmdBlock + pub const fn new() -> Self { + Self([0u32; 16]) + } +} + +impl Deref for CmdBlock { + type Target = [u32; 16]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for CmdBlock { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + /// Errors #[non_exhaustive] #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -678,7 +706,11 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// Attempt to set a new signalling mode. The selected /// signalling mode is returned. Expects the current clock /// frequency to be > 12.5MHz. - async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result { + async fn switch_signalling_mode( + &mut self, + signalling: Signalling, + cmd_buffer: &mut CmdBlock, + ) -> Result { // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not // necessary" @@ -692,13 +724,13 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Signalling::SDR12 => 0xFF_FF00, }; - let mut status = [0u32; 16]; + let status = cmd_buffer.as_mut(); // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = self.prepare_datapath_read(&mut status, 64, 6); + let transfer = self.prepare_datapath_read(status, 64, 6); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 @@ -766,20 +798,20 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Reads the SD Status (ACMD13) - async fn read_sd_status(&mut self) -> Result<(), Error> { + async fn read_sd_status(&mut self, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; let rca = card.rca; Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP - let mut status = [0u32; 16]; + let status = cmd_buffer; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = self.prepare_datapath_read(&mut status, 64, 6); + let transfer = self.prepare_datapath_read(status.as_mut(), 64, 6); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::card_status(0), true)?; @@ -813,7 +845,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { for byte in status.iter_mut() { *byte = u32::from_be(*byte); } - self.card.as_mut().unwrap().status = status.into(); + self.card.as_mut().unwrap().status = status.0.into(); } res } @@ -867,18 +899,18 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { }); } - async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { + async fn get_scr(&mut self, card: &mut Card, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { // Read the the 64-bit SCR register Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; - let mut scr = [0u32; 2]; + let scr = &mut cmd_buffer.0[..2]; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); + let transfer = self.prepare_datapath_read(scr, 8, 3); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd51(), true)?; @@ -910,7 +942,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { drop(transfer); unsafe { - let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); + let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); card.scr = SCR(u64::from_be_bytes(*scr_bytes)); } } @@ -1002,9 +1034,18 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Self::stop_datapath(); } - /// Initializes card (if present) and sets the bus at the - /// specified frequency. + /// Initializes card (if present) and sets the bus at the specified frequency. pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { + let mut cmd_buffer = CmdBlock::new(); + self.init_card_with_cmd_buffer(freq, &mut cmd_buffer).await + } + + /// Initializes card (if present) and sets the bus at the specified frequency. + /// A cmd_buffer should be passed in if the DMA requirements mean that + /// stack memory can't be used (the default in `init_card`). + /// This usually manifests itself as an indefinite wait on a dma transfer because the + /// dma peripheral cannot access the memory. + pub async fn init_card_with_cmd_buffer(&mut self, freq: Hertz, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { let regs = T::regs(); let ker_ck = T::frequency(); @@ -1093,7 +1134,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { self.select_card(Some(&card))?; - self.get_scr(&mut card).await?; + self.get_scr(&mut card, cmd_buffer).await?; // Set bus width let (width, acmd_arg) = match bus_width { @@ -1128,11 +1169,11 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { self.card = Some(card); // Read status - self.read_sd_status().await?; + self.read_sd_status(cmd_buffer).await?; if freq.0 > 25_000_000 { // Switch to SDR25 - self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; + self.signalling = self.switch_signalling_mode(Signalling::SDR25, cmd_buffer).await?; if self.signalling == Signalling::SDR25 { // Set final clock frequency @@ -1143,8 +1184,9 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } } } + // Read status after signalling change - self.read_sd_status().await?; + self.read_sd_status(cmd_buffer).await?; Ok(()) } @@ -1204,6 +1246,19 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// Write a data block. pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { + let mut cmd_buffer = CmdBlock::new(); + self.write_block_with_cmd_buffer(block_idx, buffer, &mut cmd_buffer) + .await + } + + /// Write a data block and pass in a cmd buffer rather than using a stack allocated one. + /// This is required if stack RAM cannot be used with DMA + pub async fn write_block_with_cmd_buffer( + &mut self, + block_idx: u32, + buffer: &DataBlock, + cmd_buffer: &mut CmdBlock, + ) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; // NOTE(unsafe) DataBlock uses align 4 @@ -1263,7 +1318,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { // Try to read card status (ACMD13) while timeout > 0 { - match self.read_sd_status().await { + match self.read_sd_status(cmd_buffer).await { Ok(_) => return Ok(()), Err(Error::Timeout) => (), // Try again Err(e) => return Err(e), From e7270e00f62af13cef68e52a0330f66260901b68 Mon Sep 17 00:00:00 2001 From: David Haig Date: Fri, 19 Jul 2024 02:03:53 +0100 Subject: [PATCH 010/210] Added set_cmd_block for dma memory compatibility --- embassy-stm32/src/sdmmc/mod.rs | 93 +++++++++++++++++----------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 2490db4c6..44ff9fcd5 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -320,6 +320,10 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma = NoDma> { signalling: Signalling, /// Card card: Option, + + /// An optional buffer to be used for commands + /// This should be used if there are special memory location requirements for dma + cmd_block: Option<&'d mut CmdBlock>, } const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); @@ -523,6 +527,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { clock: SD_INIT_FREQ, signalling: Default::default(), card: None, + cmd_block: None, } } @@ -559,8 +564,10 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// # Safety /// /// `buffer` must be valid for the whole transfer and word aligned + #[allow(unused_variables)] fn prepare_datapath_read<'a>( - &'a mut self, + config: &Config, + dma: &'a mut PeripheralRef<'d, Dma>, buffer: &'a mut [u32], length_bytes: u32, block_size: u8, @@ -572,15 +579,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Self::wait_idle(); Self::clear_interrupt_flags(); - regs.dtimer() - .write(|w| w.set_datatime(self.config.data_transfer_timeout)); + regs.dtimer().write(|w| w.set_datatime(config.data_transfer_timeout)); regs.dlenr().write(|w| w.set_datalength(length_bytes)); #[cfg(sdmmc_v1)] let transfer = unsafe { - let request = self.dma.request(); + let request = dma.request(); Transfer::new_read( - &mut self.dma, + dma, request, regs.fifor().as_ptr() as *mut u32, buffer, @@ -706,11 +712,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// Attempt to set a new signalling mode. The selected /// signalling mode is returned. Expects the current clock /// frequency to be > 12.5MHz. - async fn switch_signalling_mode( - &mut self, - signalling: Signalling, - cmd_buffer: &mut CmdBlock, - ) -> Result { + async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result { // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not // necessary" @@ -724,13 +726,16 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Signalling::SDR12 => 0xFF_FF00, }; - let status = cmd_buffer.as_mut(); + let status = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), + }; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = self.prepare_datapath_read(status, 64, 6); + let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 @@ -798,20 +803,25 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } /// Reads the SD Status (ACMD13) - async fn read_sd_status(&mut self, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { + async fn read_sd_status(&mut self) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; let rca = card.rca; + let cmd_block = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), + }; + Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP - let status = cmd_buffer; + let status = cmd_block; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = self.prepare_datapath_read(status.as_mut(), 64, 6); + let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::card_status(0), true)?; @@ -899,18 +909,22 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { }); } - async fn get_scr(&mut self, card: &mut Card, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { + async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { // Read the the 64-bit SCR register Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; - let scr = &mut cmd_buffer.0[..2]; + let cmd_block = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), + }; + let scr = &mut cmd_block.0[..2]; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = self.prepare_datapath_read(scr, 8, 3); + let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd51(), true)?; @@ -1036,16 +1050,6 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// Initializes card (if present) and sets the bus at the specified frequency. pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { - let mut cmd_buffer = CmdBlock::new(); - self.init_card_with_cmd_buffer(freq, &mut cmd_buffer).await - } - - /// Initializes card (if present) and sets the bus at the specified frequency. - /// A cmd_buffer should be passed in if the DMA requirements mean that - /// stack memory can't be used (the default in `init_card`). - /// This usually manifests itself as an indefinite wait on a dma transfer because the - /// dma peripheral cannot access the memory. - pub async fn init_card_with_cmd_buffer(&mut self, freq: Hertz, cmd_buffer: &mut CmdBlock) -> Result<(), Error> { let regs = T::regs(); let ker_ck = T::frequency(); @@ -1134,7 +1138,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { self.select_card(Some(&card))?; - self.get_scr(&mut card, cmd_buffer).await?; + self.get_scr(&mut card).await?; // Set bus width let (width, acmd_arg) = match bus_width { @@ -1169,11 +1173,11 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { self.card = Some(card); // Read status - self.read_sd_status(cmd_buffer).await?; + self.read_sd_status().await?; if freq.0 > 25_000_000 { // Switch to SDR25 - self.signalling = self.switch_signalling_mode(Signalling::SDR25, cmd_buffer).await?; + self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; if self.signalling == Signalling::SDR25 { // Set final clock frequency @@ -1186,7 +1190,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } // Read status after signalling change - self.read_sd_status(cmd_buffer).await?; + self.read_sd_status().await?; Ok(()) } @@ -1210,7 +1214,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = self.prepare_datapath_read(buffer, 512, 9); + let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::read_single_block(address), true)?; @@ -1246,19 +1250,6 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { /// Write a data block. pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { - let mut cmd_buffer = CmdBlock::new(); - self.write_block_with_cmd_buffer(block_idx, buffer, &mut cmd_buffer) - .await - } - - /// Write a data block and pass in a cmd buffer rather than using a stack allocated one. - /// This is required if stack RAM cannot be used with DMA - pub async fn write_block_with_cmd_buffer( - &mut self, - block_idx: u32, - buffer: &DataBlock, - cmd_buffer: &mut CmdBlock, - ) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; // NOTE(unsafe) DataBlock uses align 4 @@ -1318,7 +1309,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { // Try to read card status (ACMD13) while timeout > 0 { - match self.read_sd_status(cmd_buffer).await { + match self.read_sd_status().await { Ok(_) => return Ok(()), Err(Error::Timeout) => (), // Try again Err(e) => return Err(e), @@ -1346,6 +1337,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { pub fn clock(&self) -> Hertz { self.clock } + + /// Set a specific cmd buffer rather than using the default stack allocated one. + /// This is required if stack RAM cannot be used with DMA and usually manifests + /// itself as an indefinite wait on a dma transfer because the dma peripheral + /// cannot access the memory. + pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { + self.cmd_block = Some(cmd_block) + } } impl<'d, T: Instance, Dma: SdmmcDma + 'd> Drop for Sdmmc<'d, T, Dma> { From 7c1ecae53f062b26e06850fd66f7acb754a0f680 Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Sat, 13 Jul 2024 20:36:26 +0200 Subject: [PATCH 011/210] Add read_to_break_with_count --- embassy-rp/src/uart/mod.rs | 257 ++++++++++++++++++++++--------------- 1 file changed, 156 insertions(+), 101 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index f546abe71..d50f5b4d5 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -490,6 +490,36 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { /// * The first call to `read_to_break()` will return `Ok(20)`. /// * The next call to `read_to_break()` will work as expected pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result { + self.read_to_break_with_count(buffer, 0).await + } + + /// Read from the UART, waiting for a line break as soon as at least `min_count` bytes have been read. + /// + /// We read until one of the following occurs: + /// + /// * We read `buffer.len()` bytes without a line break + /// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))` + /// * We read `n > min_count` bytes then a line break occurs + /// * returns `Ok(n)` + /// * We encounter some error OTHER than a line break + /// * returns `Err(ReadToBreakError::Other(error))` + /// + /// If a line break occurs before `min_count` bytes have been read, the break will be ignored and the read will continue + /// + /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected + /// message to reliably detect the framing on one single call to `read_to_break()`. + /// + /// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer: + /// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))` + /// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break + /// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer: + /// * The first call to `read_to_break()` will return `Ok(20)`. + /// * The next call to `read_to_break()` will work as expected + pub async fn read_to_break_with_count( + &mut self, + buffer: &mut [u8], + min_count: usize, + ) -> Result { // clear error flags before we drain the fifo. errors that have accumulated // in the flags will also be present in the fifo. T::dma_state().rx_errs.store(0, Ordering::Relaxed); @@ -502,7 +532,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // then drain the fifo. we need to read at most 32 bytes. errors that apply // to fifo bytes will be reported directly. - let sbuffer = match { + let mut sbuffer = match { let limit = buffer.len().min(32); self.drain_fifo(&mut buffer[0..limit]) } { @@ -511,7 +541,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // Drained (some/all of the fifo), no room left Ok(len) => return Err(ReadToBreakError::MissingBreak(len)), // We got a break WHILE draining the FIFO, return what we did get before the break - Err((i, Error::Break)) => return Ok(i), + Err((len, Error::Break)) => { + if len < min_count && len < buffer.len() { + &mut buffer[len..] + } else { + return Ok(len); + } + } // Some other error, just return the error Err((_i, e)) => return Err(ReadToBreakError::Other(e)), }; @@ -530,110 +566,118 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { reg.set_rxdmae(true); reg.set_dmaonerr(true); }); - let transfer = unsafe { - // If we don't assign future to a variable, the data register pointer - // is held across an await and makes the future non-Send. - crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ) - }; - // wait for either the transfer to complete or an error to happen. - let transfer_result = select( - transfer, - poll_fn(|cx| { - T::dma_state().rx_err_waker.register(cx.waker()); - match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { - 0 => Poll::Pending, - e => Poll::Ready(Uartris(e as u32)), + loop { + let transfer = unsafe { + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ) + }; + + // wait for either the transfer to complete or an error to happen. + let transfer_result = select( + transfer, + poll_fn(|cx| { + T::dma_state().rx_err_waker.register(cx.waker()); + match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { + 0 => Poll::Pending, + e => Poll::Ready(Uartris(e as u32)), + } + }), + ) + .await; + + // Figure out our error state + let errors = match transfer_result { + Either::First(()) => { + // We're here because the DMA finished, BUT if an error occurred on the LAST + // byte, then we may still need to grab the error state! + Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) } - }), - ) - .await; - - // Figure out our error state - let errors = match transfer_result { - Either::First(()) => { - // We're here because the DMA finished, BUT if an error occurred on the LAST - // byte, then we may still need to grab the error state! - Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) - } - Either::Second(e) => { - // We're here because we errored, which means this is the error that - // was problematic. - e - } - }; - - if errors.0 == 0 { - // No errors? That means we filled the buffer without a line break. - // For THIS function, that's a problem. - return Err(ReadToBreakError::MissingBreak(buffer.len())); - } else if errors.beris() { - // We got a Line Break! By this point, we've finished/aborted the DMA - // transaction, which means that we need to figure out where it left off - // by looking at the write_addr. - // - // First, we do a sanity check to make sure the write value is within the - // range of DMA we just did. - let sval = buffer.as_ptr() as usize; - let eval = sval + buffer.len(); - - // This is the address where the DMA would write to next - let next_addr = ch.regs().write_addr().read() as usize; - - // If we DON'T end up inside the range, something has gone really wrong. - // Note that it's okay that `eval` is one past the end of the slice, as - // this is where the write pointer will end up at the end of a full - // transfer. - if (next_addr < sval) || (next_addr > eval) { - unreachable!("UART DMA reported invalid `write_addr`"); - } - - let regs = T::regs(); - let all_full = next_addr == eval; - - // NOTE: This is off label usage of RSR! See the issue below for - // why I am not checking if there is an "extra" FIFO byte, and why - // I am checking RSR directly (it seems to report the status of the LAST - // POPPED value, rather than the NEXT TO POP value like the datasheet - // suggests!) - // - // issue: https://github.com/raspberrypi/pico-feedback/issues/367 - let last_was_break = regs.uartrsr().read().be(); - - return match (all_full, last_was_break) { - (true, true) | (false, _) => { - // We got less than the full amount + a break, or the full amount - // and the last byte was a break. Subtract the break off by adding one to sval. - Ok(next_addr.saturating_sub(1 + sval)) - } - (true, false) => { - // We finished the whole DMA, and the last DMA'd byte was NOT a break - // character. This is an error. - // - // NOTE: we COULD potentially return Ok(buffer.len()) here, since we - // know a line break occured at SOME POINT after the DMA completed. - // - // However, we have no way of knowing if there was extra data BEFORE - // that line break, so instead return an Err to signal to the caller - // that there are "leftovers", and they'll catch the actual line break - // on the next call. - // - // Doing it like this also avoids racyness: now whether you finished - // the full read BEFORE the line break occurred or AFTER the line break - // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes - // getting `Ok(buffer.len())` if you were "late enough" to observe the - // line break. - Err(ReadToBreakError::MissingBreak(buffer.len())) + Either::Second(e) => { + // We're here because we errored, which means this is the error that + // was problematic. + e } }; - } else if errors.oeris() { - return Err(ReadToBreakError::Other(Error::Overrun)); - } else if errors.peris() { - return Err(ReadToBreakError::Other(Error::Parity)); - } else if errors.feris() { - return Err(ReadToBreakError::Other(Error::Framing)); + + if errors.0 == 0 { + // No errors? That means we filled the buffer without a line break. + // For THIS function, that's a problem. + return Err(ReadToBreakError::MissingBreak(buffer.len())); + } else if errors.beris() { + // We got a Line Break! By this point, we've finished/aborted the DMA + // transaction, which means that we need to figure out where it left off + // by looking at the write_addr. + // + // First, we do a sanity check to make sure the write value is within the + // range of DMA we just did. + let sval = buffer.as_ptr() as usize; + let eval = sval + buffer.len(); + + // This is the address where the DMA would write to next + let next_addr = ch.regs().write_addr().read() as usize; + + // If we DON'T end up inside the range, something has gone really wrong. + // Note that it's okay that `eval` is one past the end of the slice, as + // this is where the write pointer will end up at the end of a full + // transfer. + if (next_addr < sval) || (next_addr > eval) { + unreachable!("UART DMA reported invalid `write_addr`"); + } + + if (next_addr - sval) < min_count { + sbuffer = &mut buffer[(next_addr - sval)..]; + continue; + } + + let regs = T::regs(); + let all_full = next_addr == eval; + + // NOTE: This is off label usage of RSR! See the issue below for + // why I am not checking if there is an "extra" FIFO byte, and why + // I am checking RSR directly (it seems to report the status of the LAST + // POPPED value, rather than the NEXT TO POP value like the datasheet + // suggests!) + // + // issue: https://github.com/raspberrypi/pico-feedback/issues/367 + let last_was_break = regs.uartrsr().read().be(); + + return match (all_full, last_was_break) { + (true, true) | (false, _) => { + // We got less than the full amount + a break, or the full amount + // and the last byte was a break. Subtract the break off by adding one to sval. + Ok(next_addr.saturating_sub(1 + sval)) + } + (true, false) => { + // We finished the whole DMA, and the last DMA'd byte was NOT a break + // character. This is an error. + // + // NOTE: we COULD potentially return Ok(buffer.len()) here, since we + // know a line break occured at SOME POINT after the DMA completed. + // + // However, we have no way of knowing if there was extra data BEFORE + // that line break, so instead return an Err to signal to the caller + // that there are "leftovers", and they'll catch the actual line break + // on the next call. + // + // Doing it like this also avoids racyness: now whether you finished + // the full read BEFORE the line break occurred or AFTER the line break + // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes + // getting `Ok(buffer.len())` if you were "late enough" to observe the + // line break. + Err(ReadToBreakError::MissingBreak(buffer.len())) + } + }; + } else if errors.oeris() { + return Err(ReadToBreakError::Other(Error::Overrun)); + } else if errors.peris() { + return Err(ReadToBreakError::Other(Error::Parity)); + } else if errors.feris() { + return Err(ReadToBreakError::Other(Error::Framing)); + } + unreachable!("unrecognized rx error"); } - unreachable!("unrecognized rx error"); } } @@ -997,6 +1041,17 @@ impl<'d, T: Instance> Uart<'d, T, Async> { pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result { self.rx.read_to_break(buf).await } + + /// Read until the buffer is full or a line break occurs after at least `min_count` bytes have been read. + /// + /// See [`UartRx::read_to_break_with_count()`] for more details + pub async fn read_to_break_with_count<'a>( + &mut self, + buf: &'a mut [u8], + min_count: usize, + ) -> Result { + self.rx.read_to_break_with_count(buf, min_count).await + } } impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for UartRx<'d, T, M> { From e6f4db507d62178ddb05a4569a9f9352a25222e0 Mon Sep 17 00:00:00 2001 From: Samuel Hicks Date: Fri, 19 Jul 2024 17:45:29 +0100 Subject: [PATCH 012/210] net/tcp: fix flush() waiting forever if socket is reset with pending write data --- embassy-net/src/tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index be0e1a129..18200287e 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -515,7 +515,7 @@ impl<'d> TcpIo<'d> { async fn flush(&mut self) -> Result<(), Error> { poll_fn(move |cx| { self.with_mut(|s, _| { - let data_pending = s.send_queue() > 0; + let data_pending = (s.send_queue() > 0) && s.state() != tcp::State::Closed; let fin_pending = matches!( s.state(), tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck From dc6639fa4d53ec7ad6a6aa0bd810952e4123e51d Mon Sep 17 00:00:00 2001 From: Mark Tomlin Date: Mon, 22 Jul 2024 06:59:13 -0400 Subject: [PATCH 013/210] Updated github branch from `master` to `main`. --- docs/pages/basic_application.adoc | 2 +- docs/pages/nrf.adoc | 2 +- docs/pages/overview.adoc | 2 +- docs/pages/stm32.adoc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/pages/basic_application.adoc b/docs/pages/basic_application.adoc index 7b4ebda4f..5c4e3e8b3 100644 --- a/docs/pages/basic_application.adoc +++ b/docs/pages/basic_application.adoc @@ -4,7 +4,7 @@ So you've got one of the examples running, but what now? Let's go through a simp == Main -The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/examples/basic[here]. +The full example can be found link:https://github.com/embassy-rs/embassy/tree/main/docs/examples/basic[here]. NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly. diff --git a/docs/pages/nrf.adoc b/docs/pages/nrf.adoc index 1706087ae..de052b63f 100644 --- a/docs/pages/nrf.adoc +++ b/docs/pages/nrf.adoc @@ -1,6 +1,6 @@ = Embassy nRF HAL -The link:https://github.com/embassy-rs/embassy/tree/master/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs]. +The link:https://github.com/embassy-rs/embassy/tree/main/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs]. == Timer driver diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 1b9381bfe..7d59d5521 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -48,7 +48,7 @@ link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a w link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. === Bootloader and DFU -link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. +link:https://github.com/embassy-rs/embassy/tree/main/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. == What is DMA? diff --git a/docs/pages/stm32.adoc b/docs/pages/stm32.adoc index 7bfc0592b..df139a420 100644 --- a/docs/pages/stm32.adoc +++ b/docs/pages/stm32.adoc @@ -1,6 +1,6 @@ = Embassy STM32 HAL -The link:https://github.com/embassy-rs/embassy/tree/master/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project. +The link:https://github.com/embassy-rs/embassy/tree/main/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project. == The infinite variant problem From 4811c14cc8ad57251e50e3aaa6d221f80603f577 Mon Sep 17 00:00:00 2001 From: Mark Tomlin Date: Mon, 22 Jul 2024 07:26:55 -0400 Subject: [PATCH 014/210] Updated cargo toml section links. --- docs/pages/new_project.adoc | 2 +- docs/pages/sharing_peripherals.adoc | 4 ++-- docs/pages/time_keeping.adoc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc index 346d9f0f8..821bcbd27 100644 --- a/docs/pages/new_project.adoc +++ b/docs/pages/new_project.adoc @@ -1,6 +1,6 @@ = Starting a new project -Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. +Once you’ve successfully xref:#_getting_started[run some example projects], the next step is to make a standalone Embassy project. == Tools for generating Embassy projects diff --git a/docs/pages/sharing_peripherals.adoc b/docs/pages/sharing_peripherals.adoc index 6ba13f93b..dfb8c1ffe 100644 --- a/docs/pages/sharing_peripherals.adoc +++ b/docs/pages/sharing_peripherals.adoc @@ -8,7 +8,7 @@ The following examples shows different ways to use the on-board LED on a Raspber Using mutual exclusion is the simplest way to share a peripheral. -TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. +TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here]. [,rust] ---- use defmt::*; @@ -78,7 +78,7 @@ To indicate that the pin will be set to an Output. The `AnyPin` could have been A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things. -TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. +TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here]. [,rust] ---- use defmt::*; diff --git a/docs/pages/time_keeping.adoc b/docs/pages/time_keeping.adoc index 17492a884..11ddb2b2b 100644 --- a/docs/pages/time_keeping.adoc +++ b/docs/pages/time_keeping.adoc @@ -16,7 +16,7 @@ The `embassy::time::Timer` type provides two timing methods. An example of a delay is provided as follows: -TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. +TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here]. [,rust] ---- use embassy::executor::{task, Executor}; @@ -41,7 +41,7 @@ that expect a generic delay implementation to be provided. An example of how this can be used: -TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. +TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here]. [,rust] ---- use embassy::executor::{task, Executor}; From 2436335f9b8a1b1bc4a2eb1b738f4a52a454c29e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 24 Jul 2024 17:17:04 +0200 Subject: [PATCH 015/210] ci: add instructions to install cargo-batch if not installed. --- ci.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ci.sh b/ci.sh index 15bb6eec0..341fe6a09 100755 --- a/ci.sh +++ b/ci.sh @@ -2,6 +2,14 @@ set -eo pipefail +if ! command -v cargo-batch &> /dev/null; then + echo "cargo-batch could not be found. Install it with the following command:" + echo "" + echo " cargo install --git https://github.com/embassy-rs/cargo-batch cargo --bin cargo-batch --locked" + echo "" + exit 1 +fi + # check-cfg is stable on rustc 1.79 but not cargo 1.79. # however, our cargo-batch is currently based on cargo 1.80, which does support check-cfg. # so, force build.rs scripts to emit check-cfg commands. From 1598dd55e4f75c616d5461bde4289b962ff77615 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 24 Jul 2024 17:31:01 +0200 Subject: [PATCH 016/210] tests/rp: add timer test. --- tests/rp/src/bin/timer.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/rp/src/bin/timer.rs diff --git a/tests/rp/src/bin/timer.rs b/tests/rp/src/bin/timer.rs new file mode 100644 index 000000000..be9242144 --- /dev/null +++ b/tests/rp/src/bin/timer.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] +teleprobe_meta::target!(b"rpi-pico"); + +use defmt::{assert, *}; +use embassy_executor::Spawner; +use embassy_time::{Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let start = Instant::now(); + Timer::after_millis(100).await; + let end = Instant::now(); + let ms = (end - start).as_millis(); + info!("slept for {} ms", ms); + assert!(ms >= 99); + assert!(ms < 110); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From 6ef9e564cad088c246af97f408c5b34dc47301b5 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 25 Jul 2024 12:22:55 +0200 Subject: [PATCH 017/210] Add extra lifetime to opamp-using structs --- embassy-stm32/src/opamp.rs | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index ca94a573d..f3f8368f8 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -38,15 +38,15 @@ impl From for crate::pac::opamp::vals::Opahsm { /// OpAmp external outputs, wired to a GPIO pad. /// /// This struct can also be used as an ADC input. -pub struct OpAmpOutput<'d, T: Instance> { - _inner: &'d OpAmp<'d, T>, +pub struct OpAmpOutput<'a, 'd: 'a, T: Instance> { + _inner: &'a OpAmp<'d, T>, } /// OpAmp internal outputs, wired directly to ADC inputs. /// /// This struct can be used as an ADC input. -pub struct OpAmpInternalOutput<'d, T: Instance> { - _inner: &'d OpAmp<'d, T>, +pub struct OpAmpInternalOutput<'a, 'd: 'a, T: Instance> { + _inner: &'a OpAmp<'d, T>, } /// OpAmp driver. @@ -80,11 +80,11 @@ impl<'d, T: Instance> OpAmp<'d, T> { /// directly used as an ADC input. The opamp will be disabled when the /// [`OpAmpOutput`] is dropped. pub fn buffer_ext( - &'d mut self, + &mut self, in_pin: impl Peripheral

+ crate::gpio::Pin>, out_pin: impl Peripheral

+ crate::gpio::Pin> + 'd, gain: OpAmpGain, - ) -> OpAmpOutput<'d, T> { + ) -> OpAmpOutput<'_, 'd, T> { into_ref!(in_pin); into_ref!(out_pin); in_pin.set_as_analog(); @@ -119,9 +119,9 @@ impl<'d, T: Instance> OpAmp<'d, T> { /// [`OpAmpOutput`] is dropped. #[cfg(opamp_g4)] pub fn buffer_dac( - &'d mut self, + &mut self, out_pin: impl Peripheral

+ crate::gpio::Pin> + 'd, - ) -> OpAmpOutput<'d, T> { + ) -> OpAmpOutput<'_, 'd, T> { into_ref!(out_pin); out_pin.set_as_analog(); @@ -147,10 +147,10 @@ impl<'d, T: Instance> OpAmp<'d, T> { /// The opamp output will be disabled when it is dropped. #[cfg(opamp_g4)] pub fn buffer_int( - &'d mut self, + &mut self, pin: impl Peripheral

+ crate::gpio::Pin>, gain: OpAmpGain, - ) -> OpAmpInternalOutput<'d, T> { + ) -> OpAmpInternalOutput<'_, 'd, T> { into_ref!(pin); pin.set_as_analog(); @@ -176,7 +176,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { } } -impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { +impl<'a, 'd: 'a, T: Instance> Drop for OpAmpOutput<'a, 'd, T> { fn drop(&mut self) { T::regs().csr().modify(|w| { w.set_opampen(false); @@ -184,7 +184,7 @@ impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { } } -impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { +impl<'a, 'd: 'a, T: Instance> Drop for OpAmpInternalOutput<'a, 'd, T> { fn drop(&mut self) { T::regs().csr().modify(|w| { w.set_opampen(false); @@ -224,16 +224,16 @@ macro_rules! impl_opamp_external_output { ($inst:ident, $adc:ident, $ch:expr) => { foreach_adc!( ($adc, $common_inst:ident, $adc_clock:ident) => { - impl<'d> crate::adc::SealedAdcChannel - for OpAmpOutput<'d, crate::peripherals::$inst> + impl<'a, 'd: 'a> crate::adc::SealedAdcChannel + for OpAmpOutput<'a, 'd, crate::peripherals::$inst> { fn channel(&self) -> u8 { $ch } } - impl<'d> crate::adc::AdcChannel - for OpAmpOutput<'d, crate::peripherals::$inst> + impl<'a, 'd: 'a> crate::adc::AdcChannel + for OpAmpOutput<'a, 'd, crate::peripherals::$inst> { } }; @@ -270,16 +270,16 @@ macro_rules! impl_opamp_internal_output { ($inst:ident, $adc:ident, $ch:expr) => { foreach_adc!( ($adc, $common_inst:ident, $adc_clock:ident) => { - impl<'d> crate::adc::SealedAdcChannel - for OpAmpInternalOutput<'d, crate::peripherals::$inst> + impl<'a, 'd: 'a> crate::adc::SealedAdcChannel + for OpAmpInternalOutput<'a, 'd, crate::peripherals::$inst> { fn channel(&self) -> u8 { $ch } } - impl<'d> crate::adc::AdcChannel - for OpAmpInternalOutput<'d, crate::peripherals::$inst> + impl<'a, 'd: 'a> crate::adc::AdcChannel + for OpAmpInternalOutput<'a, 'd, crate::peripherals::$inst> { } }; From 2d678d695637ed1023fd80fea482d60a288e4343 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 25 Jul 2024 15:53:00 +0200 Subject: [PATCH 018/210] Update to Rust 1.80, make check-cfg unconditional. --- ci.sh | 6 ------ embassy-executor/build_common.rs | 21 +-------------------- embassy-hal-internal/build_common.rs | 21 +-------------------- embassy-rp/src/i2c.rs | 18 ++++++------------ embassy-stm32/build_common.rs | 21 +-------------------- embassy-stm32/src/adc/mod.rs | 1 + embassy-stm32/src/opamp.rs | 2 ++ embassy-stm32/src/ospi/mod.rs | 17 +++++------------ embassy-stm32/src/spi/mod.rs | 1 + embassy-sync/build_common.rs | 21 +-------------------- embassy-usb/src/msos.rs | 2 ++ rust-toolchain.toml | 2 +- 12 files changed, 22 insertions(+), 111 deletions(-) diff --git a/ci.sh b/ci.sh index 341fe6a09..4c9397cee 100755 --- a/ci.sh +++ b/ci.sh @@ -10,12 +10,6 @@ if ! command -v cargo-batch &> /dev/null; then exit 1 fi -# check-cfg is stable on rustc 1.79 but not cargo 1.79. -# however, our cargo-batch is currently based on cargo 1.80, which does support check-cfg. -# so, force build.rs scripts to emit check-cfg commands. -# when 1.80 hits stable we can make build.rs unconditionally emit check-cfg and remove all this. -export EMBASSY_FORCE_CHECK_CFG=1 - export RUSTFLAGS=-Dwarnings export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info if [[ -z "${CARGO_TARGET_DIR}" ]]; then diff --git a/embassy-executor/build_common.rs b/embassy-executor/build_common.rs index 0487eb3c5..4f24e6d37 100644 --- a/embassy-executor/build_common.rs +++ b/embassy-executor/build_common.rs @@ -8,8 +8,6 @@ use std::collections::HashSet; use std::env; -use std::ffi::OsString; -use std::process::Command; /// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring /// them (`cargo:rust-check-cfg=cfg(X)`). @@ -17,7 +15,6 @@ use std::process::Command; pub struct CfgSet { enabled: HashSet, declared: HashSet, - emit_declared: bool, } impl CfgSet { @@ -25,7 +22,6 @@ impl CfgSet { Self { enabled: HashSet::new(), declared: HashSet::new(), - emit_declared: is_rustc_nightly(), } } @@ -49,7 +45,7 @@ impl CfgSet { /// /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. pub fn declare(&mut self, cfg: impl AsRef) { - if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { + if self.declared.insert(cfg.as_ref().to_owned()) { println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); } } @@ -69,21 +65,6 @@ impl CfgSet { } } -fn is_rustc_nightly() -> bool { - if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() { - return true; - } - - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - String::from_utf8_lossy(&output.stdout).contains("nightly") -} - /// Sets configs that describe the target platform. pub fn set_target_cfgs(cfgs: &mut CfgSet) { let target = env::var("TARGET").unwrap(); diff --git a/embassy-hal-internal/build_common.rs b/embassy-hal-internal/build_common.rs index 0487eb3c5..4f24e6d37 100644 --- a/embassy-hal-internal/build_common.rs +++ b/embassy-hal-internal/build_common.rs @@ -8,8 +8,6 @@ use std::collections::HashSet; use std::env; -use std::ffi::OsString; -use std::process::Command; /// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring /// them (`cargo:rust-check-cfg=cfg(X)`). @@ -17,7 +15,6 @@ use std::process::Command; pub struct CfgSet { enabled: HashSet, declared: HashSet, - emit_declared: bool, } impl CfgSet { @@ -25,7 +22,6 @@ impl CfgSet { Self { enabled: HashSet::new(), declared: HashSet::new(), - emit_declared: is_rustc_nightly(), } } @@ -49,7 +45,7 @@ impl CfgSet { /// /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. pub fn declare(&mut self, cfg: impl AsRef) { - if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { + if self.declared.insert(cfg.as_ref().to_owned()) { println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); } } @@ -69,21 +65,6 @@ impl CfgSet { } } -fn is_rustc_nightly() -> bool { - if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() { - return true; - } - - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - String::from_utf8_lossy(&output.stdout).contains("nightly") -} - /// Sets configs that describe the target platform. pub fn set_target_cfgs(cfgs: &mut CfgSet) { let target = env::var("TARGET").unwrap(); diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 10d3c86b3..ac2b1bc5a 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -312,13 +312,13 @@ impl<'d, T: Instance> I2c<'d, T, Async> { } } - /// Read from address into buffer using DMA. + /// Read from address into buffer asynchronously. pub async fn read_async(&mut self, addr: impl Into, buffer: &mut [u8]) -> Result<(), Error> { Self::setup(addr.into())?; self.read_async_internal(buffer, true, true).await } - /// Write to address from buffer using DMA. + /// Write to address from buffer asynchronously. pub async fn write_async( &mut self, addr: impl Into, @@ -328,7 +328,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { self.write_async_internal(bytes, true).await } - /// Write to address from bytes and read from address into buffer using DMA. + /// Write to address from bytes and read from address into buffer asynchronously. pub async fn write_read_async( &mut self, addr: impl Into, @@ -779,9 +779,6 @@ pub fn i2c_reserved_addr(addr: u16) -> bool { } pub(crate) trait SealedInstance { - const TX_DREQ: u8; - const RX_DREQ: u8; - fn regs() -> crate::pac::i2c::I2c; fn reset() -> crate::pac::resets::regs::Peripherals; fn waker() -> &'static AtomicWaker; @@ -816,11 +813,8 @@ pub trait Instance: SealedInstance { } macro_rules! impl_instance { - ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { + ($type:ident, $irq:ident, $reset:ident) => { impl SealedInstance for peripherals::$type { - const TX_DREQ: u8 = $tx_dreq; - const RX_DREQ: u8 = $rx_dreq; - #[inline] fn regs() -> pac::i2c::I2c { pac::$type @@ -846,8 +840,8 @@ macro_rules! impl_instance { }; } -impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); -impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); +impl_instance!(I2C0, I2C0_IRQ, set_i2c0); +impl_instance!(I2C1, I2C1_IRQ, set_i2c1); /// SDA pin. pub trait SdaPin: crate::gpio::Pin {} diff --git a/embassy-stm32/build_common.rs b/embassy-stm32/build_common.rs index 0487eb3c5..4f24e6d37 100644 --- a/embassy-stm32/build_common.rs +++ b/embassy-stm32/build_common.rs @@ -8,8 +8,6 @@ use std::collections::HashSet; use std::env; -use std::ffi::OsString; -use std::process::Command; /// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring /// them (`cargo:rust-check-cfg=cfg(X)`). @@ -17,7 +15,6 @@ use std::process::Command; pub struct CfgSet { enabled: HashSet, declared: HashSet, - emit_declared: bool, } impl CfgSet { @@ -25,7 +22,6 @@ impl CfgSet { Self { enabled: HashSet::new(), declared: HashSet::new(), - emit_declared: is_rustc_nightly(), } } @@ -49,7 +45,7 @@ impl CfgSet { /// /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. pub fn declare(&mut self, cfg: impl AsRef) { - if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { + if self.declared.insert(cfg.as_ref().to_owned()) { println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); } } @@ -69,21 +65,6 @@ impl CfgSet { } } -fn is_rustc_nightly() -> bool { - if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() { - return true; - } - - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - String::from_utf8_lossy(&output.stdout).contains("nightly") -} - /// Sets configs that describe the target platform. pub fn set_target_cfgs(cfgs: &mut CfgSet) { let target = env::var("TARGET").unwrap(); diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 7a7d7cd8e..26b729f70 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -2,6 +2,7 @@ #![macro_use] #![allow(missing_docs)] // TODO +#![cfg_attr(adc_f3_v2, allow(unused))] #[cfg(not(adc_f3_v2))] #[cfg_attr(adc_f1, path = "f1.rs")] diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index ca94a573d..789176b3d 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -45,6 +45,7 @@ pub struct OpAmpOutput<'d, T: Instance> { /// OpAmp internal outputs, wired directly to ADC inputs. /// /// This struct can be used as an ADC input. +#[cfg(opamp_g4)] pub struct OpAmpInternalOutput<'d, T: Instance> { _inner: &'d OpAmp<'d, T>, } @@ -184,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { } } +#[cfg(opamp_g4)] impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { fn drop(&mut self) { T::regs().csr().modify(|w| { diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index f6eb0d17c..289bfa672 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -1060,10 +1060,6 @@ pub(crate) trait SealedInstance { const REGS: Regs; } -trait SealedWord { - const CONFIG: u8; -} - /// OSPI instance trait. #[allow(private_bounds)] pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} @@ -1110,17 +1106,14 @@ impl<'d, T: Instance, M: PeriMode> GetConfig for Ospi<'d, T, M> { /// Word sizes usable for OSPI. #[allow(private_bounds)] -pub trait Word: word::Word + SealedWord {} +pub trait Word: word::Word {} macro_rules! impl_word { - ($T:ty, $config:expr) => { - impl SealedWord for $T { - const CONFIG: u8 = $config; - } + ($T:ty) => { impl Word for $T {} }; } -impl_word!(u8, 8); -impl_word!(u16, 16); -impl_word!(u32, 32); +impl_word!(u8); +impl_word!(u16); +impl_word!(u32); diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 656676d9f..20718147a 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -1282,6 +1282,7 @@ pub(crate) struct Info { struct State {} impl State { + #[allow(unused)] const fn new() -> Self { Self {} } diff --git a/embassy-sync/build_common.rs b/embassy-sync/build_common.rs index 0487eb3c5..4f24e6d37 100644 --- a/embassy-sync/build_common.rs +++ b/embassy-sync/build_common.rs @@ -8,8 +8,6 @@ use std::collections::HashSet; use std::env; -use std::ffi::OsString; -use std::process::Command; /// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring /// them (`cargo:rust-check-cfg=cfg(X)`). @@ -17,7 +15,6 @@ use std::process::Command; pub struct CfgSet { enabled: HashSet, declared: HashSet, - emit_declared: bool, } impl CfgSet { @@ -25,7 +22,6 @@ impl CfgSet { Self { enabled: HashSet::new(), declared: HashSet::new(), - emit_declared: is_rustc_nightly(), } } @@ -49,7 +45,7 @@ impl CfgSet { /// /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. pub fn declare(&mut self, cfg: impl AsRef) { - if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { + if self.declared.insert(cfg.as_ref().to_owned()) { println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); } } @@ -69,21 +65,6 @@ impl CfgSet { } } -fn is_rustc_nightly() -> bool { - if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() { - return true; - } - - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to run `rustc --version`"); - - String::from_utf8_lossy(&output.stdout).contains("nightly") -} - /// Sets configs that describe the target platform. pub fn set_target_cfgs(cfgs: &mut CfgSet) { let target = env::var("TARGET").unwrap(); diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index 25936d084..9f4e1a57b 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs @@ -278,6 +278,7 @@ pub enum DescriptorType { /// Table 5. Descriptor set information structure. #[allow(non_snake_case)] +#[allow(unused)] #[repr(C, packed(1))] pub struct DescriptorSetInformation { dwWindowsVersion: u32, @@ -288,6 +289,7 @@ pub struct DescriptorSetInformation { /// Table 4. Microsoft OS 2.0 platform capability descriptor header. #[allow(non_snake_case)] +#[allow(unused)] #[repr(C, packed(1))] pub struct PlatformDescriptor { bLength: u8, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 037fc5c6a..ce9040a70 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.79" +channel = "1.80" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From 4a8abe802806c5d193a43ec81450636a86a34f0a Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 25 Jul 2024 16:01:27 +0200 Subject: [PATCH 019/210] Relax lifetimes again --- embassy-stm32/src/opamp.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index f3f8368f8..36b9cb9cc 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -38,15 +38,15 @@ impl From for crate::pac::opamp::vals::Opahsm { /// OpAmp external outputs, wired to a GPIO pad. /// /// This struct can also be used as an ADC input. -pub struct OpAmpOutput<'a, 'd: 'a, T: Instance> { - _inner: &'a OpAmp<'d, T>, +pub struct OpAmpOutput<'d, T: Instance> { + _inner: &'d OpAmp<'d, T>, } /// OpAmp internal outputs, wired directly to ADC inputs. /// /// This struct can be used as an ADC input. -pub struct OpAmpInternalOutput<'a, 'd: 'a, T: Instance> { - _inner: &'a OpAmp<'d, T>, +pub struct OpAmpInternalOutput<'d, T: Instance> { + _inner: &'d OpAmp<'d, T>, } /// OpAmp driver. @@ -82,9 +82,9 @@ impl<'d, T: Instance> OpAmp<'d, T> { pub fn buffer_ext( &mut self, in_pin: impl Peripheral

+ crate::gpio::Pin>, - out_pin: impl Peripheral

+ crate::gpio::Pin> + 'd, + out_pin: impl Peripheral

+ crate::gpio::Pin>, gain: OpAmpGain, - ) -> OpAmpOutput<'_, 'd, T> { + ) -> OpAmpOutput<'_, T> { into_ref!(in_pin); into_ref!(out_pin); in_pin.set_as_analog(); @@ -120,8 +120,8 @@ impl<'d, T: Instance> OpAmp<'d, T> { #[cfg(opamp_g4)] pub fn buffer_dac( &mut self, - out_pin: impl Peripheral

+ crate::gpio::Pin> + 'd, - ) -> OpAmpOutput<'_, 'd, T> { + out_pin: impl Peripheral

+ crate::gpio::Pin>, + ) -> OpAmpOutput<'_, T> { into_ref!(out_pin); out_pin.set_as_analog(); @@ -150,7 +150,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { &mut self, pin: impl Peripheral

+ crate::gpio::Pin>, gain: OpAmpGain, - ) -> OpAmpInternalOutput<'_, 'd, T> { + ) -> OpAmpInternalOutput<'_, T> { into_ref!(pin); pin.set_as_analog(); @@ -176,7 +176,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { } } -impl<'a, 'd: 'a, T: Instance> Drop for OpAmpOutput<'a, 'd, T> { +impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { fn drop(&mut self) { T::regs().csr().modify(|w| { w.set_opampen(false); @@ -184,7 +184,7 @@ impl<'a, 'd: 'a, T: Instance> Drop for OpAmpOutput<'a, 'd, T> { } } -impl<'a, 'd: 'a, T: Instance> Drop for OpAmpInternalOutput<'a, 'd, T> { +impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { fn drop(&mut self) { T::regs().csr().modify(|w| { w.set_opampen(false); @@ -224,16 +224,16 @@ macro_rules! impl_opamp_external_output { ($inst:ident, $adc:ident, $ch:expr) => { foreach_adc!( ($adc, $common_inst:ident, $adc_clock:ident) => { - impl<'a, 'd: 'a> crate::adc::SealedAdcChannel - for OpAmpOutput<'a, 'd, crate::peripherals::$inst> + impl<'d> crate::adc::SealedAdcChannel + for OpAmpOutput<'d, crate::peripherals::$inst> { fn channel(&self) -> u8 { $ch } } - impl<'a, 'd: 'a> crate::adc::AdcChannel - for OpAmpOutput<'a, 'd, crate::peripherals::$inst> + impl<'d> crate::adc::AdcChannel + for OpAmpOutput<'d, crate::peripherals::$inst> { } }; @@ -270,16 +270,16 @@ macro_rules! impl_opamp_internal_output { ($inst:ident, $adc:ident, $ch:expr) => { foreach_adc!( ($adc, $common_inst:ident, $adc_clock:ident) => { - impl<'a, 'd: 'a> crate::adc::SealedAdcChannel - for OpAmpInternalOutput<'a, 'd, crate::peripherals::$inst> + impl<'d> crate::adc::SealedAdcChannel + for OpAmpInternalOutput<'d, crate::peripherals::$inst> { fn channel(&self) -> u8 { $ch } } - impl<'a, 'd: 'a> crate::adc::AdcChannel - for OpAmpInternalOutput<'a, 'd, crate::peripherals::$inst> + impl<'d> crate::adc::AdcChannel + for OpAmpInternalOutput<'d, crate::peripherals::$inst> { } }; From 3efbd60a9054631717bcdf9a195323d18bd0dc66 Mon Sep 17 00:00:00 2001 From: Vicente Date: Thu, 25 Jul 2024 19:24:37 +0200 Subject: [PATCH 020/210] Fixing missing re-export cyw::control::ScanOptions --- cyw43/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 19b0cb194..e36f7d83e 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -28,7 +28,7 @@ use ioctl::IoctlState; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; -pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, Scanner}; +pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, Scanner, ScanOptions}; pub use crate::runner::Runner; pub use crate::structs::BssInfo; From 6eb447eb587da42644926fb1aebca8a5d0aab57f Mon Sep 17 00:00:00 2001 From: Vicente Date: Thu, 25 Jul 2024 19:45:52 +0200 Subject: [PATCH 021/210] Adding pub struct docs cyw43::ScanOptions --- cyw43/src/control.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 8944865c1..d48cd6748 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -42,6 +42,7 @@ pub enum ScanType { Passive, } +/// Scan options. #[derive(Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ScanOptions { From da5ecd29f1a046526bbb56673a6e6c986dbd8c39 Mon Sep 17 00:00:00 2001 From: Vicente Date: Thu, 25 Jul 2024 19:55:54 +0200 Subject: [PATCH 022/210] Formmating --- cyw43/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index e36f7d83e..7c8f35da7 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -28,7 +28,7 @@ use ioctl::IoctlState; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; -pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, Scanner, ScanOptions}; +pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, ScanOptions, Scanner}; pub use crate::runner::Runner; pub use crate::structs::BssInfo; From 29d79d3af2bad9ef2e3010de0589b1606bbcfb8d Mon Sep 17 00:00:00 2001 From: Vicente Date: Thu, 25 Jul 2024 20:01:19 +0200 Subject: [PATCH 023/210] Added doc comment to a public enum variant --- cyw43/src/control.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index d48cd6748..f0f179e2e 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -46,6 +46,7 @@ pub enum ScanType { #[derive(Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ScanOptions { + /// SSID to scan for. pub ssid: Option>, /// If set to `None`, all APs will be returned. If set to `Some`, only APs /// with the specified BSSID will be returned. From 60aa9c15a8a246d1d099beec8a1e3cbf08f52a8f Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Fri, 26 Jul 2024 14:25:10 +0200 Subject: [PATCH 024/210] Implement low-power feature for stm32l4 MCUs --- embassy-stm32/src/low_power.rs | 6 +++--- embassy-stm32/src/rtc/low_power.rs | 4 ++-- embassy-stm32/src/rtc/v2.rs | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 604bdf416..f3e4c6994 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -109,10 +109,10 @@ pub enum StopMode { Stop2, } -#[cfg(stm32l5)] +#[cfg(any(stm32l4, stm32l5))] use stm32_metapac::pwr::vals::Lpms; -#[cfg(stm32l5)] +#[cfg(any(stm32l4, stm32l5))] impl Into for StopMode { fn into(self) -> Lpms { match self { @@ -181,7 +181,7 @@ impl Executor { #[allow(unused_variables)] fn configure_stop(&mut self, stop_mode: StopMode) { - #[cfg(stm32l5)] + #[cfg(any(stm32l4, stm32l5))] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); #[cfg(stm32h5)] crate::pac::PWR.pmcr().modify(|v| { diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index a4ff1acbc..6042389ac 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -65,7 +65,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -79,7 +79,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index cdc1cb299..5d9025bbe 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -131,10 +131,13 @@ impl SealedInstance for crate::peripherals::RTC { #[cfg(all(feature = "low-power", stm32f4))] const EXTI_WAKEUP_LINE: usize = 22; + #[cfg(all(feature = "low-power", stm32l4))] + const EXTI_WAKEUP_LINE: usize = 20; + #[cfg(all(feature = "low-power", stm32l0))] const EXTI_WAKEUP_LINE: usize = 20; - #[cfg(all(feature = "low-power", stm32f4))] + #[cfg(all(feature = "low-power", any(stm32f4, stm32l4)))] type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; #[cfg(all(feature = "low-power", stm32l0))] From b2d8d7f009877ad288a563643f3e983eaecafc58 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:48:42 +0200 Subject: [PATCH 025/210] add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 267 +++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 examples/rp/src/bin/orchestrate_tasks.rs diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs new file mode 100644 index 000000000..b9282e273 --- /dev/null +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -0,0 +1,267 @@ +//! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system. +//! +//! We demonstrate how to: +//! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. +//! - use a signal to terminate a task. +//! - use command channels to send commands to another task. +//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple channels. +//! +//! There are more patterns to orchestrate tasks, this is just one example. +//! +//! We will use these tasks to generate example "state information": +//! - a task that generates random numbers in intervals of 60s +//! - a task that generates random numbers in intervals of 30s +//! - a task that generates random numbers in intervals of 90s +//! - a task that notifies about being attached/disattached from usb power +//! - a task that measures vsys voltage in intervals of 30s + +#![no_std] +#![no_main] + +use assign_resources::assign_resources; +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; +use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; +use embassy_rp::bind_interrupts; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Pull}; +use embassy_rp::peripherals; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::{channel, signal}; +use embassy_time::{Duration, Timer}; +use rand::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +// This is just some preparation, see example `assign_resources.rs` for more information on this. We prep the rresources that we will be using in different tasks. +// **Note**: This will not work with a board that has a wifi chip, because the wifi chip uses pins 24 and 29 for its own purposes. A way around this in software +// is not trivial, at least if you intend to use wifi, too. Workaround is to wire from vsys and vbus pins to appropriate pins on the board through a voltage divider. Then use those pins. +// For this example it will not matter much, the concept of what we are showing remains valid. +assign_resources! { + vsys: Vsys { + adc: ADC, + pin_29: PIN_29, + }, + vbus: Vbus { + pin_24: PIN_24, + }, +} + +bind_interrupts!(struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; +}); + +/// This is the type of Events that we will send from the worker tasks to the orchestrating task. +enum Events { + UsbPowered(bool), + VsysVoltage(f32), + FirstRandomSeed(u32), + SecondRandomSeed(u32), + ThirdRandomSeed(u32), +} + +/// This is the type of Commands that we will send from the orchestrating task to the worker tasks. +/// Note that we are lazy here and only have one command, you might want to have more. +enum Commands { + /// This command will stop the appropriate worker task + Stop, +} + +/// This is the state of the system, we will use this to orchestrate the system. This is a simple example, in a real world application this would be more complex. +#[derive(Default, Debug, Clone, Format)] +struct State { + usb_powered: bool, + vsys_voltage: f32, + first_random_seed: u32, + second_random_seed: u32, + third_random_seed: u32, + times_we_got_first_random_seed: u8, + maximum_times_we_want_first_random_seed: u8, +} + +impl State { + fn new() -> Self { + Self { + usb_powered: false, + vsys_voltage: 0.0, + first_random_seed: 0, + second_random_seed: 0, + third_random_seed: 0, + times_we_got_first_random_seed: 0, + maximum_times_we_want_first_random_seed: 3, + } + } +} + +/// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events. +/// We use a channel with an arbitrary size of 10, the precise size of the queue depends on your use case. This depends on how many events we +/// expect to be generated in a given time frame and how fast the orchestrator can react to them. And then if we rather want the senders to wait for +/// new slots in the queue or if we want the orchestrator to have a backlog of events to process. In this case here we expect to always be enough slots +/// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting. +/// For the events we - in this case here - do not want to loose any events, so a channel is a good choice. See embassy_sync docs for other options. +static EVENT_CHANNEL: channel::Channel = channel::Channel::new(); + +/// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. +static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); + +// And now we can put all this into use + +/// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the +/// orchestrating here. This is to show that we do not need a main loop here, the system will run indefinitely as long as at least one task is running. +#[embassy_executor::main] +async fn main(spawner: Spawner) { + // initialize the peripherals + let p = embassy_rp::init(Default::default()); + // split the resources, for convenience - see above + let r = split_resources! {p}; + + // spawn the tasks + spawner.spawn(orchestrate(spawner)).unwrap(); + spawner.spawn(random_30s(spawner)).unwrap(); + spawner.spawn(random_60s(spawner)).unwrap(); + spawner.spawn(random_90s(spawner)).unwrap(); + spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); + spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); +} + +/// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. +#[embassy_executor::task] +async fn orchestrate(_spawner: Spawner) { + let mut state = State::new(); + + // we need to have a receiver for the events + let receiver = EVENT_CHANNEL.receiver(); + + loop { + // we await on the receiver, this will block until a new event is available + // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event + // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html + // The task random_30s does a select, if you want to have a look at that. + // Another reason to use select may also be that we want to have a timeout, so we can react to the absence of events within a time frame. + // We keep it simple here. + let event = receiver.receive().await; + + // react to the events + match event { + Events::UsbPowered(usb_powered) => { + // update the state and/or react to the event here + state.usb_powered = usb_powered; + info!("Usb powered: {}", usb_powered); + } + Events::VsysVoltage(voltage) => { + // update the state and/or react to the event here + state.vsys_voltage = voltage; + info!("Vsys voltage: {}", voltage); + } + Events::FirstRandomSeed(seed) => { + // update the state and/or react to the event here + state.first_random_seed = seed; + // here we change some meta state, we count how many times we got the first random seed + state.times_we_got_first_random_seed += 1; + info!( + "First random seed: {}, and that was iteration {} of receiving this.", + seed, &state.times_we_got_first_random_seed + ); + } + Events::SecondRandomSeed(seed) => { + // update the state and/or react to the event here + state.second_random_seed = seed; + info!("Second random seed: {}", seed); + } + Events::ThirdRandomSeed(seed) => { + // update the state and/or react to the event here + state.third_random_seed = seed; + info!("Third random seed: {}", seed); + } + } + // we now have an altered state + // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here + // for now we just keep it simple + info!("State: {:?}", &state); + + // here we react to the state, in this case here we want to stop the first random seed task after we got it a defined number of times + if state.times_we_got_first_random_seed == state.maximum_times_we_want_first_random_seed { + info!("Stopping the first random signal task"); + // we send a command to the task + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + } + } +} + +/// This task will generate random numbers in intervals of 30s +/// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. +#[embassy_executor::task] +async fn random_30s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + // we either await on the timer or the signal, whichever comes first. + let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await; + match futures { + Either::First(_) => { + // we received are operating on the timer + info!("30s are up, generating random number"); + let random_number = rng.next_u32(); + sender.send(Events::FirstRandomSeed(random_number)).await; + } + Either::Second(_) => { + // we received the signal to stop + info!("Received signal to stop, goodbye!"); + break; + } + } + } +} + +/// This task will generate random numbers in intervals of 60s +#[embassy_executor::task] +async fn random_60s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + Timer::after(Duration::from_secs(60)).await; + let random_number = rng.next_u32(); + sender.send(Events::SecondRandomSeed(random_number)).await; + } +} + +/// This task will generate random numbers in intervals of 90s +#[embassy_executor::task] +async fn random_90s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + Timer::after(Duration::from_secs(90)).await; + let random_number = rng.next_u32(); + sender.send(Events::ThirdRandomSeed(random_number)).await; + } +} + +/// This task will notify if we are connected to usb power +#[embassy_executor::task] +pub async fn usb_power(_spawner: Spawner, r: Vbus) { + let mut vbus_in = Input::new(r.pin_24, Pull::None); + let sender = EVENT_CHANNEL.sender(); + loop { + sender.send(Events::UsbPowered(vbus_in.is_high())).await; + vbus_in.wait_for_any_edge().await; + } +} + +/// This task will measure the vsys voltage in intervals of 30s +#[embassy_executor::task] +pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) { + let mut adc = Adc::new(r.adc, Irqs, Config::default()); + let vsys_in = r.pin_29; + let mut channel = Channel::new_pin(vsys_in, Pull::None); + let sender = EVENT_CHANNEL.sender(); + loop { + // read the adc value + let adc_value = adc.read(&mut channel).await.unwrap(); + // convert the adc value to voltage. + // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc + let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0; + sender.send(Events::VsysVoltage(voltage)).await; + Timer::after(Duration::from_secs(30)).await; + } +} From 97125e53cdf425a146c6552a25164cdfd6075fe7 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:54:02 +0200 Subject: [PATCH 026/210] add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index b9282e273..1ef6b5fb6 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -23,10 +23,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::select::{select, Either}; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; -use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; -use embassy_rp::peripherals; +use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::{channel, signal}; use embassy_time::{Duration, Timer}; From 5d46b694ca60ee69d83eb2bd53f592b2c5b03d28 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:57:46 +0200 Subject: [PATCH 027/210] add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 1ef6b5fb6..b3c37de4c 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -4,7 +4,7 @@ //! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. //! - use a signal to terminate a task. //! - use command channels to send commands to another task. -//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple channels. +//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures. //! //! There are more patterns to orchestrate tasks, this is just one example. //! From 8680c8689419ca47ed9d31e8bb7b6954a51cc534 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 27 Jul 2024 15:04:02 +0200 Subject: [PATCH 028/210] embassy-stm32: wait for BSY flag to clear before flashing While not waiting for the BSY flag to clear works on STM32F103C8T6, it does not on APM32F103C8T6. Only one half-word gets written while the other one gets lost. --- embassy-stm32/src/flash/f1f3.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs index e66842e31..ff7f810ea 100644 --- a/embassy-stm32/src/flash/f1f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs @@ -42,9 +42,11 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) // prevents parallelism errors fence(Ordering::SeqCst); + + wait_ready_blocking()?; } - wait_ready_blocking() + Ok(()) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { From e05e5d33f0ab832b2ea1c48674c99b41581118be Mon Sep 17 00:00:00 2001 From: rafael Date: Sun, 28 Jul 2024 00:19:54 +0200 Subject: [PATCH 029/210] review comments --- examples/rp/src/bin/orchestrate_tasks.rs | 66 +++++++++++++++++++++--- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index b3c37de4c..0e21d5833 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -14,6 +14,7 @@ //! - a task that generates random numbers in intervals of 90s //! - a task that notifies about being attached/disattached from usb power //! - a task that measures vsys voltage in intervals of 30s +//! - a task that consumes the state information and reacts to it #![no_std] #![no_main] @@ -57,6 +58,7 @@ enum Events { FirstRandomSeed(u32), SecondRandomSeed(u32), ThirdRandomSeed(u32), + ResetFirstRandomSeed, } /// This is the type of Commands that we will send from the orchestrating task to the worker tasks. @@ -103,6 +105,11 @@ static EVENT_CHANNEL: channel::Channel = ch /// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); +/// Channel for the state that we want the consumer task to react to. We use a channel here, because we want to have a queue of state changes, although +/// we want the queue to be of size 1, because we want to finish rwacting to the state change before the next one comes in. This is just a design choice +/// and depends on your use case. +static CONSUMER_CHANNEL: channel::Channel = channel::Channel::new(); + // And now we can put all this into use /// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the @@ -116,11 +123,11 @@ async fn main(spawner: Spawner) { // spawn the tasks spawner.spawn(orchestrate(spawner)).unwrap(); - spawner.spawn(random_30s(spawner)).unwrap(); spawner.spawn(random_60s(spawner)).unwrap(); spawner.spawn(random_90s(spawner)).unwrap(); spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); + spawner.spawn(consumer(spawner)).unwrap(); } /// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. @@ -131,6 +138,9 @@ async fn orchestrate(_spawner: Spawner) { // we need to have a receiver for the events let receiver = EVENT_CHANNEL.receiver(); + // and we need a sender for the consumer task + let state_sender = CONSUMER_CHANNEL.sender(); + loop { // we await on the receiver, this will block until a new event is available // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event @@ -172,23 +182,65 @@ async fn orchestrate(_spawner: Spawner) { state.third_random_seed = seed; info!("Third random seed: {}", seed); } + Events::ResetFirstRandomSeed => { + // update the state and/or react to the event here + state.times_we_got_first_random_seed = 0; + state.first_random_seed = 0; + info!("Resetting the first random seed counter"); + } } // we now have an altered state // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here // for now we just keep it simple - info!("State: {:?}", &state); - // here we react to the state, in this case here we want to stop the first random seed task after we got it a defined number of times - if state.times_we_got_first_random_seed == state.maximum_times_we_want_first_random_seed { - info!("Stopping the first random signal task"); - // we send a command to the task - STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + // we send the state to the consumer task + // since the channel has a size of 1, this will block until the consumer task has received the state, which is what we want here in this example + // **Note:** It is bad design to send too much data between tasks, with no clear definition of what "too much" is. In this example we send the + // whole state, in a real world application you might want to send only the data, that is relevant to the consumer task AND only when it has changed. + // We keep it simple here. + state_sender.send(state.clone()).await; + } +} + +/// This task will consume the state information and react to it. This is a simple example, in a real world application this would be more complex +/// and we could have multiple consumer tasks, each reacting to different parts of the state. +#[embassy_executor::task] +async fn consumer(spawner: Spawner) { + // we need to have a receiver for the state + let receiver = CONSUMER_CHANNEL.receiver(); + let sender = EVENT_CHANNEL.sender(); + loop { + // we await on the receiver, this will block until a new state is available + let state = receiver.receive().await; + // react to the state, in this case here we just log it + info!("The consumer has reveived this state: {:?}", &state); + + // here we react to the state, in this case here we want to start or stop the first random signal task depending on the state of the system + match state.times_we_got_first_random_seed { + max if max == state.maximum_times_we_want_first_random_seed => { + info!("Stopping the first random signal task"); + // we send a command to the task + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + // we notify the orchestrator that we have sent the command + sender.send(Events::ResetFirstRandomSeed).await; + } + 0 => { + // we start the task, which presents us with an interesting problem, because we may return here before the task has started + // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully + info!("Starting the first random signal task"); + match spawner.spawn(random_30s(spawner)) { + Ok(_) => info!("Successfully spawned random_30s task"), + Err(e) => info!("Failed to spawn random_30s task: {:?}", e), + } + } + _ => {} } } } /// This task will generate random numbers in intervals of 30s /// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. +/// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically. #[embassy_executor::task] async fn random_30s(_spawner: Spawner) { let mut rng = RoscRng; From 05e0f128462ebdacd3dffc27f74502913d782589 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 27 Jul 2024 11:49:02 +0200 Subject: [PATCH 030/210] embassy-sync: add LazyLock `LazyLock` is inspired by Rust 1.80.0's `std::sync::LazyLock` type. --- embassy-sync/CHANGELOG.md | 2 + embassy-sync/README.md | 1 + embassy-sync/src/lazy_lock.rs | 84 +++++++++++++++++++++++++++++++++++ embassy-sync/src/lib.rs | 1 + 4 files changed, 88 insertions(+) create mode 100644 embassy-sync/src/lazy_lock.rs diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index a283adc0c..8f2d26fe0 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Add LazyLock sync primitive. + ## 0.6.0 - 2024-05-29 - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `Channel`. diff --git a/embassy-sync/README.md b/embassy-sync/README.md index 2c1c0cf68..dec1fbc32 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -13,6 +13,7 @@ Synchronization primitives and data structures with async support: - [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`. - [`AtomicWaker`](waitqueue::AtomicWaker) - A variant of `WakerRegistration` accessible using a non-mut API. - [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s. +- [`LazyLock`](lazy_lock::LazyLock) - A value which is initialized on the first access ## Interoperability diff --git a/embassy-sync/src/lazy_lock.rs b/embassy-sync/src/lazy_lock.rs new file mode 100644 index 000000000..2b5742491 --- /dev/null +++ b/embassy-sync/src/lazy_lock.rs @@ -0,0 +1,84 @@ +//! Synchronization primitive for initializing a value once, allowing others to get a reference to the value. + +use core::cell::Cell; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicBool, Ordering}; + +/// The `LazyLock` is a synchronization primitive that allows for +/// initializing a value once, and allowing others to obtain a +/// reference to the value. This is useful for lazy initialization of +/// a static value. +/// +/// # Example +/// ``` +/// use futures_executor::block_on; +/// use embassy_sync::lazy_lock::LazyLock; +/// +/// // Define a static value that will be lazily initialized +/// // at runtime at the first access. +/// static VALUE: LazyLock = LazyLock::new(|| 20); +/// +/// let reference = VALUE.get(); +/// assert_eq!(reference, &20); +/// ``` +pub struct LazyLock T> { + init: AtomicBool, + init_fn: Cell>, + data: Cell>, +} + +unsafe impl Sync for LazyLock {} + +impl T> LazyLock { + /// Create a new uninitialized `StaticLock`. + pub const fn new(init_fn: F) -> Self { + Self { + init: AtomicBool::new(false), + init_fn: Cell::new(Some(init_fn)), + data: Cell::new(MaybeUninit::zeroed()), + } + } + + /// Get a reference to the underlying value, initializing it if it + /// has not been done already. + #[inline] + pub fn get(&self) -> &T { + self.ensure_init_fast(); + unsafe { (*self.data.as_ptr()).assume_init_ref() } + } + + /// Consume the `LazyLock`, returning the underlying value. The + /// initialization function will be called if it has not been + /// already. + #[inline] + pub fn into_inner(self) -> T { + self.ensure_init_fast(); + unsafe { self.data.into_inner().assume_init() } + } + + /// Initialize the `LazyLock` if it has not been initialized yet. + /// This function is a fast track to [`Self::ensure_init`] + /// which does not require a critical section in most cases when + /// the value has been initialized already. + /// When this function returns, `self.data` is guaranteed to be + /// initialized and visible on the current core. + #[inline] + fn ensure_init_fast(&self) { + if !self.init.load(Ordering::Acquire) { + self.ensure_init(); + } + } + + /// Initialize the `LazyLock` if it has not been initialized yet. + /// When this function returns, `self.data` is guaranteed to be + /// initialized and visible on the current core. + fn ensure_init(&self) { + critical_section::with(|_| { + if !self.init.load(Ordering::Acquire) { + let init_fn = self.init_fn.take().unwrap(); + self.data.set(MaybeUninit::new(init_fn())); + self.init.store(true, Ordering::Release); + } + }); + } +} diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index a5eee8d02..014bf1d06 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -12,6 +12,7 @@ mod ring_buffer; pub mod blocking_mutex; pub mod channel; +pub mod lazy_lock; pub mod mutex; pub mod once_lock; pub mod pipe; From c5d077a2c62edb4d704fc64dc6eeea5a3ed0dcb0 Mon Sep 17 00:00:00 2001 From: Gasper Stukelj Date: Sun, 28 Jul 2024 21:50:52 +0200 Subject: [PATCH 031/210] embassy-net: dns: bound the dns_servers slice `smoltcp::socket::dns::Socket::update_servers()` will panic if a slice exceeding a fixed length is passed to it. This is can be especially inconvenient when using DHCP config. Avoid panicking by using at most `DNS_MAX_SERVER_COUNT` DNS servers from the config. --- embassy-net/src/lib.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 12f5f30b4..524799a1b 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -34,6 +34,8 @@ use embassy_sync::waitqueue::WakerRegistration; use embassy_time::{Instant, Timer}; #[allow(unused_imports)] use heapless::Vec; +#[cfg(feature = "dns")] +pub use smoltcp::config::DNS_MAX_SERVER_COUNT; #[cfg(feature = "igmp")] pub use smoltcp::iface::MulticastError; #[allow(unused_imports)] @@ -823,9 +825,17 @@ impl Inner { // Apply DNS servers #[cfg(feature = "dns")] - s.sockets - .get_mut::(self.dns_socket) - .update_servers(&dns_servers[..]); + if !dns_servers.is_empty() { + let count = if dns_servers.len() > DNS_MAX_SERVER_COUNT { + warn!("Number of DNS servers exceeds DNS_MAX_SERVER_COUNT, truncating list."); + DNS_MAX_SERVER_COUNT + } else { + dns_servers.len() + }; + s.sockets + .get_mut::(self.dns_socket) + .update_servers(&dns_servers[..count]); + } self.config_waker.wake(); } From 93696c912e7264e101308a3f205272dcdd44e6b2 Mon Sep 17 00:00:00 2001 From: wanglei Date: Wed, 31 Jul 2024 00:24:39 +0800 Subject: [PATCH 032/210] embassy-sync: fix the data of LazyLock never drop Using `union` can save more space. And the `MaybeUninit` will never drop the T, when dropping the `MaybeUninit`. Fixed it. Signed-off-by: wanglei --- embassy-sync/src/lazy_lock.rs | 41 ++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/embassy-sync/src/lazy_lock.rs b/embassy-sync/src/lazy_lock.rs index 2b5742491..cf88bfdf8 100644 --- a/embassy-sync/src/lazy_lock.rs +++ b/embassy-sync/src/lazy_lock.rs @@ -1,7 +1,7 @@ //! Synchronization primitive for initializing a value once, allowing others to get a reference to the value. -use core::cell::Cell; -use core::mem::MaybeUninit; +use core::cell::UnsafeCell; +use core::mem::ManuallyDrop; use core::sync::atomic::{AtomicBool, Ordering}; /// The `LazyLock` is a synchronization primitive that allows for @@ -23,8 +23,12 @@ use core::sync::atomic::{AtomicBool, Ordering}; /// ``` pub struct LazyLock T> { init: AtomicBool, - init_fn: Cell>, - data: Cell>, + data: UnsafeCell>, +} + +union Data { + value: ManuallyDrop, + f: ManuallyDrop, } unsafe impl Sync for LazyLock {} @@ -34,8 +38,9 @@ impl T> LazyLock { pub const fn new(init_fn: F) -> Self { Self { init: AtomicBool::new(false), - init_fn: Cell::new(Some(init_fn)), - data: Cell::new(MaybeUninit::zeroed()), + data: UnsafeCell::new(Data { + f: ManuallyDrop::new(init_fn), + }), } } @@ -44,7 +49,7 @@ impl T> LazyLock { #[inline] pub fn get(&self) -> &T { self.ensure_init_fast(); - unsafe { (*self.data.as_ptr()).assume_init_ref() } + unsafe { &(*self.data.get()).value } } /// Consume the `LazyLock`, returning the underlying value. The @@ -53,7 +58,10 @@ impl T> LazyLock { #[inline] pub fn into_inner(self) -> T { self.ensure_init_fast(); - unsafe { self.data.into_inner().assume_init() } + let this = ManuallyDrop::new(self); + let data = unsafe { core::ptr::read(&this.data) }.into_inner(); + + ManuallyDrop::into_inner(unsafe { data.value }) } /// Initialize the `LazyLock` if it has not been initialized yet. @@ -75,10 +83,23 @@ impl T> LazyLock { fn ensure_init(&self) { critical_section::with(|_| { if !self.init.load(Ordering::Acquire) { - let init_fn = self.init_fn.take().unwrap(); - self.data.set(MaybeUninit::new(init_fn())); + let data = unsafe { &mut *self.data.get() }; + let f = unsafe { ManuallyDrop::take(&mut data.f) }; + let value = f(); + data.value = ManuallyDrop::new(value); + self.init.store(true, Ordering::Release); } }); } } + +impl Drop for LazyLock { + fn drop(&mut self) { + if self.init.load(Ordering::Acquire) { + unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) }; + } else { + unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) }; + } + } +} From 05562b92af53c742c6531ec616afd518112687b8 Mon Sep 17 00:00:00 2001 From: wanglei Date: Wed, 31 Jul 2024 00:25:28 +0800 Subject: [PATCH 033/210] embassy-sync: more unit-test for LazyLock Signed-off-by: wanglei --- embassy-sync/src/lazy_lock.rs | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/embassy-sync/src/lazy_lock.rs b/embassy-sync/src/lazy_lock.rs index cf88bfdf8..18e3c2019 100644 --- a/embassy-sync/src/lazy_lock.rs +++ b/embassy-sync/src/lazy_lock.rs @@ -103,3 +103,50 @@ impl Drop for LazyLock { } } } + +#[cfg(test)] +mod tests { + use core::sync::atomic::{AtomicU32, Ordering}; + + use super::*; + + #[test] + fn test_lazy_lock() { + static VALUE: LazyLock = LazyLock::new(|| 20); + let reference = VALUE.get(); + assert_eq!(reference, &20); + } + #[test] + fn test_lazy_lock_into_inner() { + let lazy: LazyLock = LazyLock::new(|| 20); + let value = lazy.into_inner(); + assert_eq!(value, 20); + } + + static DROP_CHECKER: AtomicU32 = AtomicU32::new(0); + struct DropCheck; + + impl Drop for DropCheck { + fn drop(&mut self) { + DROP_CHECKER.fetch_add(1, Ordering::Acquire); + } + } + + #[test] + fn test_lazy_drop() { + let lazy: LazyLock = LazyLock::new(|| DropCheck); + assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 0); + lazy.get(); + drop(lazy); + assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 1); + + let dropper = DropCheck; + let lazy_fn: LazyLock = LazyLock::new(move || { + let _a = dropper; + 20 + }); + assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 1); + drop(lazy_fn); + assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 2); + } +} From ec53b9187da70213f184e9ac2206cdf4b2316a89 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 31 Jul 2024 18:16:04 +0100 Subject: [PATCH 034/210] Fix bootloader-rp's bootloader memory region overflow The bootloader region (`FLASH`) mentioned below overflows into the `BOOTLOADER_STATE` region by `0x100` bytes ``` 0x10000100 + 24K = 0x10006100 ``` https://github.com/embassy-rs/embassy/blob/32adddff9c7fc223853ada7e9ab5b7e06014a47c/examples/boot/bootloader/rp/memory.x#L3-L8 --- examples/boot/bootloader/rp/memory.x | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/boot/bootloader/rp/memory.x b/examples/boot/bootloader/rp/memory.x index c3b54976e..88b5bbb15 100644 --- a/examples/boot/bootloader/rp/memory.x +++ b/examples/boot/bootloader/rp/memory.x @@ -2,7 +2,7 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH : ORIGIN = 0x10000100, LENGTH = 24K + FLASH : ORIGIN = 0x10000100, LENGTH = 24K - 0x100 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K DFU : ORIGIN = 0x10087000, LENGTH = 516K From 4e905bfcba4f6e68ea136b23d81c5049a0b025a6 Mon Sep 17 00:00:00 2001 From: Zachary Crockett Date: Fri, 2 Aug 2024 08:39:37 -0700 Subject: [PATCH 035/210] Fix broken link to OPEN Alliance spec for ADIN1110 --- embassy-net-adin1110/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md index 39a38960d..0514274b4 100644 --- a/embassy-net-adin1110/README.md +++ b/embassy-net-adin1110/README.md @@ -21,7 +21,7 @@ APL can be used in [`intrinsic safety applications/explosion hazardous areas`](h ## Supported SPI modes -`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf) +`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/wp-content/uploads/2023/12/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf) Both modes support with and without additional CRC. Currently only `Generic` SPI with or without CRC is supported. From 7d65c5c4fa9f4a931019625168d7eacf0ec2fa40 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 3 Aug 2024 00:14:11 +0200 Subject: [PATCH 036/210] usb-synopsys-otg: ensure ep alloc fails when endpoint_count < MAX_EP_COUNT. Before, it would alloc the endpoint fine and then panic later due to out of range. This ensures it falis at ep alloc time, and with a panic message that says what's the actual problem: "no free endpoints available". --- embassy-usb-synopsys-otg/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index b90e059f6..f155f1522 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -382,8 +382,8 @@ impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> { } let eps = match D::dir() { - Direction::Out => &mut self.ep_out, - Direction::In => &mut self.ep_in, + Direction::Out => &mut self.ep_out[..self.instance.endpoint_count], + Direction::In => &mut self.ep_in[..self.instance.endpoint_count], }; // Find free endpoint slot From 2a1ace29a39f76d32ae07adff9f8b1d1e8cf5046 Mon Sep 17 00:00:00 2001 From: Rafael Bachmann Date: Sat, 3 Aug 2024 15:32:39 +0200 Subject: [PATCH 037/210] Fix possible typo in embassy-rp README.md There is no feature `time` in embassy-rp. Is it `time-driver`? Is it something else? --- embassy-rp/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/README.md b/embassy-rp/README.md index 8cf7da994..16b189344 100644 --- a/embassy-rp/README.md +++ b/embassy-rp/README.md @@ -23,5 +23,5 @@ The `embassy-rp` HAL implements the traits from [embedded-hal](https://crates.io This crate can run on any executor. -Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time` feature. If you enable it, +Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time-driver` feature. If you enable it, you must link an `embassy-time` driver in your project. From 5767c003ccccfa489648df1e902da5dd3b37e708 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 19:14:43 +0200 Subject: [PATCH 038/210] Prepare release of embassy-embedded-hal 0.2.0 --- embassy-boot/Cargo.toml | 2 +- embassy-embedded-hal/CHANGELOG.md | 21 +++++++++++++++++++ embassy-embedded-hal/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- .../boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- 23 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 embassy-embedded-hal/CHANGELOG.md diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 16dc52bcc..b7c5b6c62 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -28,7 +28,7 @@ defmt = { version = "0.3", optional = true } digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true } -embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } diff --git a/embassy-embedded-hal/CHANGELOG.md b/embassy-embedded-hal/CHANGELOG.md new file mode 100644 index 000000000..f61fe1e24 --- /dev/null +++ b/embassy-embedded-hal/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog for embassy-embedded-hal + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## 0.2.0 + +- Add Clone derive to flash Partition in embassy-embedded-hal +- Add support for all word sizes to async shared spi +- Add Copy and 'static constraint to Word type in SPI structs +- Improve flexibility by introducing SPI word size as a generic parameter +- Allow changing Spi/I2cDeviceWithConfig's config at runtime +- Impl `MultiwriteNorFlash` for `BlockingAsync` + +## 0.1.0 - 2024-01-10 + +- First release diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 905439fe7..04381e109 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-embedded-hal" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy." diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index f47b724ce..cbfb91f8d 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -140,7 +140,7 @@ embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", option embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } -embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 447c96b4d..5e9f5857b 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -94,7 +94,7 @@ embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", option embassy-time = { version = "0.3.1", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } -embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } atomic-polyfill = "1.0.1" defmt = { version = "0.3", optional = true } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 307b948c1..dcaaee8b1 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -24,7 +24,7 @@ embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } -embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } defmt = { version = "0.3", optional = true } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 523bacb11..4116499c1 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -47,7 +47,7 @@ embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } -embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index dbbe0fddc..bc9968ffc 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -11,7 +11,7 @@ embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index d4341e8f6..de96b73a5 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index c203ffc9f..1916ceb8d 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index ed13eab65..de37a6250 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f25e9815d..95edd50ce 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index c1a47dfe4..03dab6358 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 1e83d3113..b7196b173 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index bca292681..447d1695d 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 0484e6ceb..824262b69 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index b785a1968..a894ca42b 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 604112546..09fc3bc12 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 78343b74f..d1a974029 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index fc21cc894..c5ef0354f 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index de2b2bd4d..949cb588a 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 3ea7d0cbe..c5eee8668 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 45050ee0e..b6466714d 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -14,7 +14,7 @@ embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal/"} +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } perf-client = { path = "../perf-client" } From fb0ab1e42af8dd28d8f305c0db922756498ea6ca Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 19:17:23 +0200 Subject: [PATCH 039/210] Prepare release of embassy-hal-internal --- embassy-hal-internal/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml index c5013f365..d5ca95ac2 100644 --- a/embassy-hal-internal/Cargo.toml +++ b/embassy-hal-internal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-hal-internal" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY." diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index cbfb91f8d..10314cf75 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -139,7 +139,7 @@ _nrf52832_anomaly_109 = [] embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } +embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 5e9f5857b..e6c3cb8e1 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -93,7 +93,7 @@ embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-time = { version = "0.3.1", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } +embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } atomic-polyfill = "1.0.1" diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index dcaaee8b1..dedf25f6d 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -23,7 +23,7 @@ embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4116499c1..1a3aff399 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -46,7 +46,7 @@ embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } +embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } From 44282b18faf77b7ff2fa521eb7995fa46ca16e01 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 19:20:26 +0200 Subject: [PATCH 040/210] Prepare embassy-time release --- cyw43/Cargo.toml | 2 +- docs/examples/basic/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-time/CHANGELOG.md | 7 ++++++- embassy-time/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 67 files changed, 72 insertions(+), 67 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index c613698c1..9f9961aea 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -17,7 +17,7 @@ log = ["dep:log"] firmware-logs = [] [dependencies] -embassy-time = { version = "0.3.1", path = "../embassy-time"} +embassy-time = { version = "0.3.2", path = "../embassy-time"} embassy-sync = { version = "0.6.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index e82165032..40d23ffa1 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.1", path = "../../../embassy-time", features = ["defmt"] } +embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "0.3" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 23a8bb549..467ed416b 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.2.0", path = "../embassy-boot" } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 04381e109..345dc3420 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -29,7 +29,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index e75f76b16..1d99e5930 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -17,7 +17,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index dd7aa031d..cafced4b2 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/embassy-net-enc28j60" embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 24b7d0806..25121c7a9 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -17,7 +17,7 @@ log = [ "dep:log" ] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-sync = { version = "0.6.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index b6ce20325..2b6932d10 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/embassy-net-wiznet" embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 15b97af47..d86a30755 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -72,7 +72,7 @@ smoltcp = { version = "0.11.0", default-features = false, features = [ ] } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embedded-io-async = { version = "0.6.1" } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 10314cf75..53f505942 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -137,7 +137,7 @@ _nrf52832_anomaly_109 = [] [dependencies] embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } -embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index e6c3cb8e1..0d7ea1359 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -91,7 +91,7 @@ boot2-none = [] [dependencies] embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index dedf25f6d..54dfd39a6 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -21,7 +21,7 @@ features = ["stm32wb55rg"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 1a3aff399..601262315 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -43,7 +43,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } +embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 75e17fd63..1ad715242 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -7,7 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.4.0 - 2024-01-11 +## 0.3.2 - 2024-08-02 + +- Implement with_timeout()/with_deadline() method style call on Future +- Add collapse_debuginfo to fmt.rs macros. + +## 0.3.1 - 2024-01-11 - Add with\_deadline convenience function and example - Implement Clone for Delay diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 5d5bd8b23..6078c422b 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-time" -version = "0.3.1" +version = "0.3.2" edition = "2021" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 968fbec74..dec85ab41 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -34,7 +34,7 @@ cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } embassy-boot = { version = "0.2.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-usb = { version = "0.2.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index bc9968ffc..814714fcf 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index de96b73a5..071483cfc 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 1916ceb8d..7c67f4280 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index de37a6250..6b0f3fcbe 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 95edd50ce..f011707e6 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 03dab6358..2961db04a 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index b7196b173..b0b759c4d 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 447d1695d..ef05d2856 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 824262b69..82653102c 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index a894ca42b..b49af4501 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 70a89bb30..d87f089f3 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -17,7 +17,7 @@ log = [ [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time" } +embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index c52256d8e..b77308fbc 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } defmt = "0.3" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 2031b253f..84532f282 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 731cee843..f6e314d0d 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -9,7 +9,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index ff90d13af..b300a2f41 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index aeed39b3d..2760b5f70 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index d73f17e87..e6184f155 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 164f9c94e..37133f1ca 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 2ff692b24..d8a80af79 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 09fc3bc12..6563e947b 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 58ea894f3..07b1ad6b0 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["log", "std", ] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 331046a80..534b2d496 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 15fb55ca7..e91f5e202 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -14,7 +14,7 @@ defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 38b615795..904bb5134 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index ec9b54920..3892761cb 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 62c0fed16..2bfe61a6b 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 84c44a7b7..65b43a697 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index dbfaecb5e..75971a1f2 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 634f13f4e..fa60ef76c 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Specific examples only for stm32f469 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 7fc7d6f42..cd08f484e 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index b9d710ca7..f1d6ed511 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 8837ca52e..8b29133fb 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 59d3a9759..99db06c8d 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index d1a974029..7ecbb4768 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index c5ef0354f..c273f87a1 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -9,7 +9,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 13d33320f..efd1c53cb 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 5b0519ac4..e07245478 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 9e4ceac6a..48cbc3648 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 949cb588a..ef140b7ca 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index e32714cc6..06435342f 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index afeb4dc34..a06ac4cc9 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index d0134b972..c4d87af4c 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index c3a11b14b..72fe6810d 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index dc788e15b..443aa7225 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index c5eee8668..e96b8af5e 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } defmt = "0.3" diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 9d7acc175..ced1cc79b 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["log", "wasm", ] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" wasm-bindgen = "0.2" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index c714e8f7e..e082d2edd 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -10,7 +10,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 6ecc2d5e1..eb2a33a30 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", ] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 4f1d3e5c6..37dffe328 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time" } +embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } riscv-rt = "0.12.2" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index b6466714d..30b7b090c 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1.1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", ] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index f94814e70..ab0f57155 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -61,7 +61,7 @@ teleprobe-meta = "1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } From 2f3b3335e12f4c3aa988078d46cb6a3597277bd7 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 19:25:35 +0200 Subject: [PATCH 041/210] Prepare for embassy-nrf release --- docs/examples/basic/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-nrf/CHANGELOG.md | 5 +++++ embassy-nrf/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- 15 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index 40d23ffa1..6d5689d07 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } -embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } +embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 86bfc21f4..8a3c82d2e 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.17", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false } +embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false } embassy-boot = { version = "0.2.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 6f07a8c6d..213798ba9 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.2.0 - 2024-08-02 + +- Add collapse_debuginfo to fmt.rs macros. +- support EGU peripheral +- support nrf9151 - Drop `sealed` mod - nrf52840: Add dcdc voltage parameter to configure REG0 regulator - radio: Add support for IEEE 802.15.4 and BLE via radio peripheral diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 53f505942..bc0a9d199 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-nrf" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 814714fcf..d4d2bddec 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } -embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } +embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index d87f089f3..2a38d0466 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -18,7 +18,7 @@ log = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index b77308fbc..5fdd217d8 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 84532f282..12d14bb1b 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index f6e314d0d..7fae7aefc 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -10,7 +10,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index b300a2f41..6c4488370 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 2760b5f70..91509671f 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index e6184f155..2f08601a5 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 37133f1ca..60406fb2a 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index d8a80af79..2878d9c02 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index e082d2edd..4ff574f23 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -11,7 +11,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } From ffb55754c8c63b1840bc085b7c3d9d1ee02a1845 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 21:45:10 +0200 Subject: [PATCH 042/210] Prepare release embassy-net-driver-channel --- cyw43/Cargo.toml | 2 +- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-driver-channel/CHANGELOG.md | 5 +++++ embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-ppp/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-usb/Cargo.toml | 2 +- 8 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 9f9961aea..3c90873de 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -20,7 +20,7 @@ firmware-logs = [] embassy-time = { version = "0.3.2", path = "../embassy-time"} embassy-sync = { version = "0.6.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} defmt = { version = "0.3", optional = true } log = { version = "0.4.17", optional = true } diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 1d99e5930..0b2a6744d 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -16,7 +16,7 @@ log = { version = "0.4", default-features = false, optional = true } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" diff --git a/embassy-net-driver-channel/CHANGELOG.md b/embassy-net-driver-channel/CHANGELOG.md index b04d0a86b..a9aff4f2c 100644 --- a/embassy-net-driver-channel/CHANGELOG.md +++ b/embassy-net-driver-channel/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.3.0 - 2024-08-02 + +- Add collapse_debuginfo to fmt.rs macros. +- Update embassy-sync version + ## 0.2.0 - 2023-10-18 - Update `embassy-net-driver` to v0.2 diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index 3bd7d288a..abce9315b 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net-driver-channel" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "MIT OR Apache-2.0" description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack." diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 25121c7a9..915eba7a0 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -20,7 +20,7 @@ log = { version = "0.4.14", optional = true } embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-sync = { version = "0.6.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index cdfafaae1..f6371f955 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -18,7 +18,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embedded-io-async = { version = "0.6.1" } -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } ppproto = { version = "0.1.2"} embassy-sync = { version = "0.6.0", path = "../embassy-sync" } diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 2b6932d10..e7fb3f455 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -12,7 +12,7 @@ documentation = "https://docs.embassy.dev/embassy-net-wiznet" [dependencies] embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 1cc9cf64e..a00e598f8 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -49,7 +49,7 @@ max-handler-count-8 = [] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } From 61bda59d83b02b64a8a61807c949bec9990135c2 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 21:47:05 +0200 Subject: [PATCH 043/210] Prepare to release embassy-usb --- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-logger/Cargo.toml | 2 +- embassy-usb/CHANGELOG.md | 6 ++++++ embassy-usb/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- 24 files changed, 29 insertions(+), 23 deletions(-) diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index dec85ab41..0807fd200 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -35,7 +35,7 @@ embassy-boot = { version = "0.2.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time = { version = "0.3.2", path = "../embassy-time" } -embassy-usb = { version = "0.2.0", path = "../embassy-usb", default-features = false } +embassy-usb = { version = "0.3.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index 62b4ee723..d796e5d8e 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -15,7 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-l target = "thumbv7em-none-eabi" [dependencies] -embassy-usb = { version = "0.2.0", path = "../embassy-usb" } +embassy-usb = { version = "0.3.0", path = "../embassy-usb" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } log = "0.4" diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index 5f665ed25..16a18e042 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.0 - 2024-08-02 + +- bump usbd-hid from 0.7.0 to 0.8.1 +- Add collapse_debuginfo to fmt.rs macros. +- update embassy-sync dependency + ## 0.2.0 - 2024-05-20 - [#2862](https://github.com/embassy-rs/embassy/pull/2862) WebUSB implementation by @chmanie diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index a00e598f8..e310d8bae 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-usb" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 82653102c..6be678302 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -11,7 +11,7 @@ embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } -embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb" } +embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 9950ed7b6..050b672ce 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -18,7 +18,7 @@ embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" cfg-if = "1.0.0" embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } -embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb", default-features = false } +embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb", default-features = false } embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } [features] diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 6c4488370..857365d8d 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -11,7 +11,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 91509671f..e7e67428c 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -11,7 +11,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } defmt = "0.3" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 6563e947b..2ce05b703 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 904bb5134..bd4df1c5c 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 2bfe61a6b..fd6243591 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 65b43a697..cb0527bb2 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 75971a1f2..89fe6263e 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt" ] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index cd08f484e..ffd0773a3 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index f1d6ed511..3615ebfe6 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 8b29133fb..b9be103e5 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 99db06c8d..c38085f41 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 7ecbb4768..9a5a1bc0e 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -12,7 +12,7 @@ embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index efd1c53cb..dedf325c9 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 48cbc3648..b62a8aa7c 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index ef140b7ca..5db9aed0a 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 06435342f..c530a1215 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index a06ac4cc9..4644a8727 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index c4d87af4c..2be6862d9 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" From 37d7b0cd06b7a5d952d2e7de173b10ab32d96c5a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 21:50:18 +0200 Subject: [PATCH 044/210] prepare release embassy-executor --- docs/examples/basic/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-async/Cargo.toml | 2 +- embassy-executor-macros/Cargo.toml | 2 +- embassy-executor/CHANGELOG.md | 6 ++++++ embassy-executor/Cargo.toml | 4 ++-- embassy-rp/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-time/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 57 files changed, 63 insertions(+), 57 deletions(-) diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index 6d5689d07..5d391adf3 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index 64f7e8403..7f8d8af3e 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" cortex-m = "0.7" cortex-m-rt = "0.7" embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } -embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread"] } defmt = "0.3.0" defmt-rtt = "0.3.0" diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index 2953e7ccc..218e820ce 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor-macros" -version = "0.4.1" +version = "0.5.0" edition = "2021" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 77c64fd8e..a699dc238 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.6.0 - 2024-08-01 + +- Add collapse_debuginfo to fmt.rs macros. +- initial support for avr +- use nightly waker_getters APIs + ## 0.5.0 - 2024-01-11 - Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher. diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 431165cee..5984cc49c 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor" -version = "0.5.0" +version = "0.6.0" edition = "2021" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" @@ -33,7 +33,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } -embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } +embassy-executor-macros = { version = "0.5.0", path = "../embassy-executor-macros" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 0d7ea1359..024bd0668 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -125,5 +125,5 @@ rp2040-boot2 = "0.3" document-features = "0.2.7" [dev-dependencies] -embassy-executor = { version = "0.5.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } +embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 601262315..cd120c78d 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -51,7 +51,7 @@ embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } -embassy-executor = { version = "0.5.0", path = "../embassy-executor", optional = true } +embassy-executor = { version = "0.6.0", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 6078c422b..c3b4e4e3a 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -431,4 +431,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.5.0", path = "../embassy-executor" } +embassy-executor = { version = "0.6.0", path = "../embassy-executor" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index d4d2bddec..8dee81cf9 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 071483cfc..01d6436eb 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 7c67f4280..1c2934298 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 6b0f3fcbe..09e34c7df 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f011707e6..5e7f4d5e7 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 2961db04a..60fdcfafb 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index b0b759c4d..fe3ab2c04 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index ef05d2856..169856358 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 6be678302..7cef8fe0d 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index b49af4501..860a835a9 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 2a38d0466..98a678815 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,7 +16,7 @@ log = [ [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 5fdd217d8..93a19bea7 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 12d14bb1b..0e3e81c3f 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 857365d8d..17fa6234d 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index e7e67428c..0da85be07 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 2f08601a5..17fe27b67 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 60406fb2a..7253fc4be 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 2878d9c02..c30b54ebd 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 2ce05b703..0e8fe9308 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 07b1ad6b0..87491b1d2 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 534b2d496..9102467eb 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index e91f5e202..724efdaff 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -13,7 +13,7 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index bd4df1c5c..0084651a3 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 3892761cb..60eb0eb93 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index fd6243591..7fda410d9 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index cb0527bb2..1cc0a97da 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 89fe6263e..b85361596 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index fa60ef76c..6a5bd0b29 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index ffd0773a3..8c591ebd2 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 3615ebfe6..a50074ce0 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index b9be103e5..2768147a1 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index c38085f41..30b1d2be9 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 9a5a1bc0e..13fce7dc7 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index c273f87a1..93e9575b6 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index dedf325c9..f97dfd722 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index e07245478..2577f19e0 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index b62a8aa7c..062044f32 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 5db9aed0a..c5478b17b 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index c530a1215..16c184de2 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 4644a8727..2e890cdb5 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 2be6862d9..20d64c6f7 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u585ai to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 72fe6810d..1e1a0efe2 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 443aa7225..401281c0b 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index e96b8af5e..46af5218c 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index ced1cc79b..9bd37550c 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 4ff574f23..f666634d5 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 37dffe328..ae2b0e180 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 30b7b090c..28ef6ac07 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1.1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index ab0f57155..2eac636e5 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -60,7 +60,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] teleprobe-meta = "1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } From 1588fbc256fcd6444609dbd8049e810410974cb0 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 21:54:46 +0200 Subject: [PATCH 045/210] Prepare to release embassy-boot --- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 8a3c82d2e..745287710 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4.17", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false } -embassy-boot = { version = "0.2.0", path = "../embassy-boot" } +embassy-boot = { version = "0.3.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 467ed416b..1c3405b00 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -25,7 +25,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false } -embassy-boot = { version = "0.2.0", path = "../embassy-boot" } +embassy-boot = { version = "0.3.0", path = "../embassy-boot" } embassy-time = { version = "0.3.2", path = "../embassy-time" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 52ad1b463..e4ef9a612 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false } -embassy-boot = { version = "0.2.0", path = "../embassy-boot" } +embassy-boot = { version = "0.3.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index b7c5b6c62..85b3695a1 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot" -version = "0.2.0" +version = "0.3.0" description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 0807fd200..481b2699a 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -31,7 +31,7 @@ log = { version = "0.4.17", optional = true } bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } -embassy-boot = { version = "0.2.0", path = "../embassy-boot" } +embassy-boot = { version = "0.3.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time = { version = "0.3.2", path = "../embassy-time" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 8dee81cf9..c106b2956 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } -embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } +embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } From ec9a07d14362370c733843bb00a2980d73fb1737 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 21:55:40 +0200 Subject: [PATCH 046/210] Prepare to release embassy-boot-nrf --- embassy-boot-nrf/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 745287710..27407ae92 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-nrf" -version = "0.2.0" +version = "0.3.0" description = "Bootloader lib for nRF chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index c106b2956..93e49faef 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } -embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } +embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } From f60530279145d10974383cd6aacc49b8146061f6 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 22:06:39 +0200 Subject: [PATCH 047/210] Prepare to release embassy-rp --- cyw43-pio/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-rp/CHANGELOG.md | 32 +++++++++++++++++++++++++ embassy-rp/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- 7 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 embassy-rp/CHANGELOG.md diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 157046b18..9c7acd779 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -16,7 +16,7 @@ overclock = [] [dependencies] cyw43 = { version = "0.1.0", path = "../cyw43" } -embassy-rp = { version = "0.1.0", path = "../embassy-rp" } +embassy-rp = { version = "0.2.0", path = "../embassy-rp" } pio-proc = "0.2" pio = "0.2.1" fixed = "1.23.1" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 1c3405b00..af4a65db7 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -24,7 +24,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } -embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false } +embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.3.0", path = "../embassy-boot" } embassy-time = { version = "0.3.2", path = "../embassy-time" } diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md new file mode 100644 index 000000000..4d2af23fc --- /dev/null +++ b/embassy-rp/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog for embassy-rp + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## 0.2.0 - 2024-08-02 + +- Add read_to_break_with_count +- add option to provide your own boot2 +- Add multichannel ADC +- Add collapse_debuginfo to fmt.rs macros. +- Use raw slices .len() method instead of unsafe hacks. +- Add missing word "pin" in rp pwm documentation +- Add Clone and Copy to Error types +- fix spinlocks staying locked after reset. +- wait until read matches for PSM accesses. +- Remove generics +- fix drop implementation of BufferedUartRx and BufferedUartTx +- implement `embedded_storage_async::nor_flash::MultiwriteNorFlash` +- rp usb: wake ep-wakers after stalling +- rp usb: add stall implementation +- Add parameter for enabling pull-up and pull-down in RP PWM input mode +- rp: remove mod sealed. +- rename pins data type and the macro +- rename pwm channels to pwm slices, including in documentation +- rename the Channel trait to Slice and the PwmPin to PwmChannel +- i2c: Fix race condition that appears on fast repeated transfers. +- Add a basic "read to break" function diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 024bd0668..f6c0fba2d 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-rp" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller" diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 01d6436eb..8b4cafd4e 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } -embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } +embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 0e8fe9308..5ed51a5c0 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -10,7 +10,7 @@ embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } +embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 28ef6ac07..def270558 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -10,7 +10,7 @@ teleprobe-meta = "1.1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } -embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } +embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } From 187093e1475165a11f7fd8fc98494d33d339aa5c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 2 Aug 2024 22:07:54 +0200 Subject: [PATCH 048/210] Prepare to release embassy-boot-rp --- embassy-boot-rp/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index af4a65db7..5b173638e 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-rp" -version = "0.2.0" +version = "0.3.0" description = "Bootloader lib for RP2040 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 8b4cafd4e..c109c0732 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", ] } -embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } +embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } defmt = "0.3" From 886580179ff250e15b0fad6448e8ebed6cdabf2b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 5 Aug 2024 08:58:56 +0200 Subject: [PATCH 049/210] update dates --- embassy-embedded-hal/CHANGELOG.md | 2 +- embassy-executor/CHANGELOG.md | 2 +- embassy-net-driver-channel/CHANGELOG.md | 4 +++- embassy-nrf/CHANGELOG.md | 2 +- embassy-rp/CHANGELOG.md | 2 +- embassy-time/CHANGELOG.md | 2 +- embassy-usb/CHANGELOG.md | 2 +- 7 files changed, 9 insertions(+), 7 deletions(-) diff --git a/embassy-embedded-hal/CHANGELOG.md b/embassy-embedded-hal/CHANGELOG.md index f61fe1e24..f8e272160 100644 --- a/embassy-embedded-hal/CHANGELOG.md +++ b/embassy-embedded-hal/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.2.0 +## 0.2.0 - 2024-08-05 - Add Clone derive to flash Partition in embassy-embedded-hal - Add support for all word sizes to async shared spi diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index a699dc238..5582b56ec 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.6.0 - 2024-08-01 +## 0.6.0 - 2024-08-05 - Add collapse_debuginfo to fmt.rs macros. - initial support for avr diff --git a/embassy-net-driver-channel/CHANGELOG.md b/embassy-net-driver-channel/CHANGELOG.md index a9aff4f2c..d7af7e55d 100644 --- a/embassy-net-driver-channel/CHANGELOG.md +++ b/embassy-net-driver-channel/CHANGELOG.md @@ -5,7 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.3.0 - 2024-08-02 +## Unreleased + +## 0.3.0 - 2024-08-05 - Add collapse_debuginfo to fmt.rs macros. - Update embassy-sync version diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 213798ba9..45751a2e8 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.2.0 - 2024-08-02 +## 0.2.0 - 2024-08-05 - Add collapse_debuginfo to fmt.rs macros. - support EGU peripheral diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 4d2af23fc..7eef64292 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.2.0 - 2024-08-02 +## 0.2.0 - 2024-08-05 - Add read_to_break_with_count - add option to provide your own boot2 diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 1ad715242..3b4d93387 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.3.2 - 2024-08-02 +## 0.3.2 - 2024-08-05 - Implement with_timeout()/with_deadline() method style call on Future - Add collapse_debuginfo to fmt.rs macros. diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index 16a18e042..efdda96fb 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.3.0 - 2024-08-02 +## 0.3.0 - 2024-08-05 - bump usbd-hid from 0.7.0 to 0.8.1 - Add collapse_debuginfo to fmt.rs macros. From 31ac31f3f3f06b10a74e90aba662dbd836b4456f Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Mon, 5 Aug 2024 10:36:30 +0300 Subject: [PATCH 050/210] nrf: Rearrange CHANGELOG by features for better overview --- embassy-nrf/CHANGELOG.md | 49 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 45751a2e8..f8d6ab753 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -9,27 +9,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.2.0 - 2024-08-05 -- Add collapse_debuginfo to fmt.rs macros. -- support EGU peripheral -- support nrf9151 -- Drop `sealed` mod -- nrf52840: Add dcdc voltage parameter to configure REG0 regulator -- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral -- spim: Reduce trace-level messages ("Copying SPIM tx buffer..") -- uart: Add support for rx- or tx-only BufferedUart -- uart: Implement splitting Rx/Tx -- spi: Allow specifying OutputDrive for SPI spins -- pdm: Fix gain register value derivation -- spim: Implement chunked DMA transfers -- spi: Add bounds checks for EasyDMA buffer size -- uarte: Add support for handling RX errors -- nrf51: Implement support for nrf51 chip -- pwm: Expose `duty` method -- pwm: Fix infinite loop -- spi: Add support for configuring bit order for bus -- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method -- gpio: Drop GPIO Pin generics (API break) -- pwm: Allow specifying OutputDrive for PWM channels +- Support for NRF chips: + - nrf51 + - nrf9151 +- Support for new peripherals: + - EGU + - radio - low-level support for IEEE 802.15.4 and BLE via radio peripheral +- Peripheral changes: + - gpio: Drop GPIO Pin generics (API break) + - pdm: Fix gain register value derivation + - pwm: + - Expose `duty` method + - Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method + - Allow specifying OutputDrive for PWM channels + - Fix infinite loop + - spim: + - Reduce trace-level messages ("Copying SPIM tx buffer..") + - Support configuring bit order for bus + - Allow specifying OutputDrive for SPI pins + - Add bounds checks for EasyDMA buffer size + - Implement chunked DMA transfers + - uart: + - Add support for rx- or tx-only BufferedUart + - Implement splitting Rx/Tx + - Add support for handling RX errors +- Miscellaneous changes: + - Add `collapse_debuginfo` to fmt.rs macros. + - Drop `sealed` mod + - nrf52840: Add dcdc voltage parameter to configure REG0 regulator ## 0.1.0 - 2024-01-12 From 2a7fe16ceb53aca38f73ac01a923ea445654673c Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 11:18:16 +0200 Subject: [PATCH 051/210] Improve shared data placement, require less atomic support and use unsafecell for the clocks --- embassy-stm32/Cargo.toml | 2 +- embassy-stm32/src/lib.rs | 32 ++++++++++++------------- embassy-stm32/src/rcc/mod.rs | 4 ++-- examples/stm32h755cm4/memory.x | 1 + examples/stm32h755cm4/src/bin/blinky.rs | 2 +- examples/stm32h755cm7/memory.x | 1 + examples/stm32h755cm7/src/bin/blinky.rs | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index a72a1a667..30f486ccc 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -80,7 +80,7 @@ stm32-fmc = "0.3.0" cfg-if = "1.0.0" embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } -chrono = { version = "^0.4", default-features = false, optional = true} +chrono = { version = "^0.4", default-features = false, optional = true } bit_field = "0.10.2" document-features = "0.2.7" diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 03c0eda1d..12ebbae2d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -280,6 +280,7 @@ pub fn init(config: Config) -> Peripherals { #[cfg(feature = "_dual-core")] mod dual_core { + use core::cell::UnsafeCell; use core::mem::MaybeUninit; use core::sync::atomic::{AtomicUsize, Ordering}; @@ -301,9 +302,11 @@ mod dual_core { /// This static must be placed in the same position for both cores. How and where this is done is left to the user. pub struct SharedData { init_flag: AtomicUsize, - clocks: MaybeUninit, + clocks: UnsafeCell>, } + unsafe impl Sync for SharedData {} + const INIT_DONE_FLAG: usize = 0xca11ab1e; /// Initialize the `embassy-stm32` HAL with the provided configuration. @@ -319,7 +322,7 @@ mod dual_core { pub fn init_primary(config: Config, shared_data: &'static MaybeUninit) -> Peripherals { let shared_data = unsafe { shared_data.assume_init_ref() }; - rcc::set_freqs_ptr(&shared_data.clocks); + rcc::set_freqs_ptr(shared_data.clocks.get()); let p = init_hw(config); shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst); @@ -339,14 +342,13 @@ mod dual_core { pub fn try_init_secondary(shared_data: &'static MaybeUninit) -> Option { let shared_data = unsafe { shared_data.assume_init_ref() }; - if shared_data - .init_flag - .compare_exchange(INIT_DONE_FLAG, 0, Ordering::SeqCst, Ordering::SeqCst) - .is_err() - { + if shared_data.init_flag.load(Ordering::SeqCst) != INIT_DONE_FLAG { return None; } + // Separate load and store to support the CM0 of the STM32WL + shared_data.init_flag.store(0, Ordering::SeqCst); + Some(init_secondary_hw(shared_data)) } @@ -360,19 +362,15 @@ mod dual_core { /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs /// for more information on its requirements. pub fn init_secondary(shared_data: &'static MaybeUninit) -> Peripherals { - let shared_data = unsafe { shared_data.assume_init_ref() }; - - while shared_data - .init_flag - .compare_exchange(INIT_DONE_FLAG, 0, Ordering::SeqCst, Ordering::SeqCst) - .is_err() - {} - - init_secondary_hw(shared_data) + loop { + if let Some(p) = try_init_secondary(shared_data) { + return p; + } + } } fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals { - rcc::set_freqs_ptr(&shared_data.clocks); + rcc::set_freqs_ptr(shared_data.clocks.get()); // We use different timers on the different cores, so we have to still initialize one here #[cfg(feature = "_time-driver")] diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0656619b1..8022a35a4 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -59,8 +59,8 @@ static CLOCK_FREQS_PTR: core::sync::atomic::AtomicPtr> = core::sync::atomic::AtomicPtr::new(core::ptr::null_mut()); #[cfg(feature = "_dual-core")] -pub(crate) fn set_freqs_ptr(freqs: &'static MaybeUninit) { - CLOCK_FREQS_PTR.store(freqs as *const _ as *mut _, core::sync::atomic::Ordering::SeqCst); +pub(crate) fn set_freqs_ptr(freqs: *mut MaybeUninit) { + CLOCK_FREQS_PTR.store(freqs, core::sync::atomic::Ordering::SeqCst); } #[cfg(not(feature = "_dual-core"))] diff --git a/examples/stm32h755cm4/memory.x b/examples/stm32h755cm4/memory.x index 538bac586..7d60354e3 100644 --- a/examples/stm32h755cm4/memory.x +++ b/examples/stm32h755cm4/memory.x @@ -9,6 +9,7 @@ SECTIONS { .ram_d3 : { + *(.ram_d3.shared_data) *(.ram_d3) } > RAM_D3 } \ No newline at end of file diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs index f750c5db6..b5c547839 100644 --- a/examples/stm32h755cm4/src/bin/blinky.rs +++ b/examples/stm32h755cm4/src/bin/blinky.rs @@ -10,7 +10,7 @@ use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".ram_d3"] +#[link_section = ".ram_d3.shared_data"] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32h755cm7/memory.x b/examples/stm32h755cm7/memory.x index ab2afc216..ef884796a 100644 --- a/examples/stm32h755cm7/memory.x +++ b/examples/stm32h755cm7/memory.x @@ -9,6 +9,7 @@ SECTIONS { .ram_d3 : { + *(.ram_d3.shared_data) *(.ram_d3) } > RAM_D3 } \ No newline at end of file diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs index f76a136aa..94d2226c0 100644 --- a/examples/stm32h755cm7/src/bin/blinky.rs +++ b/examples/stm32h755cm7/src/bin/blinky.rs @@ -10,7 +10,7 @@ use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".ram_d3"] +#[link_section = ".ram_d3.shared_data"] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] From 90427ee231f7c58ca92100817668cd6f16843ebb Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 12:10:45 +0200 Subject: [PATCH 052/210] Fix WL boot example --- examples/boot/application/stm32wl/memory.x | 11 ++++++++++- examples/boot/application/stm32wl/src/bin/a.rs | 8 +++++++- examples/boot/application/stm32wl/src/bin/b.rs | 8 +++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x index e1d4e7fa8..9adf19f0e 100644 --- a/examples/boot/application/stm32wl/memory.x +++ b/examples/boot/application/stm32wl/memory.x @@ -5,7 +5,8 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K FLASH : ORIGIN = 0x08008000, LENGTH = 64K DFU : ORIGIN = 0x08018000, LENGTH = 68K - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K - 1K + SHARED_RAM (rwx) : ORIGIN = 0x20007C00, LENGTH = 1K } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); @@ -13,3 +14,11 @@ __bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - O __bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER); __bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER); + +SECTIONS +{ + .shared_data : + { + *(.shared_data) + } > SHARED_RAM +} \ No newline at end of file diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index 9f4f0b238..127de0237 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + #[cfg(feature = "defmt")] use defmt_rtt::*; use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; @@ -9,6 +11,7 @@ use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; +use embassy_stm32::SharedData; use embassy_sync::mutex::Mutex; use panic_reset as _; @@ -17,9 +20,12 @@ static APP_B: &[u8] = &[0, 1, 2, 3]; #[cfg(not(feature = "skip-include"))] static APP_B: &[u8] = include_bytes!("../../b.bin"); +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); let flash = Flash::new_blocking(p.FLASH); let flash = Mutex::new(BlockingAsync::new(flash)); diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs index e954d8b91..768dadf8b 100644 --- a/examples/boot/application/stm32wl/src/bin/b.rs +++ b/examples/boot/application/stm32wl/src/bin/b.rs @@ -1,16 +1,22 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + #[cfg(feature = "defmt")] use defmt_rtt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::SharedData; use embassy_time::Timer; use panic_reset as _; +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); let mut led = Output::new(p.PB15, Level::High, Speed::Low); loop { From 819d1efb5b34adc0e114444b4cd0a771dd26d8e9 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Mon, 5 Aug 2024 20:48:55 +1000 Subject: [PATCH 053/210] Uprev cyw43 and cyw43-pio for embassy-rp 0.2 --- cyw43-pio/Cargo.toml | 4 ++-- cyw43/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 9c7acd779..1172d6c31 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cyw43-pio" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "RP2040 PIO SPI implementation for cyw43" keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] @@ -15,7 +15,7 @@ documentation = "https://docs.embassy.dev/cyw43-pio" overclock = [] [dependencies] -cyw43 = { version = "0.1.0", path = "../cyw43" } +cyw43 = { version = "0.2.0", path = "../cyw43" } embassy-rp = { version = "0.2.0", path = "../embassy-rp" } pio-proc = "0.2" pio = "0.2.1" diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 3c90873de..654afe356 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cyw43" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] From 741ca2046f876b149c1978003ba0f35c259c7f52 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 14:12:46 +0200 Subject: [PATCH 054/210] Change embassy-boot ci tests to non-dual core chip for simplicity. Add new examples to CI --- ci.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index 4c9397cee..50ec3870e 100755 --- a/ci.sh +++ b/ci.sh @@ -179,7 +179,7 @@ cargo batch \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \ - --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ + --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ @@ -207,6 +207,8 @@ cargo batch \ --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \ --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ --- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h735 \ + --- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm4 \ + --- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm7 \ --- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7rs \ --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ @@ -233,7 +235,7 @@ cargo batch \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ - --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ + --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \ --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h747xi-cm7 \ --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ From 9b8848936f3035f11b16746d31bf055428263656 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 14:16:11 +0200 Subject: [PATCH 055/210] Update new examples to new releases --- examples/stm32h755cm4/Cargo.toml | 6 +++--- examples/stm32h755cm7/Cargo.toml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index c366bc3d2..9d2fb9060 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0" # Change stm32h755zi-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index a97a8a5c5..ab088fd33 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" From dc77601e9f6f78dc7681e427a66ba8314c96e535 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:15:35 +1000 Subject: [PATCH 056/210] Update rp examples to cyw43 0.2 and cyw43-pio 0.2 --- examples/rp/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 5ed51a5c0..4945f4bd2 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -16,8 +16,8 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } -cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } +cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } +cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } defmt = "0.3" defmt-rtt = "0.4" From 49a8cf251ba1357aa6ba7400e4c47d71e81e9f0c Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Mon, 5 Aug 2024 22:19:01 +1000 Subject: [PATCH 057/210] Add cyw43/cyw43-pio changelogs --- cyw43-pio/CHANGELOG.md | 17 +++++++++++++++++ cyw43/CHANGELOG.md | 23 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 cyw43-pio/CHANGELOG.md create mode 100644 cyw43/CHANGELOG.md diff --git a/cyw43-pio/CHANGELOG.md b/cyw43-pio/CHANGELOG.md new file mode 100644 index 000000000..913f3515a --- /dev/null +++ b/cyw43-pio/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## 0.2.0 - 2024-08-05 + +- Update to cyw43 0.2.0 +- Update to embassy-rp 0.2.0 + +## 0.1.0 - 2024-01-11 + +- First release diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md new file mode 100644 index 000000000..1859f7317 --- /dev/null +++ b/cyw43/CHANGELOG.md @@ -0,0 +1,23 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## 0.2.0 - 2024-08-05 + +- Update to new versions of embassy-{time,sync} +- Add more fields to the BssInfo packet struct #2461 +- Extend the Scan API #2282 +- Reuse buf to reduce stack usage #2580 +- Add MAC address getter to cyw43 controller #2818 +- Add function to join WPA2 network with precomputed PSK. #2885 +- Add function to close soft AP. #3042 +- Fixing missing re-export #3211 + +## 0.1.0 - 2024-01-11 + +- First release From 705a8fc38c0e5ef9cbd6bfaf95bca70fac5d9f81 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 14:19:45 +0200 Subject: [PATCH 058/210] Change dual bank CI test to non-dual core --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 50ec3870e..ce165cf39 100755 --- a/ci.sh +++ b/ci.sh @@ -237,7 +237,7 @@ cargo batch \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \ - --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h747xi-cm7 \ + --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \ --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ From 5884576b88e7ec7e26ec1c9b9f61e253cb0e5ea6 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 14:43:57 +0200 Subject: [PATCH 059/210] Updated WL examples to use new API --- examples/boot/application/stm32wl/memory.x | 4 ++-- examples/stm32wl/memory.x | 15 +++++++++++++++ examples/stm32wl/src/bin/blinky.rs | 12 ++++++++++-- examples/stm32wl/src/bin/button.rs | 9 +++++++-- examples/stm32wl/src/bin/button_exti.rs | 9 +++++++-- examples/stm32wl/src/bin/flash.rs | 9 +++++++-- examples/stm32wl/src/bin/random.rs | 9 +++++++-- examples/stm32wl/src/bin/rtc.rs | 9 +++++++-- examples/stm32wl/src/bin/uart_async.rs | 9 +++++++-- 9 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 examples/stm32wl/memory.x diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x index 9adf19f0e..5af1723f5 100644 --- a/examples/boot/application/stm32wl/memory.x +++ b/examples/boot/application/stm32wl/memory.x @@ -5,8 +5,8 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K FLASH : ORIGIN = 0x08008000, LENGTH = 64K DFU : ORIGIN = 0x08018000, LENGTH = 68K - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K - 1K - SHARED_RAM (rwx) : ORIGIN = 0x20007C00, LENGTH = 1K + SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 + RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 32K - 64 } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); diff --git a/examples/stm32wl/memory.x b/examples/stm32wl/memory.x new file mode 100644 index 000000000..0298caa4b --- /dev/null +++ b/examples/stm32wl/memory.x @@ -0,0 +1,15 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x08000000, LENGTH = 256K + SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 + RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 64K - 64 +} + +SECTIONS +{ + .shared_data : + { + *(.shared_data) + } > SHARED_RAM +} \ No newline at end of file diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs index 347bd093f..048ce9175 100644 --- a/examples/stm32wl/src/bin/blinky.rs +++ b/examples/stm32wl/src/bin/blinky.rs @@ -1,15 +1,23 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::{ + gpio::{Level, Output, Speed}, + SharedData, +}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); info!("Hello World!"); let mut led = Output::new(p.PB15, Level::High, Speed::Low); diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index eccd211e2..92884da1f 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -1,16 +1,21 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::{gpio::{Input, Level, Output, Pull, Speed}, SharedData}; use {defmt_rtt as _, panic_probe as _}; +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[entry] fn main() -> ! { info!("Hello World!"); - let p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); let button = Input::new(p.PA0, Pull::Up); let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs index 27d5330bd..d1e443bf8 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs @@ -1,15 +1,20 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; +use embassy_stm32::{exti::ExtiInput, SharedData}; use {defmt_rtt as _, panic_probe as _}; +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); info!("Hello World!"); let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index 0b7417c01..e7d90dc19 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -1,14 +1,19 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; +use embassy_stm32::{flash::Flash, SharedData}; use {defmt_rtt as _, panic_probe as _}; +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); info!("Hello Flash!"); const ADDR: u32 = 0x36000; diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 8e9fe02b2..df2ed0054 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -1,17 +1,22 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::{bind_interrupts, peripherals, SharedData}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ RNG => rng::InterruptHandler; }); +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); @@ -32,7 +37,7 @@ async fn main(_spawner: Spawner) { divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) }); } - let p = embassy_stm32::init(config); + let p = embassy_stm32::init_primary(config, &SHARED_DATA); info!("Hello World!"); diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index cf7d6d220..69a9ddc4c 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -1,15 +1,20 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::time::Hertz; -use embassy_stm32::Config; +use embassy_stm32::{Config, SharedData}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -31,7 +36,7 @@ async fn main(_spawner: Spawner) { divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) }); } - let p = embassy_stm32::init(config); + let p = embassy_stm32::init_primary(config, &SHARED_DATA); info!("Hello World!"); let now = NaiveDate::from_ymd_opt(2020, 5, 15) diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 3637243a0..ece9b9201 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -1,10 +1,12 @@ #![no_std] #![no_main] +use core::mem::MaybeUninit; + use defmt::*; use embassy_executor::Spawner; use embassy_stm32::usart::{Config, InterruptHandler, Uart}; -use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::{bind_interrupts, peripherals, SharedData}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ @@ -12,6 +14,9 @@ bind_interrupts!(struct Irqs{ LPUART1 => InterruptHandler; }); +#[link_section = ".shared_data"] +static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); + /* Pass Incoming data from LPUART1 to USART1 Example is written for the LoRa-E5 mini v1.0, @@ -21,7 +26,7 @@ but can be surely changed for your needs. async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); config.rcc.sys = embassy_stm32::rcc::Sysclk::HSE; - let p = embassy_stm32::init(config); + let p = embassy_stm32::init_primary(config, &SHARED_DATA); defmt::info!("Starting system"); From 3cd20814501d03852a3c30facbd204dffcf048db Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 15:07:51 +0200 Subject: [PATCH 060/210] Fix tests --- examples/stm32wl/src/bin/button.rs | 5 ++++- tests/stm32/src/bin/can.rs | 2 +- tests/stm32/src/bin/cordic.rs | 2 +- tests/stm32/src/bin/cryp.rs | 2 +- tests/stm32/src/bin/dac.rs | 2 +- tests/stm32/src/bin/dac_l1.rs | 2 +- tests/stm32/src/bin/eth.rs | 2 +- tests/stm32/src/bin/fdcan.rs | 4 ++-- tests/stm32/src/bin/gpio.rs | 2 +- tests/stm32/src/bin/hash.rs | 2 +- tests/stm32/src/bin/rng.rs | 2 +- tests/stm32/src/bin/rtc.rs | 2 +- tests/stm32/src/bin/sdmmc.rs | 2 +- tests/stm32/src/bin/spi.rs | 2 +- tests/stm32/src/bin/spi_dma.rs | 2 +- tests/stm32/src/bin/stop.rs | 2 +- tests/stm32/src/bin/timer.rs | 2 +- tests/stm32/src/bin/ucpd.rs | 2 +- tests/stm32/src/bin/usart.rs | 2 +- tests/stm32/src/bin/usart_dma.rs | 2 +- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 2 +- tests/stm32/src/bin/wpan_ble.rs | 2 +- tests/stm32/src/bin/wpan_mac.rs | 2 +- tests/stm32/src/common.rs | 18 ++++++++++++++++++ 24 files changed, 45 insertions(+), 24 deletions(-) diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index 92884da1f..e7f44b437 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -5,7 +5,10 @@ use core::mem::MaybeUninit; use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::{gpio::{Input, Level, Output, Pull, Speed}, SharedData}; +use embassy_stm32::{ + gpio::{Input, Level, Output, Pull, Speed}, + SharedData, +}; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".shared_data"] diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index ba8a33e34..85a5f8d83 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -27,7 +27,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); let options = TestOptions { diff --git a/tests/stm32/src/bin/cordic.rs b/tests/stm32/src/bin/cordic.rs index e09226de8..879ad56b6 100644 --- a/tests/stm32/src/bin/cordic.rs +++ b/tests/stm32/src/bin/cordic.rs @@ -29,7 +29,7 @@ const OUTPUT_LENGTH: usize = (INPUT_U32_COUNT - 1) * 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let dp = embassy_stm32::init(config()); + let dp = init(); // // use RNG generate random Q1.31 value diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index 60778bdaa..028775ac8 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + let p: embassy_stm32::Peripherals = init(); const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567"; const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh"; diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs index 86a68c530..88e661525 100644 --- a/tests/stm32/src/bin/dac.rs +++ b/tests/stm32/src/bin/dac.rs @@ -20,7 +20,7 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { // Initialize the board and obtain a Peripherals instance - let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + let p: embassy_stm32::Peripherals = init(); let adc = peri!(p, ADC); let dac = peri!(p, DAC); diff --git a/tests/stm32/src/bin/dac_l1.rs b/tests/stm32/src/bin/dac_l1.rs index d5e9c9722..925db617d 100644 --- a/tests/stm32/src/bin/dac_l1.rs +++ b/tests/stm32/src/bin/dac_l1.rs @@ -25,7 +25,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { // Initialize the board and obtain a Peripherals instance - let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + let p: embassy_stm32::Peripherals = init(); let adc = peri!(p, ADC); let dac = peri!(p, DAC); diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index 7c02f0354..25a06b986 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -38,7 +38,7 @@ async fn net_task(stack: &'static Stack) -> ! { #[embassy_executor::main] async fn main(spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); // Generate random seed. diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index bc2b7edd4..83d7eca85 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -102,10 +102,10 @@ fn options() -> (Config, TestOptions) { #[embassy_executor::main] async fn main(_spawner: Spawner) { - //let peripherals = embassy_stm32::init(config()); + //let peripherals = init(); let (config, options) = options(); - let peripherals = embassy_stm32::init(config); + let peripherals = init_with_config(config); let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index 1d1018c5c..4a2584b4e 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs @@ -10,7 +10,7 @@ use embassy_stm32::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull, Spe #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); // Arduino pins D0 and D1 diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index 5f54ea435..bdb3c9a69 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -35,7 +35,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + let p: embassy_stm32::Peripherals = init(); let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs); let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; diff --git a/tests/stm32/src/bin/rng.rs b/tests/stm32/src/bin/rng.rs index 15ef4fb60..8438353a8 100644 --- a/tests/stm32/src/bin/rng.rs +++ b/tests/stm32/src/bin/rng.rs @@ -41,7 +41,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); + let p: embassy_stm32::Peripherals = init(); let mut rng = Rng::new(p.RNG, Irqs); diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs index c04d616ac..5fe98d807 100644 --- a/tests/stm32/src/bin/rtc.rs +++ b/tests/stm32/src/bin/rtc.rs @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { let mut config = config(); config.rcc.ls = LsConfig::default_lse(); - let p = embassy_stm32::init(config); + let p = init_with_config(config); info!("Hello World!"); let now = NaiveDate::from_ymd_opt(2020, 5, 15) diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index 54f55d2d6..a6bc117c0 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { info!("Hello World!"); - let p = embassy_stm32::init(config()); + let p = init(); let (mut sdmmc, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) = (p.SDIO, p.DMA2_CH3, p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11); diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index 0ffd0f653..53d44a94a 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs @@ -12,7 +12,7 @@ use embassy_stm32::time::Hertz; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); let mut spi_peri = peri!(p, SPI); diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index fd26d3f71..a1cbc0ed1 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs @@ -12,7 +12,7 @@ use embassy_stm32::time::Hertz; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); let mut spi_peri = peri!(p, SPI); diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index c1106bb2f..772bc527c 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -58,7 +58,7 @@ async fn async_main(spawner: Spawner) { config.rcc.hsi = Some(HSIPrescaler::DIV4); // 64 MHz HSI will need a /4 } - let p = embassy_stm32::init(config); + let p = init_with_config(config); info!("Hello World!"); let now = NaiveDate::from_ymd_opt(2020, 5, 15) diff --git a/tests/stm32/src/bin/timer.rs b/tests/stm32/src/bin/timer.rs index d86f54ad2..8719e7670 100644 --- a/tests/stm32/src/bin/timer.rs +++ b/tests/stm32/src/bin/timer.rs @@ -10,7 +10,7 @@ use embassy_time::{Instant, Timer}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let _p = embassy_stm32::init(config()); + let _p = init(); info!("Hello World!"); let start = Instant::now(); diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs index c09334ec8..a6d13b34a 100644 --- a/tests/stm32/src/bin/ucpd.rs +++ b/tests/stm32/src/bin/ucpd.rs @@ -102,7 +102,7 @@ async fn sink( #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); // Wire between PD0 and PA8 diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index a6e34674d..53da30fff 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -11,7 +11,7 @@ use embassy_time::{block_for, Duration, Instant}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); // Arduino pins D0 and D1 diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index 24e2b2896..266b81809 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs @@ -11,7 +11,7 @@ use embassy_stm32::usart::{Config, Uart}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); // Arduino pins D0 and D1 diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index ea1e52358..98c7ef312 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -18,7 +18,7 @@ const DMA_BUF_SIZE: usize = 256; #[embassy_executor::main] async fn main(spawner: Spawner) { - let p = embassy_stm32::init(config()); + let p = init(); info!("Hello World!"); // Arduino pins D0 and D1 diff --git a/tests/stm32/src/bin/wpan_ble.rs b/tests/stm32/src/bin/wpan_ble.rs index 82a540d45..fde1dfa9b 100644 --- a/tests/stm32/src/bin/wpan_ble.rs +++ b/tests/stm32/src/bin/wpan_ble.rs @@ -41,7 +41,7 @@ async fn main(spawner: Spawner) { let mut config = config(); config.rcc = WPAN_DEFAULT; - let p = embassy_stm32::init(config); + let p = init_with_config(config); info!("Hello World!"); let config = Config::default(); diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs index fe53b8786..b65ace40f 100644 --- a/tests/stm32/src/bin/wpan_mac.rs +++ b/tests/stm32/src/bin/wpan_mac.rs @@ -34,7 +34,7 @@ async fn main(spawner: Spawner) { let mut config = config(); config.rcc = WPAN_DEFAULT; - let p = embassy_stm32::init(config); + let p = init_with_config(config); info!("Hello World!"); let config = Config::default(); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 4e0231858..649eac6f6 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -699,3 +699,21 @@ pub fn config() -> Config { config } + +#[allow(unused)] +pub fn init() -> embassy_stm32::Peripherals { + init_with_config(config()) +} + +#[allow(unused)] +pub fn init_with_config(config: Config) -> embassy_stm32::Peripherals { + #[cfg(feature = "stm32wl55jc")] + { + // Not in shared memory, but we're not running the second core, so it's fine + static SHARED_DATA: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); + embassy_stm32::init_primary(config, &SHARED_DATA) + } + + #[cfg(not(feature = "stm32wl55jc"))] + embassy_stm32::init(config) +} From e322732fdba282f4150a186aed606b88714921fe Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 5 Aug 2024 15:13:11 +0200 Subject: [PATCH 061/210] Add H7 dual core to common and run fmt --- examples/stm32wl/src/bin/blinky.rs | 6 ++---- examples/stm32wl/src/bin/button.rs | 6 ++---- examples/stm32wl/src/bin/button_exti.rs | 3 ++- examples/stm32wl/src/bin/flash.rs | 3 ++- tests/stm32/src/common.rs | 4 ++-- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs index 048ce9175..ce7d0ec58 100644 --- a/examples/stm32wl/src/bin/blinky.rs +++ b/examples/stm32wl/src/bin/blinky.rs @@ -5,10 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::{ - gpio::{Level, Output, Speed}, - SharedData, -}; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index e7f44b437..8b5204479 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -5,10 +5,8 @@ use core::mem::MaybeUninit; use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::{ - gpio::{Input, Level, Output, Pull, Speed}, - SharedData, -}; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".shared_data"] diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs index d1e443bf8..8dd1a6a5e 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs @@ -5,8 +5,9 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; -use embassy_stm32::{exti::ExtiInput, SharedData}; +use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".shared_data"] diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index e7d90dc19..147f5d293 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -5,7 +5,8 @@ use core::mem::MaybeUninit; use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::{flash::Flash, SharedData}; +use embassy_stm32::flash::Flash; +use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".shared_data"] diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 649eac6f6..935a41ed2 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -707,13 +707,13 @@ pub fn init() -> embassy_stm32::Peripherals { #[allow(unused)] pub fn init_with_config(config: Config) -> embassy_stm32::Peripherals { - #[cfg(feature = "stm32wl55jc")] + #[cfg(any(feature = "stm32wl55jc", feature = "stm32h755zi"))] { // Not in shared memory, but we're not running the second core, so it's fine static SHARED_DATA: core::mem::MaybeUninit = core::mem::MaybeUninit::uninit(); embassy_stm32::init_primary(config, &SHARED_DATA) } - #[cfg(not(feature = "stm32wl55jc"))] + #[cfg(not(any(feature = "stm32wl55jc", feature = "stm32h755zi")))] embassy_stm32::init(config) } From 06872da5f8b26fee2f660340fb636766aba1e935 Mon Sep 17 00:00:00 2001 From: Joris Kleiber Date: Mon, 5 Aug 2024 16:59:08 +0200 Subject: [PATCH 062/210] Fix broken link to rp-pac and add link to critical-section in embassy-rp --- embassy-rp/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index f6c0fba2d..b7f5a2bcc 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -22,13 +22,13 @@ features = ["defmt", "unstable-pac", "time-driver"] [features] default = [ "rt" ] -## Enable the rt feature of [`rp-pac`](https://docs.rs/crates/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. +## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. rt = [ "rp-pac/rt" ] ## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] -## Configure the critical section crate to use an implementation that is safe for multicore use on rp2040. +## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. critical-section-impl = ["critical-section/restore-state-u8"] ## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. From 4f7ac1946a43379306aa432961fb97bba1139a6e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 5 Aug 2024 20:58:04 +0200 Subject: [PATCH 063/210] cyw43: add Bluetooth support. Co-Authored-By: Brandon Ros --- ci.sh | 2 + cyw43-firmware/43439A0.bin | Bin 230321 -> 231077 bytes cyw43-firmware/43439A0_btfw.bin | Bin 0 -> 6164 bytes cyw43-firmware/43439A0_clm.bin | Bin 4752 -> 984 bytes cyw43-firmware/README.md | 11 +- cyw43-pio/src/lib.rs | 9 +- cyw43/Cargo.toml | 8 +- cyw43/src/bluetooth.rs | 508 ++++++++++++++++++++++ cyw43/src/bus.rs | 90 +++- cyw43/src/consts.rs | 67 ++- cyw43/src/control.rs | 10 +- cyw43/src/lib.rs | 87 +++- cyw43/src/runner.rs | 120 ++++- cyw43/src/util.rs | 20 + examples/rp/Cargo.toml | 17 +- examples/rp/src/bin/bluetooth.rs | 148 +++++++ examples/rp/src/bin/wifi_ap_tcp_server.rs | 4 +- examples/rp/src/bin/wifi_blinky.rs | 4 +- examples/rp/src/bin/wifi_scan.rs | 4 +- examples/rp/src/bin/wifi_tcp_server.rs | 8 +- examples/rp/src/bin/wifi_webrequest.rs | 4 +- 21 files changed, 1037 insertions(+), 84 deletions(-) mode change 100755 => 100644 cyw43-firmware/43439A0.bin create mode 100644 cyw43-firmware/43439A0_btfw.bin mode change 100755 => 100644 cyw43-firmware/43439A0_clm.bin create mode 100644 cyw43/src/bluetooth.rs create mode 100644 cyw43/src/util.rs create mode 100644 examples/rp/src/bin/bluetooth.rs diff --git a/ci.sh b/ci.sh index ce165cf39..0cd0c54bc 100755 --- a/ci.sh +++ b/ci.sh @@ -173,6 +173,8 @@ cargo batch \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \ + --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \ + --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ diff --git a/cyw43-firmware/43439A0.bin b/cyw43-firmware/43439A0.bin old mode 100755 new mode 100644 index 017375277d77d10e198deb1c668e2e6bb074d869..a05482fe957fbbf27d334e9b5c4fa6c53022f0bf GIT binary patch delta 54774 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

;x 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

&Y+ql0}nlp2EOH$C5sqy6Gc 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 SQ^lw$6Q{++#m5)K8~-2KbzOD< diff --git a/cyw43-firmware/43439A0_btfw.bin b/cyw43-firmware/43439A0_btfw.bin new file mode 100644 index 0000000000000000000000000000000000000000..290ce8ef0607f51f995e356808f8f05aab5fe4ba GIT binary patch literal 6164 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 X^C0l)rvY5Xo3-pBxXe^|a|7~sadC2< literal 0 HcmV?d00001 diff --git a/cyw43-firmware/43439A0_clm.bin b/cyw43-firmware/43439A0_clm.bin old mode 100755 new mode 100644 index 1fedd753ac255eb8feb4b81a8214d4070a8e414c..dc4ee02523209e1cc843272ead9d95fd285f2bbf GIT binary patch literal 984 zcmbVKJ#Q015S_KdmtzAVp^YrjAfa5&E87WHn)BJQ51*Zr?@UZOKuEEa#Fi5wMT&&z zC@Cpvsfg0j@B=9M0SJknn&x)*qvH!!Fv%H12%4k>XHMhE^%SE?Zt5j<4Cb$$s zNvc+{v_%=XGKX^xZ=zNeI8c{{y?Stjdr#Bf;w2DJ=~wXv7Sx*reG7cgsHNY;M~zvq z9}@Hkb_n(?Xh0`b$ZB+~r%B~zY(3j7(W+Zdi=H;K+H5Rf(SSt*>I6K+lgR3HSgS+9 zFtAj};E>AUQ%iM8b%*pkv!K@^U>iLixyK_%EE@5mA_hlPju{hEFlJ*hkDM?)Ve`qZ ztv-m&JL0{DL&>HYT<@M|DOJGZw87fR{2S~B_@lXe;r5-oOZS#n?&tBDvJ2O)-?(`z Nw`jEfwa=eK{sQ=&t>FLw literal 4752 zcmd5=&2Jn_5wGsq_1e4Z_1N)y;YH$Uq&y^q9JBU1j$@)H@63MB%zC^tyWX{OiHHOT zLQupZ5>ogF-U)Hw$Q20*#NUwvM}))$i30}?+@CbmZ@MZ$95``cWzW`jcYXY-s;jFf zOs>OcMD(+7{o@P6-PeDnIn%kRH_^{9K? z{WxKaX_}U4n_bhf);4X+w!NKZv(;+1+q><~?rx`Zb3!+#%<{*5q9Zo)hfEg?=nMw) z=T`#kFTVSo@Z5y)1pNQ=Ke(~~_WYXV;`2@&|HXlh0aGY-voVJ7^yG}A$SIyBSV zObav1ym(QIZ%r~aNnw(uNmeH9o3t?L+RPI(zcyK7vchB=v$!^kWj!C7d}{L86pKc2 zYnSJg8ri5o z-~x)M@8U&Vp`61bjaQ`ciWE)+IEY{*C;~2O4p$^_x>2l>C2$lWa6lT(>3;cuEsTHy z&Wtj#Fj5rJQdO*!>sHsS9Y8+csQFjuZz7fT+}2p)q#J_Ce+g->YrFMA=c6qPi3RUv2v;QSfb;{x^v?N2ksCm z7PV@3`>|BffEyR*pLp%!Me&BV%WW){`a_A-RZ28_6FoQ**&xK-PbG(v*u{$yM2B~r zpGb5l(V%djv%f^sYH;{OzM1!ti!HMCFdyxE~HG^M{2?0xi&)iMpYn`Si@JystNQ9O{79l_=SeD(ArXHC=2O! z{32F%v9MdHg@syJsD*{>i-2!6&QXQNw1BBVQQS(r_}b$FSE#8=c%IkLQc^2erm}dM zQ@yNll=*VfE}IqcfV+MW8)>MPDrY4Tq?HD4r75w}q+Lx#@=8$93MqjdcdK>d7TLn? z_19hUsvKLN@Cb5#eM+A=qUS~ezEwKo*J!PQV!a?!dRUy(ZrS26tqZD*5BUDMQ#LTN zqE@*B;?~vhV7;a$*n_p?e6YTwPBpSQagzNFavsjy@D<+?{35^+kCixA;)xP)0sw9# zD72Amp}P}_^4+NtJtfYRc&x;^5>J%4P~xc)x{2;msWx}IzxWnT^@MD)Ws{~&S~hI+ zee#lQ*szyO@=eiFoqrFu?5t@AvS3B_UBj+;L48Cv+p<~HW-U7b$5o9V2_B$o&&XbF z+oN53RyueI-@)wF zj=f;Pgck~YHzWE5KRCqnU8euZ_c9JH;Z@5ErumQl%+7k7;&J VvnMpWpc&p5Vcnm2-S2)w^e-;e=~w^& diff --git a/cyw43-firmware/README.md b/cyw43-firmware/README.md index db3d9c9cf..10a6b5d02 100644 --- a/cyw43-firmware/README.md +++ b/cyw43-firmware/README.md @@ -1,9 +1,14 @@ -# WiFi firmware +# WiFi + Bluetooth firmware blobs -Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439 +Firmware obtained from https://github.com/georgerobotics/cyw43-driver/tree/main/firmware Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt) ## Changelog -* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 ot 7.95.62 +* 2023-08-21: synced with `a1dc885` - Update 43439 fw + clm to come from `wb43439A0_7_95_49_00_combined.h` + add Bluetooth firmware +* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 to 7.95.62 + +## Notes + +If you update these files, please update the lengths in the `tests/rp/src/bin/cyw43_perf.rs` test (which relies on these files running from RAM). diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 8c217b995..40cf63a17 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -181,7 +181,10 @@ where let read_bits = read.len() * 32 + 32 - 1; #[cfg(feature = "defmt")] - defmt::trace!("write={} read={}", write_bits, read_bits); + defmt::trace!("cmd_read write={} read={}", write_bits, read_bits); + + #[cfg(feature = "defmt")] + defmt::trace!("cmd_read cmd = {:02x} len = {}", cmd, read.len()); unsafe { instr::set_y(&mut self.sm, read_bits as u32); @@ -201,6 +204,10 @@ where .rx() .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status)) .await; + + #[cfg(feature = "defmt")] + defmt::trace!("cmd_read cmd = {:02x} len = {} read = {:08x}", cmd, read.len(), read); + status } } diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 654afe356..9b469c338 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -10,8 +10,9 @@ repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/cyw43" [features] -defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt"] +defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt", "bt-hci?/defmt", "embedded-io-async?/defmt-03"] log = ["dep:log"] +bluetooth = ["dep:bt-hci", "dep:embedded-io-async"] # Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. firmware-logs = [] @@ -31,9 +32,12 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa embedded-hal-1 = { package = "embedded-hal", version = "1.0" } num_enum = { version = "0.5.7", default-features = false } - heapless = "0.8.0" +# Bluetooth deps +embedded-io-async = { version = "0.6.0", optional = true } +bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3", optional = true, default-features = false } + [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs new file mode 100644 index 000000000..f617a8c7e --- /dev/null +++ b/cyw43/src/bluetooth.rs @@ -0,0 +1,508 @@ +use core::cell::RefCell; +use core::future::Future; +use core::mem::MaybeUninit; + +use bt_hci::transport::WithIndicator; +use bt_hci::{ControllerToHostPacket, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci}; +use embassy_futures::yield_now; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::zerocopy_channel; +use embassy_time::{Duration, Timer}; +use embedded_hal_1::digital::OutputPin; + +use crate::bus::Bus; +pub use crate::bus::SpiBusCyw43; +use crate::consts::*; +use crate::util::round_up; +use crate::{util, CHIP}; + +pub(crate) struct BtState { + rx: [BtPacketBuf; 4], + tx: [BtPacketBuf; 4], + inner: MaybeUninit>, +} + +impl BtState { + pub const fn new() -> Self { + Self { + rx: [const { BtPacketBuf::new() }; 4], + tx: [const { BtPacketBuf::new() }; 4], + inner: MaybeUninit::uninit(), + } + } +} + +struct BtStateInnre<'d> { + rx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>, + tx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>, +} + +/// Bluetooth driver. +pub struct BtDriver<'d> { + rx: RefCell>, + tx: RefCell>, +} + +pub(crate) struct BtRunner<'d> { + pub(crate) tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>, + rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>, + + // Bluetooth circular buffers + addr: u32, + h2b_write_pointer: u32, + b2h_read_pointer: u32, +} + +const BT_HCI_MTU: usize = 1024; + +/// Represents a packet of size MTU. +pub(crate) struct BtPacketBuf { + pub(crate) len: usize, + pub(crate) buf: [u8; BT_HCI_MTU], +} + +impl BtPacketBuf { + /// Create a new packet buffer. + pub const fn new() -> Self { + Self { + len: 0, + buf: [0; BT_HCI_MTU], + } + } +} + +pub(crate) fn new<'d>(state: &'d mut BtState) -> (BtRunner<'d>, BtDriver<'d>) { + // safety: this is a self-referential struct, however: + // - it can't move while the `'d` borrow is active. + // - when the borrow ends, the dangling references inside the MaybeUninit will never be used again. + let state_uninit: *mut MaybeUninit> = + (&mut state.inner as *mut MaybeUninit>).cast(); + let state = unsafe { &mut *state_uninit }.write(BtStateInnre { + rx: zerocopy_channel::Channel::new(&mut state.rx[..]), + tx: zerocopy_channel::Channel::new(&mut state.tx[..]), + }); + + let (rx_sender, rx_receiver) = state.rx.split(); + let (tx_sender, tx_receiver) = state.tx.split(); + + ( + BtRunner { + tx_chan: tx_receiver, + rx_chan: rx_sender, + + addr: 0, + h2b_write_pointer: 0, + b2h_read_pointer: 0, + }, + BtDriver { + rx: RefCell::new(rx_receiver), + tx: RefCell::new(tx_sender), + }, + ) +} + +pub(crate) struct CybtFwCb<'a> { + pub p_next_line_start: &'a [u8], +} + +pub(crate) struct HexFileData<'a> { + pub addr_mode: i32, + pub hi_addr: u16, + pub dest_addr: u32, + pub p_ds: &'a mut [u8], +} + +pub(crate) fn read_firmware_patch_line(p_btfw_cb: &mut CybtFwCb, hfd: &mut HexFileData) -> u32 { + let mut abs_base_addr32 = 0; + + loop { + let num_bytes = p_btfw_cb.p_next_line_start[0]; + p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..]; + + let addr = (p_btfw_cb.p_next_line_start[0] as u16) << 8 | p_btfw_cb.p_next_line_start[1] as u16; + p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[2..]; + + let line_type = p_btfw_cb.p_next_line_start[0]; + p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..]; + + if num_bytes == 0 { + break; + } + + hfd.p_ds[..num_bytes as usize].copy_from_slice(&p_btfw_cb.p_next_line_start[..num_bytes as usize]); + p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[num_bytes as usize..]; + + match line_type { + BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS => { + hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16; + hfd.addr_mode = BTFW_ADDR_MODE_EXTENDED; + } + BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS => { + hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16; + hfd.addr_mode = BTFW_ADDR_MODE_SEGMENT; + } + BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS => { + abs_base_addr32 = (hfd.p_ds[0] as u32) << 24 + | (hfd.p_ds[1] as u32) << 16 + | (hfd.p_ds[2] as u32) << 8 + | hfd.p_ds[3] as u32; + hfd.addr_mode = BTFW_ADDR_MODE_LINEAR32; + } + BTFW_HEX_LINE_TYPE_DATA => { + hfd.dest_addr = addr as u32; + match hfd.addr_mode { + BTFW_ADDR_MODE_EXTENDED => hfd.dest_addr += (hfd.hi_addr as u32) << 16, + BTFW_ADDR_MODE_SEGMENT => hfd.dest_addr += (hfd.hi_addr as u32) << 4, + BTFW_ADDR_MODE_LINEAR32 => hfd.dest_addr += abs_base_addr32, + _ => {} + } + return num_bytes as u32; + } + _ => {} + } + } + 0 +} + +impl<'a> BtRunner<'a> { + pub(crate) async fn init_bluetooth(&mut self, bus: &mut Bus, firmware: &[u8]) { + trace!("init_bluetooth"); + bus.bp_write32(CHIP.bluetooth_base_address + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE) + .await; + Timer::after(Duration::from_millis(2)).await; + self.upload_bluetooth_firmware(bus, firmware).await; + self.wait_bt_ready(bus).await; + self.init_bt_buffers(bus).await; + self.wait_bt_awake(bus).await; + self.bt_set_host_ready(bus).await; + self.bt_toggle_intr(bus).await; + } + + pub(crate) async fn upload_bluetooth_firmware( + &mut self, + bus: &mut Bus, + firmware: &[u8], + ) { + // read version + let version_length = firmware[0]; + let _version = &firmware[1..=version_length as usize]; + // skip version + 1 extra byte as per cybt_shared_bus_driver.c + let firmware = &firmware[version_length as usize + 2..]; + // buffers + let mut data_buffer: [u8; 0x100] = [0; 0x100]; + let mut aligned_data_buffer: [u8; 0x100] = [0; 0x100]; + // structs + let mut btfw_cb = CybtFwCb { + p_next_line_start: firmware, + }; + let mut hfd = HexFileData { + addr_mode: BTFW_ADDR_MODE_EXTENDED, + hi_addr: 0, + dest_addr: 0, + p_ds: &mut data_buffer, + }; + loop { + let num_fw_bytes = read_firmware_patch_line(&mut btfw_cb, &mut hfd); + if num_fw_bytes == 0 { + break; + } + let fw_bytes = &hfd.p_ds[0..num_fw_bytes as usize]; + let mut dest_start_addr = hfd.dest_addr + CHIP.bluetooth_base_address; + let mut aligned_data_buffer_index: usize = 0; + // pad start + if !util::is_aligned(dest_start_addr, 4) { + let num_pad_bytes = dest_start_addr % 4; + let padded_dest_start_addr = util::round_down(dest_start_addr, 4); + let memory_value = bus.bp_read32(padded_dest_start_addr).await; + let memory_value_bytes = memory_value.to_le_bytes(); + // Copy the previous memory value's bytes to the start + for i in 0..num_pad_bytes as usize { + aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i]; + aligned_data_buffer_index += 1; + } + // Copy the firmware bytes after the padding bytes + for i in 0..num_fw_bytes as usize { + aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i]; + aligned_data_buffer_index += 1; + } + dest_start_addr = padded_dest_start_addr; + } else { + // Directly copy fw_bytes into aligned_data_buffer if no start padding is required + for i in 0..num_fw_bytes as usize { + aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i]; + aligned_data_buffer_index += 1; + } + } + // pad end + let mut dest_end_addr = dest_start_addr + aligned_data_buffer_index as u32; + if !util::is_aligned(dest_end_addr, 4) { + let offset = dest_end_addr % 4; + let num_pad_bytes_end = 4 - offset; + let padded_dest_end_addr = util::round_down(dest_end_addr, 4); + let memory_value = bus.bp_read32(padded_dest_end_addr).await; + let memory_value_bytes = memory_value.to_le_bytes(); + // Append the necessary memory bytes to pad the end of aligned_data_buffer + for i in offset..4 { + aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i as usize]; + aligned_data_buffer_index += 1; + } + dest_end_addr += num_pad_bytes_end; + } else { + // pad end alignment not needed + } + let buffer_to_write = &aligned_data_buffer[0..aligned_data_buffer_index as usize]; + assert!(dest_start_addr % 4 == 0); + assert!(dest_end_addr % 4 == 0); + assert!(aligned_data_buffer_index % 4 == 0); + bus.bp_write(dest_start_addr, buffer_to_write).await; + } + } + + pub(crate) async fn wait_bt_ready(&mut self, bus: &mut Bus) { + trace!("wait_bt_ready"); + let mut success = false; + for _ in 0..300 { + let val = bus.bp_read32(BT_CTRL_REG_ADDR).await; + trace!("BT_CTRL_REG_ADDR = {:08x}", val); + if val & BTSDIO_REG_FW_RDY_BITMASK != 0 { + success = true; + break; + } + Timer::after(Duration::from_millis(1)).await; + } + assert!(success == true); + } + + pub(crate) async fn wait_bt_awake(&mut self, bus: &mut Bus) { + trace!("wait_bt_awake"); + let mut success = false; + for _ in 0..300 { + let val = bus.bp_read32(BT_CTRL_REG_ADDR).await; + trace!("BT_CTRL_REG_ADDR = {:08x}", val); + if val & BTSDIO_REG_BT_AWAKE_BITMASK != 0 { + success = true; + break; + } + Timer::after(Duration::from_millis(1)).await; + } + assert!(success == true); + } + + pub(crate) async fn bt_set_host_ready(&mut self, bus: &mut Bus) { + trace!("bt_set_host_ready"); + let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await; + // TODO: do we need to swap endianness on this read? + let new_val = old_val | BTSDIO_REG_SW_RDY_BITMASK; + bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await; + } + + // TODO: use this + #[allow(dead_code)] + pub(crate) async fn bt_set_awake(&mut self, bus: &mut Bus, awake: bool) { + trace!("bt_set_awake"); + let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await; + // TODO: do we need to swap endianness on this read? + let new_val = if awake { + old_val | BTSDIO_REG_WAKE_BT_BITMASK + } else { + old_val & !BTSDIO_REG_WAKE_BT_BITMASK + }; + bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await; + } + + pub(crate) async fn bt_toggle_intr(&mut self, bus: &mut Bus) { + trace!("bt_toggle_intr"); + let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await; + // TODO: do we need to swap endianness on this read? + let new_val = old_val ^ BTSDIO_REG_DATA_VALID_BITMASK; + bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await; + } + + // TODO: use this + #[allow(dead_code)] + pub(crate) async fn bt_set_intr(&mut self, bus: &mut Bus) { + trace!("bt_set_intr"); + let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await; + let new_val = old_val | BTSDIO_REG_DATA_VALID_BITMASK; + bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await; + } + + pub(crate) async fn init_bt_buffers(&mut self, bus: &mut Bus) { + trace!("init_bt_buffers"); + self.addr = bus.bp_read32(WLAN_RAM_BASE_REG_ADDR).await; + assert!(self.addr != 0); + trace!("wlan_ram_base_addr = {:08x}", self.addr); + bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, 0).await; + bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT, 0).await; + bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_IN, 0).await; + bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, 0).await; + } + + async fn bt_bus_request(&mut self, bus: &mut Bus) { + // TODO: CYW43_THREAD_ENTER mutex? + self.bt_set_awake(bus, true).await; + self.wait_bt_awake(bus).await; + } + + pub(crate) async fn hci_write(&mut self, bus: &mut Bus) { + self.bt_bus_request(bus).await; + + // NOTE(unwrap): we only call this when we do have a packet in the queue. + let buf = self.tx_chan.try_receive().unwrap(); + debug!("HCI tx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len])); + + let len = buf.len as u32 - 1; // len doesn't include hci type byte + let rounded_len = round_up(len, 4); + let total_len = 4 + rounded_len; + + let read_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT).await; + let available = read_pointer.wrapping_sub(self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE; + if available < total_len { + warn!( + "bluetooth tx queue full, retrying. len {} available {}", + total_len, available + ); + yield_now().await; + return; + } + + // Build header + let mut header = [0u8; 4]; + header[0] = len as u8; + header[1] = (len >> 8) as u8; + header[2] = (len >> 16) as u8; + header[3] = buf.buf[0]; // HCI type byte + + // Write header + let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer; + bus.bp_write(addr, &header).await; + self.h2b_write_pointer = (self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE; + + // Write payload. + let payload = &buf.buf[1..][..rounded_len as usize]; + if self.h2b_write_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize { + // wraparound + let n = BTSDIO_FWBUF_SIZE - self.h2b_write_pointer; + let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer; + bus.bp_write(addr, &payload[..n as usize]).await; + let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF; + bus.bp_write(addr, &payload[n as usize..]).await; + } else { + // no wraparound + let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer; + bus.bp_write(addr, payload).await; + } + self.h2b_write_pointer = (self.h2b_write_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE; + + // Update pointer. + bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, self.h2b_write_pointer) + .await; + + self.bt_toggle_intr(bus).await; + + self.tx_chan.receive_done(); + } + + async fn bt_has_work(&mut self, bus: &mut Bus) -> bool { + let int_status = bus.bp_read32(CHIP.sdiod_core_base_address + SDIO_INT_STATUS).await; + if int_status & I_HMB_FC_CHANGE != 0 { + bus.bp_write32( + CHIP.sdiod_core_base_address + SDIO_INT_STATUS, + int_status & I_HMB_FC_CHANGE, + ) + .await; + return true; + } + return false; + } + + pub(crate) async fn handle_irq(&mut self, bus: &mut Bus) { + if self.bt_has_work(bus).await { + loop { + // Check if we have data. + let write_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_BT2HOST_IN).await; + let available = write_pointer.wrapping_sub(self.b2h_read_pointer) % BTSDIO_FWBUF_SIZE; + if available == 0 { + break; + } + + // read header + let mut header = [0u8; 4]; + let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer; + bus.bp_read(addr, &mut header).await; + + // calc length + let len = header[0] as u32 | ((header[1]) as u32) << 8 | ((header[2]) as u32) << 16; + let rounded_len = round_up(len, 4); + if available < 4 + rounded_len { + warn!("ringbuf data not enough for a full packet?"); + break; + } + self.b2h_read_pointer = (self.b2h_read_pointer + 4) % BTSDIO_FWBUF_SIZE; + + // Obtain a buf from the channel. + let buf = self.rx_chan.send().await; + + buf.buf[0] = header[3]; // hci packet type + let payload = &mut buf.buf[1..][..rounded_len as usize]; + if self.b2h_read_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize { + // wraparound + let n = BTSDIO_FWBUF_SIZE - self.b2h_read_pointer; + let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer; + bus.bp_read(addr, &mut payload[..n as usize]).await; + let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF; + bus.bp_read(addr, &mut payload[n as usize..]).await; + } else { + // no wraparound + let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer; + bus.bp_read(addr, payload).await; + } + self.b2h_read_pointer = (self.b2h_read_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE; + bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, self.b2h_read_pointer) + .await; + + buf.len = 1 + len as usize; + debug!("HCI rx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len])); + + self.rx_chan.send_done(); + + self.bt_toggle_intr(bus).await; + } + } + } +} + +impl<'d> embedded_io_async::ErrorType for BtDriver<'d> { + type Error = core::convert::Infallible; +} + +impl<'d> bt_hci::transport::Transport for BtDriver<'d> { + fn read<'a>(&self, rx: &'a mut [u8]) -> impl Future, Self::Error>> { + async { + let ch = &mut *self.rx.borrow_mut(); + let buf = ch.receive().await; + let n = buf.len; + assert!(n < rx.len()); + rx[..n].copy_from_slice(&buf.buf[..n]); + ch.receive_done(); + + let kind = PacketKind::from_hci_bytes_complete(&rx[..1]).unwrap(); + let (res, _) = ControllerToHostPacket::from_hci_bytes_with_kind(kind, &rx[1..n]).unwrap(); + Ok(res) + } + } + + /// Write a complete HCI packet from the tx buffer + fn write(&self, val: &T) -> impl Future> { + async { + let ch = &mut *self.tx.borrow_mut(); + let buf = ch.send().await; + let buf_len = buf.buf.len(); + let mut slice = &mut buf.buf[..]; + WithIndicator::new(val).write_hci(&mut slice).unwrap(); + buf.len = buf_len - slice.len(); + ch.send_done(); + Ok(()) + } + } +} diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs index 014109038..8a53484d5 100644 --- a/cyw43/src/bus.rs +++ b/cyw43/src/bus.rs @@ -4,7 +4,7 @@ use embedded_hal_1::digital::OutputPin; use futures::FutureExt; use crate::consts::*; -use crate::slice8_mut; +use crate::util::slice8_mut; /// Custom Spi Trait that _only_ supports the bus operation of the cyw43 /// Implementors are expected to hold the CS pin low during an operation. @@ -48,44 +48,91 @@ where } } - pub async fn init(&mut self) { + pub async fn init(&mut self, bluetooth_enabled: bool) { // Reset + trace!("WL_REG off/on"); self.pwr.set_low().unwrap(); Timer::after_millis(20).await; self.pwr.set_high().unwrap(); Timer::after_millis(250).await; + trace!("read REG_BUS_TEST_RO"); while self - .read32_swapped(REG_BUS_TEST_RO) + .read32_swapped(FUNC_BUS, REG_BUS_TEST_RO) .inspect(|v| trace!("{:#x}", v)) .await != FEEDBEAD {} - self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; - let val = self.read32_swapped(REG_BUS_TEST_RW).await; + trace!("write REG_BUS_TEST_RW"); + self.write32_swapped(FUNC_BUS, REG_BUS_TEST_RW, TEST_PATTERN).await; + let val = self.read32_swapped(FUNC_BUS, REG_BUS_TEST_RW).await; trace!("{:#x}", val); assert_eq!(val, TEST_PATTERN); - let val = self.read32_swapped(REG_BUS_CTRL).await; + trace!("read REG_BUS_CTRL"); + let val = self.read32_swapped(FUNC_BUS, REG_BUS_CTRL).await; trace!("{:#010b}", (val & 0xff)); // 32-bit word length, little endian (which is the default endianess). + // TODO: C library is uint32_t val = WORD_LENGTH_32 | HIGH_SPEED_MODE| ENDIAN_BIG | INTERRUPT_POLARITY_HIGH | WAKE_UP | 0x4 << (8 * SPI_RESPONSE_DELAY) | INTR_WITH_STATUS << (8 * SPI_STATUS_ENABLE); + trace!("write REG_BUS_CTRL"); self.write32_swapped( + FUNC_BUS, REG_BUS_CTRL, - WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP | STATUS_ENABLE | INTERRUPT_WITH_STATUS, + WORD_LENGTH_32 + | HIGH_SPEED + | INTERRUPT_POLARITY_HIGH + | WAKE_UP + | 0x4 << (8 * REG_BUS_RESPONSE_DELAY) + | STATUS_ENABLE << (8 * REG_BUS_STATUS_ENABLE) + | INTR_WITH_STATUS << (8 * REG_BUS_STATUS_ENABLE), ) .await; + trace!("read REG_BUS_CTRL"); let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; trace!("{:#b}", val); + // TODO: C doesn't do this? i doubt it messes anything up + trace!("read REG_BUS_TEST_RO"); let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; trace!("{:#x}", val); assert_eq!(val, FEEDBEAD); + + // TODO: C doesn't do this? i doubt it messes anything up + trace!("read REG_BUS_TEST_RW"); let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; trace!("{:#x}", val); assert_eq!(val, TEST_PATTERN); + + trace!("write SPI_RESP_DELAY_F1 CYW43_BACKPLANE_READ_PAD_LEN_BYTES"); + self.write8(FUNC_BUS, SPI_RESP_DELAY_F1, WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE) + .await; + + // TODO: Make sure error interrupt bits are clear? + // cyw43_write_reg_u8(self, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, DATA_UNAVAILABLE | COMMAND_ERROR | DATA_ERROR | F1_OVERFLOW) != 0) + trace!("Make sure error interrupt bits are clear"); + self.write8( + FUNC_BUS, + REG_BUS_INTERRUPT, + (IRQ_DATA_UNAVAILABLE | IRQ_COMMAND_ERROR | IRQ_DATA_ERROR | IRQ_F1_OVERFLOW) as u8, + ) + .await; + + // Enable a selection of interrupts + // TODO: why not all of these F2_F3_FIFO_RD_UNDERFLOW | F2_F3_FIFO_WR_OVERFLOW | COMMAND_ERROR | DATA_ERROR | F2_PACKET_AVAILABLE | F1_OVERFLOW | F1_INTR + trace!("enable a selection of interrupts"); + let mut val = IRQ_F2_F3_FIFO_RD_UNDERFLOW + | IRQ_F2_F3_FIFO_WR_OVERFLOW + | IRQ_COMMAND_ERROR + | IRQ_DATA_ERROR + | IRQ_F2_PACKET_AVAILABLE + | IRQ_F1_OVERFLOW; + if bluetooth_enabled { + val = val | IRQ_F1_INTR; + } + self.write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, val).await; } pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { @@ -107,6 +154,8 @@ where #[allow(unused)] pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) { + trace!("bp_read addr = {:08x}", addr); + // It seems the HW force-aligns the addr // to 2 if data.len() >= 2 // to 4 if data.len() >= 4 @@ -140,6 +189,8 @@ where } pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) { + trace!("bp_write addr = {:08x}", addr); + // It seems the HW force-aligns the addr // to 2 if data.len() >= 2 // to 4 if data.len() >= 4 @@ -196,23 +247,32 @@ where } async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 { + trace!("backplane_readn addr = {:08x} len = {}", addr, len); + self.backplane_set_window(addr).await; let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; if len == 4 { - bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG + bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG; } - self.readn(FUNC_BACKPLANE, bus_addr, len).await + + let val = self.readn(FUNC_BACKPLANE, bus_addr, len).await; + + trace!("backplane_readn addr = {:08x} len = {} val = {:08x}", addr, len, val); + + return val; } async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) { + trace!("backplane_writen addr = {:08x} len = {} val = {:08x}", addr, len, val); + self.backplane_set_window(addr).await; let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; if len == 4 { - bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG + bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG; } - self.writen(FUNC_BACKPLANE, bus_addr, val, len).await + self.writen(FUNC_BACKPLANE, bus_addr, val, len).await; } async fn backplane_set_window(&mut self, addr: u32) { @@ -293,8 +353,8 @@ where self.status = self.spi.cmd_write(&[cmd, val]).await; } - async fn read32_swapped(&mut self, addr: u32) -> u32 { - let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); + async fn read32_swapped(&mut self, func: u32, addr: u32) -> u32 { + let cmd = cmd_word(READ, INC_ADDR, func, addr, 4); let cmd = swap16(cmd); let mut buf = [0; 1]; @@ -303,8 +363,8 @@ where swap16(buf[0]) } - async fn write32_swapped(&mut self, addr: u32, val: u32) { - let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); + async fn write32_swapped(&mut self, func: u32, addr: u32, val: u32) { + let cmd = cmd_word(WRITE, INC_ADDR, func, addr, 4); let buf = [swap16(cmd), swap16(val)]; self.status = self.spi.cmd_write(&buf).await; diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs index 4e2836f3b..b6e22e61d 100644 --- a/cyw43/src/consts.rs +++ b/cyw43/src/consts.rs @@ -5,19 +5,33 @@ pub(crate) const FUNC_BACKPLANE: u32 = 1; pub(crate) const FUNC_WLAN: u32 = 2; pub(crate) const FUNC_BT: u32 = 3; +// Register addresses pub(crate) const REG_BUS_CTRL: u32 = 0x0; +pub(crate) const REG_BUS_RESPONSE_DELAY: u32 = 0x1; +pub(crate) const REG_BUS_STATUS_ENABLE: u32 = 0x2; pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask pub(crate) const REG_BUS_STATUS: u32 = 0x8; pub(crate) const REG_BUS_TEST_RO: u32 = 0x14; pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; + +// SPI_BUS_CONTROL Bits pub(crate) const WORD_LENGTH_32: u32 = 0x1; +pub(crate) const ENDIAN_BIG: u32 = 0x2; +pub(crate) const CLOCK_PHASE: u32 = 0x4; +pub(crate) const CLOCK_POLARITY: u32 = 0x8; pub(crate) const HIGH_SPEED: u32 = 0x10; -pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5; -pub(crate) const WAKE_UP: u32 = 1 << 7; -pub(crate) const STATUS_ENABLE: u32 = 1 << 16; -pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17; +pub(crate) const INTERRUPT_POLARITY_HIGH: u32 = 0x20; +pub(crate) const WAKE_UP: u32 = 0x80; + +// SPI_STATUS_ENABLE bits +pub(crate) const STATUS_ENABLE: u32 = 0x01; +pub(crate) const INTR_WITH_STATUS: u32 = 0x02; +pub(crate) const RESP_DELAY_ALL: u32 = 0x04; +pub(crate) const DWORD_PKT_LEN_EN: u32 = 0x08; +pub(crate) const CMD_ERR_CHK_EN: u32 = 0x20; +pub(crate) const DATA_ERR_CHK_EN: u32 = 0x40; // SPI_STATUS_REGISTER bits pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; @@ -51,6 +65,13 @@ pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C; pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E; pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F; +pub(crate) const I_HMB_SW_MASK: u32 = 0x000000f0; +pub(crate) const I_HMB_FC_CHANGE: u32 = 1 << 5; +pub(crate) const SDIO_INT_STATUS: u32 = 0x20; +pub(crate) const SDIO_INT_HOST_MASK: u32 = 0x24; + +pub(crate) const SPI_F2_WATERMARK: u8 = 0x20; + pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000; pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF; pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000; @@ -119,6 +140,44 @@ pub(crate) const WPA2_SECURITY: u32 = 0x00400000; pub(crate) const MIN_PSK_LEN: usize = 8; pub(crate) const MAX_PSK_LEN: usize = 64; +// Bluetooth firmware extraction constants. +pub(crate) const BTFW_ADDR_MODE_UNKNOWN: i32 = 0; +pub(crate) const BTFW_ADDR_MODE_EXTENDED: i32 = 1; +pub(crate) const BTFW_ADDR_MODE_SEGMENT: i32 = 2; +pub(crate) const BTFW_ADDR_MODE_LINEAR32: i32 = 3; + +pub(crate) const BTFW_HEX_LINE_TYPE_DATA: u8 = 0; +pub(crate) const BTFW_HEX_LINE_TYPE_END_OF_DATA: u8 = 1; +pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS: u8 = 2; +pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS: u8 = 4; +pub(crate) const BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS: u8 = 5; + +// Bluetooth constants. +pub(crate) const SPI_RESP_DELAY_F1: u32 = 0x001d; +pub(crate) const WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE: u8 = 4; + +pub(crate) const BT2WLAN_PWRUP_WAKE: u32 = 3; +pub(crate) const BT2WLAN_PWRUP_ADDR: u32 = 0x640894; + +pub(crate) const BT_CTRL_REG_ADDR: u32 = 0x18000c7c; +pub(crate) const HOST_CTRL_REG_ADDR: u32 = 0x18000d6c; +pub(crate) const WLAN_RAM_BASE_REG_ADDR: u32 = 0x18000d68; + +pub(crate) const BTSDIO_REG_DATA_VALID_BITMASK: u32 = 1 << 1; +pub(crate) const BTSDIO_REG_BT_AWAKE_BITMASK: u32 = 1 << 8; +pub(crate) const BTSDIO_REG_WAKE_BT_BITMASK: u32 = 1 << 17; +pub(crate) const BTSDIO_REG_SW_RDY_BITMASK: u32 = 1 << 24; +pub(crate) const BTSDIO_REG_FW_RDY_BITMASK: u32 = 1 << 24; + +pub(crate) const BTSDIO_FWBUF_SIZE: u32 = 0x1000; +pub(crate) const BTSDIO_OFFSET_HOST_WRITE_BUF: u32 = 0; +pub(crate) const BTSDIO_OFFSET_HOST_READ_BUF: u32 = BTSDIO_FWBUF_SIZE; + +pub(crate) const BTSDIO_OFFSET_HOST2BT_IN: u32 = 0x00002000; +pub(crate) const BTSDIO_OFFSET_HOST2BT_OUT: u32 = 0x00002004; +pub(crate) const BTSDIO_OFFSET_BT2HOST_IN: u32 = 0x00002008; +pub(crate) const BTSDIO_OFFSET_BT2HOST_OUT: u32 = 0x0000200C; + // Security type (authentication and encryption types are combined using bit mask) #[allow(non_camel_case_types)] #[derive(Copy, Clone, PartialEq)] diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index f0f179e2e..22c52bd96 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -83,8 +83,7 @@ impl<'a> Control<'a> { } } - /// Initialize WiFi controller. - pub async fn init(&mut self, clm: &[u8]) { + async fn load_clm(&mut self, clm: &[u8]) { const CHUNK_SIZE: usize = 1024; debug!("Downloading CLM..."); @@ -116,6 +115,11 @@ impl<'a> Control<'a> { // check clmload ok assert_eq!(self.get_iovar_u32("clmload_status").await, 0); + } + + /// Initialize WiFi controller. + pub async fn init(&mut self, clm: &[u8]) { + self.load_clm(&clm).await; debug!("Configuring misc stuff..."); @@ -186,7 +190,7 @@ impl<'a> Control<'a> { self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr)); - debug!("INIT DONE"); + debug!("cyw43 control init done"); } /// Set the WiFi interface up. diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 7c8f35da7..efeb3f313 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -8,18 +8,18 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +#[cfg(feature = "bluetooth")] +mod bluetooth; mod bus; mod consts; +mod control; mod countries; mod events; mod ioctl; -mod structs; - -mod control; mod nvram; mod runner; - -use core::slice; +mod structs; +mod util; use embassy_net_driver_channel as ch; use embedded_hal_1::digital::OutputPin; @@ -56,6 +56,7 @@ impl Core { struct Chip { arm_core_base_address: u32, socsram_base_address: u32, + bluetooth_base_address: u32, socsram_wrapper_base_address: u32, sdiod_core_base_address: u32, pmu_base_address: u32, @@ -83,6 +84,7 @@ const WRAPPER_REGISTER_OFFSET: u32 = 0x100000; const CHIP: Chip = Chip { arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET, socsram_base_address: 0x18004000, + bluetooth_base_address: 0x19000000, socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET, sdiod_core_base_address: 0x18002000, pmu_base_address: 0x18000000, @@ -107,6 +109,12 @@ const CHIP: Chip = Chip { /// Driver state. pub struct State { ioctl_state: IoctlState, + net: NetState, + #[cfg(feature = "bluetooth")] + bt: bluetooth::BtState, +} + +struct NetState { ch: ch::State, events: Events, } @@ -116,8 +124,12 @@ impl State { pub fn new() -> Self { Self { ioctl_state: IoctlState::new(), - ch: ch::State::new(), - events: Events::new(), + net: NetState { + ch: ch::State::new(), + events: Events::new(), + }, + #[cfg(feature = "bluetooth")] + bt: bluetooth::BtState::new(), } } } @@ -225,21 +237,60 @@ where PWR: OutputPin, SPI: SpiBusCyw43, { - let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); + let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); let state_ch = ch_runner.state_runner(); - let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events); + let mut runner = Runner::new( + ch_runner, + Bus::new(pwr, spi), + &state.ioctl_state, + &state.net.events, + #[cfg(feature = "bluetooth")] + None, + ); - runner.init(firmware).await; + runner.init(firmware, None).await; + let control = Control::new(state_ch, &state.net.events, &state.ioctl_state); - ( - device, - Control::new(state_ch, &state.events, &state.ioctl_state), - runner, - ) + (device, control, runner) } -fn slice8_mut(x: &mut [u32]) -> &mut [u8] { - let len = x.len() * 4; - unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } +/// Create a new instance of the CYW43 driver. +/// +/// Returns a handle to the network device, control handle and a runner for driving the low level +/// stack. +#[cfg(feature = "bluetooth")] +pub async fn new_with_bluetooth<'a, PWR, SPI>( + state: &'a mut State, + pwr: PWR, + spi: SPI, + wifi_firmware: &[u8], + bluetooth_firmware: &[u8], +) -> ( + NetDriver<'a>, + bluetooth::BtDriver<'a>, + Control<'a>, + Runner<'a, PWR, SPI>, +) +where + PWR: OutputPin, + SPI: SpiBusCyw43, +{ + let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); + let state_ch = ch_runner.state_runner(); + + let (bt_runner, bt_driver) = bluetooth::new(&mut state.bt); + let mut runner = Runner::new( + ch_runner, + Bus::new(pwr, spi), + &state.ioctl_state, + &state.net.events, + #[cfg(feature = "bluetooth")] + Some(bt_runner), + ); + + runner.init(wifi_firmware, Some(bluetooth_firmware)).await; + let control = Control::new(state_ch, &state.net.events, &state.ioctl_state); + + (device, bt_driver, control, runner) } diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index e90316302..6522d40fa 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -1,4 +1,4 @@ -use embassy_futures::select::{select3, Either3}; +use embassy_futures::select::{select4, Either4}; use embassy_net_driver_channel as ch; use embassy_time::{block_for, Duration, Timer}; use embedded_hal_1::digital::OutputPin; @@ -11,7 +11,8 @@ use crate::fmt::Bytes; use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; use crate::nvram::NVRAM; use crate::structs::*; -use crate::{events, slice8_mut, Core, CHIP, MTU}; +use crate::util::slice8_mut; +use crate::{events, Core, CHIP, MTU}; #[cfg(feature = "firmware-logs")] struct LogState { @@ -36,7 +37,7 @@ impl Default for LogState { /// Driver communicating with the WiFi chip. pub struct Runner<'a, PWR, SPI> { ch: ch::Runner<'a, MTU>, - bus: Bus, + pub(crate) bus: Bus, ioctl_state: &'a IoctlState, ioctl_id: u16, @@ -47,6 +48,9 @@ pub struct Runner<'a, PWR, SPI> { #[cfg(feature = "firmware-logs")] log: LogState, + + #[cfg(feature = "bluetooth")] + pub(crate) bt: Option>, } impl<'a, PWR, SPI> Runner<'a, PWR, SPI> @@ -59,6 +63,7 @@ where bus: Bus, ioctl_state: &'a IoctlState, events: &'a Events, + #[cfg(feature = "bluetooth")] bt: Option>, ) -> Self { Self { ch, @@ -70,33 +75,52 @@ where events, #[cfg(feature = "firmware-logs")] log: LogState::default(), + #[cfg(feature = "bluetooth")] + bt, } } - pub(crate) async fn init(&mut self, firmware: &[u8]) { - self.bus.init().await; + pub(crate) async fn init(&mut self, wifi_fw: &[u8], bt_fw: Option<&[u8]>) { + self.bus.init(bt_fw.is_some()).await; // Init ALP (Active Low Power) clock + debug!("init alp"); self.bus .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) .await; + + debug!("set f2 watermark"); + self.bus + .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 0x10) + .await; + let watermark = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK).await; + debug!("watermark = {:02x}", watermark); + assert!(watermark == 0x10); + debug!("waiting for clock..."); while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} debug!("clock ok"); + // clear request for ALP + debug!("clear request for ALP"); + self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0).await; + let chip_id = self.bus.bp_read16(0x1800_0000).await; debug!("chip ID: {}", chip_id); // Upload firmware. self.core_disable(Core::WLAN).await; + self.core_disable(Core::SOCSRAM).await; // TODO: is this needed if we reset right after? self.core_reset(Core::SOCSRAM).await; + + // this is 4343x specific stuff: Disable remap for SRAM_3 self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; let ram_addr = CHIP.atcm_ram_base_address; debug!("loading fw"); - self.bus.bp_write(ram_addr, firmware).await; + self.bus.bp_write(ram_addr, wifi_fw).await; debug!("loading nvram"); // Round up to 4 bytes. @@ -116,10 +140,23 @@ where self.core_reset(Core::WLAN).await; assert!(self.core_is_up(Core::WLAN).await); + // wait until HT clock is available; takes about 29ms + debug!("wait for HT clock"); while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} // "Set up the interrupt mask and enable interrupts" - // self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; + debug!("setup interrupt mask"); + self.bus + .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_SW_MASK) + .await; + + // Set up the interrupt mask and enable interrupts + if bt_fw.is_some() { + debug!("bluetooth setup interrupt mask"); + self.bus + .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_FC_CHANGE) + .await; + } self.bus .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) @@ -128,11 +165,11 @@ where // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." // Sounds scary... self.bus - .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32) + .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, SPI_F2_WATERMARK) .await; - // wait for wifi startup - debug!("waiting for wifi init..."); + // wait for F2 to be ready + debug!("waiting for F2 to be ready..."); while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} // Some random configs related to sleep. @@ -153,19 +190,27 @@ where */ // clear pulls + debug!("clear pad pulls"); self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; // start HT clock - //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await; - //debug!("waiting for HT clock..."); - //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} - //debug!("clock ok"); + self.bus + .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10) + .await; // SBSDIO_HT_AVAIL_REQ + debug!("waiting for HT clock..."); + while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} + debug!("clock ok"); #[cfg(feature = "firmware-logs")] self.log_init().await; - debug!("wifi init done"); + #[cfg(feature = "bluetooth")] + if let Some(bt_fw) = bt_fw { + self.bt.as_mut().unwrap().init_bluetooth(&mut self.bus, bt_fw).await; + } + + debug!("cyw43 runner init done"); } #[cfg(feature = "firmware-logs")] @@ -222,7 +267,7 @@ where } } - /// Run the + /// Run the CYW43 event handling loop. pub async fn run(mut self) -> ! { let mut buf = [0; 512]; loop { @@ -231,11 +276,27 @@ where if self.has_credit() { let ioctl = self.ioctl_state.wait_pending(); - let tx = self.ch.tx_buf(); + let wifi_tx = self.ch.tx_buf(); + #[cfg(feature = "bluetooth")] + let bt_tx = async { + match &mut self.bt { + Some(bt) => bt.tx_chan.receive().await, + None => core::future::pending().await, + } + }; + #[cfg(not(feature = "bluetooth"))] + let bt_tx = core::future::pending::<()>(); + + // interrupts aren't working yet for bluetooth. Do busy-polling instead. + // Note for this to work `ev` has to go last in the `select()`. It prefers + // first futures if they're ready, so other select branches don't get starved.` + #[cfg(feature = "bluetooth")] + let ev = core::future::ready(()); + #[cfg(not(feature = "bluetooth"))] let ev = self.bus.wait_for_event(); - match select3(ioctl, tx, ev).await { - Either3::First(PendingIoctl { + match select4(ioctl, wifi_tx, bt_tx, ev).await { + Either4::First(PendingIoctl { buf: iobuf, kind, cmd, @@ -244,7 +305,7 @@ where self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await; self.check_status(&mut buf).await; } - Either3::Second(packet) => { + Either4::Second(packet) => { trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); let buf8 = slice8_mut(&mut buf); @@ -298,7 +359,11 @@ where self.ch.tx_done(); self.check_status(&mut buf).await; } - Either3::Third(()) => { + Either4::Third(_) => { + #[cfg(feature = "bluetooth")] + self.bt.as_mut().unwrap().hci_write(&mut self.bus).await; + } + Either4::Fourth(()) => { self.handle_irq(&mut buf).await; } } @@ -314,17 +379,24 @@ where async fn handle_irq(&mut self, buf: &mut [u32; 512]) { // Receive stuff let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; - trace!("irq{}", FormatInterrupt(irq)); + if irq != 0 { + trace!("irq{}", FormatInterrupt(irq)); + } if irq & IRQ_F2_PACKET_AVAILABLE != 0 { self.check_status(buf).await; } if irq & IRQ_DATA_UNAVAILABLE != 0 { - // TODO what should we do here? - warn!("IRQ DATA_UNAVAILABLE, clearing..."); + // this seems to be ignorable with no ill effects. + trace!("IRQ DATA_UNAVAILABLE, clearing..."); self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; } + + #[cfg(feature = "bluetooth")] + if let Some(bt) = &mut self.bt { + bt.handle_irq(&mut self.bus).await; + } } /// Handle F2 events while status register is set diff --git a/cyw43/src/util.rs b/cyw43/src/util.rs new file mode 100644 index 000000000..a4adbd4ed --- /dev/null +++ b/cyw43/src/util.rs @@ -0,0 +1,20 @@ +#![allow(unused)] + +use core::slice; + +pub(crate) fn slice8_mut(x: &mut [u32]) -> &mut [u8] { + let len = x.len() * 4; + unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } +} + +pub(crate) fn is_aligned(a: u32, x: u32) -> bool { + (a & (x - 1)) == 0 +} + +pub(crate) fn round_down(x: u32, a: u32) -> u32 { + x & !(a - 1) +} + +pub(crate) fn round_up(x: u32, a: u32) -> u32 { + ((x + a - 1) / a) * a +} diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 4945f4bd2..2884ca85a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -16,8 +16,8 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } -cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } +cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } +cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" @@ -59,9 +59,22 @@ pio = "0.2.1" rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" +bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } +trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } + [profile.release] debug = 2 [profile.dev] lto = true opt-level = "z" + +[patch.crates-io] +trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } +bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } +embassy-executor = { path = "../../embassy-executor" } +embassy-sync = { path = "../../embassy-sync" } +embassy-futures = { path = "../../embassy-futures" } +embassy-time = { path = "../../embassy-time" } +embassy-time-driver = { path = "../../embassy-time-driver" } +embassy-embedded-hal = { path = "../../embassy-embedded-hal" } diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs new file mode 100644 index 000000000..901521b60 --- /dev/null +++ b/examples/rp/src/bin/bluetooth.rs @@ -0,0 +1,148 @@ +//! This example test the RP Pico W on board LED. +//! +//! It does not work with the RP Pico board. See blinky.rs. + +#![no_std] +#![no_main] + +use bt_hci::controller::ExternalController; +use cyw43_pio::PioSpi; +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::join::join3; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_time::{Duration, Timer}; +use static_cell::StaticCell; +use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE}; +use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid}; +use trouble_host::gatt::GattEvent; +use trouble_host::{Address, BleHost, BleHostResources, PacketQos}; +use {defmt_rtt as _, embassy_time as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[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 p = embassy_rp::init(Default::default()); + let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); + let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); + let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin"); + + // To make flashing faster for development, you may want to flash the firmwares independently + // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: + // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; + //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; + + let pwr = Output::new(p.PIN_23, Level::Low); + let cs = Output::new(p.PIN_25, Level::High); + let mut pio = Pio::new(p.PIO0, Irqs); + let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); + let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await; + unwrap!(spawner.spawn(cyw43_task(runner))); + control.init(clm).await; + + let controller: ExternalController<_, 10> = ExternalController::new(bt_device); + static HOST_RESOURCES: StaticCell> = StaticCell::new(); + let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None)); + + let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources); + + ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff])); + let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new(); + + // Generic Access Service (mandatory) + let id = b"Pico W Bluetooth"; + let appearance = [0x80, 0x07]; + let mut bat_level = [0; 1]; + let handle = { + let mut svc = table.add_service(Service::new(0x1800)); + let _ = svc.add_characteristic_ro(0x2a00, id); + let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]); + svc.build(); + + // Generic attribute service (mandatory) + table.add_service(Service::new(0x1801)); + + // Battery service + let mut svc = table.add_service(Service::new(0x180f)); + + svc.add_characteristic( + 0x2a19, + &[CharacteristicProp::Read, CharacteristicProp::Notify], + &mut bat_level, + ) + .build() + }; + + let mut adv_data = [0; 31]; + AdStructure::encode_slice( + &[ + AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), + AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]), + AdStructure::CompleteLocalName(b"Pico W Bluetooth"), + ], + &mut adv_data[..], + ) + .unwrap(); + + let server = ble.gatt_server(&table); + + info!("Starting advertising and GATT service"); + let _ = join3( + ble.run(), + async { + loop { + match server.next().await { + Ok(GattEvent::Write { handle, connection: _ }) => { + let _ = table.get(handle, |value| { + info!("Write event. Value written: {:?}", value); + }); + } + Ok(GattEvent::Read { .. }) => { + info!("Read event"); + } + Err(e) => { + error!("Error processing GATT events: {:?}", e); + } + } + } + }, + async { + let mut advertiser = ble + .advertise( + &Default::default(), + Advertisement::ConnectableScannableUndirected { + adv_data: &adv_data[..], + scan_data: &[], + }, + ) + .await + .unwrap(); + let conn = advertiser.accept().await.unwrap(); + // Keep connection alive + let mut tick: u8 = 0; + loop { + Timer::after(Duration::from_secs(10)).await; + tick += 1; + server.notify(handle, &conn, &[tick]).await.unwrap(); + } + }, + ) + .await; +} diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 4fc2690e3..b5fbd8e36 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -28,7 +28,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { +async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } @@ -62,7 +62,7 @@ async fn main(spawner: Spawner) { static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; - unwrap!(spawner.spawn(wifi_task(runner))); + unwrap!(spawner.spawn(cyw43_task(runner))); control.init(clm).await; control diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 471349639..04a61bbd5 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { +async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } @@ -46,7 +46,7 @@ async fn main(spawner: Spawner) { static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; - unwrap!(spawner.spawn(wifi_task(runner))); + unwrap!(spawner.spawn(cyw43_task(runner))); control.init(clm).await; control diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 5f4c848a2..ab3529112 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -23,7 +23,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { +async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } @@ -56,7 +56,7 @@ async fn main(spawner: Spawner) { static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; - unwrap!(spawner.spawn(wifi_task(runner))); + unwrap!(spawner.spawn(cyw43_task(runner))); control.init(clm).await; control diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 5575df677..87487cbe8 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -27,11 +27,11 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -const WIFI_NETWORK: &str = "EmbassyTest"; -const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; +const WIFI_NETWORK: &str = "LadronDeWifi"; +const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8"; #[embassy_executor::task] -async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { +async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } @@ -65,7 +65,7 @@ async fn main(spawner: Spawner) { static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; - unwrap!(spawner.spawn(wifi_task(runner))); + unwrap!(spawner.spawn(cyw43_task(runner))); control.init(clm).await; control diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 70b6f0949..e32be6e45 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -34,7 +34,7 @@ const WIFI_NETWORK: &str = "ssid"; // change to your network SSID const WIFI_PASSWORD: &str = "pwd"; // change to your network password #[embassy_executor::task] -async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { +async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { runner.run().await } @@ -67,7 +67,7 @@ async fn main(spawner: Spawner) { static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; - unwrap!(spawner.spawn(wifi_task(runner))); + unwrap!(spawner.spawn(cyw43_task(runner))); control.init(clm).await; control From a7258927209827e27f4190af57020c2a8017dbaa Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 5 Aug 2024 15:37:03 -0400 Subject: [PATCH 064/210] Convert uart half_duplex to use open-drain pull-up --- embassy-stm32/src/usart/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 7ed3793a1..3283fb6b7 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1029,8 +1029,9 @@ impl<'d> Uart<'d, Async> { /// (when it is available for your chip). There is no functional difference between these methods, as both /// allow bidirectional communication. /// - /// The pin is always released when no data is transmitted. Thus, it acts as a standard - /// I/O in idle or in reception. + /// The TX pin is always released when no data is transmitted. Thus, it acts as a standard + /// I/O in idle or in reception. It means that the I/O must be configured so that TX is + /// configured as alternate function open-drain with an external pull-up /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict /// on the line must be managed by software (for instance by using a centralized arbiter). #[doc(alias("HDSEL"))] @@ -1051,7 +1052,7 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(tx, AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up)), None, None, None, From 21edbd3c17837f9a3f196fe1bdda4a065805d12f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 5 Aug 2024 20:58:46 +0200 Subject: [PATCH 065/210] Silence some unused warnings on nightly. --- embassy-net-esp-hosted/src/proto.rs | 2 ++ embassy-stm32-wpan/src/mac/commands.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs index 034d5bf84..089ded677 100644 --- a/embassy-net-esp-hosted/src/proto.rs +++ b/embassy-net-esp-hosted/src/proto.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use heapless::{String, Vec}; /// internal supporting structures for CtrlMsg diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs index 8f6dcbbbc..c97c609c3 100644 --- a/embassy-stm32-wpan/src/mac/commands.rs +++ b/embassy-stm32-wpan/src/mac/commands.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use core::{mem, slice}; use super::opcodes::OpcodeM4ToM0; From 446169b2c1c85ced844e1a888d7fec75047e11c1 Mon Sep 17 00:00:00 2001 From: Karun Date: Tue, 6 Aug 2024 11:52:16 -0400 Subject: [PATCH 066/210] Add gpio version dependency Add configurable output type for half-duplex --- embassy-stm32/src/usart/mod.rs | 81 ++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 3283fb6b7..0c5bbf491 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -211,6 +211,19 @@ impl Default for Config { } } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Half duplex IO mode +pub enum HalfDuplexConfig { + /// Push pull allows for faster baudrates, may require series resistor + PushPull, + /// Open drain output using external pull up resistor + OpenDrainExternal, + #[cfg(not(gpio_v1))] + /// Open drain output using internal pull up resistor + OpenDrainInternal, +} + /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1042,6 +1055,7 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1052,7 +1066,21 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up)), + new_pin!( + tx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, @@ -1080,6 +1108,7 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.half_duplex = true; @@ -1088,7 +1117,21 @@ impl<'d> Uart<'d, Async> { peri, None, None, - new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + rx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, new_dma!(tx_dma), @@ -1193,6 +1236,7 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1203,7 +1247,21 @@ impl<'d> Uart<'d, Blocking> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + tx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, @@ -1228,6 +1286,7 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.half_duplex = true; @@ -1236,7 +1295,21 @@ impl<'d> Uart<'d, Blocking> { peri, None, None, - new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + rx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, From 3f045ede48c35af298e0b8f158cbf34e8bdd0d72 Mon Sep 17 00:00:00 2001 From: Niels Becker Date: Tue, 6 Aug 2024 20:08:26 +0200 Subject: [PATCH 067/210] Rename package for embassy-stm32h755cm4-example --- examples/stm32h755cm4/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 9d2fb9060..7a42fbdaa 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "embassy-stm32h7-examples" +name = "embassy-stm32h755cm4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" From 207048ff38fef29a00e7ae9a020973c43acffa8a Mon Sep 17 00:00:00 2001 From: Niels Becker Date: Tue, 6 Aug 2024 20:10:46 +0200 Subject: [PATCH 068/210] Rename package for embassy-stm32h755cm7-example --- examples/stm32h755cm7/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index ab088fd33..4f0f69c3f 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "embassy-stm32h7-examples" +name = "embassy-stm32h755cm7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" From 59cb1531c91386cec8d7b209630b6b4d9eb7fd7c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 5 Aug 2024 21:38:30 +0200 Subject: [PATCH 069/210] examples: ensure at least 3 sockets to avoid running out (DHCP, DNS, the user's) --- embassy-net/src/lib.rs | 7 +++++-- examples/nrf52840/src/bin/ethernet_enc28j60.rs | 9 ++------- examples/nrf52840/src/bin/usb_ethernet.rs | 2 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 9 ++------- examples/rp/src/bin/ethernet_w5500_multisocket.rs | 2 +- examples/rp/src/bin/ethernet_w5500_tcp_client.rs | 4 ++-- examples/rp/src/bin/ethernet_w5500_tcp_server.rs | 4 ++-- examples/rp/src/bin/ethernet_w5500_udp.rs | 4 ++-- examples/rp/src/bin/usb_ethernet.rs | 9 ++------- examples/rp/src/bin/wifi_ap_tcp_server.rs | 4 ++-- examples/rp/src/bin/wifi_tcp_server.rs | 4 ++-- examples/rp/src/bin/wifi_webrequest.rs | 2 +- examples/std/src/bin/net.rs | 7 +------ examples/std/src/bin/net_dns.rs | 7 +------ examples/std/src/bin/net_ppp.rs | 2 +- examples/std/src/bin/net_udp.rs | 7 +------ examples/std/src/bin/tcp_accept.rs | 7 +------ examples/stm32f4/src/bin/eth.rs | 9 ++------- examples/stm32f4/src/bin/eth_w5500.rs | 9 ++------- examples/stm32f4/src/bin/usb_ethernet.rs | 9 ++------- examples/stm32f7/src/bin/eth.rs | 9 ++------- examples/stm32h5/src/bin/eth.rs | 9 ++------- examples/stm32h7/src/bin/eth.rs | 7 +------ examples/stm32h7/src/bin/eth_client.rs | 7 +------ examples/stm32h7/src/bin/eth_client_mii.rs | 7 +------ examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 9 ++------- examples/stm32l5/src/bin/usb_ethernet.rs | 9 ++------- 27 files changed, 46 insertions(+), 128 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index bd3de1f8c..56321cec9 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -415,8 +415,11 @@ impl Stack { /// ## Example /// ```ignore /// let config = embassy_net::Config::dhcpv4(Default::default()); - ///// Init network stack - /// static RESOURCES: StaticCell> = StaticCell::new(); + /// // Init network stack + /// // NOTE: DHCP and DNS need one socket slot if enabled. This is why we're + /// // provisioning space for 3 sockets here: one for DHCP, one for DNS, and one for your code (e.g. TCP). + /// // If you use more sockets you must increase this. If you don't enable DHCP or DNS you can decrease it. + /// static RESOURCES: StaticCell> = StaticCell::new(); /// static STACK: StaticCell = StaticCell::new(); /// let stack = &*STACK.init(embassy_net::Stack::new( /// device, diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index 279f32edc..94cf09c88 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -66,16 +66,11 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); static STACK: StaticCell< Stack, Output<'static>, Delay>, Output<'static>>>, > = StaticCell::new(); - let stack = STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + let stack = STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index a7e5c2668..e56b215e3 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -115,7 +115,7 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); static STACK: StaticCell>> = StaticCell::new(); let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index 00bd50081..a3b69a99b 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -89,14 +89,9 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); static STACK: StaticCell>> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index def26b53d..aaa035a72 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -76,7 +76,7 @@ async fn main(spawner: Spawner) { let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - RESOURCES.init(StackResources::<3>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 6c4a78361..8e96a114c 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -75,11 +75,11 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 30a3a7463..40736bf3c 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -74,11 +74,11 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 1613ed887..c79f01538 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -72,11 +72,11 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 22dc88d28..03c510f37 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -109,13 +109,8 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 4fc2690e3..11978adf1 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -81,11 +81,11 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); let stack = &*STACK.init(Stack::new( net_device, config, - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 5575df677..f77932202 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -84,11 +84,11 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); let stack = &*STACK.init(Stack::new( net_device, config, - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 70b6f0949..1a716d1a8 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -91,7 +91,7 @@ async fn main(spawner: Spawner) { let stack = &*STACK.init(Stack::new( net_device, config, - RESOURCES.init(StackResources::<5>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index 59813d8cb..310e7264d 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -52,12 +52,7 @@ async fn main_task(spawner: Spawner) { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<3>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task spawner.spawn(net_task(stack)).unwrap(); diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index 3b6a3de37..c9615ef35 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs @@ -51,12 +51,7 @@ async fn main_task(spawner: Spawner) { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack: &Stack<_> = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<3>::new()), - seed, - )); + let stack: &Stack<_> = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task spawner.spawn(net_task(stack)).unwrap(); diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index 9ec0ea91f..c5c27c4a3 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -102,7 +102,7 @@ async fn main_task(spawner: Spawner) { let stack = &*STACK.init(Stack::new( device, Config::default(), // don't configure IP yet - RESOURCES.init(StackResources::<3>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index bee91990d..b2ba4915a 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs @@ -50,12 +50,7 @@ async fn main_task(spawner: Spawner) { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<3>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task spawner.spawn(net_task(stack)).unwrap(); diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index e8b6eaa6c..39b29a449 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -64,12 +64,7 @@ async fn main_task(spawner: Spawner) { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<3>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task spawner.spawn(net_task(stack)).unwrap(); diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 648c45bbd..9388c64bf 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -89,13 +89,8 @@ async fn main(spawner: Spawner) -> ! { // Init network stack static STACK: StaticCell> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs index 3c770a873..5c3c6c3ba 100644 --- a/examples/stm32f4/src/bin/eth_w5500.rs +++ b/examples/stm32f4/src/bin/eth_w5500.rs @@ -93,13 +93,8 @@ async fn main(spawner: Spawner) -> ! { //}); static STACK: StaticCell> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index b398c35da..94e51c338 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -145,13 +145,8 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 41e2a6061..2fd10c8fb 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -90,13 +90,8 @@ async fn main(spawner: Spawner) -> ! { // Init network stack static STACK: StaticCell> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 2370656e6..65cfad8c9 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -93,13 +93,8 @@ async fn main(spawner: Spawner) -> ! { // Init network stack static STACK: StaticCell> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(&stack))); diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 7c7964ecd..b2f8ed91e 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -93,12 +93,7 @@ async fn main(spawner: Spawner) -> ! { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<3>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(&stack))); diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 0639fb99f..274c24ab1 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -93,12 +93,7 @@ async fn main(spawner: Spawner) -> ! { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<3>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index 9a52e8d3b..aa6544f41 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -99,12 +99,7 @@ async fn main(spawner: Spawner) -> ! { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<3>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 33149144c..bd633cecb 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -207,13 +207,8 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - ip_cfg, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(stack))); diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 7f73fd677..d02bac91d 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -122,13 +122,8 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell>> = StaticCell::new(); - static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); unwrap!(spawner.spawn(net_task(stack))); From 961ec387edec33fbaa9d63144f8826e3aff6cd45 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 8 Aug 2024 10:53:55 +0200 Subject: [PATCH 070/210] Simplify construction of StackResources::new() --- tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 7 +------ tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 2 +- tests/rp/src/bin/cyw43-perf.rs | 2 +- tests/rp/src/bin/ethernet_w5100s_perf.rs | 2 +- tests/stm32/src/bin/eth.rs | 7 +------ 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index 5f4220b1e..304754c0e 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -67,12 +67,7 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); unwrap!(spawner.spawn(net_task(stack))); diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index a6c93c8a6..6632442f1 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -91,7 +91,7 @@ async fn main(spawner: Spawner) { let stack = &*STACK.init(Stack::new( device, Config::dhcpv4(Default::default()), - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 53c84e711..38fbde7c1 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -74,7 +74,7 @@ async fn main(spawner: Spawner) { let stack = &*STACK.init(Stack::new( net_device, Config::dhcpv4(Default::default()), - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index 4b04571bd..f15f33743 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -72,7 +72,7 @@ async fn main(spawner: Spawner) { let stack = &*STACK.init(Stack::new( device, embassy_net::Config::dhcpv4(Default::default()), - RESOURCES.init(StackResources::<2>::new()), + RESOURCES.init(StackResources::new()), seed, )); diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index 25a06b986..9da514881 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -101,12 +101,7 @@ async fn main(spawner: Spawner) { // Init network stack static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); // Launch network task unwrap!(spawner.spawn(net_task(&stack))); From 7c8f57e5641857cab0f8df8277fd7165faf87ecb Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 8 Aug 2024 11:02:07 +0300 Subject: [PATCH 071/210] nrf: buffered_uarte: Add overrides for `too_many_arguments` lint One possible future fix for this could be refactoring at least ppi arguments into separate struct. --- embassy-nrf/src/buffered_uarte.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index b368a3d33..159b4db8f 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -219,6 +219,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// # Panics /// /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] pub fn new( uarte: impl Peripheral

+ 'd, timer: impl Peripheral

+ 'd, @@ -254,6 +255,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// # Panics /// /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] pub fn new_with_rtscts( uarte: impl Peripheral

+ 'd, timer: impl Peripheral

+ 'd, @@ -286,6 +288,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { ) } + #[allow(clippy::too_many_arguments)] fn new_inner( peri: PeripheralRef<'d, U>, timer: PeripheralRef<'d, T>, @@ -534,6 +537,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { /// # Panics /// /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] pub fn new( uarte: impl Peripheral

+ 'd, timer: impl Peripheral

+ 'd, @@ -564,6 +568,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { /// # Panics /// /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] pub fn new_with_rts( uarte: impl Peripheral

+ 'd, timer: impl Peripheral

+ 'd, @@ -590,6 +595,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { ) } + #[allow(clippy::too_many_arguments)] fn new_inner( peri: PeripheralRef<'d, U>, timer: PeripheralRef<'d, T>, @@ -614,6 +620,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { this } + #[allow(clippy::too_many_arguments)] fn new_innerer( peri: PeripheralRef<'d, U>, timer: PeripheralRef<'d, T>, From 2767b14a4e8ef501a6f02afa11758c0783c07cd4 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 8 Aug 2024 11:45:11 +0300 Subject: [PATCH 072/210] nrf: gpio: Fix return values for functions returning unit type - `()` --- embassy-nrf/src/gpio.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 7b272dca0..dbc26ea3f 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -534,11 +534,13 @@ mod eh02 { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) + self.set_high(); + Ok(()) } fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) + self.set_low(); + Ok(()) } } @@ -580,11 +582,13 @@ mod eh02 { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) + self.set_high(); + Ok(()) } fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) + self.set_low(); + Ok(()) } } @@ -628,11 +632,13 @@ impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> { impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> { fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) + self.set_high(); + Ok(()) } fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) + self.set_low(); + Ok(()) } } @@ -665,11 +671,13 @@ impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> { impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> { fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) + self.set_high(); + Ok(()) } fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) + self.set_low(); + Ok(()) } } From 2e8d9dba1443d1bb9a621027df06b0f9ba0097bc Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 8 Aug 2024 11:54:50 +0300 Subject: [PATCH 073/210] nrf: wdt: Fix formatting for `Safety` section --- embassy-nrf/src/wdt.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index 5a261ce8f..e4cfa3344 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -184,8 +184,9 @@ impl WatchdogHandle { /// Steal a watchdog handle by index. /// - /// Safety: watchdog must be initialized, index must be between 0 and N-1 where - /// N is the handle count when initializing. + /// # Safety + /// Watchdog must be initialized and `index` must be between `0` and `N-1` + /// where `N` is the handle count when initializing. pub unsafe fn steal(index: u8) -> Self { Self { index } } From ad4df1c1adaec95d32b9729945fa234a988ea2f1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 9 Aug 2024 01:05:10 +0200 Subject: [PATCH 074/210] cyw43: make sure to yield if doing busy-polling for interrupts. --- cyw43/src/runner.rs | 7 +++++++ examples/rp/Cargo.toml | 3 +++ 2 files changed, 10 insertions(+) diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index 6522d40fa..959718341 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -365,6 +365,13 @@ where } Either4::Fourth(()) => { self.handle_irq(&mut buf).await; + + // If we do busy-polling, make sure to yield. + // `handle_irq` will only do a 32bit read if there's no work to do, which is really fast. + // Depending on optimization level, it is possible that the 32-bit read finishes on + // first poll, so it never yields and we starve all other tasks. + #[cfg(feature = "bluetooth")] + embassy_futures::yield_now().await; } } } else { diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 2884ca85a..031f68253 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -64,8 +64,11 @@ trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } [profile.release] debug = 2 +lto = true +opt-level = 'z' [profile.dev] +debug = 2 lto = true opt-level = "z" From b185e02a42ad751ec6c31ffa6a1b87503f15489d Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 7 Aug 2024 23:20:26 -0400 Subject: [PATCH 075/210] Initial rp235x support Examples have been run, but there is not yet a test suite. --- embassy-rp/Cargo.toml | 20 +- embassy-rp/build.rs | 18 +- embassy-rp/link-rp.x.in | 2 +- embassy-rp/src/adc.rs | 27 +- embassy-rp/src/binary_info/consts.rs | 31 + embassy-rp/src/binary_info/macros.rs | 171 +++ embassy-rp/src/binary_info/mod.rs | 174 +++ embassy-rp/src/binary_info/types.rs | 192 ++++ embassy-rp/src/block.rs | 1076 ++++++++++++++++++ embassy-rp/src/clocks.rs | 84 +- embassy-rp/src/dma.rs | 32 +- embassy-rp/src/flash.rs | 25 +- embassy-rp/src/float/mod.rs | 1 + embassy-rp/src/gpio.rs | 76 ++ embassy-rp/src/i2c.rs | 36 + embassy-rp/src/lib.rs | 218 +++- embassy-rp/src/multicore.rs | 36 +- embassy-rp/src/pio/mod.rs | 95 +- embassy-rp/src/pwm.rs | 45 + embassy-rp/src/reset.rs | 2 +- embassy-rp/src/rtc/mod.rs | 1 + embassy-rp/src/spi.rs | 98 +- embassy-rp/src/time_driver.rs | 73 +- embassy-rp/src/uart/mod.rs | 122 +- embassy-rp/src/usb.rs | 6 +- embassy-rp/src/watchdog.rs | 1 + examples/rp/Cargo.toml | 4 +- examples/rp23/.cargo/config.toml | 9 + examples/rp23/Cargo.toml | 80 ++ examples/rp23/assets/ferris.raw | Bin 0 -> 11008 bytes examples/rp23/build.rs | 35 + examples/rp23/memory.x | 74 ++ examples/rp23/src/bin/adc.rs | 64 ++ examples/rp23/src/bin/adc_dma.rs | 70 ++ examples/rp23/src/bin/assign_resources.rs | 95 ++ examples/rp23/src/bin/blinky.rs | 44 + examples/rp23/src/bin/blinky_two_channels.rs | 66 ++ examples/rp23/src/bin/blinky_two_tasks.rs | 65 ++ examples/rp23/src/bin/button.rs | 44 + examples/rp23/src/bin/debounce.rs | 96 ++ examples/rp23/src/bin/flash.rs | 150 +++ examples/rp23/src/bin/gpio_async.rs | 56 + examples/rp23/src/bin/gpout.rs | 53 + examples/rp23/src/bin/i2c_async.rs | 126 ++ examples/rp23/src/bin/i2c_async_embassy.rs | 101 ++ examples/rp23/src/bin/i2c_blocking.rs | 90 ++ examples/rp23/src/bin/i2c_slave.rs | 132 +++ examples/rp23/src/bin/interrupt.rs | 110 ++ examples/rp23/src/bin/multicore.rs | 82 ++ examples/rp23/src/bin/multiprio.rs | 161 +++ examples/rp23/src/bin/pio_async.rs | 146 +++ examples/rp23/src/bin/pio_dma.rs | 99 ++ examples/rp23/src/bin/pio_hd44780.rs | 256 +++++ examples/rp23/src/bin/pio_i2s.rs | 141 +++ examples/rp23/src/bin/pio_pwm.rs | 134 +++ examples/rp23/src/bin/pio_rotary_encoder.rs | 96 ++ examples/rp23/src/bin/pio_servo.rs | 224 ++++ examples/rp23/src/bin/pio_stepper.rs | 184 +++ examples/rp23/src/bin/pio_ws2812.rs | 177 +++ examples/rp23/src/bin/pwm.rs | 45 + examples/rp23/src/bin/pwm_input.rs | 42 + examples/rp23/src/bin/rosc.rs | 47 + examples/rp23/src/bin/shared_bus.rs | 131 +++ examples/rp23/src/bin/sharing.rs | 166 +++ examples/rp23/src/bin/spi.rs | 62 + examples/rp23/src/bin/spi_async.rs | 47 + examples/rp23/src/bin/spi_display.rs | 328 ++++++ examples/rp23/src/bin/spi_sdmmc.rs | 99 ++ examples/rp23/src/bin/uart.rs | 40 + examples/rp23/src/bin/uart_buffered_split.rs | 74 ++ examples/rp23/src/bin/uart_r503.rs | 174 +++ examples/rp23/src/bin/uart_unidir.rs | 66 ++ examples/rp23/src/bin/usb_webusb.rs | 171 +++ examples/rp23/src/bin/watchdog.rs | 67 ++ examples/rp23/src/bin/zerocopy.rs | 110 ++ tests/rp/Cargo.toml | 2 +- 76 files changed, 7507 insertions(+), 90 deletions(-) create mode 100644 embassy-rp/src/binary_info/consts.rs create mode 100644 embassy-rp/src/binary_info/macros.rs create mode 100644 embassy-rp/src/binary_info/mod.rs create mode 100644 embassy-rp/src/binary_info/types.rs create mode 100644 embassy-rp/src/block.rs create mode 100644 examples/rp23/.cargo/config.toml create mode 100644 examples/rp23/Cargo.toml create mode 100644 examples/rp23/assets/ferris.raw create mode 100644 examples/rp23/build.rs create mode 100644 examples/rp23/memory.x create mode 100644 examples/rp23/src/bin/adc.rs create mode 100644 examples/rp23/src/bin/adc_dma.rs create mode 100644 examples/rp23/src/bin/assign_resources.rs create mode 100644 examples/rp23/src/bin/blinky.rs create mode 100644 examples/rp23/src/bin/blinky_two_channels.rs create mode 100644 examples/rp23/src/bin/blinky_two_tasks.rs create mode 100644 examples/rp23/src/bin/button.rs create mode 100644 examples/rp23/src/bin/debounce.rs create mode 100644 examples/rp23/src/bin/flash.rs create mode 100644 examples/rp23/src/bin/gpio_async.rs create mode 100644 examples/rp23/src/bin/gpout.rs create mode 100644 examples/rp23/src/bin/i2c_async.rs create mode 100644 examples/rp23/src/bin/i2c_async_embassy.rs create mode 100644 examples/rp23/src/bin/i2c_blocking.rs create mode 100644 examples/rp23/src/bin/i2c_slave.rs create mode 100644 examples/rp23/src/bin/interrupt.rs create mode 100644 examples/rp23/src/bin/multicore.rs create mode 100644 examples/rp23/src/bin/multiprio.rs create mode 100644 examples/rp23/src/bin/pio_async.rs create mode 100644 examples/rp23/src/bin/pio_dma.rs create mode 100644 examples/rp23/src/bin/pio_hd44780.rs create mode 100644 examples/rp23/src/bin/pio_i2s.rs create mode 100644 examples/rp23/src/bin/pio_pwm.rs create mode 100644 examples/rp23/src/bin/pio_rotary_encoder.rs create mode 100644 examples/rp23/src/bin/pio_servo.rs create mode 100644 examples/rp23/src/bin/pio_stepper.rs create mode 100644 examples/rp23/src/bin/pio_ws2812.rs create mode 100644 examples/rp23/src/bin/pwm.rs create mode 100644 examples/rp23/src/bin/pwm_input.rs create mode 100644 examples/rp23/src/bin/rosc.rs create mode 100644 examples/rp23/src/bin/shared_bus.rs create mode 100644 examples/rp23/src/bin/sharing.rs create mode 100644 examples/rp23/src/bin/spi.rs create mode 100644 examples/rp23/src/bin/spi_async.rs create mode 100644 examples/rp23/src/bin/spi_display.rs create mode 100644 examples/rp23/src/bin/spi_sdmmc.rs create mode 100644 examples/rp23/src/bin/uart.rs create mode 100644 examples/rp23/src/bin/uart_buffered_split.rs create mode 100644 examples/rp23/src/bin/uart_r503.rs create mode 100644 examples/rp23/src/bin/uart_unidir.rs create mode 100644 examples/rp23/src/bin/usb_webusb.rs create mode 100644 examples/rp23/src/bin/watchdog.rs create mode 100644 examples/rp23/src/bin/zerocopy.rs diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index b7f5a2bcc..4e36c885b 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -15,6 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/sr features = ["defmt", "unstable-pac", "time-driver"] flavors = [ { name = "rp2040", target = "thumbv6m-none-eabi" }, + { name = "rp235x", target = "thumbv8m.main-none-eabi" }, ] [package.metadata.docs.rs] @@ -23,7 +24,9 @@ features = ["defmt", "unstable-pac", "time-driver"] [features] default = [ "rt" ] ## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. -rt = [ "rp-pac/rt" ] +rt = [] +rt-2040 = [ "rt", "rp-pac/rt" ] +rt-235x = [ "rt", "rp23-pac/rt" ] ## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] @@ -88,6 +91,17 @@ boot2-w25x10cl = [] ## ``` boot2-none = [] +rp2040 = ["dep:rp-pac"] +rp235x = ["dep:rp23-pac"] +rp235xa = ["rp235x"] +rp235xb = ["rp235x"] + +# Add a binary-info header block containing picotool-compatible metadata. +# +# Takes up a little flash space, but picotool can then report the name of your +# program and other details. +binary-info = [ "rt-235x" ] + [dependencies] embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } @@ -112,7 +126,8 @@ embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { version = "6" } +rp-pac = { path = "/home/cbjamo/235x/rp-pac", feature = ["rt"], optional = true } +rp23-pac = { path = "/home/cbjamo/235x/rp23-pac/", feature = ["rt"], optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } @@ -123,6 +138,7 @@ pio-proc = {version= "0.2" } pio = {version= "0.2.1" } rp2040-boot2 = "0.3" document-features = "0.2.7" +sha2-const-stable = "0.1" [dev-dependencies] embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } diff --git a/embassy-rp/build.rs b/embassy-rp/build.rs index f41ccd220..3216a3826 100644 --- a/embassy-rp/build.rs +++ b/embassy-rp/build.rs @@ -4,14 +4,16 @@ use std::io::Write; use std::path::PathBuf; fn main() { - // Put the linker script somewhere the linker can find it - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let link_x = include_bytes!("link-rp.x.in"); - let mut f = File::create(out.join("link-rp.x")).unwrap(); - f.write_all(link_x).unwrap(); + if env::var("CARGO_FEATURE_RP2040").is_ok() { + // Put the linker script somewhere the linker can find it + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let link_x = include_bytes!("link-rp.x.in"); + let mut f = File::create(out.join("link-rp.x")).unwrap(); + f.write_all(link_x).unwrap(); - println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rustc-link-search={}", out.display()); - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=link-rp.x.in"); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=link-rp.x.in"); + } } diff --git a/embassy-rp/link-rp.x.in b/embassy-rp/link-rp.x.in index af463f963..1839dda68 100644 --- a/embassy-rp/link-rp.x.in +++ b/embassy-rp/link-rp.x.in @@ -5,4 +5,4 @@ SECTIONS { { KEEP(*(.boot2)); } > BOOT2 -} \ No newline at end of file +} diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index eb1cc9a66..12d08d06b 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -11,6 +11,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin}; use crate::interrupt::typelevel::Binding; use crate::interrupt::InterruptExt; +use crate::pac::dma::vals::TreqSel; use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt}; @@ -229,7 +230,10 @@ impl<'d> Adc<'d, Async> { div: u16, dma: impl Peripheral

, ) -> Result<(), Error> { + #[cfg(feature = "rp2040")] let mut rrobin = 0_u8; + #[cfg(feature = "rp235x")] + let mut rrobin = 0_u16; for c in channels { rrobin |= 1 << c; } @@ -278,7 +282,7 @@ impl<'d> Adc<'d, Async> { } let auto_reset = ResetDmaConfig; - let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], 36) }; + let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], TreqSel::ADC) }; // start conversions and wait for dma to finish. we can't report errors early // because there's no interrupt to signal them, and inspecting every element // of the fifo is too costly to do here. @@ -423,10 +427,31 @@ macro_rules! impl_pin { }; } +#[cfg(any(feature = "rp235xa", feature = "rp2040"))] impl_pin!(PIN_26, 0); +#[cfg(any(feature = "rp235xa", feature = "rp2040"))] impl_pin!(PIN_27, 1); +#[cfg(any(feature = "rp235xa", feature = "rp2040"))] impl_pin!(PIN_28, 2); +#[cfg(any(feature = "rp235xa", feature = "rp2040"))] impl_pin!(PIN_29, 3); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_40, 0); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_41, 1); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_42, 2); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_43, 3); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_44, 4); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_45, 5); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_46, 6); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_47, 7); + impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {} impl AdcChannel for peripherals::ADC_TEMP_SENSOR {} diff --git a/embassy-rp/src/binary_info/consts.rs b/embassy-rp/src/binary_info/consts.rs new file mode 100644 index 000000000..c8270c081 --- /dev/null +++ b/embassy-rp/src/binary_info/consts.rs @@ -0,0 +1,31 @@ +//! Constants for binary info + +/// All Raspberry Pi specified IDs have this tag. +/// +/// You can create your own for custom fields. +pub const TAG_RASPBERRY_PI: u16 = super::make_tag(b"RP"); + +/// Used to note the program name - use with StringEntry +pub const ID_RP_PROGRAM_NAME: u32 = 0x02031c86; +/// Used to note the program version - use with StringEntry +pub const ID_RP_PROGRAM_VERSION_STRING: u32 = 0x11a9bc3a; +/// Used to note the program build date - use with StringEntry +pub const ID_RP_PROGRAM_BUILD_DATE_STRING: u32 = 0x9da22254; +/// Used to note the size of the binary - use with IntegerEntry +pub const ID_RP_BINARY_END: u32 = 0x68f465de; +/// Used to note a URL for the program - use with StringEntry +pub const ID_RP_PROGRAM_URL: u32 = 0x1856239a; +/// Used to note a description of the program - use with StringEntry +pub const ID_RP_PROGRAM_DESCRIPTION: u32 = 0xb6a07c19; +/// Used to note some feature of the program - use with StringEntry +pub const ID_RP_PROGRAM_FEATURE: u32 = 0xa1f4b453; +/// Used to note some whether this was a Debug or Release build - use with StringEntry +pub const ID_RP_PROGRAM_BUILD_ATTRIBUTE: u32 = 0x4275f0d3; +/// Used to note the Pico SDK version used - use with StringEntry +pub const ID_RP_SDK_VERSION: u32 = 0x5360b3ab; +/// Used to note which board this program targets - use with StringEntry +pub const ID_RP_PICO_BOARD: u32 = 0xb63cffbb; +/// Used to note which `boot2` image this program uses - use with StringEntry +pub const ID_RP_BOOT2_NAME: u32 = 0x7f8882e1; + +// End of file diff --git a/embassy-rp/src/binary_info/macros.rs b/embassy-rp/src/binary_info/macros.rs new file mode 100644 index 000000000..ef98c8399 --- /dev/null +++ b/embassy-rp/src/binary_info/macros.rs @@ -0,0 +1,171 @@ +//! Handy macros for making Binary Info entries + +/// Generate a static item containing the given environment variable, +/// and return its [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_env { + ($tag:expr, $id:expr, $env_var_name:expr) => { + $crate::binary_info_str!($tag, $id, { + let value = concat!(env!($env_var_name), "\0"); + // # Safety + // + // We used `concat!` to null-terminate on the line above. + let value_cstr = + unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(value.as_bytes()) }; + value_cstr + }) + }; +} + +/// Generate a static item containing the given string, and return its +/// [`EntryAddr`](super::EntryAddr). +/// +/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always +/// null-terminated). +#[macro_export] +macro_rules! binary_info_str { + ($tag:expr, $id:expr, $str:expr) => {{ + static ENTRY: $crate::binary_info::StringEntry = + $crate::binary_info::StringEntry::new($tag, $id, $str); + ENTRY.addr() + }}; +} + +/// Generate a static item containing the given string, and return its +/// [`EntryAddr`](super::EntryAddr). +/// +/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always +/// null-terminated). +#[macro_export] +macro_rules! binary_info_int { + ($tag:expr, $id:expr, $int:expr) => {{ + static ENTRY: $crate::binary_info::IntegerEntry = + $crate::binary_info::IntegerEntry::new($tag, $id, $int); + ENTRY.addr() + }}; +} + +/// Generate a static item containing the program name, and return its +/// [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_program_name { + ($name:expr) => { + $crate::binary_info_str!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_NAME, + $name + ) + }; +} + +/// Generate a static item containing the `CARGO_BIN_NAME` as the program name, +/// and return its [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_cargo_bin_name { + () => { + $crate::binary_info_env!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_NAME, + "CARGO_BIN_NAME" + ) + }; +} + +/// Generate a static item containing the program version, and return its +/// [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_program_version { + ($version:expr) => {{ + $crate::binary_info_str!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_VERSION, + $version + ) + }}; +} + +/// Generate a static item containing the `CARGO_PKG_VERSION` as the program +/// version, and return its [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_cargo_version { + () => { + $crate::binary_info_env!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_VERSION_STRING, + "CARGO_PKG_VERSION" + ) + }; +} + +/// Generate a static item containing the program URL, and return its +/// [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_program_url { + ($url:expr) => { + $crate::binary_info_str!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_URL, + $url + ) + }; +} + +/// Generate a static item containing the `CARGO_PKG_HOMEPAGE` as the program URL, +/// and return its [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_cargo_homepage_url { + () => { + $crate::binary_info_env!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_URL, + "CARGO_PKG_HOMEPAGE" + ) + }; +} + +/// Generate a static item containing the program description, and return its +/// [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_program_description { + ($description:expr) => { + $crate::binary_info_str!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_DESCRIPTION, + $description + ) + }; +} + +/// Generate a static item containing whether this is a debug or a release +/// build, and return its [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_program_build_attribute { + () => { + $crate::binary_info_str!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, + { + if cfg!(debug_assertions) { + c"debug" + } else { + c"release" + } + } + ) + }; +} + +/// Generate a static item containing the specific board this program runs on, +/// and return its [`EntryAddr`](super::EntryAddr). +#[macro_export] +macro_rules! binary_info_rp_pico_board { + ($board:expr) => { + $crate::binary_info_str!( + $crate::binary_info::consts::TAG_RASPBERRY_PI, + $crate::binary_info::consts::ID_RP_PICO_BOARD, + $board + ) + }; +} + +// End of file diff --git a/embassy-rp/src/binary_info/mod.rs b/embassy-rp/src/binary_info/mod.rs new file mode 100644 index 000000000..ce3829a7c --- /dev/null +++ b/embassy-rp/src/binary_info/mod.rs @@ -0,0 +1,174 @@ +//! Code and types for creating Picotool compatible "Binary Info" metadata +//! +//! Add something like this to your program, and compile with the "binary-info" +//! and "rt" features: +//! +//! ``` +//! # use rp235x_hal as hal; +//! #[link_section = ".bi_entries"] +//! #[used] +//! pub static PICOTOOL_ENTRIES: [hal::binary_info::EntryAddr; 3] = [ +//! hal::binary_info_rp_program_name!(c"Program Name Here"), +//! hal::binary_info_rp_cargo_version!(), +//! hal::binary_info_int!(hal::binary_info::make_tag(b"JP"), 0x0000_0001, 0x12345678), +//! ]; +//! ``` + +pub mod consts; + +mod types; +pub use types::*; + +#[macro_use] +mod macros; + +extern "C" { + /// The linker script sets this symbol to have the address of the first + /// entry in the `.bi_entries` section. + static __bi_entries_start: EntryAddr; + /// The linker script sets this symbol to have the address just past the + /// last entry in the `.bi_entries` section. + static __bi_entries_end: EntryAddr; + /// The linker script sets this symbol to have the address of the first + /// entry in the `.data` section. + static __sdata: u32; + /// The linker script sets this symbol to have the address just past the + /// first entry in the `.data` section. + static __edata: u32; + /// The linker script sets this symbol to have the address of the + /// initialisation data for the first entry in the `.data` section (i.e. a + /// flash address, not a RAM address). + static __sidata: u32; +} + +/// Picotool can find this block in our ELF file and report interesting +/// metadata. +/// +/// The data here tells picotool the start and end flash addresses of our +/// metadata. +#[cfg(feature = "binary-info")] +#[link_section = ".start_block"] +#[used] +pub static PICOTOOL_HEADER: Header = unsafe { + Header::new( + core::ptr::addr_of!(__bi_entries_start), + core::ptr::addr_of!(__bi_entries_end), + &MAPPING_TABLE, + ) +}; + +/// This tells picotool how to convert RAM addresses back into Flash addresses +#[cfg(feature = "binary-info")] +pub static MAPPING_TABLE: [MappingTableEntry; 2] = [ + // This is the entry for .data + MappingTableEntry { + source_addr_start: unsafe { core::ptr::addr_of!(__sidata) }, + dest_addr_start: unsafe { core::ptr::addr_of!(__sdata) }, + dest_addr_end: unsafe { core::ptr::addr_of!(__edata) }, + }, + // This is the terminating marker + MappingTableEntry::null(), +]; + +/// Create a 'Binary Info' entry containing the program name +/// +/// This is well-known to picotool, and will be displayed if you run `picotool info`. +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * ID: [`consts::ID_RP_PROGRAM_NAME`] +pub const fn rp_program_name(name: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_NAME, name) +} + +/// Create a 'Binary Info' entry containing the program version. +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_PROGRAM_VERSION_STRING`] +pub const fn rp_program_version(name: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_VERSION_STRING, name) +} + +/// Create a 'Binary Info' entry with a URL +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_PROGRAM_URL`] +pub const fn rp_program_url(url: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_URL, url) +} + +/// Create a 'Binary Info' with the program build date +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_PROGRAM_BUILD_DATE_STRING`] +pub const fn rp_program_build_date_string(value: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_DATE_STRING, value) +} + +/// Create a 'Binary Info' with the size of the binary +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_BINARY_END`] +pub const fn rp_binary_end(value: u32) -> IntegerEntry { + IntegerEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BINARY_END, value) +} + +/// Create a 'Binary Info' with a description of the program +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_PROGRAM_DESCRIPTION`] +pub const fn rp_program_description(value: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_DESCRIPTION, value) +} + +/// Create a 'Binary Info' with some feature of the program +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_PROGRAM_FEATURE`] +pub const fn rp_program_feature(value: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_FEATURE, value) +} + +/// Create a 'Binary Info' with some whether this was a Debug or Release build +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE`] +pub const fn rp_program_build_attribute(value: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, value) +} + +/// Create a 'Binary Info' with the Pico SDK version used +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_SDK_VERSION`] +pub const fn rp_sdk_version(value: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_SDK_VERSION, value) +} + +/// Create a 'Binary Info' with which board this program targets +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_PICO_BOARD`] +pub const fn rp_pico_board(value: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PICO_BOARD, value) +} + +/// Create a 'Binary Info' with which `boot2` image this program uses +/// +/// * Tag: [`consts::TAG_RASPBERRY_PI`] +/// * Id: [`consts::ID_RP_BOOT2_NAME`] +pub const fn rp_boot2_name(value: &'static core::ffi::CStr) -> StringEntry { + StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BOOT2_NAME, value) +} + +/// Create a tag from two ASCII letters. +/// +/// ``` +/// # use rp235x_hal as hal; +/// let tag = hal::binary_info::make_tag(b"RP"); +/// assert_eq!(tag, 0x5052); +/// ``` +pub const fn make_tag(c: &[u8; 2]) -> u16 { + u16::from_le_bytes(*c) +} + +// End of file diff --git a/embassy-rp/src/binary_info/types.rs b/embassy-rp/src/binary_info/types.rs new file mode 100644 index 000000000..d2b192e32 --- /dev/null +++ b/embassy-rp/src/binary_info/types.rs @@ -0,0 +1,192 @@ +//! Types for the Binary Info system + +/// This is the 'Binary Info' header block that `picotool` looks for in your UF2 +/// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your +/// program. +/// +/// It should be placed in the first 4096 bytes of flash, so use your `memory.x` +/// to insert a section between `.text` and `.vector_table` and put a static +/// value of this type in that section. +#[repr(C)] +pub struct Header { + /// Must be equal to Picotool::MARKER_START + marker_start: u32, + /// The first in our table of pointers to Entries + entries_start: *const EntryAddr, + /// The last in our table of pointers to Entries + entries_end: *const EntryAddr, + /// The first entry in a null-terminated RAM/Flash mapping table + mapping_table: *const MappingTableEntry, + /// Must be equal to Picotool::MARKER_END + marker_end: u32, +} + +impl Header { + /// This is the `BINARY_INFO_MARKER_START` magic value from `picotool` + const MARKER_START: u32 = 0x7188ebf2; + /// This is the `BINARY_INFO_MARKER_END` magic value from `picotool` + const MARKER_END: u32 = 0xe71aa390; + + /// Create a new `picotool` compatible header. + /// + /// * `entries_start` - the first [`EntryAddr`] in the table + /// * `entries_end` - the last [`EntryAddr`] in the table + /// * `mapping_table` - the RAM/Flash address mapping table + pub const fn new( + entries_start: *const EntryAddr, + entries_end: *const EntryAddr, + mapping_table: &'static [MappingTableEntry], + ) -> Self { + let mapping_table = mapping_table.as_ptr(); + Self { + marker_start: Self::MARKER_START, + entries_start, + entries_end, + mapping_table, + marker_end: Self::MARKER_END, + } + } +} + +// We need this as rustc complains that is is unsafe to share `*const u32` +// pointers between threads. We only allow these to be created with static +// data, so this is OK. +unsafe impl Sync for Header {} + +/// This is a reference to an entry. It's like a `&dyn` ref to some type `T: +/// Entry`, except that the run-time type information is encoded into the +/// Entry itself in very specific way. +#[repr(transparent)] +pub struct EntryAddr(*const u32); + +// We need this as rustc complains that is is unsafe to share `*const u32` +// pointers between threads. We only allow these to be created with static +// data, so this is OK. +unsafe impl Sync for EntryAddr {} + +/// Allows us to tell picotool where values are in the UF2 given their run-time +/// address. +/// +/// The most obvious example is RAM variables, which must be found in the +/// `.data` section of the UF2. +#[repr(C)] +pub struct MappingTableEntry { + /// The start address in RAM (or wherever the address picotool finds will + /// point) + pub source_addr_start: *const u32, + /// The start address in flash (or whever the data actually lives in the + /// ELF) + pub dest_addr_start: *const u32, + /// The end address in flash + pub dest_addr_end: *const u32, +} + +impl MappingTableEntry { + /// Generate a null entry to mark the end of the list + pub const fn null() -> MappingTableEntry { + MappingTableEntry { + source_addr_start: core::ptr::null(), + dest_addr_start: core::ptr::null(), + dest_addr_end: core::ptr::null(), + } + } +} + +// We need this as rustc complains that is is unsafe to share `*const u32` +// pointers between threads. We only allow these to be created with static +// data, so this is OK. +unsafe impl Sync for MappingTableEntry {} + +/// This is the set of data types that `picotool` supports. +#[repr(u16)] +pub enum DataType { + /// Raw data + Raw = 1, + /// Data with a size + SizedData = 2, + /// A list of binary data + BinaryInfoListZeroTerminated = 3, + /// A BSON encoded blob + Bson = 4, + /// An Integer with an ID + IdAndInt = 5, + /// A string with an Id + IdAndString = 6, + /// A block device + BlockDevice = 7, + /// GPIO pins, with their function + PinsWithFunction = 8, + /// GPIO pins, with their name + PinsWithName = 9, + /// GPIO pins, with multiple names? + PinsWithNames = 10, +} + +/// All Entries start with this common header +#[repr(C)] +struct EntryCommon { + data_type: DataType, + tag: u16, +} + +/// An entry which contains both an ID (e.g. `ID_RP_PROGRAM_NAME`) and a pointer +/// to a null-terminated string. +#[repr(C)] +pub struct StringEntry { + header: EntryCommon, + id: u32, + value: *const core::ffi::c_char, +} + +impl StringEntry { + /// Create a new `StringEntry` + pub const fn new(tag: u16, id: u32, value: &'static core::ffi::CStr) -> StringEntry { + StringEntry { + header: EntryCommon { + data_type: DataType::IdAndString, + tag, + }, + id, + value: value.as_ptr(), + } + } + + /// Get this entry's address + pub const fn addr(&self) -> EntryAddr { + EntryAddr(self as *const Self as *const u32) + } +} + +// We need this as rustc complains that is is unsafe to share `*const +// core::ffi::c_char` pointers between threads. We only allow these to be +// created with static string slices, so it's OK. +unsafe impl Sync for StringEntry {} + +/// An entry which contains both an ID (e.g. `ID_RP_BINARY_END`) and an integer. +#[repr(C)] +pub struct IntegerEntry { + header: EntryCommon, + id: u32, + value: u32, +} + +impl IntegerEntry { + /// Create a new `StringEntry` + pub const fn new(tag: u16, id: u32, value: u32) -> IntegerEntry { + IntegerEntry { + header: EntryCommon { + data_type: DataType::IdAndInt, + tag, + }, + id, + value, + } + } + + /// Get this entry's address + pub const fn addr(&self) -> EntryAddr { + EntryAddr(self as *const Self as *const u32) + } +} + +// End of file diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs new file mode 100644 index 000000000..d270bbf1c --- /dev/null +++ b/embassy-rp/src/block.rs @@ -0,0 +1,1076 @@ +//! Support for the RP235x Boot ROM's "Block" structures +//! +//! Blocks contain pointers, to form Block Loops. +//! +//! The `IMAGE_DEF` Block (here the `ImageDef` type) tells the ROM how to boot a +//! firmware image. The `PARTITION_TABLE` Block (here the `PartitionTable` type) +//! tells the ROM how to divide the flash space up into partitions. + +// These all have a 1 byte size + +/// An item ID for encoding a Vector Table address +pub const ITEM_1BS_VECTOR_TABLE: u8 = 0x03; + +/// An item ID for encoding a Rolling Window Delta +pub const ITEM_1BS_ROLLING_WINDOW_DELTA: u8 = 0x05; + +/// An item ID for encoding a Signature +pub const ITEM_1BS_SIGNATURE: u8 = 0x09; + +/// An item ID for encoding a Salt +pub const ITEM_1BS_SALT: u8 = 0x0c; + +/// An item ID for encoding an Image Type +pub const ITEM_1BS_IMAGE_TYPE: u8 = 0x42; + +/// An item ID for encoding the image's Entry Point +pub const ITEM_1BS_ENTRY_POINT: u8 = 0x44; + +/// An item ID for encoding the definition of a Hash +pub const ITEM_2BS_HASH_DEF: u8 = 0x47; + +/// An item ID for encoding a Version +pub const ITEM_1BS_VERSION: u8 = 0x48; + +/// An item ID for encoding a Hash +pub const ITEM_1BS_HASH_VALUE: u8 = 0x4b; + +// These all have a 2-byte size + +/// An item ID for encoding a Load Map +pub const ITEM_2BS_LOAD_MAP: u8 = 0x06; + +/// An item ID for encoding a Partition Table +pub const ITEM_2BS_PARTITION_TABLE: u8 = 0x0a; + +/// An item ID for encoding a placeholder entry that is ignored +/// +/// Allows a Block to not be empty. +pub const ITEM_2BS_IGNORED: u8 = 0xfe; + +/// An item ID for encoding the special last item in a Block +/// +/// It records how long the Block is. +pub const ITEM_2BS_LAST: u8 = 0xff; + +// Options for ITEM_1BS_IMAGE_TYPE + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as invalid +pub const IMAGE_TYPE_INVALID: u16 = 0x0000; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as an executable +pub const IMAGE_TYPE_EXE: u16 = 0x0001; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as data +pub const IMAGE_TYPE_DATA: u16 = 0x0002; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as unspecified +pub const IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED: u16 = 0x0000; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure +pub const IMAGE_TYPE_EXE_TYPE_SECURITY_NS: u16 = 0x0010; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure +pub const IMAGE_TYPE_EXE_TYPE_SECURITY_S: u16 = 0x0020; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as Arm +pub const IMAGE_TYPE_EXE_CPU_ARM: u16 = 0x0000; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as RISC-V +pub const IMAGE_TYPE_EXE_CPU_RISCV: u16 = 0x0100; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2040 +pub const IMAGE_TYPE_EXE_CHIP_RP2040: u16 = 0x0000; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2350 +pub const IMAGE_TYPE_EXE_CHIP_RP2350: u16 = 0x1000; + +/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the image as Try Before You Buy. +/// +/// This means the image must be marked as 'Bought' with the ROM before the +/// watchdog times out the trial period, otherwise it is erased and the previous +/// image will be booted. +pub const IMAGE_TYPE_TBYB: u16 = 0x8000; + +/// This is the magic Block Start value. +/// +/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_START` +const BLOCK_MARKER_START: u32 = 0xffffded3; + +/// This is the magic Block END value. +/// +/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_END` +const BLOCK_MARKER_END: u32 = 0xab123579; + +/// An Image Definition has one item in it - an [`ITEM_1BS_IMAGE_TYPE`] +pub type ImageDef = Block<1>; + +/// A Block as understood by the Boot ROM. +/// +/// This could be an Image Definition, or a Partition Table, or maybe some other +/// kind of block. +/// +/// It contains within the special start and end markers the Boot ROM is looking +/// for. +#[derive(Debug)] +#[repr(C)] +pub struct Block { + marker_start: u32, + items: [u32; N], + length: u32, + offset: *const u32, + marker_end: u32, +} + +unsafe impl Sync for Block {} + +impl Block { + /// Construct a new Binary Block, with the given items. + /// + /// The length, and the Start and End markers are added automatically. The + /// Block Loop pointer initially points to itself. + pub const fn new(items: [u32; N]) -> Block { + Block { + marker_start: BLOCK_MARKER_START, + items, + length: item_last(N as u16), + // offset from this block to next block in loop. By default + // we form a Block Loop with a single Block in it. + offset: core::ptr::null(), + marker_end: BLOCK_MARKER_END, + } + } + + /// Change the Block Loop offset value. + /// + /// This method isn't that useful because you can't evaluate the difference + /// between two pointers in a const context as the addresses aren't assigned + /// until long after the const evaluator has run. + /// + /// If you think you need this method, you might want to set a unique random + /// value here and swap it for the real offset as a post-processing step. + pub const fn with_offset(self, offset: *const u32) -> Block { + Block { offset, ..self } + } +} + +impl Block<0> { + /// Construct an empty block. + pub const fn empty() -> Block<0> { + Block::new([]) + } + + /// Make the block one word larger + pub const fn extend(self, word: u32) -> Block<1> { + Block::new([word]) + } +} + +impl Block<1> { + /// Make the block one word larger + pub const fn extend(self, word: u32) -> Block<2> { + Block::new([self.items[0], word]) + } +} + +impl Block<2> { + /// Make the block one word larger + pub const fn extend(self, word: u32) -> Block<3> { + Block::new([self.items[0], self.items[1], word]) + } +} + +impl ImageDef { + /// Construct a new IMAGE_DEF Block, for an EXE with the given security and + /// architecture. + pub const fn arch_exe(security: Security, architecture: Architecture) -> Self { + Self::new([item_image_type_exe(security, architecture)]) + } + + /// Construct a new IMAGE_DEF Block, for an EXE with the given security. + /// + /// The target architecture is taken from the current build target (i.e. Arm + /// or RISC-V). + pub const fn exe(security: Security) -> Self { + if cfg!(all(target_arch = "riscv32", target_os = "none")) { + Self::arch_exe(security, Architecture::Riscv) + } else { + Self::arch_exe(security, Architecture::Arm) + } + } + + /// Construct a new IMAGE_DEF Block, for a Non-Secure EXE. + /// + /// The target architecture is taken from the current build target (i.e. Arm + /// or RISC-V). + pub const fn non_secure_exe() -> Self { + Self::exe(Security::NonSecure) + } + + /// Construct a new IMAGE_DEF Block, for a Secure EXE. + /// + /// The target architecture is taken from the current build target (i.e. Arm + /// or RISC-V). + pub const fn secure_exe() -> Self { + Self::exe(Security::Secure) + } +} + +/// We make our partition table this fixed size. +pub const PARTITION_TABLE_MAX_ITEMS: usize = 128; + +/// Describes a unpartitioned space +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct UnpartitionedSpace { + permissions_and_location: u32, + permissions_and_flags: u32, +} + +impl UnpartitionedSpace { + /// Create a new unpartitioned space. + /// + /// It defaults to no permissions. + pub const fn new() -> Self { + Self { + permissions_and_location: 0, + permissions_and_flags: 0, + } + } + + /// Create a new unpartition space from run-time values. + /// + /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`. + pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self { + Self { + permissions_and_location, + permissions_and_flags, + } + } + + /// Add a permission + pub const fn with_permission(self, permission: Permission) -> Self { + Self { + permissions_and_flags: self.permissions_and_flags | permission as u32, + permissions_and_location: self.permissions_and_location | permission as u32, + } + } + + /// Set a flag + pub const fn with_flag(self, flag: UnpartitionedFlag) -> Self { + Self { + permissions_and_flags: self.permissions_and_flags | flag as u32, + ..self + } + } + + /// Get the partition start and end + /// + /// The offsets are in 4 KiB sectors, inclusive. + pub fn get_first_last_sectors(&self) -> (u16, u16) { + ( + (self.permissions_and_location & 0x0000_1FFF) as u16, + ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16, + ) + } + + /// Get the partition start and end + /// + /// The offsets are in bytes, inclusive. + pub fn get_first_last_bytes(&self) -> (u32, u32) { + let (first, last) = self.get_first_last_sectors(); + (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095) + } + + /// Check if it has a permission + pub fn has_permission(&self, permission: Permission) -> bool { + let mask = permission as u32; + (self.permissions_and_flags & mask) != 0 + } + + /// Check if the partition has a flag set + pub fn has_flag(&self, flag: UnpartitionedFlag) -> bool { + let mask = flag as u32; + (self.permissions_and_flags & mask) != 0 + } +} + +impl core::fmt::Display for UnpartitionedSpace { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let (first, last) = self.get_first_last_bytes(); + write!( + f, + "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}", + first, + last, + if self.has_permission(Permission::SecureRead) { + 'R' + } else { + '_' + }, + if self.has_permission(Permission::SecureWrite) { + 'W' + } else { + '_' + }, + if self.has_permission(Permission::NonSecureRead) { + 'R' + } else { + '_' + }, + if self.has_permission(Permission::NonSecureWrite) { + 'W' + } else { + '_' + }, + if self.has_permission(Permission::BootRead) { + 'R' + } else { + '_' + }, + if self.has_permission(Permission::BootWrite) { + 'W' + } else { + '_' + } + ) + } +} + +/// Describes a Partition +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Partition { + permissions_and_location: u32, + permissions_and_flags: u32, + id: Option, + extra_families: [u32; 4], + extra_families_len: usize, + name: [u8; 128], +} + +impl Partition { + const FLAGS_HAS_ID: u32 = 0b1; + const FLAGS_LINK_TYPE_A_PARTITION: u32 = 0b01 << 1; + const FLAGS_LINK_TYPE_OWNER: u32 = 0b10 << 1; + const FLAGS_LINK_MASK: u32 = 0b111111 << 1; + const FLAGS_HAS_NAME: u32 = 0b1 << 12; + const FLAGS_HAS_EXTRA_FAMILIES_SHIFT: u8 = 7; + const FLAGS_HAS_EXTRA_FAMILIES_MASK: u32 = 0b11 << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT; + + /// Create a new partition, with the given start and end sectors. + /// + /// It defaults to no permissions. + pub const fn new(first_sector: u16, last_sector: u16) -> Self { + // 0x2000 sectors of 4 KiB is 32 MiB, which is the total XIP area + core::assert!(first_sector < 0x2000); + core::assert!(last_sector < 0x2000); + core::assert!(first_sector <= last_sector); + Self { + permissions_and_location: (last_sector as u32) << 13 | first_sector as u32, + permissions_and_flags: 0, + id: None, + extra_families: [0; 4], + extra_families_len: 0, + name: [0; 128], + } + } + + /// Create a new partition from run-time values. + /// + /// Get these from the ROM function `get_partition_table_info` with an argument of `PARTITION_LOCATION_AND_FLAGS`. + pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self { + Self { + permissions_and_location, + permissions_and_flags, + id: None, + extra_families: [0; 4], + extra_families_len: 0, + name: [0; 128], + } + } + + /// Add a permission + pub const fn with_permission(self, permission: Permission) -> Self { + Self { + permissions_and_location: self.permissions_and_location | permission as u32, + permissions_and_flags: self.permissions_and_flags | permission as u32, + ..self + } + } + + /// Set the name of the partition + pub const fn with_name(self, name: &str) -> Self { + let mut new_name = [0u8; 128]; + let name = name.as_bytes(); + let mut idx = 0; + new_name[0] = name.len() as u8; + while idx < name.len() { + new_name[idx + 1] = name[idx]; + idx += 1; + } + Self { + name: new_name, + permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_NAME, + ..self + } + } + + /// Set the extra families for the partition. + /// + /// You can supply up to four. + pub const fn with_extra_families(self, extra_families: &[u32]) -> Self { + core::assert!(extra_families.len() <= 4); + let mut new_extra_families = [0u32; 4]; + let mut idx = 0; + while idx < extra_families.len() { + new_extra_families[idx] = extra_families[idx]; + idx += 1; + } + Self { + extra_families: new_extra_families, + extra_families_len: extra_families.len(), + permissions_and_flags: (self.permissions_and_flags & !Self::FLAGS_HAS_EXTRA_FAMILIES_MASK) + | (extra_families.len() as u32) << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT, + ..self + } + } + + /// Set the ID + pub const fn with_id(self, id: u64) -> Self { + Self { + id: Some(id), + permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_ID, + ..self + } + } + + /// Add a link + pub const fn with_link(self, link: Link) -> Self { + let mut new_flags = self.permissions_and_flags & !Self::FLAGS_LINK_MASK; + match link { + Link::Nothing => {} + Link::ToA { partition_idx } => { + core::assert!(partition_idx < 16); + new_flags |= Self::FLAGS_LINK_TYPE_A_PARTITION; + new_flags |= (partition_idx as u32) << 3; + } + Link::ToOwner { partition_idx } => { + core::assert!(partition_idx < 16); + new_flags |= Self::FLAGS_LINK_TYPE_OWNER; + new_flags |= (partition_idx as u32) << 3; + } + } + Self { + permissions_and_flags: new_flags, + ..self + } + } + + /// Set a flag + pub const fn with_flag(self, flag: PartitionFlag) -> Self { + Self { + permissions_and_flags: self.permissions_and_flags | flag as u32, + ..self + } + } + + /// Get the partition start and end + /// + /// The offsets are in 4 KiB sectors, inclusive. + pub fn get_first_last_sectors(&self) -> (u16, u16) { + ( + (self.permissions_and_location & 0x0000_1FFF) as u16, + ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16, + ) + } + + /// Get the partition start and end + /// + /// The offsets are in bytes, inclusive. + pub fn get_first_last_bytes(&self) -> (u32, u32) { + let (first, last) = self.get_first_last_sectors(); + (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095) + } + + /// Check if it has a permission + pub fn has_permission(&self, permission: Permission) -> bool { + let mask = permission as u32; + (self.permissions_and_flags & mask) != 0 + } + + /// Get which extra families are allowed in this partition + pub fn get_extra_families(&self) -> &[u32] { + &self.extra_families[0..self.extra_families_len] + } + + /// Get the name of the partition + /// + /// Returns `None` if there's no name, or the name is not valid UTF-8. + pub fn get_name(&self) -> Option<&str> { + let len = self.name[0] as usize; + if len == 0 { + None + } else { + core::str::from_utf8(&self.name[1..=len]).ok() + } + } + + /// Get the ID + pub fn get_id(&self) -> Option { + self.id + } + + /// Check if this partition is linked + pub fn get_link(&self) -> Link { + if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_A_PARTITION) != 0 { + let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8; + Link::ToA { partition_idx } + } else if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_OWNER) != 0 { + let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8; + Link::ToOwner { partition_idx } + } else { + Link::Nothing + } + } + + /// Check if the partition has a flag set + pub fn has_flag(&self, flag: PartitionFlag) -> bool { + let mask = flag as u32; + (self.permissions_and_flags & mask) != 0 + } +} + +impl core::fmt::Display for Partition { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let (first, last) = self.get_first_last_bytes(); + write!( + f, + "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}", + first, + last, + if self.has_permission(Permission::SecureRead) { + 'R' + } else { + '_' + }, + if self.has_permission(Permission::SecureWrite) { + 'W' + } else { + '_' + }, + if self.has_permission(Permission::NonSecureRead) { + 'R' + } else { + '_' + }, + if self.has_permission(Permission::NonSecureWrite) { + 'W' + } else { + '_' + }, + if self.has_permission(Permission::BootRead) { + 'R' + } else { + '_' + }, + if self.has_permission(Permission::BootWrite) { + 'W' + } else { + '_' + } + ) + } +} + +/// Describes a partition table. +/// +/// Don't store this as a static - make sure you convert it to a block. +#[derive(Clone)] +pub struct PartitionTableBlock { + /// This must look like a block, including the 1 word header and the 3 word footer. + contents: [u32; PARTITION_TABLE_MAX_ITEMS], + /// This value doesn't include the 1 word header or the 3 word footer + num_items: usize, +} + +impl PartitionTableBlock { + /// Create an empty Block, big enough for a partition table. + /// + /// At a minimum you need to call [`Self::add_partition_item`]. + pub const fn new() -> PartitionTableBlock { + let mut contents = [0; PARTITION_TABLE_MAX_ITEMS]; + contents[0] = BLOCK_MARKER_START; + contents[1] = item_last(0); + contents[2] = 0; + contents[3] = BLOCK_MARKER_END; + PartitionTableBlock { contents, num_items: 0 } + } + + /// Add a partition to the partition table + pub const fn add_partition_item(self, unpartitioned: UnpartitionedSpace, partitions: &[Partition]) -> Self { + let mut new_table = PartitionTableBlock::new(); + let mut idx = 0; + // copy over old table, with the header but not the footer + while idx < self.num_items + 1 { + new_table.contents[idx] = self.contents[idx]; + idx += 1; + } + + // 1. add item header space (we fill this in later) + let header_idx = idx; + new_table.contents[idx] = 0; + idx += 1; + + // 2. unpartitioned space flags + // + // (the location of unpartition space is not recorded here - it is + // inferred because the unpartitioned space is where the partitions are + // not) + new_table.contents[idx] = unpartitioned.permissions_and_flags; + idx += 1; + + // 3. partition info + + let mut partition_no = 0; + while partition_no < partitions.len() { + // a. permissions_and_location (4K units) + new_table.contents[idx] = partitions[partition_no].permissions_and_location; + idx += 1; + + // b. permissions_and_flags + new_table.contents[idx] = partitions[partition_no].permissions_and_flags; + idx += 1; + + // c. ID + if let Some(id) = partitions[partition_no].id { + new_table.contents[idx] = id as u32; + new_table.contents[idx + 1] = (id >> 32) as u32; + idx += 2; + } + + // d. Extra Families + let mut extra_families_idx = 0; + while extra_families_idx < partitions[partition_no].extra_families_len { + new_table.contents[idx] = partitions[partition_no].extra_families[extra_families_idx]; + idx += 1; + extra_families_idx += 1; + } + + // e. Name + let mut name_idx = 0; + while name_idx < partitions[partition_no].name[0] as usize { + let name_chunk = [ + partitions[partition_no].name[name_idx], + partitions[partition_no].name[name_idx + 1], + partitions[partition_no].name[name_idx + 2], + partitions[partition_no].name[name_idx + 3], + ]; + new_table.contents[idx] = u32::from_le_bytes(name_chunk); + name_idx += 4; + idx += 1; + } + + partition_no += 1; + } + + let len = idx - header_idx; + new_table.contents[header_idx] = item_generic_2bs(partitions.len() as u8, len as u16, ITEM_2BS_PARTITION_TABLE); + + // 7. New Footer + new_table.contents[idx] = item_last(idx as u16 - 1); + new_table.contents[idx + 1] = 0; + new_table.contents[idx + 2] = BLOCK_MARKER_END; + + // ignore the header + new_table.num_items = idx - 1; + new_table + } + + /// Add a version number to the partition table + pub const fn with_version(self, major: u16, minor: u16) -> Self { + let mut new_table = PartitionTableBlock::new(); + let mut idx = 0; + // copy over old table, with the header but not the footer + while idx < self.num_items + 1 { + new_table.contents[idx] = self.contents[idx]; + idx += 1; + } + + // 1. add item + new_table.contents[idx] = item_generic_2bs(0, 2, ITEM_1BS_VERSION); + idx += 1; + new_table.contents[idx] = (major as u32) << 16 | minor as u32; + idx += 1; + + // 2. New Footer + new_table.contents[idx] = item_last(idx as u16 - 1); + new_table.contents[idx + 1] = 0; + new_table.contents[idx + 2] = BLOCK_MARKER_END; + + // ignore the header + new_table.num_items = idx - 1; + new_table + } + + /// Add a a SHA256 hash of the Block + /// + /// Adds a `HASH_DEF` covering all the previous items in the Block, and a + /// `HASH_VALUE` with a SHA-256 hash of them. + pub const fn with_sha256(self) -> Self { + let mut new_table = PartitionTableBlock::new(); + let mut idx = 0; + // copy over old table, with the header but not the footer + while idx < self.num_items + 1 { + new_table.contents[idx] = self.contents[idx]; + idx += 1; + } + + // 1. HASH_DEF says what is hashed + new_table.contents[idx] = item_generic_2bs(1, 2, ITEM_2BS_HASH_DEF); + idx += 1; + // we're hashing all the previous contents - including this line. + new_table.contents[idx] = (idx + 1) as u32; + idx += 1; + + // calculate hash over prior contents + let input = unsafe { core::slice::from_raw_parts(new_table.contents.as_ptr() as *const u8, idx * 4) }; + let hash: [u8; 32] = sha2_const_stable::Sha256::new().update(input).finalize(); + + // 2. HASH_VALUE contains the hash + new_table.contents[idx] = item_generic_2bs(0, 9, ITEM_1BS_HASH_VALUE); + idx += 1; + + let mut hash_idx = 0; + while hash_idx < hash.len() { + new_table.contents[idx] = u32::from_le_bytes([ + hash[hash_idx], + hash[hash_idx + 1], + hash[hash_idx + 2], + hash[hash_idx + 3], + ]); + idx += 1; + hash_idx += 4; + } + + // 3. New Footer + new_table.contents[idx] = item_last(idx as u16 - 1); + new_table.contents[idx + 1] = 0; + new_table.contents[idx + 2] = BLOCK_MARKER_END; + + // ignore the header + new_table.num_items = idx - 1; + new_table + } +} + +impl Default for PartitionTableBlock { + fn default() -> Self { + Self::new() + } +} + +/// Flags that a Partition can have +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u32)] +#[allow(missing_docs)] +pub enum PartitionFlag { + NotBootableArm = 1 << 9, + NotBootableRiscv = 1 << 10, + Uf2DownloadAbNonBootableOwnerAffinity = 1 << 11, + Uf2DownloadNoReboot = 1 << 13, + AcceptsDefaultFamilyRp2040 = 1 << 14, + AcceptsDefaultFamilyData = 1 << 16, + AcceptsDefaultFamilyRp2350ArmS = 1 << 17, + AcceptsDefaultFamilyRp2350Riscv = 1 << 18, + AcceptsDefaultFamilyRp2350ArmNs = 1 << 19, +} + +/// Flags that a Partition can have +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u32)] +#[allow(missing_docs)] +pub enum UnpartitionedFlag { + Uf2DownloadNoReboot = 1 << 13, + AcceptsDefaultFamilyRp2040 = 1 << 14, + AcceptsDefaultFamilyAbsolute = 1 << 15, + AcceptsDefaultFamilyData = 1 << 16, + AcceptsDefaultFamilyRp2350ArmS = 1 << 17, + AcceptsDefaultFamilyRp2350Riscv = 1 << 18, + AcceptsDefaultFamilyRp2350ArmNs = 1 << 19, +} + +/// Kinds of linked partition +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Link { + /// Not linked to anything + Nothing, + /// This is a B partition - link to our A partition. + ToA { + /// The index of our matching A partition. + partition_idx: u8, + }, + /// Link to the partition that owns this one. + ToOwner { + /// The idx of our owner + partition_idx: u8, + }, +} + +/// Permissions that a Partition can have +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u32)] +pub enum Permission { + /// Can be read in Secure Mode + /// + /// Corresponds to `PERMISSION_S_R_BITS` in the Pico SDK + SecureRead = 1 << 26, + /// Can be written in Secure Mode + /// + /// Corresponds to `PERMISSION_S_W_BITS` in the Pico SDK + SecureWrite = 1 << 27, + /// Can be read in Non-Secure Mode + /// + /// Corresponds to `PERMISSION_NS_R_BITS` in the Pico SDK + NonSecureRead = 1 << 28, + /// Can be written in Non-Secure Mode + /// + /// Corresponds to `PERMISSION_NS_W_BITS` in the Pico SDK + NonSecureWrite = 1 << 29, + /// Can be read in Non-Secure Bootloader mode + /// + /// Corresponds to `PERMISSION_NSBOOT_R_BITS` in the Pico SDK + BootRead = 1 << 30, + /// Can be written in Non-Secure Bootloader mode + /// + /// Corresponds to `PERMISSION_NSBOOT_W_BITS` in the Pico SDK + BootWrite = 1 << 31, +} + +impl Permission { + /// Is this permission bit set this in this bitmask? + pub const fn is_in(self, mask: u32) -> bool { + (mask & (self as u32)) != 0 + } +} + +/// The supported RP2350 CPU architectures +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Architecture { + /// Core is in Arm Cortex-M33 mode + Arm, + /// Core is in RISC-V / Hazard3 mode + Riscv, +} + +/// The kinds of Secure Boot we support +#[derive(Debug, Copy, Clone)] +pub enum Security { + /// Security mode not given + Unspecified, + /// Start in Non-Secure mode + NonSecure, + /// Start in Secure mode + Secure, +} + +/// Make an item containing a tag, 1 byte length and two extra bytes. +/// +/// The `command` arg should contain `1BS` +pub const fn item_generic_1bs(value: u16, length: u8, command: u8) -> u32 { + ((value as u32) << 16) | ((length as u32) << 8) | (command as u32) +} + +/// Make an item containing a tag, 2 byte length and one extra byte. +/// +/// The `command` arg should contain `2BS` +pub const fn item_generic_2bs(value: u8, length: u16, command: u8) -> u32 { + ((value as u32) << 24) | ((length as u32) << 8) | (command as u32) +} + +/// Create Image Type item, of type IGNORED. +pub const fn item_ignored() -> u32 { + item_generic_2bs(0, 1, ITEM_2BS_IGNORED) +} + +/// Create Image Type item, of type INVALID. +pub const fn item_image_type_invalid() -> u32 { + let value = IMAGE_TYPE_INVALID; + item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE) +} + +/// Create Image Type item, of type DATA. +pub const fn item_image_type_data() -> u32 { + let value = IMAGE_TYPE_DATA; + item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE) +} + +/// Create Image Type item, of type EXE. +pub const fn item_image_type_exe(security: Security, arch: Architecture) -> u32 { + let mut value = IMAGE_TYPE_EXE | IMAGE_TYPE_EXE_CHIP_RP2350; + + match arch { + Architecture::Arm => { + value |= IMAGE_TYPE_EXE_CPU_ARM; + } + Architecture::Riscv => { + value |= IMAGE_TYPE_EXE_CPU_RISCV; + } + } + + match security { + Security::Unspecified => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED, + Security::NonSecure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_NS, + Security::Secure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_S, + } + + item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE) +} + +/// Create a Block Last item. +pub const fn item_last(length: u16) -> u32 { + item_generic_2bs(0, length, ITEM_2BS_LAST) +} + +/// Create a Vector Table item. +/// +/// This is only allowed on Arm systems. +pub const fn item_vector_table(table_ptr: u32) -> [u32; 2] { + [item_generic_1bs(0, 2, ITEM_1BS_VECTOR_TABLE), table_ptr] +} + +/// Create an Entry Point item. +pub const fn item_entry_point(entry_point: u32, initial_sp: u32) -> [u32; 3] { + [item_generic_1bs(0, 3, ITEM_1BS_ENTRY_POINT), entry_point, initial_sp] +} + +/// Create an Rolling Window item. +/// +/// The delta is the number of bytes into the image that 0x10000000 should +/// be mapped. +pub const fn item_rolling_window(delta: u32) -> [u32; 2] { + [item_generic_1bs(0, 3, ITEM_1BS_ROLLING_WINDOW_DELTA), delta] +} + +#[cfg(test)] +mod test { + use super::*; + + /// I used this JSON, with `picotool partition create`: + /// + /// ```json + /// { + /// "version": [1, 0], + /// "unpartitioned": { + /// "families": ["absolute"], + /// "permissions": { + /// "secure": "rw", + /// "nonsecure": "rw", + /// "bootloader": "rw" + /// } + /// }, + /// "partitions": [ + /// { + /// "name": "A", + /// "id": 0, + /// "size": "2044K", + /// "families": ["rp2350-arm-s", "rp2350-riscv"], + /// "permissions": { + /// "secure": "rw", + /// "nonsecure": "rw", + /// "bootloader": "rw" + /// } + /// }, + /// { + /// "name": "B", + /// "id": 1, + /// "size": "2044K", + /// "families": ["rp2350-arm-s", "rp2350-riscv"], + /// "permissions": { + /// "secure": "rw", + /// "nonsecure": "rw", + /// "bootloader": "rw" + /// }, + /// "link": ["a", 0] + /// } + /// ] + /// } + /// ``` + #[test] + fn make_hashed_partition_table() { + let table = PartitionTableBlock::new() + .add_partition_item( + UnpartitionedSpace::new() + .with_permission(Permission::SecureRead) + .with_permission(Permission::SecureWrite) + .with_permission(Permission::NonSecureRead) + .with_permission(Permission::NonSecureWrite) + .with_permission(Permission::BootRead) + .with_permission(Permission::BootWrite) + .with_flag(UnpartitionedFlag::AcceptsDefaultFamilyAbsolute), + &[ + Partition::new(2, 512) + .with_id(0) + .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS) + .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv) + .with_permission(Permission::SecureRead) + .with_permission(Permission::SecureWrite) + .with_permission(Permission::NonSecureRead) + .with_permission(Permission::NonSecureWrite) + .with_permission(Permission::BootRead) + .with_permission(Permission::BootWrite) + .with_name("A"), + Partition::new(513, 1023) + .with_id(1) + .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS) + .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv) + .with_link(Link::ToA { partition_idx: 0 }) + .with_permission(Permission::SecureRead) + .with_permission(Permission::SecureWrite) + .with_permission(Permission::NonSecureRead) + .with_permission(Permission::NonSecureWrite) + .with_permission(Permission::BootRead) + .with_permission(Permission::BootWrite) + .with_name("B"), + ], + ) + .with_version(1, 0) + .with_sha256(); + let expected = &[ + 0xffffded3, // start + 0x02000c0a, // Item = PARTITION_TABLE + 0xfc008000, // Unpartitioned Space - permissions_and_flags + 0xfc400002, // Partition 0 - permissions_and_location (512 * 4096, 2 * 4096) + 0xfc061001, // permissions_and_flags HAS_ID | HAS_NAME | ARM-S | RISC-V + 0x00000000, // ID + 0x00000000, // ID + 0x00004101, // Name ("A") + 0xfc7fe201, // Partition 1 - permissions_and_location (1023 * 4096, 513 * 4096) + 0xfc061003, // permissions_and_flags LINKA(0) | HAS_ID | HAS_NAME | ARM-S | RISC-V + 0x00000001, // ID + 0x00000000, // ID + 0x00004201, // Name ("B") + 0x00000248, // Item = Version + 0x00010000, // 0, 1 + 0x01000247, // HASH_DEF with 2 words, and SHA256 hash + 0x00000011, // 17 words hashed + 0x0000094b, // HASH_VALUE with 9 words + 0x1945cdad, // Hash word 0 + 0x6b5f9773, // Hash word 1 + 0xe2bf39bd, // Hash word 2 + 0xb243e599, // Hash word 3 + 0xab2f0e9a, // Hash word 4 + 0x4d5d6d0b, // Hash word 5 + 0xf973050f, // Hash word 6 + 0x5ab6dadb, // Hash word 7 + 0x000019ff, // Last Item + 0x00000000, // Block Loop Next Offset + 0xab123579, // End + ]; + core::assert_eq!( + &table.contents[..29], + expected, + "{:#010x?}\n != \n{:#010x?}", + &table.contents[0..29], + expected, + ); + } +} diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index d0c6c19bd..9f387b70f 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,12 +1,17 @@ //! Clock configuration for the RP2040 + +#[cfg(feature = "rp2040")] use core::arch::asm; use core::marker::PhantomData; -use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; +#[cfg(feature = "rp2040")] +use core::sync::atomic::AtomicU16; +use core::sync::atomic::{AtomicU32, Ordering}; use embassy_hal_internal::{into_ref, PeripheralRef}; use pac::clocks::vals::*; use crate::gpio::{AnyPin, SealedPin}; +#[cfg(feature = "rp2040")] use crate::pac::common::{Reg, RW}; use crate::{pac, reset, Peripheral}; @@ -26,6 +31,7 @@ struct Clocks { // gpin1: AtomicU32, rosc: AtomicU32, peri: AtomicU32, + #[cfg(feature = "rp2040")] rtc: AtomicU16, } @@ -41,6 +47,7 @@ static CLOCKS: Clocks = Clocks { // gpin1: AtomicU32::new(0), rosc: AtomicU32::new(0), peri: AtomicU32::new(0), + #[cfg(feature = "rp2040")] rtc: AtomicU16::new(0), }; @@ -81,6 +88,7 @@ pub struct ClockConfig { /// ADC clock configuration. pub adc_clk: Option, /// RTC clock configuration. + #[cfg(feature = "rp2040")] pub rtc_clk: Option, // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, @@ -135,6 +143,7 @@ impl ClockConfig { phase: 0, }), // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz + #[cfg(feature = "rp2040")] rtc_clk: Some(RtcClkConfig { src: RtcClkSrc::PllUsb, div_int: 1024, @@ -174,6 +183,7 @@ impl ClockConfig { phase: 0, }), // CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz + #[cfg(feature = "rp2040")] rtc_clk: Some(RtcClkConfig { src: RtcClkSrc::Rosc, div_int: 2986, @@ -295,9 +305,17 @@ pub struct SysClkConfig { /// SYS clock source. pub src: SysClkSrc, /// SYS clock divider. + #[cfg(feature = "rp2040")] pub div_int: u32, /// SYS clock fraction. + #[cfg(feature = "rp2040")] pub div_frac: u8, + /// SYS clock divider. + #[cfg(feature = "rp235x")] + pub div_int: u16, + /// SYS clock fraction. + #[cfg(feature = "rp235x")] + pub div_frac: u16, } /// USB clock source. @@ -358,6 +376,7 @@ pub struct AdcClkConfig { #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg(feature = "rp2040")] pub enum RtcClkSrc { /// PLL USB. PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, @@ -372,6 +391,7 @@ pub enum RtcClkSrc { } /// RTC clock config. +#[cfg(feature = "rp2040")] pub struct RtcClkConfig { /// RTC clock source. pub src: RtcClkSrc, @@ -396,10 +416,9 @@ pub(crate) unsafe fn init(config: ClockConfig) { peris.set_pads_qspi(false); peris.set_pll_sys(false); peris.set_pll_usb(false); - // TODO investigate if usb should be unreset here peris.set_usbctrl(false); peris.set_syscfg(false); - peris.set_rtc(false); + //peris.set_rtc(false); reset::reset(peris); // Disable resus that may be enabled from previous software @@ -409,9 +428,15 @@ pub(crate) unsafe fn init(config: ClockConfig) { // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); + #[cfg(feature = "rp2040")] while c.clk_sys_selected().read() != 1 {} + #[cfg(feature = "rp235x")] + while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1) {} c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); + #[cfg(feature = "rp2040")] while c.clk_ref_selected().read() != 1 {} + #[cfg(feature = "rp235x")] + while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {} // Reset the PLLs let mut peris = reset::Peripherals(0); @@ -479,11 +504,16 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_src(ref_src); w.set_auxsrc(ref_aux); }); - while c.clk_ref_selected().read() != 1 << ref_src as u32 {} + #[cfg(feature = "rp2040")] + while c.clk_ref_selected().read() != (1 << ref_src as u32) {} + #[cfg(feature = "rp235x")] + while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ref_src as u32) {} c.clk_ref_div().write(|w| { w.set_int(config.ref_clk.div); }); + // Configure tick generation on the 2040. On the 2350 the timers are driven from the sysclk. + #[cfg(feature = "rp2040")] pac::WATCHDOG.tick().write(|w| { w.set_cycles((clk_ref_freq / 1_000_000) as u16); w.set_enable(true); @@ -500,7 +530,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), }; - assert!(config.sys_clk.div_int <= 0x1000000); let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64; (src, aux, ((freq as u64 * 256) / div) as u32) }; @@ -508,13 +537,21 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); if sys_src != ClkSysCtrlSrc::CLK_REF { c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); - while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {} + #[cfg(feature = "rp2040")] + while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLK_REF as u32) {} + #[cfg(feature = "rp235x")] + while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLK_REF as u32) {} } c.clk_sys_ctrl().write(|w| { w.set_auxsrc(sys_aux); w.set_src(sys_src); }); - while c.clk_sys_selected().read() != 1 << sys_src as u32 {} + + #[cfg(feature = "rp2040")] + while c.clk_sys_selected().read() != (1 << sys_src as u32) {} + #[cfg(feature = "rp235x")] + while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << sys_src as u32) {} + c.clk_sys_div().write(|w| { w.set_int(config.sys_clk.div_int); w.set_frac(config.sys_clk.div_frac); @@ -592,6 +629,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.adc.store(0, Ordering::Relaxed); } + // rp2040 specific clocks + #[cfg(feature = "rp2040")] if let Some(conf) = config.rtc_clk { c.clk_rtc_div().write(|w| { w.set_int(conf.div_int); @@ -621,6 +660,13 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.rtc.store(0, Ordering::Relaxed); } + // rp235x specific clocks + #[cfg(feature = "rp235x")] + { + // TODO hstx clock + peris.set_hstx(false); + } + // Peripheral clocks should now all be running reset::unreset_wait(peris); } @@ -709,6 +755,7 @@ pub fn clk_adc_freq() -> u32 { } /// RTC clock frequency. +#[cfg(feature = "rp2040")] pub fn clk_rtc_freq() -> u16 { CLOCKS.rtc.load(Ordering::Relaxed) } @@ -855,8 +902,8 @@ pub enum GpoutSrc { Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, /// ADC. Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, - /// RTC. - Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, + // RTC. + //Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, /// REF. Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, } @@ -877,6 +924,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { } /// Set clock divider. + #[cfg(feature = "rp2040")] pub fn set_div(&self, int: u32, frac: u8) { let c = pac::CLOCKS; c.clk_gpout_div(self.gpout.number()).write(|w| { @@ -885,6 +933,16 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { }); } + /// Set clock divider. + #[cfg(feature = "rp235x")] + pub fn set_div(&self, int: u16, frac: u16) { + let c = pac::CLOCKS; + c.clk_gpout_div(self.gpout.number()).write(|w| { + w.set_int(int); + w.set_frac(frac); + }); + } + /// Set clock source. pub fn set_src(&self, src: GpoutSrc) { let c = pac::CLOCKS; @@ -924,13 +982,13 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), - ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _, + //ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _, ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), _ => unreachable!(), }; let div = c.clk_gpout_div(self.gpout.number()).read(); - let int = if div.int() == 0 { 65536 } else { div.int() } as u64; + let int = if div.int() == 0 { 0xFFFF } else { div.int() } as u64; let frac = div.frac() as u64; ((base as u64 * 256) / (int * 256 + frac)) as u32 @@ -987,7 +1045,7 @@ impl rand_core::RngCore for RoscRng { /// and can only be exited through resets, dormant-wake GPIO interrupts, /// and RTC interrupts. If RTC is clocked from an internal clock source /// it will be stopped and not function as a wakeup source. -#[cfg(target_arch = "arm")] +#[cfg(all(target_arch = "arm", feature = "rp2040"))] pub fn dormant_sleep() { struct Set(Reg, T, F); @@ -1107,7 +1165,7 @@ pub fn dormant_sleep() { coma = in (reg) 0x636f6d61, ); } else { - pac::ROSC.dormant().write_value(0x636f6d61); + pac::ROSC.dormant().write_value(rp_pac::rosc::regs::Dormant(0x636f6d61)); } } } diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 8c04b43a1..df10da0b6 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -45,7 +45,7 @@ pub unsafe fn read<'a, C: Channel, W: Word>( ch: impl Peripheral

+ 'a, from: *const W, to: *mut [W], - dreq: u8, + dreq: vals::TreqSel, ) -> Transfer<'a, C> { copy_inner( ch, @@ -66,7 +66,7 @@ pub unsafe fn write<'a, C: Channel, W: Word>( ch: impl Peripheral

+ 'a, from: *const [W], to: *mut W, - dreq: u8, + dreq: vals::TreqSel, ) -> Transfer<'a, C> { copy_inner( ch, @@ -90,7 +90,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>( ch: impl Peripheral

+ 'a, to: *mut W, len: usize, - dreq: u8, + dreq: vals::TreqSel, ) -> Transfer<'a, C> { copy_inner( ch, @@ -123,7 +123,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>( W::size(), true, true, - vals::TreqSel::PERMANENT.0, + vals::TreqSel::PERMANENT, ) } @@ -135,7 +135,7 @@ fn copy_inner<'a, C: Channel>( data_size: DataSize, incr_read: bool, incr_write: bool, - dreq: u8, + dreq: vals::TreqSel, ) -> Transfer<'a, C> { into_ref!(ch); @@ -143,14 +143,20 @@ fn copy_inner<'a, C: Channel>( p.read_addr().write_value(from as u32); p.write_addr().write_value(to as u32); - p.trans_count().write_value(len as u32); + #[cfg(feature = "rp2040")] + p.trans_count().write(|w| { + *w = len as u32; + }); + #[cfg(feature = "rp235x")] + p.trans_count().write(|w| { + w.set_mode(0.into()); + w.set_count(len as u32); + }); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { - // TODO: Add all DREQ options to pac vals::TreqSel, and use - // `set_treq:sel` - w.0 = ((dreq as u32) & 0x3f) << 15usize; + w.set_treq_sel(dreq); w.set_data_size(data_size); w.set_incr_read(incr_read); w.set_incr_write(incr_write); @@ -297,3 +303,11 @@ channel!(DMA_CH8, 8); channel!(DMA_CH9, 9); channel!(DMA_CH10, 10); channel!(DMA_CH11, 11); +#[cfg(feature = "rp235x")] +channel!(DMA_CH12, 12); +#[cfg(feature = "rp235x")] +channel!(DMA_CH13, 13); +#[cfg(feature = "rp235x")] +channel!(DMA_CH14, 14); +#[cfg(feature = "rp235x")] +channel!(DMA_CH15, 15); diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 9e4542b2f..cc84bb12d 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -302,7 +302,14 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on // general XIP access. const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _; - let transfer = unsafe { crate::dma::read(self.dma.as_mut().unwrap(), XIP_AUX_BASE, data, 37) }; + let transfer = unsafe { + crate::dma::read( + self.dma.as_mut().unwrap(), + XIP_AUX_BASE, + data, + pac::dma::vals::TreqSel::XIP_STREAM, + ) + }; Ok(BackgroundRead { flash: PhantomData, @@ -597,6 +604,7 @@ mod ram_helpers { /// addr must be aligned to 4096 #[inline(never)] #[link_section = ".data.ram_func"] + #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { /* Should be equivalent to: @@ -659,6 +667,11 @@ mod ram_helpers { ); } + #[inline(never)] + #[link_section = ".data.ram_func"] + #[cfg(feature = "rp235x")] + unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) {} + #[repr(C)] struct FlashCommand { cmd_addr: *const u8, @@ -758,6 +771,7 @@ mod ram_helpers { /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) #[inline(never)] #[link_section = ".data.ram_func"] + #[cfg(feature = "rp2040")] unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] core::arch::asm!( @@ -874,6 +888,11 @@ mod ram_helpers { clobber_abi("C"), ); } + + #[inline(never)] + #[link_section = ".data.ram_func"] + #[cfg(feature = "rp235x")] + unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) {} } /// Make sure to uphold the contract points with rp2040-flash. @@ -887,7 +906,7 @@ pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> { } // Make sure CORE1 is paused during the entire duration of the RAM function - crate::multicore::pause_core1(); + //crate::multicore::pause_core1(); critical_section::with(|_| { // Wait for all DMA channels in flash to finish before ram operation @@ -904,7 +923,7 @@ pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> { }); // Resume CORE1 execution - crate::multicore::resume_core1(); + //crate::multicore::resume_core1(); Ok(()) } diff --git a/embassy-rp/src/float/mod.rs b/embassy-rp/src/float/mod.rs index 3ad6f1c50..1df8c0e08 100644 --- a/embassy-rp/src/float/mod.rs +++ b/embassy-rp/src/float/mod.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "rp2040")] // Credit: taken from `rp-hal` (also licensed Apache+MIT) // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/float/mod.rs diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index ea87fd9da..8d6a8f2bd 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -178,6 +178,13 @@ impl<'d> Input<'d> { pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> { self.pin.dormant_wake(cfg) } + + /// Set the pin's pad isolation + #[cfg(feature = "rp235x")] + #[inline] + pub fn set_pad_isolation(&mut self, isolate: bool) { + self.pin.set_pad_isolation(isolate) + } } /// Interrupt trigger levels. @@ -413,6 +420,13 @@ impl<'d> Output<'d> { pub fn toggle(&mut self) { self.pin.toggle() } + + /// Set the pin's pad isolation + #[cfg(feature = "rp235x")] + #[inline] + pub fn set_pad_isolation(&mut self, isolate: bool) { + self.pin.set_pad_isolation(isolate) + } } /// GPIO output open-drain. @@ -539,6 +553,13 @@ impl<'d> OutputOpenDrain<'d> { pub async fn wait_for_any_edge(&mut self) { self.pin.wait_for_any_edge().await; } + + /// Set the pin's pad isolation + #[cfg(feature = "rp235x")] + #[inline] + pub fn set_pad_isolation(&mut self, isolate: bool) { + self.pin.set_pad_isolation(isolate) + } } /// GPIO flexible pin. @@ -564,7 +585,15 @@ impl<'d> Flex<'d> { }); pin.gpio().ctrl().write(|w| { + #[cfg(feature = "rp2040")] w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _); + #[cfg(feature = "rp235x")] + w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIOB_PROC_0 as _); + }); + + #[cfg(feature = "rp235x")] + pin.pad_ctrl().modify(|w| { + w.set_iso(false); }); Self { pin: pin.map_into() } @@ -760,6 +789,15 @@ impl<'d> Flex<'d> { cfg, } } + + /// Set the pin's pad isolation + #[cfg(feature = "rp235x")] + #[inline] + pub fn set_pad_isolation(&mut self, isolate: bool) { + self.pin.pad_ctrl().modify(|w| { + w.set_iso(isolate); + }); + } } impl<'d> Drop for Flex<'d> { @@ -956,6 +994,44 @@ impl_pin!(PIN_27, Bank::Bank0, 27); impl_pin!(PIN_28, Bank::Bank0, 28); impl_pin!(PIN_29, Bank::Bank0, 29); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_30, Bank::Bank0, 30); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_31, Bank::Bank0, 31); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_32, Bank::Bank0, 32); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_33, Bank::Bank0, 33); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_34, Bank::Bank0, 34); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_35, Bank::Bank0, 35); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_36, Bank::Bank0, 36); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_37, Bank::Bank0, 37); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_38, Bank::Bank0, 38); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_39, Bank::Bank0, 39); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_40, Bank::Bank0, 40); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_41, Bank::Bank0, 41); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_42, Bank::Bank0, 42); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_43, Bank::Bank0, 43); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_44, Bank::Bank0, 44); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_45, Bank::Bank0, 45); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_46, Bank::Bank0, 46); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_47, Bank::Bank0, 47); + +// TODO rp235x bank1 as gpio support #[cfg(feature = "qspi-as-gpio")] impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0); #[cfg(feature = "qspi-as-gpio")] diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index ac2b1bc5a..d95b17ff1 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -884,3 +884,39 @@ impl_pin!(PIN_26, I2C1, SdaPin); impl_pin!(PIN_27, I2C1, SclPin); impl_pin!(PIN_28, I2C0, SdaPin); impl_pin!(PIN_29, I2C0, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_30, I2C1, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_31, I2C1, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_32, I2C0, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_33, I2C0, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_34, I2C1, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_35, I2C1, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_36, I2C0, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_37, I2C0, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_38, I2C1, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_39, I2C1, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_40, I2C0, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_41, I2C0, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_42, I2C1, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_43, I2C1, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_44, I2C0, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_45, I2C0, SclPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_46, I2C1, SdaPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_47, I2C1, SclPin); diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 471e7f8b1..c5b2498b4 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -15,6 +15,11 @@ mod critical_section_impl; mod intrinsics; pub mod adc; +#[cfg(feature = "rp235x")] +pub mod binary_info; +#[cfg(feature = "rp235x")] +pub mod block; +#[cfg(feature = "rp2040")] pub mod bootsel; pub mod clocks; pub mod dma; @@ -41,14 +46,20 @@ pub(crate) mod relocate; // Reexports pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -#[cfg(feature = "unstable-pac")] +#[cfg(all(feature = "unstable-pac", feature = "rp235x"))] +pub use rp23_pac as pac; +#[cfg(all(feature = "unstable-pac", feature = "rp2040"))] pub use rp_pac as pac; -#[cfg(not(feature = "unstable-pac"))] + +#[cfg(all(not(feature = "unstable-pac"), feature = "rp235x"))] +pub(crate) use rp23_pac as pac; +#[cfg(all(not(feature = "unstable-pac"), feature = "rp2040"))] pub(crate) use rp_pac as pac; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; +#[cfg(feature = "rp2040")] embassy_hal_internal::interrupt_mod!( TIMER_IRQ_0, TIMER_IRQ_1, @@ -84,6 +95,54 @@ embassy_hal_internal::interrupt_mod!( SWI_IRQ_5, ); +#[cfg(feature = "rp235x")] +embassy_hal_internal::interrupt_mod!( + TIMER0_IRQ_0, + TIMER0_IRQ_1, + TIMER0_IRQ_2, + TIMER0_IRQ_3, + TIMER1_IRQ_0, + TIMER1_IRQ_1, + TIMER1_IRQ_2, + TIMER1_IRQ_3, + PWM_IRQ_WRAP_0, + PWM_IRQ_WRAP_1, + DMA_IRQ_0, + DMA_IRQ_1, + USBCTRL_IRQ, + PIO0_IRQ_0, + PIO0_IRQ_1, + PIO1_IRQ_0, + PIO1_IRQ_1, + PIO2_IRQ_0, + PIO2_IRQ_1, + IO_IRQ_BANK0, + IO_IRQ_BANK0_NS, + IO_IRQ_QSPI, + IO_IRQ_QSPI_NS, + SIO_IRQ_FIFO, + SIO_IRQ_BELL, + SIO_IRQ_FIFO_NS, + SIO_IRQ_BELL_NS, + CLOCKS_IRQ, + SPI0_IRQ, + SPI1_IRQ, + UART0_IRQ, + UART1_IRQ, + ADC_IRQ_FIFO, + I2C0_IRQ, + I2C1_IRQ, + TRNG_IRQ, + PLL_SYS_IRQ, + PLL_USB_IRQ, + SWI_IRQ_0, + SWI_IRQ_1, + SWI_IRQ_2, + SWI_IRQ_3, + SWI_IRQ_4, + SWI_IRQ_5, +); + /// Macro to bind interrupts to handlers. /// /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) @@ -123,6 +182,7 @@ macro_rules! bind_interrupts { }; } +#[cfg(feature = "rp2040")] embassy_hal_internal::peripherals! { PIN_0, PIN_1, @@ -210,6 +270,139 @@ embassy_hal_internal::peripherals! { BOOTSEL, } +#[cfg(feature = "rp235x")] +embassy_hal_internal::peripherals! { + PIN_0, + PIN_1, + PIN_2, + PIN_3, + PIN_4, + PIN_5, + PIN_6, + PIN_7, + PIN_8, + PIN_9, + PIN_10, + PIN_11, + PIN_12, + PIN_13, + PIN_14, + PIN_15, + PIN_16, + PIN_17, + PIN_18, + PIN_19, + PIN_20, + PIN_21, + PIN_22, + PIN_23, + PIN_24, + PIN_25, + PIN_26, + PIN_27, + PIN_28, + PIN_29, + #[cfg(feature = "rp235xb")] + PIN_30, + #[cfg(feature = "rp235xb")] + PIN_31, + #[cfg(feature = "rp235xb")] + PIN_32, + #[cfg(feature = "rp235xb")] + PIN_33, + #[cfg(feature = "rp235xb")] + PIN_34, + #[cfg(feature = "rp235xb")] + PIN_35, + #[cfg(feature = "rp235xb")] + PIN_36, + #[cfg(feature = "rp235xb")] + PIN_37, + #[cfg(feature = "rp235xb")] + PIN_38, + #[cfg(feature = "rp235xb")] + PIN_39, + #[cfg(feature = "rp235xb")] + PIN_40, + #[cfg(feature = "rp235xb")] + PIN_41, + #[cfg(feature = "rp235xb")] + PIN_42, + #[cfg(feature = "rp235xb")] + PIN_43, + #[cfg(feature = "rp235xb")] + PIN_44, + #[cfg(feature = "rp235xb")] + PIN_45, + #[cfg(feature = "rp235xb")] + PIN_46, + #[cfg(feature = "rp235xb")] + PIN_47, + PIN_QSPI_SCLK, + PIN_QSPI_SS, + PIN_QSPI_SD0, + PIN_QSPI_SD1, + PIN_QSPI_SD2, + PIN_QSPI_SD3, + + UART0, + UART1, + + SPI0, + SPI1, + + I2C0, + I2C1, + + DMA_CH0, + DMA_CH1, + DMA_CH2, + DMA_CH3, + DMA_CH4, + DMA_CH5, + DMA_CH6, + DMA_CH7, + DMA_CH8, + DMA_CH9, + DMA_CH10, + DMA_CH11, + DMA_CH12, + DMA_CH13, + DMA_CH14, + DMA_CH15, + + PWM_SLICE0, + PWM_SLICE1, + PWM_SLICE2, + PWM_SLICE3, + PWM_SLICE4, + PWM_SLICE5, + PWM_SLICE6, + PWM_SLICE7, + PWM_SLICE8, + PWM_SLICE9, + PWM_SLICE10, + PWM_SLICE11, + + USB, + + RTC, + + FLASH, + + ADC, + ADC_TEMP_SENSOR, + + CORE1, + + PIO0, + PIO1, + PIO2, + + WATCHDOG, + BOOTSEL, +} + #[cfg(not(feature = "boot2-none"))] macro_rules! select_bootloader { ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { @@ -279,6 +472,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> { unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } } +#[cfg(feature = "rp2040")] #[inline(always)] fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { let core = unsafe { cortex_m::Peripherals::steal() }; @@ -306,6 +500,24 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } +#[cfg(feature = "rp235x")] +#[inline(always)] +fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { + let core = unsafe { cortex_m::Peripherals::steal() }; + + // Fail if MPU is already configured + if core.MPU.ctrl.read() != 0 { + return Err(()); + } + + unsafe { + core.MPU.ctrl.write(5); // enable mpu with background default map + core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address + core.MPU.rlar.write(1); // enable region + } + Ok(()) +} + /// HAL configuration for RP. pub mod config { use crate::clocks::ClockConfig; @@ -354,7 +566,7 @@ pub fn init(config: config::Config) -> Peripherals { peripherals } -#[cfg(feature = "rt")] +#[cfg(all(feature = "rt", feature = "rp2040"))] #[cortex_m_rt::pre_init] unsafe fn pre_init() { // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD. diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index d9d65694a..d1ce688ce 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -84,7 +84,7 @@ impl Stack { } } -#[cfg(feature = "rt")] +#[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] #[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_PROC1() { @@ -109,6 +109,31 @@ unsafe fn SIO_IRQ_PROC1() { } } +#[cfg(all(feature = "rt", feature = "rp235x"))] +#[interrupt] +#[link_section = ".data.ram_func"] +unsafe fn SIO_IRQ_FIFO() { + let sio = pac::SIO; + // Clear IRQ + sio.fifo().st().write(|w| w.set_wof(false)); + + while sio.fifo().st().read().vld() { + // Pause CORE1 execution and disable interrupts + if fifo_read_wfe() == PAUSE_TOKEN { + cortex_m::interrupt::disable(); + // Signal to CORE0 that execution is paused + fifo_write(PAUSE_TOKEN); + // Wait for `resume` signal from CORE0 + while fifo_read_wfe() != RESUME_TOKEN { + cortex_m::asm::nop(); + } + cortex_m::interrupt::enable(); + // Signal to CORE0 that execution is resumed + fifo_write(RESUME_TOKEN); + } + } +} + /// Spawn a function on this core pub fn spawn_core1(_core1: CORE1, stack: &'static mut Stack, entry: F) where @@ -135,7 +160,14 @@ where IS_CORE1_INIT.store(true, Ordering::Release); // Enable fifo interrupt on CORE1 for `pause` functionality. - unsafe { interrupt::SIO_IRQ_PROC1.enable() }; + #[cfg(feature = "rp2040")] + unsafe { + interrupt::SIO_IRQ_PROC1.enable() + }; + #[cfg(feature = "rp235x")] + unsafe { + interrupt::SIO_IRQ_FIFO.enable() + }; entry() } diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 1f7adbda3..89313086b 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -10,14 +10,11 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use fixed::types::extra::U8; use fixed::FixedU32; -use pac::io::vals::Gpio0ctrlFuncsel; -use pac::pio::vals::SmExecctrlStatusSel; use pio::{Program, SideSet, Wrap}; use crate::dma::{Channel, Transfer, Word}; use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; -use crate::pac::dma::vals::TreqSel; use crate::relocate::RelocatedProgram; use crate::{pac, peripherals, RegExt}; @@ -355,11 +352,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { let p = ch.regs(); p.write_addr().write_value(data.as_ptr() as u32); p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); - p.trans_count().write_value(data.len() as u32); + #[cfg(feature = "rp2040")] + p.trans_count().write(|w| *w = data.len() as u32); + #[cfg(feature = "rp235x")] + p.trans_count().write(|w| w.set_count(data.len() as u32)); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { // Set RX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); + w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8 + 4)); w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(false); @@ -437,11 +437,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { let p = ch.regs(); p.read_addr().write_value(data.as_ptr() as u32); p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32); - p.trans_count().write_value(data.len() as u32); + #[cfg(feature = "rp2040")] + p.trans_count().write(|w| *w = data.len() as u32); + #[cfg(feature = "rp235x")] + p.trans_count().write(|w| w.set_count(data.len() as u32)); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { // Set TX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); + w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8)); w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(true); @@ -523,6 +526,39 @@ pub struct PinConfig { pub out_base: u8, } +/// Comparison level or IRQ index for the MOV x, STATUS instruction. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg(feature = "rp235x")] +pub enum StatusN { + /// IRQ flag in this PIO block + This(u8), + /// IRQ flag in the next lower PIO block + Lower(u8), + /// IRQ flag in the next higher PIO block + Higher(u8), +} + +#[cfg(feature = "rp235x")] +impl Default for StatusN { + fn default() -> Self { + Self::This(0) + } +} + +#[cfg(feature = "rp235x")] +impl Into for StatusN { + fn into(self) -> crate::pac::pio::vals::ExecctrlStatusN { + let x = match self { + StatusN::This(n) => n, + StatusN::Lower(n) => n + 0x08, + StatusN::Higher(n) => n + 0x10, + }; + + crate::pac::pio::vals::ExecctrlStatusN(x) + } +} + /// PIO config. #[derive(Clone, Copy, Debug)] pub struct Config<'d, PIO: Instance> { @@ -537,7 +573,12 @@ pub struct Config<'d, PIO: Instance> { /// Which source to use for checking status. pub status_sel: StatusSource, /// Status comparison level. + #[cfg(feature = "rp2040")] pub status_n: u8, + // This cfg probably shouldn't be required, but the SVD for the 2040 doesn't have the enum + #[cfg(feature = "rp235x")] + /// Status comparison level. + pub status_n: StatusN, exec: ExecConfig, origin: Option, /// Configure FIFO allocation. @@ -653,7 +694,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536"); assert!(config.clock_divider >= 1, "clkdiv must be >= 1"); assert!(config.out_en_sel < 32, "out_en_sel must be < 32"); - assert!(config.status_n < 32, "status_n must be < 32"); + //assert!(config.status_n < 32, "status_n must be < 32"); // sm expects 0 for 32, truncation makes that happen assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); @@ -668,11 +709,17 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_out_sticky(config.out_sticky); w.set_wrap_top(config.exec.wrap_top); w.set_wrap_bottom(config.exec.wrap_bottom); + #[cfg(feature = "rp235x")] w.set_status_sel(match config.status_sel { - StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, - StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, + StatusSource::TxFifoLevel => pac::pio::vals::ExecctrlStatusSel::TXLEVEL, + StatusSource::RxFifoLevel => pac::pio::vals::ExecctrlStatusSel::RXLEVEL, }); - w.set_status_n(config.status_n); + #[cfg(feature = "rp2040")] + w.set_status_sel(match config.status_sel { + StatusSource::TxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::TXLEVEL, + StatusSource::RxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::RXLEVEL, + }); + w.set_status_n(config.status_n.into()); }); sm.shiftctrl().write(|w| { w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); @@ -1147,7 +1194,7 @@ fn on_pio_drop() { let state = PIO::state(); if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { let used_pins = state.used_pins.load(Ordering::Relaxed); - let null = Gpio0ctrlFuncsel::NULL as _; + let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; // we only have 30 pins. don't test the other two since gpio() asserts. for i in 0..30 { if used_pins & (1 << i) != 0 { @@ -1203,6 +1250,8 @@ macro_rules! impl_pio { impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0); impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); +#[cfg(feature = "rp235x")] +impl_pio!(PIO2, 2, PIO2, PIO2_0, PIO2_IRQ_0); /// PIO pin. pub trait PioPin: gpio::Pin {} @@ -1247,3 +1296,25 @@ impl_pio_pin! { PIN_28, PIN_29, } + +#[cfg(feature = "rp235xb")] +impl_pio_pin! { + PIN_30, + PIN_31, + PIN_32, + PIN_33, + PIN_34, + PIN_35, + PIN_36, + PIN_37, + PIN_38, + PIN_39, + PIN_40, + PIN_41, + PIN_42, + PIN_43, + PIN_44, + PIN_45, + PIN_46, + PIN_47, +} diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index c35e76587..3f96a3f05 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -363,6 +363,15 @@ slice!(PWM_SLICE5, 5); slice!(PWM_SLICE6, 6); slice!(PWM_SLICE7, 7); +#[cfg(feature = "rp235x")] +slice!(PWM_SLICE8, 8); +#[cfg(feature = "rp235x")] +slice!(PWM_SLICE9, 9); +#[cfg(feature = "rp235x")] +slice!(PWM_SLICE10, 10); +#[cfg(feature = "rp235x")] +slice!(PWM_SLICE11, 11); + /// PWM Channel A. pub trait ChannelAPin: GpioPin {} /// PWM Channel B. @@ -404,3 +413,39 @@ impl_pin!(PIN_26, PWM_SLICE5, ChannelAPin); impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin); impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin); impl_pin!(PIN_29, PWM_SLICE6, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_30, PWM_SLICE7, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_31, PWM_SLICE7, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_32, PWM_SLICE8, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_33, PWM_SLICE8, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_34, PWM_SLICE9, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_35, PWM_SLICE9, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_36, PWM_SLICE10, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_37, PWM_SLICE10, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_38, PWM_SLICE11, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_39, PWM_SLICE11, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_40, PWM_SLICE8, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_41, PWM_SLICE8, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_42, PWM_SLICE9, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_43, PWM_SLICE9, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_44, PWM_SLICE10, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_45, PWM_SLICE10, ChannelBPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_46, PWM_SLICE11, ChannelAPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_47, PWM_SLICE11, ChannelBPin); diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs index 70512fa14..4b9e42483 100644 --- a/embassy-rp/src/reset.rs +++ b/embassy-rp/src/reset.rs @@ -2,7 +2,7 @@ pub use pac::resets::regs::Peripherals; use crate::pac; -pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); +pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ff_ffff); pub(crate) fn reset(peris: Peripherals) { pac::RESETS.reset().write_value(peris); diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 2ce7ac645..4ba5bad4b 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "rp2040")] //! RTC driver. mod filter; diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 1617c144c..bc852ff7b 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -106,15 +106,55 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { if let Some(pin) = &clk { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_schmitt(true); + w.set_slewfast(false); + w.set_ie(true); + w.set_od(false); + w.set_pue(false); + w.set_pde(false); + }); } if let Some(pin) = &mosi { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_schmitt(true); + w.set_slewfast(false); + w.set_ie(true); + w.set_od(false); + w.set_pue(false); + w.set_pde(false); + }); } if let Some(pin) = &miso { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_schmitt(true); + w.set_slewfast(false); + w.set_ie(true); + w.set_od(false); + w.set_pue(false); + w.set_pde(false); + }); } if let Some(pin) = &cs { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_schmitt(true); + w.set_slewfast(false); + w.set_ie(true); + w.set_od(false); + w.set_pue(false); + w.set_pde(false); + }); } Self { inner, @@ -442,8 +482,8 @@ impl<'d, T: Instance> Spi<'d, T, Async> { trait SealedMode {} trait SealedInstance { - const TX_DREQ: u8; - const RX_DREQ: u8; + const TX_DREQ: pac::dma::vals::TreqSel; + const RX_DREQ: pac::dma::vals::TreqSel; fn regs(&self) -> pac::spi::Spi; } @@ -459,8 +499,8 @@ pub trait Instance: SealedInstance {} macro_rules! impl_instance { ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { impl SealedInstance for peripherals::$type { - const TX_DREQ: u8 = $tx_dreq; - const RX_DREQ: u8 = $rx_dreq; + const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq; + const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq; fn regs(&self) -> pac::spi::Spi { pac::$type @@ -470,8 +510,18 @@ macro_rules! impl_instance { }; } -impl_instance!(SPI0, Spi0, 16, 17); -impl_instance!(SPI1, Spi1, 18, 19); +impl_instance!( + SPI0, + Spi0, + pac::dma::vals::TreqSel::SPI0_TX, + pac::dma::vals::TreqSel::SPI0_RX +); +impl_instance!( + SPI1, + Spi1, + pac::dma::vals::TreqSel::SPI1_TX, + pac::dma::vals::TreqSel::SPI1_RX +); /// CLK pin. pub trait ClkPin: GpioPin {} @@ -518,6 +568,42 @@ impl_pin!(PIN_26, SPI1, ClkPin); impl_pin!(PIN_27, SPI1, MosiPin); impl_pin!(PIN_28, SPI1, MisoPin); impl_pin!(PIN_29, SPI1, CsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_30, SPI1, ClkPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_31, SPI1, MosiPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_32, SPI0, MisoPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_33, SPI0, CsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_34, SPI0, ClkPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_35, SPI0, MosiPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_36, SPI0, MisoPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_37, SPI0, CsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_38, SPI0, ClkPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_39, SPI0, MosiPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_40, SPI1, MisoPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_41, SPI1, CsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_42, SPI1, ClkPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_43, SPI1, MosiPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_44, SPI1, MisoPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_45, SPI1, CsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_46, SPI1, ClkPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_47, SPI1, MosiPin); macro_rules! impl_mode { ($name:ident) => { diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index bab1044cb..6f532fa8e 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -10,6 +10,11 @@ use embassy_time_driver::{AlarmHandle, Driver}; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; +#[cfg(feature = "rp2040")] +use pac::TIMER; +#[cfg(feature = "rp235x")] +use pac::TIMER0 as TIMER; + struct AlarmState { timestamp: Cell, callback: Cell>, @@ -35,9 +40,9 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ impl Driver for TimerDriver { fn now(&self) -> u64 { loop { - let hi = pac::TIMER.timerawh().read(); - let lo = pac::TIMER.timerawl().read(); - let hi2 = pac::TIMER.timerawh().read(); + let hi = TIMER.timerawh().read(); + let lo = TIMER.timerawl().read(); + let hi2 = TIMER.timerawh().read(); if hi == hi2 { return (hi as u64) << 32 | (lo as u64); } @@ -77,13 +82,13 @@ impl Driver for TimerDriver { // Note that we're not checking the high bits at all. This means the irq may fire early // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire // it is checked if the alarm time has passed. - pac::TIMER.alarm(n).write_value(timestamp as u32); + TIMER.alarm(n).write_value(timestamp as u32); let now = self.now(); if timestamp <= now { // If alarm timestamp has passed the alarm will not fire. // Disarm the alarm and return `false` to indicate that. - pac::TIMER.armed().write(|w| w.set_armed(1 << n)); + TIMER.armed().write(|w| w.set_armed(1 << n)); alarm.timestamp.set(u64::MAX); @@ -105,17 +110,17 @@ impl TimerDriver { } else { // Not elapsed, arm it again. // This can happen if it was set more than 2^32 us in the future. - pac::TIMER.alarm(n).write_value(timestamp as u32); + TIMER.alarm(n).write_value(timestamp as u32); } }); // clear the irq - pac::TIMER.intr().write(|w| w.set_alarm(n, true)); + TIMER.intr().write(|w| w.set_alarm(n, true)); } fn trigger_alarm(&self, n: usize, cs: CriticalSection) { // disarm - pac::TIMER.armed().write(|w| w.set_armed(1 << n)); + TIMER.armed().write(|w| w.set_armed(1 << n)); let alarm = &self.alarms.borrow(cs)[n]; alarm.timestamp.set(u64::MAX); @@ -138,38 +143,72 @@ pub unsafe fn init() { }); // enable all irqs - pac::TIMER.inte().write(|w| { + TIMER.inte().write(|w| { w.set_alarm(0, true); w.set_alarm(1, true); w.set_alarm(2, true); w.set_alarm(3, true); }); - interrupt::TIMER_IRQ_0.enable(); - interrupt::TIMER_IRQ_1.enable(); - interrupt::TIMER_IRQ_2.enable(); - interrupt::TIMER_IRQ_3.enable(); + #[cfg(feature = "rp2040")] + { + interrupt::TIMER_IRQ_0.enable(); + interrupt::TIMER_IRQ_1.enable(); + interrupt::TIMER_IRQ_2.enable(); + interrupt::TIMER_IRQ_3.enable(); + } + #[cfg(feature = "rp235x")] + { + interrupt::TIMER0_IRQ_0.enable(); + interrupt::TIMER0_IRQ_1.enable(); + interrupt::TIMER0_IRQ_2.enable(); + interrupt::TIMER0_IRQ_3.enable(); + } } -#[cfg(feature = "rt")] +#[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] fn TIMER_IRQ_0() { DRIVER.check_alarm(0) } -#[cfg(feature = "rt")] +#[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] fn TIMER_IRQ_1() { DRIVER.check_alarm(1) } -#[cfg(feature = "rt")] +#[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] fn TIMER_IRQ_2() { DRIVER.check_alarm(2) } -#[cfg(feature = "rt")] +#[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] fn TIMER_IRQ_3() { DRIVER.check_alarm(3) } + +#[cfg(all(feature = "rt", feature = "rp235x"))] +#[interrupt] +fn TIMER0_IRQ_0() { + DRIVER.check_alarm(0) +} + +#[cfg(all(feature = "rt", feature = "rp235x"))] +#[interrupt] +fn TIMER0_IRQ_1() { + DRIVER.check_alarm(1) +} + +#[cfg(all(feature = "rt", feature = "rp235x"))] +#[interrupt] +fn TIMER0_IRQ_2() { + DRIVER.check_alarm(2) +} + +#[cfg(all(feature = "rt", feature = "rp235x"))] +#[interrupt] +fn TIMER0_IRQ_3() { + DRIVER.check_alarm(3) +} diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index d50f5b4d5..058cfcbee 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -247,7 +247,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> { }); // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. - crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ) + crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into()) }; transfer.await; Ok(()) @@ -422,7 +422,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { let transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. - crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ) + crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into()) }; // wait for either the transfer to complete or an error to happen. @@ -571,7 +571,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { let transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. - crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ) + crate::dma::read( + &mut ch, + T::regs().uartdr().as_ptr() as *const _, + sbuffer, + T::RX_DREQ.into(), + ) }; // wait for either the transfer to complete or an error to happen. @@ -830,8 +835,16 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { ) { let r = T::regs(); if let Some(pin) = &tx { + let funcsel = { + let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; + if (pin_number % 4) == 0 { + 2 + } else { + 11 + } + }; pin.gpio().ctrl().write(|w| { - w.set_funcsel(2); + w.set_funcsel(funcsel); w.set_outover(if config.invert_tx { Outover::INVERT } else { @@ -841,8 +854,16 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { pin.pad_ctrl().write(|w| w.set_ie(true)); } if let Some(pin) = &rx { + let funcsel = { + let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; + if ((pin_number - 1) % 4) == 0 { + 2 + } else { + 11 + } + }; pin.gpio().ctrl().write(|w| { - w.set_funcsel(2); + w.set_funcsel(funcsel); w.set_inover(if config.invert_rx { Inover::INVERT } else { @@ -904,7 +925,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); } - fn lcr_modify(f: impl FnOnce(&mut rp_pac::uart::regs::UartlcrH) -> R) -> R { + fn lcr_modify(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R { let r = T::regs(); // Notes from PL011 reference manual: @@ -1332,3 +1353,92 @@ impl_pin!(PIN_26, UART1, CtsPin); impl_pin!(PIN_27, UART1, RtsPin); impl_pin!(PIN_28, UART0, TxPin); impl_pin!(PIN_29, UART0, RxPin); + +// Additional functions added by all 2350s +#[cfg(feature = "rp235x")] +impl_pin!(PIN_2, UART0, TxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_3, UART0, RxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_6, UART1, TxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_7, UART1, RxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_10, UART1, TxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_11, UART1, RxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_14, UART0, TxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_15, UART0, RxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_18, UART0, TxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_19, UART0, RxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_22, UART1, TxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_23, UART1, RxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_26, UART1, TxPin); +#[cfg(feature = "rp235x")] +impl_pin!(PIN_27, UART1, RxPin); + +// Additional pins added by larger 2350 packages. +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_30, UART0, CtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_31, UART0, RtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_32, UART0, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_33, UART0, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_34, UART0, CtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_35, UART0, RtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_36, UART1, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_37, UART1, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_38, UART1, CtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_39, UART1, RtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_40, UART1, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_41, UART1, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_42, UART1, CtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_43, UART1, RtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_44, UART0, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_45, UART0, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_46, UART0, CtsPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_47, UART0, RtsPin); + +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_30, UART0, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_31, UART0, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_34, UART0, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_35, UART0, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_38, UART1, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_39, UART1, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_42, UART1, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_43, UART1, RxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_46, UART0, TxPin); +#[cfg(feature = "rp235xb")] +impl_pin!(PIN_47, UART0, RxPin); diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 512271ae4..20ef881f9 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -28,10 +28,10 @@ pub trait Instance: SealedInstance + 'static { impl crate::usb::SealedInstance for peripherals::USB { fn regs() -> pac::usb::Usb { - pac::USBCTRL_REGS + pac::USB } fn dpram() -> crate::pac::usb_dpram::UsbDpram { - pac::USBCTRL_DPRAM + pac::USB_DPRAM } } @@ -41,7 +41,7 @@ impl crate::usb::Instance for peripherals::USB { const EP_COUNT: usize = 16; const EP_MEMORY_SIZE: usize = 4096; -const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8; +const EP_MEMORY: *mut u8 = pac::USB_DPRAM.as_ptr() as *mut u8; const NEW_AW: AtomicWaker = AtomicWaker::new(); static BUS_WAKER: AtomicWaker = NEW_AW; diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index 229a306fe..edd48e0e0 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs @@ -34,6 +34,7 @@ impl Watchdog { /// /// * `cycles` - Total number of tick cycles before the next tick is generated. /// It is expected to be the frequency in MHz of clk_ref. + #[cfg(feature = "rp2040")] pub fn enable_tick_generation(&mut self, cycles: u8) { let watchdog = pac::WATCHDOG; watchdog.tick().write(|w| { diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 2884ca85a..500425315 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -10,7 +10,7 @@ embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } +embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } @@ -51,7 +51,7 @@ embedded-hal-async = "1.0" embedded-hal-bus = { version = "0.1", features = ["async"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-storage = { version = "0.3" } -static_cell = "2" +static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" pio-proc = "0.2" diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml new file mode 100644 index 000000000..f77e004dc --- /dev/null +++ b/examples/rp23/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +#runner = "probe-rs run --chip RP2040" +runner = "elf2uf2-rs -d" + +[build] +target = "thumbv8m.main-none-eabihf" + +[env] +DEFMT_LOG = "debug" diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml new file mode 100644 index 000000000..89947ae46 --- /dev/null +++ b/examples/rp23/Cargo.toml @@ -0,0 +1,80 @@ +[package] +edition = "2021" +name = "embassy-rp2350-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + + +[dependencies] +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info", "rt-235x", "boot2-none"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } +embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } +embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } +cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } +cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } + +defmt = "0.3" +defmt-rtt = "0.4" +fixed = "1.23.1" +fixed-macro = "1.2" + +# for web request example +reqwless = { version = "0.12.0", features = ["defmt",]} +serde = { version = "1.0.203", default-features = false, features = ["derive"] } +serde-json-core = "0.5.1" + +# for assign resources example +assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } + +#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } +cortex-m = { version = "0.7.6", features = ["inline-asm"] } +cortex-m-rt = "0.7.0" +critical-section = "1.1" +panic-probe = { version = "0.3", features = ["print-defmt"] } +display-interface-spi = "0.4.1" +embedded-graphics = "0.7.1" +st7789 = "0.6.1" +display-interface = "0.4.1" +byte-slice-cast = { version = "1.2.0", default-features = false } +smart-leds = "0.3.0" +heapless = "0.8" +usbd-hid = "0.8.1" + +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = "1.0" +embedded-hal-bus = { version = "0.1", features = ["async"] } +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } +embedded-storage = { version = "0.3" } +static_cell = "2.1" +portable-atomic = { version = "1.5", features = ["critical-section"] } +log = "0.4" +pio-proc = "0.2" +pio = "0.2.1" +rand = { version = "0.8.5", default-features = false } +embedded-sdmmc = "0.7.0" + +bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } +trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } + +[profile.release] +debug = 2 + +[profile.dev] +lto = true +opt-level = "z" + +[patch.crates-io] +trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } +bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } +embassy-executor = { path = "../../embassy-executor" } +embassy-sync = { path = "../../embassy-sync" } +embassy-futures = { path = "../../embassy-futures" } +embassy-time = { path = "../../embassy-time" } +embassy-time-driver = { path = "../../embassy-time-driver" } +embassy-embedded-hal = { path = "../../embassy-embedded-hal" } diff --git a/examples/rp23/assets/ferris.raw b/examples/rp23/assets/ferris.raw new file mode 100644 index 0000000000000000000000000000000000000000..9733889c577bdcc9277858ce019abff5b7dd23d0 GIT binary patch literal 11008 zcmd5?F^ua(5VexV#V@WS1%*kP(1k9)^CeA06$+&At2oh@0@XE0K{Vfvgzh8?f}lvb zaTTFoMCc>A0LerGojwRfh{6R({wd%DqNSjK9Zxp1YdbzW$#K|Hylc$27uoSiXeOk>`2)ETl94!X5 z7Q>oZcLS)K_4`3-o24s~T)IN69FL)C0^2HN9bPjKDaXE$Ic$?^cUdyd0GqoOdUSk& z)m^jRz!NpcXI*DkTWzhvYD}(y;w}+V+oZYh0`w@b-S)J(p2N{9vWWl6CTvs4TZIEp zjPY$qVZOB%L?z8dQo~6~tV8R|HSw}(AjjO>R-?O3dK=P)$+xlX57w1NDRi&LI%rLY>sr5EE+juPZOcMX}yJB|mkDykmG+wG!3h1HTYe>d!M?e7lGC6 z*CPx~h==!G##uBQ12?+&w8cHc-QHX25Ibgg1deqZUEVF4{H^cPD!jixPnCv0%w84v z9`yfmyFr${f@Z6`o!)(89(aH!>$KBeG2&lFFpG5`z_}1?1`ZJ zzdYT*@mtKNoQ}5jtBFy_hZy}K?`K9&cQgmekZnQU4d+9MR8IK)kI#O-dPmdEiq%ZF zpLzJvAD{m8_@Sm-jp}rDQ>1;Q75OHC_^|Q+?)QJ9>x0*@9m*FGqCY=JnpFj8{1JW0 zS8~^s$3rQH&HtDFL>zB?h^=VaV5uOu3CESMkmkV36t9Zas@`UY{l z`&3|6_ht~||NRTn{O~@~!0ssjE$8fnjPL?;V)H*Oy51 z{1MWal_ECl1_MuCzYM*&PI;ehH2uL4aeVtwVAXWTr~bl<{`?Wpy!@-P%N`e>8<4ld ztEdGb7Tm+V{ra0ve>)c~@uz~-AHkQ$uYUH3kaC;$s5f~_nC(dSG`F{rzTY$ytm*sb zL$LB#R;SGK?dW0@H&$KJ=eB56X!lH+c$Kb*y^_pu9FD10w3K#Y!D6{Dd0rsmLo*|- z#X;k-^Er^&mMDtjgp%`EIYqZ>m$$oNcE0y}`1NwxaV@ zIM*6GS+|$vS-el~+KEmYWGwCF=CU@MB>EuJsO7=ZAC;~$ddT;hTmu=g4YlX4YqQNI z-1H7h125?X+yH6I)AnK_`N}x2Qa>OfQTQXPBAi@XEdIU4(sDsHhG;jJ_EfOaR>A|sbvyIQkX zDuS;z6DZt(=b6lTe>L7b**qyv%QKF2Ib60ET>3{q5ASMGAD|yHuIS4m!pf1(M^5LQ zdopRZ@HNzG2$@`lG8=?e!BfXiTKHP8pVyIdHFkW#>8>#v(e!F;)`3?l&*uHFNBq8k z-}z|XpZA=u)2T64?~V^=&&HYTgCKI4_fVqKQSrnx1@Q06y8nrpOg>(GZ03D6SCy83QFk90Az3DH8)x}RC72juAcQ zf!J1$kVgA!XE&1ja`G~Tv(3;r-Oc5>0Xoj>ulQbW8v*3&AY!`+ON%XiwnDdZz8Cc@AOcvBcOCKD8vW4f211 zh$8MU(vc*+U^-p8UQ6#Gb$U+-3zQHocz*Rg)KveKjsX76lBZ8x8JU zd?+d1uH*ioWE&N$VRu;1ABE$RUAltRlJy*a;0>0oMT=FZrK|9Q_3V!7m${Emo#U`Z zq+1{%luNMsrH?`KKO}ii)KOnF7U{a+dgXfp+HJ_F_LWT|eS|b!T{Ylz`L;O#GU9!t zf4syI*qyw+k8`Hg9cf(wJtf!HI2VtT1JbDa-?BLEY3pj-0T|*tT2)>=qR*yQc~4P` wR$bCnkn#T-omP-|F6|UZ^0i?#!;9#oVeR<*+&^_zgQd0@_=A$oddFDezjq(d^8f$< literal 0 HcmV?d00001 diff --git a/examples/rp23/build.rs b/examples/rp23/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/rp23/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/rp23/memory.x b/examples/rp23/memory.x new file mode 100644 index 000000000..777492062 --- /dev/null +++ b/examples/rp23/memory.x @@ -0,0 +1,74 @@ +MEMORY { + /* + * The RP2350 has either external or internal flash. + * + * 2 MiB is a safe default here, although a Pico 2 has 4 MiB. + */ + FLASH : ORIGIN = 0x10000000, LENGTH = 2048K + /* + * RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping. + * This is usually good for performance, as it distributes load on + * those banks evenly. + */ + RAM : ORIGIN = 0x20000000, LENGTH = 512K + /* + * RAM banks 8 and 9 use a direct mapping. They can be used to have + * memory areas dedicated for some specific job, improving predictability + * of access times. + * Example: Separate stacks for core0 and core1. + */ + SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K + SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K +} + +SECTIONS { + /* ### Boot ROM info + * + * Goes after .vector_table, to keep it in the first 4K of flash + * where the Boot ROM (and picotool) can find it + */ + .start_block : ALIGN(4) + { + __start_block_addr = .; + KEEP(*(.start_block)); + } > FLASH + +} INSERT AFTER .vector_table; + +/* move .text to start /after/ the boot info */ +_stext = ADDR(.start_block) + SIZEOF(.start_block); + +SECTIONS { + /* ### Picotool 'Binary Info' Entries + * + * Picotool looks through this block (as we have pointers to it in our + * header) to find interesting information. + */ + .bi_entries : ALIGN(4) + { + /* We put this in the header */ + __bi_entries_start = .; + /* Here are the entries */ + KEEP(*(.bi_entries)); + /* Keep this block a nice round size */ + . = ALIGN(4); + /* We put this in the header */ + __bi_entries_end = .; + } > FLASH +} INSERT AFTER .text; + +SECTIONS { + /* ### Boot ROM extra info + * + * Goes after everything in our program, so it can contain a signature. + */ + .end_block : ALIGN(4) + { + __end_block_addr = .; + KEEP(*(.end_block)); + } > FLASH + +} INSERT AFTER .uninit; + +PROVIDE(start_to_end = __end_block_addr - __start_block_addr); +PROVIDE(end_to_start = __start_block_addr - __end_block_addr); diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs new file mode 100644 index 000000000..a1a94ca47 --- /dev/null +++ b/examples/rp23/src/bin/adc.rs @@ -0,0 +1,64 @@ +//! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28. +//! It also reads the temperature sensor in the chip. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::Pull; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut adc = Adc::new(p.ADC, Irqs, Config::default()); + + let mut p26 = Channel::new_pin(p.PIN_26, Pull::None); + let mut p27 = Channel::new_pin(p.PIN_27, Pull::None); + let mut p28 = Channel::new_pin(p.PIN_28, Pull::None); + let mut ts = Channel::new_temp_sensor(p.ADC_TEMP_SENSOR); + + loop { + let level = adc.read(&mut p26).await.unwrap(); + info!("Pin 26 ADC: {}", level); + let level = adc.read(&mut p27).await.unwrap(); + info!("Pin 27 ADC: {}", level); + let level = adc.read(&mut p28).await.unwrap(); + info!("Pin 28 ADC: {}", level); + let temp = adc.read(&mut ts).await.unwrap(); + info!("Temp: {} degrees", convert_to_celsius(temp)); + Timer::after_secs(1).await; + } +} + +fn convert_to_celsius(raw_temp: u16) -> f32 { + // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet + let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721; + let sign = if temp < 0.0 { -1.0 } else { 1.0 }; + let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16; + (rounded_temp_x10 as f32) / 10.0 +} diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs new file mode 100644 index 000000000..887c8500a --- /dev/null +++ b/examples/rp23/src/bin/adc_dma.rs @@ -0,0 +1,70 @@ +//! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads. +//! For multichannel, the samples are interleaved in the buffer: +//! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]` +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::Pull; +use embassy_time::{Duration, Ticker}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Here we go!"); + + let mut adc = Adc::new(p.ADC, Irqs, Config::default()); + let mut dma = p.DMA_CH0; + let mut pin = Channel::new_pin(p.PIN_26, Pull::Up); + let mut pins = [ + Channel::new_pin(p.PIN_27, Pull::Down), + Channel::new_pin(p.PIN_28, Pull::None), + Channel::new_pin(p.PIN_29, Pull::Up), + Channel::new_temp_sensor(p.ADC_TEMP_SENSOR), + ]; + + const BLOCK_SIZE: usize = 100; + const NUM_CHANNELS: usize = 4; + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + // Read 100 samples from a single channel + let mut buf = [0_u16; BLOCK_SIZE]; + let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) + adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); + info!("single: {:?} ...etc", buf[..8]); + + // Read 100 samples from 4 channels interleaved + let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; + let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) + adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) + .await + .unwrap(); + info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); + + ticker.next().await; + } +} diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs new file mode 100644 index 000000000..8aea2f35d --- /dev/null +++ b/examples/rp23/src/bin/assign_resources.rs @@ -0,0 +1,95 @@ +//! This example demonstrates how to assign resources to multiple tasks by splitting up the peripherals. +//! It is not about sharing the same resources between tasks, see sharing.rs for that or head to https://embassy.dev/book/#_sharing_peripherals_between_tasks) +//! Of course splitting up resources and sharing resources can be combined, yet this example is only about splitting up resources. +//! +//! There are basically two ways we demonstrate here: +//! 1) Assigning resources to a task by passing parts of the peripherals +//! 2) Assigning resources to a task by passing a struct with the split up peripherals, using the assign-resources macro +//! +//! using four LEDs on Pins 10, 11, 20 and 21 + +#![no_std] +#![no_main] + +use assign_resources::assign_resources; +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::peripherals::{self, PIN_20, PIN_21}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + // initialize the peripherals + let p = embassy_rp::init(Default::default()); + + // 1) Assigning a resource to a task by passing parts of the peripherals. + spawner + .spawn(double_blinky_manually_assigned(spawner, p.PIN_20, p.PIN_21)) + .unwrap(); + + // 2) Using the assign-resources macro to assign resources to a task. + // we perform the split, see further below for the definition of the resources struct + let r = split_resources!(p); + // and then we can use them + spawner.spawn(double_blinky_macro_assigned(spawner, r.leds)).unwrap(); +} + +// 1) Assigning a resource to a task by passing parts of the peripherals. +#[embassy_executor::task] +async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { + let mut led_20 = Output::new(pin_20, Level::Low); + let mut led_21 = Output::new(pin_21, Level::High); + + loop { + info!("toggling leds"); + led_20.toggle(); + led_21.toggle(); + Timer::after_secs(1).await; + } +} + +// 2) Using the assign-resources macro to assign resources to a task. +// first we define the resources we want to assign to the task using the assign_resources! macro +// basically this will split up the peripherals struct into smaller structs, that we define here +// naming is up to you, make sure your future self understands what you did here +assign_resources! { + leds: Leds{ + led_10: PIN_10, + led_11: PIN_11, + } + // add more resources to more structs if needed, for example defining one struct for each task +} +// this could be done in another file and imported here, but for the sake of simplicity we do it here +// see https://github.com/adamgreig/assign-resources for more information + +// 2) Using the split resources in a task +#[embassy_executor::task] +async fn double_blinky_macro_assigned(_spawner: Spawner, r: Leds) { + let mut led_10 = Output::new(r.led_10, Level::Low); + let mut led_11 = Output::new(r.led_11, Level::High); + + loop { + info!("toggling leds"); + led_10.toggle(); + led_11.toggle(); + Timer::after_secs(1).await; + } +} diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs new file mode 100644 index 000000000..1e3a52085 --- /dev/null +++ b/examples/rp23/src/bin/blinky.rs @@ -0,0 +1,44 @@ +//! This example test the RP Pico on board LED. +//! +//! It does not work with the RP Pico W board. See wifi_blinky.rs. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_time::Timer; +use gpio::{Level, Output}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut led = Output::new(p.PIN_2, Level::Low); + + loop { + info!("led on!"); + led.set_high(); + Timer::after_millis(250).await; + + info!("led off!"); + led.set_low(); + Timer::after_millis(250).await; + } +} diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs new file mode 100644 index 000000000..aae0283cf --- /dev/null +++ b/examples/rp23/src/bin/blinky_two_channels.rs @@ -0,0 +1,66 @@ +#![no_std] +#![no_main] +/// This example demonstrates how to access a given pin from more than one embassy task +/// The on-board LED is toggled by two tasks with slightly different periods, leading to the +/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar +/// to interference and the 'beats' you can hear if you play two frequencies close to one another +/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::channel::{Channel, Sender}; +use embassy_time::{Duration, Ticker}; +use gpio::{AnyPin, Level, Output}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +enum LedState { + Toggle, +} +static CHANNEL: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); + + let dt = 100 * 1_000_000; + let k = 1.003; + + unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_led( + CHANNEL.sender(), + Duration::from_nanos((dt as f64 * k) as u64) + ))); + + loop { + match CHANNEL.receive().await { + LedState::Toggle => led.toggle(), + } + } +} + +#[embassy_executor::task(pool_size = 2)] +async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>, delay: Duration) { + let mut ticker = Ticker::every(delay); + loop { + control.send(LedState::Toggle).await; + ticker.next().await; + } +} diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs new file mode 100644 index 000000000..aeabb238f --- /dev/null +++ b/examples/rp23/src/bin/blinky_two_tasks.rs @@ -0,0 +1,65 @@ +#![no_std] +#![no_main] +/// This example demonstrates how to access a given pin from more than one embassy task +/// The on-board LED is toggled by two tasks with slightly different periods, leading to the +/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar +/// to interference and the 'beats' you can hear if you play two frequencies close to one another +/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::{Duration, Ticker}; +use gpio::{AnyPin, Level, Output}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +type LedType = Mutex>>; +static LED: LedType = Mutex::new(None); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + // set the content of the global LED reference to the real LED pin + let led = Output::new(AnyPin::from(p.PIN_25), Level::High); + // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the + // Mutex is released + { + *(LED.lock().await) = Some(led); + } + let dt = 100 * 1_000_000; + let k = 1.003; + + unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos(dt)))); + unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64)))); +} + +#[embassy_executor::task(pool_size = 2)] +async fn toggle_led(led: &'static LedType, delay: Duration) { + let mut ticker = Ticker::every(delay); + loop { + { + let mut led_unlocked = led.lock().await; + if let Some(pin_ref) = led_unlocked.as_mut() { + pin_ref.toggle(); + } + } + ticker.next().await; + } +} diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs new file mode 100644 index 000000000..2a78a19db --- /dev/null +++ b/examples/rp23/src/bin/button.rs @@ -0,0 +1,44 @@ +//! This example uses the RP Pico on board LED to test input pin 28. This is not the button on the board. +//! +//! It does not work with the RP Pico W board. Use wifi_blinky.rs and add input pin. + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_rp::gpio::{Input, Level, Output, Pull}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut led = Output::new(p.PIN_25, Level::Low); + + // Use PIN_28, Pin34 on J0 for RP Pico, as a input. + // You need to add your own button. + let button = Input::new(p.PIN_28, Pull::Up); + + loop { + if button.is_high() { + led.set_high(); + } else { + led.set_low(); + } + } +} diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs new file mode 100644 index 000000000..0e3b5cb54 --- /dev/null +++ b/examples/rp23/src/bin/debounce.rs @@ -0,0 +1,96 @@ +//! This example shows the ease of debouncing a button with async rust. +//! Hook up a button or switch between pin 9 and ground. + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::gpio::{Input, Level, Pull}; +use embassy_time::{with_deadline, Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +pub struct Debouncer<'a> { + input: Input<'a>, + debounce: Duration, +} + +impl<'a> Debouncer<'a> { + pub fn new(input: Input<'a>, debounce: Duration) -> Self { + Self { input, debounce } + } + + pub async fn debounce(&mut self) -> Level { + loop { + let l1 = self.input.get_level(); + + self.input.wait_for_any_edge().await; + + Timer::after(self.debounce).await; + + let l2 = self.input.get_level(); + if l1 != l2 { + break l2; + } + } + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20)); + + info!("Debounce Demo"); + + loop { + // button pressed + btn.debounce().await; + let start = Instant::now(); + info!("Button Press"); + + match with_deadline(start + Duration::from_secs(1), btn.debounce()).await { + // Button Released < 1s + Ok(_) => { + info!("Button pressed for: {}ms", start.elapsed().as_millis()); + continue; + } + // button held for > 1s + Err(_) => { + info!("Button Held"); + } + } + + match with_deadline(start + Duration::from_secs(5), btn.debounce()).await { + // Button released <5s + Ok(_) => { + info!("Button pressed for: {}ms", start.elapsed().as_millis()); + continue; + } + // button held for > >5s + Err(_) => { + info!("Button Long Held"); + } + } + + // wait for button release before handling another press + btn.debounce().await; + info!("Button pressed for: {}ms", start.elapsed().as_millis()); + } +} diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs new file mode 100644 index 000000000..42620ca93 --- /dev/null +++ b/examples/rp23/src/bin/flash.rs @@ -0,0 +1,150 @@ +//! This example test the flash connected to the RP2040 chip. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE}; +use embassy_rp::peripherals::FLASH; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +const ADDR_OFFSET: u32 = 0x100000; +const FLASH_SIZE: usize = 2 * 1024 * 1024; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + // add some delay to give an attached debug probe time to parse the + // defmt RTT header. Reading that header might touch flash memory, which + // interferes with flash write operations. + // https://github.com/knurling-rs/defmt/pull/683 + Timer::after_millis(10).await; + + let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); + + // Get JEDEC id + let jedec = flash.blocking_jedec_id().unwrap(); + info!("jedec id: 0x{:x}", jedec); + + // Get unique id + let mut uid = [0; 8]; + flash.blocking_unique_id(&mut uid).unwrap(); + info!("unique id: {:?}", uid); + + erase_write_sector(&mut flash, 0x00); + + multiwrite_bytes(&mut flash, ERASE_SIZE as u32); + + background_read(&mut flash, (ERASE_SIZE * 2) as u32).await; + + loop {} +} + +fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { + info!(">>>> [multiwrite_bytes]"); + let mut read_buf = [0u8; ERASE_SIZE]; + defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); + + info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); + info!("Contents start with {=[u8]}", read_buf[0..4]); + + defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); + + defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); + info!("Contents after erase starts with {=[u8]}", read_buf[0..4]); + if read_buf.iter().any(|x| *x != 0xFF) { + defmt::panic!("unexpected"); + } + + defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &[0x01])); + defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 1, &[0x02])); + defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 2, &[0x03])); + defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 3, &[0x04])); + + defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); + info!("Contents after write starts with {=[u8]}", read_buf[0..4]); + if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { + defmt::panic!("unexpected"); + } +} + +fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { + info!(">>>> [erase_write_sector]"); + let mut buf = [0u8; ERASE_SIZE]; + defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); + + info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); + info!("Contents start with {=[u8]}", buf[0..4]); + + defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); + + defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); + info!("Contents after erase starts with {=[u8]}", buf[0..4]); + if buf.iter().any(|x| *x != 0xFF) { + defmt::panic!("unexpected"); + } + + for b in buf.iter_mut() { + *b = 0xDA; + } + + defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &buf)); + + defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); + info!("Contents after write starts with {=[u8]}", buf[0..4]); + if buf.iter().any(|x| *x != 0xDA) { + defmt::panic!("unexpected"); + } +} + +async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { + info!(">>>> [background_read]"); + + let mut buf = [0u32; 8]; + defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; + + info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); + info!("Contents start with {=u32:x}", buf[0]); + + defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); + + defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; + info!("Contents after erase starts with {=u32:x}", buf[0]); + if buf.iter().any(|x| *x != 0xFFFFFFFF) { + defmt::panic!("unexpected"); + } + + for b in buf.iter_mut() { + *b = 0xDABA1234; + } + + defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, unsafe { + core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4) + })); + + defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; + info!("Contents after write starts with {=u32:x}", buf[0]); + if buf.iter().any(|x| *x != 0xDABA1234) { + defmt::panic!("unexpected"); + } +} diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs new file mode 100644 index 000000000..360932d62 --- /dev/null +++ b/examples/rp23/src/bin/gpio_async.rs @@ -0,0 +1,56 @@ +//! This example shows how async gpio can be used with a RP2040. +//! +//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_time::Timer; +use gpio::{Input, Level, Output, Pull}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +/// It requires an external signal to be manually triggered on PIN 16. For +/// example, this could be accomplished using an external power source with a +/// button so that it is possible to toggle the signal from low to high. +/// +/// This example will begin with turning on the LED on the board and wait for a +/// high signal on PIN 16. Once the high event/signal occurs the program will +/// continue and turn off the LED, and then wait for 2 seconds before completing +/// the loop and starting over again. +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut led = Output::new(p.PIN_25, Level::Low); + let mut async_input = Input::new(p.PIN_16, Pull::None); + + loop { + info!("wait_for_high. Turn on LED"); + led.set_high(); + + async_input.wait_for_high().await; + + info!("done wait_for_high. Turn off LED"); + led.set_low(); + + Timer::after_secs(2).await; + } +} diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs new file mode 100644 index 000000000..8d1e4d05f --- /dev/null +++ b/examples/rp23/src/bin/gpout.rs @@ -0,0 +1,53 @@ +//! This example shows how GPOUT (General purpose clock outputs) can toggle a output pin. +//! +//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::clocks; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let gpout3 = clocks::Gpout::new(p.PIN_25); + gpout3.set_div(1000, 0); + gpout3.enable(); + + loop { + gpout3.set_src(clocks::GpoutSrc::Sys); + info!( + "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}", + gpout3.get_freq() + ); + Timer::after_secs(2).await; + + gpout3.set_src(clocks::GpoutSrc::Ref); + info!( + "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}", + gpout3.get_freq() + ); + Timer::after_secs(2).await; + } +} diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs new file mode 100644 index 000000000..64f103849 --- /dev/null +++ b/examples/rp23/src/bin/i2c_async.rs @@ -0,0 +1,126 @@ +//! This example shows how to communicate asynchronous using i2c with external chips. +//! +//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip. +//! (https://www.microchip.com/en-us/product/mcp23017) + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::i2c::{self, Config, InterruptHandler}; +use embassy_rp::peripherals::I2C1; +use embassy_time::Timer; +use embedded_hal_async::i2c::I2c; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + I2C1_IRQ => InterruptHandler; +}); + +#[allow(dead_code)] +mod mcp23017 { + pub const ADDR: u8 = 0x20; // default addr + + macro_rules! mcpregs { + ($($name:ident : $val:expr),* $(,)?) => { + $( + pub const $name: u8 = $val; + )* + + pub fn regname(reg: u8) -> &'static str { + match reg { + $( + $val => stringify!($name), + )* + _ => panic!("bad reg"), + } + } + } + } + + // These are correct for IOCON.BANK=0 + mcpregs! { + IODIRA: 0x00, + IPOLA: 0x02, + GPINTENA: 0x04, + DEFVALA: 0x06, + INTCONA: 0x08, + IOCONA: 0x0A, + GPPUA: 0x0C, + INTFA: 0x0E, + INTCAPA: 0x10, + GPIOA: 0x12, + OLATA: 0x14, + IODIRB: 0x01, + IPOLB: 0x03, + GPINTENB: 0x05, + DEFVALB: 0x07, + INTCONB: 0x09, + IOCONB: 0x0B, + GPPUB: 0x0D, + INTFB: 0x0F, + INTCAPB: 0x11, + GPIOB: 0x13, + OLATB: 0x15, + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let sda = p.PIN_14; + let scl = p.PIN_15; + + info!("set up i2c "); + let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, Config::default()); + + use mcp23017::*; + + info!("init mcp23017 config for IxpandO"); + // init - a outputs, b inputs + i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap(); + i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap(); + i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups + + let mut val = 1; + loop { + let mut portb = [0]; + + i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap(); + info!("portb = {:02x}", portb[0]); + i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap(); + val = val.rotate_left(1); + + // get a register dump + info!("getting register dump"); + let mut regs = [0; 22]; + i2c.write_read(ADDR, &[0], &mut regs).await.unwrap(); + // always get the regdump but only display it if portb'0 is set + if portb[0] & 1 != 0 { + for (idx, reg) in regs.into_iter().enumerate() { + info!("{} => {:02x}", regname(idx as u8), reg); + } + } + + Timer::after_millis(100).await; + } +} diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs new file mode 100644 index 000000000..4b14ec6f6 --- /dev/null +++ b/examples/rp23/src/bin/i2c_async_embassy.rs @@ -0,0 +1,101 @@ +//! This example shows how to communicate asynchronous using i2c with external chip. +//! +//! It's using embassy's functions directly instead of traits from embedded_hal_async::i2c::I2c. +//! While most of i2c devices are addressed using 7 bits, an extension allows 10 bits too. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_rp::i2c::InterruptHandler; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +// Our anonymous hypotetical temperature sensor could be: +// a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C +// It requires no configuration or calibration, works with all i2c bus speeds, +// never stretches clock or does anything complicated. Replies with one u16. +// It requires only one write to take it out of suspend mode, and stays on. +// Often result would be just on 12 bits, but here we'll simplify it to 16. + +enum UncomplicatedSensorId { + A(UncomplicatedSensorU8), + B(UncomplicatedSensorU16), +} +enum UncomplicatedSensorU8 { + First = 0x48, +} +enum UncomplicatedSensorU16 { + Other = 0x0049, +} + +impl Into for UncomplicatedSensorU16 { + fn into(self) -> u16 { + self as u16 + } +} +impl Into for UncomplicatedSensorU8 { + fn into(self) -> u16 { + 0x48 + } +} +impl From for u16 { + fn from(t: UncomplicatedSensorId) -> Self { + match t { + UncomplicatedSensorId::A(x) => x.into(), + UncomplicatedSensorId::B(x) => x.into(), + } + } +} + +embassy_rp::bind_interrupts!(struct Irqs { + I2C1_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_task_spawner: embassy_executor::Spawner) { + let p = embassy_rp::init(Default::default()); + let sda = p.PIN_14; + let scl = p.PIN_15; + let config = embassy_rp::i2c::Config::default(); + let mut bus = embassy_rp::i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, config); + + const WAKEYWAKEY: u16 = 0xBABE; + let mut result: [u8; 2] = [0, 0]; + // wait for sensors to initialize + embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await; + + let _res_1 = bus + .write_async(UncomplicatedSensorU8::First, WAKEYWAKEY.to_be_bytes()) + .await; + let _res_2 = bus + .write_async(UncomplicatedSensorU16::Other, WAKEYWAKEY.to_be_bytes()) + .await; + + loop { + let s1 = UncomplicatedSensorId::A(UncomplicatedSensorU8::First); + let s2 = UncomplicatedSensorId::B(UncomplicatedSensorU16::Other); + let sensors = [s1, s2]; + for sensor in sensors { + if bus.read_async(sensor, &mut result).await.is_ok() { + info!("Result {}", u16::from_be_bytes(result.into())); + } + } + embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await; + } +} diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs new file mode 100644 index 000000000..d2cccf09b --- /dev/null +++ b/examples/rp23/src/bin/i2c_blocking.rs @@ -0,0 +1,90 @@ +//! This example shows how to communicate using i2c with external chips. +//! +//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip. +//! (https://www.microchip.com/en-us/product/mcp23017) + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::i2c::{self, Config}; +use embassy_time::Timer; +use embedded_hal_1::i2c::I2c; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[allow(dead_code)] +mod mcp23017 { + pub const ADDR: u8 = 0x20; // default addr + + pub const IODIRA: u8 = 0x00; + pub const IPOLA: u8 = 0x02; + pub const GPINTENA: u8 = 0x04; + pub const DEFVALA: u8 = 0x06; + pub const INTCONA: u8 = 0x08; + pub const IOCONA: u8 = 0x0A; + pub const GPPUA: u8 = 0x0C; + pub const INTFA: u8 = 0x0E; + pub const INTCAPA: u8 = 0x10; + pub const GPIOA: u8 = 0x12; + pub const OLATA: u8 = 0x14; + pub const IODIRB: u8 = 0x01; + pub const IPOLB: u8 = 0x03; + pub const GPINTENB: u8 = 0x05; + pub const DEFVALB: u8 = 0x07; + pub const INTCONB: u8 = 0x09; + pub const IOCONB: u8 = 0x0B; + pub const GPPUB: u8 = 0x0D; + pub const INTFB: u8 = 0x0F; + pub const INTCAPB: u8 = 0x11; + pub const GPIOB: u8 = 0x13; + pub const OLATB: u8 = 0x15; +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let sda = p.PIN_14; + let scl = p.PIN_15; + + info!("set up i2c "); + let mut i2c = i2c::I2c::new_blocking(p.I2C1, scl, sda, Config::default()); + + use mcp23017::*; + + info!("init mcp23017 config for IxpandO"); + // init - a outputs, b inputs + i2c.write(ADDR, &[IODIRA, 0x00]).unwrap(); + i2c.write(ADDR, &[IODIRB, 0xff]).unwrap(); + i2c.write(ADDR, &[GPPUB, 0xff]).unwrap(); // pullups + + let mut val = 0xaa; + loop { + let mut portb = [0]; + + i2c.write(mcp23017::ADDR, &[GPIOA, val]).unwrap(); + i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).unwrap(); + + info!("portb = {:02x}", portb[0]); + val = !val; + + Timer::after_secs(1).await; + } +} diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs new file mode 100644 index 000000000..4bf407bcc --- /dev/null +++ b/examples/rp23/src/bin/i2c_slave.rs @@ -0,0 +1,132 @@ +//! This example shows how to use the 2040 as an i2c slave. +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::peripherals::{I2C0, I2C1}; +use embassy_rp::{bind_interrupts, i2c, i2c_slave}; +use embassy_time::Timer; +use embedded_hal_async::i2c::I2c; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::{block::ImageDef}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + +bind_interrupts!(struct Irqs { + I2C0_IRQ => i2c::InterruptHandler; + I2C1_IRQ => i2c::InterruptHandler; +}); + +const DEV_ADDR: u8 = 0x42; + +#[embassy_executor::task] +async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { + info!("Device start"); + + let mut state = 0; + + loop { + let mut buf = [0u8; 128]; + match dev.listen(&mut buf).await { + Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]), + Ok(i2c_slave::Command::Read) => loop { + match dev.respond_to_read(&[state]).await { + Ok(x) => match x { + i2c_slave::ReadStatus::Done => break, + i2c_slave::ReadStatus::NeedMoreBytes => (), + i2c_slave::ReadStatus::LeftoverBytes(x) => { + info!("tried to write {} extra bytes", x); + break; + } + }, + Err(e) => error!("error while responding {}", e), + } + }, + Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]), + Ok(i2c_slave::Command::WriteRead(len)) => { + info!("device received write read: {:x}", buf[..len]); + match buf[0] { + // Set the state + 0xC2 => { + state = buf[1]; + match dev.respond_and_fill(&[state], 0x00).await { + Ok(read_status) => info!("response read status {}", read_status), + Err(e) => error!("error while responding {}", e), + } + } + // Reset State + 0xC8 => { + state = 0; + match dev.respond_and_fill(&[state], 0x00).await { + Ok(read_status) => info!("response read status {}", read_status), + Err(e) => error!("error while responding {}", e), + } + } + x => error!("Invalid Write Read {:x}", x), + } + } + Err(e) => error!("{}", e), + } + } +} + +#[embassy_executor::task] +async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) { + info!("Controller start"); + + loop { + let mut resp_buff = [0u8; 2]; + for i in 0..10 { + match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await { + Ok(_) => info!("write_read response: {}", resp_buff), + Err(e) => error!("Error writing {}", e), + } + + Timer::after_millis(100).await; + } + match con.read(DEV_ADDR, &mut resp_buff).await { + Ok(_) => info!("read response: {}", resp_buff), + Err(e) => error!("Error writing {}", e), + } + match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await { + Ok(_) => info!("write_read response: {}", resp_buff), + Err(e) => error!("Error writing {}", e), + } + Timer::after_millis(100).await; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let d_sda = p.PIN_3; + let d_scl = p.PIN_2; + let mut config = i2c_slave::Config::default(); + config.addr = DEV_ADDR as u16; + let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); + + unwrap!(spawner.spawn(device_task(device))); + + let c_sda = p.PIN_1; + let c_scl = p.PIN_0; + let mut config = i2c::Config::default(); + config.frequency = 1_000_000; + let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); + + unwrap!(spawner.spawn(controller_task(controller))); +} diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs new file mode 100644 index 000000000..f46117f95 --- /dev/null +++ b/examples/rp23/src/bin/interrupt.rs @@ -0,0 +1,110 @@ +//! This example shows how you can use raw interrupt handlers alongside embassy. +//! The example also showcases some of the options available for sharing resources/data. +//! +//! In the example, an ADC reading is triggered every time the PWM wraps around. +//! The sample data is sent down a channel, to be processed inside a low priority task. +//! The processed data is then used to adjust the PWM duty cycle, once every second. + +#![no_std] +#![no_main] + +use core::cell::{Cell, RefCell}; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::adc::{self, Adc, Blocking}; +use embassy_rp::gpio::Pull; +use embassy_rp::interrupt; +use embassy_rp::pwm::{Config, Pwm}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::channel::Channel; +use embassy_time::{Duration, Ticker}; +use portable_atomic::{AtomicU32, Ordering}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +static COUNTER: AtomicU32 = AtomicU32::new(0); +static PWM: Mutex>> = Mutex::new(RefCell::new(None)); +static ADC: Mutex, adc::Channel)>>> = + Mutex::new(RefCell::new(None)); +static ADC_VALUES: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + embassy_rp::pac::SIO.spinlock(31).write_value(1); + let p = embassy_rp::init(Default::default()); + + let adc = Adc::new_blocking(p.ADC, Default::default()); + let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None); + ADC.lock(|a| a.borrow_mut().replace((adc, p26))); + + let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default()); + PWM.lock(|p| p.borrow_mut().replace(pwm)); + + // Enable the interrupt for pwm slice 4 + embassy_rp::pac::PWM.irq0_inte().modify(|w| w.set_ch4(true)); + unsafe { + cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP_0); + } + + // Tasks require their resources to have 'static lifetime + // No Mutex needed when sharing within the same executor/prio level + static AVG: StaticCell> = StaticCell::new(); + let avg = AVG.init(Default::default()); + spawner.must_spawn(processing(avg)); + + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + ticker.next().await; + let freq = COUNTER.swap(0, Ordering::Relaxed); + info!("pwm freq: {:?} Hz", freq); + info!("adc average: {:?}", avg.get()); + + // Update the pwm duty cycle, based on the averaged adc reading + let mut config = Config::default(); + config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _; + PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config)); + } +} + +#[embassy_executor::task] +async fn processing(avg: &'static Cell) { + let mut buffer: heapless::HistoryBuffer = Default::default(); + loop { + let val = ADC_VALUES.receive().await; + buffer.write(val); + let sum: u32 = buffer.iter().map(|x| *x as u32).sum(); + avg.set(sum / buffer.len() as u32); + } +} + +#[interrupt] +fn PWM_IRQ_WRAP_0() { + critical_section::with(|cs| { + let mut adc = ADC.borrow(cs).borrow_mut(); + let (adc, p26) = adc.as_mut().unwrap(); + let val = adc.blocking_read(p26).unwrap(); + ADC_VALUES.try_send(val).ok(); + + // Clear the interrupt, so we don't immediately re-enter this irq handler + PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped(); + }); + COUNTER.fetch_add(1, Ordering::Relaxed); +} diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs new file mode 100644 index 000000000..0b20ecaae --- /dev/null +++ b/examples/rp23/src/bin/multicore.rs @@ -0,0 +1,82 @@ +//! This example shows how to send messages between the two cores in the RP2040 chip. +//! +//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Executor; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::Channel; +use embassy_time::Timer; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +static mut CORE1_STACK: Stack<4096> = Stack::new(); +static EXECUTOR0: StaticCell = StaticCell::new(); +static EXECUTOR1: StaticCell = StaticCell::new(); +static CHANNEL: Channel = Channel::new(); + +enum LedState { + On, + Off, +} + +#[cortex_m_rt::entry] +fn main() -> ! { + let p = embassy_rp::init(Default::default()); + let led = Output::new(p.PIN_25, Level::Low); + + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); + }, + ); + + let executor0 = EXECUTOR0.init(Executor::new()); + executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); +} + +#[embassy_executor::task] +async fn core0_task() { + info!("Hello from core 0"); + loop { + CHANNEL.send(LedState::On).await; + Timer::after_millis(100).await; + CHANNEL.send(LedState::Off).await; + Timer::after_millis(400).await; + } +} + +#[embassy_executor::task] +async fn core1_task(mut led: Output<'static>) { + info!("Hello from core 1"); + loop { + match CHANNEL.receive().await { + LedState::On => led.set_high(), + LedState::Off => led.set_low(), + } + } +} diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs new file mode 100644 index 000000000..52c801973 --- /dev/null +++ b/examples/rp23/src/bin/multiprio.rs @@ -0,0 +1,161 @@ +//! This example showcases how to create multiple Executor instances to run tasks at +//! different priority levels. +//! +//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling +//! there's work in the queue, and `wfe` for waiting for work. +//! +//! Medium and high priority executors run in two interrupts with different priorities. +//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since +//! when there's work the interrupt will trigger and run the executor. +//! +//! Sample output below. Note that high priority ticks can interrupt everything else, and +//! medium priority computations can interrupt low priority computations, making them to appear +//! to take significantly longer time. +//! +//! ```not_rust +//! [med] Starting long computation +//! [med] done in 992 ms +//! [high] tick! +//! [low] Starting long computation +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [low] done in 3972 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! ``` +//! +//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. +//! You will get an output like the following. Note that no computation is ever interrupted. +//! +//! ```not_rust +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [low] Starting long computation +//! [low] done in 992 ms +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! [low] Starting long computation +//! [low] done in 992 ms +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! ``` +//! + +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::{info, unwrap}; +use embassy_executor::{Executor, InterruptExecutor}; +use embassy_rp::interrupt; +use embassy_rp::interrupt::{InterruptExt, Priority}; +use embassy_time::{Instant, Timer, TICK_HZ}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::task] +async fn run_high() { + loop { + info!(" [high] tick!"); + Timer::after_ticks(673740).await; + } +} + +#[embassy_executor::task] +async fn run_med() { + loop { + let start = Instant::now(); + info!(" [med] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; + info!(" [med] done in {} ms", ms); + + Timer::after_ticks(53421).await; + } +} + +#[embassy_executor::task] +async fn run_low() { + loop { + let start = Instant::now(); + info!("[low] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; + info!("[low] done in {} ms", ms); + + Timer::after_ticks(82983).await; + } +} + +static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); +static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); +static EXECUTOR_LOW: StaticCell = StaticCell::new(); + +#[interrupt] +unsafe fn SWI_IRQ_1() { + EXECUTOR_HIGH.on_interrupt() +} + +#[interrupt] +unsafe fn SWI_IRQ_0() { + EXECUTOR_MED.on_interrupt() +} + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let _p = embassy_rp::init(Default::default()); + + // High-priority executor: SWI_IRQ_1, priority level 2 + interrupt::SWI_IRQ_1.set_priority(Priority::P2); + let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1); + unwrap!(spawner.spawn(run_high())); + + // Medium-priority executor: SWI_IRQ_0, priority level 3 + interrupt::SWI_IRQ_0.set_priority(Priority::P3); + let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0); + unwrap!(spawner.spawn(run_med())); + + // Low priority executor: runs in thread mode, using WFE/SEV + let executor = EXECUTOR_LOW.init(Executor::new()); + executor.run(|spawner| { + unwrap!(spawner.spawn(run_low())); + }); +} diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs new file mode 100644 index 000000000..f3a48bbce --- /dev/null +++ b/examples/rp23/src/bin/pio_async.rs @@ -0,0 +1,146 @@ +//! This example shows powerful PIO module in the RP2040 chip. + +#![no_std] +#![no_main] +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; +use fixed::traits::ToFixed; +use fixed_macro::types::U56F8; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { + // Setup sm0 + + // Send data serially to pin + let prg = pio_proc::pio_asm!( + ".origin 16", + "set pindirs, 1", + ".wrap_target", + "out pins,1 [19]", + ".wrap", + ); + + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + let out_pin = pio.make_pio_pin(pin); + cfg.set_out_pins(&[&out_pin]); + cfg.set_set_pins(&[&out_pin]); + cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed(); + cfg.shift_out.auto_fill = true; + sm.set_config(&cfg); +} + +#[embassy_executor::task] +async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) { + sm.set_enable(true); + + let mut v = 0x0f0caffa; + loop { + sm.tx().wait_push(v).await; + v ^= 0xffff; + info!("Pushed {:032b} to FIFO", v); + } +} + +fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) { + // Setupm sm1 + + // Read 0b10101 repeatedly until ISR is full + let prg = pio_proc::pio_asm!( + // + ".origin 8", + "set x, 0x15", + ".wrap_target", + "in x, 5 [31]", + ".wrap", + ); + + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); + cfg.shift_in.auto_fill = true; + cfg.shift_in.direction = ShiftDirection::Right; + sm.set_config(&cfg); +} + +#[embassy_executor::task] +async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) { + sm.set_enable(true); + loop { + let rx = sm.rx().wait_pull().await; + info!("Pulled {:032b} from FIFO", rx); + } +} + +fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) { + // Setup sm2 + + // Repeatedly trigger IRQ 3 + let prg = pio_proc::pio_asm!( + ".origin 0", + ".wrap_target", + "set x,10", + "delay:", + "jmp x-- delay [15]", + "irq 3 [15]", + ".wrap", + ); + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); + sm.set_config(&cfg); +} + +#[embassy_executor::task] +async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) { + sm.set_enable(true); + loop { + irq.wait().await; + info!("IRQ trigged"); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let pio = p.PIO0; + + let Pio { + mut common, + irq3, + mut sm0, + mut sm1, + mut sm2, + .. + } = Pio::new(pio, Irqs); + + setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0); + setup_pio_task_sm1(&mut common, &mut sm1); + setup_pio_task_sm2(&mut common, &mut sm2); + spawner.spawn(pio_task_sm0(sm0)).unwrap(); + spawner.spawn(pio_task_sm1(sm1)).unwrap(); + spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap(); +} diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs new file mode 100644 index 000000000..d5a831d09 --- /dev/null +++ b/examples/rp23/src/bin/pio_dma.rs @@ -0,0 +1,99 @@ +//! This example shows powerful PIO module in the RP2040 chip. + +#![no_std] +#![no_main] +use defmt::info; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; +use embassy_rp::{bind_interrupts, Peripheral}; +use fixed::traits::ToFixed; +use fixed_macro::types::U56F8; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +fn swap_nibbles(v: u32) -> u32 { + let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4; + let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8; + (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16 +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let pio = p.PIO0; + let Pio { + mut common, + sm0: mut sm, + .. + } = Pio::new(pio, Irqs); + + let prg = pio_proc::pio_asm!( + ".origin 0", + "set pindirs,1", + ".wrap_target", + "set y,7", + "loop:", + "out x,4", + "in x,4", + "jmp y--, loop", + ".wrap", + ); + + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&prg.program), &[]); + cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed(); + cfg.shift_in = ShiftConfig { + auto_fill: true, + threshold: 32, + direction: ShiftDirection::Left, + }; + cfg.shift_out = ShiftConfig { + auto_fill: true, + threshold: 32, + direction: ShiftDirection::Right, + }; + + sm.set_config(&cfg); + sm.set_enable(true); + + let mut dma_out_ref = p.DMA_CH0.into_ref(); + let mut dma_in_ref = p.DMA_CH1.into_ref(); + let mut dout = [0x12345678u32; 29]; + for i in 1..dout.len() { + dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; + } + let mut din = [0u32; 29]; + loop { + let (rx, tx) = sm.rx_tx(); + join( + tx.dma_push(dma_out_ref.reborrow(), &dout), + rx.dma_pull(dma_in_ref.reborrow(), &mut din), + ) + .await; + for i in 0..din.len() { + assert_eq!(din[i], swap_nibbles(dout[i])); + } + info!("Swapped {} words", dout.len()); + } +} diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs new file mode 100644 index 000000000..f601bbc66 --- /dev/null +++ b/examples/rp23/src/bin/pio_hd44780.rs @@ -0,0 +1,256 @@ +//! This example shows powerful PIO module in the RP2040 chip to communicate with a HD44780 display. +//! See (https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) + +#![no_std] +#![no_main] + +use core::fmt::Write; + +use embassy_executor::Spawner; +use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{ + Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, +}; +use embassy_rp::pwm::{self, Pwm}; +use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; +use embassy_time::{Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(pub struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // this test assumes a 2x16 HD44780 display attached as follow: + // rs = PIN0 + // rw = PIN1 + // e = PIN2 + // db4 = PIN3 + // db5 = PIN4 + // db6 = PIN5 + // db7 = PIN6 + // additionally a pwm signal for a bias voltage charge pump is provided on pin 15, + // allowing direct connection of the display to the RP2040 without level shifters. + let p = embassy_rp::init(Default::default()); + + let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, { + let mut c = pwm::Config::default(); + c.divider = 125.into(); + c.top = 100; + c.compare_b = 50; + c + }); + + let mut hd = HD44780::new( + p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, + ) + .await; + + loop { + struct Buf([u8; N], usize); + impl Write for Buf { + fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { + for b in s.as_bytes() { + if self.1 >= N { + return Err(core::fmt::Error); + } + self.0[self.1] = *b; + self.1 += 1; + } + Ok(()) + } + } + let mut buf = Buf([0; 16], 0); + write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap(); + hd.add_line(&buf.0[0..buf.1]).await; + Timer::after_secs(1).await; + } +} + +pub struct HD44780<'l> { + dma: PeripheralRef<'l, AnyChannel>, + sm: StateMachine<'l, PIO0, 0>, + + buf: [u8; 40], +} + +impl<'l> HD44780<'l> { + pub async fn new( + pio: impl Peripheral

+ 'l, + irq: Irqs, + dma: impl Peripheral

+ 'l, + rs: impl PioPin, + rw: impl PioPin, + e: impl PioPin, + db4: impl PioPin, + db5: impl PioPin, + db6: impl PioPin, + db7: impl PioPin, + ) -> HD44780<'l> { + into_ref!(dma); + + let Pio { + mut common, + mut irq0, + mut sm0, + .. + } = Pio::new(pio, irq); + + // takes command words ( <0:4>) + let prg = pio_proc::pio_asm!( + r#" + .side_set 1 opt + .origin 20 + + loop: + out x, 24 + delay: + jmp x--, delay + out pins, 4 side 1 + out null, 4 side 0 + jmp !osre, loop + irq 0 + "#, + ); + + let rs = common.make_pio_pin(rs); + let rw = common.make_pio_pin(rw); + let e = common.make_pio_pin(e); + let db4 = common.make_pio_pin(db4); + let db5 = common.make_pio_pin(db5); + let db6 = common.make_pio_pin(db6); + let db7 = common.make_pio_pin(db7); + + sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); + + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&prg.program), &[&e]); + cfg.clock_divider = 125u8.into(); + cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); + cfg.shift_out = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Left, + threshold: 32, + }; + cfg.fifo_join = FifoJoin::TxOnly; + sm0.set_config(&cfg); + + sm0.set_enable(true); + // init to 8 bit thrice + sm0.tx().push((50000 << 8) | 0x30); + sm0.tx().push((5000 << 8) | 0x30); + sm0.tx().push((200 << 8) | 0x30); + // init 4 bit + sm0.tx().push((200 << 8) | 0x20); + // set font and lines + sm0.tx().push((50 << 8) | 0x20); + sm0.tx().push(0b1100_0000); + + irq0.wait().await; + sm0.set_enable(false); + + // takes command sequences ( , data...) + // many side sets are only there to free up a delay bit! + let prg = pio_proc::pio_asm!( + r#" + .origin 27 + .side_set 1 + + .wrap_target + pull side 0 + out x 1 side 0 ; !rs + out y 7 side 0 ; #data - 1 + + ; rs/rw to e: >= 60ns + ; e high time: >= 500ns + ; e low time: >= 500ns + ; read data valid after e falling: ~5ns + ; write data hold after e falling: ~10ns + + loop: + pull side 0 + jmp !x data side 0 + command: + set pins 0b00 side 0 + jmp shift side 0 + data: + set pins 0b01 side 0 + shift: + out pins 4 side 1 [9] + nop side 0 [9] + out pins 4 side 1 [9] + mov osr null side 0 [7] + out pindirs 4 side 0 + set pins 0b10 side 0 + busy: + nop side 1 [9] + jmp pin more side 0 [9] + mov osr ~osr side 1 [9] + nop side 0 [4] + out pindirs 4 side 0 + jmp y-- loop side 0 + .wrap + more: + nop side 1 [9] + jmp busy side 0 [9] + "# + ); + + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&prg.program), &[&e]); + cfg.clock_divider = 8u8.into(); // ~64ns/insn + cfg.set_jmp_pin(&db7); + cfg.set_set_pins(&[&rs, &rw]); + cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); + cfg.shift_out.direction = ShiftDirection::Left; + cfg.fifo_join = FifoJoin::TxOnly; + sm0.set_config(&cfg); + + sm0.set_enable(true); + + // display on and cursor on and blinking, reset display + sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; + + Self { + dma: dma.map_into(), + sm: sm0, + buf: [0x20; 40], + } + } + + pub async fn add_line(&mut self, s: &[u8]) { + // move cursor to 0:0, prepare 16 characters + self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); + // move line 2 up + self.buf.copy_within(22..38, 3); + // move cursor to 1:0, prepare 16 characters + self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); + // file line 2 with spaces + self.buf[22..38].fill(0x20); + // copy input line + let len = s.len().min(16); + self.buf[22..22 + len].copy_from_slice(&s[0..len]); + // set cursor to 1:15 + self.buf[38..].copy_from_slice(&[0x80, 0xcf]); + + self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; + } +} diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs new file mode 100644 index 000000000..b12b050e6 --- /dev/null +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -0,0 +1,141 @@ +//! This example shows generating audio and sending it to a connected i2s DAC using the PIO +//! module of the RP2040. +//! +//! Connect the i2s DAC as follows: +//! bclk : GPIO 18 +//! lrc : GPIO 19 +//! din : GPIO 20 +//! Then hold down the boot select button to trigger a rising triangle waveform. + +#![no_std] +#![no_main] + +use core::mem; + +use embassy_executor::Spawner; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; +use embassy_rp::{bind_interrupts, Peripheral}; +use fixed::traits::ToFixed; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +const SAMPLE_RATE: u32 = 48_000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + // Setup pio state machine for i2s output + let mut pio = Pio::new(p.PIO0, Irqs); + + #[rustfmt::skip] + let pio_program = pio_proc::pio_asm!( + ".side_set 2", + " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock + "left_data:", + " out pins, 1 side 0b00", + " jmp x-- left_data side 0b01", + " out pins 1 side 0b10", + " set x, 14 side 0b11", + "right_data:", + " out pins 1 side 0b10", + " jmp x-- right_data side 0b11", + " out pins 1 side 0b00", + ); + + let bit_clock_pin = p.PIN_18; + let left_right_clock_pin = p.PIN_19; + let data_pin = p.PIN_20; + + let data_pin = pio.common.make_pio_pin(data_pin); + let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); + let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); + + let cfg = { + let mut cfg = Config::default(); + cfg.use_program( + &pio.common.load_program(&pio_program.program), + &[&bit_clock_pin, &left_right_clock_pin], + ); + cfg.set_out_pins(&[&data_pin]); + const BIT_DEPTH: u32 = 16; + const CHANNELS: u32 = 2; + let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS; + cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); + cfg.shift_out = ShiftConfig { + threshold: 32, + direction: ShiftDirection::Left, + auto_fill: true, + }; + // join fifos to have twice the time to start the next dma transfer + cfg.fifo_join = FifoJoin::TxOnly; + cfg + }; + pio.sm0.set_config(&cfg); + pio.sm0.set_pin_dirs( + embassy_rp::pio::Direction::Out, + &[&data_pin, &left_right_clock_pin, &bit_clock_pin], + ); + + // create two audio buffers (back and front) which will take turns being + // filled with new audio data and being sent to the pio fifo using dma + const BUFFER_SIZE: usize = 960; + static DMA_BUFFER: StaticCell<[u32; BUFFER_SIZE * 2]> = StaticCell::new(); + let dma_buffer = DMA_BUFFER.init_with(|| [0u32; BUFFER_SIZE * 2]); + let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); + + // start pio state machine + pio.sm0.set_enable(true); + let tx = pio.sm0.tx(); + let mut dma_ref = p.DMA_CH0.into_ref(); + + let mut fade_value: i32 = 0; + let mut phase: i32 = 0; + + loop { + // trigger transfer of front buffer data to the pio fifo + // but don't await the returned future, yet + let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); + + // fade in audio + let fade_target = i32::MAX; + + // fill back buffer with fresh audio samples before awaiting the dma future + for s in back_buffer.iter_mut() { + // exponential approach of fade_value => fade_target + fade_value += (fade_target - fade_value) >> 14; + // generate triangle wave with amplitude and frequency based on fade value + phase = (phase + (fade_value >> 22)) & 0xffff; + let triangle_sample = (phase as i16 as i32).abs() - 16384; + let sample = (triangle_sample * (fade_value >> 15)) >> 16; + // duplicate mono sample into lower and upper half of dma word + *s = (sample as u16 as u32) * 0x10001; + } + + // now await the dma future. once the dma finishes, the next buffer needs to be queued + // within DMA_DEPTH / SAMPLE_RATE = 8 / 48000 seconds = 166us + dma_future.await; + mem::swap(&mut back_buffer, &mut front_buffer); + } +} diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs new file mode 100644 index 000000000..c8e834eae --- /dev/null +++ b/examples/rp23/src/bin/pio_pwm.rs @@ -0,0 +1,134 @@ +//! This example shows how to create a pwm using the PIO module in the RP2040 chip. + +#![no_std] +#![no_main] +use core::time::Duration; + +use embassy_executor::Spawner; +use embassy_rp::gpio::Level; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; +use embassy_rp::{bind_interrupts, clocks}; +use embassy_time::Timer; +use pio::InstructionOperands; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +const REFRESH_INTERVAL: u64 = 20000; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub fn to_pio_cycles(duration: Duration) -> u32 { + (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow +} + +pub struct PwmPio<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { + pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { + let prg = pio_proc::pio_asm!( + ".side_set 1 opt" + "pull noblock side 0" + "mov x, osr" + "mov y, isr" + "countloop:" + "jmp x!=y noset" + "jmp skip side 1" + "noset:" + "nop" + "skip:" + "jmp y-- countloop" + ); + + pio.load_program(&prg.program); + let pin = pio.make_pio_pin(pin); + sm.set_pins(Level::High, &[&pin]); + sm.set_pin_dirs(Direction::Out, &[&pin]); + + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&prg.program), &[&pin]); + + sm.set_config(&cfg); + + Self { sm } + } + + pub fn start(&mut self) { + self.sm.set_enable(true); + } + + pub fn stop(&mut self) { + self.sm.set_enable(false); + } + + pub fn set_period(&mut self, duration: Duration) { + let is_enabled = self.sm.is_enabled(); + while !self.sm.tx().empty() {} // Make sure that the queue is empty + self.sm.set_enable(false); + self.sm.tx().push(to_pio_cycles(duration)); + unsafe { + self.sm.exec_instr( + InstructionOperands::PULL { + if_empty: false, + block: false, + } + .encode(), + ); + self.sm.exec_instr( + InstructionOperands::OUT { + destination: ::pio::OutDestination::ISR, + bit_count: 32, + } + .encode(), + ); + }; + if is_enabled { + self.sm.set_enable(true) // Enable if previously enabled + } + } + + pub fn set_level(&mut self, level: u32) { + self.sm.tx().push(level); + } + + pub fn write(&mut self, duration: Duration) { + self.set_level(to_pio_cycles(duration)); + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + // Note that PIN_25 is the led pin on the Pico + let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); + pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); + pwm_pio.start(); + + let mut duration = 0; + loop { + duration = (duration + 1) % 1000; + pwm_pio.write(Duration::from_micros(duration)); + Timer::after_millis(1).await; + } +} diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs new file mode 100644 index 000000000..971b55c9e --- /dev/null +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -0,0 +1,96 @@ +//! This example shows how to use the PIO module in the RP2040 to read a quadrature rotary encoder. + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::gpio::Pull; +use embassy_rp::peripherals::PIO0; +use embassy_rp::{bind_interrupts, pio}; +use fixed::traits::ToFixed; +use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub struct PioEncoder<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + pin_a: impl PioPin, + pin_b: impl PioPin, + ) -> Self { + let mut pin_a = pio.make_pio_pin(pin_a); + let mut pin_b = pio.make_pio_pin(pin_b); + pin_a.set_pull(Pull::Up); + pin_b.set_pull(Pull::Up); + sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); + + let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); + + let mut cfg = Config::default(); + cfg.set_in_pins(&[&pin_a, &pin_b]); + cfg.fifo_join = FifoJoin::RxOnly; + cfg.shift_in.direction = ShiftDirection::Left; + cfg.clock_divider = 10_000.to_fixed(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + sm.set_config(&cfg); + sm.set_enable(true); + Self { sm } + } + + pub async fn read(&mut self) -> Direction { + loop { + match self.sm.rx().wait_pull().await { + 0 => return Direction::CounterClockwise, + 1 => return Direction::Clockwise, + _ => {} + } + } + } +} + +pub enum Direction { + Clockwise, + CounterClockwise, +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); + + let mut count = 0; + loop { + info!("Count: {}", count); + count += match encoder.read().await { + Direction::Clockwise => 1, + Direction::CounterClockwise => -1, + }; + } +} diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs new file mode 100644 index 000000000..67e52019a --- /dev/null +++ b/examples/rp23/src/bin/pio_servo.rs @@ -0,0 +1,224 @@ +//! This example shows how to create a pwm using the PIO module in the RP2040 chip. + +#![no_std] +#![no_main] +use core::time::Duration; + +use embassy_executor::Spawner; +use embassy_rp::gpio::Level; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; +use embassy_rp::{bind_interrupts, clocks}; +use embassy_time::Timer; +use pio::InstructionOperands; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo +const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo +const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical +const REFRESH_INTERVAL: u64 = 20000; // The period of each cycle + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub fn to_pio_cycles(duration: Duration) -> u32 { + (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow +} + +pub struct PwmPio<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { + pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { + let prg = pio_proc::pio_asm!( + ".side_set 1 opt" + "pull noblock side 0" + "mov x, osr" + "mov y, isr" + "countloop:" + "jmp x!=y noset" + "jmp skip side 1" + "noset:" + "nop" + "skip:" + "jmp y-- countloop" + ); + + pio.load_program(&prg.program); + let pin = pio.make_pio_pin(pin); + sm.set_pins(Level::High, &[&pin]); + sm.set_pin_dirs(Direction::Out, &[&pin]); + + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&prg.program), &[&pin]); + + sm.set_config(&cfg); + + Self { sm } + } + + pub fn start(&mut self) { + self.sm.set_enable(true); + } + + pub fn stop(&mut self) { + self.sm.set_enable(false); + } + + pub fn set_period(&mut self, duration: Duration) { + let is_enabled = self.sm.is_enabled(); + while !self.sm.tx().empty() {} // Make sure that the queue is empty + self.sm.set_enable(false); + self.sm.tx().push(to_pio_cycles(duration)); + unsafe { + self.sm.exec_instr( + InstructionOperands::PULL { + if_empty: false, + block: false, + } + .encode(), + ); + self.sm.exec_instr( + InstructionOperands::OUT { + destination: ::pio::OutDestination::ISR, + bit_count: 32, + } + .encode(), + ); + }; + if is_enabled { + self.sm.set_enable(true) // Enable if previously enabled + } + } + + pub fn set_level(&mut self, level: u32) { + self.sm.tx().push(level); + } + + pub fn write(&mut self, duration: Duration) { + self.set_level(to_pio_cycles(duration)); + } +} + +pub struct ServoBuilder<'d, T: Instance, const SM: usize> { + pwm: PwmPio<'d, T, SM>, + period: Duration, + min_pulse_width: Duration, + max_pulse_width: Duration, + max_degree_rotation: u64, +} + +impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { + pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { + Self { + pwm, + period: Duration::from_micros(REFRESH_INTERVAL), + min_pulse_width: Duration::from_micros(DEFAULT_MIN_PULSE_WIDTH), + max_pulse_width: Duration::from_micros(DEFAULT_MAX_PULSE_WIDTH), + max_degree_rotation: DEFAULT_MAX_DEGREE_ROTATION, + } + } + + pub fn set_period(mut self, duration: Duration) -> Self { + self.period = duration; + self + } + + pub fn set_min_pulse_width(mut self, duration: Duration) -> Self { + self.min_pulse_width = duration; + self + } + + pub fn set_max_pulse_width(mut self, duration: Duration) -> Self { + self.max_pulse_width = duration; + self + } + + pub fn set_max_degree_rotation(mut self, degree: u64) -> Self { + self.max_degree_rotation = degree; + self + } + + pub fn build(mut self) -> Servo<'d, T, SM> { + self.pwm.set_period(self.period); + Servo { + pwm: self.pwm, + min_pulse_width: self.min_pulse_width, + max_pulse_width: self.max_pulse_width, + max_degree_rotation: self.max_degree_rotation, + } + } +} + +pub struct Servo<'d, T: Instance, const SM: usize> { + pwm: PwmPio<'d, T, SM>, + min_pulse_width: Duration, + max_pulse_width: Duration, + max_degree_rotation: u64, +} + +impl<'d, T: Instance, const SM: usize> Servo<'d, T, SM> { + pub fn start(&mut self) { + self.pwm.start(); + } + + pub fn stop(&mut self) { + self.pwm.stop(); + } + + pub fn write_time(&mut self, duration: Duration) { + self.pwm.write(duration); + } + + pub fn rotate(&mut self, degree: u64) { + let degree_per_nano_second = (self.max_pulse_width.as_nanos() as u64 - self.min_pulse_width.as_nanos() as u64) + / self.max_degree_rotation; + let mut duration = + Duration::from_nanos(degree * degree_per_nano_second + self.min_pulse_width.as_nanos() as u64); + if self.max_pulse_width < duration { + duration = self.max_pulse_width; + } + + self.pwm.write(duration); + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); + let mut servo = ServoBuilder::new(pwm_pio) + .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo + .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. + .set_max_pulse_width(Duration::from_micros(2600)) // Along with this value. + .build(); + + servo.start(); + + let mut degree = 0; + loop { + degree = (degree + 1) % 120; + servo.rotate(degree); + Timer::after_millis(50).await; + } +} diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs new file mode 100644 index 000000000..9cbf0bd92 --- /dev/null +++ b/examples/rp23/src/bin/pio_stepper.rs @@ -0,0 +1,184 @@ +//! This example shows how to use the PIO module in the RP2040 to implement a stepper motor driver +//! for a 5-wire stepper such as the 28BYJ-48. You can halt an ongoing rotation by dropping the future. + +#![no_std] +#![no_main] +use core::mem::{self, MaybeUninit}; + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; +use embassy_time::{with_timeout, Duration, Timer}; +use fixed::traits::ToFixed; +use fixed::types::extra::U8; +use fixed::FixedU32; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub struct PioStepper<'d, T: Instance, const SM: usize> { + irq: Irq<'d, T, SM>, + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + irq: Irq<'d, T, SM>, + pin0: impl PioPin, + pin1: impl PioPin, + pin2: impl PioPin, + pin3: impl PioPin, + ) -> Self { + let prg = pio_proc::pio_asm!( + "pull block", + "mov x, osr", + "pull block", + "mov y, osr", + "jmp !x end", + "loop:", + "jmp !osre step", + "mov osr, y", + "step:", + "out pins, 4 [31]" + "jmp x-- loop", + "end:", + "irq 0 rel" + ); + let pin0 = pio.make_pio_pin(pin0); + let pin1 = pio.make_pio_pin(pin1); + let pin2 = pio.make_pio_pin(pin2); + let pin3 = pio.make_pio_pin(pin3); + sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); + let mut cfg = Config::default(); + cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); + cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + sm.set_config(&cfg); + sm.set_enable(true); + Self { irq, sm } + } + + // Set pulse frequency + pub fn set_frequency(&mut self, freq: u32) { + let clock_divider: FixedU32 = (125_000_000 / (freq * 136)).to_fixed(); + assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); + assert!(clock_divider >= 1, "clkdiv must be >= 1"); + self.sm.set_clock_divider(clock_divider); + self.sm.clkdiv_restart(); + } + + // Full step, one phase + pub async fn step(&mut self, steps: i32) { + if steps > 0 { + self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await + } else { + self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await + } + } + + // Full step, two phase + pub async fn step2(&mut self, steps: i32) { + if steps > 0 { + self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await + } else { + self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await + } + } + + // Half step + pub async fn step_half(&mut self, steps: i32) { + if steps > 0 { + self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await + } else { + self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await + } + } + + async fn run(&mut self, steps: i32, pattern: u32) { + self.sm.tx().wait_push(steps as u32).await; + self.sm.tx().wait_push(pattern).await; + let drop = OnDrop::new(|| { + self.sm.clear_fifos(); + unsafe { + self.sm.exec_instr( + pio::InstructionOperands::JMP { + address: 0, + condition: pio::JmpCondition::Always, + } + .encode(), + ); + } + }); + self.irq.wait().await; + drop.defuse(); + } +} + +struct OnDrop { + f: MaybeUninit, +} + +impl OnDrop { + pub fn new(f: F) -> Self { + Self { f: MaybeUninit::new(f) } + } + + pub fn defuse(self) { + mem::forget(self) + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { + mut common, irq0, sm0, .. + } = Pio::new(p.PIO0, Irqs); + + let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); + stepper.set_frequency(120); + loop { + info!("CW full steps"); + stepper.step(1000).await; + + info!("CCW full steps, drop after 1 sec"); + if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await { + info!("Time's up!"); + Timer::after(Duration::from_secs(1)).await; + } + + info!("CW half steps"); + stepper.step_half(1000).await; + + info!("CCW half steps"); + stepper.step_half(-1000).await; + } +} diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs new file mode 100644 index 000000000..2e62a3d97 --- /dev/null +++ b/examples/rp23/src/bin/pio_ws2812.rs @@ -0,0 +1,177 @@ +//! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules. +//! See (https://www.sparkfun.com/categories/tags/ws2812) + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{ + Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, +}; +use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; +use embassy_time::{Duration, Ticker, Timer}; +use fixed::types::U24F8; +use fixed_macro::fixed; +use smart_leds::RGB8; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { + dma: PeripheralRef<'d, AnyChannel>, + sm: StateMachine<'d, P, S>, +} + +impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { + pub fn new( + pio: &mut Common<'d, P>, + mut sm: StateMachine<'d, P, S>, + dma: impl Peripheral

+ 'd, + pin: impl PioPin, + ) -> Self { + into_ref!(dma); + + // Setup sm0 + + // prepare the PIO program + let side_set = pio::SideSet::new(false, 1, false); + let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); + + const T1: u8 = 2; // start bit + const T2: u8 = 5; // data bit + const T3: u8 = 3; // stop bit + const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; + + let mut wrap_target = a.label(); + let mut wrap_source = a.label(); + let mut do_zero = a.label(); + a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); + a.bind(&mut wrap_target); + // Do stop bit + a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); + // Do start bit + a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); + // Do data bit = 1 + a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); + a.bind(&mut do_zero); + // Do data bit = 0 + a.nop_with_delay_and_side_set(T2 - 1, 0); + a.bind(&mut wrap_source); + + let prg = a.assemble_with_wrap(wrap_source, wrap_target); + let mut cfg = Config::default(); + + // Pin config + let out_pin = pio.make_pio_pin(pin); + cfg.set_out_pins(&[&out_pin]); + cfg.set_set_pins(&[&out_pin]); + + cfg.use_program(&pio.load_program(&prg), &[&out_pin]); + + // Clock config, measured in kHz to avoid overflows + // TODO CLOCK_FREQ should come from embassy_rp + let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); + let ws2812_freq = fixed!(800: U24F8); + let bit_freq = ws2812_freq * CYCLES_PER_BIT; + cfg.clock_divider = clock_freq / bit_freq; + + // FIFO config + cfg.fifo_join = FifoJoin::TxOnly; + cfg.shift_out = ShiftConfig { + auto_fill: true, + threshold: 24, + direction: ShiftDirection::Left, + }; + + sm.set_config(&cfg); + sm.set_enable(true); + + Self { + dma: dma.map_into(), + sm, + } + } + + pub async fn write(&mut self, colors: &[RGB8; N]) { + // Precompute the word bytes from the colors + let mut words = [0u32; N]; + for i in 0..N { + let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); + words[i] = word; + } + + // DMA transfer + self.sm.tx().dma_push(self.dma.reborrow(), &words).await; + + Timer::after_micros(55).await; + } +} + +/// Input a value 0 to 255 to get a color value +/// The colours are a transition r - g - b - back to r. +fn wheel(mut wheel_pos: u8) -> RGB8 { + wheel_pos = 255 - wheel_pos; + if wheel_pos < 85 { + return (255 - wheel_pos * 3, 0, wheel_pos * 3).into(); + } + if wheel_pos < 170 { + wheel_pos -= 85; + return (0, wheel_pos * 3, 255 - wheel_pos * 3).into(); + } + wheel_pos -= 170; + (wheel_pos * 3, 255 - wheel_pos * 3, 0).into() +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Start"); + let p = embassy_rp::init(Default::default()); + + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit + // feather boards for the 2040 both have one built in. + const NUM_LEDS: usize = 1; + let mut data = [RGB8::default(); NUM_LEDS]; + + // Common neopixel pins: + // Thing plus: 8 + // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 + let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); + + // Loop forever making RGB values and pushing them out to the WS2812. + let mut ticker = Ticker::every(Duration::from_millis(10)); + loop { + for j in 0..(256 * 5) { + debug!("New Colors:"); + for i in 0..NUM_LEDS { + data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8); + debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b); + } + ws2812.write(&data).await; + + ticker.next().await; + } + } +} diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs new file mode 100644 index 000000000..ab38a03bb --- /dev/null +++ b/examples/rp23/src/bin/pwm.rs @@ -0,0 +1,45 @@ +//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip. +//! +//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::pwm::{Config, Pwm}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let mut c: Config = Default::default(); + c.top = 0x8000; + c.compare_b = 8; + let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); + + loop { + info!("current LED duty cycle: {}/32768", c.compare_b); + Timer::after_secs(1).await; + c.compare_b = c.compare_b.rotate_left(4); + pwm.set_config(&c); + } +} diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs new file mode 100644 index 000000000..fcb561cfd --- /dev/null +++ b/examples/rp23/src/bin/pwm_input.rs @@ -0,0 +1,42 @@ +//! This example shows how to use the PWM module to measure the frequency of an input signal. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio::Pull; +use embassy_rp::pwm::{Config, InputMode, Pwm}; +use embassy_time::{Duration, Ticker}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let cfg: Config = Default::default(); + let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, Pull::None, InputMode::RisingEdge, cfg); + + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + info!("Input frequency: {} Hz", pwm.counter()); + pwm.set_counter(0); + ticker.next().await; + } +} diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs new file mode 100644 index 000000000..051b4710f --- /dev/null +++ b/examples/rp23/src/bin/rosc.rs @@ -0,0 +1,47 @@ +//! This example test the RP Pico on board LED. +//! +//! It does not work with the RP Pico W board. See wifi_blinky.rs. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::{clocks, gpio}; +use embassy_time::Timer; +use gpio::{Level, Output}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_rp::config::Config::default(); + config.clocks = clocks::ClockConfig::rosc(); + let p = embassy_rp::init(config); + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + info!("led on!"); + led.set_high(); + Timer::after_secs(1).await; + + info!("led off!"); + led.set_low(); + Timer::after_secs(1).await; + } +} diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs new file mode 100644 index 000000000..e3213cd91 --- /dev/null +++ b/examples/rp23/src/bin/shared_bus.rs @@ -0,0 +1,131 @@ +//! This example shows how to share (async) I2C and SPI buses between multiple devices. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; +use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::{AnyPin, Level, Output}; +use embassy_rp::i2c::{self, I2c, InterruptHandler}; +use embassy_rp::peripherals::{I2C1, SPI1}; +use embassy_rp::spi::{self, Spi}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::Timer; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +type Spi1Bus = Mutex>; +type I2c1Bus = Mutex>; + +bind_interrupts!(struct Irqs { + I2C1_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Here we go!"); + + // Shared I2C bus + let i2c = I2c::new_async(p.I2C1, p.PIN_15, p.PIN_14, Irqs, i2c::Config::default()); + static I2C_BUS: StaticCell = StaticCell::new(); + let i2c_bus = I2C_BUS.init(Mutex::new(i2c)); + + spawner.must_spawn(i2c_task_a(i2c_bus)); + spawner.must_spawn(i2c_task_b(i2c_bus)); + + // Shared SPI bus + let spi_cfg = spi::Config::default(); + let spi = Spi::new(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, spi_cfg); + static SPI_BUS: StaticCell = StaticCell::new(); + let spi_bus = SPI_BUS.init(Mutex::new(spi)); + + // Chip select pins for the SPI devices + let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); + let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); + + spawner.must_spawn(spi_task_a(spi_bus, cs_a)); + spawner.must_spawn(spi_task_b(spi_bus, cs_b)); +} + +#[embassy_executor::task] +async fn i2c_task_a(i2c_bus: &'static I2c1Bus) { + let i2c_dev = I2cDevice::new(i2c_bus); + let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xC0); + loop { + info!("i2c task A"); + Timer::after_secs(1).await; + } +} + +#[embassy_executor::task] +async fn i2c_task_b(i2c_bus: &'static I2c1Bus) { + let i2c_dev = I2cDevice::new(i2c_bus); + let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xDE); + loop { + info!("i2c task B"); + Timer::after_secs(1).await; + } +} + +#[embassy_executor::task] +async fn spi_task_a(spi_bus: &'static Spi1Bus, cs: Output<'static>) { + let spi_dev = SpiDevice::new(spi_bus, cs); + let _sensor = DummySpiDeviceDriver::new(spi_dev); + loop { + info!("spi task A"); + Timer::after_secs(1).await; + } +} + +#[embassy_executor::task] +async fn spi_task_b(spi_bus: &'static Spi1Bus, cs: Output<'static>) { + let spi_dev = SpiDevice::new(spi_bus, cs); + let _sensor = DummySpiDeviceDriver::new(spi_dev); + loop { + info!("spi task B"); + Timer::after_secs(1).await; + } +} + +// Dummy I2C device driver, using `embedded-hal-async` +struct DummyI2cDeviceDriver { + _i2c: I2C, +} + +impl DummyI2cDeviceDriver { + fn new(i2c_dev: I2C, _address: u8) -> Self { + Self { _i2c: i2c_dev } + } +} + +// Dummy SPI device driver, using `embedded-hal-async` +struct DummySpiDeviceDriver { + _spi: SPI, +} + +impl DummySpiDeviceDriver { + fn new(spi_dev: SPI) -> Self { + Self { _spi: spi_dev } + } +} diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs new file mode 100644 index 000000000..10f064947 --- /dev/null +++ b/examples/rp23/src/bin/sharing.rs @@ -0,0 +1,166 @@ +//! This example shows some common strategies for sharing resources between tasks. +//! +//! We demonstrate five different ways of sharing, covering different use cases: +//! - Atomics: This method is used for simple values, such as bool and u8..u32 +//! - Blocking Mutex: This is used for sharing non-async things, using Cell/RefCell for interior mutability. +//! - Async Mutex: This is used for sharing async resources, where you need to hold the lock across await points. +//! The async Mutex has interior mutability built-in, so no RefCell is needed. +//! - Cell: For sharing Copy types between tasks running on the same executor. +//! - RefCell: When you want &mut access to a value shared between tasks running on the same executor. +//! +//! More information: https://embassy.dev/book/#_sharing_peripherals_between_tasks + +#![no_std] +#![no_main] + +use core::cell::{Cell, RefCell}; +use core::sync::atomic::{AtomicU32, Ordering}; + +use cortex_m_rt::entry; +use defmt::info; +use embassy_executor::{Executor, InterruptExecutor}; +use embassy_rp::clocks::RoscRng; +use embassy_rp::interrupt::{Priority, InterruptExt}; +use embassy_rp::peripherals::UART0; +use embassy_rp::uart::{self, InterruptHandler, UartTx}; +use embassy_rp::{bind_interrupts, interrupt}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::{blocking_mutex, mutex}; +use embassy_time::{Duration, Ticker}; +use rand::RngCore; +use static_cell::{ConstStaticCell, StaticCell}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +type UartAsyncMutex = mutex::Mutex>; + +struct MyType { + inner: u32, +} + +static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new(); +static EXECUTOR_LOW: StaticCell = StaticCell::new(); + +// Use Atomics for simple values +static ATOMIC: AtomicU32 = AtomicU32::new(0); + +// Use blocking Mutex with Cell/RefCell for sharing non-async things +static MUTEX_BLOCKING: blocking_mutex::Mutex> = + blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 })); + +bind_interrupts!(struct Irqs { + UART0_IRQ => InterruptHandler; +}); + +#[interrupt] +unsafe fn SWI_IRQ_0() { + EXECUTOR_HI.on_interrupt() +} + +#[entry] +fn main() -> ! { + let p = embassy_rp::init(Default::default()); + info!("Here we go!"); + + let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default()); + // Use the async Mutex for sharing async things (built-in interior mutability) + static UART: StaticCell = StaticCell::new(); + let uart = UART.init(mutex::Mutex::new(uart)); + + // High-priority executor: runs in interrupt mode + interrupt::SWI_IRQ_0.set_priority(Priority::P3); + let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0); + spawner.must_spawn(task_a(uart)); + + // Low priority executor: runs in thread mode + let executor = EXECUTOR_LOW.init(Executor::new()); + executor.run(|spawner| { + // No Mutex needed when sharing between tasks running on the same executor + + // Use Cell for Copy-types + static CELL: ConstStaticCell> = ConstStaticCell::new(Cell::new([0; 4])); + let cell = CELL.take(); + + // Use RefCell for &mut access + static REF_CELL: ConstStaticCell> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 })); + let ref_cell = REF_CELL.take(); + + spawner.must_spawn(task_b(uart, cell, ref_cell)); + spawner.must_spawn(task_c(cell, ref_cell)); + }); +} + +#[embassy_executor::task] +async fn task_a(uart: &'static UartAsyncMutex) { + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + let random = RoscRng.next_u32(); + + { + let mut uart = uart.lock().await; + uart.write(b"task a").await.unwrap(); + // The uart lock is released when it goes out of scope + } + + ATOMIC.store(random, Ordering::Relaxed); + + MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random); + + ticker.next().await; + } +} + +#[embassy_executor::task] +async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell) { + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + let random = RoscRng.next_u32(); + + uart.lock().await.write(b"task b").await.unwrap(); + + cell.set(random.to_be_bytes()); + + ref_cell.borrow_mut().inner = random; + + ticker.next().await; + } +} + +#[embassy_executor::task] +async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell) { + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + info!("======================="); + + let atomic_val = ATOMIC.load(Ordering::Relaxed); + info!("atomic: {}", atomic_val); + + MUTEX_BLOCKING.lock(|x| { + let val = x.borrow().inner; + info!("blocking mutex: {}", val); + }); + + let cell_val = cell.get(); + info!("cell: {:?}", cell_val); + + let ref_cell_val = ref_cell.borrow().inner; + info!("ref_cell: {:?}", ref_cell_val); + + ticker.next().await; + } +} diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs new file mode 100644 index 000000000..bcf356188 --- /dev/null +++ b/examples/rp23/src/bin/spi.rs @@ -0,0 +1,62 @@ +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! +//! Example for resistive touch sensor in Waveshare Pico-ResTouch + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::spi::Spi; +use embassy_rp::{gpio, spi}; +use gpio::{Level, Output}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + // Example for resistive touch sensor in Waveshare Pico-ResTouch + + let miso = p.PIN_12; + let mosi = p.PIN_11; + let clk = p.PIN_10; + let touch_cs = p.PIN_16; + + // create SPI + let mut config = spi::Config::default(); + config.frequency = 2_000_000; + let mut spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, config); + + // Configure CS + let mut cs = Output::new(touch_cs, Level::Low); + + loop { + cs.set_low(); + let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00]; + spi.blocking_transfer_in_place(&mut buf).unwrap(); + cs.set_high(); + + let x = (buf[1] as u32) << 5 | (buf[2] as u32) >> 3; + let y = (buf[4] as u32) << 5 | (buf[5] as u32) >> 3; + + info!("touch: {=u32} {=u32}", x, y); + } +} diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs new file mode 100644 index 000000000..7a43995d2 --- /dev/null +++ b/examples/rp23/src/bin/spi_async.rs @@ -0,0 +1,47 @@ +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::spi::{Config, Spi}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let miso = p.PIN_12; + let mosi = p.PIN_11; + let clk = p.PIN_10; + + let mut spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default()); + + loop { + let tx_buf = [1_u8, 2, 3, 4, 5, 6]; + let mut rx_buf = [0_u8; 6]; + spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); + info!("{:?}", rx_buf); + Timer::after_secs(1).await; + } +} diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs new file mode 100644 index 000000000..25368bb94 --- /dev/null +++ b/examples/rp23/src/bin/spi_display.rs @@ -0,0 +1,328 @@ +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! +//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch +//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8) + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use defmt::*; +use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; +use embassy_executor::Spawner; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::spi; +use embassy_rp::spi::{Blocking, Spi}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_time::Delay; +use embedded_graphics::image::{Image, ImageRawLE}; +use embedded_graphics::mono_font::ascii::FONT_10X20; +use embedded_graphics::mono_font::MonoTextStyle; +use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use embedded_graphics::text::Text; +use st7789::{Orientation, ST7789}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +use crate::my_display_interface::SPIDeviceInterface; +use crate::touch::Touch; + +const DISPLAY_FREQ: u32 = 64_000_000; +const TOUCH_FREQ: u32 = 200_000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let bl = p.PIN_13; + let rst = p.PIN_15; + let display_cs = p.PIN_9; + let dcx = p.PIN_8; + let miso = p.PIN_12; + let mosi = p.PIN_11; + let clk = p.PIN_10; + let touch_cs = p.PIN_16; + //let touch_irq = p.PIN_17; + + // create SPI + let mut display_config = spi::Config::default(); + display_config.frequency = DISPLAY_FREQ; + display_config.phase = spi::Phase::CaptureOnSecondTransition; + display_config.polarity = spi::Polarity::IdleHigh; + let mut touch_config = spi::Config::default(); + touch_config.frequency = TOUCH_FREQ; + touch_config.phase = spi::Phase::CaptureOnSecondTransition; + touch_config.polarity = spi::Polarity::IdleHigh; + + let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); + let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); + + let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); + let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config); + + let mut touch = Touch::new(touch_spi); + + let dcx = Output::new(dcx, Level::Low); + let rst = Output::new(rst, Level::Low); + // dcx: 0 = command, 1 = data + + // Enable LCD backlight + let _bl = Output::new(bl, Level::High); + + // display interface abstraction from SPI and DC + let di = SPIDeviceInterface::new(display_spi, dcx); + + // create driver + let mut display = ST7789::new(di, rst, 240, 320); + + // initialize + display.init(&mut Delay).unwrap(); + + // set default orientation + display.set_orientation(Orientation::Landscape).unwrap(); + + display.clear(Rgb565::BLACK).unwrap(); + + let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); + let ferris = Image::new(&raw_image_data, Point::new(34, 68)); + + // Display the image + ferris.draw(&mut display).unwrap(); + + let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN); + Text::new( + "Hello embedded_graphics \n + embassy + RP2040!", + Point::new(20, 200), + style, + ) + .draw(&mut display) + .unwrap(); + + loop { + if let Some((x, y)) = touch.read() { + let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLUE).build(); + + Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3)) + .into_styled(style) + .draw(&mut display) + .unwrap(); + } + } +} + +/// Driver for the XPT2046 resistive touchscreen sensor +mod touch { + use embedded_hal_1::spi::{Operation, SpiDevice}; + + struct Calibration { + x1: i32, + x2: i32, + y1: i32, + y2: i32, + sx: i32, + sy: i32, + } + + const CALIBRATION: Calibration = Calibration { + x1: 3880, + x2: 340, + y1: 262, + y2: 3850, + sx: 320, + sy: 240, + }; + + pub struct Touch { + spi: SPI, + } + + impl Touch + where + SPI: SpiDevice, + { + pub fn new(spi: SPI) -> Self { + Self { spi } + } + + pub fn read(&mut self) -> Option<(i32, i32)> { + let mut x = [0; 2]; + let mut y = [0; 2]; + self.spi + .transaction(&mut [ + Operation::Write(&[0x90]), + Operation::Read(&mut x), + Operation::Write(&[0xd0]), + Operation::Read(&mut y), + ]) + .unwrap(); + + let x = (u16::from_be_bytes(x) >> 3) as i32; + let y = (u16::from_be_bytes(y) >> 3) as i32; + + let cal = &CALIBRATION; + + let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx); + let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy); + if x == 0 && y == 0 { + None + } else { + Some((x, y)) + } + } + } +} + +mod my_display_interface { + use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; + use embedded_hal_1::digital::OutputPin; + use embedded_hal_1::spi::SpiDevice; + + /// SPI display interface. + /// + /// This combines the SPI peripheral and a data/command pin + pub struct SPIDeviceInterface { + spi: SPI, + dc: DC, + } + + impl SPIDeviceInterface + where + SPI: SpiDevice, + DC: OutputPin, + { + /// Create new SPI interface for communciation with a display driver + pub fn new(spi: SPI, dc: DC) -> Self { + Self { spi, dc } + } + } + + impl WriteOnlyDataCommand for SPIDeviceInterface + where + SPI: SpiDevice, + DC: OutputPin, + { + fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { + // 1 = data, 0 = command + self.dc.set_low().map_err(|_| DisplayError::DCError)?; + + send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; + Ok(()) + } + + fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { + // 1 = data, 0 = command + self.dc.set_high().map_err(|_| DisplayError::DCError)?; + + send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; + Ok(()) + } + } + + fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { + match words { + DataFormat::U8(slice) => spi.write(slice), + DataFormat::U16(slice) => { + use byte_slice_cast::*; + spi.write(slice.as_byte_slice()) + } + DataFormat::U16LE(slice) => { + use byte_slice_cast::*; + for v in slice.as_mut() { + *v = v.to_le(); + } + spi.write(slice.as_byte_slice()) + } + DataFormat::U16BE(slice) => { + use byte_slice_cast::*; + for v in slice.as_mut() { + *v = v.to_be(); + } + spi.write(slice.as_byte_slice()) + } + DataFormat::U8Iter(iter) => { + let mut buf = [0; 32]; + let mut i = 0; + + for v in iter.into_iter() { + buf[i] = v; + i += 1; + + if i == buf.len() { + spi.write(&buf)?; + i = 0; + } + } + + if i > 0 { + spi.write(&buf[..i])?; + } + + Ok(()) + } + DataFormat::U16LEIter(iter) => { + use byte_slice_cast::*; + let mut buf = [0; 32]; + let mut i = 0; + + for v in iter.map(u16::to_le) { + buf[i] = v; + i += 1; + + if i == buf.len() { + spi.write(&buf.as_byte_slice())?; + i = 0; + } + } + + if i > 0 { + spi.write(&buf[..i].as_byte_slice())?; + } + + Ok(()) + } + DataFormat::U16BEIter(iter) => { + use byte_slice_cast::*; + let mut buf = [0; 64]; + let mut i = 0; + let len = buf.len(); + + for v in iter.map(u16::to_be) { + buf[i] = v; + i += 1; + + if i == len { + spi.write(&buf.as_byte_slice())?; + i = 0; + } + } + + if i > 0 { + spi.write(&buf[..i].as_byte_slice())?; + } + + Ok(()) + } + _ => unimplemented!(), + } + } +} diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs new file mode 100644 index 000000000..992215b0d --- /dev/null +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -0,0 +1,99 @@ +//! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI. +//! +//! The example will attempt to read a file `MY_FILE.TXT` from the root directory +//! of the SD card and print its contents. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_embedded_hal::SetConfig; +use embassy_executor::Spawner; +use embassy_rp::spi::Spi; +use embassy_rp::{gpio, spi}; +use embedded_hal_bus::spi::ExclusiveDevice; +use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; +use gpio::{Level, Output}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +struct DummyTimesource(); + +impl embedded_sdmmc::TimeSource for DummyTimesource { + fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { + embedded_sdmmc::Timestamp { + year_since_1970: 0, + zero_indexed_month: 0, + zero_indexed_day: 0, + hours: 0, + minutes: 0, + seconds: 0, + } + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + embassy_rp::pac::SIO.spinlock(31).write_value(1); + let p = embassy_rp::init(Default::default()); + + // SPI clock needs to be running at <= 400kHz during initialization + let mut config = spi::Config::default(); + config.frequency = 400_000; + let spi = Spi::new_blocking(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, config); + // Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons + let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin); + // Real cs pin + let cs = Output::new(p.PIN_16, Level::High); + + let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay); + info!("Card size is {} bytes", sdcard.num_bytes().unwrap()); + + // Now that the card is initialized, the SPI clock can go faster + let mut config = spi::Config::default(); + config.frequency = 16_000_000; + sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); + + // Now let's look for volumes (also known as partitions) on our block device. + // To do this we need a Volume Manager. It will take ownership of the block device. + let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, DummyTimesource()); + + // Try and access Volume 0 (i.e. the first partition). + // The volume object holds information about the filesystem on that volume. + let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)).unwrap(); + info!("Volume 0: {:?}", defmt::Debug2Format(&volume0)); + + // Open the root directory (mutably borrows from the volume). + let mut root_dir = volume0.open_root_dir().unwrap(); + + // Open a file called "MY_FILE.TXT" in the root directory + // This mutably borrows the directory. + let mut my_file = root_dir + .open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly) + .unwrap(); + + // Print the contents of the file + while !my_file.is_eof() { + let mut buf = [0u8; 32]; + if let Ok(n) = my_file.read(&mut buf) { + info!("{:a}", buf[..n]); + } + } + + loop {} +} diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs new file mode 100644 index 000000000..7b82fa350 --- /dev/null +++ b/examples/rp23/src/bin/uart.rs @@ -0,0 +1,40 @@ +//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. +//! +//! No specific hardware is specified in this example. Only output on pin 0 is tested. +//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used +//! with its UART port. + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_rp::uart; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let config = uart::Config::default(); + let mut uart = uart::Uart::new_blocking(p.UART1, p.PIN_4, p.PIN_5, config); + uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap(); + + loop { + uart.blocking_write("hello there!\r\n".as_bytes()).unwrap(); + cortex_m::asm::delay(1_000_000); + } +} diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs new file mode 100644 index 000000000..f7acdade9 --- /dev/null +++ b/examples/rp23/src/bin/uart_buffered_split.rs @@ -0,0 +1,74 @@ +//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. +//! +//! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back. +//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used +//! with its UART port. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::UART0; +use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; +use embassy_time::Timer; +use embedded_io_async::{Read, Write}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + UART0_IRQ => BufferedInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0); + + static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); + let tx_buf = &mut TX_BUF.init([0; 16])[..]; + static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); + let rx_buf = &mut RX_BUF.init([0; 16])[..]; + let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); + let (mut tx, rx) = uart.split(); + + unwrap!(spawner.spawn(reader(rx))); + + info!("Writing..."); + loop { + let data = [ + 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, + ]; + info!("TX {:?}", data); + tx.write_all(&data).await.unwrap(); + Timer::after_secs(1).await; + } +} + +#[embassy_executor::task] +async fn reader(mut rx: BufferedUartRx<'static, UART0>) { + info!("Reading..."); + loop { + let mut buf = [0; 31]; + rx.read_exact(&mut buf).await.unwrap(); + info!("RX {:?}", buf); + } +} diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs new file mode 100644 index 000000000..69f6dbbff --- /dev/null +++ b/examples/rp23/src/bin/uart_r503.rs @@ -0,0 +1,174 @@ +#![no_std] +#![no_main] + +use defmt::{debug, error, info}; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::UART0; +use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; +use embassy_time::{with_timeout, Duration, Timer}; +use heapless::Vec; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(pub struct Irqs { + UART0_IRQ => UARTInterruptHandler; +}); + +const START: u16 = 0xEF01; +const ADDRESS: u32 = 0xFFFFFFFF; + +// ================================================================================ + +// Data package format +// Name Length Description +// ========================================================================================================== +// Start 2 bytes Fixed value of 0xEF01; High byte transferred first. +// Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command. +// High byte transferred first and at wrong adder value, module +// will reject to transfer. +// PID 1 byte 01H Command packet; +// 02H Data packet; Data packet shall not appear alone in executing +// processs, must follow command packet or acknowledge packet. +// 07H Acknowledge packet; +// 08H End of Data packet. +// LENGTH 2 bytes Refers to the length of package content (command packets and data packets) +// plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes. +// And high byte is transferred first. +// DATA - It can be commands, data, command’s parameters, acknowledge result, etc. +// (fingerprint character value, template are all deemed as data); +// SUM 2 bytes The arithmetic sum of package identifier, package length and all package +// contens. Overflowing bits are omitted. high byte is transferred first. + +// ================================================================================ + +// Checksum is calculated on 'length (2 bytes) + data (??)'. +fn compute_checksum(buf: Vec) -> u16 { + let mut checksum = 0u16; + + let check_end = buf.len(); + let checked_bytes = &buf[6..check_end]; + for byte in checked_bytes { + checksum += (*byte) as u16; + } + return checksum; +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Start"); + + let p = embassy_rp::init(Default::default()); + + // Initialize the fingerprint scanner. + let mut config = Config::default(); + config.baudrate = 57600; + config.stop_bits = StopBits::STOP1; + config.data_bits = DataBits::DataBits8; + config.parity = Parity::ParityNone; + + let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1); + let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config); + let (mut tx, mut rx) = uart.split(); + + let mut vec_buf: Vec = heapless::Vec::new(); + let mut data: Vec = heapless::Vec::new(); + + let mut speeds: Vec = heapless::Vec::new(); + let _ = speeds.push(0xC8); // Slow + let _ = speeds.push(0x20); // Medium + let _ = speeds.push(0x02); // Fast + + // Cycle through the three colours Red, Blue and Purple forever. + loop { + for colour in 1..=3 { + for speed in &speeds { + // Set the data first, because the length is dependent on that. + // However, we write the length bits before we do the data. + data.clear(); + let _ = data.push(0x01); // ctrl=Breathing light + let _ = data.push(*speed); + let _ = data.push(colour as u8); // colour=Red, Blue, Purple + let _ = data.push(0x00); // times=Infinite + + // Clear buffers + vec_buf.clear(); + + // START + let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]); + + // ADDRESS + let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]); + + // PID + let _ = vec_buf.extend_from_slice(&[0x01]); + + // LENGTH + let len: u16 = (1 + data.len() + 2).try_into().unwrap(); + let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]); + + // COMMAND + let _ = vec_buf.push(0x35); // Command: AuraLedConfig + + // DATA + let _ = vec_buf.extend_from_slice(&data); + + // SUM + let chk = compute_checksum(vec_buf.clone()); + let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]); + + // ===== + + // Send command buffer. + let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); + debug!(" write='{:?}'", data_write[..]); + match tx.write(&data_write).await { + Ok(..) => info!("Write successful."), + Err(e) => error!("Write error: {:?}", e), + } + + // ===== + + // Read command buffer. + let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! + let mut data_read: Vec = heapless::Vec::new(); // Save buffer. + + info!("Attempting read."); + loop { + // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms + // for this command. + match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await { + Ok(..) => { + // Extract and save read byte. + debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]); + let _ = data_read.push(read_buf[0]).unwrap(); + } + Err(..) => break, // TimeoutError -> Ignore. + } + } + info!("Read successful"); + debug!(" read='{:?}'", data_read[..]); + + Timer::after_secs(3).await; + info!("Changing speed."); + } + + info!("Changing colour."); + } + } +} diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs new file mode 100644 index 000000000..4d3163285 --- /dev/null +++ b/examples/rp23/src/bin/uart_unidir.rs @@ -0,0 +1,66 @@ +//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. +//! +//! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for +//! this to work +//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used +//! with its UART port. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::UART1; +use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + UART1_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default()); + let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default()); + + unwrap!(spawner.spawn(reader(uart_rx))); + + info!("Writing..."); + loop { + let data = [1u8, 2, 3, 4, 5, 6, 7, 8]; + info!("TX {:?}", data); + uart_tx.write(&data).await.unwrap(); + Timer::after_secs(1).await; + } +} + +#[embassy_executor::task] +async fn reader(mut rx: UartRx<'static, UART1, Async>) { + info!("Reading..."); + loop { + // read a total of 4 transmissions (32 / 8) and then print the result + let mut buf = [0; 32]; + rx.read(&mut buf).await.unwrap(); + info!("RX {:?}", buf); + } +} diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs new file mode 100644 index 000000000..c9cab45c1 --- /dev/null +++ b/examples/rp23/src/bin/usb_webusb.rs @@ -0,0 +1,171 @@ +//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. +//! +//! This creates a WebUSB capable device that echoes data back to the host. +//! +//! To test this in the browser (ideally host this on localhost:8080, to test the landing page +//! feature): +//! ```js +//! (async () => { +//! const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0xf569 }] }); +//! await device.open(); +//! await device.claimInterface(1); +//! device.transferIn(1, 64).then(data => console.log(data)); +//! await device.transferOut(1, new Uint8Array([1,2,3])); +//! })(); +//! ``` + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::USB; +use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; +use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; +use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; +use embassy_usb::msos::{self, windows_version}; +use embassy_usb::{Builder, Config}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +// This is a randomly generated GUID to allow clients on Windows to find our device +const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + // Create the driver, from the HAL. + let driver = UsbDriver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xf569, 0x0001); + config.manufacturer = Some("Embassy"); + config.product = Some("WebUSB example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xff; + config.device_sub_class = 0x00; + config.device_protocol = 0x00; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + let mut msos_descriptor = [0; 256]; + + let webusb_config = WebUsbConfig { + max_packet_size: 64, + vendor_code: 1, + // If defined, shows a landing page which the device manufacturer would like the user to visit in order to control their device. Suggest the user to navigate to this URL when the device is connected. + landing_url: Some(Url::new("http://localhost:8080")), + }; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut msos_descriptor, + &mut control_buf, + ); + + // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor. + // We tell Windows that this entire device is compatible with the "WINUSB" feature, + // which causes it to use the built-in WinUSB driver automatically, which in turn + // can be used by libusb/rusb software without needing a custom driver or INF file. + // In principle you might want to call msos_feature() just on a specific function, + // if your device also has other functions that still use standard class drivers. + builder.msos_descriptor(windows_version::WIN8_1, 0); + builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), + )); + + // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything) + WebUsb::configure(&mut builder, &mut state, &webusb_config); + // Create some USB bulk endpoints for testing. + let mut endpoints = WebEndpoints::new(&mut builder, &webusb_config); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do some WebUSB transfers. + let webusb_fut = async { + loop { + endpoints.wait_connected().await; + info!("Connected"); + endpoints.echo().await; + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, webusb_fut).await; +} + +struct WebEndpoints<'d, D: Driver<'d>> { + write_ep: D::EndpointIn, + read_ep: D::EndpointOut, +} + +impl<'d, D: Driver<'d>> WebEndpoints<'d, D> { + fn new(builder: &mut Builder<'d, D>, config: &'d WebUsbConfig<'d>) -> Self { + let mut func = builder.function(0xff, 0x00, 0x00); + let mut iface = func.interface(); + let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None); + + let write_ep = alt.endpoint_bulk_in(config.max_packet_size); + let read_ep = alt.endpoint_bulk_out(config.max_packet_size); + + WebEndpoints { write_ep, read_ep } + } + + // Wait until the device's endpoints are enabled. + async fn wait_connected(&mut self) { + self.read_ep.wait_enabled().await + } + + // Echo data back to the host. + async fn echo(&mut self) { + let mut buf = [0; 64]; + loop { + let n = self.read_ep.read(&mut buf).await.unwrap(); + let data = &buf[..n]; + info!("Data read: {:x}", data); + self.write_ep.write(data).await.unwrap(); + } + } +} diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs new file mode 100644 index 000000000..8cc723150 --- /dev/null +++ b/examples/rp23/src/bin/watchdog.rs @@ -0,0 +1,67 @@ +//! This example shows how to use Watchdog in the RP2040 chip. +//! +//! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor. + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_rp::watchdog::*; +use embassy_time::{Duration, Timer}; +use gpio::{Level, Output}; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello world!"); + + let mut watchdog = Watchdog::new(p.WATCHDOG); + let mut led = Output::new(p.PIN_25, Level::Low); + + // Set the LED high for 2 seconds so we know when we're about to start the watchdog + led.set_high(); + Timer::after_secs(2).await; + + // Set to watchdog to reset if it's not fed within 1.05 seconds, and start it + watchdog.start(Duration::from_millis(1_050)); + info!("Started the watchdog timer"); + + // Blink once a second for 5 seconds, feed the watchdog timer once a second to avoid a reset + for _ in 1..=5 { + led.set_low(); + Timer::after_millis(500).await; + led.set_high(); + Timer::after_millis(500).await; + info!("Feeding watchdog"); + watchdog.feed(); + } + + info!("Stopped feeding, device will reset in 1.05 seconds"); + // Blink 10 times per second, not feeding the watchdog. + // The processor should reset in 1.05 seconds. + loop { + led.set_low(); + Timer::after_millis(100).await; + led.set_high(); + Timer::after_millis(100).await; + } +} diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs new file mode 100644 index 000000000..e379d9c00 --- /dev/null +++ b/examples/rp23/src/bin/zerocopy.rs @@ -0,0 +1,110 @@ +//! This example shows how to use `zerocopy_channel` from `embassy_sync` for +//! sending large values between two tasks without copying. +//! The example also shows how to use the RP2040 ADC with DMA. +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicU16, Ordering}; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::Pull; +use embassy_rp::peripherals::DMA_CH0; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; +use embassy_time::{Duration, Ticker, Timer}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; +use embassy_rp::block::ImageDef; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info_rp_cargo_bin_name!(), + embassy_rp::binary_info_rp_cargo_version!(), + embassy_rp::binary_info_rp_program_description!(c"Blinky"), + embassy_rp::binary_info_rp_program_build_attribute!(), +]; + + +type SampleBuffer = [u16; 512]; + +bind_interrupts!(struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; +}); + +const BLOCK_SIZE: usize = 512; +const NUM_BLOCKS: usize = 2; +static MAX: AtomicU16 = AtomicU16::new(0); + +struct AdcParts { + adc: Adc<'static, Async>, + pin: adc::Channel<'static>, + dma: DMA_CH0, +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Here we go!"); + + let adc_parts = AdcParts { + adc: Adc::new(p.ADC, Irqs, Config::default()), + pin: adc::Channel::new_pin(p.PIN_29, Pull::None), + dma: p.DMA_CH0, + }; + + static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new(); + let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]); + + static CHANNEL: StaticCell> = StaticCell::new(); + let channel = CHANNEL.init(Channel::new(buf)); + let (sender, receiver) = channel.split(); + + spawner.must_spawn(consumer(receiver)); + spawner.must_spawn(producer(sender, adc_parts)); + + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + ticker.next().await; + let max = MAX.load(Ordering::Relaxed); + info!("latest block's max value: {:?}", max); + } +} + +#[embassy_executor::task] +async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) { + loop { + // Obtain a free buffer from the channel + let buf = sender.send().await; + + // Fill it with data + adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); + + // Notify the channel that the buffer is now ready to be received + sender.send_done(); + } +} + +#[embassy_executor::task] +async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) { + loop { + // Receive a buffer from the channel + let buf = receiver.receive().await; + + // Simulate using the data, while the producer is filling up the next buffer + Timer::after_micros(1000).await; + let max = buf.iter().max().unwrap(); + MAX.store(*max, Ordering::Relaxed); + + // Notify the channel that the buffer is now ready to be reused + receiver.receive_done(); + } +} diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index def270558..12f1ec3ce 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -10,7 +10,7 @@ teleprobe-meta = "1.1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } -embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } +embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } From 6f03c40516b49104b33a51f6e189a7fc812c1068 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 8 Aug 2024 21:54:21 -0400 Subject: [PATCH 076/210] cargo fmt --- embassy-rp/src/binary_info/macros.rs | 9 +++------ embassy-rp/src/lib.rs | 5 ++--- embassy-rp/src/time_driver.rs | 7 +++---- examples/rp23/src/bin/adc.rs | 3 +-- examples/rp23/src/bin/adc_dma.rs | 3 +-- examples/rp23/src/bin/assign_resources.rs | 3 +-- examples/rp23/src/bin/blinky.rs | 2 +- examples/rp23/src/bin/blinky_two_channels.rs | 3 +-- examples/rp23/src/bin/blinky_two_tasks.rs | 3 +-- examples/rp23/src/bin/button.rs | 3 +-- examples/rp23/src/bin/debounce.rs | 3 +-- examples/rp23/src/bin/flash.rs | 3 +-- examples/rp23/src/bin/gpio_async.rs | 3 +-- examples/rp23/src/bin/gpout.rs | 3 +-- examples/rp23/src/bin/i2c_async.rs | 3 +-- examples/rp23/src/bin/i2c_async_embassy.rs | 3 +-- examples/rp23/src/bin/i2c_blocking.rs | 3 +-- examples/rp23/src/bin/i2c_slave.rs | 2 +- examples/rp23/src/bin/interrupt.rs | 3 +-- examples/rp23/src/bin/multicore.rs | 3 +-- examples/rp23/src/bin/multiprio.rs | 3 +-- examples/rp23/src/bin/pio_async.rs | 3 +-- examples/rp23/src/bin/pio_dma.rs | 3 +-- examples/rp23/src/bin/pio_hd44780.rs | 3 +-- examples/rp23/src/bin/pio_i2s.rs | 3 +-- examples/rp23/src/bin/pio_pwm.rs | 3 +-- examples/rp23/src/bin/pio_rotary_encoder.rs | 3 +-- examples/rp23/src/bin/pio_servo.rs | 3 +-- examples/rp23/src/bin/pio_stepper.rs | 3 +-- examples/rp23/src/bin/pio_ws2812.rs | 3 +-- examples/rp23/src/bin/pwm.rs | 3 +-- examples/rp23/src/bin/pwm_input.rs | 3 +-- examples/rp23/src/bin/rosc.rs | 3 +-- examples/rp23/src/bin/shared_bus.rs | 3 +-- examples/rp23/src/bin/sharing.rs | 5 ++--- examples/rp23/src/bin/spi.rs | 3 +-- examples/rp23/src/bin/spi_async.rs | 3 +-- examples/rp23/src/bin/spi_display.rs | 3 +-- examples/rp23/src/bin/spi_sdmmc.rs | 3 +-- examples/rp23/src/bin/uart.rs | 2 +- examples/rp23/src/bin/uart_buffered_split.rs | 3 +-- examples/rp23/src/bin/uart_r503.rs | 3 +-- examples/rp23/src/bin/uart_unidir.rs | 3 +-- examples/rp23/src/bin/usb_webusb.rs | 3 +-- examples/rp23/src/bin/watchdog.rs | 3 +-- examples/rp23/src/bin/zerocopy.rs | 3 +-- 46 files changed, 52 insertions(+), 97 deletions(-) diff --git a/embassy-rp/src/binary_info/macros.rs b/embassy-rp/src/binary_info/macros.rs index ef98c8399..0d6ba5eb5 100644 --- a/embassy-rp/src/binary_info/macros.rs +++ b/embassy-rp/src/binary_info/macros.rs @@ -10,8 +10,7 @@ macro_rules! binary_info_env { // # Safety // // We used `concat!` to null-terminate on the line above. - let value_cstr = - unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(value.as_bytes()) }; + let value_cstr = unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(value.as_bytes()) }; value_cstr }) }; @@ -25,8 +24,7 @@ macro_rules! binary_info_env { #[macro_export] macro_rules! binary_info_str { ($tag:expr, $id:expr, $str:expr) => {{ - static ENTRY: $crate::binary_info::StringEntry = - $crate::binary_info::StringEntry::new($tag, $id, $str); + static ENTRY: $crate::binary_info::StringEntry = $crate::binary_info::StringEntry::new($tag, $id, $str); ENTRY.addr() }}; } @@ -39,8 +37,7 @@ macro_rules! binary_info_str { #[macro_export] macro_rules! binary_info_int { ($tag:expr, $id:expr, $int:expr) => {{ - static ENTRY: $crate::binary_info::IntegerEntry = - $crate::binary_info::IntegerEntry::new($tag, $id, $int); + static ENTRY: $crate::binary_info::IntegerEntry = $crate::binary_info::IntegerEntry::new($tag, $id, $int); ENTRY.addr() }}; } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index c5b2498b4..ff9c0803d 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -48,11 +48,10 @@ pub(crate) mod relocate; pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; #[cfg(all(feature = "unstable-pac", feature = "rp235x"))] pub use rp23_pac as pac; -#[cfg(all(feature = "unstable-pac", feature = "rp2040"))] -pub use rp_pac as pac; - #[cfg(all(not(feature = "unstable-pac"), feature = "rp235x"))] pub(crate) use rp23_pac as pac; +#[cfg(all(feature = "unstable-pac", feature = "rp2040"))] +pub use rp_pac as pac; #[cfg(all(not(feature = "unstable-pac"), feature = "rp2040"))] pub(crate) use rp_pac as pac; diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index 6f532fa8e..ba5a91c29 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -6,15 +6,14 @@ use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::{AlarmHandle, Driver}; - -use crate::interrupt::InterruptExt; -use crate::{interrupt, pac}; - #[cfg(feature = "rp2040")] use pac::TIMER; #[cfg(feature = "rp235x")] use pac::TIMER0 as TIMER; +use crate::interrupt::InterruptExt; +use crate::{interrupt, pac}; + struct AlarmState { timestamp: Cell, callback: Cell>, diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs index a1a94ca47..19872607e 100644 --- a/examples/rp23/src/bin/adc.rs +++ b/examples/rp23/src/bin/adc.rs @@ -8,10 +8,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -27,7 +27,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs index 887c8500a..d538ddaa2 100644 --- a/examples/rp23/src/bin/adc_dma.rs +++ b/examples/rp23/src/bin/adc_dma.rs @@ -8,10 +8,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_time::{Duration, Ticker}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -27,7 +27,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs index 8aea2f35d..923c13514 100644 --- a/examples/rp23/src/bin/assign_resources.rs +++ b/examples/rp23/src/bin/assign_resources.rs @@ -14,11 +14,11 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -34,7 +34,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(spawner: Spawner) { // initialize the peripherals diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs index 1e3a52085..02bdf9b3d 100644 --- a/examples/rp23/src/bin/blinky.rs +++ b/examples/rp23/src/bin/blinky.rs @@ -7,11 +7,11 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_time::Timer; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs index aae0283cf..4d7dc89fa 100644 --- a/examples/rp23/src/bin/blinky_two_channels.rs +++ b/examples/rp23/src/bin/blinky_two_channels.rs @@ -7,13 +7,13 @@ /// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::{Channel, Sender}; use embassy_time::{Duration, Ticker}; use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -29,7 +29,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - enum LedState { Toggle, } diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs index aeabb238f..24b960242 100644 --- a/examples/rp23/src/bin/blinky_two_tasks.rs +++ b/examples/rp23/src/bin/blinky_two_tasks.rs @@ -7,13 +7,13 @@ /// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Ticker}; use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -29,7 +29,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - type LedType = Mutex>>; static LED: LedType = Mutex::new(None); diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs index 2a78a19db..0a0559397 100644 --- a/examples/rp23/src/bin/button.rs +++ b/examples/rp23/src/bin/button.rs @@ -6,9 +6,9 @@ #![no_main] use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -24,7 +24,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs index 0e3b5cb54..e82e71f61 100644 --- a/examples/rp23/src/bin/debounce.rs +++ b/examples/rp23/src/bin/debounce.rs @@ -6,10 +6,10 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Input, Level, Pull}; use embassy_time::{with_deadline, Duration, Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -25,7 +25,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - pub struct Debouncer<'a> { input: Input<'a>, debounce: Duration, diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 42620ca93..2917dda0b 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -5,11 +5,11 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE}; use embassy_rp::peripherals::FLASH; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -25,7 +25,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - const ADDR_OFFSET: u32 = 0x100000; const FLASH_SIZE: usize = 2 * 1024 * 1024; diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs index 360932d62..1618f7c8b 100644 --- a/examples/rp23/src/bin/gpio_async.rs +++ b/examples/rp23/src/bin/gpio_async.rs @@ -7,11 +7,11 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_time::Timer; use gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -27,7 +27,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - /// It requires an external signal to be manually triggered on PIN 16. For /// example, this could be accomplished using an external power source with a /// button so that it is possible to toggle the signal from low to high. diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs index 8d1e4d05f..b15963f02 100644 --- a/examples/rp23/src/bin/gpout.rs +++ b/examples/rp23/src/bin/gpout.rs @@ -7,10 +7,10 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::clocks; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -26,7 +26,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs index 64f103849..2528fe1d2 100644 --- a/examples/rp23/src/bin/i2c_async.rs +++ b/examples/rp23/src/bin/i2c_async.rs @@ -9,12 +9,12 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::i2c::{self, Config, InterruptHandler}; use embassy_rp::peripherals::I2C1; use embassy_time::Timer; use embedded_hal_async::i2c::I2c; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -30,7 +30,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { I2C1_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs index 4b14ec6f6..461b1d171 100644 --- a/examples/rp23/src/bin/i2c_async_embassy.rs +++ b/examples/rp23/src/bin/i2c_async_embassy.rs @@ -7,9 +7,9 @@ #![no_main] use defmt::*; +use embassy_rp::block::ImageDef; use embassy_rp::i2c::InterruptHandler; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -25,7 +25,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - // Our anonymous hypotetical temperature sensor could be: // a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C // It requires no configuration or calibration, works with all i2c bus speeds, diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs index d2cccf09b..6d36d1890 100644 --- a/examples/rp23/src/bin/i2c_blocking.rs +++ b/examples/rp23/src/bin/i2c_blocking.rs @@ -8,11 +8,11 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::i2c::{self, Config}; use embassy_time::Timer; use embedded_hal_1::i2c::I2c; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -28,7 +28,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[allow(dead_code)] mod mcp23017 { pub const ADDR: u8 = 0x20; // default addr diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs index 4bf407bcc..1f3408cf3 100644 --- a/examples/rp23/src/bin/i2c_slave.rs +++ b/examples/rp23/src/bin/i2c_slave.rs @@ -4,12 +4,12 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::{I2C0, I2C1}; use embassy_rp::{bind_interrupts, i2c, i2c_slave}; use embassy_time::Timer; use embedded_hal_async::i2c::I2c; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::{block::ImageDef}; #[link_section = ".start_block"] #[used] diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs index f46117f95..6184b1bd7 100644 --- a/examples/rp23/src/bin/interrupt.rs +++ b/examples/rp23/src/bin/interrupt.rs @@ -13,6 +13,7 @@ use core::cell::{Cell, RefCell}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Blocking}; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::interrupt; use embassy_rp::pwm::{Config, Pwm}; @@ -23,7 +24,6 @@ use embassy_time::{Duration, Ticker}; use portable_atomic::{AtomicU32, Ordering}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -39,7 +39,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - static COUNTER: AtomicU32 = AtomicU32::new(0); static PWM: Mutex>> = Mutex::new(RefCell::new(None)); static ADC: Mutex, adc::Channel)>>> = diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs index 0b20ecaae..8649143e1 100644 --- a/examples/rp23/src/bin/multicore.rs +++ b/examples/rp23/src/bin/multicore.rs @@ -7,6 +7,7 @@ use defmt::*; use embassy_executor::Executor; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Level, Output}; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; @@ -14,7 +15,6 @@ use embassy_sync::channel::Channel; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -30,7 +30,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - static mut CORE1_STACK: Stack<4096> = Stack::new(); static EXECUTOR0: StaticCell = StaticCell::new(); static EXECUTOR1: StaticCell = StaticCell::new(); diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs index 52c801973..7590fb431 100644 --- a/examples/rp23/src/bin/multiprio.rs +++ b/examples/rp23/src/bin/multiprio.rs @@ -59,12 +59,12 @@ use cortex_m_rt::entry; use defmt::{info, unwrap}; use embassy_executor::{Executor, InterruptExecutor}; +use embassy_rp::block::ImageDef; use embassy_rp::interrupt; use embassy_rp::interrupt::{InterruptExt, Priority}; use embassy_time::{Instant, Timer, TICK_HZ}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -80,7 +80,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::task] async fn run_high() { loop { diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs index f3a48bbce..005708bc2 100644 --- a/examples/rp23/src/bin/pio_async.rs +++ b/examples/rp23/src/bin/pio_async.rs @@ -5,12 +5,12 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -26,7 +26,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs index d5a831d09..48fd9123f 100644 --- a/examples/rp23/src/bin/pio_dma.rs +++ b/examples/rp23/src/bin/pio_dma.rs @@ -5,13 +5,13 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -27,7 +27,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs index f601bbc66..fc658267d 100644 --- a/examples/rp23/src/bin/pio_hd44780.rs +++ b/examples/rp23/src/bin/pio_hd44780.rs @@ -7,6 +7,7 @@ use core::fmt::Write; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{ @@ -16,7 +17,6 @@ use embassy_rp::pwm::{self, Pwm}; use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -32,7 +32,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(pub struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs index b12b050e6..5a3bde759 100644 --- a/examples/rp23/src/bin/pio_i2s.rs +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -13,13 +13,13 @@ use core::mem; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -35,7 +35,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs index c8e834eae..7c5eefc45 100644 --- a/examples/rp23/src/bin/pio_pwm.rs +++ b/examples/rp23/src/bin/pio_pwm.rs @@ -5,6 +5,7 @@ use core::time::Duration; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Level; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; @@ -12,7 +13,6 @@ use embassy_rp::{bind_interrupts, clocks}; use embassy_time::Timer; use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -28,7 +28,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - const REFRESH_INTERVAL: u64 = 20000; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs index 971b55c9e..287992a83 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -5,13 +5,13 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; use embassy_rp::{bind_interrupts, pio}; use fixed::traits::ToFixed; use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -27,7 +27,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs index 67e52019a..1dec86927 100644 --- a/examples/rp23/src/bin/pio_servo.rs +++ b/examples/rp23/src/bin/pio_servo.rs @@ -5,6 +5,7 @@ use core::time::Duration; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Level; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; @@ -12,7 +13,6 @@ use embassy_rp::{bind_interrupts, clocks}; use embassy_time::Timer; use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -28,7 +28,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs index 9cbf0bd92..8b52dc37a 100644 --- a/examples/rp23/src/bin/pio_stepper.rs +++ b/examples/rp23/src/bin/pio_stepper.rs @@ -8,6 +8,7 @@ use core::mem::{self, MaybeUninit}; use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; use embassy_time::{with_timeout, Duration, Timer}; @@ -15,7 +16,6 @@ use fixed::traits::ToFixed; use fixed::types::extra::U8; use fixed::FixedU32; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -31,7 +31,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs index 2e62a3d97..99d9cf7e6 100644 --- a/examples/rp23/src/bin/pio_ws2812.rs +++ b/examples/rp23/src/bin/pio_ws2812.rs @@ -6,6 +6,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{ @@ -17,7 +18,6 @@ use fixed::types::U24F8; use fixed_macro::fixed; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -33,7 +33,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index ab38a03bb..4cd3b3eb4 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -7,10 +7,10 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::pwm::{Config, Pwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -26,7 +26,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs index fcb561cfd..b75d04963 100644 --- a/examples/rp23/src/bin/pwm_input.rs +++ b/examples/rp23/src/bin/pwm_input.rs @@ -5,11 +5,11 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::pwm::{Config, InputMode, Pwm}; use embassy_time::{Duration, Ticker}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -25,7 +25,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs index 051b4710f..28c778f51 100644 --- a/examples/rp23/src/bin/rosc.rs +++ b/examples/rp23/src/bin/rosc.rs @@ -7,11 +7,11 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::{clocks, gpio}; use embassy_time::Timer; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -27,7 +27,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_rp::config::Config::default(); diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs index e3213cd91..00e65f80d 100644 --- a/examples/rp23/src/bin/shared_bus.rs +++ b/examples/rp23/src/bin/shared_bus.rs @@ -8,6 +8,7 @@ use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::{AnyPin, Level, Output}; use embassy_rp::i2c::{self, I2c, InterruptHandler}; use embassy_rp::peripherals::{I2C1, SPI1}; @@ -17,7 +18,6 @@ use embassy_sync::mutex::Mutex; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -33,7 +33,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - type Spi1Bus = Mutex>; type I2c1Bus = Mutex>; diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs index 10f064947..b5ef08147 100644 --- a/examples/rp23/src/bin/sharing.rs +++ b/examples/rp23/src/bin/sharing.rs @@ -19,8 +19,9 @@ use core::sync::atomic::{AtomicU32, Ordering}; use cortex_m_rt::entry; use defmt::info; use embassy_executor::{Executor, InterruptExecutor}; +use embassy_rp::block::ImageDef; use embassy_rp::clocks::RoscRng; -use embassy_rp::interrupt::{Priority, InterruptExt}; +use embassy_rp::interrupt::{InterruptExt, Priority}; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{self, InterruptHandler, UartTx}; use embassy_rp::{bind_interrupts, interrupt}; @@ -30,7 +31,6 @@ use embassy_time::{Duration, Ticker}; use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -46,7 +46,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - type UartAsyncMutex = mutex::Mutex>; struct MyType { diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs index bcf356188..98aa7622c 100644 --- a/examples/rp23/src/bin/spi.rs +++ b/examples/rp23/src/bin/spi.rs @@ -7,11 +7,11 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::spi::Spi; use embassy_rp::{gpio, spi}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -27,7 +27,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs index 7a43995d2..71eaa5c05 100644 --- a/examples/rp23/src/bin/spi_async.rs +++ b/examples/rp23/src/bin/spi_async.rs @@ -6,10 +6,10 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::spi::{Config, Spi}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -25,7 +25,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs index 25368bb94..2441b1186 100644 --- a/examples/rp23/src/bin/spi_display.rs +++ b/examples/rp23/src/bin/spi_display.rs @@ -11,6 +11,7 @@ use core::cell::RefCell; use defmt::*; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::{Blocking, Spi}; @@ -26,7 +27,6 @@ use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; use st7789::{Orientation, ST7789}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -42,7 +42,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - use crate::my_display_interface::SPIDeviceInterface; use crate::touch::Touch; diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs index 992215b0d..d7af77a30 100644 --- a/examples/rp23/src/bin/spi_sdmmc.rs +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -9,13 +9,13 @@ use defmt::*; use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::spi::Spi; use embassy_rp::{gpio, spi}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -31,7 +31,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - struct DummyTimesource(); impl embedded_sdmmc::TimeSource for DummyTimesource { diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs index 7b82fa350..ae00f36dc 100644 --- a/examples/rp23/src/bin/uart.rs +++ b/examples/rp23/src/bin/uart.rs @@ -8,9 +8,9 @@ #![no_main] use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::uart; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs index f7acdade9..2b14520d5 100644 --- a/examples/rp23/src/bin/uart_buffered_split.rs +++ b/examples/rp23/src/bin/uart_buffered_split.rs @@ -10,13 +10,13 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; use embassy_time::Timer; use embedded_io_async::{Read, Write}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -32,7 +32,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { UART0_IRQ => BufferedInterruptHandler; }); diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs index 69f6dbbff..39a17d305 100644 --- a/examples/rp23/src/bin/uart_r503.rs +++ b/examples/rp23/src/bin/uart_r503.rs @@ -4,12 +4,12 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; use embassy_time::{with_timeout, Duration, Timer}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -25,7 +25,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(pub struct Irqs { UART0_IRQ => UARTInterruptHandler; }); diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs index 4d3163285..38210a8d0 100644 --- a/examples/rp23/src/bin/uart_unidir.rs +++ b/examples/rp23/src/bin/uart_unidir.rs @@ -11,11 +11,11 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::UART1; use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -31,7 +31,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { UART1_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs index c9cab45c1..f4ecde30e 100644 --- a/examples/rp23/src/bin/usb_webusb.rs +++ b/examples/rp23/src/bin/usb_webusb.rs @@ -21,6 +21,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; @@ -28,7 +29,6 @@ use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; use embassy_usb::msos::{self, windows_version}; use embassy_usb::{Builder, Config}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -44,7 +44,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs index 8cc723150..3ac457219 100644 --- a/examples/rp23/src/bin/watchdog.rs +++ b/examples/rp23/src/bin/watchdog.rs @@ -7,12 +7,12 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_rp::watchdog::*; use embassy_time::{Duration, Timer}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -28,7 +28,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs index e379d9c00..d04e1bf2a 100644 --- a/examples/rp23/src/bin/zerocopy.rs +++ b/examples/rp23/src/bin/zerocopy.rs @@ -10,6 +10,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; use embassy_sync::blocking_mutex::raw::NoopRawMutex; @@ -17,7 +18,6 @@ use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::block::ImageDef; #[link_section = ".start_block"] #[used] @@ -33,7 +33,6 @@ pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info_rp_program_build_attribute!(), ]; - type SampleBuffer = [u16; 512]; bind_interrupts!(struct Irqs { From 6a797deb7200447c20bdd4bddcf79f32affe210b Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 8 Aug 2024 22:07:43 -0400 Subject: [PATCH 077/210] Fixup pac dep sources --- embassy-rp/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 4e36c885b..80f7eca66 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -126,8 +126,8 @@ embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { path = "/home/cbjamo/235x/rp-pac", feature = ["rt"], optional = true } -rp23-pac = { path = "/home/cbjamo/235x/rp23-pac/", feature = ["rt"], optional = true } +rp-pac = { git = "https://github.com/CBJamo/rp-pac.git", feature = ["rt"], optional = true } +rp23-pac = { git = "https://github.com/HellbenderInc/rp23-pac.git", feature = ["rt"], optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } From 0eb07896275f26f1206ed968436d1f0e78a163b8 Mon Sep 17 00:00:00 2001 From: Frank Plowman Date: Fri, 9 Aug 2024 14:15:23 +0100 Subject: [PATCH 078/210] nrf, doc: Don't refer to `Default` impl of `saadc::ChannelConfig` `saadc::ChannelConfig` does not implement the `Default` trait, so its documentation should not refer to it. Modify the documentation to instead describe how the struct should be created and configured. --- embassy-nrf/src/saadc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index a3a5b9cfe..bbfa9b3b9 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -78,7 +78,8 @@ impl Default for Config { /// Used to configure an individual SAADC peripheral channel. /// -/// See the `Default` impl for suitable default values. +/// Construct using the `single_ended` or `differential` methods. These provide sensible defaults +/// for the public fields, which can be overridden if required. #[non_exhaustive] pub struct ChannelConfig<'d> { /// Reference voltage of the SAADC input. From e5d8d8b18e80244275458c38b3dc13a5b9d72a9f Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Fri, 9 Aug 2024 12:31:29 -0400 Subject: [PATCH 079/210] Switch to single pac --- embassy-rp/Cargo.toml | 13 +++++-------- embassy-rp/src/lib.rs | 9 +++------ examples/rp23/Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 80f7eca66..6a504335d 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -24,9 +24,7 @@ features = ["defmt", "unstable-pac", "time-driver"] [features] default = [ "rt" ] ## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. -rt = [] -rt-2040 = [ "rt", "rp-pac/rt" ] -rt-235x = [ "rt", "rp23-pac/rt" ] +rt = [ "rp-pac/rt" ] ## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] @@ -91,8 +89,8 @@ boot2-w25x10cl = [] ## ``` boot2-none = [] -rp2040 = ["dep:rp-pac"] -rp235x = ["dep:rp23-pac"] +rp2040 = ["rp-pac/rp2040"] +rp235x = ["rp-pac/rp235x"] rp235xa = ["rp235x"] rp235xb = ["rp235x"] @@ -100,7 +98,7 @@ rp235xb = ["rp235x"] # # Takes up a little flash space, but picotool can then report the name of your # program and other details. -binary-info = [ "rt-235x" ] +binary-info = [ "rt" ] [dependencies] embassy-sync = { version = "0.6.0", path = "../embassy-sync" } @@ -126,8 +124,7 @@ embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { git = "https://github.com/CBJamo/rp-pac.git", feature = ["rt"], optional = true } -rp23-pac = { git = "https://github.com/HellbenderInc/rp23-pac.git", feature = ["rt"], optional = true } +rp-pac = { git = "https://github.com/CBJamo/rp-pac.git", feature = ["rt"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index ff9c0803d..a0c6538d2 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -46,13 +46,10 @@ pub(crate) mod relocate; // Reexports pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -#[cfg(all(feature = "unstable-pac", feature = "rp235x"))] -pub use rp23_pac as pac; -#[cfg(all(not(feature = "unstable-pac"), feature = "rp235x"))] -pub(crate) use rp23_pac as pac; -#[cfg(all(feature = "unstable-pac", feature = "rp2040"))] + +#[cfg(feature = "unstable-pac")] pub use rp_pac as pac; -#[cfg(all(not(feature = "unstable-pac"), feature = "rp2040"))] +#[cfg(not(feature = "unstable-pac"))] pub(crate) use rp_pac as pac; #[cfg(feature = "rt")] diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 89947ae46..8f8d6ff10 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -10,7 +10,7 @@ embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info", "rt-235x", "boot2-none"] } +embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } From 101977f23f47e549473067773600f79d3c920b23 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Fri, 9 Aug 2024 12:39:21 -0400 Subject: [PATCH 080/210] Maybe fix ci/build? --- ci.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ci.sh b/ci.sh index 0cd0c54bc..81b093a0e 100755 --- a/ci.sh +++ b/ci.sh @@ -82,10 +82,14 @@ cargo batch \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt,rp2040 \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log,rp2040 \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics,rp2040 \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,defmt,rp235x \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,log,rp235x \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,intrinsics,rp235x \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,qspi-as-gpio,rp235x \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ From 67c2ee22be48f9adfc8ac0f636e31afa4ae3f799 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Fri, 9 Aug 2024 15:52:16 -0400 Subject: [PATCH 081/210] Maybe fix ci/build II --- ci.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ci.sh b/ci.sh index 81b093a0e..81fbc8072 100755 --- a/ci.sh +++ b/ci.sh @@ -86,10 +86,9 @@ cargo batch \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log,rp2040 \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics,rp2040 \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,defmt,rp235x \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,log,rp235x \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,intrinsics,rp235x \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabi --features time-driver,qspi-as-gpio,rp235x \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235x \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235x \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,intrinsics,rp235x \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ From 05cb1baf375caff29f263f97dc3ade36562d4e1e Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Fri, 9 Aug 2024 15:54:30 -0400 Subject: [PATCH 082/210] Fix ci/rustfmt --- embassy-rp/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index a0c6538d2..006588c54 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -46,7 +46,6 @@ pub(crate) mod relocate; // Reexports pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; - #[cfg(feature = "unstable-pac")] pub use rp_pac as pac; #[cfg(not(feature = "unstable-pac"))] From ffdc60d6fb3fa8883b22a2b201a6cdf55b0d163f Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Fri, 9 Aug 2024 16:07:30 -0400 Subject: [PATCH 083/210] Move #![cfg]s to lib.rs --- embassy-rp/src/float/mod.rs | 1 - embassy-rp/src/lib.rs | 2 ++ embassy-rp/src/rtc/mod.rs | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/float/mod.rs b/embassy-rp/src/float/mod.rs index 1df8c0e08..3ad6f1c50 100644 --- a/embassy-rp/src/float/mod.rs +++ b/embassy-rp/src/float/mod.rs @@ -1,4 +1,3 @@ -#![cfg(feature = "rp2040")] // Credit: taken from `rp-hal` (also licensed Apache+MIT) // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/float/mod.rs diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 006588c54..0bcc58b86 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -24,6 +24,7 @@ pub mod bootsel; pub mod clocks; pub mod dma; pub mod flash; +#[cfg(feature = "rp2040")] mod float; pub mod gpio; pub mod i2c; @@ -32,6 +33,7 @@ pub mod multicore; pub mod pwm; mod reset; pub mod rom_data; +#[cfg(feature = "rp2040")] pub mod rtc; pub mod spi; #[cfg(feature = "time-driver")] diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 4ba5bad4b..2ce7ac645 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -1,4 +1,3 @@ -#![cfg(feature = "rp2040")] //! RTC driver. mod filter; From 168a9f9d8ab451ca724e68de777e4e1601f865dd Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Fri, 9 Aug 2024 16:25:05 -0400 Subject: [PATCH 084/210] Intrinsics aren't implemented for 235x yet. --- ci.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index 81fbc8072..7538af22c 100755 --- a/ci.sh +++ b/ci.sh @@ -86,9 +86,8 @@ cargo batch \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log,rp2040 \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics,rp2040 \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235x \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235x \ - --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,intrinsics,rp235x \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ From 9a863f07fe97f59c3e6a1d5aa125ed3b4094156f Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sat, 10 Aug 2024 17:36:28 -0400 Subject: [PATCH 085/210] Handle pad isolation everywhere and in the same way. --- embassy-rp/src/adc.rs | 2 ++ embassy-rp/src/gpio.rs | 7 ++----- embassy-rp/src/i2c.rs | 2 ++ embassy-rp/src/pwm.rs | 2 ++ embassy-rp/src/uart/mod.rs | 24 ++++++++++++++++++++---- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 12d08d06b..9768f480d 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -35,6 +35,8 @@ impl<'p> Channel<'p> { pub fn new_pin(pin: impl Peripheral

+ 'p, pull: Pull) -> Self { into_ref!(pin); pin.pad_ctrl().modify(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); // manual says: // // > When using an ADC input shared with a GPIO pin, the pin’s diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 8d6a8f2bd..24208b82e 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -581,6 +581,8 @@ impl<'d> Flex<'d> { into_ref!(pin); pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); w.set_ie(true); }); @@ -591,11 +593,6 @@ impl<'d> Flex<'d> { w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIOB_PROC_0 as _); }); - #[cfg(feature = "rp235x")] - pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }); - Self { pin: pin.map_into() } } diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index d95b17ff1..82189d29a 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -363,6 +363,8 @@ where { pin.gpio().ctrl().write(|w| w.set_funcsel(3)); pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); w.set_schmitt(true); w.set_slewfast(false); w.set_ie(true); diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 3f96a3f05..b50337ad1 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -110,6 +110,8 @@ impl<'d> Pwm<'d> { if let Some(pin) = &b { pin.gpio().ctrl().write(|w| w.set_funcsel(4)); pin.pad_ctrl().modify(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); w.set_pue(b_pull == Pull::Up); w.set_pde(b_pull == Pull::Down); }); diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 058cfcbee..9fc2ad89f 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -851,7 +851,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { Outover::NORMAL }); }); - pin.pad_ctrl().write(|w| w.set_ie(true)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_ie(true); + }); } if let Some(pin) = &rx { let funcsel = { @@ -870,7 +874,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { Inover::NORMAL }); }); - pin.pad_ctrl().write(|w| w.set_ie(true)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_ie(true); + }); } if let Some(pin) = &cts { pin.gpio().ctrl().write(|w| { @@ -881,7 +889,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { Inover::NORMAL }); }); - pin.pad_ctrl().write(|w| w.set_ie(true)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_ie(true); + }); } if let Some(pin) = &rts { pin.gpio().ctrl().write(|w| { @@ -892,7 +904,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { Outover::NORMAL }); }); - pin.pad_ctrl().write(|w| w.set_ie(true)); + pin.pad_ctrl().write(|w| { + #[cfg(feature = "rp235x")] + w.set_iso(false); + w.set_ie(true); + }); } Self::set_baudrate_inner(config.baudrate); From 0d41566c245d6e4cf5359b237b61b578f81a0524 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sat, 10 Aug 2024 17:39:33 -0400 Subject: [PATCH 086/210] Switch to embassy's rp-pac repo, also use a patch. --- embassy-rp/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 6a504335d..2e821f4a0 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -124,7 +124,7 @@ embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { git = "https://github.com/CBJamo/rp-pac.git", feature = ["rt"] } +rp-pac = { version = "6.0.0", feature = ["rt"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } @@ -140,3 +140,6 @@ sha2-const-stable = "0.1" [dev-dependencies] embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } + +[patch.crates-io] +rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git" } From 9dc4375f185d5098d9b61116bb5c5279e7298222 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Aug 2024 00:02:15 +0200 Subject: [PATCH 087/210] rp: update PAC, fix CI. --- .github/ci/test.sh | 2 +- ci.sh | 7 ++++--- embassy-rp/Cargo.toml | 5 +---- embassy-rp/src/dma.rs | 6 +++--- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/bootloader/rp/Cargo.toml | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 41da644fc..771251bd1 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -21,7 +21,7 @@ cargo test --manifest-path ./embassy-boot/Cargo.toml --features ed25519-salty cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nrf52840,time-driver-rtc1,gpiote -cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver +cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040 cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti diff --git a/ci.sh b/ci.sh index 7538af22c..82108536b 100755 --- a/ci.sh +++ b/ci.sh @@ -177,12 +177,12 @@ cargo batch \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \ - --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \ - --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \ + --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ + --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040,overclock' \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ - --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \ + --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/rp2040 \ --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ @@ -197,6 +197,7 @@ cargo batch \ --- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/ns \ --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ + --- build --release --manifest-path examples/rp23/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/rp23 \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \ diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 2e821f4a0..3cc6c4e6a 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -124,7 +124,7 @@ embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { version = "6.0.0", feature = ["rt"] } +rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git", rev = "a7f42d25517f7124ad3b4ed492dec8b0f50a0e6c", feature = ["rt"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } @@ -140,6 +140,3 @@ sha2-const-stable = "0.1" [dev-dependencies] embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } - -[patch.crates-io] -rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git" } diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index df10da0b6..b00ab3f3b 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -15,7 +15,7 @@ use crate::{interrupt, pac, peripherals}; #[cfg(feature = "rt")] #[interrupt] fn DMA_IRQ_0() { - let ints0 = pac::DMA.ints0().read().ints0(); + let ints0 = pac::DMA.ints(0).read(); for channel in 0..CHANNEL_COUNT { let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); if ctrl_trig.ahb_error() { @@ -26,14 +26,14 @@ fn DMA_IRQ_0() { CHANNEL_WAKERS[channel].wake(); } } - pac::DMA.ints0().write(|w| w.set_ints0(ints0)); + pac::DMA.ints(0).write_value(ints0); } pub(crate) unsafe fn init() { interrupt::DMA_IRQ_0.disable(); interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3); - pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF)); + pac::DMA.inte(0).write_value(0xFFFF); interrupt::DMA_IRQ_0.enable(); } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index c109c0732..8bb8afdfe 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } -embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", ] } +embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index c15c980ca..9df396e5e 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } -embassy-rp = { path = "../../../../embassy-rp", features = [] } +embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] } embassy-boot-rp = { path = "../../../../embassy-boot-rp" } embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-time = { path = "../../../../embassy-time", features = [] } From 778241fd71b8a0cb541d23b69c3f9e47ec2753ff Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 12 Aug 2024 04:32:31 -0400 Subject: [PATCH 088/210] Fix CI, rename private feature, address comments from dirbaio. --- embassy-rp/Cargo.toml | 14 +++++++----- embassy-rp/src/adc.rs | 4 ++-- embassy-rp/src/binary_info/mod.rs | 12 +++++------ embassy-rp/src/clocks.rs | 21 +++++++++--------- embassy-rp/src/dma.rs | 13 ++++++----- embassy-rp/src/flash.rs | 14 +++++++----- embassy-rp/src/gpio.rs | 17 +++++++++------ embassy-rp/src/i2c.rs | 2 +- embassy-rp/src/lib.rs | 18 +++++++++++----- embassy-rp/src/multicore.rs | 4 ++-- embassy-rp/src/pio/mod.rs | 16 +++++++------- embassy-rp/src/pwm.rs | 10 ++++----- embassy-rp/src/spi.rs | 8 +++---- embassy-rp/src/time_driver.rs | 12 +++++------ embassy-rp/src/uart/mod.rs | 36 +++++++++++++++---------------- 15 files changed, 112 insertions(+), 89 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 3cc6c4e6a..1ab6cf440 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -14,8 +14,9 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/emba src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/" features = ["defmt", "unstable-pac", "time-driver"] flavors = [ - { name = "rp2040", target = "thumbv6m-none-eabi" }, - { name = "rp235x", target = "thumbv8m.main-none-eabi" }, + { name = "rp2040", target = "thumbv6m-none-eabi", features = ["rp2040"] }, + { name = "rp235xa", target = "thumbv8m.main-none-eabi", features = ["rp235xa"] }, + { name = "rp235xb", target = "thumbv8m.main-none-eabi", features = ["rp235xb"] }, ] [package.metadata.docs.rs] @@ -89,10 +90,13 @@ boot2-w25x10cl = [] ## ``` boot2-none = [] +## Configure the hal for use with the rp2040 rp2040 = ["rp-pac/rp2040"] -rp235x = ["rp-pac/rp235x"] -rp235xa = ["rp235x"] -rp235xb = ["rp235x"] +_rp235x = ["rp-pac/rp235x"] +## Configure the hal for use with the rp235xA +rp235xa = ["_rp235x"] +## Configure the hal for use with the rp235xB +rp235xb = ["_rp235x"] # Add a binary-info header block containing picotool-compatible metadata. # diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 9768f480d..9582e43c8 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -35,7 +35,7 @@ impl<'p> Channel<'p> { pub fn new_pin(pin: impl Peripheral

+ 'p, pull: Pull) -> Self { into_ref!(pin); pin.pad_ctrl().modify(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); // manual says: // @@ -234,7 +234,7 @@ impl<'d> Adc<'d, Async> { ) -> Result<(), Error> { #[cfg(feature = "rp2040")] let mut rrobin = 0_u8; - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] let mut rrobin = 0_u16; for c in channels { rrobin |= 1 << c; diff --git a/embassy-rp/src/binary_info/mod.rs b/embassy-rp/src/binary_info/mod.rs index ce3829a7c..213565cdf 100644 --- a/embassy-rp/src/binary_info/mod.rs +++ b/embassy-rp/src/binary_info/mod.rs @@ -4,13 +4,12 @@ //! and "rt" features: //! //! ``` -//! # use rp235x_hal as hal; //! #[link_section = ".bi_entries"] //! #[used] -//! pub static PICOTOOL_ENTRIES: [hal::binary_info::EntryAddr; 3] = [ -//! hal::binary_info_rp_program_name!(c"Program Name Here"), -//! hal::binary_info_rp_cargo_version!(), -//! hal::binary_info_int!(hal::binary_info::make_tag(b"JP"), 0x0000_0001, 0x12345678), +//! pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 3] = [ +//! embassy_rp::binary_info_rp_program_name!(c"Program Name Here"), +//! embassy_rp::binary_info_rp_cargo_version!(), +//! embassy_rp::binary_info_int!(embassy_rp::binary_info::make_tag(b"JP"), 0x0000_0001, 0x12345678), //! ]; //! ``` @@ -163,8 +162,7 @@ pub const fn rp_boot2_name(value: &'static core::ffi::CStr) -> StringEntry { /// Create a tag from two ASCII letters. /// /// ``` -/// # use rp235x_hal as hal; -/// let tag = hal::binary_info::make_tag(b"RP"); +/// let tag = embassy_rp::binary_info::make_tag(b"RP"); /// assert_eq!(tag, 0x5052); /// ``` pub const fn make_tag(c: &[u8; 2]) -> u16 { diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 9f387b70f..0084707f5 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -311,10 +311,10 @@ pub struct SysClkConfig { #[cfg(feature = "rp2040")] pub div_frac: u8, /// SYS clock divider. - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] pub div_int: u16, /// SYS clock fraction. - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] pub div_frac: u16, } @@ -430,12 +430,12 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); #[cfg(feature = "rp2040")] while c.clk_sys_selected().read() != 1 {} - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1) {} c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); #[cfg(feature = "rp2040")] while c.clk_ref_selected().read() != 1 {} - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {} // Reset the PLLs @@ -506,7 +506,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { }); #[cfg(feature = "rp2040")] while c.clk_ref_selected().read() != (1 << ref_src as u32) {} - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ref_src as u32) {} c.clk_ref_div().write(|w| { w.set_int(config.ref_clk.div); @@ -539,7 +539,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); #[cfg(feature = "rp2040")] while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLK_REF as u32) {} - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLK_REF as u32) {} } c.clk_sys_ctrl().write(|w| { @@ -549,7 +549,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { #[cfg(feature = "rp2040")] while c.clk_sys_selected().read() != (1 << sys_src as u32) {} - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << sys_src as u32) {} c.clk_sys_div().write(|w| { @@ -661,7 +661,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { } // rp235x specific clocks - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] { // TODO hstx clock peris.set_hstx(false); @@ -903,7 +903,8 @@ pub enum GpoutSrc { /// ADC. Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, // RTC. - //Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, + #[cfg(feature = "rp2040")] + Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, /// REF. Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, } @@ -934,7 +935,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { } /// Set clock divider. - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] pub fn set_div(&self, int: u16, frac: u16) { let c = pac::CLOCKS; c.clk_gpout_div(self.gpout.number()).write(|w| { diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index b00ab3f3b..34abe3e2d 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -147,7 +147,7 @@ fn copy_inner<'a, C: Channel>( p.trans_count().write(|w| { *w = len as u32; }); - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] p.trans_count().write(|w| { w.set_mode(0.into()); w.set_count(len as u32); @@ -208,7 +208,10 @@ impl<'a, C: Channel> Future for Transfer<'a, C> { } } +#[cfg(feature = "rp2040")] pub(crate) const CHANNEL_COUNT: usize = 12; +#[cfg(feature = "_rp235x")] +pub(crate) const CHANNEL_COUNT: usize = 16; const NEW_AW: AtomicWaker = AtomicWaker::new(); static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; @@ -303,11 +306,11 @@ channel!(DMA_CH8, 8); channel!(DMA_CH9, 9); channel!(DMA_CH10, 10); channel!(DMA_CH11, 11); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] channel!(DMA_CH12, 12); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] channel!(DMA_CH13, 13); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] channel!(DMA_CH14, 14); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] channel!(DMA_CH15, 15); diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index cc84bb12d..9991c3ac0 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -669,8 +669,10 @@ mod ram_helpers { #[inline(never)] #[link_section = ".data.ram_func"] - #[cfg(feature = "rp235x")] - unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) {} + #[cfg(feature = "_rp235x")] + unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) { + todo!(); + } #[repr(C)] struct FlashCommand { @@ -891,8 +893,10 @@ mod ram_helpers { #[inline(never)] #[link_section = ".data.ram_func"] - #[cfg(feature = "rp235x")] - unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) {} + #[cfg(feature = "_rp235x")] + unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) { + todo!(); + } } /// Make sure to uphold the contract points with rp2040-flash. @@ -906,7 +910,7 @@ pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> { } // Make sure CORE1 is paused during the entire duration of the RAM function - //crate::multicore::pause_core1(); + crate::multicore::pause_core1(); critical_section::with(|_| { // Wait for all DMA channels in flash to finish before ram operation diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 24208b82e..d0bb7e574 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -14,7 +14,12 @@ use crate::pac::SIO; use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; const NEW_AW: AtomicWaker = AtomicWaker::new(); + +#[cfg(any(feature = "rp2040", feature = "rp235xa"))] const BANK0_PIN_COUNT: usize = 30; +#[cfg(feature = "rp235xb")] +const BANK0_PIN_COUNT: usize = 48; + static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT]; #[cfg(feature = "qspi-as-gpio")] const QSPI_PIN_COUNT: usize = 6; @@ -180,7 +185,7 @@ impl<'d> Input<'d> { } /// Set the pin's pad isolation - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] #[inline] pub fn set_pad_isolation(&mut self, isolate: bool) { self.pin.set_pad_isolation(isolate) @@ -422,7 +427,7 @@ impl<'d> Output<'d> { } /// Set the pin's pad isolation - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] #[inline] pub fn set_pad_isolation(&mut self, isolate: bool) { self.pin.set_pad_isolation(isolate) @@ -555,7 +560,7 @@ impl<'d> OutputOpenDrain<'d> { } /// Set the pin's pad isolation - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] #[inline] pub fn set_pad_isolation(&mut self, isolate: bool) { self.pin.set_pad_isolation(isolate) @@ -581,7 +586,7 @@ impl<'d> Flex<'d> { into_ref!(pin); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_ie(true); }); @@ -589,7 +594,7 @@ impl<'d> Flex<'d> { pin.gpio().ctrl().write(|w| { #[cfg(feature = "rp2040")] w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _); - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIOB_PROC_0 as _); }); @@ -788,7 +793,7 @@ impl<'d> Flex<'d> { } /// Set the pin's pad isolation - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] #[inline] pub fn set_pad_isolation(&mut self, isolate: bool) { self.pin.pad_ctrl().modify(|w| { diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 82189d29a..32778215f 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -363,7 +363,7 @@ where { pin.gpio().ctrl().write(|w| w.set_funcsel(3)); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_schmitt(true); w.set_slewfast(false); diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 0bcc58b86..dc54c1bfe 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -15,9 +15,9 @@ mod critical_section_impl; mod intrinsics; pub mod adc; -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] pub mod binary_info; -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] pub mod block; #[cfg(feature = "rp2040")] pub mod bootsel; @@ -92,7 +92,7 @@ embassy_hal_internal::interrupt_mod!( SWI_IRQ_5, ); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] embassy_hal_internal::interrupt_mod!( TIMER0_IRQ_0, TIMER0_IRQ_1, @@ -267,7 +267,7 @@ embassy_hal_internal::peripherals! { BOOTSEL, } -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] embassy_hal_internal::peripherals! { PIN_0, PIN_1, @@ -497,7 +497,7 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } -#[cfg(feature = "rp235x")] +#[cfg(all(feature = "_rp235x", armv8m))] #[inline(always)] fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { let core = unsafe { cortex_m::Peripherals::steal() }; @@ -515,6 +515,14 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } +// This is to hack around cortex_m defaulting to ARMv7 when building tests, +// so the compile fails when we try to use ARMv8 peripherals. +#[cfg(all(feature = "_rp235x", not(armv8m)))] +#[inline(always)] +fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { + Ok(()) +} + /// HAL configuration for RP. pub mod config { use crate::clocks::ClockConfig; diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index d1ce688ce..9f7d77bf5 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -109,7 +109,7 @@ unsafe fn SIO_IRQ_PROC1() { } } -#[cfg(all(feature = "rt", feature = "rp235x"))] +#[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] #[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_FIFO() { @@ -164,7 +164,7 @@ where unsafe { interrupt::SIO_IRQ_PROC1.enable() }; - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] unsafe { interrupt::SIO_IRQ_FIFO.enable() }; diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 89313086b..68b1d6849 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -354,7 +354,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); #[cfg(feature = "rp2040")] p.trans_count().write(|w| *w = data.len() as u32); - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] p.trans_count().write(|w| w.set_count(data.len() as u32)); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { @@ -439,7 +439,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32); #[cfg(feature = "rp2040")] p.trans_count().write(|w| *w = data.len() as u32); - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] p.trans_count().write(|w| w.set_count(data.len() as u32)); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { @@ -529,7 +529,7 @@ pub struct PinConfig { /// Comparison level or IRQ index for the MOV x, STATUS instruction. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] pub enum StatusN { /// IRQ flag in this PIO block This(u8), @@ -539,14 +539,14 @@ pub enum StatusN { Higher(u8), } -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl Default for StatusN { fn default() -> Self { Self::This(0) } } -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl Into for StatusN { fn into(self) -> crate::pac::pio::vals::ExecctrlStatusN { let x = match self { @@ -576,7 +576,7 @@ pub struct Config<'d, PIO: Instance> { #[cfg(feature = "rp2040")] pub status_n: u8, // This cfg probably shouldn't be required, but the SVD for the 2040 doesn't have the enum - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] /// Status comparison level. pub status_n: StatusN, exec: ExecConfig, @@ -709,7 +709,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_out_sticky(config.out_sticky); w.set_wrap_top(config.exec.wrap_top); w.set_wrap_bottom(config.exec.wrap_bottom); - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_status_sel(match config.status_sel { StatusSource::TxFifoLevel => pac::pio::vals::ExecctrlStatusSel::TXLEVEL, StatusSource::RxFifoLevel => pac::pio::vals::ExecctrlStatusSel::RXLEVEL, @@ -1250,7 +1250,7 @@ macro_rules! impl_pio { impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0); impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pio!(PIO2, 2, PIO2, PIO2_0, PIO2_IRQ_0); /// PIO pin. diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index b50337ad1..7da3dccb0 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -110,7 +110,7 @@ impl<'d> Pwm<'d> { if let Some(pin) = &b { pin.gpio().ctrl().write(|w| w.set_funcsel(4)); pin.pad_ctrl().modify(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_pue(b_pull == Pull::Up); w.set_pde(b_pull == Pull::Down); @@ -365,13 +365,13 @@ slice!(PWM_SLICE5, 5); slice!(PWM_SLICE6, 6); slice!(PWM_SLICE7, 7); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] slice!(PWM_SLICE8, 8); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] slice!(PWM_SLICE9, 9); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] slice!(PWM_SLICE10, 10); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] slice!(PWM_SLICE11, 11); /// PWM Channel A. diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index bc852ff7b..b89df74a2 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -107,7 +107,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { if let Some(pin) = &clk { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_schmitt(true); w.set_slewfast(false); @@ -120,7 +120,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { if let Some(pin) = &mosi { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_schmitt(true); w.set_slewfast(false); @@ -133,7 +133,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { if let Some(pin) = &miso { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_schmitt(true); w.set_slewfast(false); @@ -146,7 +146,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { if let Some(pin) = &cs { pin.gpio().ctrl().write(|w| w.set_funcsel(1)); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_schmitt(true); w.set_slewfast(false); diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index ba5a91c29..e5b407a29 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -8,7 +8,7 @@ use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::{AlarmHandle, Driver}; #[cfg(feature = "rp2040")] use pac::TIMER; -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] use pac::TIMER0 as TIMER; use crate::interrupt::InterruptExt; @@ -155,7 +155,7 @@ pub unsafe fn init() { interrupt::TIMER_IRQ_2.enable(); interrupt::TIMER_IRQ_3.enable(); } - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] { interrupt::TIMER0_IRQ_0.enable(); interrupt::TIMER0_IRQ_1.enable(); @@ -188,25 +188,25 @@ fn TIMER_IRQ_3() { DRIVER.check_alarm(3) } -#[cfg(all(feature = "rt", feature = "rp235x"))] +#[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] fn TIMER0_IRQ_0() { DRIVER.check_alarm(0) } -#[cfg(all(feature = "rt", feature = "rp235x"))] +#[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] fn TIMER0_IRQ_1() { DRIVER.check_alarm(1) } -#[cfg(all(feature = "rt", feature = "rp235x"))] +#[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] fn TIMER0_IRQ_2() { DRIVER.check_alarm(2) } -#[cfg(all(feature = "rt", feature = "rp235x"))] +#[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] fn TIMER0_IRQ_3() { DRIVER.check_alarm(3) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 9fc2ad89f..aba4b792a 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -852,7 +852,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); }); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_ie(true); }); @@ -875,7 +875,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); }); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_ie(true); }); @@ -890,7 +890,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); }); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_ie(true); }); @@ -905,7 +905,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); }); pin.pad_ctrl().write(|w| { - #[cfg(feature = "rp235x")] + #[cfg(feature = "_rp235x")] w.set_iso(false); w.set_ie(true); }); @@ -1371,33 +1371,33 @@ impl_pin!(PIN_28, UART0, TxPin); impl_pin!(PIN_29, UART0, RxPin); // Additional functions added by all 2350s -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_2, UART0, TxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_3, UART0, RxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_6, UART1, TxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_7, UART1, RxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_10, UART1, TxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_11, UART1, RxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_14, UART0, TxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_15, UART0, RxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_18, UART0, TxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_19, UART0, RxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_22, UART1, TxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_23, UART1, RxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_26, UART1, TxPin); -#[cfg(feature = "rp235x")] +#[cfg(feature = "_rp235x")] impl_pin!(PIN_27, UART1, RxPin); // Additional pins added by larger 2350 packages. From 752fbc662a43b677b7ffb7672b01772b28ff4e1f Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 12 Aug 2024 05:06:59 -0400 Subject: [PATCH 089/210] Fix docs, ci --- embassy-rp/src/clocks.rs | 2 +- embassy-rp/src/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 0084707f5..5f7ba10e2 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -902,7 +902,7 @@ pub enum GpoutSrc { Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, /// ADC. Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, - // RTC. + /// RTC. #[cfg(feature = "rp2040")] Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, /// REF. diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index dc54c1bfe..f968572b3 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -497,7 +497,7 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } -#[cfg(all(feature = "_rp235x", armv8m))] +#[cfg(all(feature = "_rp235x", not(test)))] #[inline(always)] fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { let core = unsafe { cortex_m::Peripherals::steal() }; @@ -517,9 +517,9 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { // This is to hack around cortex_m defaulting to ARMv7 when building tests, // so the compile fails when we try to use ARMv8 peripherals. -#[cfg(all(feature = "_rp235x", not(armv8m)))] +#[cfg(test)] #[inline(always)] -fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { +fn install_stack_guard(_stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } From 13cb4314725bb60d2252575f8fd06828e8661064 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 12 Aug 2024 05:47:16 -0400 Subject: [PATCH 090/210] Enable rp235x doc tests, fixup feature doc The rp235x doc test requires an unfortunate workaround using a private feature, "_test", in order compile. --- .github/ci/test.sh | 3 ++- embassy-rp/Cargo.toml | 11 +++++++---- embassy-rp/src/lib.rs | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 771251bd1..da0021684 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -21,7 +21,8 @@ cargo test --manifest-path ./embassy-boot/Cargo.toml --features ed25519-salty cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nrf52840,time-driver-rtc1,gpiote -cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040 +cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040,_test +cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp235xa,_test cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 1ab6cf440..453f1aa0f 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -98,10 +98,13 @@ rp235xa = ["_rp235x"] ## Configure the hal for use with the rp235xB rp235xb = ["_rp235x"] -# Add a binary-info header block containing picotool-compatible metadata. -# -# Takes up a little flash space, but picotool can then report the name of your -# program and other details. +# hack around cortex-m peripherals being wrong when running tests. +_test = [] + +## Add a binary-info header block containing picotool-compatible metadata. +## +## Takes up a little flash space, but picotool can then report the name of your +## program and other details. binary-info = [ "rt" ] [dependencies] diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index f968572b3..1fc397107 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -469,7 +469,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> { unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } } -#[cfg(feature = "rp2040")] +#[cfg(all(feature = "rp2040", not(feature = "_test")))] #[inline(always)] fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { let core = unsafe { cortex_m::Peripherals::steal() }; @@ -497,7 +497,7 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } -#[cfg(all(feature = "_rp235x", not(test)))] +#[cfg(all(feature = "_rp235x", not(feature = "_test")))] #[inline(always)] fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { let core = unsafe { cortex_m::Peripherals::steal() }; @@ -517,7 +517,7 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { // This is to hack around cortex_m defaulting to ARMv7 when building tests, // so the compile fails when we try to use ARMv8 peripherals. -#[cfg(test)] +#[cfg(feature = "_test")] #[inline(always)] fn install_stack_guard(_stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) From b7dc4c7b6f057d4e22b179563ca8565eedbff18a Mon Sep 17 00:00:00 2001 From: nerwalt Date: Mon, 12 Aug 2024 06:23:32 -0600 Subject: [PATCH 091/210] Fixes build issues related to nrf9120 features --- embassy-nrf/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index bc0a9d199..3e66d6886 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -103,12 +103,12 @@ nrf9160-ns = ["_nrf9160", "_ns", "_nrf91"] ## The nRF9120 is the internal part number for the nRF9161 and nRF9151. ## nRF9120 in Secure mode nrf9120-s = ["_nrf9120", "_s", "_nrf91"] -nrf9151-s = ["_nrf9120", "_s", "_nrf91"] -nrf9161-s = ["_nrf9120", "_s", "_nrf91"] +nrf9151-s = ["nrf9120-s"] +nrf9161-s = ["nrf9120-s"] ## nRF9120 in Non-Secure mode nrf9120-ns = ["_nrf9120", "_ns", "_nrf91"] -nrf9151-ns = ["_nrf9120", "_ns", "_nrf91"] -nrf9161-ns = ["_nrf9120", "_ns", "_nrf91"] +nrf9151-ns = ["nrf9120-ns"] +nrf9161-ns = ["nrf9120-ns"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. From 7a950f424362d28718fc48d182949c7ab8336d48 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Aug 2024 14:29:56 +0200 Subject: [PATCH 092/210] fix rp docs build --- cyw43-pio/Cargo.toml | 1 + embassy-boot-rp/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 1172d6c31..4e21c255f 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -26,3 +26,4 @@ defmt = { version = "0.3", optional = true } src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/" target = "thumbv6m-none-eabi" +features = ["embassy-rp/rp2040"] diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 5b173638e..bf5f34abe 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -16,6 +16,7 @@ categories = [ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-rp/src/" target = "thumbv6m-none-eabi" +features = ["embassy-rp/rp2040"] [lib] From 3e27ee1ecc290eeb81d46e7beacb522f012769b8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Aug 2024 14:38:52 +0200 Subject: [PATCH 093/210] Actually fix embassy-rp docs build. --- embassy-rp/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 453f1aa0f..d0612957f 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -15,8 +15,8 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/sr features = ["defmt", "unstable-pac", "time-driver"] flavors = [ { name = "rp2040", target = "thumbv6m-none-eabi", features = ["rp2040"] }, - { name = "rp235xa", target = "thumbv8m.main-none-eabi", features = ["rp235xa"] }, - { name = "rp235xb", target = "thumbv8m.main-none-eabi", features = ["rp235xb"] }, + { name = "rp235xa", target = "thumbv8m.main-none-eabihf", features = ["rp235xa"] }, + { name = "rp235xb", target = "thumbv8m.main-none-eabihf", features = ["rp235xb"] }, ] [package.metadata.docs.rs] From 5a0c75682a50a429aebff91e1cd6a347c07e42ff Mon Sep 17 00:00:00 2001 From: nerwalt Date: Mon, 12 Aug 2024 06:42:07 -0600 Subject: [PATCH 094/210] Adding nrf9151 and nrf9161 feature coverage to CI --- ci.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ci.sh b/ci.sh index 82108536b..3e3d9ad00 100755 --- a/ci.sh +++ b/ci.sh @@ -182,6 +182,8 @@ cargo batch \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ + --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \ + --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \ --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/rp2040 \ --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ @@ -227,6 +229,8 @@ cargo batch \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --out-dir out/examples/boot/nrf9120 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns,skip-include --out-dir out/examples/boot/nrf9151 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns,skip-include --out-dir out/examples/boot/nrf9161 \ --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \ --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \ --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \ @@ -239,6 +243,8 @@ cargo batch \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ + --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \ + --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \ From 0b58ef8f1ba4faa9d79bd61ee58c6cee234b402c Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 13 Aug 2024 00:53:58 -0400 Subject: [PATCH 095/210] Fix commented out code --- embassy-rp/src/flash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 9991c3ac0..a68493932 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -927,7 +927,7 @@ pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> { }); // Resume CORE1 execution - //crate::multicore::resume_core1(); + crate::multicore::resume_core1(); Ok(()) } From 0b8779593772f336531c0ebb5a583190b4f31c6b Mon Sep 17 00:00:00 2001 From: ferris Date: Tue, 13 Aug 2024 17:25:00 +0200 Subject: [PATCH 096/210] Add OTG core DMA address registers --- embassy-usb-synopsys-otg/src/otg_v1.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs index 111bc4a63..a8530980c 100644 --- a/embassy-usb-synopsys-otg/src/otg_v1.rs +++ b/embassy-usb-synopsys-otg/src/otg_v1.rs @@ -272,6 +272,12 @@ impl Otg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x0510usize + n * 32usize) as _) } } + #[doc = "Host channel DMA address register"] + #[inline(always)] + pub const fn hcdma(self, n: usize) -> Reg { + assert!(n < 12usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0514usize + n * 32usize) as _) } + } #[doc = "Device configuration register"] #[inline(always)] pub const fn dcfg(self) -> Reg { @@ -364,6 +370,12 @@ impl Otg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0b10usize + n * 32usize) as _) } } + #[doc = "Device OUT/IN endpoint DMA address register"] + #[inline(always)] + pub const fn doepdma(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0b14usize + n * 32usize) as _) } + } #[doc = "Power and clock gating control register"] #[inline(always)] pub const fn pcgcctl(self) -> Reg { From a63d46507de7fbb44233ba5557630791f62a985a Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Thu, 15 Aug 2024 10:58:10 +0800 Subject: [PATCH 097/210] feat(usb): add device qualifier descriptor Signed-off-by: Haobo Gu --- embassy-usb/src/descriptor.rs | 21 +++++++++++++++++++++ embassy-usb/src/lib.rs | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index eb3d1f53a..f1773fa8a 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -13,6 +13,8 @@ pub mod descriptor_type { pub const STRING: u8 = 3; pub const INTERFACE: u8 = 4; pub const ENDPOINT: u8 = 5; + pub const DEVICE_QUALIFIER: u8 = 6; + pub const OTHER_SPEED_CONFIGURATION: u8 = 7; pub const IAD: u8 = 11; pub const BOS: u8 = 15; pub const CAPABILITY: u8 = 16; @@ -272,6 +274,25 @@ pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] { ] } +/// Create a new Device Qualifier Descriptor array. +/// +/// All device qualifier descriptors are always 10 bytes, so there's no need for +/// a variable-length buffer or DescriptorWriter. +pub(crate) fn device_qualifier_descriptor(config: &Config) -> [u8; 10] { + [ + 10, // bLength + 0x06, // bDescriptorType + 0x10, + 0x02, // bcdUSB 2.1 + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 + 1, // bNumConfigurations + 0, // Reserved + ] +} + /// A writer for Binary Object Store descriptor. pub struct BosWriter<'a> { pub(crate) writer: DescriptorWriter<'a>, diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index d58950838..a5478ca0e 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -190,6 +190,7 @@ struct Inner<'d, D: Driver<'d>> { config: Config<'d>, device_descriptor: [u8; 18], + device_qualifier_descriptor: [u8; 10], config_descriptor: &'d [u8], bos_descriptor: &'d [u8], msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, @@ -225,6 +226,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { // This prevent further allocation by consuming the driver. let (bus, control) = driver.start(config.max_packet_size_0 as u16); let device_descriptor = descriptor::device_descriptor(&config); + let device_qualifier_descriptor = descriptor::device_qualifier_descriptor(&config); Self { control_buf, @@ -233,6 +235,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { bus, config, device_descriptor, + device_qualifier_descriptor, config_descriptor, bos_descriptor, msos_descriptor, @@ -764,6 +767,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> { } } } + descriptor_type::DEVICE_QUALIFIER => InResponse::Accepted(&self.device_qualifier_descriptor), _ => InResponse::Rejected, } } From ccf8ce7c7e01555755c43996b65d4d9043eebbf5 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Fri, 16 Aug 2024 15:23:56 +0100 Subject: [PATCH 098/210] Note where some embassy-rs files come from. In a similar fashion to other source files taken from rp-rs. --- embassy-rp/src/binary_info/consts.rs | 3 +++ embassy-rp/src/binary_info/macros.rs | 3 +++ embassy-rp/src/binary_info/mod.rs | 3 +++ embassy-rp/src/binary_info/types.rs | 3 +++ embassy-rp/src/block.rs | 3 +++ 5 files changed, 15 insertions(+) diff --git a/embassy-rp/src/binary_info/consts.rs b/embassy-rp/src/binary_info/consts.rs index c8270c081..d5fcd0d75 100644 --- a/embassy-rp/src/binary_info/consts.rs +++ b/embassy-rp/src/binary_info/consts.rs @@ -1,5 +1,8 @@ //! Constants for binary info +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + /// All Raspberry Pi specified IDs have this tag. /// /// You can create your own for custom fields. diff --git a/embassy-rp/src/binary_info/macros.rs b/embassy-rp/src/binary_info/macros.rs index 0d6ba5eb5..faf6148c8 100644 --- a/embassy-rp/src/binary_info/macros.rs +++ b/embassy-rp/src/binary_info/macros.rs @@ -1,5 +1,8 @@ //! Handy macros for making Binary Info entries +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + /// Generate a static item containing the given environment variable, /// and return its [`EntryAddr`](super::EntryAddr). #[macro_export] diff --git a/embassy-rp/src/binary_info/mod.rs b/embassy-rp/src/binary_info/mod.rs index 213565cdf..ea475086b 100644 --- a/embassy-rp/src/binary_info/mod.rs +++ b/embassy-rp/src/binary_info/mod.rs @@ -13,6 +13,9 @@ //! ]; //! ``` +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + pub mod consts; mod types; diff --git a/embassy-rp/src/binary_info/types.rs b/embassy-rp/src/binary_info/types.rs index d2b192e32..6aec1902e 100644 --- a/embassy-rp/src/binary_info/types.rs +++ b/embassy-rp/src/binary_info/types.rs @@ -1,5 +1,8 @@ //! Types for the Binary Info system +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + /// This is the 'Binary Info' header block that `picotool` looks for in your UF2 /// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your /// program. diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs index d270bbf1c..a3e1ad925 100644 --- a/embassy-rp/src/block.rs +++ b/embassy-rp/src/block.rs @@ -6,6 +6,9 @@ //! firmware image. The `PARTITION_TABLE` Block (here the `PartitionTable` type) //! tells the ROM how to divide the flash space up into partitions. +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + // These all have a 1 byte size /// An item ID for encoding a Vector Table address From 16c3e5880fcbd21b0b67ac313e28c3b340fe3ece Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 16 Aug 2024 17:51:52 +0200 Subject: [PATCH 099/210] Add license files to embassy-rp crediting rp-rs. --- embassy-rp/LICENSE-APACHE | 202 ++++++++++++++++++++++++++++++++++++++ embassy-rp/LICENSE-MIT | 26 +++++ 2 files changed, 228 insertions(+) create mode 100644 embassy-rp/LICENSE-APACHE create mode 100644 embassy-rp/LICENSE-MIT diff --git a/embassy-rp/LICENSE-APACHE b/embassy-rp/LICENSE-APACHE new file mode 100644 index 000000000..48be1263d --- /dev/null +++ b/embassy-rp/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright (c) Embassy project contributors +Portions copyright (c) rp-rs organization + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/embassy-rp/LICENSE-MIT b/embassy-rp/LICENSE-MIT new file mode 100644 index 000000000..f1cfbd5f7 --- /dev/null +++ b/embassy-rp/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) Embassy project contributors +Portions copyright (c) rp-rs organization + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From d6bf4c45d28072348f1527809c21311989e52012 Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Fri, 16 Aug 2024 22:51:28 -0400 Subject: [PATCH 100/210] feat(mdns): Enable mdns support through smoltcp --- embassy-net/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index d86a30755..28bac485b 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -44,6 +44,8 @@ raw = ["smoltcp/socket-raw"] tcp = ["smoltcp/socket-tcp"] ## Enable DNS support dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] +## Enable mDNS support +mdns = ["dns", "smoltcp/socket-mdns"] ## Enable DHCPv4 support dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] ## Enable DHCPv4 support with hostname From 20b1b15bda969309566ad495d54635da8b7f29b2 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 17 Aug 2024 12:37:42 +0200 Subject: [PATCH 101/210] add one more embassy in the wild example (#3262) --- docs/pages/embassy_in_the_wild.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc index 76b1169bd..bb457a869 100644 --- a/docs/pages/embassy_in_the_wild.adoc +++ b/docs/pages/embassy_in_the_wild.adoc @@ -2,6 +2,8 @@ Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]! +* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock] +** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files. * link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] ** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! ** Targets STM32, RP2040, nRF52 and ESP32 MCUs From 2b7e76efe9916170cba69da964d53c19a246ae45 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Sat, 17 Aug 2024 00:26:33 +0300 Subject: [PATCH 102/210] Fix dma nvic issues on dual core lines This commit addresses #3256 by disabling dma NVIC interrupt enablement at startup. Instead, per-channel NVIC interrupt enablement is now done with the rest of the dma channel configuration. This ensures that each core will only handle the interrupts of the DMA channels that it uses. --- embassy-stm32/build.rs | 70 +++++++++++++++------- embassy-stm32/src/dma/dma_bdma.rs | 9 +++ embassy-stm32/src/dma/gpdma.rs | 9 +++ embassy-stm32/src/lib.rs | 20 ++++++- embassy-stm32/src/rcc/bd.rs | 2 + embassy-stm32/src/rcc/c0.rs | 1 + embassy-stm32/src/rcc/f013.rs | 1 + embassy-stm32/src/rcc/f247.rs | 2 + embassy-stm32/src/rcc/g0.rs | 2 + embassy-stm32/src/rcc/g4.rs | 2 + embassy-stm32/src/rcc/h.rs | 3 +- embassy-stm32/src/rcc/l.rs | 1 + embassy-stm32/src/rcc/u5.rs | 1 + embassy-stm32/src/rcc/wba.rs | 1 + examples/boot/application/stm32wl/memory.x | 6 +- examples/stm32wl/memory.x | 6 +- 16 files changed, 108 insertions(+), 28 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d8a7ea0e6..1984a1420 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1494,6 +1494,36 @@ fn main() { .flat_map(|p| &p.registers) .any(|p| p.kind == "dmamux"); + let mut dma_irqs: BTreeMap<&str, Vec> = BTreeMap::new(); + + for p in METADATA.peripherals { + if let Some(r) = &p.registers { + if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" { + for irq in p.interrupts { + let ch_name = format!("{}_{}", p.name, irq.signal); + let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap(); + + // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. + if has_dmamux && ch.dmamux.is_none() { + continue; + } + + dma_irqs.entry(irq.interrupt).or_default().push(ch_name); + } + } + } + } + + #[cfg(feature = "_dual-core")] + let mut dma_ch_to_irq: BTreeMap<&str, Vec> = BTreeMap::new(); + + #[cfg(feature = "_dual-core")] + for (irq, channels) in &dma_irqs { + for channel in channels { + dma_ch_to_irq.entry(channel).or_default().push(irq.to_string()); + } + } + for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() { // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. if has_dmamux && ch.dmamux.is_none() { @@ -1502,6 +1532,16 @@ fn main() { let name = format_ident!("{}", ch.name); let idx = ch_idx as u8; + #[cfg(feature = "_dual-core")] + let irq = { + let irq_name = if let Some(x) = &dma_ch_to_irq.get(ch.name) { + format_ident!("{}", x.get(0).unwrap()) + } else { + panic!("failed to find dma interrupt") + }; + quote!(crate::pac::Interrupt::#irq_name) + }; + g.extend(quote!(dma_channel_impl!(#name, #idx);)); let dma = format_ident!("{}", ch.dma); @@ -1532,6 +1572,7 @@ fn main() { None => quote!(), }; + #[cfg(not(feature = "_dual-core"))] dmas.extend(quote! { crate::dma::ChannelInfo { dma: #dma_info, @@ -1539,31 +1580,20 @@ fn main() { #dmamux }, }); + #[cfg(feature = "_dual-core")] + dmas.extend(quote! { + crate::dma::ChannelInfo { + dma: #dma_info, + num: #ch_num, + irq: #irq, + #dmamux + }, + }); } // ======== // Generate DMA IRQs. - let mut dma_irqs: BTreeMap<&str, Vec> = BTreeMap::new(); - - for p in METADATA.peripherals { - if let Some(r) = &p.registers { - if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" { - for irq in p.interrupts { - let ch_name = format!("{}_{}", p.name, irq.signal); - let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap(); - - // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. - if has_dmamux && ch.dmamux.is_none() { - continue; - } - - dma_irqs.entry(irq.interrupt).or_default().push(ch_name); - } - } - } - } - let dma_irqs: TokenStream = dma_irqs .iter() .map(|(irq, channels)| { diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 8a6aa53a0..8e2964f94 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -15,6 +15,8 @@ use crate::{interrupt, pac}; pub(crate) struct ChannelInfo { pub(crate) dma: DmaInfo, pub(crate) num: usize, + #[cfg(feature = "_dual-core")] + pub(crate) irq: pac::Interrupt, #[cfg(dmamux)] pub(crate) dmamux: super::DmamuxInfo, } @@ -259,10 +261,12 @@ pub(crate) unsafe fn init( foreach_interrupt! { ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority); + #[cfg(not(feature = "_dual-core"))] crate::interrupt::typelevel::$irq::enable(); }; ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority); + #[cfg(not(feature = "_dual-core"))] crate::interrupt::typelevel::$irq::enable(); }; } @@ -341,6 +345,11 @@ impl AnyChannel { options: TransferOptions, ) { let info = self.info(); + #[cfg(feature = "_dual-core")] + { + use embassy_hal_internal::interrupt::InterruptExt as _; + info.irq.enable(); + } #[cfg(dmamux)] super::dmamux::configure_dmamux(&info.dmamux, _request); diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 13d5d15be..f9d66ca86 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -18,6 +18,8 @@ use crate::pac::gpdma::vals; pub(crate) struct ChannelInfo { pub(crate) dma: pac::gpdma::Gpdma, pub(crate) num: usize, + #[cfg(feature = "_dual-core")] + pub(crate) irq: pac::Interrupt, } /// GPDMA transfer options. @@ -57,6 +59,7 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: P foreach_interrupt! { ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); + #[cfg(not(feature = "_dual-core"))] crate::interrupt::typelevel::$irq::enable(); }; } @@ -67,6 +70,12 @@ impl AnyChannel { /// Safety: Must be called with a matching set of parameters for a valid dma channel pub(crate) unsafe fn on_irq(&self) { let info = self.info(); + #[cfg(feature = "_dual-core")] + { + use embassy_hal_internal::interrupt::InterruptExt as _; + info.irq.enable(); + } + let state = &STATE[self.id as usize]; let ch = info.dma.ch(info.num); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 12ebbae2d..98695e738 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -197,6 +197,7 @@ pub use crate::pac::NVIC_PRIO_BITS; /// `embassy-stm32` global configuration. #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// RCC config. pub rcc: rcc::Config, @@ -303,6 +304,7 @@ mod dual_core { pub struct SharedData { init_flag: AtomicUsize, clocks: UnsafeCell>, + config: UnsafeCell>, } unsafe impl Sync for SharedData {} @@ -325,6 +327,8 @@ mod dual_core { rcc::set_freqs_ptr(shared_data.clocks.get()); let p = init_hw(config); + unsafe { *shared_data.config.get() }.write(config); + shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst); p @@ -372,9 +376,23 @@ mod dual_core { fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals { rcc::set_freqs_ptr(shared_data.clocks.get()); + let config = unsafe { (*shared_data.config.get()).assume_init() }; + // We use different timers on the different cores, so we have to still initialize one here - #[cfg(feature = "_time-driver")] critical_section::with(|cs| { + unsafe { + dma::init( + cs, + #[cfg(bdma)] + config.bdma_interrupt_priority, + #[cfg(dma)] + config.dma_interrupt_priority, + #[cfg(gpdma)] + config.gpdma_interrupt_priority, + ) + } + + #[cfg(feature = "_time-driver")] // must be after rcc init time_driver::init(cs); }); diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 4e9c18594..9ccca8a2a 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -16,6 +16,7 @@ pub enum LseMode { Bypass, } +#[derive(Clone, Copy)] pub struct LseConfig { pub frequency: Hertz, pub mode: LseMode, @@ -80,6 +81,7 @@ fn bdcr() -> Reg { return crate::pac::RCC.csr1(); } +#[derive(Clone, Copy)] pub struct LsConfig { pub rtc: RtcClockSource, pub lsi: bool, diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 5adf37941..6712aedc4 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -37,6 +37,7 @@ pub struct Hsi { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// HSI Configuration pub hsi: Option, diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 63dc27bdd..60577b213 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -76,6 +76,7 @@ pub enum HrtimClockSource { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { pub hsi: bool, pub hse: Option, diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 61f687d30..58056301a 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -63,6 +63,7 @@ pub struct Pll { /// Used to calculate flash waitstates. See /// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency #[cfg(stm32f2)] +#[derive(Clone, Copy)] pub enum VoltageScale { /// 2.7 to 3.6 V Range0, @@ -76,6 +77,7 @@ pub enum VoltageScale { /// Configuration of the core clocks #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { pub hsi: bool, pub hse: Option, diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index c2fa0ca39..c53c83b0e 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -33,6 +33,7 @@ pub struct Hse { /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output /// dividers. Be sure to keep check the datasheet for your specific part for the appropriate /// frequency ranges for each of these settings. +#[derive(Clone, Copy)] pub struct Pll { /// PLL Source clock selection. pub source: PllSource, @@ -55,6 +56,7 @@ pub struct Pll { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// HSI Enable pub hsi: bool, diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index c261c0fed..16561f908 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -32,6 +32,7 @@ pub struct Hse { /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output /// dividers. Be sure to keep check the datasheet for your specific part for the appropriate /// frequency ranges for each of these settings. +#[derive(Clone, Copy)] pub struct Pll { /// PLL Source clock selection. pub source: PllSource, @@ -54,6 +55,7 @@ pub struct Pll { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// HSI Enable pub hsi: bool, diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index e3c7dd158..376a0b454 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -120,7 +120,7 @@ impl From for Timpre { /// Power supply configuration /// See RM0433 Rev 4 7.4 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] pub enum SupplyConfig { /// Default power supply configuration. /// V CORE Power Domains are supplied from the LDO according to VOS. @@ -180,6 +180,7 @@ pub enum SMPSSupplyVoltage { /// Configuration of the core clocks #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { pub hsi: Option, pub hse: Option, diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index e9266c65b..6120d33be 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -30,6 +30,7 @@ pub struct Hse { } /// Clocks configuration +#[derive(Clone, Copy)] pub struct Config { // base clock sources pub msi: Option, diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index d6331f512..28545ca51 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -59,6 +59,7 @@ pub struct Pll { pub divr: Option, } +#[derive(Clone, Copy)] pub struct Config { // base clock sources pub msi: Option, diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 8e1779d7c..1fee648d4 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -15,6 +15,7 @@ pub struct Hse { } /// Clocks configuration +#[derive(Clone, Copy)] pub struct Config { // base clock sources pub hsi: bool, diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x index 5af1723f5..20109e37e 100644 --- a/examples/boot/application/stm32wl/memory.x +++ b/examples/boot/application/stm32wl/memory.x @@ -5,8 +5,8 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K FLASH : ORIGIN = 0x08008000, LENGTH = 64K DFU : ORIGIN = 0x08018000, LENGTH = 68K - SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 - RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 32K - 64 + SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128 + RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 32K - 128 } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); @@ -21,4 +21,4 @@ SECTIONS { *(.shared_data) } > SHARED_RAM -} \ No newline at end of file +} diff --git a/examples/stm32wl/memory.x b/examples/stm32wl/memory.x index 0298caa4b..4590867a8 100644 --- a/examples/stm32wl/memory.x +++ b/examples/stm32wl/memory.x @@ -2,8 +2,8 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ FLASH : ORIGIN = 0x08000000, LENGTH = 256K - SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 - RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 64K - 64 + SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128 + RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128 } SECTIONS @@ -12,4 +12,4 @@ SECTIONS { *(.shared_data) } > SHARED_RAM -} \ No newline at end of file +} From 550f2cfca020222868670b927f9de130559b09a7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 17:45:29 +0200 Subject: [PATCH 103/210] Temporarily disable stm32f1 tests. --- ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci.sh b/ci.sh index 3e3d9ad00..8ccdb09c8 100755 --- a/ci.sh +++ b/ci.sh @@ -289,6 +289,9 @@ cargo batch \ $BUILD_EXTRA +# temporarily disabled, bluepill board got bricked +rm -rf out/tests/stm32f103c8 + rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From 4bef0fc95342adbda42a4cc6751a406a4f602c67 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 18:14:56 +0200 Subject: [PATCH 104/210] disable uart ringbuffered test on f2. --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 8ccdb09c8..da842577d 100755 --- a/ci.sh +++ b/ci.sh @@ -301,8 +301,9 @@ rm out/tests/stm32f207zg/eth # doesn't work, gives "noise error", no idea why. usart_dma does pass. rm out/tests/stm32u5a5zj/usart -# flaky, perhaps bad wire +# flaky, probably due to bad ringbuffered dma code. rm out/tests/stm32l152re/usart_rx_ringbuffered +rm out/tests/stm32f207zg/usart_rx_ringbuffered if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests From 8884766450e49e4557a2b5babed1ccf93058680a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 21:49:06 +0200 Subject: [PATCH 105/210] stm32: update metapac --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/f3.rs | 2 +- embassy-stm32/src/adc/f3_v1_1.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ac9e9644c..54abd0799 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b" } vcell = "0.1.3" nb = "1.0.0" @@ -97,7 +97,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index ac88c9742..0ebeb8a9e 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -42,7 +42,7 @@ impl super::SealedAdcChannel for Vref { impl Vref { /// The value that vref would be if vdda was at 3300mv pub fn value(&self) -> u16 { - crate::pac::VREFINTCAL.data().read().value() + crate::pac::VREFINTCAL.data().read() } } diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 689c2871d..291a3861e 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -74,7 +74,7 @@ impl super::SealedAdcChannel for Vref { impl Vref { /// The value that vref would be if vdda was at 3000mv pub fn calibrated_value(&self) -> u16 { - crate::pac::VREFINTCAL.data().read().value() + crate::pac::VREFINTCAL.data().read() } pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { From eab3a57263d52eed517ee0fb9ccb307196664ee6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 21:56:14 +0200 Subject: [PATCH 106/210] rp: use the rp-binary-info crate for binary info. --- ci.sh | 1 + embassy-rp/Cargo.toml | 3 +- embassy-rp/src/binary_info/consts.rs | 34 ---- embassy-rp/src/binary_info/macros.rs | 171 ---------------- embassy-rp/src/binary_info/mod.rs | 175 ----------------- embassy-rp/src/binary_info/types.rs | 195 ------------------- embassy-rp/src/lib.rs | 5 +- examples/rp23/src/bin/adc.rs | 8 +- examples/rp23/src/bin/adc_dma.rs | 8 +- examples/rp23/src/bin/assign_resources.rs | 8 +- examples/rp23/src/bin/blinky.rs | 8 +- examples/rp23/src/bin/blinky_two_channels.rs | 8 +- examples/rp23/src/bin/blinky_two_tasks.rs | 8 +- examples/rp23/src/bin/button.rs | 8 +- examples/rp23/src/bin/debounce.rs | 8 +- examples/rp23/src/bin/flash.rs | 8 +- examples/rp23/src/bin/gpio_async.rs | 8 +- examples/rp23/src/bin/gpout.rs | 8 +- examples/rp23/src/bin/i2c_async.rs | 8 +- examples/rp23/src/bin/i2c_async_embassy.rs | 8 +- examples/rp23/src/bin/i2c_blocking.rs | 8 +- examples/rp23/src/bin/i2c_slave.rs | 8 +- examples/rp23/src/bin/interrupt.rs | 8 +- examples/rp23/src/bin/multicore.rs | 8 +- examples/rp23/src/bin/multiprio.rs | 8 +- examples/rp23/src/bin/pio_async.rs | 8 +- examples/rp23/src/bin/pio_dma.rs | 8 +- examples/rp23/src/bin/pio_hd44780.rs | 8 +- examples/rp23/src/bin/pio_i2s.rs | 8 +- examples/rp23/src/bin/pio_pwm.rs | 8 +- examples/rp23/src/bin/pio_rotary_encoder.rs | 8 +- examples/rp23/src/bin/pio_servo.rs | 8 +- examples/rp23/src/bin/pio_stepper.rs | 8 +- examples/rp23/src/bin/pio_ws2812.rs | 8 +- examples/rp23/src/bin/pwm.rs | 8 +- examples/rp23/src/bin/pwm_input.rs | 8 +- examples/rp23/src/bin/rosc.rs | 8 +- examples/rp23/src/bin/shared_bus.rs | 8 +- examples/rp23/src/bin/sharing.rs | 8 +- examples/rp23/src/bin/spi.rs | 8 +- examples/rp23/src/bin/spi_async.rs | 8 +- examples/rp23/src/bin/spi_display.rs | 8 +- examples/rp23/src/bin/spi_sdmmc.rs | 8 +- examples/rp23/src/bin/uart.rs | 8 +- examples/rp23/src/bin/uart_buffered_split.rs | 8 +- examples/rp23/src/bin/uart_r503.rs | 8 +- examples/rp23/src/bin/uart_unidir.rs | 8 +- examples/rp23/src/bin/usb_webusb.rs | 8 +- examples/rp23/src/bin/watchdog.rs | 8 +- examples/rp23/src/bin/zerocopy.rs | 8 +- 50 files changed, 178 insertions(+), 750 deletions(-) delete mode 100644 embassy-rp/src/binary_info/consts.rs delete mode 100644 embassy-rp/src/binary_info/macros.rs delete mode 100644 embassy-rp/src/binary_info/mod.rs delete mode 100644 embassy-rp/src/binary_info/types.rs diff --git a/ci.sh b/ci.sh index da842577d..70fe4f5d8 100755 --- a/ci.sh +++ b/ci.sh @@ -88,6 +88,7 @@ cargo batch \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index d0612957f..29a8a3c53 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -105,7 +105,7 @@ _test = [] ## ## Takes up a little flash space, but picotool can then report the name of your ## program and other details. -binary-info = [ "rt" ] +binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] embassy-sync = { version = "0.6.0", path = "../embassy-sync" } @@ -143,6 +143,7 @@ pio = {version= "0.2.1" } rp2040-boot2 = "0.3" document-features = "0.2.7" sha2-const-stable = "0.1" +rp-binary-info = { version = "0.1.0", optional = true } [dev-dependencies] embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } diff --git a/embassy-rp/src/binary_info/consts.rs b/embassy-rp/src/binary_info/consts.rs deleted file mode 100644 index d5fcd0d75..000000000 --- a/embassy-rp/src/binary_info/consts.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Constants for binary info - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -/// All Raspberry Pi specified IDs have this tag. -/// -/// You can create your own for custom fields. -pub const TAG_RASPBERRY_PI: u16 = super::make_tag(b"RP"); - -/// Used to note the program name - use with StringEntry -pub const ID_RP_PROGRAM_NAME: u32 = 0x02031c86; -/// Used to note the program version - use with StringEntry -pub const ID_RP_PROGRAM_VERSION_STRING: u32 = 0x11a9bc3a; -/// Used to note the program build date - use with StringEntry -pub const ID_RP_PROGRAM_BUILD_DATE_STRING: u32 = 0x9da22254; -/// Used to note the size of the binary - use with IntegerEntry -pub const ID_RP_BINARY_END: u32 = 0x68f465de; -/// Used to note a URL for the program - use with StringEntry -pub const ID_RP_PROGRAM_URL: u32 = 0x1856239a; -/// Used to note a description of the program - use with StringEntry -pub const ID_RP_PROGRAM_DESCRIPTION: u32 = 0xb6a07c19; -/// Used to note some feature of the program - use with StringEntry -pub const ID_RP_PROGRAM_FEATURE: u32 = 0xa1f4b453; -/// Used to note some whether this was a Debug or Release build - use with StringEntry -pub const ID_RP_PROGRAM_BUILD_ATTRIBUTE: u32 = 0x4275f0d3; -/// Used to note the Pico SDK version used - use with StringEntry -pub const ID_RP_SDK_VERSION: u32 = 0x5360b3ab; -/// Used to note which board this program targets - use with StringEntry -pub const ID_RP_PICO_BOARD: u32 = 0xb63cffbb; -/// Used to note which `boot2` image this program uses - use with StringEntry -pub const ID_RP_BOOT2_NAME: u32 = 0x7f8882e1; - -// End of file diff --git a/embassy-rp/src/binary_info/macros.rs b/embassy-rp/src/binary_info/macros.rs deleted file mode 100644 index faf6148c8..000000000 --- a/embassy-rp/src/binary_info/macros.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! Handy macros for making Binary Info entries - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -/// Generate a static item containing the given environment variable, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_env { - ($tag:expr, $id:expr, $env_var_name:expr) => { - $crate::binary_info_str!($tag, $id, { - let value = concat!(env!($env_var_name), "\0"); - // # Safety - // - // We used `concat!` to null-terminate on the line above. - let value_cstr = unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(value.as_bytes()) }; - value_cstr - }) - }; -} - -/// Generate a static item containing the given string, and return its -/// [`EntryAddr`](super::EntryAddr). -/// -/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always -/// null-terminated). -#[macro_export] -macro_rules! binary_info_str { - ($tag:expr, $id:expr, $str:expr) => {{ - static ENTRY: $crate::binary_info::StringEntry = $crate::binary_info::StringEntry::new($tag, $id, $str); - ENTRY.addr() - }}; -} - -/// Generate a static item containing the given string, and return its -/// [`EntryAddr`](super::EntryAddr). -/// -/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always -/// null-terminated). -#[macro_export] -macro_rules! binary_info_int { - ($tag:expr, $id:expr, $int:expr) => {{ - static ENTRY: $crate::binary_info::IntegerEntry = $crate::binary_info::IntegerEntry::new($tag, $id, $int); - ENTRY.addr() - }}; -} - -/// Generate a static item containing the program name, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_name { - ($name:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_NAME, - $name - ) - }; -} - -/// Generate a static item containing the `CARGO_BIN_NAME` as the program name, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_cargo_bin_name { - () => { - $crate::binary_info_env!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_NAME, - "CARGO_BIN_NAME" - ) - }; -} - -/// Generate a static item containing the program version, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_version { - ($version:expr) => {{ - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_VERSION, - $version - ) - }}; -} - -/// Generate a static item containing the `CARGO_PKG_VERSION` as the program -/// version, and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_cargo_version { - () => { - $crate::binary_info_env!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_VERSION_STRING, - "CARGO_PKG_VERSION" - ) - }; -} - -/// Generate a static item containing the program URL, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_url { - ($url:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_URL, - $url - ) - }; -} - -/// Generate a static item containing the `CARGO_PKG_HOMEPAGE` as the program URL, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_cargo_homepage_url { - () => { - $crate::binary_info_env!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_URL, - "CARGO_PKG_HOMEPAGE" - ) - }; -} - -/// Generate a static item containing the program description, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_description { - ($description:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_DESCRIPTION, - $description - ) - }; -} - -/// Generate a static item containing whether this is a debug or a release -/// build, and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_build_attribute { - () => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, - { - if cfg!(debug_assertions) { - c"debug" - } else { - c"release" - } - } - ) - }; -} - -/// Generate a static item containing the specific board this program runs on, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_pico_board { - ($board:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PICO_BOARD, - $board - ) - }; -} - -// End of file diff --git a/embassy-rp/src/binary_info/mod.rs b/embassy-rp/src/binary_info/mod.rs deleted file mode 100644 index ea475086b..000000000 --- a/embassy-rp/src/binary_info/mod.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Code and types for creating Picotool compatible "Binary Info" metadata -//! -//! Add something like this to your program, and compile with the "binary-info" -//! and "rt" features: -//! -//! ``` -//! #[link_section = ".bi_entries"] -//! #[used] -//! pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 3] = [ -//! embassy_rp::binary_info_rp_program_name!(c"Program Name Here"), -//! embassy_rp::binary_info_rp_cargo_version!(), -//! embassy_rp::binary_info_int!(embassy_rp::binary_info::make_tag(b"JP"), 0x0000_0001, 0x12345678), -//! ]; -//! ``` - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -pub mod consts; - -mod types; -pub use types::*; - -#[macro_use] -mod macros; - -extern "C" { - /// The linker script sets this symbol to have the address of the first - /// entry in the `.bi_entries` section. - static __bi_entries_start: EntryAddr; - /// The linker script sets this symbol to have the address just past the - /// last entry in the `.bi_entries` section. - static __bi_entries_end: EntryAddr; - /// The linker script sets this symbol to have the address of the first - /// entry in the `.data` section. - static __sdata: u32; - /// The linker script sets this symbol to have the address just past the - /// first entry in the `.data` section. - static __edata: u32; - /// The linker script sets this symbol to have the address of the - /// initialisation data for the first entry in the `.data` section (i.e. a - /// flash address, not a RAM address). - static __sidata: u32; -} - -/// Picotool can find this block in our ELF file and report interesting -/// metadata. -/// -/// The data here tells picotool the start and end flash addresses of our -/// metadata. -#[cfg(feature = "binary-info")] -#[link_section = ".start_block"] -#[used] -pub static PICOTOOL_HEADER: Header = unsafe { - Header::new( - core::ptr::addr_of!(__bi_entries_start), - core::ptr::addr_of!(__bi_entries_end), - &MAPPING_TABLE, - ) -}; - -/// This tells picotool how to convert RAM addresses back into Flash addresses -#[cfg(feature = "binary-info")] -pub static MAPPING_TABLE: [MappingTableEntry; 2] = [ - // This is the entry for .data - MappingTableEntry { - source_addr_start: unsafe { core::ptr::addr_of!(__sidata) }, - dest_addr_start: unsafe { core::ptr::addr_of!(__sdata) }, - dest_addr_end: unsafe { core::ptr::addr_of!(__edata) }, - }, - // This is the terminating marker - MappingTableEntry::null(), -]; - -/// Create a 'Binary Info' entry containing the program name -/// -/// This is well-known to picotool, and will be displayed if you run `picotool info`. -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * ID: [`consts::ID_RP_PROGRAM_NAME`] -pub const fn rp_program_name(name: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_NAME, name) -} - -/// Create a 'Binary Info' entry containing the program version. -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_VERSION_STRING`] -pub const fn rp_program_version(name: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_VERSION_STRING, name) -} - -/// Create a 'Binary Info' entry with a URL -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_URL`] -pub const fn rp_program_url(url: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_URL, url) -} - -/// Create a 'Binary Info' with the program build date -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_BUILD_DATE_STRING`] -pub const fn rp_program_build_date_string(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_DATE_STRING, value) -} - -/// Create a 'Binary Info' with the size of the binary -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_BINARY_END`] -pub const fn rp_binary_end(value: u32) -> IntegerEntry { - IntegerEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BINARY_END, value) -} - -/// Create a 'Binary Info' with a description of the program -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_DESCRIPTION`] -pub const fn rp_program_description(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_DESCRIPTION, value) -} - -/// Create a 'Binary Info' with some feature of the program -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_FEATURE`] -pub const fn rp_program_feature(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_FEATURE, value) -} - -/// Create a 'Binary Info' with some whether this was a Debug or Release build -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE`] -pub const fn rp_program_build_attribute(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, value) -} - -/// Create a 'Binary Info' with the Pico SDK version used -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_SDK_VERSION`] -pub const fn rp_sdk_version(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_SDK_VERSION, value) -} - -/// Create a 'Binary Info' with which board this program targets -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PICO_BOARD`] -pub const fn rp_pico_board(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PICO_BOARD, value) -} - -/// Create a 'Binary Info' with which `boot2` image this program uses -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_BOOT2_NAME`] -pub const fn rp_boot2_name(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BOOT2_NAME, value) -} - -/// Create a tag from two ASCII letters. -/// -/// ``` -/// let tag = embassy_rp::binary_info::make_tag(b"RP"); -/// assert_eq!(tag, 0x5052); -/// ``` -pub const fn make_tag(c: &[u8; 2]) -> u16 { - u16::from_le_bytes(*c) -} - -// End of file diff --git a/embassy-rp/src/binary_info/types.rs b/embassy-rp/src/binary_info/types.rs deleted file mode 100644 index 6aec1902e..000000000 --- a/embassy-rp/src/binary_info/types.rs +++ /dev/null @@ -1,195 +0,0 @@ -//! Types for the Binary Info system - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -/// This is the 'Binary Info' header block that `picotool` looks for in your UF2 -/// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your -/// program. -/// -/// It should be placed in the first 4096 bytes of flash, so use your `memory.x` -/// to insert a section between `.text` and `.vector_table` and put a static -/// value of this type in that section. -#[repr(C)] -pub struct Header { - /// Must be equal to Picotool::MARKER_START - marker_start: u32, - /// The first in our table of pointers to Entries - entries_start: *const EntryAddr, - /// The last in our table of pointers to Entries - entries_end: *const EntryAddr, - /// The first entry in a null-terminated RAM/Flash mapping table - mapping_table: *const MappingTableEntry, - /// Must be equal to Picotool::MARKER_END - marker_end: u32, -} - -impl Header { - /// This is the `BINARY_INFO_MARKER_START` magic value from `picotool` - const MARKER_START: u32 = 0x7188ebf2; - /// This is the `BINARY_INFO_MARKER_END` magic value from `picotool` - const MARKER_END: u32 = 0xe71aa390; - - /// Create a new `picotool` compatible header. - /// - /// * `entries_start` - the first [`EntryAddr`] in the table - /// * `entries_end` - the last [`EntryAddr`] in the table - /// * `mapping_table` - the RAM/Flash address mapping table - pub const fn new( - entries_start: *const EntryAddr, - entries_end: *const EntryAddr, - mapping_table: &'static [MappingTableEntry], - ) -> Self { - let mapping_table = mapping_table.as_ptr(); - Self { - marker_start: Self::MARKER_START, - entries_start, - entries_end, - mapping_table, - marker_end: Self::MARKER_END, - } - } -} - -// We need this as rustc complains that is is unsafe to share `*const u32` -// pointers between threads. We only allow these to be created with static -// data, so this is OK. -unsafe impl Sync for Header {} - -/// This is a reference to an entry. It's like a `&dyn` ref to some type `T: -/// Entry`, except that the run-time type information is encoded into the -/// Entry itself in very specific way. -#[repr(transparent)] -pub struct EntryAddr(*const u32); - -// We need this as rustc complains that is is unsafe to share `*const u32` -// pointers between threads. We only allow these to be created with static -// data, so this is OK. -unsafe impl Sync for EntryAddr {} - -/// Allows us to tell picotool where values are in the UF2 given their run-time -/// address. -/// -/// The most obvious example is RAM variables, which must be found in the -/// `.data` section of the UF2. -#[repr(C)] -pub struct MappingTableEntry { - /// The start address in RAM (or wherever the address picotool finds will - /// point) - pub source_addr_start: *const u32, - /// The start address in flash (or whever the data actually lives in the - /// ELF) - pub dest_addr_start: *const u32, - /// The end address in flash - pub dest_addr_end: *const u32, -} - -impl MappingTableEntry { - /// Generate a null entry to mark the end of the list - pub const fn null() -> MappingTableEntry { - MappingTableEntry { - source_addr_start: core::ptr::null(), - dest_addr_start: core::ptr::null(), - dest_addr_end: core::ptr::null(), - } - } -} - -// We need this as rustc complains that is is unsafe to share `*const u32` -// pointers between threads. We only allow these to be created with static -// data, so this is OK. -unsafe impl Sync for MappingTableEntry {} - -/// This is the set of data types that `picotool` supports. -#[repr(u16)] -pub enum DataType { - /// Raw data - Raw = 1, - /// Data with a size - SizedData = 2, - /// A list of binary data - BinaryInfoListZeroTerminated = 3, - /// A BSON encoded blob - Bson = 4, - /// An Integer with an ID - IdAndInt = 5, - /// A string with an Id - IdAndString = 6, - /// A block device - BlockDevice = 7, - /// GPIO pins, with their function - PinsWithFunction = 8, - /// GPIO pins, with their name - PinsWithName = 9, - /// GPIO pins, with multiple names? - PinsWithNames = 10, -} - -/// All Entries start with this common header -#[repr(C)] -struct EntryCommon { - data_type: DataType, - tag: u16, -} - -/// An entry which contains both an ID (e.g. `ID_RP_PROGRAM_NAME`) and a pointer -/// to a null-terminated string. -#[repr(C)] -pub struct StringEntry { - header: EntryCommon, - id: u32, - value: *const core::ffi::c_char, -} - -impl StringEntry { - /// Create a new `StringEntry` - pub const fn new(tag: u16, id: u32, value: &'static core::ffi::CStr) -> StringEntry { - StringEntry { - header: EntryCommon { - data_type: DataType::IdAndString, - tag, - }, - id, - value: value.as_ptr(), - } - } - - /// Get this entry's address - pub const fn addr(&self) -> EntryAddr { - EntryAddr(self as *const Self as *const u32) - } -} - -// We need this as rustc complains that is is unsafe to share `*const -// core::ffi::c_char` pointers between threads. We only allow these to be -// created with static string slices, so it's OK. -unsafe impl Sync for StringEntry {} - -/// An entry which contains both an ID (e.g. `ID_RP_BINARY_END`) and an integer. -#[repr(C)] -pub struct IntegerEntry { - header: EntryCommon, - id: u32, - value: u32, -} - -impl IntegerEntry { - /// Create a new `StringEntry` - pub const fn new(tag: u16, id: u32, value: u32) -> IntegerEntry { - IntegerEntry { - header: EntryCommon { - data_type: DataType::IdAndInt, - tag, - }, - id, - value, - } - } - - /// Get this entry's address - pub const fn addr(&self) -> EntryAddr { - EntryAddr(self as *const Self as *const u32) - } -} - -// End of file diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 1fc397107..21f0771de 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -9,6 +9,9 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +#[cfg(feature = "binary-info")] +pub use rp_binary_info as binary_info; + #[cfg(feature = "critical-section-impl")] mod critical_section_impl; @@ -16,8 +19,6 @@ mod intrinsics; pub mod adc; #[cfg(feature = "_rp235x")] -pub mod binary_info; -#[cfg(feature = "_rp235x")] pub mod block; #[cfg(feature = "rp2040")] pub mod bootsel; diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs index 19872607e..d1f053d39 100644 --- a/examples/rp23/src/bin/adc.rs +++ b/examples/rp23/src/bin/adc.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs index d538ddaa2..5046e5530 100644 --- a/examples/rp23/src/bin/adc_dma.rs +++ b/examples/rp23/src/bin/adc_dma.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs index 923c13514..2f9783917 100644 --- a/examples/rp23/src/bin/assign_resources.rs +++ b/examples/rp23/src/bin/assign_resources.rs @@ -28,10 +28,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs index 02bdf9b3d..9e45679c8 100644 --- a/examples/rp23/src/bin/blinky.rs +++ b/examples/rp23/src/bin/blinky.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs index 4d7dc89fa..87fc58bbc 100644 --- a/examples/rp23/src/bin/blinky_two_channels.rs +++ b/examples/rp23/src/bin/blinky_two_channels.rs @@ -23,10 +23,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; enum LedState { diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs index 24b960242..40236c53b 100644 --- a/examples/rp23/src/bin/blinky_two_tasks.rs +++ b/examples/rp23/src/bin/blinky_two_tasks.rs @@ -23,10 +23,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type LedType = Mutex>>; diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs index 0a0559397..fb067a370 100644 --- a/examples/rp23/src/bin/button.rs +++ b/examples/rp23/src/bin/button.rs @@ -18,10 +18,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs index e82e71f61..e672521ec 100644 --- a/examples/rp23/src/bin/debounce.rs +++ b/examples/rp23/src/bin/debounce.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; pub struct Debouncer<'a> { diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 2917dda0b..811561f26 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; const ADDR_OFFSET: u32 = 0x100000; diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs index 1618f7c8b..ff12367bf 100644 --- a/examples/rp23/src/bin/gpio_async.rs +++ b/examples/rp23/src/bin/gpio_async.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; /// It requires an external signal to be manually triggered on PIN 16. For diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs index b15963f02..d2ee55197 100644 --- a/examples/rp23/src/bin/gpout.rs +++ b/examples/rp23/src/bin/gpout.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs index 2528fe1d2..c8d918b56 100644 --- a/examples/rp23/src/bin/i2c_async.rs +++ b/examples/rp23/src/bin/i2c_async.rs @@ -24,10 +24,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs index 461b1d171..cce0abcde 100644 --- a/examples/rp23/src/bin/i2c_async_embassy.rs +++ b/examples/rp23/src/bin/i2c_async_embassy.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; // Our anonymous hypotetical temperature sensor could be: diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs index 6d36d1890..85c33bf0d 100644 --- a/examples/rp23/src/bin/i2c_blocking.rs +++ b/examples/rp23/src/bin/i2c_blocking.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[allow(dead_code)] diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs index 1f3408cf3..fb5f3cda1 100644 --- a/examples/rp23/src/bin/i2c_slave.rs +++ b/examples/rp23/src/bin/i2c_slave.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs index 6184b1bd7..ee3d9bfe7 100644 --- a/examples/rp23/src/bin/interrupt.rs +++ b/examples/rp23/src/bin/interrupt.rs @@ -33,10 +33,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; static COUNTER: AtomicU32 = AtomicU32::new(0); diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs index 8649143e1..9ab43d7a5 100644 --- a/examples/rp23/src/bin/multicore.rs +++ b/examples/rp23/src/bin/multicore.rs @@ -24,10 +24,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; static mut CORE1_STACK: Stack<4096> = Stack::new(); diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs index 7590fb431..27cd3656e 100644 --- a/examples/rp23/src/bin/multiprio.rs +++ b/examples/rp23/src/bin/multiprio.rs @@ -74,10 +74,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::task] diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs index 005708bc2..231afc80e 100644 --- a/examples/rp23/src/bin/pio_async.rs +++ b/examples/rp23/src/bin/pio_async.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs index 48fd9123f..60fbcb83a 100644 --- a/examples/rp23/src/bin/pio_dma.rs +++ b/examples/rp23/src/bin/pio_dma.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs index fc658267d..92aa858f9 100644 --- a/examples/rp23/src/bin/pio_hd44780.rs +++ b/examples/rp23/src/bin/pio_hd44780.rs @@ -26,10 +26,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(pub struct Irqs { diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs index 5a3bde759..d6d2d0ade 100644 --- a/examples/rp23/src/bin/pio_i2s.rs +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -29,10 +29,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs index 7c5eefc45..587f91ac3 100644 --- a/examples/rp23/src/bin/pio_pwm.rs +++ b/examples/rp23/src/bin/pio_pwm.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; const REFRESH_INTERVAL: u64 = 20000; diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs index 287992a83..c147351e8 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs index 1dec86927..5e8714178 100644 --- a/examples/rp23/src/bin/pio_servo.rs +++ b/examples/rp23/src/bin/pio_servo.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs index 8b52dc37a..24785443b 100644 --- a/examples/rp23/src/bin/pio_stepper.rs +++ b/examples/rp23/src/bin/pio_stepper.rs @@ -25,10 +25,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs index 99d9cf7e6..00fe5e396 100644 --- a/examples/rp23/src/bin/pio_ws2812.rs +++ b/examples/rp23/src/bin/pio_ws2812.rs @@ -27,10 +27,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index 4cd3b3eb4..bfc2c6f67 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs index b75d04963..b65f2778b 100644 --- a/examples/rp23/src/bin/pwm_input.rs +++ b/examples/rp23/src/bin/pwm_input.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs index 28c778f51..f65b236b1 100644 --- a/examples/rp23/src/bin/rosc.rs +++ b/examples/rp23/src/bin/rosc.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs index 00e65f80d..b3fde13e3 100644 --- a/examples/rp23/src/bin/shared_bus.rs +++ b/examples/rp23/src/bin/shared_bus.rs @@ -27,10 +27,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type Spi1Bus = Mutex>; diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs index b5ef08147..4a3301cfd 100644 --- a/examples/rp23/src/bin/sharing.rs +++ b/examples/rp23/src/bin/sharing.rs @@ -40,10 +40,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type UartAsyncMutex = mutex::Mutex>; diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs index 98aa7622c..924873e60 100644 --- a/examples/rp23/src/bin/spi.rs +++ b/examples/rp23/src/bin/spi.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs index 71eaa5c05..4a74f991c 100644 --- a/examples/rp23/src/bin/spi_async.rs +++ b/examples/rp23/src/bin/spi_async.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs index 2441b1186..71dd84658 100644 --- a/examples/rp23/src/bin/spi_display.rs +++ b/examples/rp23/src/bin/spi_display.rs @@ -36,10 +36,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; use crate::my_display_interface::SPIDeviceInterface; diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs index d7af77a30..dabf41ab8 100644 --- a/examples/rp23/src/bin/spi_sdmmc.rs +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -25,10 +25,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; struct DummyTimesource(); diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs index ae00f36dc..0ffe0b293 100644 --- a/examples/rp23/src/bin/uart.rs +++ b/examples/rp23/src/bin/uart.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs index 2b14520d5..4e69a20c4 100644 --- a/examples/rp23/src/bin/uart_buffered_split.rs +++ b/examples/rp23/src/bin/uart_buffered_split.rs @@ -26,10 +26,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs index 39a17d305..5ac8839e3 100644 --- a/examples/rp23/src/bin/uart_r503.rs +++ b/examples/rp23/src/bin/uart_r503.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(pub struct Irqs { diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs index 38210a8d0..988e44a79 100644 --- a/examples/rp23/src/bin/uart_unidir.rs +++ b/examples/rp23/src/bin/uart_unidir.rs @@ -25,10 +25,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs index f4ecde30e..3ade2226b 100644 --- a/examples/rp23/src/bin/usb_webusb.rs +++ b/examples/rp23/src/bin/usb_webusb.rs @@ -38,10 +38,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs index 3ac457219..a901c1164 100644 --- a/examples/rp23/src/bin/watchdog.rs +++ b/examples/rp23/src/bin/watchdog.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs index d04e1bf2a..86fca6f12 100644 --- a/examples/rp23/src/bin/zerocopy.rs +++ b/examples/rp23/src/bin/zerocopy.rs @@ -27,10 +27,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type SampleBuffer = [u16; 512]; From a91de8d6b02e9ea69e9f2c62f11f590c64e771a2 Mon Sep 17 00:00:00 2001 From: Rafael Bachmann Date: Sun, 18 Aug 2024 10:36:04 +0200 Subject: [PATCH 107/210] Fix link to PriorityChannel Fix: #2899 --- embassy-sync/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/README.md b/embassy-sync/README.md index dec1fbc32..97a663d6d 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -5,7 +5,7 @@ An [Embassy](https://embassy.dev) project. Synchronization primitives and data structures with async support: - [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. -- [`PriorityChannel`](channel::priority::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. +- [`PriorityChannel`](channel::priority_channel::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. - [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. - [`Signal`](signal::Signal) - Signalling latest value to a single consumer. - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. From d8459685fd1e53a0fb57f44d950e0bc4f450c5f7 Mon Sep 17 00:00:00 2001 From: James Munns Date: Sun, 18 Aug 2024 10:58:07 +0200 Subject: [PATCH 108/210] Update faq.adoc - "code doesn't work in release mode" (#3267) Add debugging tips from chat --- docs/pages/faq.adoc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index 4ab04e2a1..8eb947b5e 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -361,4 +361,14 @@ Practically, there's not a LOT of difference either way - so go with what makes == splitting peripherals resources between tasks -There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example] \ No newline at end of file +There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example] + +== My code/driver works in debug mode, but not release mode (or with LTO) + +Issues like these while implementing drivers often fall into one of the following general causes, which are a good list of common errors to check for: + +1. Some kind of race condition - the faster code means you miss an interrupt or something +2. Some kind of UB, if you have unsafe code, or something like DMA with fences missing +3. Some kind of hardware errata, or some hardware misconfiguration like wrong clock speeds +4. Some issue with an interrupt handler, either enabling, disabling, or re-enabling of interrupts when necessary +5. Some kind of async issue, like not registering wakers fully before checking flags, or not registering or pending wakers at the right time From 1b0661ebb17fca93d11891a1c488005d3d644784 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Sun, 18 Aug 2024 21:06:13 +0200 Subject: [PATCH 109/210] [UCPD] Add support for non-SOP packets Allow capturing (and distinguishing) non-SOP packets as well. The default configuration will just configure SOP packets. For ease of use the default receive function signature is unchanged as for PD sinks (which is likely the common usage) just SOP is enough so no need to differentiate. --- embassy-stm32/src/ucpd.rs | 77 ++++++++++++++++++++++++++-- examples/stm32g4/src/bin/usb_c_pd.rs | 2 +- tests/stm32/src/bin/ucpd.rs | 4 +- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 40aea75cb..ee0a2c7c1 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -27,7 +27,7 @@ use crate::dma::{ChannelAndRequest, TransferOptions}; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; -pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; +pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; use crate::rcc::{self, RccPeripheral}; pub(crate) fn init( @@ -86,6 +86,34 @@ pub enum CcPull { Source3_0A, } +/// UCPD configuration +#[non_exhaustive] +#[derive(Copy, Clone, Debug)] +pub struct Config { + /// Receive SOP packets + pub sop: bool, + /// Receive SOP' packets + pub sop_prime: bool, + /// Receive SOP'' packets + pub sop_double_prime: bool, + /// Receive SOP'_Debug packets + pub sop_prime_debug: bool, + /// Receive SOP''_Debug packets + pub sop_double_prime_debug: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + sop: true, + sop_prime: false, + sop_double_prime: false, + sop_prime_debug: false, + sop_double_prime_debug: false, + } + } +} + /// UCPD driver. pub struct Ucpd<'d, T: Instance> { cc_phy: CcPhy<'d, T>, @@ -98,6 +126,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { _irq: impl interrupt::typelevel::Binding> + 'd, cc1: impl Peripheral

> + 'd, cc2: impl Peripheral

> + 'd, + config: Config, ) -> Self { into_ref!(cc1, cc2); cc1.set_as_analog(); @@ -129,9 +158,15 @@ impl<'d, T: Instance> Ucpd<'d, T> { // 1.75us * 17 = ~30us w.set_ifrgap(17 - 1); - // TODO: Currently only hard reset and SOP messages can be received. // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing). - w.set_rxordseten(0b1001); + let rxordset = (config.sop as u16) << 0 + | (config.sop_prime as u16) << 1 + | (config.sop_double_prime as u16) << 2 + // Hard reset + | 0x1 << 3 + | (config.sop_prime_debug as u16) << 4 + | (config.sop_double_prime_debug as u16) << 5; + w.set_rxordseten(rxordset); // Enable DMA w.set_txdmaen(true); @@ -288,6 +323,22 @@ impl<'d, T: Instance> CcPhy<'d, T> { } } +/// Receive SOP. +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Sop { + /// SOP + Sop, + /// SOP' + SopPrime, + /// SOP'' + SopDoublePrime, + /// SOP'_Debug + SopPrimeDebug, + /// SOP''_Debug + SopDoublePrimeDebug, +} + /// Receive Error. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -340,6 +391,13 @@ impl<'d, T: Instance> PdPhy<'d, T> { /// /// Returns the number of received bytes or an error. pub async fn receive(&mut self, buf: &mut [u8]) -> Result { + self.receive_with_sop(buf).await.map(|(_sop, size)| size) + } + + /// Receives SOP and a PD message into the provided buffer. + /// + /// Returns the start of packet type and number of received bytes or an error. + pub async fn receive_with_sop(&mut self, buf: &mut [u8]) -> Result<(Sop, usize), RxError> { let r = T::REGS; let dma = unsafe { @@ -388,7 +446,18 @@ impl<'d, T: Instance> PdPhy<'d, T> { } } - Ok(r.rx_payszr().read().rxpaysz().into()) + let sop = match r.rx_ordsetr().read().rxordset() { + Rxordset::SOP => Sop::Sop, + Rxordset::SOPPRIME => Sop::SopPrime, + Rxordset::SOPDOUBLEPRIME => Sop::SopDoublePrime, + Rxordset::SOPPRIMEDEBUG => Sop::SopPrimeDebug, + Rxordset::SOPDOUBLEPRIMEDEBUG => Sop::SopDoublePrimeDebug, + Rxordset::CABLERESET => return Err(RxError::HardReset), + // Extension headers are not supported + _ => unreachable!(), + }; + + Ok((sop, r.rx_payszr().read().rxpaysz().into())) } fn enable_rx_interrupt(enable: bool) { diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 7caea634f..2e87d3931 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4); + let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default()); ucpd.cc_phy().set_pull(CcPull::Sink); info!("Waiting for USB connection..."); diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs index a6d13b34a..bd7b35d6b 100644 --- a/tests/stm32/src/bin/ucpd.rs +++ b/tests/stm32/src/bin/ucpd.rs @@ -106,8 +106,8 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); // Wire between PD0 and PA8 - let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15); - let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2); + let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15, Default::default()); + let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2, Default::default()); join( source(ucpd1, p.DMA1_CH1, p.DMA1_CH2), From fcf9b3239e9c845d8f2b4eb5aea853f7ce377bf1 Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 19 Aug 2024 11:27:18 -0400 Subject: [PATCH 110/210] remove duplication --- embassy-stm32/src/usart/mod.rs | 77 +++++++--------------------------- 1 file changed, 16 insertions(+), 61 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0c5bbf491..4f2ff8b2a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker; use futures_util::future::{select, Either}; use crate::dma::ChannelAndRequest; -use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::gpio::{self, AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt as _; use crate::interrupt::{self, Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; @@ -224,6 +224,17 @@ pub enum HalfDuplexConfig { OpenDrainInternal, } +impl HalfDuplexConfig { + pub fn af_type(self) -> gpio::AfType { + match self { + HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), + HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), + } + } +} + /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1066,21 +1077,7 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!( - tx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(tx, half_duplex.af_type()), None, None, None, @@ -1117,21 +1114,7 @@ impl<'d> Uart<'d, Async> { peri, None, None, - new_pin!( - rx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(rx, half_duplex.af_type()), None, None, new_dma!(tx_dma), @@ -1247,21 +1230,7 @@ impl<'d> Uart<'d, Blocking> { Self::new_inner( peri, None, - new_pin!( - tx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(tx, half_duplex.af_type()), None, None, None, @@ -1295,21 +1264,7 @@ impl<'d> Uart<'d, Blocking> { peri, None, None, - new_pin!( - rx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(rx, half_duplex.af_type()), None, None, None, From bbc06035c136887aad91a1944efcc4c98401866f Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 19 Aug 2024 12:15:39 -0400 Subject: [PATCH 111/210] make half duplex fn private --- embassy-stm32/src/usart/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 4f2ff8b2a..89d92dda2 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -225,7 +225,7 @@ pub enum HalfDuplexConfig { } impl HalfDuplexConfig { - pub fn af_type(self) -> gpio::AfType { + fn af_type(self) -> gpio::AfType { match self { HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), From aff66b9695a70222b20c19585f04df2ecbabccb1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 21 Jun 2024 20:17:39 +0200 Subject: [PATCH 112/210] nrf: add try_write to BufferedUarte. --- embassy-nrf/src/buffered_uarte.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 159b4db8f..6d39597c6 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -358,6 +358,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { self.tx.write(buf).await } + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + self.tx.try_write(buf) + } + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. pub async fn flush(&mut self) -> Result<(), Error> { self.tx.flush().await @@ -482,6 +487,29 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { .await } + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + //trace!("poll_write: {:?}", buf.len()); + let s = U::buffered_state(); + let mut tx = unsafe { s.tx_buf.writer() }; + + let tx_buf = tx.push_slice(); + if tx_buf.is_empty() { + return Ok(0); + } + + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + tx.push_done(n); + + //trace!("poll_write: queued {:?}", n); + + compiler_fence(Ordering::SeqCst); + U::Interrupt::pend(); + + Ok(n) + } + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. pub async fn flush(&mut self) -> Result<(), Error> { poll_fn(move |cx| { From 160e1c38ceab0ae8876c2bf5f12438edd4d9b018 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 21 Jun 2024 20:19:54 +0200 Subject: [PATCH 113/210] Add embassy-net-nrf91. --- embassy-net-nrf91/Cargo.toml | 37 + embassy-net-nrf91/README.md | 9 + embassy-net-nrf91/src/fmt.rs | 274 ++++++ embassy-net-nrf91/src/lib.rs | 970 +++++++++++++++++++ examples/nrf9160/.cargo/config.toml | 3 +- examples/nrf9160/Cargo.toml | 5 + examples/nrf9160/memory.x | 8 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 250 +++++ 8 files changed, 1553 insertions(+), 3 deletions(-) create mode 100644 embassy-net-nrf91/Cargo.toml create mode 100644 embassy-net-nrf91/README.md create mode 100644 embassy-net-nrf91/src/fmt.rs create mode 100644 embassy-net-nrf91/src/lib.rs create mode 100644 examples/nrf9160/src/bin/modem_tcp_client.rs diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml new file mode 100644 index 000000000..2156346a4 --- /dev/null +++ b/embassy-net-nrf91/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "embassy-net-nrf91" +version = "0.1.0" +edition = "2021" +description = "embassy-net driver for Nordic nRF91-series cellular modems" +keywords = ["embedded", "nrf91", "embassy-net", "cellular"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-nrf91" + +[features] +defmt = [ "dep:defmt", "heapless/defmt-03" ] +log = [ "dep:log" ] + +[dependencies] +defmt = { version = "0.3", optional = true } +log = { version = "0.4.14", optional = true } + +nrf9160-pac = { version = "0.12.0" } + +embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-sync = { version = "0.6.0", path = "../embassy-sync"} +embassy-futures = { version = "0.1.0", path = "../embassy-futures"} +embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} + +heapless = "0.8" +embedded-io = "0.6.1" + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-nrf91-v$VERSION/embassy-net-nrf91/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-nrf91/src/" +target = "thumbv7em-none-eabi" +features = ["defmt"] + +[package.metadata.docs.rs] +features = ["defmt"] diff --git a/embassy-net-nrf91/README.md b/embassy-net-nrf91/README.md new file mode 100644 index 000000000..30da71787 --- /dev/null +++ b/embassy-net-nrf91/README.md @@ -0,0 +1,9 @@ +# nRF91 `embassy-net` integration + +[`embassy-net`](https://crates.io/crates/embassy-net) driver for Nordic nRF91-series cellular modems. + +See the [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160) directory for usage examples with the nRF9160. + +## Interoperability + +This crate can run on any executor. diff --git a/embassy-net-nrf91/src/fmt.rs b/embassy-net-nrf91/src/fmt.rs new file mode 100644 index 000000000..35b929fde --- /dev/null +++ b/embassy-net-nrf91/src/fmt.rs @@ -0,0 +1,274 @@ +#![macro_use] +#![allow(unused)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +#[collapse_debuginfo(yes)] +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[cfg(not(feature = "defmt"))] +#[collapse_debuginfo(yes)] +macro_rules! unreachable { + ($($x:tt)*) => { + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +#[collapse_debuginfo(yes)] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs new file mode 100644 index 000000000..62ade6dd3 --- /dev/null +++ b/embassy-net-nrf91/src/lib.rs @@ -0,0 +1,970 @@ +#![no_std] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] + +// must be first +mod fmt; + +use core::cell::RefCell; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::mem::{self, MaybeUninit}; +use core::ptr::{self, addr_of, addr_of_mut, copy_nonoverlapping}; +use core::slice; +use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::task::{Poll, Waker}; + +use embassy_net_driver_channel as ch; +use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; +use heapless::Vec; +use nrf9160_pac as pac; +use pac::NVIC; + +const RX_SIZE: usize = 8 * 1024; +const TRACE_SIZE: usize = 16 * 1024; +const MTU: usize = 1500; + +/// Network driver. +/// +/// This is the type you have to pass to `embassy-net` when creating the network stack. +pub type NetDriver<'a> = ch::Device<'a, MTU>; + +static WAKER: AtomicWaker = AtomicWaker::new(); + +/// Call this function on IPC IRQ +pub fn on_ipc_irq() { + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + + trace!("irq"); + + ipc.inten.write(|w| w); + WAKER.wake(); +} + +struct Allocator<'a> { + start: *mut u8, + end: *mut u8, + _phantom: PhantomData<&'a mut u8>, +} + +impl<'a> Allocator<'a> { + fn alloc_bytes(&mut self, size: usize) -> &'a mut [MaybeUninit] { + // safety: both pointers come from the same allocation. + let available_size = unsafe { self.end.offset_from(self.start) } as usize; + if size > available_size { + panic!("out of memory") + } + + // safety: we've checked above this doesn't go out of bounds. + let p = self.start; + self.start = unsafe { p.add(size) }; + + // safety: we've checked the pointer is in-bounds. + unsafe { slice::from_raw_parts_mut(p as *mut _, size) } + } + + fn alloc(&mut self) -> &'a mut MaybeUninit { + let align = mem::align_of::(); + let size = mem::size_of::(); + + let align_size = match (self.start as usize) % align { + 0 => 0, + n => align - n, + }; + + // safety: both pointers come from the same allocation. + let available_size = unsafe { self.end.offset_from(self.start) } as usize; + if align_size + size > available_size { + panic!("out of memory") + } + + // safety: we've checked above this doesn't go out of bounds. + let p = unsafe { self.start.add(align_size) }; + self.start = unsafe { p.add(size) }; + + // safety: we've checked the pointer is aligned and in-bounds. + unsafe { &mut *(p as *mut _) } + } +} + +/// Create a new nRF91 embassy-net driver. +pub async fn new<'a, TW: embedded_io::Write>( + state: &'a mut State, + shmem: &'a mut [MaybeUninit], + trace_writer: TW, +) -> (NetDriver<'a>, Control<'a>, Runner<'a, TW>) { + let shmem_len = shmem.len(); + let shmem_ptr = shmem.as_mut_ptr() as *mut u8; + + const SPU_REGION_SIZE: usize = 8192; // 8kb + assert!(shmem_len != 0); + assert!( + shmem_len % SPU_REGION_SIZE == 0, + "shmem length must be a multiple of 8kb" + ); + assert!( + (shmem_ptr as usize) % SPU_REGION_SIZE == 0, + "shmem length must be a multiple of 8kb" + ); + assert!( + (shmem_ptr as usize + shmem_len) < 0x2002_0000, + "shmem must be in the lower 128kb of RAM" + ); + + let spu = unsafe { &*pac::SPU_S::ptr() }; + debug!("Setting IPC RAM as nonsecure..."); + let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE; + let region_end = region_start + shmem_len / SPU_REGION_SIZE; + for i in region_start..region_end { + spu.ramregion[i].perm.write(|w| { + w.execute().set_bit(); + w.write().set_bit(); + w.read().set_bit(); + w.secattr().clear_bit(); + w.lock().clear_bit(); + w + }) + } + + spu.periphid[42].perm.write(|w| w.secattr().non_secure()); + + let mut alloc = Allocator { + start: shmem_ptr, + end: unsafe { shmem_ptr.add(shmem_len) }, + _phantom: PhantomData, + }; + + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + let power = unsafe { &*pac::POWER_S::ptr() }; + + let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() }); + let rx = alloc.alloc_bytes(RX_SIZE); + let trace = alloc.alloc_bytes(TRACE_SIZE); + + cb.version = 0x00010000; + cb.rx_base = rx.as_mut_ptr() as _; + cb.rx_size = RX_SIZE; + cb.control_list_ptr = &mut cb.lists[0]; + cb.data_list_ptr = &mut cb.lists[1]; + cb.modem_info_ptr = &mut cb.modem_info; + cb.trace_ptr = &mut cb.trace; + cb.lists[0].len = LIST_LEN; + cb.lists[1].len = LIST_LEN; + cb.trace.base = trace.as_mut_ptr() as _; + cb.trace.size = TRACE_SIZE; + + ipc.gpmem[0].write(|w| unsafe { w.bits(cb as *mut _ as u32) }); + ipc.gpmem[1].write(|w| unsafe { w.bits(0) }); + + // connect task/event i to channel i + for i in 0..8 { + ipc.send_cnf[i].write(|w| unsafe { w.bits(1 << i) }); + ipc.receive_cnf[i].write(|w| unsafe { w.bits(1 << i) }); + } + + compiler_fence(Ordering::SeqCst); + + // POWER.LTEMODEM.STARTN = 0 + // The reg is missing in the PAC?? + let startn = unsafe { (power as *const _ as *mut u32).add(0x610 / 4) }; + unsafe { startn.write_volatile(0) } + + unsafe { NVIC::unmask(pac::Interrupt::IPC) }; + + let state_inner = &*state.inner.write(RefCell::new(StateInner { + init: false, + init_waker: WakerRegistration::new(), + cb, + requests: [const { None }; REQ_COUNT], + next_req_serial: 0x12345678, + + rx_control_list: ptr::null_mut(), + rx_data_list: ptr::null_mut(), + rx_seq_no: 0, + rx_check: PointerChecker { + start: rx.as_mut_ptr() as *mut u8, + end: (rx.as_mut_ptr() as *mut u8).wrapping_add(RX_SIZE), + }, + + tx_seq_no: 0, + tx_buf_used: [false; TX_BUF_COUNT], + + trace_chans: Vec::new(), + trace_check: PointerChecker { + start: trace.as_mut_ptr() as *mut u8, + end: (trace.as_mut_ptr() as *mut u8).wrapping_add(TRACE_SIZE), + }, + })); + + let control = Control { state: state_inner }; + + let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ip); + let state_ch = ch_runner.state_runner(); + state_ch.set_link_state(ch::driver::LinkState::Up); + + let runner = Runner { + ch: ch_runner, + state: state_inner, + trace_writer, + }; + + (device, control, runner) +} + +/// Shared state for the drivver. +pub struct State { + ch: ch::State, + inner: MaybeUninit>, +} + +impl State { + /// Create a new State. + pub const fn new() -> Self { + Self { + ch: ch::State::new(), + inner: MaybeUninit::uninit(), + } + } +} + +const TX_BUF_COUNT: usize = 4; +const TX_BUF_SIZE: usize = 1024; + +struct TraceChannelInfo { + ptr: *mut TraceChannel, + start: *mut u8, + end: *mut u8, +} + +const REQ_COUNT: usize = 4; + +struct PendingRequest { + req_serial: u32, + resp_msg: *mut Message, + waker: Waker, +} + +struct StateInner { + init: bool, + init_waker: WakerRegistration, + + cb: *mut ControlBlock, + requests: [Option; REQ_COUNT], + next_req_serial: u32, + + rx_control_list: *mut List, + rx_data_list: *mut List, + rx_seq_no: u16, + rx_check: PointerChecker, + + tx_seq_no: u16, + tx_buf_used: [bool; TX_BUF_COUNT], + + trace_chans: Vec, + trace_check: PointerChecker, +} + +impl StateInner { + fn poll(&mut self, trace_writer: &mut impl embedded_io::Write, ch: &mut ch::Runner) { + trace!("poll!"); + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + + if ipc.events_receive[0].read().bits() != 0 { + ipc.events_receive[0].reset(); + trace!("ipc 0"); + } + + if ipc.events_receive[2].read().bits() != 0 { + ipc.events_receive[2].reset(); + trace!("ipc 2"); + + if !self.init { + let desc = unsafe { addr_of!((*self.cb).modem_info).read_volatile() }; + assert_eq!(desc.version, 1); + + self.rx_check.check_mut(desc.control_list_ptr); + self.rx_check.check_mut(desc.data_list_ptr); + + self.rx_control_list = desc.control_list_ptr; + self.rx_data_list = desc.data_list_ptr; + let rx_control_len = unsafe { addr_of!((*self.rx_control_list).len).read_volatile() }; + let rx_data_len = unsafe { addr_of!((*self.rx_data_list).len).read_volatile() }; + assert_eq!(rx_control_len, LIST_LEN); + assert_eq!(rx_data_len, LIST_LEN); + self.init = true; + + debug!("IPC initialized OK!"); + self.init_waker.wake(); + } + } + + if ipc.events_receive[4].read().bits() != 0 { + ipc.events_receive[4].reset(); + trace!("ipc 4"); + + loop { + let list = unsafe { &mut *self.rx_control_list }; + let control_work = self.process(list, true, ch); + let list = unsafe { &mut *self.rx_data_list }; + let data_work = self.process(list, false, ch); + if !control_work && !data_work { + break; + } + } + } + + if ipc.events_receive[6].read().bits() != 0 { + ipc.events_receive[6].reset(); + trace!("ipc 6"); + } + + if ipc.events_receive[7].read().bits() != 0 { + ipc.events_receive[7].reset(); + trace!("ipc 7: trace"); + + let msg = unsafe { addr_of!((*self.cb).trace.rx_state).read_volatile() }; + if msg != 0 { + trace!("trace msg {}", msg); + match msg { + 0 => unreachable!(), + 1 => { + let ctx = unsafe { addr_of!((*self.cb).trace.rx_ptr).read_volatile() } as *mut TraceContext; + debug!("trace init: {:?}", ctx); + self.trace_check.check(ctx); + let chans = unsafe { addr_of!((*ctx).chans).read_volatile() }; + for chan_ptr in chans { + let chan = self.trace_check.check_read(chan_ptr); + self.trace_check.check(chan.start); + self.trace_check.check(chan.end); + assert!(chan.start < chan.end); + self.trace_chans + .push(TraceChannelInfo { + ptr: chan_ptr, + start: chan.start, + end: chan.end, + }) + .map_err(|_| ()) + .unwrap() + } + } + 2 => { + for chan_info in &self.trace_chans { + let read_ptr = unsafe { addr_of!((*chan_info.ptr).read_ptr).read_volatile() }; + let write_ptr = unsafe { addr_of!((*chan_info.ptr).write_ptr).read_volatile() }; + assert!(read_ptr >= chan_info.start && read_ptr <= chan_info.end); + assert!(write_ptr >= chan_info.start && write_ptr <= chan_info.end); + if read_ptr != write_ptr { + let id = unsafe { addr_of!((*chan_info.ptr).id).read_volatile() }; + fence(Ordering::SeqCst); // synchronize volatile accesses with the slice access. + if read_ptr < write_ptr { + Self::handle_trace(trace_writer, id, unsafe { + slice::from_raw_parts(read_ptr, write_ptr.offset_from(read_ptr) as _) + }); + } else { + Self::handle_trace(trace_writer, id, unsafe { + slice::from_raw_parts(read_ptr, chan_info.end.offset_from(read_ptr) as _) + }); + Self::handle_trace(trace_writer, id, unsafe { + slice::from_raw_parts( + chan_info.start, + write_ptr.offset_from(chan_info.start) as _, + ) + }); + } + fence(Ordering::SeqCst); // synchronize volatile accesses with the slice access. + unsafe { addr_of_mut!((*chan_info.ptr).read_ptr).write_volatile(write_ptr) }; + } + } + } + _ => warn!("unknown trace msg {}", msg), + } + unsafe { addr_of_mut!((*self.cb).trace.rx_state).write_volatile(0) }; + } + } + + ipc.intenset.write(|w| { + w.receive0().set_bit(); + w.receive2().set_bit(); + w.receive4().set_bit(); + w.receive6().set_bit(); + w.receive7().set_bit(); + w + }); + } + + fn handle_trace(writer: &mut impl embedded_io::Write, id: u8, data: &[u8]) { + trace!("trace: {} {}", id, data.len()); + let mut header = [0u8; 5]; + header[0] = 0xEF; + header[1] = 0xBE; + header[2..4].copy_from_slice(&(data.len() as u16).to_le_bytes()); + header[4] = id; + writer.write_all(&header).unwrap(); + writer.write_all(data).unwrap(); + } + + fn process(&mut self, list: *mut List, is_control: bool, ch: &mut ch::Runner) -> bool { + let mut did_work = false; + for i in 0..LIST_LEN { + let item_ptr = unsafe { addr_of_mut!((*list).items[i]) }; + let preamble = unsafe { addr_of!((*item_ptr).state).read_volatile() }; + if preamble & 0xFF == 0x01 && preamble >> 16 == self.rx_seq_no as u32 { + let msg_ptr = unsafe { addr_of!((*item_ptr).message).read_volatile() }; + let msg = self.rx_check.check_read(msg_ptr); + + debug!("rx seq {} msg: {:?}", preamble >> 16, msg); + + if is_control { + self.handle_control(&msg); + } else { + self.handle_data(&msg, ch); + } + + unsafe { addr_of_mut!((*item_ptr).state).write_volatile(0x03) }; + self.rx_seq_no = self.rx_seq_no.wrapping_add(1); + + did_work = true; + } + } + did_work + } + + fn find_free_message(&mut self, ch: usize) -> Option { + for i in 0..LIST_LEN { + let preamble = unsafe { addr_of!((*self.cb).lists[ch].items[i].state).read_volatile() }; + if matches!(preamble & 0xFF, 0 | 3) { + trace!("using tx msg idx {}", i); + return Some(i); + } + } + return None; + } + + fn find_free_tx_buf(&mut self) -> Option { + for i in 0..TX_BUF_COUNT { + if !self.tx_buf_used[i] { + trace!("using tx buf idx {}", i); + return Some(i); + } + } + return None; + } + + fn send_message(&mut self, msg: &mut Message, data: &[u8]) { + if data.is_empty() { + msg.data = ptr::null_mut(); + msg.data_len = 0; + } else { + assert!(data.len() <= TX_BUF_SIZE); + let buf_idx = self.find_free_tx_buf().unwrap(); // TODO handle out of bufs + let buf = unsafe { addr_of_mut!((*self.cb).tx_bufs[buf_idx]) } as *mut u8; + unsafe { copy_nonoverlapping(data.as_ptr(), buf, data.len()) } + msg.data = buf; + msg.data_len = data.len(); + self.tx_buf_used[buf_idx] = true; + + fence(Ordering::SeqCst); // synchronize copy_nonoverlapping (non-volatile) with volatile writes below. + } + + // TODO free data buf if send_message_raw fails. + self.send_message_raw(msg); + } + + fn send_message_raw(&mut self, msg: &Message) { + let (ch, ipc_ch) = match msg.channel { + 1 => (0, 1), // control + 2 => (1, 3), // data + _ => unreachable!(), + }; + + // allocate a msg. + let idx = self.find_free_message(ch).unwrap(); // TODO handle list full + + debug!("tx seq {} msg: {:?}", self.tx_seq_no, msg); + + let msg_slot = unsafe { addr_of_mut!((*self.cb).msgs[ch][idx]) }; + unsafe { msg_slot.write_volatile(*msg) } + let list_item = unsafe { addr_of_mut!((*self.cb).lists[ch].items[idx]) }; + unsafe { addr_of_mut!((*list_item).message).write_volatile(msg_slot) } + unsafe { addr_of_mut!((*list_item).state).write_volatile((self.tx_seq_no as u32) << 16 | 0x01) } + self.tx_seq_no = self.tx_seq_no.wrapping_add(1); + + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) }); + } + + fn handle_control(&mut self, msg: &Message) { + match msg.id >> 16 { + 1 => debug!("control msg: modem ready"), + 2 => self.handle_control_free(msg.data), + _ => warn!("unknown control message id {:08x}", msg.id), + } + } + + fn handle_control_free(&mut self, ptr: *mut u8) { + let base = unsafe { addr_of!((*self.cb).tx_bufs) } as usize; + let ptr = ptr as usize; + + if ptr < base { + warn!("control free bad pointer {:08x}", ptr); + return; + } + + let diff = ptr - base; + let idx = diff / TX_BUF_SIZE; + + if idx >= TX_BUF_COUNT || idx * TX_BUF_SIZE != diff { + warn!("control free bad pointer {:08x}", ptr); + return; + } + + trace!("control free pointer {:08x} idx {}", ptr, idx); + if !self.tx_buf_used[idx] { + warn!( + "control free pointer {:08x} idx {}: buffer was already free??", + ptr, idx + ); + } + self.tx_buf_used[idx] = false; + } + + fn handle_data(&mut self, msg: &Message, ch: &mut ch::Runner) { + if !msg.data.is_null() { + self.rx_check.check_length(msg.data, msg.data_len); + } + + let freed = match msg.id & 0xFFFF { + // AT + 3 => { + match msg.id >> 16 { + // AT request ack + 2 => false, + // AT response + 3 => self.handle_resp(msg), + // AT notification + 4 => false, + x => { + warn!("received unknown AT kind {}", x); + false + } + } + } + // IP + 4 => { + match msg.id >> 28 { + // IP response + 8 => self.handle_resp(msg), + // IP notification + 9 => match (msg.id >> 16) & 0xFFF { + // IP receive notification + 1 => { + if let Some(buf) = ch.try_rx_buf() { + let mut len = msg.data_len; + if len > buf.len() { + warn!("truncating rx'd packet from {} to {} bytes", len, buf.len()); + len = buf.len(); + } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + unsafe { ptr::copy_nonoverlapping(msg.data, buf.as_mut_ptr(), len) } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + ch.rx_done(len); + } + false + } + _ => false, + }, + x => { + warn!("received unknown IP kind {}", x); + false + } + } + } + x => { + warn!("received unknown kind {}", x); + false + } + }; + + if !freed { + self.send_free(msg); + } + } + + fn handle_resp(&mut self, msg: &Message) -> bool { + let req_serial = u32::from_le_bytes(msg.param[0..4].try_into().unwrap()); + if req_serial == 0 { + return false; + } + + for optr in &mut self.requests { + if let Some(r) = optr { + if r.req_serial == req_serial { + let r = optr.take().unwrap(); + unsafe { r.resp_msg.write(*msg) } + r.waker.wake(); + *optr = None; + return true; + } + } + } + + warn!( + "resp with id {} serial {} doesn't match any pending req", + msg.id, req_serial + ); + false + } + + fn send_free(&mut self, msg: &Message) { + if msg.data.is_null() { + return; + } + + let mut free_msg: Message = unsafe { mem::zeroed() }; + free_msg.channel = 1; // control + free_msg.id = 0x20001; // free + free_msg.data = msg.data; + free_msg.data_len = msg.data_len; + + self.send_message_raw(&free_msg); + } +} + +struct PointerChecker { + start: *mut u8, + end: *mut u8, +} + +impl PointerChecker { + // check the pointer is in bounds in the arena, panic otherwise. + fn check_length(&self, ptr: *const u8, len: usize) { + assert!(ptr as usize >= self.start as usize); + let end_ptr = (ptr as usize).checked_add(len).unwrap(); + assert!(end_ptr <= self.end as usize); + } + + // check the pointer is in bounds in the arena, panic otherwise. + fn check(&self, ptr: *const T) { + assert!(ptr.is_aligned()); + self.check_length(ptr as *const u8, mem::size_of::()); + } + + // check the pointer is in bounds in the arena, panic otherwise. + fn check_read(&self, ptr: *const T) -> T { + self.check(ptr); + unsafe { ptr.read_volatile() } + } + + // check the pointer is in bounds in the arena, panic otherwise. + fn check_mut(&self, ptr: *mut T) { + self.check(ptr as *const T) + } +} + +/// Control handle for the driver. +/// +/// You can use this object to control the modem at runtime, such as running AT commands. +pub struct Control<'a> { + state: &'a RefCell, +} + +impl<'a> Control<'a> { + /// Wait for modem IPC to be initialized. + pub async fn wait_init(&self) { + poll_fn(|cx| { + let mut state = self.state.borrow_mut(); + if state.init { + return Poll::Ready(()); + } + state.init_waker.register(cx.waker()); + Poll::Pending + }) + .await + } + + async fn request(&self, msg: &mut Message, req_data: &[u8], resp_data: &mut [u8]) -> usize { + // get waker + let waker = poll_fn(|cx| Poll::Ready(cx.waker().clone())).await; + + // Send request + let mut state = self.state.borrow_mut(); + let mut req_serial = state.next_req_serial; + if msg.id & 0xFFFF == 3 { + // AT response seems to keep only the lower 8 bits. Others do keep the full 32 bits..?? + req_serial &= 0xFF; + } + + // increment next_req_serial, skip zero because we use it as an "ignore" value. + // We have to skip when the *lowest byte* is zero because AT responses. + state.next_req_serial = state.next_req_serial.wrapping_add(1); + if state.next_req_serial & 0xFF == 0 { + state.next_req_serial = state.next_req_serial.wrapping_add(1); + } + + msg.param[0..4].copy_from_slice(&req_serial.to_le_bytes()); + state.send_message(msg, req_data); + + // Setup the pending request state. + let (req_slot_idx, req_slot) = state + .requests + .iter_mut() + .enumerate() + .find(|(_, x)| x.is_none()) + .unwrap(); + msg.id = 0; // zero out id, so when it becomes nonzero we know the req is done. + let msg_ptr: *mut Message = msg; + *req_slot = Some(PendingRequest { + req_serial, + resp_msg: msg_ptr, + waker, + }); + + drop(state); // don't borrow state across awaits. + + // On cancel, unregister the request slot. + let _drop = OnDrop::new(|| { + // Remove request slot. + let mut state = self.state.borrow_mut(); + let slot = &mut state.requests[req_slot_idx]; + if let Some(s) = slot { + if s.req_serial == req_serial { + *slot = None; + } + } + + // If cancelation raced with actually receiving the response, + // we own the data, so we have to free it. + let msg = unsafe { &mut *msg_ptr }; + if msg.id != 0 { + state.send_free(msg); + } + }); + // Wait for response. + poll_fn(|_| { + // we have to use the raw pointer and not the original reference `msg` + // because that'd invalidate the raw ptr that's still stored in `req_slot`. + if unsafe { (*msg_ptr).id } != 0 { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + _drop.defuse(); + + if msg.data.is_null() { + // no response data. + return 0; + } + + // Copy response data out, if any. + // Pointer was validated in StateInner::handle_data(). + let mut len = msg.data_len; + if len > resp_data.len() { + warn!("truncating response data from {} to {}", len, resp_data.len()); + len = resp_data.len(); + } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + unsafe { ptr::copy_nonoverlapping(msg.data, resp_data.as_mut_ptr(), len) } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + self.state.borrow_mut().send_free(msg); + len + } + + /// Run an AT command. + /// + /// The response is written in `resp` and its length returned. + pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x0001_0003; // AT command + msg.param_len = 4; + + self.request(&mut msg, req, resp).await + } + + /// Open the raw socket used for sending/receiving IP packets. + /// + /// This must be done after `AT+CFUN=1` (?) + pub async fn open_raw_socket(&self) { + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x7001_0004; // open socket + msg.param_len = 20; + + let param = [ + 0xFF, 0xFF, 0xFF, 0xFF, // req_serial + 0xFF, 0xFF, 0xFF, 0xFF, // ??? + 0x05, 0x00, 0x00, 0x00, // family + 0x03, 0x00, 0x00, 0x00, // type + 0x00, 0x00, 0x00, 0x00, // protocol + ]; + msg.param[..param.len()].copy_from_slice(¶m); + + self.request(&mut msg, &[], &mut []).await; + + assert_eq!(msg.id, 0x80010004); + assert!(msg.param_len >= 12); + let status = u32::from_le_bytes(msg.param[8..12].try_into().unwrap()); + assert_eq!(status, 0); + assert_eq!(msg.param_len, 16); + let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap()); + debug!("got FD: {}", fd); + } +} + +/// Background runner for the driver. +pub struct Runner<'a, TW: embedded_io::Write> { + ch: ch::Runner<'a, MTU>, + state: &'a RefCell, + trace_writer: TW, +} + +impl<'a, TW: embedded_io::Write> Runner<'a, TW> { + /// Run the driver operation in the background. + /// + /// You must run this in a background task, concurrently with all network operations. + pub async fn run(mut self) -> ! { + poll_fn(|cx| { + WAKER.register(cx.waker()); + + let mut state = self.state.borrow_mut(); + state.poll(&mut self.trace_writer, &mut self.ch); + + if let Poll::Ready(buf) = self.ch.poll_tx_buf(cx) { + let fd = 128u32; // TODO unhardcode + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x7006_0004; // IP send + msg.param_len = 12; + msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); + state.send_message(&mut msg, buf); + self.ch.tx_done(); + } + + Poll::Pending + }) + .await + } +} + +const LIST_LEN: usize = 16; + +#[repr(C)] +struct ControlBlock { + version: u32, + rx_base: *mut u8, + rx_size: usize, + control_list_ptr: *mut List, + data_list_ptr: *mut List, + modem_info_ptr: *mut ModemInfo, + trace_ptr: *mut Trace, + unk: u32, + + modem_info: ModemInfo, + trace: Trace, + + // 0 = control, 1 = data + lists: [List; 2], + msgs: [[Message; LIST_LEN]; 2], + + tx_bufs: [[u8; TX_BUF_SIZE]; TX_BUF_COUNT], +} + +#[repr(C)] +struct ModemInfo { + version: u32, + control_list_ptr: *mut List, + data_list_ptr: *mut List, + padding: [u32; 5], +} + +#[repr(C)] +struct Trace { + size: usize, + base: *mut u8, + tx_state: u32, + tx_ptr: *mut u8, + rx_state: u32, + rx_ptr: *mut u8, + unk1: u32, + unk2: u32, +} + +const TRACE_CHANNEL_COUNT: usize = 3; + +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +struct TraceContext { + unk1: u32, + unk2: u32, + len: u32, + chans: [*mut TraceChannel; TRACE_CHANNEL_COUNT], +} + +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +struct TraceChannel { + id: u8, + unk1: u8, + unk2: u8, + unk3: u8, + write_ptr: *mut u8, + read_ptr: *mut u8, + start: *mut u8, + end: *mut u8, +} + +#[repr(C)] +struct List { + len: usize, + items: [ListItem; LIST_LEN], +} + +#[repr(C)] +struct ListItem { + /// top 16 bits: seqno + /// bottom 8 bits: + /// 0x01: sent + /// 0x02: held + /// 0x03: freed + state: u32, + message: *mut Message, +} + +#[repr(C)] +#[derive(defmt::Format, Clone, Copy)] +struct Message { + id: u32, + + /// 1 = control, 2 = data + channel: u8, + unk1: u8, + unk2: u8, + unk3: u8, + + data: *mut u8, + data_len: usize, + param_len: usize, + param: [u8; 44], +} + +struct OnDrop { + f: MaybeUninit, +} + +impl OnDrop { + pub fn new(f: F) -> Self { + Self { f: MaybeUninit::new(f) } + } + + pub fn defuse(self) { + mem::forget(self) + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } +} diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml index f64c63966..6072b8595 100644 --- a/examples/nrf9160/.cargo/config.toml +++ b/examples/nrf9160/.cargo/config.toml @@ -1,5 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs run --chip nRF9160_xxAA" +# runner = "probe-rs run --chip nRF9160_xxAA" +runner = [ "probe-rs", "run", "--chip=nRF9160_xxAA", "--always-print-stacktrace", "--log-format={t} {[{L}]%bold} {s} {{c} {ff}:{l:1}%dimmed}" ] [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index c30b54ebd..fc24e99d2 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -8,6 +8,8 @@ license = "MIT OR Apache-2.0" embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } defmt = "0.3" defmt-rtt = "0.4" @@ -15,6 +17,9 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } +static_cell = { version = "2" } +embedded-io = "0.6.1" +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } [profile.release] debug = 2 diff --git a/examples/nrf9160/memory.x b/examples/nrf9160/memory.x index 4c7d4ebf0..e33498773 100644 --- a/examples/nrf9160/memory.x +++ b/examples/nrf9160/memory.x @@ -1,5 +1,9 @@ MEMORY { - FLASH : ORIGIN = 0x00000000, LENGTH = 1024K - RAM : ORIGIN = 0x20018000, LENGTH = 160K + FLASH : ORIGIN = 0x00000000, LENGTH = 1024K + RAM : ORIGIN = 0x20010000, LENGTH = 192K + IPC : ORIGIN = 0x20000000, LENGTH = 64K } + +PROVIDE(__start_ipc = ORIGIN(IPC)); +PROVIDE(__end_ipc = ORIGIN(IPC) + LENGTH(IPC)); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs new file mode 100644 index 000000000..b1dac18a1 --- /dev/null +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -0,0 +1,250 @@ +#![no_std] +#![no_main] + +use core::mem::MaybeUninit; +use core::ptr::addr_of_mut; +use core::str::FromStr; +use core::{slice, str}; + +use defmt::{assert, *}; +use embassy_executor::Spawner; +use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net_nrf91::{Runner, State}; +use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; +use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; +use embassy_nrf::uarte::Baudrate; +use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; +use embassy_time::{Duration, Timer}; +use embedded_io_async::Write; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[interrupt] +fn IPC() { + embassy_net_nrf91::on_ipc_irq(); +} + +bind_interrupts!(struct Irqs { + UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler; +}); + +// embassy-net-nrf91 only supports blocking trace write for now. +// We don't want to block packet processing with slow uart writes, so +// we make an adapter that writes whatever fits in the buffer and drops +// data if it's full. +struct TraceWriter(BufferedUarteTx<'static, peripherals::SERIAL0>); + +impl embedded_io::ErrorType for TraceWriter { + type Error = core::convert::Infallible; +} + +impl embedded_io::Write for TraceWriter { + fn write(&mut self, buf: &[u8]) -> Result { + let _ = self.0.try_write(buf); + Ok(buf.len()) + } + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[embassy_executor::task] +async fn modem_task(runner: Runner<'static, TraceWriter>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack>) -> ! { + stack.run().await +} + +#[embassy_executor::task] +async fn blink_task(pin: AnyPin) { + let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); + loop { + led.set_high(); + Timer::after_millis(100).await; + led.set_low(); + Timer::after_millis(100).await; + } +} + +extern "C" { + static __start_ipc: u8; + static __end_ipc: u8; +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + info!("Hello World!"); + + unwrap!(spawner.spawn(blink_task(p.P0_02.degrade()))); + + let ipc_mem = unsafe { + let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit; + let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit; + let ipc_len = ipc_end.offset_from(ipc_start) as usize; + slice::from_raw_parts_mut(ipc_start, ipc_len) + }; + + static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; + let mut config = uarte::Config::default(); + config.baudrate = Baudrate::BAUD1M; + let trace_writer = TraceWriter(BufferedUarteTx::new( + //let trace_uart = BufferedUarteTx::new( + unsafe { peripherals::SERIAL0::steal() }, + Irqs, + unsafe { peripherals::P0_01::steal() }, + //unsafe { peripherals::P0_14::steal() }, + config, + unsafe { &mut *addr_of_mut!(TRACE_BUF) }, + )); + + static STATE: StaticCell = StaticCell::new(); + let (device, control, runner) = embassy_net_nrf91::new(STATE.init(State::new()), ipc_mem, trace_writer).await; + unwrap!(spawner.spawn(modem_task(runner))); + + let config = embassy_net::Config::default(); + + // Generate "random" seed. nRF91 has no RNG, TODO figure out something... + let seed = 123456; + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + static STACK: StaticCell>> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( + device, + config, + RESOURCES.init(StackResources::<2>::new()), + seed, + )); + + unwrap!(spawner.spawn(net_task(stack))); + + control.wait_init().await; + info!("INIT OK"); + + let mut buf = [0u8; 256]; + + let n = control.at_command(b"AT+CFUN?", &mut buf).await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + let n = control + .at_command(b"AT+CGDCONT=0,\"IP\",\"iot.nat.es\"", &mut buf) + .await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + let n = control + .at_command(b"AT+CGAUTH=0,1,\"orange\",\"orange\"", &mut buf) + .await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + let n = control.at_command(b"AT+CFUN=1", &mut buf).await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + info!("waiting for attach..."); + loop { + Timer::after_millis(500).await; + let n = control.at_command(b"AT+CGATT?", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGATT: "); + let res = split_field(&mut res); + info!("AT resp field: '{}'", unsafe { str::from_utf8_unchecked(res) }); + if res == b"1" { + break; + } + } + + let n = control.at_command(b"AT+CGPADDR=0", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGPADDR: 0,"); + let ip = split_field(&mut res); + let ip = Ipv4Address::from_str(unsafe { str::from_utf8_unchecked(ip) }).unwrap(); + info!("IP: '{}'", ip); + + info!("============== OPENING SOCKET"); + control.open_raw_socket().await; + + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(ip, 32), + gateway: None, + dns_servers: Default::default(), + })); + + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + loop { + let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("Connecting..."); + let host_addr = embassy_net::Ipv4Address::from_str("83.51.182.206").unwrap(); + if let Err(e) = socket.connect((host_addr, 8000)).await { + warn!("connect error: {:?}", e); + continue; + } + info!("Connected to {:?}", socket.remote_endpoint()); + + let msg = b"Hello world!\n"; + loop { + if let Err(e) = socket.write_all(msg).await { + warn!("write error: {:?}", e); + break; + } + info!("txd: {}", core::str::from_utf8(msg).unwrap()); + Timer::after_secs(1).await; + } + } +} + +fn is_whitespace(char: u8) -> bool { + match char { + b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +fn is_separator(char: u8) -> bool { + match char { + b',' | b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { + while !data.is_empty() && is_whitespace(data[0]) { + *data = &data[1..]; + } + + if data.is_empty() { + return &[]; + } + + if data[0] == b'"' { + let data2 = &data[1..]; + let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); + let field = &data2[..end]; + let mut rest = &data2[data2.len().min(end + 1)..]; + if rest.first() == Some(&b'\"') { + rest = &rest[1..]; + } + while !rest.is_empty() && is_separator(rest[0]) { + rest = &rest[1..]; + } + *data = rest; + field + } else { + let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); + let field = &data[0..end]; + let rest = &data[data.len().min(end + 1)..]; + *data = rest; + field + } +} + +fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { + assert!(data.len() >= prefix.len()); + assert!(&data[..prefix.len()] == prefix); + *data = &data[prefix.len()..]; +} From 11652ff5c7b139fd14ae270659181c65e59515dc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 25 Jun 2024 21:15:23 +0200 Subject: [PATCH 114/210] don't crash if tx buffers fill up. --- embassy-net-nrf91/src/lib.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 62ade6dd3..70ad176da 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![doc = include_str!("../README.md")] #![warn(missing_docs)] +#![deny(unused_must_use)] // must be first mod fmt; @@ -244,6 +245,10 @@ struct PendingRequest { waker: Waker, } +#[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +struct NoFreeBufs; + struct StateInner { init: bool, init_waker: WakerRegistration, @@ -450,13 +455,13 @@ impl StateInner { return None; } - fn send_message(&mut self, msg: &mut Message, data: &[u8]) { + fn send_message(&mut self, msg: &mut Message, data: &[u8]) -> Result<(), NoFreeBufs> { if data.is_empty() { msg.data = ptr::null_mut(); msg.data_len = 0; } else { assert!(data.len() <= TX_BUF_SIZE); - let buf_idx = self.find_free_tx_buf().unwrap(); // TODO handle out of bufs + let buf_idx = self.find_free_tx_buf().ok_or(NoFreeBufs)?; let buf = unsafe { addr_of_mut!((*self.cb).tx_bufs[buf_idx]) } as *mut u8; unsafe { copy_nonoverlapping(data.as_ptr(), buf, data.len()) } msg.data = buf; @@ -467,10 +472,10 @@ impl StateInner { } // TODO free data buf if send_message_raw fails. - self.send_message_raw(msg); + self.send_message_raw(msg) } - fn send_message_raw(&mut self, msg: &Message) { + fn send_message_raw(&mut self, msg: &Message) -> Result<(), NoFreeBufs> { let (ch, ipc_ch) = match msg.channel { 1 => (0, 1), // control 2 => (1, 3), // data @@ -478,7 +483,7 @@ impl StateInner { }; // allocate a msg. - let idx = self.find_free_message(ch).unwrap(); // TODO handle list full + let idx = self.find_free_message(ch).ok_or(NoFreeBufs)?; debug!("tx seq {} msg: {:?}", self.tx_seq_no, msg); @@ -491,6 +496,7 @@ impl StateInner { let ipc = unsafe { &*pac::IPC_NS::ptr() }; ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) }); + Ok(()) } fn handle_control(&mut self, msg: &Message) { @@ -626,7 +632,7 @@ impl StateInner { free_msg.data = msg.data; free_msg.data_len = msg.data_len; - self.send_message_raw(&free_msg); + unwrap!(self.send_message_raw(&free_msg)); } } @@ -702,7 +708,7 @@ impl<'a> Control<'a> { } msg.param[0..4].copy_from_slice(&req_serial.to_le_bytes()); - state.send_message(msg, req_data); + unwrap!(state.send_message(msg, req_data)); // Setup the pending request state. let (req_slot_idx, req_slot) = state @@ -838,7 +844,9 @@ impl<'a, TW: embedded_io::Write> Runner<'a, TW> { msg.id = 0x7006_0004; // IP send msg.param_len = 12; msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); - state.send_message(&mut msg, buf); + if let Err(e) = state.send_message(&mut msg, buf) { + warn!("tx failed: {:?}", e); + } self.ch.tx_done(); } From bc67cc22aa1461e6bce19b663b00bdccc818a998 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 5 Aug 2024 12:09:29 +0200 Subject: [PATCH 115/210] update driver channel dependency --- embassy-net-nrf91/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 2156346a4..e2d596d59 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -22,7 +22,7 @@ nrf9160-pac = { version = "0.12.0" } embassy-time = { version = "0.3.1", path = "../embassy-time" } embassy-sync = { version = "0.6.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} heapless = "0.8" embedded-io = "0.6.1" From 86a45b47e529864ac5a203b4ad26b9ee62127a1e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 5 Aug 2024 12:09:58 +0200 Subject: [PATCH 116/210] add at command file --- embassy-net-nrf91/src/at.rs | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 embassy-net-nrf91/src/at.rs diff --git a/embassy-net-nrf91/src/at.rs b/embassy-net-nrf91/src/at.rs new file mode 100644 index 000000000..04cbf3876 --- /dev/null +++ b/embassy-net-nrf91/src/at.rs @@ -0,0 +1,45 @@ +use crate::{Error, Control}; + +// Drives the control loop of the modem based on declarative configuration. +pub struct AtDriver<'a> { + control: Control<'a>, + config: Config, +} + +pub struct Config { + pub network: NetworkConfig, +} + +pub struct NetworkConfig { + pub apn: &'static str, + pub prot: AuthProtection, + pub userid: &'static str, + pub password: &'static str, +} + +#[repr(u8)] +pub enum AuthProtection { + None = 0, + Pap = 1, + Chap = 2, +} + +impl<'a> AtDriver<'a> { + pub async fn new(control: Control<'a>, config: Config) -> Result { + control.wait_init().await; + Ok(Self { + control, + config, + }) + } + + async fn setup(&self) -> Result<(), Error> { + + } + + pub fn run(&self, stack: Stack>) -> ! { + loop { + + } + } +} From c9ad897d4a6f1c66d77372fd27ec135e0c798f65 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 21 Aug 2024 18:12:59 +0200 Subject: [PATCH 117/210] Use released bt-hci crate --- cyw43/Cargo.toml | 2 +- examples/rp/Cargo.toml | 1 - examples/rp23/Cargo.toml | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 9b469c338..751e59a69 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -36,7 +36,7 @@ heapless = "0.8.0" # Bluetooth deps embedded-io-async = { version = "0.6.0", optional = true } -bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3", optional = true, default-features = false } +bt-hci = { version = "0.1.0", optional = true } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 83d5792b6..04b4c6317 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -74,7 +74,6 @@ opt-level = "z" [patch.crates-io] trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } -bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } embassy-executor = { path = "../../embassy-executor" } embassy-sync = { path = "../../embassy-sync" } embassy-futures = { path = "../../embassy-futures" } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 8f8d6ff10..087f6fd69 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -71,7 +71,6 @@ opt-level = "z" [patch.crates-io] trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } -bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } embassy-executor = { path = "../../embassy-executor" } embassy-sync = { path = "../../embassy-sync" } embassy-futures = { path = "../../embassy-futures" } From acc26a076a44c4c64b960e259bb516a9bd636dfd Mon Sep 17 00:00:00 2001 From: dvdsk Date: Fri, 23 Aug 2024 15:04:00 +0200 Subject: [PATCH 118/210] embassy-net/read document return value Ok(0) --- embassy-net/src/tcp.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 18200287e..62ee5cb66 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -79,6 +79,9 @@ impl<'a> TcpReader<'a> { /// /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. + /// + /// A return value of Ok(0) means that the socket was closed and is longer able to + /// accept bytes or that the buffer provided is empty. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } @@ -273,6 +276,9 @@ impl<'a> TcpSocket<'a> { /// /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. + /// + /// A return value of Ok(0) means that the socket was closed and is longer able to + /// accept bytes or that the buffer provided is empty. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } From 5479647962477a794dfcde19d8e865eb47150caf Mon Sep 17 00:00:00 2001 From: dvdsk Date: Fri, 23 Aug 2024 19:16:33 +0200 Subject: [PATCH 119/210] embassy-net: fix/clearify TcpReader docs. Expand docs on timeouts --- embassy-net/src/tcp.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 62ee5cb66..b2e3279cc 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -80,8 +80,14 @@ impl<'a> TcpReader<'a> { /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. /// - /// A return value of Ok(0) means that the socket was closed and is longer able to - /// accept bytes or that the buffer provided is empty. + /// # Note + /// A return value of Ok(0) means that we have read all data and the remote + /// side has closed our receive half of the socket. The remote can no longer + /// send bytes. + /// + /// The send half of the socket is still open. If you want to reconnect using + /// the socket you split this reader off the send half needs to be closed using + /// [`abort()`](TcpSocket::abort). pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } @@ -277,8 +283,8 @@ impl<'a> TcpSocket<'a> { /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. /// - /// A return value of Ok(0) means that the socket was closed and is longer able to - /// accept bytes or that the buffer provided is empty. + /// A return value of Ok(0) means that the socket was closed and is longer + /// able to receive any data. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } @@ -303,6 +309,10 @@ impl<'a> TcpSocket<'a> { /// /// If the timeout is set, the socket will be closed if no data is received for the /// specified duration. + /// + /// # Note: + /// Set a keep alive interval ([`set_keep_alive`] to prevent timeouts when + /// the remote could still respond. pub fn set_timeout(&mut self, duration: Option) { self.io .with_mut(|s, _| s.set_timeout(duration.map(duration_to_smoltcp))) @@ -314,6 +324,9 @@ impl<'a> TcpSocket<'a> { /// the specified duration of inactivity. /// /// If not set, the socket will not send keep-alive packets. + /// + /// By setting a [`timeout`](Self::timeout) larger then the keep alive you + /// can detect a remote endpoint that no longer answers. pub fn set_keep_alive(&mut self, interval: Option) { self.io .with_mut(|s, _| s.set_keep_alive(interval.map(duration_to_smoltcp))) From 8c1024b2a59c82ffccaba0327c02bc99da047943 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 24 Aug 2024 12:11:54 +0200 Subject: [PATCH 120/210] Set up timer0 tick when initializing clocks --- embassy-rp/src/clocks.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 5f7ba10e2..ed146844c 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -512,12 +512,18 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_int(config.ref_clk.div); }); - // Configure tick generation on the 2040. On the 2350 the timers are driven from the sysclk. + // Configure tick generation on the 2040. #[cfg(feature = "rp2040")] pac::WATCHDOG.tick().write(|w| { w.set_cycles((clk_ref_freq / 1_000_000) as u16); w.set_enable(true); }); + // Configure tick generator on the 2350 + #[cfg(feature = "_rp235x")] + { + pac::TICKS.timer0_cycles().write(|w| w.0 = clk_ref_freq / 1_000_000); + pac::TICKS.timer0_ctrl().write(|w| w.set_enable(true)); + } let (sys_src, sys_aux, clk_sys_freq) = { use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; From 87e97fb69d31606456ddbf9e3308364773648929 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 24 Aug 2024 20:16:00 +0200 Subject: [PATCH 121/210] feat: add function to check if SAI is muted --- embassy-stm32/src/sai/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index c48d81b5f..6bf184dd8 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -987,6 +987,21 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { ch.cr2().modify(|w| w.set_mute(value)); } + /// Determine the mute state of the receiver. + /// + /// Clears the mute state flag in the status register. + pub fn is_muted(&self) -> Result { + match &self.ring_buffer { + RingBuffer::Readable(_) => { + let ch = T::REGS.ch(self.sub_block as usize); + let mute_state = ch.sr().read().mutedet(); + ch.clrfr().write(|w| w.set_cmutedet(true)); + Ok(mute_state) + } + _ => Err(Error::NotAReceiver), + } + } + /// Write data to the SAI ringbuffer. /// /// This appends the data to the buffer and returns immediately. The From 557cff708505eb02c2b4c7f264a726bb9c17812a Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 24 Aug 2024 20:23:10 +0200 Subject: [PATCH 122/210] feat: Add support for a full-speed ULPI mode --- embassy-stm32/src/usb/otg.rs | 49 +++++++++++++++++++++++++++++ embassy-usb-synopsys-otg/src/lib.rs | 7 +++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 8ee8dcc36..e27b164e4 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -97,6 +97,55 @@ impl<'d, T: Instance> Driver<'d, T> { } } + /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode). + /// + /// # Arguments + /// + /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets. + /// Must be large enough to fit all OUT endpoint max packet sizes. + /// Endpoint allocation will fail if it is too small. + pub fn new_fs_ulpi( + _peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ulpi_clk: impl Peripheral

> + 'd, + ulpi_dir: impl Peripheral

> + 'd, + ulpi_nxt: impl Peripheral

> + 'd, + ulpi_stp: impl Peripheral

> + 'd, + ulpi_d0: impl Peripheral

> + 'd, + ulpi_d1: impl Peripheral

> + 'd, + ulpi_d2: impl Peripheral

> + 'd, + ulpi_d3: impl Peripheral

> + 'd, + ulpi_d4: impl Peripheral

> + 'd, + ulpi_d5: impl Peripheral

> + 'd, + ulpi_d6: impl Peripheral

> + 'd, + ulpi_d7: impl Peripheral

> + 'd, + ep_out_buffer: &'d mut [u8], + config: Config, + ) -> Self { + config_ulpi_pins!( + ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6, + ulpi_d7 + ); + + let regs = T::regs(); + + let instance = OtgInstance { + regs: T::regs(), + state: T::state(), + fifo_depth_words: T::FIFO_DEPTH_WORDS, + extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, + endpoint_count: T::ENDPOINT_COUNT, + phy_type: PhyType::ExternalFullSpeed, + quirk_setup_late_cnak: quirk_setup_late_cnak(regs), + calculate_trdt_fn: calculate_trdt::, + }; + + Self { + inner: OtgDriver::new(ep_out_buffer, instance, config), + phantom: PhantomData, + } + } + /// Initializes USB OTG peripheral with external High-Speed PHY. /// /// # Arguments diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index b90e059f6..82752010a 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -179,6 +179,8 @@ pub enum PhyType { /// /// Available on a few STM32 chips. InternalHighSpeed, + /// External ULPI Full-Speed PHY (or High-Speed PHY in Full-Speed mode) + ExternalFullSpeed, /// External ULPI High-Speed PHY ExternalHighSpeed, } @@ -188,14 +190,14 @@ impl PhyType { pub fn internal(&self) -> bool { match self { PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, - PhyType::ExternalHighSpeed => false, + PhyType::ExternalHighSpeed | PhyType::ExternalFullSpeed => false, } } /// Get whether this PHY is any of the high-speed types. pub fn high_speed(&self) -> bool { match self { - PhyType::InternalFullSpeed => false, + PhyType::InternalFullSpeed | PhyType::ExternalFullSpeed => false, PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true, } } @@ -204,6 +206,7 @@ impl PhyType { match self { PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, + PhyType::ExternalFullSpeed => vals::Dspd::FULL_SPEED_EXTERNAL, PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED, } } From 41e162541aa56553162932278ba8b6763fb63ecd Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 25 Aug 2024 07:14:19 +0200 Subject: [PATCH 123/210] stm32: Fix log storm when no CAN is connected Running the bxcan driver without having it connected to a CAN bus causes the `info` logs to bombard. This removes the logging statements as they looked like remnants from the development of the driver. --- embassy-stm32/src/can/bxcan/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 278c93ff4..baa4bee79 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -68,7 +68,6 @@ pub struct SceInterruptHandler { impl interrupt::typelevel::Handler for SceInterruptHandler { unsafe fn on_interrupt() { - info!("sce irq"); let msr = T::regs().msr(); let msr_val = msr.read(); @@ -76,9 +75,8 @@ impl interrupt::typelevel::Handler for SceInterrup msr.modify(|m| m.set_slaki(true)); T::state().err_waker.wake(); } else if msr_val.erri() { - info!("Error interrupt"); // Disable the interrupt, but don't acknowledge the error, so that it can be - // forwarded off the the bus message consumer. If we don't provide some way for + // forwarded off the bus message consumer. If we don't provide some way for // downstream code to determine that it has already provided this bus error instance // to the bus message consumer, we are doomed to re-provide a single error instance for // an indefinite amount of time. From bea1f34440eff7842c0c04e8b7381cdb429f5005 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Wed, 21 Aug 2024 13:15:48 +0200 Subject: [PATCH 124/210] stm32/usart: sending break character --- embassy-stm32/src/usart/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 89d92dda2..cbd4ac3bc 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -520,6 +520,21 @@ impl<'d, M: Mode> UartTx<'d, M> { pub fn blocking_flush(&mut self) -> Result<(), Error> { blocking_flush(self.info) } + + /// Send break character + pub fn send_break(&self) { + // Busy wait until previous break has been sent + #[cfg(any(usart_v1, usart_v2))] + while self.info.regs.cr1().read().sbk() {} + #[cfg(any(usart_v3, usart_v4))] + while self.info.regs.isr().read().sbkf() {} + + // Send break right after completing the current character transmission + #[cfg(any(usart_v1, usart_v2))] + self.info.regs.cr1().modify(|w| w.set_sbk(true)); + #[cfg(any(usart_v3, usart_v4))] + self.info.regs.rqr().write(|w| w.set_sbkrq(true)); + } } fn blocking_flush(info: &Info) -> Result<(), Error> { @@ -1365,6 +1380,11 @@ impl<'d, M: Mode> Uart<'d, M> { pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) { (self.tx, self.rx) } + + /// Send break character + pub fn send_break(&self) { + self.tx.send_break(); + } } fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { From 9b142bd80fad43beeb1114ec289f570310aae2de Mon Sep 17 00:00:00 2001 From: Cirrus Date: Sun, 25 Aug 2024 13:14:36 -0700 Subject: [PATCH 125/210] feat(embassy-net): add zero-copy UDP send/recv functions Added recv_from_with and send_to_with. These are conceptually similar to TCP's read_with and write_with functions. An application can parse received datagrams directly out of the receive buffer or assemble a datagram of known-length directly into the send buffer. --- embassy-net/src/udp.rs | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 6e50c4e01..1d5360187 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -138,6 +138,35 @@ impl<'a> UdpSocket<'a> { }) } + /// Receive a datagram with a zero-copy function. + /// + /// When no datagram is available, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + /// + /// When a datagram is received, this method will call the provided function + /// with the number of bytes received and the remote endpoint and return + /// `Poll::Ready` with the function's returned value. + pub async fn recv_from_with(&mut self, f: F) -> R + where + F: FnOnce(&[u8], UdpMetadata) -> R, + { + let mut f = Some(f); + poll_fn(move |cx| { + self.with_mut(|s, _| { + match s.recv() { + Ok((buffer, endpoint)) => Poll::Ready(unwrap!(f.take())(buffer, endpoint)), + Err(udp::RecvError::Truncated) => unreachable!(), + Err(udp::RecvError::Exhausted) => { + // socket buffer is empty wait until at least one byte has arrived + s.register_recv_waker(cx.waker()); + Poll::Pending + } + } + }) + }) + .await + } + /// Send a datagram to the specified remote endpoint. /// /// This method will wait until the datagram has been sent. @@ -181,6 +210,40 @@ impl<'a> UdpSocket<'a> { }) } + /// Send a datagram to the specified remote endpoint with a zero-copy function. + /// + /// This method will wait until the buffer can fit the requested size before + /// calling the function to fill its contents. + /// + /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` + pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result + where + T: Into + Copy, + F: FnOnce(&mut [u8]) -> R, + { + let mut f = Some(f); + poll_fn(move |cx| { + self.with_mut(|s, _| { + match s.send(size, remote_endpoint) { + Ok(buffer) => Poll::Ready(Ok(unwrap!(f.take())(buffer))), + Err(udp::SendError::BufferFull) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + Err(udp::SendError::Unaddressable) => { + // If no sender/outgoing port is specified, there is not really "no route" + if s.endpoint().port == 0 { + Poll::Ready(Err(SendError::SocketNotBound)) + } else { + Poll::Ready(Err(SendError::NoRoute)) + } + } + } + }) + }) + .await + } + /// Returns the local endpoint of the socket. pub fn endpoint(&self) -> IpListenEndpoint { self.with(|s, _| s.endpoint()) From 0a33edc9976caddcdebe0943cce78376f9c49789 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 26 Aug 2024 09:41:52 -0400 Subject: [PATCH 126/210] Import rom_data for the rp235x, don't use intrinsics on rp235x Many thanks to @thejpster for his work on the rom_data! Working around boot2 is currently a bit hacky for the rp235x, that will improve in upcoming rp235x flash pr. --- embassy-rp/src/flash.rs | 82 +- embassy-rp/src/lib.rs | 1 + embassy-rp/src/rom_data/mod.rs | 33 + .../src/{rom_data.rs => rom_data/rp2040.rs} | 4 +- embassy-rp/src/rom_data/rp235x.rs | 752 ++++++++++++++++++ 5 files changed, 850 insertions(+), 22 deletions(-) create mode 100644 embassy-rp/src/rom_data/mod.rs rename embassy-rp/src/{rom_data.rs => rom_data/rp2040.rs} (99%) create mode 100644 embassy-rp/src/rom_data/rp235x.rs diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index a68493932..5f7922f8e 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -510,11 +510,19 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase(addr: u32, len: u32) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, false, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(true, false, &boot2) + } else { + flash_function_pointers(true, false) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(true, false) }; @@ -540,11 +548,19 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, true, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(true, true, &boot2) + } else { + flash_function_pointers(true, true) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(true, true) }; @@ -575,11 +591,19 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_program(addr: u32, data: &[u8]) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, true, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, true, &boot2) + } else { + flash_function_pointers(false, true) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(false, true) }; @@ -708,13 +732,22 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) pub unsafe fn flash_unique_id(out: &mut [u8]) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { + flash_function_pointers(false, false) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(false, false) }; + // 4B - read unique ID let cmd = [0x4B]; read_flash(&cmd[..], 4, out, &ptrs as *const FlashFunctionPointers); @@ -736,13 +769,22 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) pub unsafe fn flash_jedec_id() -> u32 { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { + flash_function_pointers(false, false) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(false, false) }; + let mut id = [0u8; 4]; // 9F - read JEDEC ID let cmd = [0x9F]; diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 21f0771de..c2c57eaa0 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -15,6 +15,7 @@ pub use rp_binary_info as binary_info; #[cfg(feature = "critical-section-impl")] mod critical_section_impl; +#[cfg(feature = "rp2040")] mod intrinsics; pub mod adc; diff --git a/embassy-rp/src/rom_data/mod.rs b/embassy-rp/src/rom_data/mod.rs new file mode 100644 index 000000000..e5fcf8e3c --- /dev/null +++ b/embassy-rp/src/rom_data/mod.rs @@ -0,0 +1,33 @@ +#![cfg_attr( + feature = "rp2040", + doc = r" +//! Functions and data from the RPI Bootrom. +//! +//! From the [RP2040 datasheet](https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf), Section 2.8.2.1: +//! +//! > The Bootrom contains a number of public functions that provide useful +//! > RP2040 functionality that might be needed in the absence of any other code +//! > on the device, as well as highly optimized versions of certain key +//! > functionality that would otherwise have to take up space in most user +//! > binaries. +" +)] +#![cfg_attr( + feature = "_rp235x", + doc = r" +//! Functions and data from the RPI Bootrom. +//! +//! From [Section 5.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the +//! RP2350 datasheet: +//! +//! > Whilst some ROM space is dedicated to the implementation of the boot +//! > sequence and USB/UART boot interfaces, the bootrom also contains public +//! > functions that provide useful RP2350 functionality that may be useful for +//! > any code or runtime running on the device +" +)] + +#[cfg_attr(feature = "rp2040", path = "rp2040.rs")] +#[cfg_attr(feature = "_rp235x", path = "rp235x.rs")] +mod inner; +pub use inner::*; diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data/rp2040.rs similarity index 99% rename from embassy-rp/src/rom_data.rs rename to embassy-rp/src/rom_data/rp2040.rs index baebe5b6c..5a74eddd6 100644 --- a/embassy-rp/src/rom_data.rs +++ b/embassy-rp/src/rom_data/rp2040.rs @@ -189,7 +189,7 @@ macro_rules! rom_functions { declare_rom_function! { $(#[$outer])* fn $name( $($argname: $ty),* ) -> $ret { - $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c) + $crate::rom_data::inner::rom_table_lookup($crate::rom_data::inner::FUNC_TABLE, *$c) } } @@ -205,7 +205,7 @@ macro_rules! rom_functions { declare_rom_function! { $(#[$outer])* unsafe fn $name( $($argname: $ty),* ) -> $ret { - $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c) + $crate::rom_data::inner::rom_table_lookup($crate::rom_data::inner::FUNC_TABLE, *$c) } } diff --git a/embassy-rp/src/rom_data/rp235x.rs b/embassy-rp/src/rom_data/rp235x.rs new file mode 100644 index 000000000..b16fee8f7 --- /dev/null +++ b/embassy-rp/src/rom_data/rp235x.rs @@ -0,0 +1,752 @@ +//! Functions and data from the RPI Bootrom. +//! +//! From [Section 5.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the +//! RP2350 datasheet: +//! +//! > Whilst some ROM space is dedicated to the implementation of the boot +//! > sequence and USB/UART boot interfaces, the bootrom also contains public +//! > functions that provide useful RP2350 functionality that may be useful for +//! > any code or runtime running on the device + +// Credit: taken from `rp-hal` (also licensed Apache+MIT) +// https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs + +/// A bootrom function table code. +pub type RomFnTableCode = [u8; 2]; + +/// This function searches for the tag which matches the mask. +type RomTableLookupFn = unsafe extern "C" fn(code: u32, mask: u32) -> usize; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_0016 as _; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_0018 as _; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On Arm, the same function is used to look up code and data. +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_DATA_LOOKUP_A2: *const u16 = ROM_TABLE_LOOKUP_A2; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On Arm, the same function is used to look up code and data. +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_DATA_LOOKUP_A1: *const u32 = ROM_TABLE_LOOKUP_A1; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_7DFA as _; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_7DF8 as _; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On RISC-V, a different function is used to look up data. +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_DATA_LOOKUP_A2: *const u16 = 0x0000_7DF8 as _; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On RISC-V, a different function is used to look up data. +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_DATA_LOOKUP_A1: *const u32 = 0x0000_7DF4 as _; + +/// Address of the version number of the ROM. +const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; + +#[allow(unused)] +mod rt_flags { + pub const FUNC_RISCV: u32 = 0x0001; + pub const FUNC_RISCV_FAR: u32 = 0x0003; + pub const FUNC_ARM_SEC: u32 = 0x0004; + // reserved for 32-bit pointer: 0x0008 + pub const FUNC_ARM_NONSEC: u32 = 0x0010; + // reserved for 32-bit pointer: 0x0020 + pub const DATA: u32 = 0x0040; + // reserved for 32-bit pointer: 0x0080 + #[cfg(all(target_arch = "arm", target_os = "none"))] + pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_ARM_SEC; + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_RISCV; +} + +/// Retrieve rom content from a table using a code. +pub fn rom_table_lookup(tag: RomFnTableCode, mask: u32) -> usize { + let tag = u16::from_le_bytes(tag) as u32; + unsafe { + let lookup_func = if rom_version_number() == 1 { + ROM_TABLE_LOOKUP_A1.read() as usize + } else { + ROM_TABLE_LOOKUP_A2.read() as usize + }; + let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func); + lookup_func(tag, mask) + } +} + +/// Retrieve rom data content from a table using a code. +pub fn rom_data_lookup(tag: RomFnTableCode, mask: u32) -> usize { + let tag = u16::from_le_bytes(tag) as u32; + unsafe { + let lookup_func = if rom_version_number() == 1 { + ROM_DATA_LOOKUP_A1.read() as usize + } else { + ROM_DATA_LOOKUP_A2.read() as usize + }; + let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func); + lookup_func(tag, mask) + } +} + +macro_rules! declare_rom_function { + ( + $(#[$outer:meta])* + fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty + $lookup:block + ) => { + #[doc = r"Additional access for the `"] + #[doc = stringify!($name)] + #[doc = r"` ROM function."] + pub mod $name { + /// Retrieve a function pointer. + #[cfg(not(feature = "rom-func-cache"))] + pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret { + let p: usize = $lookup; + unsafe { + let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + + /// Retrieve a function pointer. + #[cfg(feature = "rom-func-cache")] + pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret { + use core::sync::atomic::{AtomicU16, Ordering}; + + // All pointers in the ROM fit in 16 bits, so we don't need a + // full width word to store the cached value. + static CACHED_PTR: AtomicU16 = AtomicU16::new(0); + // This is safe because the lookup will always resolve + // to the same value. So even if an interrupt or another + // core starts at the same time, it just repeats some + // work and eventually writes back the correct value. + let p: usize = match CACHED_PTR.load(Ordering::Relaxed) { + 0 => { + let raw: usize = $lookup; + CACHED_PTR.store(raw as u16, Ordering::Relaxed); + raw + }, + val => val as usize, + }; + unsafe { + let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + } + + $(#[$outer])* + pub extern "C" fn $name( $($argname: $ty),* ) -> $ret { + $name::ptr()($($argname),*) + } + }; + + ( + $(#[$outer:meta])* + unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty + $lookup:block + ) => { + #[doc = r"Additional access for the `"] + #[doc = stringify!($name)] + #[doc = r"` ROM function."] + pub mod $name { + /// Retrieve a function pointer. + #[cfg(not(feature = "rom-func-cache"))] + pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret { + let p: usize = $lookup; + unsafe { + let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + + /// Retrieve a function pointer. + #[cfg(feature = "rom-func-cache")] + pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret { + use core::sync::atomic::{AtomicU16, Ordering}; + + // All pointers in the ROM fit in 16 bits, so we don't need a + // full width word to store the cached value. + static CACHED_PTR: AtomicU16 = AtomicU16::new(0); + // This is safe because the lookup will always resolve + // to the same value. So even if an interrupt or another + // core starts at the same time, it just repeats some + // work and eventually writes back the correct value. + let p: usize = match CACHED_PTR.load(Ordering::Relaxed) { + 0 => { + let raw: usize = $lookup; + CACHED_PTR.store(raw as u16, Ordering::Relaxed); + raw + }, + val => val as usize, + }; + unsafe { + let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + } + + $(#[$outer])* + /// # Safety + /// + /// This is a low-level C function. It may be difficult to call safely from + /// Rust. If in doubt, check the rp235x datasheet for details and do your own + /// safety evaluation. + pub unsafe extern "C" fn $name( $($argname: $ty),* ) -> $ret { + $name::ptr()($($argname),*) + } + }; +} + +// **************** 5.5.7 Low-level Flash Commands **************** + +declare_rom_function! { + /// Restore all QSPI pad controls to their default state, and connect the + /// QMI peripheral to the QSPI pads. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn connect_internal_flash() -> () { + crate::rom_data::rom_table_lookup(*b"IF", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Initialise the QMI for serial operations (direct mode) + /// + /// Also initialise a basic XIP mode, where the QMI will perform 03h serial + /// read commands at low speed (CLKDIV=12) in response to XIP reads. + /// + /// Then, issue a sequence to the QSPI device on chip select 0, designed to + /// return it from continuous read mode ("XIP mode") and/or QPI mode to a + /// state where it will accept serial commands. This is necessary after + /// system reset to restore the QSPI device to a known state, because + /// resetting RP2350 does not reset attached QSPI devices. It is also + /// necessary when user code, having already performed some + /// continuous-read-mode or QPI-mode accesses, wishes to return the QSPI + /// device to a state where it will accept the serial erase and programming + /// commands issued by the bootrom’s flash access functions. + /// + /// If a GPIO for the secondary chip select is configured via FLASH_DEVINFO, + /// then the XIP exit sequence is also issued to chip select 1. + /// + /// The QSPI device should be accessible for XIP reads after calling this + /// function; the name flash_exit_xip refers to returning the QSPI device + /// from its XIP state to a serial command state. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_exit_xip() -> () { + crate::rom_data::rom_table_lookup(*b"EX", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Erase count bytes, starting at addr (offset from start of flash). + /// + /// Optionally, pass a block erase command e.g. D8h block erase, and the + /// size of the block erased by this command — this function will use the + /// larger block erase where possible, for much higher erase speed. addr + /// must be aligned to a 4096-byte sector, and count must be a multiple of + /// 4096 bytes. + /// + /// This is a low-level flash API, and no validation of the arguments is + /// performed. See flash_op() for a higher-level API which checks alignment, + /// flash bounds and partition permissions, and can transparently apply a + /// runtime-to-storage address translation. + /// + /// The QSPI device must be in a serial command state before calling this + /// API, which can be achieved by calling connect_internal_flash() followed + /// by flash_exit_xip(). After the erase, the flash cache should be flushed + /// via flash_flush_cache() to ensure the modified flash data is visible to + /// cached XIP accesses. + /// + /// Finally, the original XIP mode should be restored by copying the saved + /// XIP setup function from bootram into SRAM, and executing it: the bootrom + /// provides a default function which restores the flash mode/clkdiv + /// discovered during flash scanning, and user programs can override this + /// with their own XIP setup function. + /// + /// For the duration of the erase operation, QMI is in direct mode (Section + /// 12.14.5) and attempting to access XIP from DMA, the debugger or the + /// other core will return a bus fault. XIP becomes accessible again once + /// the function returns. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_range_erase(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> () { + crate::rom_data::rom_table_lookup(*b"RE", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Program data to a range of flash storage addresses starting at addr + /// (offset from the start of flash) and count bytes in size. + /// + /// `addr` must be aligned to a 256-byte boundary, and count must be a + /// multiple of 256. + /// + /// This is a low-level flash API, and no validation of the arguments is + /// performed. See flash_op() for a higher-level API which checks alignment, + /// flash bounds and partition permissions, and can transparently apply a + /// runtime-to-storage address translation. + /// + /// The QSPI device must be in a serial command state before calling this + /// API — see notes on flash_range_erase(). + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_range_program(addr: u32, data: *const u8, count: usize) -> () { + crate::rom_data::rom_table_lookup(*b"RP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Flush the entire XIP cache, by issuing an invalidate by set/way + /// maintenance operation to every cache line (Section 4.4.1). + /// + /// This ensures that flash program/erase operations are visible to + /// subsequent cached XIP reads. + /// + /// Note that this unpins pinned cache lines, which may interfere with + /// cache-as-SRAM use of the XIP cache. + /// + /// No other operations are performed. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_flush_cache() -> () { + crate::rom_data::rom_table_lookup(*b"FC", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Configure the QMI to generate a standard 03h serial read command, with + /// 24 address bits, upon each XIP access. + /// + /// This is a slow XIP configuration, but is widely supported. CLKDIV is set + /// to 12. The debugger may call this function to ensure that flash is + /// readable following a program/erase operation. + /// + /// Note that the same setup is performed by flash_exit_xip(), and the + /// RP2350 flash program/erase functions do not leave XIP in an inaccessible + /// state, so calls to this function are largely redundant. It is provided + /// for compatibility with RP2040. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_enter_cmd_xip() -> () { + crate::rom_data::rom_table_lookup(*b"CX", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Configure QMI for one of a small menu of XIP read modes supported by the + /// bootrom. This mode is configured for both memory windows (both chip + /// selects), and the clock divisor is also applied to direct mode. + /// + /// The available modes are: + /// + /// * 0: `03h` serial read: serial address, serial data, no wait cycles + /// * 1: `0Bh` serial read: serial address, serial data, 8 wait cycles + /// * 2: `BBh` dual-IO read: dual address, dual data, 4 wait cycles + /// (including MODE bits, which are driven to 0) + /// * 3: `EBh` quad-IO read: quad address, quad data, 6 wait cycles + /// (including MODE bits, which are driven to 0) + /// + /// The XIP write command/format are not configured by this function. When + /// booting from flash, the bootrom tries each of these modes in turn, from + /// 3 down to 0. The first mode that is found to work is remembered, and a + /// default XIP setup function is written into bootram that calls this + /// function (flash_select_xip_read_mode) with the parameters discovered + /// during flash scanning. This can be called at any time to restore the + /// flash parameters discovered during flash boot. + /// + /// All XIP modes configured by the bootrom have an 8-bit serial command + /// prefix, so that the flash can remain in a serial command state, meaning + /// XIP accesses can be mixed more freely with program/erase serial + /// operations. This has a performance penalty, so users can perform their + /// own flash setup after flash boot using continuous read mode or QPI mode + /// to avoid or alleviate the command prefix cost. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_select_xip_read_mode(bootrom_xip_mode: u8, clkdiv: u8) -> () { + crate::rom_data::rom_table_lookup(*b"XM", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Restore the QMI address translation registers, ATRANS0 through ATRANS7, + /// to their reset state. This makes the runtime- to-storage address map an + /// identity map, i.e. the mapped and unmapped address are equal, and the + /// entire space is fully mapped. + /// + /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350 + /// datasheet. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_reset_address_trans() -> () { + crate::rom_data::rom_table_lookup(*b"RA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** High-level Flash Commands **************** + +declare_rom_function! { + /// Applies the address translation currently configured by QMI address + /// translation registers, ATRANS0 through ATRANS7. + /// + /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350 + /// datasheet. + /// + /// Translating an address outside of the XIP runtime address window, or + /// beyond the bounds of an ATRANSx_SIZE field, returns + /// BOOTROM_ERROR_INVALID_ADDRESS, which is not a valid flash storage + /// address. Otherwise, return the storage address which QMI would access + /// when presented with the runtime address addr. This is effectively a + /// virtual-to-physical address translation for QMI. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_runtime_to_storage_addr(addr: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [flash_runtime_to_storage_addr()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn flash_runtime_to_storage_addr_ns(addr: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Perform a flash read, erase, or program operation. + /// + /// Erase operations must be sector-aligned (4096 bytes) and sector- + /// multiple-sized, and program operations must be page-aligned (256 bytes) + /// and page-multiple-sized; misaligned erase and program operations will + /// return BOOTROM_ERROR_BAD_ALIGNMENT. The operation — erase, read, program + /// — is selected by the CFLASH_OP_BITS bitfield of the flags argument. + /// + /// See datasheet section 5.5.8.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_op(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 { + crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [flash_op()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn flash_op_ns(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 { + crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +// **************** Security Related Functions **************** + +declare_rom_function! { + /// Allow or disallow the specific NS API (note all NS APIs default to + /// disabled). + /// + /// See datasheet section 5.5.9.1 for more details. + /// + /// Supported architectures: ARM-S + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn set_ns_api_permission(ns_api_num: u32, allowed: u8) -> i32 { + crate::rom_data::rom_table_lookup(*b"SP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC) + } +} + +declare_rom_function! { + /// Utility method that can be used by secure ARM code to validate a buffer + /// passed to it from Non-secure code. + /// + /// See datasheet section 5.5.9.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn validate_ns_buffer() -> () { + crate::rom_data::rom_table_lookup(*b"VB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** Miscellaneous Functions **************** + +declare_rom_function! { + /// Resets the RP2350 and uses the watchdog facility to restart. + /// + /// See datasheet section 5.5.10.1 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + fn reboot(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [reboot()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + fn reboot_ns(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Resets internal bootrom state. + /// + /// See datasheet section 5.5.10.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn bootrom_state_reset(flags: u32) -> () { + crate::rom_data::rom_table_lookup(*b"SR", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Set a boot ROM callback. + /// + /// The only supported callback_number is 0 which sets the callback used for + /// the secure_call API. + /// + /// See datasheet section 5.5.10.3 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn set_rom_callback(callback_number: i32, callback_fn: *const ()) -> i32 { + crate::rom_data::rom_table_lookup(*b"RC", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** System Information Functions **************** + +declare_rom_function! { + /// Fills a buffer with various system information. + /// + /// Note that this API is also used to return information over the PICOBOOT + /// interface. + /// + /// See datasheet section 5.5.11.1 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_sys_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [get_sys_info()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn get_sys_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Fills a buffer with information from the partition table. + /// + /// Note that this API is also used to return information over the PICOBOOT + /// interface. + /// + /// See datasheet section 5.5.11.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_partition_table_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [get_partition_table_info()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn get_partition_table_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Loads the current partition table from flash, if present. + /// + /// See datasheet section 5.5.11.3 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn load_partition_table(workarea_base: *mut u8, workarea_size: usize, force_reload: bool) -> i32 { + crate::rom_data::rom_table_lookup(*b"LP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Writes data from a buffer into OTP, or reads data from OTP into a buffer. + /// + /// See datasheet section 5.5.11.4 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn otp_access(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [otp_access()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn otp_access_ns(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +// **************** Boot Related Functions **************** + +declare_rom_function! { + /// Determines which of the partitions has the "better" IMAGE_DEF. In the + /// case of executable images, this is the one that would be booted. + /// + /// See datasheet section 5.5.12.1 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn pick_ab_parition(workarea_base: *mut u8, workarea_size: usize, partition_a_num: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"AB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Searches a memory region for a launchable image, and executes it if + /// possible. + /// + /// See datasheet section 5.5.12.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn chain_image(workarea_base: *mut u8, workarea_size: usize, region_base: i32, region_size: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"CI", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Perform an "explicit" buy of an executable launched via an IMAGE_DEF + /// which was "explicit buy" flagged. + /// + /// See datasheet section 5.5.12.3 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn explicit_buy(buffer: *mut u8, buffer_size: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"EB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Not yet documented. + /// + /// See datasheet section 5.5.12.4 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_uf2_target_partition(workarea_base: *mut u8, workarea_size: usize, family_id: u32, partition_out: *mut u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GU", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Returns: The index of the B partition of partition A if a partition + /// table is present and loaded, and there is a partition A with a B + /// partition; otherwise returns BOOTROM_ERROR_NOT_FOUND. + /// + /// See datasheet section 5.5.12.5 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_b_partition(partition_a: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** Non-secure-specific Functions **************** + +// NB: The "secure_call" function should be here, but it doesn't have a fixed +// function signature as it is designed to let you bounce into any secure +// function from non-secure mode. + +// **************** RISC-V Functions **************** + +declare_rom_function! { + /// Set stack for RISC-V bootrom functions to use. + /// + /// See datasheet section 5.5.14.1 for more details. + /// + /// Supported architectures: RISC-V + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + unsafe fn set_bootrom_stack(base_size: *mut u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"SS", crate::rom_data::inner::rt_flags::FUNC_RISCV) + } +} + +/// The version number of the rom. +pub fn rom_version_number() -> u8 { + unsafe { *VERSION_NUMBER } +} + +/// The 8 most significant hex digits of the Bootrom git revision. +pub fn git_revision() -> u32 { + let ptr = rom_data_lookup(*b"GR", rt_flags::DATA) as *const u32; + unsafe { ptr.read() } +} + +/// A pointer to the resident partition table info. +/// +/// The resident partition table is the subset of the full partition table that +/// is kept in memory, and used for flash permissions. +pub fn partition_table_pointer() -> *const u32 { + let ptr = rom_data_lookup(*b"PT", rt_flags::DATA) as *const *const u32; + unsafe { ptr.read() } +} + +/// Determine if we are in secure mode +/// +/// Returns `true` if we are in secure mode and `false` if we are in non-secure +/// mode. +#[cfg(all(target_arch = "arm", target_os = "none"))] +pub fn is_secure_mode() -> bool { + // Look at the start of ROM, which is always readable + #[allow(clippy::zero_ptr)] + let rom_base: *mut u32 = 0x0000_0000 as *mut u32; + // Use the 'tt' instruction to check the permissions for that address + let tt = cortex_m::asm::tt(rom_base); + // Is the secure bit set? => secure mode + (tt & (1 << 22)) != 0 +} + +/// Determine if we are in secure mode +/// +/// Always returns `false` on RISC-V as it is impossible to determine if +/// you are in Machine Mode or User Mode by design. +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +pub fn is_secure_mode() -> bool { + false +} From d4ab9fc247731e5f8ede4bb60a8c3c63136e1e6d Mon Sep 17 00:00:00 2001 From: James Bowes Date: Mon, 26 Aug 2024 10:33:13 -0300 Subject: [PATCH 127/210] chore: Remove unused keyboard code from rp mouse example The usb mouse example included code copied from the keyboard example to set up a button, which is not used in the mouse example. Remove it, to make the example clearer. --- examples/rp/src/bin/usb_hid_mouse.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index cce344fb0..5ee650910 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -8,7 +8,6 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; -use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; use embassy_time::Timer; @@ -75,12 +74,6 @@ async fn main(_spawner: Spawner) { // Run the USB device. let usb_fut = usb.run(); - // Set up the signal pin that will be used to trigger the keyboard. - let mut signal_pin = Input::new(p.PIN_16, Pull::None); - - // Enable the schmitt trigger to slightly debounce. - signal_pin.set_schmitt(true); - let (reader, mut writer) = hid.split(); // Do stuff with the class! From 9347571fea243719826ff21b250bc0dff7f51fa5 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 26 Aug 2024 20:28:30 +0200 Subject: [PATCH 128/210] rp: add example code to flash bluetooth fw (#3290) --- examples/rp/src/bin/bluetooth.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs index 901521b60..7524e7929 100644 --- a/examples/rp/src/bin/bluetooth.rs +++ b/examples/rp/src/bin/bluetooth.rs @@ -43,8 +43,10 @@ async fn main(spawner: Spawner) { // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; + //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) }; let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); From f0a86070512ad739641cee7d9fa39d63f5c8a9f6 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Mon, 26 Aug 2024 19:45:57 +0100 Subject: [PATCH 129/210] Add block-device-driver impl for use with embedded-fatfs (#2607) --- embassy-stm32/Cargo.toml | 2 ++ embassy-stm32/src/sdmmc/mod.rs | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 54abd0799..9a6a5908e 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -88,6 +88,8 @@ static_assertions = { version = "1.1" } volatile-register = { version = "0.2.1" } bitflags = "2.4.2" +block-device-driver = { version = "0.2" } +aligned = "0.4.1" [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 44ff9fcd5..ed344c412 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1511,3 +1511,44 @@ foreach_peripheral!( } }; ); + +impl<'d, T: Instance, Dma: SdmmcDma + 'd> block_device_driver::BlockDevice<512> for Sdmmc<'d, T, Dma> { + type Error = Error; + type Align = aligned::A4; + + async fn read( + &mut self, + mut block_address: u32, + buf: &mut [aligned::Aligned], + ) -> Result<(), Self::Error> { + // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time + for block in buf.iter_mut() { + // safety aligned by block device + let block = unsafe { &mut *(block as *mut _ as *mut crate::sdmmc::DataBlock) }; + self.read_block(block_address, block).await?; + block_address += 1; + } + + Ok(()) + } + + async fn write( + &mut self, + mut block_address: u32, + buf: &[aligned::Aligned], + ) -> Result<(), Self::Error> { + // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time + for block in buf.iter() { + // safety aligned by block device + let block = unsafe { &*(block as *const _ as *const crate::sdmmc::DataBlock) }; + self.write_block(block_address, block).await?; + block_address += 1; + } + + Ok(()) + } + + async fn size(&mut self) -> Result { + Ok(self.card()?.size()) + } +} From b56e95bf7c2c5ab0ead23ee66de05cf9a288bc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 28 Aug 2024 10:26:48 +0200 Subject: [PATCH 130/210] Fix a typo --- embassy-time-driver/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 565597935..aab2f626e 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -98,7 +98,7 @@ pub trait Driver: Send + Sync + 'static { /// /// Implementations MUST ensure that: /// - This is guaranteed to be monotonic, i.e. a call to now() will always return - /// a greater or equal value than earler calls. Time can't "roll backwards". + /// a greater or equal value than earlier calls. Time can't "roll backwards". /// - It "never" overflows. It must not overflow in a sufficiently long time frame, say /// in 10_000 years (Human civilization is likely to already have self-destructed /// 10_000 years from now.). This means if your hardware only has 16bit/32bit timers From 22f4459ae28fe7e299f775f95952132d3c3dffa2 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Wed, 28 Aug 2024 21:35:31 +0200 Subject: [PATCH 131/210] stm32/usart: sending break character in buffered usart --- embassy-stm32/src/usart/buffered.rs | 14 ++++++++++++-- embassy-stm32/src/usart/mod.rs | 27 ++++++++++++++++----------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 06cc0e41d..86f56eb7c 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -12,8 +12,8 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] use super::DePin; use super::{ - clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance, - Regs, RtsPin, RxPin, TxPin, + clear_interrupt_flags, configure, rdr, reconfigure, send_break, sr, tdr, Config, ConfigError, CtsPin, Error, Info, + Instance, Regs, RtsPin, RxPin, TxPin, }; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::{self, InterruptExt}; @@ -359,6 +359,11 @@ impl<'d> BufferedUart<'d> { Ok(()) } + + /// Send break character + pub fn send_break(&self) { + self.tx.send_break() + } } impl<'d> BufferedUartRx<'d> { @@ -538,6 +543,11 @@ impl<'d> BufferedUartTx<'d> { Ok(()) } + + /// Send break character + pub fn send_break(&self) { + send_break(&self.info.regs); + } } impl<'d> Drop for BufferedUartRx<'d> { diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index cbd4ac3bc..e7f2f890a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -523,17 +523,7 @@ impl<'d, M: Mode> UartTx<'d, M> { /// Send break character pub fn send_break(&self) { - // Busy wait until previous break has been sent - #[cfg(any(usart_v1, usart_v2))] - while self.info.regs.cr1().read().sbk() {} - #[cfg(any(usart_v3, usart_v4))] - while self.info.regs.isr().read().sbkf() {} - - // Send break right after completing the current character transmission - #[cfg(any(usart_v1, usart_v2))] - self.info.regs.cr1().modify(|w| w.set_sbk(true)); - #[cfg(any(usart_v3, usart_v4))] - self.info.regs.rqr().write(|w| w.set_sbkrq(true)); + send_break(&self.info.regs); } } @@ -549,6 +539,21 @@ fn blocking_flush(info: &Info) -> Result<(), Error> { Ok(()) } +/// Send break character +pub fn send_break(regs: &Regs) { + // Busy wait until previous break has been sent + #[cfg(any(usart_v1, usart_v2))] + while regs.cr1().read().sbk() {} + #[cfg(any(usart_v3, usart_v4))] + while regs.isr().read().sbkf() {} + + // Send break right after completing the current character transmission + #[cfg(any(usart_v1, usart_v2))] + regs.cr1().modify(|w| w.set_sbk(true)); + #[cfg(any(usart_v3, usart_v4))] + regs.rqr().write(|w| w.set_sbkrq(true)); +} + impl<'d> UartRx<'d, Async> { /// Create a new rx-only UART with no hardware flow control. /// From 372270a9b962196ede9c60a705cc3138ba592fec Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 27 Aug 2024 13:19:07 -0400 Subject: [PATCH 132/210] rp235x flash support. The 2350 doesn't have a boot2 like the 2040, but it does have the concept of a xip setup function that could be customized. By default the bootrom searches for the attached flash chip and provides an xip setup func at the base of the bootram. That bootram is not executable, so it still needs to be copied to ram like boot2 would be. Currently does not use inline assembly. Also switch to picotool, as elf2uf2 has not been patched to support the 2350. --- embassy-rp/src/flash.rs | 135 ++++++++++++++----------------- embassy-rp/src/lib.rs | 4 +- examples/rp23/.cargo/config.toml | 3 +- examples/rp23/src/bin/flash.rs | 15 +--- 4 files changed, 68 insertions(+), 89 deletions(-) diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 5f7922f8e..dab99b4e2 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -17,9 +17,13 @@ use crate::peripherals::FLASH; /// Flash base address. pub const FLASH_BASE: *const u32 = 0x10000000 as _; +/// Address for xip setup function set up by the 235x bootrom. +#[cfg(feature = "_rp235x")] +pub const BOOTROM_BASE: *const u32 = 0x400e0000 as _; + /// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. // TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. -pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); +pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram") | cfg!(feature = "_rp235x"); // **NOTE**: // @@ -97,7 +101,10 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, ' // Errata RP2040-E8: Perform an uncached read to make sure there's not a transfer in // flight that might effect an address written to start a new transfer. This stalls // until after any transfer is complete, so the address will not change anymore. + #[cfg(feature = "rp2040")] const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x13000000 as *const _; + #[cfg(feature = "_rp235x")] + const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x14000000 as *const _; unsafe { core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE); } @@ -225,12 +232,14 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI } /// Read SPI flash unique ID + #[cfg(feature = "rp2040")] pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? }; Ok(()) } /// Read SPI flash JEDEC ID + #[cfg(feature = "rp2040")] pub fn blocking_jedec_id(&mut self) -> Result { let mut jedec = None; unsafe { @@ -301,7 +310,10 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { // Use the XIP AUX bus port, rather than the FIFO register access (e.x. // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on // general XIP access. + #[cfg(feature = "rp2040")] const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _; + #[cfg(feature = "_rp235x")] + const XIP_AUX_BASE: *const u32 = 0x50500000 as *const _; let transfer = unsafe { crate::dma::read( self.dma.as_mut().unwrap(), @@ -510,19 +522,14 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase(addr: u32, len: u32) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { + let ptrs = if USE_BOOT2 { #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, false, &boot2) - } else { - flash_function_pointers(true, false) - } - } + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] + core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); + flash_function_pointers_with_boot2(true, false, &boot2) + } else { flash_function_pointers(true, false) }; @@ -548,19 +555,14 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { + let ptrs = if USE_BOOT2 { #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, true, &boot2) - } else { - flash_function_pointers(true, true) - } - } + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] + core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, (boot2).as_mut_ptr() as *mut u8, 256); + flash_function_pointers_with_boot2(true, true, &boot2) + } else { flash_function_pointers(true, true) }; @@ -591,19 +593,14 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_program(addr: u32, data: &[u8]) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { + let ptrs = if USE_BOOT2 { #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, true, &boot2) - } else { - flash_function_pointers(false, true) - } - } + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] + core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); + flash_function_pointers_with_boot2(false, true, &boot2) + } else { flash_function_pointers(false, true) }; @@ -630,16 +627,7 @@ mod ram_helpers { #[link_section = ".data.ram_func"] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { - /* - Should be equivalent to: - rom_data::connect_internal_flash(); - rom_data::flash_exit_xip(); - rom_data::flash_range_erase(addr, len, 1 << 31, 0); // if selected - rom_data::flash_range_program(addr, data as *const _, len); // if selected - rom_data::flash_flush_cache(); - rom_data::flash_enter_cmd_xip(); - */ - #[cfg(target_arch = "arm")] + //#[cfg(target_arch = "arm")] core::arch::asm!( "mov r8, r0", "mov r9, r2", @@ -691,11 +679,30 @@ mod ram_helpers { ); } + /// # Safety + /// + /// Nothing must access flash while this is running. + /// Usually this means: + /// - interrupts must be disabled + /// - 2nd core must be running code from RAM or ROM with interrupts disabled + /// - DMA must not access flash memory + /// Length of data must be a multiple of 4096 + /// addr must be aligned to 4096 #[inline(never)] #[link_section = ".data.ram_func"] #[cfg(feature = "_rp235x")] - unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) { - todo!(); + unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { + let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()); + ((*ptrs).connect_internal_flash)(); + ((*ptrs).flash_exit_xip)(); + if (*ptrs).flash_range_erase.is_some() { + ((*ptrs).flash_range_erase.unwrap())(addr, len as usize, 1 << 31, 0); + } + if (*ptrs).flash_range_program.is_some() { + ((*ptrs).flash_range_program.unwrap())(addr, data as *const _, len as usize); + } + ((*ptrs).flash_flush_cache)(); + ((*ptrs).flash_enter_cmd_xip)(); } #[repr(C)] @@ -731,20 +738,13 @@ mod ram_helpers { /// - DMA must not access flash memory /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) + #[cfg(feature = "rp2040")] pub unsafe fn flash_unique_id(out: &mut [u8]) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { - #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { - flash_function_pointers(false, false) - } - } - #[cfg(feature = "_rp235x")] + let ptrs = if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { flash_function_pointers(false, false) }; @@ -768,20 +768,13 @@ mod ram_helpers { /// - DMA must not access flash memory /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) + #[cfg(feature = "rp2040")] pub unsafe fn flash_jedec_id() -> u32 { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { - #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { - flash_function_pointers(false, false) - } - } - #[cfg(feature = "_rp235x")] + let ptrs = if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { flash_function_pointers(false, false) }; @@ -792,6 +785,7 @@ mod ram_helpers { u32::from_be_bytes(id) } + #[cfg(feature = "rp2040")] unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) { read_flash_inner( FlashCommand { @@ -932,13 +926,6 @@ mod ram_helpers { clobber_abi("C"), ); } - - #[inline(never)] - #[link_section = ".data.ram_func"] - #[cfg(feature = "_rp235x")] - unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) { - todo!(); - } } /// Make sure to uphold the contract points with rp2040-flash. diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index c2c57eaa0..f8fcfe52b 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -402,7 +402,7 @@ embassy_hal_internal::peripherals! { BOOTSEL, } -#[cfg(not(feature = "boot2-none"))] +#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))] macro_rules! select_bootloader { ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { $( @@ -419,7 +419,7 @@ macro_rules! select_bootloader { } } -#[cfg(not(feature = "boot2-none"))] +#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))] select_bootloader! { "boot2-at25sf128a" => BOOT_LOADER_AT25SF128A, "boot2-gd25q64cs" => BOOT_LOADER_GD25Q64CS, diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml index f77e004dc..9a92b1ce2 100644 --- a/examples/rp23/.cargo/config.toml +++ b/examples/rp23/.cargo/config.toml @@ -1,6 +1,7 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] #runner = "probe-rs run --chip RP2040" -runner = "elf2uf2-rs -d" +#runner = "elf2uf2-rs -d" +runner = "picotool load -u -v -x -t elf" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 811561f26..84011e394 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -21,7 +21,7 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info::rp_program_name!(c"example"), embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_description!(c"Flash"), embassy_rp::binary_info::rp_program_build_attribute!(), ]; @@ -41,22 +41,13 @@ async fn main(_spawner: Spawner) { let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); - // Get JEDEC id - let jedec = flash.blocking_jedec_id().unwrap(); - info!("jedec id: 0x{:x}", jedec); - - // Get unique id - let mut uid = [0; 8]; - flash.blocking_unique_id(&mut uid).unwrap(); - info!("unique id: {:?}", uid); - erase_write_sector(&mut flash, 0x00); multiwrite_bytes(&mut flash, ERASE_SIZE as u32); background_read(&mut flash, (ERASE_SIZE * 2) as u32).await; - loop {} + info!("Flash Works!"); } fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { @@ -82,7 +73,7 @@ fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); info!("Contents after write starts with {=[u8]}", read_buf[0..4]); - if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { + if read_buf[0..4] != [0x01, 0x02, 0x03, 0x04] { defmt::panic!("unexpected"); } } From abcb39a58b63c32e91b748d4380f4f6492fd28cb Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Thu, 29 Aug 2024 17:32:43 +0200 Subject: [PATCH 133/210] Allow bos_descriptor_buf to be a zero-length slice --- embassy-usb/src/descriptor.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index f1773fa8a..c4d79e39f 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -308,6 +308,9 @@ impl<'a> BosWriter<'a> { } pub(crate) fn bos(&mut self) { + if (self.writer.buf.len() - self.writer.position) < 5 { + return; + } self.num_caps_mark = Some(self.writer.position + 4); self.writer.write( descriptor_type::BOS, @@ -350,6 +353,9 @@ impl<'a> BosWriter<'a> { } pub(crate) fn end_bos(&mut self) { + if self.writer.position == 0 { + return; + } self.num_caps_mark = None; let position = self.writer.position as u16; self.writer.buf[2..4].copy_from_slice(&position.to_le_bytes()); From 0434798439b9037a4fa5f30165879292e388f042 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 29 Aug 2024 12:28:23 -0400 Subject: [PATCH 134/210] Import otp from rp-hal, helper fns for chipid and randid Again, credit to @thejpster for doing the hard part and figuring out the otp. --- embassy-rp/src/lib.rs | 2 + embassy-rp/src/otp.rs | 108 +++++++++++++++++++++++++++++++++++ examples/rp23/src/bin/otp.rs | 46 +++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 embassy-rp/src/otp.rs create mode 100644 examples/rp23/src/bin/otp.rs diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index f8fcfe52b..c357c14c2 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -32,6 +32,8 @@ pub mod gpio; pub mod i2c; pub mod i2c_slave; pub mod multicore; +#[cfg(feature = "_rp235x")] +pub mod otp; pub mod pwm; mod reset; pub mod rom_data; diff --git a/embassy-rp/src/otp.rs b/embassy-rp/src/otp.rs new file mode 100644 index 000000000..cdaf5bded --- /dev/null +++ b/embassy-rp/src/otp.rs @@ -0,0 +1,108 @@ +//! Interface to the RP2350's One Time Programmable Memory + +// Credit: taken from `rp-hal` (also licensed Apache+MIT) +// https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs + +/// The ways in which we can fail to read OTP +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// The user passed an invalid index to a function. + InvalidIndex, + /// The hardware refused to let us read this word, probably due to + /// read lock set earlier in the boot process. + InvalidPermissions, +} + +/// OTP read address, using automatic Error Correction. +/// +/// A 32-bit read returns the ECC-corrected data for two neighbouring rows, or +/// all-ones on permission failure. Only the first 8 KiB is populated. +pub const OTP_DATA_BASE: *const u32 = 0x4013_0000 as *const u32; + +/// OTP read address, without using any automatic Error Correction. +/// +/// A 32-bit read returns 24-bits of raw data from the OTP word. +pub const OTP_DATA_RAW_BASE: *const u32 = 0x4013_4000 as *const u32; + +/// How many pages in OTP (post error-correction) +pub const NUM_PAGES: usize = 64; + +/// How many rows in one page in OTP (post error-correction) +pub const NUM_ROWS_PER_PAGE: usize = 64; + +/// How many rows in OTP (post error-correction) +pub const NUM_ROWS: usize = NUM_PAGES * NUM_ROWS_PER_PAGE; + +/// Read one ECC protected word from the OTP +pub fn read_ecc_word(row: usize) -> Result { + if row >= NUM_ROWS { + return Err(Error::InvalidIndex); + } + // First do a raw read to check permissions + let _ = read_raw_word(row)?; + // One 32-bit read gets us two rows + let offset = row >> 1; + // # Safety + // + // We checked this offset was in range already. + let value = unsafe { OTP_DATA_BASE.add(offset).read() }; + if (row & 1) == 0 { + Ok(value as u16) + } else { + Ok((value >> 16) as u16) + } +} + +/// Read one raw word from the OTP +/// +/// You get the 24-bit raw value in the lower part of the 32-bit result. +pub fn read_raw_word(row: usize) -> Result { + if row >= NUM_ROWS { + return Err(Error::InvalidIndex); + } + // One 32-bit read gets us one row + // # Safety + // + // We checked this offset was in range already. + let value = unsafe { OTP_DATA_RAW_BASE.add(row).read() }; + if value == 0xFFFF_FFFF { + Err(Error::InvalidPermissions) + } else { + Ok(value) + } +} + +/// Get the random 64bit chipid from rows 0x0-0x3. +pub fn get_chipid() -> Result { + let w0 = read_ecc_word(0x000)?.to_be_bytes(); + let w1 = read_ecc_word(0x001)?.to_be_bytes(); + let w2 = read_ecc_word(0x002)?.to_be_bytes(); + let w3 = read_ecc_word(0x003)?.to_be_bytes(); + + Ok(u64::from_be_bytes([ + w3[0], w3[1], w2[0], w2[1], w1[0], w1[1], w0[0], w0[1], + ])) +} + +/// Get the 128bit private random number from rows 0x4-0xb. +/// +/// This ID is not exposed through the USB PICOBOOT GET_INFO command +/// or the ROM get_sys_info() API. However note that the USB PICOBOOT OTP +/// access point can read the entirety of page 0, so this value is not +/// meaningfully private unless the USB PICOBOOT interface is disabled via the +//// DISABLE_BOOTSEL_USB_PICOBOOT_IFC flag in BOOT_FLAGS0 +pub fn get_private_random_number() -> Result { + let w0 = read_ecc_word(0x004)?.to_be_bytes(); + let w1 = read_ecc_word(0x005)?.to_be_bytes(); + let w2 = read_ecc_word(0x006)?.to_be_bytes(); + let w3 = read_ecc_word(0x007)?.to_be_bytes(); + let w4 = read_ecc_word(0x008)?.to_be_bytes(); + let w5 = read_ecc_word(0x009)?.to_be_bytes(); + let w6 = read_ecc_word(0x00a)?.to_be_bytes(); + let w7 = read_ecc_word(0x00b)?.to_be_bytes(); + + Ok(u128::from_be_bytes([ + w7[0], w7[1], w6[0], w6[1], w5[0], w5[1], w4[0], w4[1], w3[0], w3[1], w2[0], w2[1], w1[0], w1[1], w0[0], w0[1], + ])) +} diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs new file mode 100644 index 000000000..c4d79c6ea --- /dev/null +++ b/examples/rp23/src/bin/otp.rs @@ -0,0 +1,46 @@ +//! This example shows reading the OTP constants on the RP235x. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; +use embassy_rp::otp; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"OTP Read Example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"OTP Read Example"), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _ = embassy_rp::init(Default::default()); + // + // add some delay to give an attached debug probe time to parse the + // defmt RTT header. Reading that header might touch flash memory, which + // interferes with flash write operations. + // https://github.com/knurling-rs/defmt/pull/683 + Timer::after_millis(10).await; + + let unique_id = unwrap!(otp::get_unique_id()); + info!("Unique id:{:X}", unique_id); + + let private_rand = unwrap!(otp::get_private_random_number()); + info!("Private Rand:{:X}", private_rand); + + loop { + Timer::after_secs(1).await; + } +} From 4c07c356e44020d39bc27d44d24272ad369426c3 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 29 Aug 2024 21:35:57 -0400 Subject: [PATCH 135/210] Fixup: forgot to rename fn in example --- examples/rp23/src/bin/otp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs index c4d79c6ea..106e514ca 100644 --- a/examples/rp23/src/bin/otp.rs +++ b/examples/rp23/src/bin/otp.rs @@ -34,8 +34,8 @@ async fn main(_spawner: Spawner) { // https://github.com/knurling-rs/defmt/pull/683 Timer::after_millis(10).await; - let unique_id = unwrap!(otp::get_unique_id()); - info!("Unique id:{:X}", unique_id); + let chip_id = unwrap!(otp::get_chipid()); + info!("Unique id:{:X}", chip_id); let private_rand = unwrap!(otp::get_private_random_number()); info!("Private Rand:{:X}", private_rand); From 82f274ea097c4aef35cb452d94654f94ab549895 Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Mon, 2 Sep 2024 12:05:33 +0200 Subject: [PATCH 136/210] stm32: add f2 flash support (blocking) --- embassy-stm32/src/flash/f2.rs | 142 +++++++++++++++++++++++++++++++++ embassy-stm32/src/flash/mod.rs | 5 +- 2 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32/src/flash/f2.rs diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs new file mode 100644 index 000000000..cdab1fd2d --- /dev/null +++ b/embassy-stm32/src/flash/f2.rs @@ -0,0 +1,142 @@ +use core::ptr::write_volatile; +use core::sync::atomic::{fence, AtomicBool, Ordering}; + +use pac::flash::regs::Sr; + +use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use crate::flash::Error; +use crate::pac; + +static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false); + +impl FlashSector { + const fn snb(&self) -> u8 { + ((self.bank as u8) << 4) + self.index_in_bank + } +} + +pub(crate) const fn is_default_layout() -> bool { + true +} + +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + +pub(crate) unsafe fn lock() { + pac::FLASH.cr().modify(|w| w.set_lock(true)); +} + +pub(crate) unsafe fn unlock() { + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); + } +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); + save_data_cache_state(); + + pac::FLASH.cr().write(|w| { + w.set_pg(true); + w.set_psize(pac::flash::vals::Psize::PSIZE32); + }); +} + +pub(crate) unsafe fn disable_blocking_write() { + pac::FLASH.cr().write(|w| w.set_pg(false)); + restore_data_cache_state(); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + write_start(start_address, buf); + blocking_wait_ready() +} + +unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into()))); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + save_data_cache_state(); + + trace!("Blocking erasing sector number {}", sector.snb()); + + pac::FLASH.cr().modify(|w| { + w.set_ser(true); + w.set_snb(sector.snb()) + }); + + pac::FLASH.cr().modify(|w| { + w.set_strt(true); + }); + + let ret: Result<(), Error> = blocking_wait_ready(); + clear_all_err(); + restore_data_cache_state(); + ret +} + +pub(crate) unsafe fn clear_all_err() { + // read and write back the same value. + // This clears all "write 1 to clear" bits. + pac::FLASH.sr().modify(|_| {}); +} + +unsafe fn blocking_wait_ready() -> Result<(), Error> { + loop { + let sr = pac::FLASH.sr().read(); + + if !sr.bsy() { + return get_result(sr); + } + } +} + +fn get_result(sr: Sr) -> Result<(), Error> { + if sr.pgserr() { + Err(Error::Seq) + } else if sr.pgperr() { + Err(Error::Parallelism) + } else if sr.pgaerr() { + Err(Error::Unaligned) + } else if sr.wrperr() { + Err(Error::Protected) + } else { + Ok(()) + } +} + +fn save_data_cache_state() { + let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2; + if dual_bank { + // Disable data cache during write/erase if there are two banks, see errata 2.2.12 + let dcen = pac::FLASH.acr().read().dcen(); + DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); + if dcen { + pac::FLASH.acr().modify(|w| w.set_dcen(false)); + } + } +} + +fn restore_data_cache_state() { + let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2; + if dual_bank { + // Restore data cache if it was enabled + let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); + if dcen { + // Reset data cache before we enable it again + pac::FLASH.acr().modify(|w| w.set_dcrst(true)); + pac::FLASH.acr().modify(|w| w.set_dcrst(false)); + pac::FLASH.acr().modify(|w| w.set_dcen(true)) + } + } +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index ce2d1a04c..bce638db0 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -94,6 +94,7 @@ pub enum FlashBank { #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f0, path = "f0.rs")] #[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] +#[cfg_attr(flash_f2, path = "f2.rs")] #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] @@ -104,8 +105,8 @@ pub enum FlashBank { #[cfg_attr(flash_u0, path = "u0.rs")] #[cfg_attr( not(any( - flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, - flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 + flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, flash_f7, + flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 )), path = "other.rs" )] From b277f42c9d681ce3c929858adffcefbdb7adabef Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Mon, 2 Sep 2024 22:07:49 +0200 Subject: [PATCH 137/210] nrf52840: fix naming of LED states in examples (#3304) The LEDs on the nrf52840 DK are active low. --- examples/nrf52840/src/bin/channel.rs | 4 ++-- examples/nrf52840/src/bin/channel_sender_receiver.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs index 7fcea9dbd..e06ba1c73 100644 --- a/examples/nrf52840/src/bin/channel.rs +++ b/examples/nrf52840/src/bin/channel.rs @@ -35,8 +35,8 @@ async fn main(spawner: Spawner) { loop { match CHANNEL.receive().await { - LedState::On => led.set_high(), - LedState::Off => led.set_low(), + LedState::On => led.set_low(), + LedState::Off => led.set_high(), } } } diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs index 3095a04ec..29f70f91c 100644 --- a/examples/nrf52840/src/bin/channel_sender_receiver.rs +++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs @@ -33,8 +33,8 @@ async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedSta loop { match receiver.receive().await { - LedState::On => led.set_high(), - LedState::Off => led.set_low(), + LedState::On => led.set_low(), + LedState::Off => led.set_high(), } } } From 32cff6530fdb81066451cc1d3f1fbbb420e985da Mon Sep 17 00:00:00 2001 From: Lucas Martins Mendes Date: Tue, 3 Sep 2024 16:02:39 -0300 Subject: [PATCH 138/210] chore: fix using default_features instead of default-features in embassy boot dependency (#3306) --- embassy-boot/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 85b3695a1..d27fe763e 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -27,7 +27,7 @@ features = ["defmt"] defmt = { version = "0.3", optional = true } digest = "0.10" log = { version = "0.4", optional = true } -ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true } +ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true } embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embedded-storage = "0.3.1" @@ -42,7 +42,7 @@ rand = "0.8" futures = { version = "0.3", features = ["executor"] } sha1 = "0.10.5" critical-section = { version = "1.1.1", features = ["std"] } -ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] } +ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core", "digest"] } [features] ed25519-dalek = ["dep:ed25519-dalek", "_verify"] From a6db8678eb5a7c9ebcf6449799b4ff525fe52d5f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 11:04:36 +0200 Subject: [PATCH 139/210] Add utility for setting configuration for a context --- embassy-net-nrf91/src/at.rs | 45 ----- embassy-net-nrf91/src/context.rs | 196 +++++++++++++++++++ embassy-net-nrf91/src/lib.rs | 2 + examples/nrf9160/src/bin/modem_tcp_client.rs | 64 +++--- 4 files changed, 220 insertions(+), 87 deletions(-) delete mode 100644 embassy-net-nrf91/src/at.rs create mode 100644 embassy-net-nrf91/src/context.rs diff --git a/embassy-net-nrf91/src/at.rs b/embassy-net-nrf91/src/at.rs deleted file mode 100644 index 04cbf3876..000000000 --- a/embassy-net-nrf91/src/at.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::{Error, Control}; - -// Drives the control loop of the modem based on declarative configuration. -pub struct AtDriver<'a> { - control: Control<'a>, - config: Config, -} - -pub struct Config { - pub network: NetworkConfig, -} - -pub struct NetworkConfig { - pub apn: &'static str, - pub prot: AuthProtection, - pub userid: &'static str, - pub password: &'static str, -} - -#[repr(u8)] -pub enum AuthProtection { - None = 0, - Pap = 1, - Chap = 2, -} - -impl<'a> AtDriver<'a> { - pub async fn new(control: Control<'a>, config: Config) -> Result { - control.wait_init().await; - Ok(Self { - control, - config, - }) - } - - async fn setup(&self) -> Result<(), Error> { - - } - - pub fn run(&self, stack: Stack>) -> ! { - loop { - - } - } -} diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs new file mode 100644 index 000000000..6dda51793 --- /dev/null +++ b/embassy-net-nrf91/src/context.rs @@ -0,0 +1,196 @@ +use core::net::IpAddr; +use heapless::String; +use core::str::FromStr; +use core::fmt::Write; + +/// Provides a higher level API for configuring and reading information for a given +/// context id. +pub struct Control<'a> { + control: crate::Control<'a>, + cid: u8, +} + +pub struct Config<'a> { + pub gateway: &'a str, + pub auth_prot: AuthProt, + pub auth: Option<(&'a str, &'a str)>, +} + +#[repr(u8)] +pub enum AuthProt { + None = 0, + Pap = 1, + Chap = 2, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + BufferTooSmall, + AtCommand, + AddrParseError, + Format, +} + +impl From for Error { + fn from(_: core::fmt::Error) -> Self { + Self::Format + } +} + +#[derive(PartialEq, Debug)] +pub struct Status { + pub attached: bool, + pub ip: Option, +} + +#[cfg(feature = "defmt")] +impl defmt::Format for Status { + fn format(&self, f: defmt::Formatter<'_>) { + defmt::write!(f, "attached: {}", self.attached); + if let Some(ip) = &self.ip { + defmt::write!(f, ", ip: {}", defmt::Debug2Format(&ip)); + } + } +} + +impl<'a> Control<'a> { + pub async fn new(control: crate::Control<'a>, cid: u8) -> Self { + control.wait_init().await; + Self { control, cid } + } + + /// Bypass modem configurator + pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { + self.control.at_command(req, resp).await + } + + /// Configures the modem with the provided config. + pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { + let mut cmd: String<128> = String::new(); + let mut buf: [u8; 256] = [0; 256]; + + write!(cmd, "AT+CGDCONT={},\"IP\",\"{}\"", self.cid, config.gateway).map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; + let mut res = &buf[..n]; + let res = split_field(&mut res); + if res != b"OK" { + return Err(Error::AtCommand) + } + cmd.clear(); + + write!(cmd, "AT+CGAUTH={},{}", self.cid, config.auth_prot as u8)?; + if let Some((username, password)) = config.auth { + write!(cmd, ",\"{}\",\"{}\"", username, password).map_err(|_| Error::BufferTooSmall)?; + } + let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; + let mut res = &buf[..n]; + let res = split_field(&mut res); + if res != b"OK" { + return Err(Error::AtCommand) + } + cmd.clear(); + + let n = self.control.at_command(b"AT+CFUN=1", &mut buf).await; + let mut res = &buf[..n]; + let res = split_field(&mut res); + if res != b"OK" { + return Err(Error::AtCommand); + } + + Ok(()) + } + + pub async fn status(&self) -> Result { + let mut buf: [u8; 256] = [0; 256]; + let n = self.control.at_command(b"AT+CGATT?", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGATT: "); + let res = split_field(&mut res); + let attached = res == b"1"; + + if !attached { + return Ok(Status { attached, ip: None }) + } + + let mut s: String<128> = String::new(); + write!(s, "AT+CGPADDR={}", self.cid)?; + let n = self.control.at_command(s.as_bytes(), &mut buf).await; + let mut res = &buf[..n]; + s.clear(); + + write!(s, "+CGPADDR: {},", self.cid)?; + + info!("RES: {:?}", unsafe {core::str::from_utf8_unchecked(res)}); + if s.len() > res.len() { + let res = split_field(&mut res); + if res == b"OK" { + Ok(Status { attached, ip: None }) + } else { + Err(Error::AtCommand) + } + } else { + pop_prefix(&mut res, s.as_bytes()); + + let ip = split_field(&mut res); + if !ip.is_empty() { + let ip = IpAddr::from_str(unsafe { core::str::from_utf8_unchecked(ip) }).map_err(|_| Error::AddrParseError)?; + self.control.open_raw_socket().await; + Ok(Status { attached, ip: Some(ip) }) + } else { + Ok(Status { attached, ip: None }) + } + } + } +} + +pub(crate) fn is_whitespace(char: u8) -> bool { + match char { + b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +pub(crate) fn is_separator(char: u8) -> bool { + match char { + b',' | b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +pub(crate) fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { + while !data.is_empty() && is_whitespace(data[0]) { + *data = &data[1..]; + } + + if data.is_empty() { + return &[]; + } + + if data[0] == b'"' { + let data2 = &data[1..]; + let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); + let field = &data2[..end]; + let mut rest = &data2[data2.len().min(end + 1)..]; + if rest.first() == Some(&b'\"') { + rest = &rest[1..]; + } + while !rest.is_empty() && is_separator(rest[0]) { + rest = &rest[1..]; + } + *data = rest; + field + } else { + let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); + let field = &data[0..end]; + let rest = &data[data.len().min(end + 1)..]; + *data = rest; + field + } +} + +pub(crate) fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { + assert!(data.len() >= prefix.len()); + assert!(&data[..prefix.len()] == prefix); + *data = &data[prefix.len()..]; +} diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 70ad176da..beed7c65a 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -6,6 +6,8 @@ // must be first mod fmt; +pub mod context; + use core::cell::RefCell; use core::future::poll_fn; use core::marker::PhantomData; diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index b1dac18a1..817ad17c7 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -2,14 +2,15 @@ #![no_main] use core::mem::MaybeUninit; +use core::net::IpAddr; use core::ptr::addr_of_mut; use core::str::FromStr; use core::{slice, str}; -use defmt::{assert, *}; +use defmt::{assert, info, warn, unwrap}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; -use embassy_net_nrf91::{Runner, State}; +use embassy_net_nrf91::{Runner, State, context}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; use embassy_nrf::uarte::Baudrate; @@ -63,9 +64,9 @@ async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); loop { led.set_high(); - Timer::after_millis(100).await; + Timer::after_millis(1000).await; led.set_low(); - Timer::after_millis(100).await; + Timer::after_millis(1000).await; } } @@ -123,51 +124,30 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - control.wait_init().await; - info!("INIT OK"); + let control = context::Control::new(control, 0).await; - let mut buf = [0u8; 256]; - - let n = control.at_command(b"AT+CFUN?", &mut buf).await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - - let n = control - .at_command(b"AT+CGDCONT=0,\"IP\",\"iot.nat.es\"", &mut buf) - .await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - let n = control - .at_command(b"AT+CGAUTH=0,1,\"orange\",\"orange\"", &mut buf) - .await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - - let n = control.at_command(b"AT+CFUN=1", &mut buf).await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + unwrap!(control.configure(context::Config { + gateway: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }).await); info!("waiting for attach..."); - loop { - Timer::after_millis(500).await; - let n = control.at_command(b"AT+CGATT?", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGATT: "); - let res = split_field(&mut res); - info!("AT resp field: '{}'", unsafe { str::from_utf8_unchecked(res) }); - if res == b"1" { - break; - } + + let mut status = unwrap!(control.status().await); + while !status.attached && status.ip.is_none() { + Timer::after_millis(1000).await; + status = unwrap!(control.status().await); + info!("STATUS: {:?}", status); } - let n = control.at_command(b"AT+CGPADDR=0", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGPADDR: 0,"); - let ip = split_field(&mut res); - let ip = Ipv4Address::from_str(unsafe { str::from_utf8_unchecked(ip) }).unwrap(); - info!("IP: '{}'", ip); - - info!("============== OPENING SOCKET"); - control.open_raw_socket().await; + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(ip, 32), + address: Ipv4Cidr::new(addr, 32), gateway: None, dns_servers: Default::default(), })); From aabdd45424ae71550be542a3a62872b33a4e0717 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 11:09:27 +0200 Subject: [PATCH 140/210] remove debug logging --- embassy-net-nrf91/src/context.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 6dda51793..c47b1ade6 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -121,7 +121,6 @@ impl<'a> Control<'a> { write!(s, "+CGPADDR: {},", self.cid)?; - info!("RES: {:?}", unsafe {core::str::from_utf8_unchecked(res)}); if s.len() > res.len() { let res = split_field(&mut res); if res == b"OK" { From b76b7ca9f5d64e83f7f69a6f7d97ba605ab2af7f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 12:58:33 +0200 Subject: [PATCH 141/210] Use at-commands crate and support DNS * Use at-commands for building and parsing AT commands which has better error handling. * Retrieve DNS servers * Retrieve gateway * Update example to configure embassy-net with retrieved parameters. --- embassy-net-nrf91/Cargo.toml | 1 + embassy-net-nrf91/src/context.rs | 202 ++++++++++--------- examples/nrf9160/Cargo.toml | 1 + examples/nrf9160/src/bin/modem_tcp_client.rs | 78 ++----- 4 files changed, 126 insertions(+), 156 deletions(-) diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index e2d596d59..07a0c8886 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -26,6 +26,7 @@ embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver- heapless = "0.8" embedded-io = "0.6.1" +at-commands = "0.5.4" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-nrf91-v$VERSION/embassy-net-nrf91/src/" diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index c47b1ade6..b532dca14 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -2,6 +2,8 @@ use core::net::IpAddr; use heapless::String; use core::str::FromStr; use core::fmt::Write; +use heapless::Vec; +use at_commands::{builder::CommandBuilder, parser::CommandParser}; /// Provides a higher level API for configuring and reading information for a given /// context id. @@ -28,10 +30,17 @@ pub enum AuthProt { pub enum Error { BufferTooSmall, AtCommand, + AtParseError, AddrParseError, Format, } +impl From for Error { + fn from(_: at_commands::parser::ParseError) -> Self { + Self::AtParseError + } +} + impl From for Error { fn from(_: core::fmt::Error) -> Self { Self::Format @@ -42,6 +51,8 @@ impl From for Error { pub struct Status { pub attached: bool, pub ip: Option, + pub gateway: Option, + pub dns: Vec, } #[cfg(feature = "defmt")] @@ -67,129 +78,122 @@ impl<'a> Control<'a> { /// Configures the modem with the provided config. pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { - let mut cmd: String<128> = String::new(); + let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; - write!(cmd, "AT+CGDCONT={},\"IP\",\"{}\"", self.cid, config.gateway).map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; - let mut res = &buf[..n]; - let res = split_field(&mut res); - if res != b"OK" { - return Err(Error::AtCommand) - } - cmd.clear(); + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGDCONT") + .with_int_parameter(self.cid) + .with_string_parameter("IP") + .with_string_parameter(config.gateway) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - write!(cmd, "AT+CGAUTH={},{}", self.cid, config.auth_prot as u8)?; + let mut op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGAUTH") + .with_int_parameter(self.cid) + .with_int_parameter(config.auth_prot as u8); if let Some((username, password)) = config.auth { - write!(cmd, ",\"{}\",\"{}\"", username, password).map_err(|_| Error::BufferTooSmall)?; + op = op.with_string_parameter(username).with_string_parameter(password); } - let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; - let mut res = &buf[..n]; - let res = split_field(&mut res); - if res != b"OK" { - return Err(Error::AtCommand) - } - cmd.clear(); + let op = op.finish().map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(b"AT+CFUN=1", &mut buf).await; - let mut res = &buf[..n]; - let res = split_field(&mut res); - if res != b"OK" { - return Err(Error::AtCommand); - } + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(1) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; Ok(()) } pub async fn status(&self) -> Result { + let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; - let n = self.control.at_command(b"AT+CGATT?", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGATT: "); - let res = split_field(&mut res); - let attached = res == b"1"; + let op = CommandBuilder::create_query(&mut cmd, true) + .named("+CGATT") + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (res, ) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGATT: ") + .expect_int_parameter() + .expect_identifier(b"\r\nOK").finish()?; + let attached = res == 1; if !attached { - return Ok(Status { attached, ip: None }) + return Ok(Status { attached, ip: None, gateway: None, dns: Vec::new() }) } - let mut s: String<128> = String::new(); - write!(s, "AT+CGPADDR={}", self.cid)?; - let n = self.control.at_command(s.as_bytes(), &mut buf).await; - let mut res = &buf[..n]; - s.clear(); + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGPADDR") + .with_int_parameter(self.cid) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (_, ip1, ip2, ) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGPADDR: ") + .expect_int_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_identifier(b"\r\nOK").finish()?; - write!(s, "+CGPADDR: {},", self.cid)?; + let ip = if let Some(ip) = ip1 { + let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?; + self.control.open_raw_socket().await; + Some(ip) + } else { + None + }; - if s.len() > res.len() { - let res = split_field(&mut res); - if res == b"OK" { - Ok(Status { attached, ip: None }) + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGCONTRDP") + .with_int_parameter(self.cid) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, mtu) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGCONTRDP: ") + .expect_int_parameter() + .expect_optional_int_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_identifier(b"\r\nOK").finish()?; + + let gateway = if let Some(ip) = gateway { + if ip.is_empty() { + None } else { - Err(Error::AtCommand) + Some(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?) } } else { - pop_prefix(&mut res, s.as_bytes()); + None + }; - let ip = split_field(&mut res); - if !ip.is_empty() { - let ip = IpAddr::from_str(unsafe { core::str::from_utf8_unchecked(ip) }).map_err(|_| Error::AddrParseError)?; - self.control.open_raw_socket().await; - Ok(Status { attached, ip: Some(ip) }) - } else { - Ok(Status { attached, ip: None }) - } + let mut dns = Vec::new(); + if let Some(ip) = dns1 { + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); } - } -} -pub(crate) fn is_whitespace(char: u8) -> bool { - match char { - b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -pub(crate) fn is_separator(char: u8) -> bool { - match char { - b',' | b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -pub(crate) fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { - while !data.is_empty() && is_whitespace(data[0]) { - *data = &data[1..]; - } - - if data.is_empty() { - return &[]; - } - - if data[0] == b'"' { - let data2 = &data[1..]; - let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); - let field = &data2[..end]; - let mut rest = &data2[data2.len().min(end + 1)..]; - if rest.first() == Some(&b'\"') { - rest = &rest[1..]; + if let Some(ip) = dns2 { + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); } - while !rest.is_empty() && is_separator(rest[0]) { - rest = &rest[1..]; - } - *data = rest; - field - } else { - let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); - let field = &data[0..end]; - let rest = &data[data.len().min(end + 1)..]; - *data = rest; - field + + Ok(Status { + attached, + ip, + gateway, + dns, + }) } } - -pub(crate) fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { - assert!(data.len() >= prefix.len()); - assert!(&data[..prefix.len()] == prefix); - *data = &data[prefix.len()..]; -} diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index fc24e99d2..9aeb99317 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -14,6 +14,7 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm defmt = "0.3" defmt-rtt = "0.4" +heapless = "0.8" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 817ad17c7..f80861693 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -5,9 +5,10 @@ use core::mem::MaybeUninit; use core::net::IpAddr; use core::ptr::addr_of_mut; use core::str::FromStr; -use core::{slice, str}; +use core::slice; use defmt::{assert, info, warn, unwrap}; +use heapless::Vec; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; use embassy_net_nrf91::{Runner, State, context}; @@ -146,10 +147,23 @@ async fn main(spawner: Spawner) { }; let addr = Ipv4Address(addr.octets()); + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { address: Ipv4Cidr::new(addr, 32), - gateway: None, - dns_servers: Default::default(), + gateway, + dns_servers, })); let mut rx_buffer = [0; 4096]; @@ -159,15 +173,16 @@ async fn main(spawner: Spawner) { socket.set_timeout(Some(Duration::from_secs(10))); info!("Connecting..."); - let host_addr = embassy_net::Ipv4Address::from_str("83.51.182.206").unwrap(); - if let Err(e) = socket.connect((host_addr, 8000)).await { + let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); + if let Err(e) = socket.connect((host_addr, 4242)).await { warn!("connect error: {:?}", e); + Timer::after_secs(1).await; continue; } info!("Connected to {:?}", socket.remote_endpoint()); let msg = b"Hello world!\n"; - loop { + for _ in 0..10 { if let Err(e) = socket.write_all(msg).await { warn!("write error: {:?}", e); break; @@ -177,54 +192,3 @@ async fn main(spawner: Spawner) { } } } - -fn is_whitespace(char: u8) -> bool { - match char { - b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -fn is_separator(char: u8) -> bool { - match char { - b',' | b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { - while !data.is_empty() && is_whitespace(data[0]) { - *data = &data[1..]; - } - - if data.is_empty() { - return &[]; - } - - if data[0] == b'"' { - let data2 = &data[1..]; - let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); - let field = &data2[..end]; - let mut rest = &data2[data2.len().min(end + 1)..]; - if rest.first() == Some(&b'\"') { - rest = &rest[1..]; - } - while !rest.is_empty() && is_separator(rest[0]) { - rest = &rest[1..]; - } - *data = rest; - field - } else { - let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); - let field = &data[0..end]; - let rest = &data[data.len().min(end + 1)..]; - *data = rest; - field - } -} - -fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { - assert!(data.len() >= prefix.len()); - assert!(&data[..prefix.len()] == prefix); - *data = &data[prefix.len()..]; -} From 5e27a3e64f46340e50bc6f61e6ef5a89e9f077ab Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 13:09:27 +0200 Subject: [PATCH 142/210] Document public API and fix warnings --- embassy-net-nrf91/src/context.rs | 48 +++++++++++--------- examples/nrf9160/src/bin/modem_tcp_client.rs | 6 +-- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index b532dca14..9c67cbc9f 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -1,38 +1,46 @@ +//! Helper utility to configure a specific modem context. use core::net::IpAddr; -use heapless::String; use core::str::FromStr; -use core::fmt::Write; use heapless::Vec; use at_commands::{builder::CommandBuilder, parser::CommandParser}; -/// Provides a higher level API for configuring and reading information for a given -/// context id. +/// Provides a higher level API for controlling a given context. pub struct Control<'a> { control: crate::Control<'a>, cid: u8, } +/// Configuration for a given context pub struct Config<'a> { - pub gateway: &'a str, + /// Desired APN address. + pub apn: &'a str, + /// Desired authentication protocol. pub auth_prot: AuthProt, + /// Credentials. pub auth: Option<(&'a str, &'a str)>, } +/// Authentication protocol. #[repr(u8)] pub enum AuthProt { + /// No authentication. None = 0, + /// PAP authentication. Pap = 1, + /// CHAP authentication. Chap = 2, } +/// Error returned by control. #[derive(Clone, Copy, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Not enough space for command. BufferTooSmall, - AtCommand, + /// Error parsing response from modem. AtParseError, + /// Error parsing IP addresses. AddrParseError, - Format, } impl From for Error { @@ -41,17 +49,16 @@ impl From for Error { } } -impl From for Error { - fn from(_: core::fmt::Error) -> Self { - Self::Format - } -} - +/// Status of a given context. #[derive(PartialEq, Debug)] pub struct Status { + /// Attached to APN or not. pub attached: bool, + /// IP if assigned. pub ip: Option, + /// Gateway if assigned. pub gateway: Option, + /// DNS servers if assigned. pub dns: Vec, } @@ -66,16 +73,14 @@ impl defmt::Format for Status { } impl<'a> Control<'a> { + /// Create a new instance of a control handle for a given context. + /// + /// Will wait for the modem to be initialized if not. pub async fn new(control: crate::Control<'a>, cid: u8) -> Self { control.wait_init().await; Self { control, cid } } - /// Bypass modem configurator - pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { - self.control.at_command(req, resp).await - } - /// Configures the modem with the provided config. pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; @@ -85,7 +90,7 @@ impl<'a> Control<'a> { .named("+CGDCONT") .with_int_parameter(self.cid) .with_string_parameter("IP") - .with_string_parameter(config.gateway) + .with_string_parameter(config.apn) .finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; @@ -112,6 +117,7 @@ impl<'a> Control<'a> { Ok(()) } + /// Read current connectivity status for modem. pub async fn status(&self) -> Result { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; @@ -134,7 +140,7 @@ impl<'a> Control<'a> { .with_int_parameter(self.cid) .finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (_, ip1, ip2, ) = CommandParser::parse(&buf[..n]) + let (_, ip1, _ip2, ) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGPADDR: ") .expect_int_parameter() .expect_optional_string_parameter() @@ -154,7 +160,7 @@ impl<'a> Control<'a> { .with_int_parameter(self.cid) .finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, mtu) = CommandParser::parse(&buf[..n]) + let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, _mtu) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGCONTRDP: ") .expect_int_parameter() .expect_optional_int_parameter() diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index f80861693..55ab2a707 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -7,7 +7,7 @@ use core::ptr::addr_of_mut; use core::str::FromStr; use core::slice; -use defmt::{assert, info, warn, unwrap}; +use defmt::{info, warn, unwrap}; use heapless::Vec; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; @@ -93,7 +93,7 @@ async fn main(spawner: Spawner) { static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; let mut config = uarte::Config::default(); - config.baudrate = Baudrate::BAUD1M; + config.baudrate = Baudrate::BAUD115200; let trace_writer = TraceWriter(BufferedUarteTx::new( //let trace_uart = BufferedUarteTx::new( unsafe { peripherals::SERIAL0::steal() }, @@ -128,7 +128,7 @@ async fn main(spawner: Spawner) { let control = context::Control::new(control, 0).await; unwrap!(control.configure(context::Config { - gateway: "iot.nat.es", + apn: "iot.nat.es", auth_prot: context::AuthProt::Pap, auth: Some(("orange", "orange")), }).await); From b4221d75b87664485977d37df28f7319143411fc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 14:09:17 +0200 Subject: [PATCH 143/210] Make tracing optional and use dedicated task --- embassy-net-nrf91/src/lib.rs | 90 +++++++++++++++----- examples/nrf9160/src/bin/modem_tcp_client.rs | 58 ++++++------- 2 files changed, 98 insertions(+), 50 deletions(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index beed7c65a..673784cb2 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -19,12 +19,15 @@ use core::task::{Poll, Waker}; use embassy_net_driver_channel as ch; use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use heapless::Vec; use nrf9160_pac as pac; use pac::NVIC; +use embassy_sync::pipe; const RX_SIZE: usize = 8 * 1024; const TRACE_SIZE: usize = 16 * 1024; +const TRACE_BUF: usize = 1024; const MTU: usize = 1500; /// Network driver. @@ -91,11 +94,30 @@ impl<'a> Allocator<'a> { } /// Create a new nRF91 embassy-net driver. -pub async fn new<'a, TW: embedded_io::Write>( +pub async fn new<'a>( state: &'a mut State, shmem: &'a mut [MaybeUninit], - trace_writer: TW, -) -> (NetDriver<'a>, Control<'a>, Runner<'a, TW>) { +) -> (NetDriver<'a>, Control<'a>, Runner<'a>) { + let (n, c, r, _) = new_internal(state, shmem, None).await; + (n, c, r) +} + +/// Create a new nRF91 embassy-net driver with trace. +pub async fn new_with_trace<'a>( + state: &'a mut State, + shmem: &'a mut [MaybeUninit], + trace_buffer: &'a mut TraceBuffer, +) -> (NetDriver<'a>, Control<'a>, Runner<'a>, TraceReader<'a>) { + let (n, c, r, t) = new_internal(state, shmem, Some(trace_buffer)).await; + (n, c, r, t.unwrap()) +} + +/// Create a new nRF91 embassy-net driver. +async fn new_internal<'a>( + state: &'a mut State, + shmem: &'a mut [MaybeUninit], + trace_buffer: Option<&'a mut TraceBuffer>, +) -> (NetDriver<'a>, Control<'a>, Runner<'a>, Option>) { let shmem_len = shmem.len(); let shmem_ptr = shmem.as_mut_ptr() as *mut u8; @@ -205,21 +227,49 @@ pub async fn new<'a, TW: embedded_io::Write>( let state_ch = ch_runner.state_runner(); state_ch.set_link_state(ch::driver::LinkState::Up); + let (trace_reader, trace_writer) = if let Some(trace) = trace_buffer { + let (r, w) = trace.trace.split(); + (Some(r), Some(w)) + } else { + (None, None) + }; + let runner = Runner { ch: ch_runner, state: state_inner, trace_writer, }; - (device, control, runner) + (device, control, runner, trace_reader) } -/// Shared state for the drivver. +/// State holding modem traces. +pub struct TraceBuffer { + trace: pipe::Pipe, +} + +/// Represents writer half of the trace buffer. +pub type TraceWriter<'a> = pipe::Writer<'a, NoopRawMutex, TRACE_BUF>; + +/// Represents the reader half of the trace buffer. +pub type TraceReader<'a> = pipe::Reader<'a, NoopRawMutex, TRACE_BUF>; + +impl TraceBuffer { + /// Create a new TraceBuffer. + pub const fn new() -> Self { + Self { + trace: pipe::Pipe::new(), + } + } +} + +/// Shared state for the driver. pub struct State { ch: ch::State, inner: MaybeUninit>, } + impl State { /// Create a new State. pub const fn new() -> Self { @@ -272,7 +322,7 @@ struct StateInner { } impl StateInner { - fn poll(&mut self, trace_writer: &mut impl embedded_io::Write, ch: &mut ch::Runner) { + fn poll(&mut self, trace_writer: &mut Option>, ch: &mut ch::Runner) { trace!("poll!"); let ipc = unsafe { &*pac::IPC_NS::ptr() }; @@ -399,15 +449,17 @@ impl StateInner { }); } - fn handle_trace(writer: &mut impl embedded_io::Write, id: u8, data: &[u8]) { - trace!("trace: {} {}", id, data.len()); - let mut header = [0u8; 5]; - header[0] = 0xEF; - header[1] = 0xBE; - header[2..4].copy_from_slice(&(data.len() as u16).to_le_bytes()); - header[4] = id; - writer.write_all(&header).unwrap(); - writer.write_all(data).unwrap(); + fn handle_trace(writer: &mut Option>, id: u8, data: &[u8]) { + if let Some(writer) = writer { + trace!("trace: {} {}", id, data.len()); + let mut header = [0u8; 5]; + header[0] = 0xEF; + header[1] = 0xBE; + header[2..4].copy_from_slice(&(data.len() as u16).to_le_bytes()); + header[4] = id; + writer.try_write(&header).ok(); + writer.try_write(data).ok(); + } } fn process(&mut self, list: *mut List, is_control: bool, ch: &mut ch::Runner) -> bool { @@ -794,7 +846,7 @@ impl<'a> Control<'a> { /// Open the raw socket used for sending/receiving IP packets. /// /// This must be done after `AT+CFUN=1` (?) - pub async fn open_raw_socket(&self) { + async fn open_raw_socket(&self) { let mut msg: Message = unsafe { mem::zeroed() }; msg.channel = 2; // data msg.id = 0x7001_0004; // open socket @@ -822,13 +874,13 @@ impl<'a> Control<'a> { } /// Background runner for the driver. -pub struct Runner<'a, TW: embedded_io::Write> { +pub struct Runner<'a> { ch: ch::Runner<'a, MTU>, state: &'a RefCell, - trace_writer: TW, + trace_writer: Option>, } -impl<'a, TW: embedded_io::Write> Runner<'a, TW> { +impl<'a> Runner<'a> { /// Run the driver operation in the background. /// /// You must run this in a background task, concurrently with all network operations. diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 55ab2a707..c65e6e153 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -4,20 +4,20 @@ use core::mem::MaybeUninit; use core::net::IpAddr; use core::ptr::addr_of_mut; -use core::str::FromStr; use core::slice; +use core::str::FromStr; -use defmt::{info, warn, unwrap}; -use heapless::Vec; +use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; -use embassy_net_nrf91::{Runner, State, context}; +use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; use embassy_nrf::uarte::Baudrate; use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; +use heapless::Vec; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -30,28 +30,17 @@ bind_interrupts!(struct Irqs { UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler; }); -// embassy-net-nrf91 only supports blocking trace write for now. -// We don't want to block packet processing with slow uart writes, so -// we make an adapter that writes whatever fits in the buffer and drops -// data if it's full. -struct TraceWriter(BufferedUarteTx<'static, peripherals::SERIAL0>); - -impl embedded_io::ErrorType for TraceWriter { - type Error = core::convert::Infallible; -} - -impl embedded_io::Write for TraceWriter { - fn write(&mut self, buf: &[u8]) -> Result { - let _ = self.0.try_write(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) +#[embassy_executor::task] +async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! { + let mut rx = [0u8; 1024]; + loop { + let n = reader.read(&mut rx[..]).await; + unwrap!(uart.write_all(&rx[..n]).await); } } #[embassy_executor::task] -async fn modem_task(runner: Runner<'static, TraceWriter>) -> ! { +async fn modem_task(runner: Runner<'static>) -> ! { runner.run().await } @@ -93,8 +82,8 @@ async fn main(spawner: Spawner) { static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; let mut config = uarte::Config::default(); - config.baudrate = Baudrate::BAUD115200; - let trace_writer = TraceWriter(BufferedUarteTx::new( + config.baudrate = Baudrate::BAUD1M; + let uart = BufferedUarteTx::new( //let trace_uart = BufferedUarteTx::new( unsafe { peripherals::SERIAL0::steal() }, Irqs, @@ -102,11 +91,14 @@ async fn main(spawner: Spawner) { //unsafe { peripherals::P0_14::steal() }, config, unsafe { &mut *addr_of_mut!(TRACE_BUF) }, - )); + ); static STATE: StaticCell = StaticCell::new(); - let (device, control, runner) = embassy_net_nrf91::new(STATE.init(State::new()), ipc_mem, trace_writer).await; + static TRACE: StaticCell = StaticCell::new(); + let (device, control, runner, tracer) = + embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await; unwrap!(spawner.spawn(modem_task(runner))); + unwrap!(spawner.spawn(trace_task(uart, tracer))); let config = embassy_net::Config::default(); @@ -127,11 +119,15 @@ async fn main(spawner: Spawner) { let control = context::Control::new(control, 0).await; - unwrap!(control.configure(context::Config { - apn: "iot.nat.es", - auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), - }).await); + unwrap!( + control + .configure(context::Config { + apn: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }) + .await + ); info!("waiting for attach..."); From 49881f6fd1e3d77d63dea2313afb5201eca8ebd9 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 14:21:13 +0200 Subject: [PATCH 144/210] rustfmt --- embassy-net-nrf91/src/context.rs | 45 ++++++++++++++++++++++---------- embassy-net-nrf91/src/lib.rs | 10 +++---- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 9c67cbc9f..954830417 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -1,8 +1,10 @@ //! Helper utility to configure a specific modem context. use core::net::IpAddr; use core::str::FromStr; + +use at_commands::builder::CommandBuilder; +use at_commands::parser::CommandParser; use heapless::Vec; -use at_commands::{builder::CommandBuilder, parser::CommandParser}; /// Provides a higher level API for controlling a given context. pub struct Control<'a> { @@ -91,7 +93,8 @@ impl<'a> Control<'a> { .with_int_parameter(self.cid) .with_string_parameter("IP") .with_string_parameter(config.apn) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; @@ -110,7 +113,8 @@ impl<'a> Control<'a> { let op = CommandBuilder::create_set(&mut cmd, true) .named("+CFUN") .with_int_parameter(1) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; @@ -124,28 +128,37 @@ impl<'a> Control<'a> { let op = CommandBuilder::create_query(&mut cmd, true) .named("+CGATT") - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (res, ) = CommandParser::parse(&buf[..n]) + let (res,) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGATT: ") .expect_int_parameter() - .expect_identifier(b"\r\nOK").finish()?; + .expect_identifier(b"\r\nOK") + .finish()?; let attached = res == 1; if !attached { - return Ok(Status { attached, ip: None, gateway: None, dns: Vec::new() }) + return Ok(Status { + attached, + ip: None, + gateway: None, + dns: Vec::new(), + }); } let op = CommandBuilder::create_set(&mut cmd, true) .named("+CGPADDR") .with_int_parameter(self.cid) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (_, ip1, _ip2, ) = CommandParser::parse(&buf[..n]) + let (_, ip1, _ip2) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGPADDR: ") .expect_int_parameter() .expect_optional_string_parameter() .expect_optional_string_parameter() - .expect_identifier(b"\r\nOK").finish()?; + .expect_identifier(b"\r\nOK") + .finish()?; let ip = if let Some(ip) = ip1 { let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?; @@ -158,7 +171,8 @@ impl<'a> Control<'a> { let op = CommandBuilder::create_set(&mut cmd, true) .named("+CGCONTRDP") .with_int_parameter(self.cid) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, _mtu) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGCONTRDP: ") @@ -174,7 +188,8 @@ impl<'a> Control<'a> { .expect_optional_int_parameter() .expect_optional_int_parameter() .expect_optional_int_parameter() - .expect_identifier(b"\r\nOK").finish()?; + .expect_identifier(b"\r\nOK") + .finish()?; let gateway = if let Some(ip) = gateway { if ip.is_empty() { @@ -188,11 +203,13 @@ impl<'a> Control<'a> { let mut dns = Vec::new(); if let Some(ip) = dns1 { - dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?) + .unwrap(); } if let Some(ip) = dns2 { - dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?) + .unwrap(); } Ok(Status { diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 673784cb2..a60e27d97 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -17,13 +17,12 @@ use core::slice; use core::sync::atomic::{compiler_fence, fence, Ordering}; use core::task::{Poll, Waker}; -use embassy_net_driver_channel as ch; -use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use heapless::Vec; -use nrf9160_pac as pac; -use pac::NVIC; use embassy_sync::pipe; +use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; +use heapless::Vec; +use pac::NVIC; +use {embassy_net_driver_channel as ch, nrf9160_pac as pac}; const RX_SIZE: usize = 8 * 1024; const TRACE_SIZE: usize = 16 * 1024; @@ -269,7 +268,6 @@ pub struct State { inner: MaybeUninit>, } - impl State { /// Create a new State. pub const fn new() -> Self { From 372e45dabc0cfd3eb495e902665bb752a67aa804 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 18:47:26 +0200 Subject: [PATCH 145/210] Add context run task --- embassy-net-nrf91/src/context.rs | 86 +++++++++++++++++- embassy-net-nrf91/src/lib.rs | 5 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 93 +++++++++++--------- 3 files changed, 137 insertions(+), 47 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 954830417..f73719224 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -5,6 +5,7 @@ use core::str::FromStr; use at_commands::builder::CommandBuilder; use at_commands::parser::CommandParser; use heapless::Vec; +use embassy_time::{Timer, Duration}; /// Provides a higher level API for controlling a given context. pub struct Control<'a> { @@ -23,6 +24,8 @@ pub struct Config<'a> { } /// Authentication protocol. +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum AuthProt { /// No authentication. @@ -84,7 +87,7 @@ impl<'a> Control<'a> { } /// Configures the modem with the provided config. - pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { + pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; @@ -118,9 +121,64 @@ impl<'a> Control<'a> { let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("%XPDNCFG") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + + Ok(()) } + /// Attach to the PDN + pub async fn attach(&self) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGATT") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + Ok(()) + } + + /// Read current connectivity status for modem. + pub async fn detach(&self) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGATT") + .with_int_parameter(0) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + Ok(()) + } + + async fn attached(&self) -> Result { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + + let op = CommandBuilder::create_query(&mut cmd, true) + .named("+CGATT") + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (res,) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGATT: ") + .expect_int_parameter() + .expect_identifier(b"\r\nOK") + .finish()?; + Ok(res == 1) + } + /// Read current connectivity status for modem. pub async fn status(&self) -> Result { let mut cmd: [u8; 256] = [0; 256]; @@ -162,7 +220,6 @@ impl<'a> Control<'a> { let ip = if let Some(ip) = ip1 { let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?; - self.control.open_raw_socket().await; Some(ip) } else { None @@ -219,4 +276,29 @@ impl<'a> Control<'a> { dns, }) } + + /// Run a control loop for this context, ensuring that reaattach is handled. + pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { + self.configure(config).await?; + while !self.attached().await? { + Timer::after(Duration::from_secs(1)).await; + } + let status = self.status().await?; + let mut fd = self.control.open_raw_socket().await; + reattach(&status); + + loop { + if !self.attached().await? { + // TODO: self.control.close_raw_socket(fd).await; + self.attach().await?; + while !self.attached().await? { + Timer::after(Duration::from_secs(1)).await; + } + let status = self.status().await?; + // TODO: let mut fd = self.control.open_raw_socket().await; + reattach(&status); + } + Timer::after(Duration::from_secs(10)).await; + } + } } diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index a60e27d97..ab3c6f327 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -844,7 +844,7 @@ impl<'a> Control<'a> { /// Open the raw socket used for sending/receiving IP packets. /// /// This must be done after `AT+CFUN=1` (?) - async fn open_raw_socket(&self) { + async fn open_raw_socket(&self) -> u32 { let mut msg: Message = unsafe { mem::zeroed() }; msg.channel = 2; // data msg.id = 0x7001_0004; // open socket @@ -867,7 +867,8 @@ impl<'a> Control<'a> { assert_eq!(status, 0); assert_eq!(msg.param_len, 16); let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap()); - debug!("got FD: {}", fd); + trace!("got FD: {}", fd); + fd } } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index c65e6e153..a6f42eb3b 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -49,6 +49,43 @@ async fn net_task(stack: &'static Stack>) stack.run().await } +#[embassy_executor::task] +async fn control_task( + control: &'static context::Control<'static>, + config: context::Config<'static>, + stack: &'static Stack>, +) { + unwrap!( + control + .run(&config, |status| { + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); + + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns.iter() { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(addr, 32), + gateway, + dns_servers, + })); + }) + .await + ); +} + #[embassy_executor::task] async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); @@ -117,50 +154,20 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - let control = context::Control::new(control, 0).await; + static CONTROL: StaticCell> = StaticCell::new(); + let control = CONTROL.init(context::Control::new(control, 0).await); - unwrap!( - control - .configure(context::Config { - apn: "iot.nat.es", - auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), - }) - .await - ); + unwrap!(spawner.spawn(control_task( + control, + context::Config { + apn: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }, + stack + ))); - info!("waiting for attach..."); - - let mut status = unwrap!(control.status().await); - while !status.attached && status.ip.is_none() { - Timer::after_millis(1000).await; - status = unwrap!(control.status().await); - info!("STATUS: {:?}", status); - } - - let Some(IpAddr::V4(addr)) = status.ip else { - panic!("Unexpected IP address"); - }; - let addr = Ipv4Address(addr.octets()); - - let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { - Some(Ipv4Address(addr.octets())) - } else { - None - }; - - let mut dns_servers = Vec::new(); - for dns in status.dns { - if let IpAddr::V4(ip) = dns { - unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); - } - } - - stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(addr, 32), - gateway, - dns_servers, - })); + stack.wait_config_up().await; let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; @@ -172,7 +179,7 @@ async fn main(spawner: Spawner) { let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); if let Err(e) = socket.connect((host_addr, 4242)).await { warn!("connect error: {:?}", e); - Timer::after_secs(1).await; + Timer::after_secs(10).await; continue; } info!("Connected to {:?}", socket.remote_endpoint()); From aa3c7b900e5dfba440f86743cdf37c4e14ad60f0 Mon Sep 17 00:00:00 2001 From: Kezi Date: Wed, 4 Sep 2024 18:36:40 +0200 Subject: [PATCH 146/210] support custom style for usb logger --- embassy-usb-logger/src/lib.rs | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 34d1ca663..11188b4ef 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -41,12 +41,24 @@ pub const MAX_PACKET_SIZE: u8 = 64; /// The logger handle, which contains a pipe with configurable size for buffering log messages. pub struct UsbLogger { buffer: Pipe, + custom_style: Option) -> ()>, } impl UsbLogger { /// Create a new logger instance. pub const fn new() -> Self { - Self { buffer: Pipe::new() } + Self { + buffer: Pipe::new(), + custom_style: None, + } + } + + /// Create a new logger instance with a custom formatter. + pub const fn with_custom_style(custom_style: fn(&Record, &mut Writer<'_, N>) -> ()) -> Self { + Self { + buffer: Pipe::new(), + custom_style: Some(custom_style), + } } /// Run the USB logger using the state and USB driver. Never returns. @@ -137,14 +149,19 @@ impl log::Log for UsbLogger { fn log(&self, record: &Record) { if self.enabled(record.metadata()) { - let _ = write!(Writer(&self.buffer), "{}\r\n", record.args()); + if let Some(custom_style) = self.custom_style { + custom_style(record, &mut Writer(&self.buffer)); + } else { + let _ = write!(Writer(&self.buffer), "{}\r\n", record.args()); + } } } fn flush(&self) {} } -struct Writer<'d, const N: usize>(&'d Pipe); +/// A writer that writes to the USB logger buffer. +pub struct Writer<'d, const N: usize>(&'d Pipe); impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { @@ -210,3 +227,33 @@ macro_rules! with_class { LOGGER.create_future_from_class($p) }}; } + +/// Initialize the USB serial logger from a serial class and return the future to run it. +/// This version of the macro allows for a custom style function to be passed in. +/// The custom style function will be called for each log record and is responsible for writing the log message to the buffer. +/// +/// Arguments specify the buffer size, log level, the serial class and the custom style function, respectively. +/// +/// # Usage +/// +/// ``` +/// let log_fut = embassy_usb_logger::with_custom_style!(1024, log::LevelFilter::Info, logger_class, |record, writer| { +/// use core::fmt::Write; +/// let level = record.level().as_str(); +/// write!(writer, "[{level}] {}\r\n", record.args()).unwrap(); +/// }); +/// ``` +/// +/// # Safety +/// +/// This macro should only be invoked only once since it is setting the global logging state of the application. +#[macro_export] +macro_rules! with_custom_style { + ( $x:expr, $l:expr, $p:ident, $s:expr ) => {{ + static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::with_custom_style($s); + unsafe { + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + } + LOGGER.create_future_from_class($p) + }}; +} From ccfa6264b0ad258625f2dd667ba8e6eaca1cfdc3 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 19:31:55 +0200 Subject: [PATCH 147/210] Add closing if raw socket to handle re-attach --- embassy-net-nrf91/src/context.rs | 8 +++----- embassy-net-nrf91/src/lib.rs | 15 +++++++++++++++ examples/nrf9160/src/bin/modem_tcp_client.rs | 2 ++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index f73719224..511468316 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -4,8 +4,8 @@ use core::str::FromStr; use at_commands::builder::CommandBuilder; use at_commands::parser::CommandParser; +use embassy_time::{Duration, Timer}; use heapless::Vec; -use embassy_time::{Timer, Duration}; /// Provides a higher level API for controlling a given context. pub struct Control<'a> { @@ -129,8 +129,6 @@ impl<'a> Control<'a> { let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - - Ok(()) } @@ -289,13 +287,13 @@ impl<'a> Control<'a> { loop { if !self.attached().await? { - // TODO: self.control.close_raw_socket(fd).await; + self.control.close_raw_socket(fd).await; self.attach().await?; while !self.attached().await? { Timer::after(Duration::from_secs(1)).await; } let status = self.status().await?; - // TODO: let mut fd = self.control.open_raw_socket().await; + fd = self.control.open_raw_socket().await; reattach(&status); } Timer::after(Duration::from_secs(10)).await; diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index ab3c6f327..d8cbe47fc 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -870,6 +870,21 @@ impl<'a> Control<'a> { trace!("got FD: {}", fd); fd } + + async fn close_raw_socket(&self, fd: u32) { + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x7009_0004; // close socket + msg.param_len = 8; + msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); + + self.request(&mut msg, &[], &mut []).await; + + assert_eq!(msg.id, 0x80090004); + assert!(msg.param_len >= 12); + let status = u32::from_le_bytes(msg.param[8..12].try_into().unwrap()); + assert_eq!(status, 0); + } } /// Background runner for the driver. diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index a6f42eb3b..fb14b746f 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -193,5 +193,7 @@ async fn main(spawner: Spawner) { info!("txd: {}", core::str::from_utf8(msg).unwrap()); Timer::after_secs(1).await; } + // Test auto-attach + unwrap!(control.detach().await); } } From e75903138a92e6c749454cee516c812df618bbfa Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 4 Sep 2024 13:42:03 -0400 Subject: [PATCH 148/210] Fix commented out code --- embassy-rp/src/flash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index dab99b4e2..fbc8b35ec 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -627,7 +627,7 @@ mod ram_helpers { #[link_section = ".data.ram_func"] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { - //#[cfg(target_arch = "arm")] + #[cfg(target_arch = "arm")] core::arch::asm!( "mov r8, r0", "mov r9, r2", From df4ed5c91ded2e7292e72d7e38dc6c6e0958fece Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 4 Sep 2024 21:09:37 +0200 Subject: [PATCH 149/210] stm32/tests: disable flaky stm32wl55jc/usart_rx_ringbuffered --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index 70fe4f5d8..8fef731a4 100755 --- a/ci.sh +++ b/ci.sh @@ -305,6 +305,7 @@ rm out/tests/stm32u5a5zj/usart # flaky, probably due to bad ringbuffered dma code. rm out/tests/stm32l152re/usart_rx_ringbuffered rm out/tests/stm32f207zg/usart_rx_ringbuffered +rm out/tests/stm32wl55jc/usart_rx_ringbuffered if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests From 836e8add1bcb09c476a3aa3d7a416a15b8c21e6a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 10:02:45 +0200 Subject: [PATCH 150/210] Mintor fixes after testing re-attach --- embassy-net-nrf91/src/context.rs | 20 +++++--- examples/nrf9160/src/bin/modem_tcp_client.rs | 54 +++++++++++--------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 511468316..6b841aa16 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -275,24 +275,28 @@ impl<'a> Control<'a> { }) } - /// Run a control loop for this context, ensuring that reaattach is handled. - pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { - self.configure(config).await?; + async fn wait_attached(&self) -> Result { while !self.attached().await? { Timer::after(Duration::from_secs(1)).await; } let status = self.status().await?; + Ok(status) + } + + /// Run a control loop for this context, ensuring that reaattach is handled. + pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { + self.configure(config).await?; + let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); loop { if !self.attached().await? { + trace!("detached"); + self.control.close_raw_socket(fd).await; - self.attach().await?; - while !self.attached().await? { - Timer::after(Duration::from_secs(1)).await; - } - let status = self.status().await?; + let status = self.wait_attached().await?; + trace!("attached"); fd = self.control.open_raw_socket().await; reattach(&status); } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index fb14b746f..b7d56802d 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -10,6 +10,7 @@ use core::str::FromStr; use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net_nrf91::context::Status; use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; @@ -58,34 +59,38 @@ async fn control_task( unwrap!( control .run(&config, |status| { - let Some(IpAddr::V4(addr)) = status.ip else { - panic!("Unexpected IP address"); - }; - let addr = Ipv4Address(addr.octets()); - - let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { - Some(Ipv4Address(addr.octets())) - } else { - None - }; - - let mut dns_servers = Vec::new(); - for dns in status.dns.iter() { - if let IpAddr::V4(ip) = dns { - unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); - } - } - - stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(addr, 32), - gateway, - dns_servers, - })); + stack.set_config_v4(status_to_config(status)); }) .await ); } +fn status_to_config(status: &Status) -> embassy_net::ConfigV4 { + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); + + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns.iter() { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + + embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(addr, 32), + gateway, + dns_servers, + }) +} + #[embassy_executor::task] async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); @@ -193,7 +198,6 @@ async fn main(spawner: Spawner) { info!("txd: {}", core::str::from_utf8(msg).unwrap()); Timer::after_secs(1).await; } - // Test auto-attach - unwrap!(control.detach().await); + Timer::after_secs(4).await; } } From 5d0ed246400b1e7973c1fe870dba977ab7186a21 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 10:31:51 +0200 Subject: [PATCH 151/210] Move configure out of run --- embassy-net-nrf91/src/context.rs | 3 +-- examples/nrf9160/src/bin/modem_tcp_client.rs | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 6b841aa16..3671fdd68 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -284,8 +284,7 @@ impl<'a> Control<'a> { } /// Run a control loop for this context, ensuring that reaattach is handled. - pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { - self.configure(config).await?; + pub async fn run(&self, reattach: F) -> Result<(), Error> { let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index b7d56802d..7d78eba0a 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -56,9 +56,10 @@ async fn control_task( config: context::Config<'static>, stack: &'static Stack>, ) { + unwrap!(control.configure(&config).await); unwrap!( control - .run(&config, |status| { + .run(|status| { stack.set_config_v4(status_to_config(status)); }) .await From d71fd447cc4778be8abfdaf510be3a75dac23bf8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 11:25:19 +0200 Subject: [PATCH 152/210] Add method for buypassing and running at command directly --- embassy-net-nrf91/src/context.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 3671fdd68..b936e5f87 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -86,6 +86,11 @@ impl<'a> Control<'a> { Self { control, cid } } + /// Perform a raw AT command + pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { + self.control.at_command(req, resp).await + } + /// Configures the modem with the provided config. pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; From db00f3f5ecbf7f9a8acb340556b8fc6b156736fa Mon Sep 17 00:00:00 2001 From: Samuel Maier Date: Thu, 5 Sep 2024 11:45:49 +0200 Subject: [PATCH 153/210] Enable critical-section/std on wasm Without that feature one will find import errors on opening the webpage, that are hard to debug. The feature was indirectly enabled in the wasm example, however the reason wasn't documented and thus it was easy to miss. --- embassy-executor/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 5984cc49c..01fa28b88 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -79,7 +79,7 @@ arch-cortex-m = ["_arch", "dep:cortex-m"] ## RISC-V 32 arch-riscv32 = ["_arch"] ## WASM -arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] +arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"] ## AVR arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 9bd37550c..75de079b7 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -16,7 +16,6 @@ wasm-logger = "0.2.0" wasm-bindgen = "0.2" web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] } log = "0.4.11" -critical-section = { version = "1.1", features = ["std"] } [profile.release] debug = 2 From ccf68d73910a68dc9e33beb666b20aba7430e015 Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 5 Sep 2024 21:29:04 +0200 Subject: [PATCH 154/210] feat(usb): add support for ISO endpoints --- embassy-stm32/src/usb/usb.rs | 211 ++++++++++++++++++++++++++++++----- 1 file changed, 186 insertions(+), 25 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 9384c8688..0ab2306c8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -80,6 +80,8 @@ impl interrupt::typelevel::Handler for InterruptHandl if istr.ctr() { let index = istr.ep_id() as usize; + CTR_TRIGGERED[index].store(true, Ordering::Relaxed); + let mut epr = regs.epr(index).read(); if epr.ctr_rx() { if index == 0 && epr.setup() { @@ -120,6 +122,10 @@ const USBRAM_ALIGN: usize = 4; const NEW_AW: AtomicWaker = AtomicWaker::new(); static BUS_WAKER: AtomicWaker = NEW_AW; static EP0_SETUP: AtomicBool = AtomicBool::new(false); + +const NEW_CTR_TRIGGERED: AtomicBool = AtomicBool::new(false); +static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [NEW_CTR_TRIGGERED; EP_COUNT]; + static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; static IRQ_RESET: AtomicBool = AtomicBool::new(false); @@ -163,20 +169,37 @@ fn calc_out_len(len: u16) -> (u16, u16) { mod btable { use super::*; - pub(super) fn write_in(index: usize, addr: u16) { + pub(super) fn write_in_tx(index: usize, addr: u16) { USBRAM.mem(index * 4 + 0).write_value(addr); } - pub(super) fn write_in_len(index: usize, _addr: u16, len: u16) { + pub(super) fn write_in_rx(index: usize, addr: u16) { + USBRAM.mem(index * 4 + 2).write_value(addr); + } + + pub(super) fn write_in_len_rx(index: usize, _addr: u16, len: u16) { + USBRAM.mem(index * 4 + 3).write_value(len); + } + + pub(super) fn write_in_len_tx(index: usize, _addr: u16, len: u16) { USBRAM.mem(index * 4 + 1).write_value(len); } - pub(super) fn write_out(index: usize, addr: u16, max_len_bits: u16) { + pub(super) fn write_out_rx(index: usize, addr: u16, max_len_bits: u16) { USBRAM.mem(index * 4 + 2).write_value(addr); USBRAM.mem(index * 4 + 3).write_value(max_len_bits); } - pub(super) fn read_out_len(index: usize) -> u16 { + pub(super) fn write_out_tx(index: usize, addr: u16, max_len_bits: u16) { + USBRAM.mem(index * 4 + 0).write_value(addr); + USBRAM.mem(index * 4 + 1).write_value(max_len_bits); + } + + pub(super) fn read_out_len_tx(index: usize) -> u16 { + USBRAM.mem(index * 4 + 1).read() + } + + pub(super) fn read_out_len_rx(index: usize) -> u16 { USBRAM.mem(index * 4 + 3).read() } } @@ -184,19 +207,37 @@ mod btable { mod btable { use super::*; - pub(super) fn write_in(_index: usize, _addr: u16) {} + pub(super) fn write_in_tx(_index: usize, _addr: u16) {} - pub(super) fn write_in_len(index: usize, addr: u16, len: u16) { + pub(super) fn write_in_rx(_index: usize, _addr: u16) {} + + pub(super) fn write_in_len_tx(index: usize, addr: u16, len: u16) { USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); } - pub(super) fn write_out(index: usize, addr: u16, max_len_bits: u16) { + pub(super) fn write_in_len_rx(index: usize, addr: u16, len: u16) { + USBRAM + .mem(index * 2 + 1) + .write_value((addr as u32) | ((len as u32) << 16)); + } + + pub(super) fn write_out_tx(index: usize, addr: u16, max_len_bits: u16) { + USBRAM + .mem(index * 2) + .write_value((addr as u32) | ((max_len_bits as u32) << 16)); + } + + pub(super) fn write_out_rx(index: usize, addr: u16, max_len_bits: u16) { USBRAM .mem(index * 2 + 1) .write_value((addr as u32) | ((max_len_bits as u32) << 16)); } - pub(super) fn read_out_len(index: usize) -> u16 { + pub(super) fn read_out_len_tx(index: usize) -> u16 { + (USBRAM.mem(index * 2).read() >> 16) as u16 + } + + pub(super) fn read_out_len_rx(index: usize) -> u16 { (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 } } @@ -327,6 +368,13 @@ impl<'d, T: Instance> Driver<'d, T> { return false; // reserved for control pipe } let used = ep.used_out || ep.used_in; + if used && (ep.ep_type == EndpointType::Isochronous || ep.ep_type == EndpointType::Bulk) { + // Isochronous and bulk endpoints are double-buffered. + // Their corresponding endpoint/channel registers are forced to be unidirectional. + // Do not reuse this index. + return false; + } + let used_dir = match D::dir() { Direction::Out => ep.used_out, Direction::In => ep.used_in, @@ -350,7 +398,11 @@ impl<'d, T: Instance> Driver<'d, T> { let addr = self.alloc_ep_mem(len); trace!(" len_bits = {:04x}", len_bits); - btable::write_out::(index, addr, len_bits); + btable::write_out_rx::(index, addr, len_bits); + + if ep_type == EndpointType::Isochronous { + btable::write_out_tx::(index, addr, len_bits); + } EndpointBuffer { addr, @@ -366,7 +418,11 @@ impl<'d, T: Instance> Driver<'d, T> { let addr = self.alloc_ep_mem(len); // ep_in_len is written when actually TXing packets. - btable::write_in::(index, addr); + btable::write_in_tx::(index, addr); + + if ep_type == EndpointType::Isochronous { + btable::write_in_rx::(index, addr); + } EndpointBuffer { addr, @@ -656,6 +712,18 @@ impl Dir for Out { } } +/// Selects the packet buffer. +/// +/// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same +/// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve +/// two directions at the same time. +enum PacketBuffer { + /// The RX buffer - must be used for single-buffered OUT endpoints + Rx, + /// The TX buffer - must be used for single-buffered IN endpoints + Tx, +} + /// USB endpoint. pub struct Endpoint<'d, T: Instance, D> { _phantom: PhantomData<(&'d mut T, D)>, @@ -664,15 +732,46 @@ pub struct Endpoint<'d, T: Instance, D> { } impl<'d, T: Instance, D> Endpoint<'d, T, D> { - fn write_data(&mut self, buf: &[u8]) { + /// Write to a double-buffered endpoint. + /// + /// For double-buffered endpoints, the data buffers overlap, but we still need to write to the right counter field. + /// The DTOG_TX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in + /// which the next transmit packet will be stored, so we need to write the counter of the OTHER buffer, which is + /// where the last transmitted packet was stored. + fn write_data_double_buffered(&mut self, buf: &[u8], packet_buffer: PacketBuffer) { let index = self.info.addr.index(); self.buf.write(buf); - btable::write_in_len::(index, self.buf.addr, buf.len() as _); + + match packet_buffer { + PacketBuffer::Rx => btable::write_in_len_rx::(index, self.buf.addr, buf.len() as _), + PacketBuffer::Tx => btable::write_in_len_tx::(index, self.buf.addr, buf.len() as _), + } } - fn read_data(&mut self, buf: &mut [u8]) -> Result { + /// Write to a single-buffered endpoint. + fn write_data(&mut self, buf: &[u8]) { + self.write_data_double_buffered(buf, PacketBuffer::Tx); + } + + /// Read from a double-buffered endpoint. + /// + /// For double-buffered endpoints, the data buffers overlap, but we still need to read from the right counter field. + /// The DTOG_RX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in + /// which the next received packet will be stored, so we need to read the counter of the OTHER buffer, which is + /// where the last received packet was stored. + fn read_data_double_buffered( + &mut self, + buf: &mut [u8], + packet_buffer: PacketBuffer, + ) -> Result { let index = self.info.addr.index(); - let rx_len = btable::read_out_len::(index) as usize & 0x3FF; + + let rx_len = match packet_buffer { + PacketBuffer::Rx => btable::read_out_len_rx::(index), + PacketBuffer::Tx => btable::read_out_len_tx::(index), + } as usize + & 0x3FF; + trace!("READ DONE, rx_len = {}", rx_len); if rx_len > buf.len() { return Err(EndpointError::BufferOverflow); @@ -680,6 +779,11 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { self.buf.read(&mut buf[..rx_len]); Ok(rx_len) } + + /// Read from a single-buffered endpoint. + fn read_data(&mut self, buf: &mut [u8]) -> Result { + self.read_data_double_buffered(buf, PacketBuffer::Rx) + } } impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { @@ -734,25 +838,53 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { EP_OUT_WAKERS[index].register(cx.waker()); let regs = T::regs(); let stat = regs.epr(index).read().stat_rx(); - if matches!(stat, Stat::NAK | Stat::DISABLED) { - Poll::Ready(stat) + if self.info.ep_type == EndpointType::Isochronous { + // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. + // Therefore, this instead waits until the `CTR` interrupt was triggered. + if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { + Poll::Ready(stat) + } else { + Poll::Pending + } } else { - Poll::Pending + if matches!(stat, Stat::NAK | Stat::DISABLED) { + Poll::Ready(stat) + } else { + Poll::Pending + } } }) .await; + CTR_TRIGGERED[index].store(false, Ordering::Relaxed); + if stat == Stat::DISABLED { return Err(EndpointError::Disabled); } - let rx_len = self.read_data(buf)?; - let regs = T::regs(); + + let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { + // Find the buffer, which is currently in use. Read from the OTHER buffer. + if regs.epr(index).read().dtog_rx() { + PacketBuffer::Rx + } else { + PacketBuffer::Tx + } + } else { + PacketBuffer::Rx + }; + + let rx_len = self.read_data_double_buffered(buf, packet_buffer)?; + regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); - w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + if self.info.ep_type == EndpointType::Isochronous { + w.set_stat_rx(Stat::from_bits(0)); // STAT_RX remains `VALID`. + } else { + w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + } w.set_stat_tx(Stat::from_bits(0)); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear @@ -776,25 +908,54 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { EP_IN_WAKERS[index].register(cx.waker()); let regs = T::regs(); let stat = regs.epr(index).read().stat_tx(); - if matches!(stat, Stat::NAK | Stat::DISABLED) { - Poll::Ready(stat) + if self.info.ep_type == EndpointType::Isochronous { + // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. + // Therefore, this instead waits until the `CTR` interrupt was triggered. + if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { + Poll::Ready(stat) + } else { + Poll::Pending + } } else { - Poll::Pending + if matches!(stat, Stat::NAK | Stat::DISABLED) { + Poll::Ready(stat) + } else { + Poll::Pending + } } }) .await; + CTR_TRIGGERED[index].store(false, Ordering::Relaxed); + if stat == Stat::DISABLED { return Err(EndpointError::Disabled); } - self.write_data(buf); + let regs = T::regs(); + + let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { + // Find the buffer, which is currently in use. Write to the OTHER buffer. + if regs.epr(index).read().dtog_tx() { + PacketBuffer::Tx + } else { + PacketBuffer::Rx + } + } else { + PacketBuffer::Tx + }; + + self.write_data_double_buffered(buf, packet_buffer); let regs = T::regs(); regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); - w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + if self.info.ep_type == EndpointType::Isochronous { + w.set_stat_tx(Stat::from_bits(0)); // STAT_TX remains `VALID`. + } else { + w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + } w.set_stat_rx(Stat::from_bits(0)); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear From d37c482e2179c95740bb4284f4df30637551199b Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 5 Sep 2024 21:29:11 +0200 Subject: [PATCH 155/210] feat(usb-otg): add support for ISO endpoints --- embassy-usb-synopsys-otg/src/lib.rs | 30 ++++++++++++++++++++++++++ embassy-usb-synopsys-otg/src/otg_v1.rs | 16 +++++++------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index 5fb82db42..b145f4aa8 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -1071,6 +1071,21 @@ impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> { w.set_pktcnt(1); }); + if self.info.ep_type == EndpointType::Isochronous { + // Isochronous endpoints must set the correct even/odd frame bit to + // correspond with the next frame's number. + let frame_number = self.regs.dsts().read().fnsof(); + let frame_is_odd = frame_number & 0x01 == 1; + + self.regs.doepctl(index).modify(|r| { + if frame_is_odd { + r.set_sd0pid_sevnfrm(true); + } else { + r.set_sd1pid_soddfrm(true); + } + }); + } + // Clear NAK to indicate we are ready to receive more data self.regs.doepctl(index).modify(|w| { w.set_cnak(true); @@ -1158,6 +1173,21 @@ impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> { w.set_xfrsiz(buf.len() as _); }); + if self.info.ep_type == EndpointType::Isochronous { + // Isochronous endpoints must set the correct even/odd frame bit to + // correspond with the next frame's number. + let frame_number = self.regs.dsts().read().fnsof(); + let frame_is_odd = frame_number & 0x01 == 1; + + self.regs.diepctl(index).modify(|r| { + if frame_is_odd { + r.set_sd0pid_sevnfrm(true); + } else { + r.set_sd1pid_soddfrm(true); + } + }); + } + // Enable endpoint self.regs.diepctl(index).modify(|w| { w.set_cnak(true); diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs index a8530980c..d3abc328d 100644 --- a/embassy-usb-synopsys-otg/src/otg_v1.rs +++ b/embassy-usb-synopsys-otg/src/otg_v1.rs @@ -795,15 +795,15 @@ pub mod regs { pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); } - #[doc = "SODDFRM/SD1PID"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub const fn soddfrm_sd1pid(&self) -> bool { + pub const fn sd1pid_soddfrm(&self) -> bool { let val = (self.0 >> 29usize) & 0x01; val != 0 } - #[doc = "SODDFRM/SD1PID"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub fn set_soddfrm_sd1pid(&mut self, val: bool) { + pub fn set_sd1pid_soddfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); } #[doc = "EPDIS"] @@ -1174,15 +1174,15 @@ pub mod regs { pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); } - #[doc = "SODDFRM"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub const fn soddfrm(&self) -> bool { + pub const fn sd1pid_soddfrm(&self) -> bool { let val = (self.0 >> 29usize) & 0x01; val != 0 } - #[doc = "SODDFRM"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub fn set_soddfrm(&mut self, val: bool) { + pub fn set_sd1pid_soddfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); } #[doc = "EPDIS"] From a8ca6713e6e9b7ad5dd53f9b46bcf5e893adda1e Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 5 Sep 2024 21:29:24 +0200 Subject: [PATCH 156/210] feat(usb): make use of ISO endpoint support --- embassy-usb/src/builder.rs | 140 ++++++++++++++++++++++++++++++---- embassy-usb/src/descriptor.rs | 91 +++++++++++++++++++--- 2 files changed, 206 insertions(+), 25 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 7168e077c..e1bf8041f 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -1,8 +1,8 @@ use heapless::Vec; use crate::config::MAX_HANDLER_COUNT; -use crate::descriptor::{BosWriter, DescriptorWriter}; -use crate::driver::{Driver, Endpoint, EndpointType}; +use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType}; +use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType}; use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; use crate::types::{InterfaceNumber, StringIndex}; use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; @@ -414,7 +414,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { - self.builder.config_descriptor.write(descriptor_type, descriptor); + self.builder.config_descriptor.write(descriptor_type, descriptor, &[]); } /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting. @@ -422,26 +422,80 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { self.builder.bos_descriptor.capability(capability_type, capability); } - fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { + /// Write a custom endpoint descriptor for a certain endpoint. + /// + /// This can be necessary, if the endpoint descriptors can only be written + /// after the endpoint was created. As an example, an endpoint descriptor + /// may contain the address of an endpoint that was allocated earlier. + pub fn endpoint_descriptor( + &mut self, + endpoint: &EndpointInfo, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) { + self.builder + .config_descriptor + .endpoint(endpoint, synchronization_type, usage_type, extra_fields); + } + + /// Allocate an IN endpoint, without writing its descriptor. + /// + /// Used for granular control over the order of endpoint and descriptor creation. + pub fn alloc_endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { let ep = self .builder .driver .alloc_endpoint_in(ep_type, max_packet_size, interval_ms) .expect("alloc_endpoint_in failed"); - self.builder.config_descriptor.endpoint(ep.info()); + ep + } + + fn endpoint_in( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointIn { + let ep = self.alloc_endpoint_in(ep_type, max_packet_size, interval_ms); + self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields); ep } - fn endpoint_out(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { + /// Allocate an OUT endpoint, without writing its descriptor. + /// + /// Use for granular control over the order of endpoint and descriptor creation. + pub fn alloc_endpoint_out( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> D::EndpointOut { let ep = self .builder .driver .alloc_endpoint_out(ep_type, max_packet_size, interval_ms) .expect("alloc_endpoint_out failed"); - self.builder.config_descriptor.endpoint(ep.info()); + ep + } + + fn endpoint_out( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointOut { + let ep = self.alloc_endpoint_out(ep_type, max_packet_size, interval_ms); + self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields); ep } @@ -451,7 +505,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn { - self.endpoint_in(EndpointType::Bulk, max_packet_size, 0) + self.endpoint_in( + EndpointType::Bulk, + max_packet_size, + 0, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a BULK OUT endpoint and write its descriptor. @@ -459,7 +520,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut { - self.endpoint_out(EndpointType::Bulk, max_packet_size, 0) + self.endpoint_out( + EndpointType::Bulk, + max_packet_size, + 0, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a INTERRUPT IN endpoint and write its descriptor. @@ -467,24 +535,66 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { - self.endpoint_in(EndpointType::Interrupt, max_packet_size, interval_ms) + self.endpoint_in( + EndpointType::Interrupt, + max_packet_size, + interval_ms, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a INTERRUPT OUT endpoint and write its descriptor. pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { - self.endpoint_out(EndpointType::Interrupt, max_packet_size, interval_ms) + self.endpoint_out( + EndpointType::Interrupt, + max_packet_size, + interval_ms, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor. /// /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. - pub fn endpoint_isochronous_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { - self.endpoint_in(EndpointType::Isochronous, max_packet_size, interval_ms) + pub fn endpoint_isochronous_in( + &mut self, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointIn { + self.endpoint_in( + EndpointType::Isochronous, + max_packet_size, + interval_ms, + synchronization_type, + usage_type, + extra_fields, + ) } /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor. - pub fn endpoint_isochronous_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { - self.endpoint_out(EndpointType::Isochronous, max_packet_size, interval_ms) + pub fn endpoint_isochronous_out( + &mut self, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointOut { + self.endpoint_out( + EndpointType::Isochronous, + max_packet_size, + interval_ms, + synchronization_type, + usage_type, + extra_fields, + ) } } diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index f1773fa8a..0f2931c38 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -1,4 +1,5 @@ //! Utilities for writing USB descriptors. +use embassy_usb_driver::EndpointType; use crate::builder::Config; use crate::driver::EndpointInfo; @@ -38,6 +39,40 @@ pub mod capability_type { pub const PLATFORM: u8 = 5; } +/// USB endpoint synchronization type. The values of this enum can be directly +/// cast into `u8` to get the bmAttributes synchronization type bits. +/// Values other than `NoSynchronization` are only allowed on isochronous endpoints. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SynchronizationType { + /// No synchronization is used. + NoSynchronization = 0b00, + /// Unsynchronized, although sinks provide data rate feedback. + Asynchronous = 0b01, + /// Synchronized using feedback or feedforward data rate information. + Adaptive = 0b10, + /// Synchronized to the USB’s SOF. + Synchronous = 0b11, +} + +/// USB endpoint usage type. The values of this enum can be directly cast into +/// `u8` to get the bmAttributes usage type bits. +/// Values other than `DataEndpoint` are only allowed on isochronous endpoints. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum UsageType { + /// Use the endpoint for regular data transfer. + DataEndpoint = 0b00, + /// Endpoint conveys explicit feedback information for one or more data endpoints. + FeedbackEndpoint = 0b01, + /// A data endpoint that also serves as an implicit feedback endpoint for one or more data endpoints. + ImplicitFeedbackDataEndpoint = 0b10, + /// Reserved usage type. + Reserved = 0b11, +} + /// A writer for USB descriptors. pub(crate) struct DescriptorWriter<'a> { pub buf: &'a mut [u8], @@ -65,23 +100,26 @@ impl<'a> DescriptorWriter<'a> { self.position } - /// Writes an arbitrary (usually class-specific) descriptor. - pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) { - let length = descriptor.len(); + /// Writes an arbitrary (usually class-specific) descriptor with optional extra fields. + pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8], extra_fields: &[u8]) { + let descriptor_length = descriptor.len(); + let extra_fields_length = extra_fields.len(); + let total_length = descriptor_length + extra_fields_length; assert!( - (self.position + 2 + length) <= self.buf.len() && (length + 2) <= 255, + (self.position + 2 + total_length) <= self.buf.len() && (total_length + 2) <= 255, "Descriptor buffer full" ); - self.buf[self.position] = (length + 2) as u8; + self.buf[self.position] = (total_length + 2) as u8; self.buf[self.position + 1] = descriptor_type; let start = self.position + 2; - self.buf[start..start + length].copy_from_slice(descriptor); + self.buf[start..start + descriptor_length].copy_from_slice(descriptor); + self.buf[start + descriptor_length..start + total_length].copy_from_slice(extra_fields); - self.position = start + length; + self.position = start + total_length; } pub(crate) fn configuration(&mut self, config: &Config) { @@ -99,6 +137,7 @@ impl<'a> DescriptorWriter<'a> { | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes (config.max_power / 2) as u8, // bMaxPower ], + &[], ); } @@ -145,6 +184,7 @@ impl<'a> DescriptorWriter<'a> { function_protocol, 0, ], + &[], ); } @@ -195,6 +235,7 @@ impl<'a> DescriptorWriter<'a> { interface_protocol, // bInterfaceProtocol str_index, // iInterface ], + &[], ); } @@ -204,21 +245,50 @@ impl<'a> DescriptorWriter<'a> { /// /// * `endpoint` - Endpoint previously allocated with /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder). - pub fn endpoint(&mut self, endpoint: &EndpointInfo) { + /// * `synchronization_type` - The synchronization type of the endpoint. + /// * `usage_type` - The usage type of the endpoint. + /// * `extra_fields` - Additional, class-specific entries at the end of the endpoint descriptor. + pub fn endpoint( + &mut self, + endpoint: &EndpointInfo, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) { match self.num_endpoints_mark { Some(mark) => self.buf[mark] += 1, None => panic!("you can only call `endpoint` after `interface/interface_alt`."), }; + let mut bm_attributes = endpoint.ep_type as u8; + + // Synchronization types other than `NoSynchronization`, + // and usage types other than `DataEndpoint` + // are only allowed for isochronous endpoints. + if endpoint.ep_type != EndpointType::Isochronous { + assert_eq!(synchronization_type, SynchronizationType::NoSynchronization); + assert_eq!(usage_type, UsageType::DataEndpoint); + } else { + if usage_type == UsageType::FeedbackEndpoint { + assert_eq!(synchronization_type, SynchronizationType::NoSynchronization) + } + + let synchronization_bm_attibutes: u8 = (synchronization_type as u8) << 2; + let usage_bm_attibutes: u8 = (usage_type as u8) << 4; + + bm_attributes |= usage_bm_attibutes | synchronization_bm_attibutes; + } + self.write( descriptor_type::ENDPOINT, &[ - endpoint.addr.into(), // bEndpointAddress - endpoint.ep_type as u8, // bmAttributes + endpoint.addr.into(), // bEndpointAddress + bm_attributes, // bmAttributes endpoint.max_packet_size as u8, (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize endpoint.interval_ms, // bInterval ], + extra_fields, ); } @@ -315,6 +385,7 @@ impl<'a> BosWriter<'a> { 0x00, 0x00, // wTotalLength 0x00, // bNumDeviceCaps ], + &[], ); self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]); From ccce870642f295cda901493df422b25d211da503 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 18:01:05 -0400 Subject: [PATCH 157/210] ci: Fix the "test" task when using stm32-metapac from a CI artifact --- .github/ci/test.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index da0021684..0de265049 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target +# needed for "dumb HTTP" transport support +# used when pointing stm32-metapac to a CI-built one. +export CARGO_NET_GIT_FETCH_WITH_CLI=true + cargo test --manifest-path ./embassy-futures/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml From ac7ebea762519505a0ea54ce753ec2a9fc67dfe9 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 09:34:39 +0200 Subject: [PATCH 158/210] Make sure to CFUN=0 before changing configuration --- embassy-net-nrf91/src/context.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index b936e5f87..d5d088ec0 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -92,10 +92,21 @@ impl<'a> Control<'a> { } /// Configures the modem with the provided config. + /// + /// NOTE: This will disconnect the modem from any current APN and should not + /// be called if the configuration has not been changed. pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(0) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + let op = CommandBuilder::create_set(&mut cmd, true) .named("+CGDCONT") .with_int_parameter(self.cid) @@ -104,6 +115,7 @@ impl<'a> Control<'a> { .finish() .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; + // info!("RES1: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) }); CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; let mut op = CommandBuilder::create_set(&mut cmd, true) @@ -116,6 +128,7 @@ impl<'a> Control<'a> { let op = op.finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; + // info!("RES2: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) }); CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; let op = CommandBuilder::create_set(&mut cmd, true) From 5e74434cb8b89b62f7bc0d2a9ab90d94aa11fe4b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 09:52:26 +0200 Subject: [PATCH 159/210] Ensure modem is enabled in run() --- embassy-net-nrf91/src/context.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index d5d088ec0..2f2452bd0 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -303,6 +303,18 @@ impl<'a> Control<'a> { /// Run a control loop for this context, ensuring that reaattach is handled. pub async fn run(&self, reattach: F) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + + // Make sure modem is enabled + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); From e2e3143c2ea9a606eff2fa1d4e51a74824b5c2ac Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 09:58:54 +0200 Subject: [PATCH 160/210] Add explicit disable/enable function and skip enable in configure --- embassy-net-nrf91/src/context.rs | 55 ++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 2f2452bd0..22629fe5b 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -95,6 +95,8 @@ impl<'a> Control<'a> { /// /// NOTE: This will disconnect the modem from any current APN and should not /// be called if the configuration has not been changed. + /// + /// After configuring, invoke [`enable()`] to activate the configuration. pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; @@ -131,22 +133,6 @@ impl<'a> Control<'a> { // info!("RES2: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) }); CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - let op = CommandBuilder::create_set(&mut cmd, true) - .named("+CFUN") - .with_int_parameter(1) - .finish() - .map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(op, &mut buf).await; - CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - - let op = CommandBuilder::create_set(&mut cmd, true) - .named("%XPDNCFG") - .with_int_parameter(1) - .finish() - .map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(op, &mut buf).await; - CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - Ok(()) } @@ -301,20 +287,49 @@ impl<'a> Control<'a> { Ok(status) } - /// Run a control loop for this context, ensuring that reaattach is handled. - pub async fn run(&self, reattach: F) -> Result<(), Error> { + /// Disable modem + pub async fn disable(&self) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(0) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + Ok(()) + } + + /// Enable modem + pub async fn enable(&self) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; - // Make sure modem is enabled let op = CommandBuilder::create_set(&mut cmd, true) .named("+CFUN") .with_int_parameter(1) .finish() .map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + // Make modem survive PDN detaches + let op = CommandBuilder::create_set(&mut cmd, true) + .named("%XPDNCFG") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + Ok(()) + } + + /// Run a control loop for this context, ensuring that reaattach is handled. + pub async fn run(&self, reattach: F) -> Result<(), Error> { + self.enable().await?; let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); From 01d8508b6c9bf89e27a83b9587bcc13c358c1e51 Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Fri, 6 Sep 2024 11:16:44 +0200 Subject: [PATCH 161/210] fix: nightly api changed during the night --- embassy-executor/src/raw/waker.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index 8d3910a25..8bb2cfd05 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -50,8 +50,7 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { #[cfg(feature = "nightly")] { - let raw_waker = waker.as_raw(); - (raw_waker.vtable(), raw_waker.data()) + (waker.vtable(), waker.data()) } }; From 1b1db2401bfdfe6f813fb7738529749e4ec80882 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 11:22:07 +0200 Subject: [PATCH 162/210] Use byte slice for config --- embassy-net-nrf91/src/context.rs | 4 ++-- examples/nrf9160/src/bin/modem_tcp_client.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 22629fe5b..8b45919ef 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -16,11 +16,11 @@ pub struct Control<'a> { /// Configuration for a given context pub struct Config<'a> { /// Desired APN address. - pub apn: &'a str, + pub apn: &'a [u8], /// Desired authentication protocol. pub auth_prot: AuthProt, /// Credentials. - pub auth: Option<(&'a str, &'a str)>, + pub auth: Option<(&'a [u8], &'a [u8])>, } /// Authentication protocol. diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 7d78eba0a..5335b6b51 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -166,9 +166,9 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(control_task( control, context::Config { - apn: "iot.nat.es", + apn: b"iot.nat.es", auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), + auth: Some((b"orange", b"orange")), }, stack ))); From 5b4941a51040d1bbcc00590a504e078e2f72f3bd Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Fri, 6 Sep 2024 11:29:12 +0200 Subject: [PATCH 163/210] ci: update rust-toolchain --- rust-toolchain-nightly.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index dfa231344..0b10d7194 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-07-16" +channel = "nightly-2024-09-06" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", From 1443f3386b3b216dc50306d14f5dacce29b2bf97 Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Fri, 6 Sep 2024 11:34:30 +0200 Subject: [PATCH 164/210] fix: remove stable nightly feature --- embassy-executor/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 553ed76d3..6a2e493a2 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -1,5 +1,4 @@ #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] -#![cfg_attr(feature = "nightly", feature(waker_getters))] #![allow(clippy::new_without_default)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] From ee25f14b20fc2aabf428fbc7b2bd684ece66a2a1 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 6 Sep 2024 18:35:23 +0200 Subject: [PATCH 165/210] fix(stm32): reorder dma and idle futures --- embassy-stm32/src/usart/ringbuffered.rs | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 8cf75933a..b0652046c 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -184,20 +184,6 @@ impl<'d> RingBufferedUartRx<'d> { async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { compiler_fence(Ordering::SeqCst); - let mut dma_init = false; - // Future which completes when there is dma is half full or full - let dma = poll_fn(|cx| { - self.ring_buf.set_waker(cx.waker()); - - let status = match dma_init { - false => Poll::Pending, - true => Poll::Ready(()), - }; - - dma_init = true; - status - }); - // Future which completes when idle line is detected let s = self.state; let uart = poll_fn(|cx| { @@ -219,9 +205,23 @@ impl<'d> RingBufferedUartRx<'d> { } }); - match select(dma, uart).await { - Either::Left(((), _)) => Ok(()), - Either::Right((result, _)) => result, + let mut dma_init = false; + // Future which completes when there is dma is half full or full + let dma = poll_fn(|cx| { + self.ring_buf.set_waker(cx.waker()); + + let status = match dma_init { + false => Poll::Pending, + true => Poll::Ready(()), + }; + + dma_init = true; + status + }); + + match select(uart, dma).await { + Either::Left((result, _)) => result, + Either::Right(((), _)) => Ok(()), } } } From 0e477a4df506981e770e41edec31e2bc0cd6b6c6 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 6 Sep 2024 18:36:11 +0200 Subject: [PATCH 166/210] fix(stm32): enable dma half transfer interrupt for buffereduart --- embassy-stm32/src/dma/dma_bdma.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 8e2964f94..df041c4e9 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -777,6 +777,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { let dir = Dir::PeripheralToMemory; let data_size = W::size(); + options.half_transfer_ir = true; options.complete_transfer_ir = true; options.circular = true; From 74e724f96869680da4893ad7024676bef1c57334 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Sep 2024 02:13:17 +0200 Subject: [PATCH 167/210] Update to Rust 1.81 (#3322) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ce9040a70..80acb3b5e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.80" +channel = "1.81" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From 3ac38e917cc56530fa9b3515fd28a1f576b285e8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 8 Sep 2024 23:48:45 +0200 Subject: [PATCH 168/210] cyw43: use enum for ioctl instead of consts. --- cyw43/src/consts.rs | 299 +++++++++++++++++++++++++++++++++++++++++-- cyw43/src/control.rs | 59 ++++----- cyw43/src/ioctl.rs | 5 +- cyw43/src/runner.rs | 4 +- 4 files changed, 319 insertions(+), 48 deletions(-) diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs index b6e22e61d..d47e5097a 100644 --- a/cyw43/src/consts.rs +++ b/cyw43/src/consts.rs @@ -113,17 +113,6 @@ pub(crate) const IRQ_F1_INTR: u16 = 0x2000; pub(crate) const IRQ_F2_INTR: u16 = 0x4000; pub(crate) const IRQ_F3_INTR: u16 = 0x8000; -pub(crate) const IOCTL_CMD_UP: u32 = 2; -pub(crate) const IOCTL_CMD_DOWN: u32 = 3; -pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26; -pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30; -pub(crate) const IOCTL_CMD_DISASSOC: u32 = 52; -pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64; -pub(crate) const IOCTL_CMD_SET_AP: u32 = 118; -pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263; -pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262; -pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268; - pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0; pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1; pub(crate) const CHANNEL_TYPE_DATA: u8 = 2; @@ -376,3 +365,291 @@ impl core::fmt::Display for FormatInterrupt { core::fmt::Debug::fmt(self, f) } } + +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u32)] +pub(crate) enum Ioctl { + GetMagic = 0, + GetVersion = 1, + Up = 2, + Down = 3, + GetLoop = 4, + SetLoop = 5, + Dump = 6, + GetMsglevel = 7, + SetMsglevel = 8, + GetPromisc = 9, + SetPromisc = 10, + GetRate = 12, + GetInstance = 14, + GetInfra = 19, + SetInfra = 20, + GetAuth = 21, + SetAuth = 22, + GetBssid = 23, + SetBssid = 24, + GetSsid = 25, + SetSsid = 26, + Restart = 27, + GetChannel = 29, + SetChannel = 30, + GetSrl = 31, + SetSrl = 32, + GetLrl = 33, + SetLrl = 34, + GetPlcphdr = 35, + SetPlcphdr = 36, + GetRadio = 37, + SetRadio = 38, + GetPhytype = 39, + DumpRate = 40, + SetRateParams = 41, + GetKey = 44, + SetKey = 45, + GetRegulatory = 46, + SetRegulatory = 47, + GetPassiveScan = 48, + SetPassiveScan = 49, + Scan = 50, + ScanResults = 51, + Disassoc = 52, + Reassoc = 53, + GetRoamTrigger = 54, + SetRoamTrigger = 55, + GetRoamDelta = 56, + SetRoamDelta = 57, + GetRoamScanPeriod = 58, + SetRoamScanPeriod = 59, + Evm = 60, + GetTxant = 61, + SetTxant = 62, + GetAntdiv = 63, + SetAntdiv = 64, + GetClosed = 67, + SetClosed = 68, + GetMaclist = 69, + SetMaclist = 70, + GetRateset = 71, + SetRateset = 72, + Longtrain = 74, + GetBcnprd = 75, + SetBcnprd = 76, + GetDtimprd = 77, + SetDtimprd = 78, + GetSrom = 79, + SetSrom = 80, + GetWepRestrict = 81, + SetWepRestrict = 82, + GetCountry = 83, + SetCountry = 84, + GetPm = 85, + SetPm = 86, + GetWake = 87, + SetWake = 88, + GetForcelink = 90, + SetForcelink = 91, + FreqAccuracy = 92, + CarrierSuppress = 93, + GetPhyreg = 94, + SetPhyreg = 95, + GetRadioreg = 96, + SetRadioreg = 97, + GetRevinfo = 98, + GetUcantdiv = 99, + SetUcantdiv = 100, + RReg = 101, + WReg = 102, + GetMacmode = 105, + SetMacmode = 106, + GetMonitor = 107, + SetMonitor = 108, + GetGmode = 109, + SetGmode = 110, + GetLegacyErp = 111, + SetLegacyErp = 112, + GetRxAnt = 113, + GetCurrRateset = 114, + GetScansuppress = 115, + SetScansuppress = 116, + GetAp = 117, + SetAp = 118, + GetEapRestrict = 119, + SetEapRestrict = 120, + ScbAuthorize = 121, + ScbDeauthorize = 122, + GetWdslist = 123, + SetWdslist = 124, + GetAtim = 125, + SetAtim = 126, + GetRssi = 127, + GetPhyantdiv = 128, + SetPhyantdiv = 129, + ApRxOnly = 130, + GetTxPathPwr = 131, + SetTxPathPwr = 132, + GetWsec = 133, + SetWsec = 134, + GetPhyNoise = 135, + GetBssInfo = 136, + GetPktcnts = 137, + GetLazywds = 138, + SetLazywds = 139, + GetBandlist = 140, + GetBand = 141, + SetBand = 142, + ScbDeauthenticate = 143, + GetShortslot = 144, + GetShortslotOverride = 145, + SetShortslotOverride = 146, + GetShortslotRestrict = 147, + SetShortslotRestrict = 148, + GetGmodeProtection = 149, + GetGmodeProtectionOverride = 150, + SetGmodeProtectionOverride = 151, + Upgrade = 152, + GetIgnoreBcns = 155, + SetIgnoreBcns = 156, + GetScbTimeout = 157, + SetScbTimeout = 158, + GetAssoclist = 159, + GetClk = 160, + SetClk = 161, + GetUp = 162, + Out = 163, + GetWpaAuth = 164, + SetWpaAuth = 165, + GetUcflags = 166, + SetUcflags = 167, + GetPwridx = 168, + SetPwridx = 169, + GetTssi = 170, + GetSupRatesetOverride = 171, + SetSupRatesetOverride = 172, + GetProtectionControl = 178, + SetProtectionControl = 179, + GetPhylist = 180, + EncryptStrength = 181, + DecryptStatus = 182, + GetKeySeq = 183, + GetScanChannelTime = 184, + SetScanChannelTime = 185, + GetScanUnassocTime = 186, + SetScanUnassocTime = 187, + GetScanHomeTime = 188, + SetScanHomeTime = 189, + GetScanNprobes = 190, + SetScanNprobes = 191, + GetPrbRespTimeout = 192, + SetPrbRespTimeout = 193, + GetAtten = 194, + SetAtten = 195, + GetShmem = 196, + SetShmem = 197, + SetWsecTest = 200, + ScbDeauthenticateForReason = 201, + TkipCountermeasures = 202, + GetPiomode = 203, + SetPiomode = 204, + SetAssocPrefer = 205, + GetAssocPrefer = 206, + SetRoamPrefer = 207, + GetRoamPrefer = 208, + SetLed = 209, + GetLed = 210, + GetInterferenceMode = 211, + SetInterferenceMode = 212, + GetChannelQa = 213, + StartChannelQa = 214, + GetChannelSel = 215, + StartChannelSel = 216, + GetValidChannels = 217, + GetFakefrag = 218, + SetFakefrag = 219, + GetPwroutPercentage = 220, + SetPwroutPercentage = 221, + SetBadFramePreempt = 222, + GetBadFramePreempt = 223, + SetLeapList = 224, + GetLeapList = 225, + GetCwmin = 226, + SetCwmin = 227, + GetCwmax = 228, + SetCwmax = 229, + GetWet = 230, + SetWet = 231, + GetPub = 232, + GetKeyPrimary = 235, + SetKeyPrimary = 236, + GetAciArgs = 238, + SetAciArgs = 239, + UnsetCallback = 240, + SetCallback = 241, + GetRadar = 242, + SetRadar = 243, + SetSpectManagment = 244, + GetSpectManagment = 245, + WdsGetRemoteHwaddr = 246, + WdsGetWpaSup = 247, + SetCsScanTimer = 248, + GetCsScanTimer = 249, + MeasureRequest = 250, + Init = 251, + SendQuiet = 252, + Keepalive = 253, + SendPwrConstraint = 254, + UpgradeStatus = 255, + CurrentPwr = 256, + GetScanPassiveTime = 257, + SetScanPassiveTime = 258, + LegacyLinkBehavior = 259, + GetChannelsInCountry = 260, + GetCountryList = 261, + GetVar = 262, + SetVar = 263, + NvramGet = 264, + NvramSet = 265, + NvramDump = 266, + Reboot = 267, + SetWsecPmk = 268, + GetAuthMode = 269, + SetAuthMode = 270, + GetWakeentry = 271, + SetWakeentry = 272, + NdconfigItem = 273, + Nvotpw = 274, + Otpw = 275, + IovBlockGet = 276, + IovModulesGet = 277, + SoftReset = 278, + GetAllowMode = 279, + SetAllowMode = 280, + GetDesiredBssid = 281, + SetDesiredBssid = 282, + DisassocMyap = 283, + GetNbands = 284, + GetBandstates = 285, + GetWlcBssInfo = 286, + GetAssocInfo = 287, + GetOidPhy = 288, + SetOidPhy = 289, + SetAssocTime = 290, + GetDesiredSsid = 291, + GetChanspec = 292, + GetAssocState = 293, + SetPhyState = 294, + GetScanPending = 295, + GetScanreqPending = 296, + GetPrevRoamReason = 297, + SetPrevRoamReason = 298, + GetBandstatesPi = 299, + GetPhyState = 300, + GetBssWpaRsn = 301, + GetBssWpa2Rsn = 302, + GetBssBcnTs = 303, + GetIntDisassoc = 304, + SetNumPeers = 305, + GetNumBss = 306, + GetWsecPmk = 318, + GetRandomBytes = 319, +} diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 22c52bd96..48be772c0 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -109,7 +109,7 @@ impl<'a> Control<'a> { buf[0..8].copy_from_slice(b"clmload\x00"); buf[8..20].copy_from_slice(&header.to_bytes()); buf[20..][..chunk.len()].copy_from_slice(&chunk); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()]) + self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..8 + 12 + chunk.len()]) .await; } @@ -145,7 +145,7 @@ impl<'a> Control<'a> { Timer::after_millis(100).await; // Set antenna to chip antenna - self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; + self.ioctl_set_u32(Ioctl::SetAntdiv, 0, 0).await; self.set_iovar_u32("bus:txglom", 0).await; Timer::after_millis(100).await; @@ -183,8 +183,8 @@ impl<'a> Control<'a> { Timer::after_millis(100).await; - self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto - self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any + self.ioctl_set_u32(Ioctl::SetGmode, 0, 1).await; // SET_GMODE = auto + self.ioctl_set_u32(Ioctl::SetBand, 0, 0).await; // SET_BAND = any Timer::after_millis(100).await; @@ -195,12 +195,12 @@ impl<'a> Control<'a> { /// Set the WiFi interface up. async fn up(&mut self) { - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + self.ioctl(IoctlType::Set, Ioctl::Up, 0, &mut []).await; } /// Set the interface down. async fn down(&mut self) { - self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; + self.ioctl(IoctlType::Set, Ioctl::Down, 0, &mut []).await; } /// Set power management mode. @@ -213,17 +213,17 @@ impl<'a> Control<'a> { self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await; self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await; } - self.ioctl_set_u32(86, 0, mode_num).await; + self.ioctl_set_u32(Ioctl::SetPm, 0, mode_num).await; } /// Join an unprotected network with the provided ssid. pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; - self.ioctl_set_u32(134, 0, 0).await; // wsec = open + self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await; // wsec = open self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0) + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = open (0) let mut i = SsidInfo { len: ssid.len() as _, @@ -238,24 +238,19 @@ impl<'a> Control<'a> { async fn join_wpa2_passphrase_info(&mut self, ssid: &str, passphrase_info: &PassphraseInfo) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; - self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2 + self.ioctl_set_u32(Ioctl::SetWsec, 0, 4).await; // wsec = open self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; Timer::after_millis(100).await; - self.ioctl( - IoctlType::Set, - IOCTL_CMD_SET_PASSPHRASE, - 0, - &mut passphrase_info.to_bytes(), - ) - .await; // WLC_SET_WSEC_PMK + self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut passphrase_info.to_bytes()) + .await; // WLC_SET_WSEC_PMK - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open) - self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = 0 (open) + self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, 0x80).await; let mut i = SsidInfo { len: ssid.len() as _, @@ -294,9 +289,7 @@ impl<'a> Control<'a> { // the actual join operation starts here // we make sure to enable events before so we don't miss any - // set_ssid - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) - .await; + self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await; // to complete the join, we wait for a SET_SSID event // we also save the AUTH status for the user, it may be interesting @@ -357,7 +350,7 @@ impl<'a> Control<'a> { self.up().await; // Turn on AP mode - self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; + self.ioctl_set_u32(Ioctl::SetAp, 0, 1).await; // Set SSID let mut i = SsidInfoWithIndex { @@ -371,7 +364,7 @@ impl<'a> Control<'a> { self.set_iovar("bsscfg:ssid", &i.to_bytes()).await; // Set channel number - self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await; + self.ioctl_set_u32(Ioctl::SetChannel, 0, channel as u32).await; // Set security self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await; @@ -388,7 +381,7 @@ impl<'a> Control<'a> { passphrase: [0; 64], }; pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) + self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) .await; } @@ -405,7 +398,7 @@ impl<'a> Control<'a> { self.set_iovar_u32x2("bss", 0, 0).await; // bss = BSS_DOWN // Turn off AP mode - self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 0).await; + self.ioctl_set_u32(Ioctl::SetAp, 0, 0).await; // Temporarily set wifi down self.down().await; @@ -496,7 +489,7 @@ impl<'a> Control<'a> { buf[name.len() + 1..][..val.len()].copy_from_slice(val); let total_len = name.len() + 1 + val.len(); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len]) + self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len]) .await; } @@ -510,7 +503,7 @@ impl<'a> Control<'a> { let total_len = max(name.len() + 1, res.len()); let res_len = self - .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len]) + .ioctl(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len]) .await; let out_len = min(res.len(), res_len); @@ -518,12 +511,12 @@ impl<'a> Control<'a> { out_len } - async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) { + async fn ioctl_set_u32(&mut self, cmd: Ioctl, iface: u32, val: u32) { let mut buf = val.to_le_bytes(); self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await; } - async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + async fn ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { struct CancelOnDrop<'a>(&'a IoctlState); impl CancelOnDrop<'_> { @@ -615,7 +608,7 @@ impl<'a> Control<'a> { } /// Leave the wifi, with which we are currently associated. pub async fn leave(&mut self) { - self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await; + self.ioctl(IoctlType::Set, Ioctl::Disassoc, 0, &mut []).await; info!("Disassociated") } diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index 61524c274..3186370cc 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -4,6 +4,7 @@ use core::task::{Poll, Waker}; use embassy_sync::waitqueue::WakerRegistration; +use crate::consts::Ioctl; use crate::fmt::Bytes; #[derive(Clone, Copy)] @@ -16,7 +17,7 @@ pub enum IoctlType { pub struct PendingIoctl { pub buf: *mut [u8], pub kind: IoctlType, - pub cmd: u32, + pub cmd: Ioctl, pub iface: u32, } @@ -101,7 +102,7 @@ impl IoctlState { self.state.set(IoctlStateInner::Done { resp_len: 0 }); } - pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + pub async fn do_ioctl(&self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { self.state .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); self.wake_runner(); diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index 959718341..77910b281 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -560,7 +560,7 @@ where self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 } - async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8], buf: &mut [u32; 512]) { + async fn send_ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, data: &[u8], buf: &mut [u32; 512]) { let buf8 = slice8_mut(buf); let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); @@ -582,7 +582,7 @@ where }; let cdc_header = CdcHeader { - cmd: cmd, + cmd: cmd as u32, len: data.len() as _, flags: kind as u16 | (iface as u16) << 12, id: self.ioctl_id, From 6b21f6d3d1f48bfa722d648918e06b627350bbff Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Sep 2024 01:03:41 +0200 Subject: [PATCH 169/210] cyw43: log ioctls. --- cyw43/src/control.rs | 16 ++++++++++++---- cyw43/src/ioctl.rs | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 48be772c0..97dcb4d09 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -481,7 +481,7 @@ impl<'a> Control<'a> { } async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { - debug!("set {} = {:02x}", name, Bytes(val)); + debug!("iovar set {} = {:02x}", name, Bytes(val)); let mut buf = [0; BUFSIZE]; buf[..name.len()].copy_from_slice(name.as_bytes()); @@ -489,13 +489,13 @@ impl<'a> Control<'a> { buf[name.len() + 1..][..val.len()].copy_from_slice(val); let total_len = name.len() + 1 + val.len(); - self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len]) + self.ioctl_inner(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len]) .await; } // TODO this is not really working, it always returns all zeros. async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { - debug!("get {}", name); + debug!("iovar get {}", name); let mut buf = [0; 64]; buf[..name.len()].copy_from_slice(name.as_bytes()); @@ -503,7 +503,7 @@ impl<'a> Control<'a> { let total_len = max(name.len() + 1, res.len()); let res_len = self - .ioctl(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len]) + .ioctl_inner(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len]) .await; let out_len = min(res.len(), res_len); @@ -517,6 +517,14 @@ impl<'a> Control<'a> { } async fn ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { + if kind == IoctlType::Set { + debug!("ioctl set {:?} iface {} = {:02x}", cmd, iface, Bytes(buf)); + } + let n = self.ioctl_inner(kind, cmd, iface, buf).await; + n + } + + async fn ioctl_inner(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { struct CancelOnDrop<'a>(&'a IoctlState); impl CancelOnDrop<'_> { diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index 3186370cc..f8b2d9aba 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -7,7 +7,7 @@ use embassy_sync::waitqueue::WakerRegistration; use crate::consts::Ioctl; use crate::fmt::Bytes; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum IoctlType { Get = 0, Set = 2, From b9a1aaea5b89bd5689796bdfa4227353ee8a452b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Sep 2024 01:09:15 +0200 Subject: [PATCH 170/210] cyw43: add support for WPA3 and more extensive security options. --- cyw43/src/consts.rs | 15 ++ cyw43/src/control.rs | 196 ++++++++++++++++++------- cyw43/src/lib.rs | 4 +- cyw43/src/structs.rs | 9 ++ examples/rp/src/bin/wifi_tcp_server.rs | 7 +- examples/rp/src/bin/wifi_webrequest.rs | 7 +- tests/rp/src/bin/cyw43-perf.rs | 6 +- 7 files changed, 181 insertions(+), 63 deletions(-) diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs index d47e5097a..c3f0dbfd8 100644 --- a/cyw43/src/consts.rs +++ b/cyw43/src/consts.rs @@ -653,3 +653,18 @@ pub(crate) enum Ioctl { GetWsecPmk = 318, GetRandomBytes = 319, } + +pub(crate) const WSEC_TKIP: u32 = 0x02; +pub(crate) const WSEC_AES: u32 = 0x04; + +pub(crate) const AUTH_OPEN: u32 = 0x00; +pub(crate) const AUTH_SAE: u32 = 0x03; + +pub(crate) const MFP_NONE: u32 = 0; +pub(crate) const MFP_CAPABLE: u32 = 1; +pub(crate) const MFP_REQUIRED: u32 = 2; + +pub(crate) const WPA_AUTH_DISABLED: u32 = 0x0000; +pub(crate) const WPA_AUTH_WPA_PSK: u32 = 0x0004; +pub(crate) const WPA_AUTH_WPA2_PSK: u32 = 0x0080; +pub(crate) const WPA_AUTH_WPA3_SAE_PSK: u32 = 0x40000; diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 97dcb4d09..071ba88e4 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -35,7 +35,7 @@ pub struct Control<'a> { ioctl_state: &'a IoctlState, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ScanType { Active, @@ -43,8 +43,9 @@ pub enum ScanType { } /// Scan options. -#[derive(Clone)] +#[derive(Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] pub struct ScanOptions { /// SSID to scan for. pub ssid: Option>, @@ -74,6 +75,79 @@ impl Default for ScanOptions { } } +/// Authentication type, used in [`JoinOptions::auth`]. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum JoinAuth { + /// Open network + Open, + /// WPA only + Wpa, + /// WPA2 only + Wpa2, + /// WPA3 only + Wpa3, + /// WPA2 + WPA3 + Wpa2Wpa3, +} + +/// Options for [`Control::join`]. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct JoinOptions<'a> { + /// Authentication type. Default `Wpa2Wpa3`. + pub auth: JoinAuth, + /// Enable TKIP encryption. Default false. + pub cipher_tkip: bool, + /// Enable AES encryption. Default true. + pub cipher_aes: bool, + /// Passphrase. Default empty. + pub passphrase: &'a [u8], + /// If false, `passphrase` is the human-readable passphrase string. + /// If true, `passphrase` is the result of applying the PBKDF2 hash to the + /// passphrase string. This makes it possible to avoid storing unhashed passwords. + /// + /// This is not compatible with WPA3. + /// Default false. + pub passphrase_is_prehashed: bool, +} + +impl<'a> JoinOptions<'a> { + /// Create a new `JoinOptions` for joining open networks. + pub fn new_open() -> Self { + Self { + auth: JoinAuth::Open, + cipher_tkip: false, + cipher_aes: false, + passphrase: &[], + passphrase_is_prehashed: false, + } + } + + /// Create a new `JoinOptions` for joining encrypted networks. + /// + /// Defaults to supporting WPA2+WPA3 with AES only, you may edit + /// the returned options to change this. + pub fn new(passphrase: &'a [u8]) -> Self { + let mut this = Self::default(); + this.passphrase = passphrase; + this + } +} + +impl<'a> Default for JoinOptions<'a> { + fn default() -> Self { + Self { + auth: JoinAuth::Wpa2Wpa3, + cipher_tkip: false, + cipher_aes: true, + passphrase: &[], + passphrase_is_prehashed: false, + } + } +} + impl<'a> Control<'a> { pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { Self { @@ -217,13 +291,70 @@ impl<'a> Control<'a> { } /// Join an unprotected network with the provided ssid. - pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { + pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; - self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await; // wsec = open - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; - self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = open (0) + if options.auth == JoinAuth::Open { + self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await; + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; + self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; + self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, WPA_AUTH_DISABLED).await; + } else { + let mut wsec = 0; + if options.cipher_aes { + wsec |= WSEC_AES; + } + if options.cipher_tkip { + wsec |= WSEC_TKIP; + } + self.ioctl_set_u32(Ioctl::SetWsec, 0, wsec).await; + + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; + self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; + self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; + + Timer::after_millis(100).await; + + let (wpa12, wpa3, auth, mfp, wpa_auth) = match options.auth { + JoinAuth::Open => unreachable!(), + JoinAuth::Wpa => (true, false, AUTH_OPEN, MFP_NONE, WPA_AUTH_WPA_PSK), + JoinAuth::Wpa2 => (true, false, AUTH_OPEN, MFP_CAPABLE, WPA_AUTH_WPA2_PSK), + JoinAuth::Wpa3 => (false, true, AUTH_SAE, MFP_REQUIRED, WPA_AUTH_WPA3_SAE_PSK), + JoinAuth::Wpa2Wpa3 => (true, true, AUTH_SAE, MFP_CAPABLE, WPA_AUTH_WPA3_SAE_PSK), + }; + + if wpa12 { + let mut flags = 0; + if !options.passphrase_is_prehashed { + flags |= 1; + } + let mut pfi = PassphraseInfo { + len: options.passphrase.len() as _, + flags, + passphrase: [0; 64], + }; + pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase); + Timer::after_millis(3).await; + self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) + .await; + } + + if wpa3 { + let mut pfi = SaePassphraseInfo { + len: options.passphrase.len() as _, + passphrase: [0; 128], + }; + pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase); + Timer::after_millis(3).await; + self.set_iovar("sae_password", &pfi.to_bytes()).await; + } + + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; + self.ioctl_set_u32(Ioctl::SetAuth, 0, auth).await; + self.set_iovar_u32("mfp", mfp).await; + self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, wpa_auth).await; + } let mut i = SsidInfo { len: ssid.len() as _, @@ -234,55 +365,6 @@ impl<'a> Control<'a> { self.wait_for_join(i).await } - /// Join a protected network with the provided ssid and [`PassphraseInfo`]. - async fn join_wpa2_passphrase_info(&mut self, ssid: &str, passphrase_info: &PassphraseInfo) -> Result<(), Error> { - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - - self.ioctl_set_u32(Ioctl::SetWsec, 0, 4).await; // wsec = open - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; - self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; - self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; - - Timer::after_millis(100).await; - - self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut passphrase_info.to_bytes()) - .await; // WLC_SET_WSEC_PMK - - self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = 0 (open) - self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, 0x80).await; - - let mut i = SsidInfo { - len: ssid.len() as _, - ssid: [0; 32], - }; - i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); - - self.wait_for_join(i).await - } - - /// Join a protected network with the provided ssid and passphrase. - pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - let mut pfi = PassphraseInfo { - len: passphrase.len() as _, - flags: 1, - passphrase: [0; 64], - }; - pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes()); - self.join_wpa2_passphrase_info(ssid, &pfi).await - } - - /// Join a protected network with the provided ssid and precomputed PSK. - pub async fn join_wpa2_psk(&mut self, ssid: &str, psk: &[u8; 32]) -> Result<(), Error> { - let mut pfi = PassphraseInfo { - len: psk.len() as _, - flags: 0, - passphrase: [0; 64], - }; - pfi.passphrase[..psk.len()].copy_from_slice(psk); - self.join_wpa2_passphrase_info(ssid, &pfi).await - } - async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); let mut subscriber = self.events.queue.subscriber().unwrap(); @@ -477,7 +559,7 @@ impl<'a> Control<'a> { } async fn set_iovar(&mut self, name: &str, val: &[u8]) { - self.set_iovar_v::<64>(name, val).await + self.set_iovar_v::<196>(name, val).await } async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index efeb3f313..6b71c18e6 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -28,7 +28,9 @@ use ioctl::IoctlState; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; -pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, ScanOptions, Scanner}; +pub use crate::control::{ + AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, Scanner, +}; pub use crate::runner::Runner; pub use crate::structs::BssInfo; diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs index ae7ef6038..81ae6a98d 100644 --- a/cyw43/src/structs.rs +++ b/cyw43/src/structs.rs @@ -394,6 +394,15 @@ pub struct PassphraseInfo { } impl_bytes!(PassphraseInfo); +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct SaePassphraseInfo { + pub len: u16, + pub passphrase: [u8; 128], +} +impl_bytes!(SaePassphraseInfo); + #[derive(Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(C)] diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 61eeb82f7..b2950d98a 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -7,6 +7,7 @@ use core::str::from_utf8; +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; @@ -95,8 +96,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - //control.join_open(WIFI_NETWORK).await; - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { info!("join failed with status={}", err.status); diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 889371241..b43be8905 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -7,6 +7,7 @@ use core::str::from_utf8; +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; @@ -98,8 +99,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - //match control.join_open(WIFI_NETWORK).await { // for open networks - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { info!("join failed with status={}", err.status); diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 38fbde7c1..11c8aa58c 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -2,6 +2,7 @@ #![no_main] teleprobe_meta::target!(b"rpi-pico"); +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::{panic, *}; use embassy_executor::Spawner; @@ -81,7 +82,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { panic!("join failed with status={}", err.status); From 6af1cb7a20fe15750b353e2e6af6832786f8c065 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 9 Sep 2024 15:45:15 +0200 Subject: [PATCH 171/210] Use TX_BUF_SIZE matching MTU --- embassy-net-nrf91/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index d8cbe47fc..60cdc38c6 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -279,7 +279,7 @@ impl State { } const TX_BUF_COUNT: usize = 4; -const TX_BUF_SIZE: usize = 1024; +const TX_BUF_SIZE: usize = 1500; struct TraceChannelInfo { ptr: *mut TraceChannel, From e698fbe598def25a1aa3e2a2625144817f2fa12d Mon Sep 17 00:00:00 2001 From: elagil Date: Tue, 10 Sep 2024 21:33:31 +0200 Subject: [PATCH 172/210] fix: pull-down clock/data lines for receive --- embassy-stm32/src/sai/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 6bf184dd8..63f48ace0 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -661,12 +661,12 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AfType, AfType) { //sd is defined by tx/rx mode match tx_rx { TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh), - TxRx::Receiver => AfType::input(Pull::None), + TxRx::Receiver => AfType::input(Pull::Down), // Ensure mute level when no input is connected. }, //clocks (mclk, sck and fs) are defined by master/slave match mode { Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh), - Mode::Slave => AfType::input(Pull::None), + Mode::Slave => AfType::input(Pull::Down), // Ensure no clocks when no input is connected. }, ) } From a1c9a2e8bd83852d774255c82e71d2054c7c02e4 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 29 Aug 2024 16:18:43 -0400 Subject: [PATCH 173/210] First working draft of a lptim driver This driver is able to PWM a pin --- embassy-stm32/build.rs | 2 + embassy-stm32/src/lib.rs | 2 + embassy-stm32/src/lptim/mod.rs | 145 ++++++++++++++++++++++++++++++ embassy-stm32/src/lptim/traits.rs | 95 ++++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 embassy-stm32/src/lptim/mod.rs create mode 100644 embassy-stm32/src/lptim/traits.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 1984a1420..33985a3f4 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1015,6 +1015,8 @@ fn main() { (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)), (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)), (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), + (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)), + (("lptim", "CH2"), quote!(crate::lptim::Channel1Pin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 98695e738..451f595e0 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -89,6 +89,8 @@ pub mod i2s; pub mod ipcc; #[cfg(feature = "low-power")] pub mod low_power; +#[cfg(lptim)] +pub mod lptim; #[cfg(ltdc)] pub mod ltdc; #[cfg(opamp)] diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs new file mode 100644 index 000000000..3cf95149e --- /dev/null +++ b/embassy-stm32/src/lptim/mod.rs @@ -0,0 +1,145 @@ +//! Low-power timer (LPTIM) + +mod traits; + +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +pub use traits::Instance; + +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +// use crate::time::Hertz; +use crate::{rcc, Peripheral}; + +/// LPTIM master instance. +pub struct Master { + phantom: PhantomData, +} + +/// LPTIM channel 1 instance. +pub struct Ch1 { + phantom: PhantomData, +} + +/// LPTIM channel 2 instance. +pub struct Ch2 { + phantom: PhantomData, +} + +trait SealedChannel { + fn raw() -> usize; +} + +/// channel instance trait. +#[allow(private_bounds)] +pub trait Channel: SealedChannel {} + +/// LPTIM PWM pin. +pub struct PwmPin<'d, T, C> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(T, C)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident) => { + impl<'d, T: Instance> PwmPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + AfType::output(OutputType::PushPull, Speed::VeryHigh), + ); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + + impl SealedChannel for $channel { + fn raw() -> usize { + $ch_num + } + } + impl Channel for $channel {} + }; +} + +channel_impl!(new_ch1, Ch1, 0, Channel1Pin); +channel_impl!(new_ch2, Ch2, 1, Channel2Pin); + +/// Struct used to divide a high resolution timer into multiple channels +pub struct Pwm<'d, T: Instance> { + _inner: PeripheralRef<'d, T>, + /// Master instance. + pub master: Master, + /// Channel 1. + pub ch_1: Ch1, + /// Channel 2. + pub ch_2: Ch2, +} + +impl<'d, T: Instance> Pwm<'d, T> { + /// Create a new LPTIM driver. + /// + /// This splits the LPTIM into its constituent parts, which you can then use individually. + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1: Option>>, + _ch2: Option>>, + ) -> Self { + Self::new_inner(tim) + } + + fn new_inner(tim: impl Peripheral

+ 'd) -> Self { + into_ref!(tim); + + rcc::enable_and_reset::(); + + T::regs().cr().modify(|w| w.set_enable(true)); + + // Set frequency. Should be configurable. + // By default, 16MHz. We want 440Hz. + // That's 36363 cycles + T::regs().arr().write_value(stm32_metapac::lptim::regs::Arr(36363)); + + // Set duty cycle. Should be configurable. Should take care of channel too (only Ch1 now) + T::regs().ccr(0).write_value(stm32_metapac::lptim::regs::Ccr(18181)); + + // Enable channel as PWM. Default state anyway. Implement later. + // T::regs().ccmr().modify(|w| { + // w.set_ccsel(0, 0); + // w.set_ccsel(1, 0); + // }) + + // Enable output on pins. Should care about the channels! + T::regs().ccmr().modify(|w| { + w.set_cce(0, true); + w.set_cce(1, true); + }); + + Self { + _inner: tim, + master: Master { phantom: PhantomData }, + ch_1: Ch1 { phantom: PhantomData }, + ch_2: Ch2 { phantom: PhantomData }, + } + } + + /// Start + pub fn start(&mut self) { + T::regs().cr().modify(|w| w.set_cntstrt(true)); + } + + /// Stop + pub fn stop(&mut self) { + T::regs().cr().modify(|w| w.set_cntstrt(false)); + } +} + +pin_trait!(Channel1Pin, Instance); +pin_trait!(Channel2Pin, Instance); diff --git a/embassy-stm32/src/lptim/traits.rs b/embassy-stm32/src/lptim/traits.rs new file mode 100644 index 000000000..a8f890a78 --- /dev/null +++ b/embassy-stm32/src/lptim/traits.rs @@ -0,0 +1,95 @@ +use crate::rcc::RccPeripheral; +use crate::time::Hertz; + +#[repr(u8)] +#[derive(Clone, Copy)] +pub(crate) enum Prescaler { + Div1 = 1, + Div2 = 2, + Div4 = 4, + Div8 = 8, + Div16 = 16, + Div32 = 32, + Div64 = 64, + Div128 = 128, +} + +impl From for u8 { + fn from(val: Prescaler) -> Self { + match val { + Prescaler::Div1 => 0b000, + Prescaler::Div2 => 0b001, + Prescaler::Div4 => 0b010, + Prescaler::Div8 => 0b011, + Prescaler::Div16 => 0b100, + Prescaler::Div32 => 0b101, + Prescaler::Div64 => 0b110, + Prescaler::Div128 => 0b111, + } + } +} + +impl From for Prescaler { + fn from(val: u8) -> Self { + match val { + 0b000 => Prescaler::Div1, + 0b001 => Prescaler::Div2, + 0b010 => Prescaler::Div4, + 0b011 => Prescaler::Div8, + 0b100 => Prescaler::Div16, + 0b101 => Prescaler::Div32, + 0b110 => Prescaler::Div64, + 0b111 => Prescaler::Div128, + _ => unreachable!(), + } + } +} + +impl Prescaler { + pub fn compute_min_high_res(val: u32) -> Self { + *[ + Prescaler::Div1, + Prescaler::Div2, + Prescaler::Div4, + Prescaler::Div8, + Prescaler::Div16, + Prescaler::Div32, + Prescaler::Div64, + Prescaler::Div128, + ] + .iter() + .skip_while(|psc| **psc as u32 <= val) + .next() + .unwrap() + } + + pub fn compute_min_low_res(val: u32) -> Self { + *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] + .iter() + .skip_while(|psc| **psc as u32 <= val) + .next() + .unwrap() + } +} + +pub(crate) trait SealedInstance: RccPeripheral { + fn regs() -> crate::pac::lptim::LptimAdv; +} + +/// LPTIM instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} + +foreach_interrupt! { + ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { + impl SealedInstance for crate::peripherals::$inst { + fn regs() -> crate::pac::lptim::LptimAdv { + crate::pac::$inst + } + } + + impl Instance for crate::peripherals::$inst { + + } + }; +} From 3b8859653e4028c194ceed9432a4f76c3c856816 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 4 Sep 2024 14:46:35 -0400 Subject: [PATCH 174/210] stm32: Clean up the lptim driver --- embassy-stm32/src/lptim/mod.rs | 166 +++++------------------ embassy-stm32/src/lptim/pwm.rs | 122 +++++++++++++++++ embassy-stm32/src/lptim/timer.rs | 212 ++++++++++++++++++++++++++++++ embassy-stm32/src/lptim/traits.rs | 95 ------------- 4 files changed, 369 insertions(+), 226 deletions(-) create mode 100644 embassy-stm32/src/lptim/pwm.rs create mode 100644 embassy-stm32/src/lptim/timer.rs delete mode 100644 embassy-stm32/src/lptim/traits.rs diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 3cf95149e..baedf9fe2 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -1,145 +1,49 @@ //! Low-power timer (LPTIM) -mod traits; +pub mod pwm; +pub mod timer; -use core::marker::PhantomData; +use crate::rcc::RccPeripheral; -use embassy_hal_internal::{into_ref, PeripheralRef}; -pub use traits::Instance; - -use crate::gpio::{AfType, AnyPin, OutputType, Speed}; -// use crate::time::Hertz; -use crate::{rcc, Peripheral}; - -/// LPTIM master instance. -pub struct Master { - phantom: PhantomData, -} - -/// LPTIM channel 1 instance. -pub struct Ch1 { - phantom: PhantomData, -} - -/// LPTIM channel 2 instance. -pub struct Ch2 { - phantom: PhantomData, -} - -trait SealedChannel { - fn raw() -> usize; -} - -/// channel instance trait. -#[allow(private_bounds)] -pub trait Channel: SealedChannel {} - -/// LPTIM PWM pin. -pub struct PwmPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(T, C)>, -} - -macro_rules! channel_impl { - ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident) => { - impl<'d, T: Instance> PwmPin<'d, T, $channel> { - #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - AfType::output(OutputType::PushPull, Speed::VeryHigh), - ); - }); - PwmPin { - _pin: pin.map_into(), - phantom: PhantomData, - } - } - } - - impl SealedChannel for $channel { - fn raw() -> usize { - $ch_num - } - } - impl Channel for $channel {} - }; -} - -channel_impl!(new_ch1, Ch1, 0, Channel1Pin); -channel_impl!(new_ch2, Ch2, 1, Channel2Pin); - -/// Struct used to divide a high resolution timer into multiple channels -pub struct Pwm<'d, T: Instance> { - _inner: PeripheralRef<'d, T>, - /// Master instance. - pub master: Master, +/// Timer channel. +#[derive(Clone, Copy)] +pub enum Channel { /// Channel 1. - pub ch_1: Ch1, + Ch1, /// Channel 2. - pub ch_2: Ch2, + Ch2, } -impl<'d, T: Instance> Pwm<'d, T> { - /// Create a new LPTIM driver. - /// - /// This splits the LPTIM into its constituent parts, which you can then use individually. - pub fn new( - tim: impl Peripheral

+ 'd, - _ch1: Option>>, - _ch2: Option>>, - ) -> Self { - Self::new_inner(tim) - } - - fn new_inner(tim: impl Peripheral

+ 'd) -> Self { - into_ref!(tim); - - rcc::enable_and_reset::(); - - T::regs().cr().modify(|w| w.set_enable(true)); - - // Set frequency. Should be configurable. - // By default, 16MHz. We want 440Hz. - // That's 36363 cycles - T::regs().arr().write_value(stm32_metapac::lptim::regs::Arr(36363)); - - // Set duty cycle. Should be configurable. Should take care of channel too (only Ch1 now) - T::regs().ccr(0).write_value(stm32_metapac::lptim::regs::Ccr(18181)); - - // Enable channel as PWM. Default state anyway. Implement later. - // T::regs().ccmr().modify(|w| { - // w.set_ccsel(0, 0); - // w.set_ccsel(1, 0); - // }) - - // Enable output on pins. Should care about the channels! - T::regs().ccmr().modify(|w| { - w.set_cce(0, true); - w.set_cce(1, true); - }); - - Self { - _inner: tim, - master: Master { phantom: PhantomData }, - ch_1: Ch1 { phantom: PhantomData }, - ch_2: Ch2 { phantom: PhantomData }, +impl Channel { + /// Get the channel index (0..1) + pub fn index(&self) -> usize { + match self { + Channel::Ch1 => 0, + Channel::Ch2 => 1, } } - - /// Start - pub fn start(&mut self) { - T::regs().cr().modify(|w| w.set_cntstrt(true)); - } - - /// Stop - pub fn stop(&mut self) { - T::regs().cr().modify(|w| w.set_cntstrt(false)); - } } pin_trait!(Channel1Pin, Instance); pin_trait!(Channel2Pin, Instance); + +pub(crate) trait SealedInstance: RccPeripheral { + fn regs() -> crate::pac::lptim::LptimAdv; +} + +/// LPTIM instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} +foreach_interrupt! { + ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { + impl SealedInstance for crate::peripherals::$inst { + fn regs() -> crate::pac::lptim::LptimAdv { + crate::pac::$inst + } + } + + impl Instance for crate::peripherals::$inst { + + } + }; +} diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs new file mode 100644 index 000000000..725aa676e --- /dev/null +++ b/embassy-stm32/src/lptim/pwm.rs @@ -0,0 +1,122 @@ +//! PWM driver. + +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use super::timer::{ChannelDirection, Timer}; +use super::{Channel, Channel1Pin, Channel2Pin, Instance}; +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +use crate::time::Hertz; +use crate::Peripheral; + +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} + +/// PWM pin wrapper. +/// +/// This wraps a pin to make it usable with PWM. +pub struct PwmPin<'d, T, C> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(T, C)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + impl<'d, T: Instance> PwmPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + AfType::output(OutputType::PushPull, Speed::VeryHigh), + ); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + }; +} + +channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch2, Ch2, Channel2Pin); + +/// PWM driver. +pub struct Pwm<'d, T: Instance> { + inner: Timer<'d, T>, // _inner: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Pwm<'d, T> { + /// Create a new PWM driver. + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1_pin: Option>, + _ch2_pin: Option>, + freq: Hertz, + ) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.enable(); + this.set_frequency(freq); + + [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { + this.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); + }); + + this.inner.continuous_mode_start(); + + this + } + + /// Enable the given channel. + pub fn enable(&mut self, channel: Channel) { + self.inner.enable_channel(channel, true); + } + + /// Disable the given channel. + pub fn disable(&mut self, channel: Channel) { + self.inner.enable_channel(channel, false); + } + + /// Check whether given channel is enabled + pub fn is_enabled(&self, channel: Channel) -> bool { + self.inner.get_channel_enable_state(channel) + } + + /// Set PWM frequency. + /// + /// Note: when you call this, the max duty value changes, so you will have to + /// call `set_duty` on all channels with the duty calculated based on the new max duty. + pub fn set_frequency(&mut self, frequency: Hertz) { + self.inner.set_frequency(frequency); + } + + /// Get max duty value. + /// + /// This value depends on the configured frequency and the timer's clock rate from RCC. + pub fn get_max_duty(&self) -> u16 { + self.inner.get_max_compare_value() + 1 + } + + /// Set the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn set_duty(&mut self, channel: Channel, duty: u16) { + assert!(duty <= self.get_max_duty()); + self.inner.set_compare_value(channel, duty) + } + + /// Get the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn get_duty(&self, channel: Channel) -> u16 { + self.inner.get_compare_value(channel) + } +} diff --git a/embassy-stm32/src/lptim/timer.rs b/embassy-stm32/src/lptim/timer.rs new file mode 100644 index 000000000..06392b2e7 --- /dev/null +++ b/embassy-stm32/src/lptim/timer.rs @@ -0,0 +1,212 @@ +//! Low-level timer driver. + +use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; + +use super::{Channel, Instance}; +use crate::pac::lptim::vals; +use crate::rcc; +use crate::time::Hertz; + +/// Direction of a low-power timer channel +pub enum ChannelDirection { + /// Use channel as a PWM output + OutputPwm, + /// Use channel as an input capture + InputCapture, +} + +impl From for vals::Ccsel { + fn from(direction: ChannelDirection) -> Self { + match direction { + ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE, + ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE, + } + } +} + +enum Prescaler { + Div1, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +impl From<&Prescaler> for vals::Presc { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => vals::Presc::DIV1, + Prescaler::Div2 => vals::Presc::DIV2, + Prescaler::Div4 => vals::Presc::DIV4, + Prescaler::Div8 => vals::Presc::DIV8, + Prescaler::Div16 => vals::Presc::DIV16, + Prescaler::Div32 => vals::Presc::DIV32, + Prescaler::Div64 => vals::Presc::DIV64, + Prescaler::Div128 => vals::Presc::DIV128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: vals::Presc) -> Self { + match prescaler { + vals::Presc::DIV1 => Prescaler::Div1, + vals::Presc::DIV2 => Prescaler::Div2, + vals::Presc::DIV4 => Prescaler::Div4, + vals::Presc::DIV8 => Prescaler::Div8, + vals::Presc::DIV16 => Prescaler::Div16, + vals::Presc::DIV32 => Prescaler::Div32, + vals::Presc::DIV64 => Prescaler::Div64, + vals::Presc::DIV128 => Prescaler::Div128, + } + } +} + +impl From<&Prescaler> for u32 { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => 1, + Prescaler::Div2 => 2, + Prescaler::Div4 => 4, + Prescaler::Div8 => 8, + Prescaler::Div16 => 16, + Prescaler::Div32 => 32, + Prescaler::Div64 => 64, + Prescaler::Div128 => 128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: u32) -> Self { + match prescaler { + 1 => Prescaler::Div1, + 2 => Prescaler::Div2, + 4 => Prescaler::Div4, + 8 => Prescaler::Div8, + 16 => Prescaler::Div16, + 32 => Prescaler::Div32, + 64 => Prescaler::Div64, + 128 => Prescaler::Div128, + _ => unreachable!(), + } + } +} + +impl Prescaler { + pub fn from_ticks(ticks: u32) -> Self { + // We need to scale down to a 16-bit range + (ticks >> 16).next_power_of_two().into() + } + + pub fn scale_down(&self, ticks: u32) -> u16 { + (ticks / u32::from(self)).try_into().unwrap() + } + + pub fn scale_up(&self, ticks: u16) -> u32 { + u32::from(self) * ticks as u32 + } +} + +/// Low-level timer driver. +pub struct Timer<'d, T: Instance> { + _tim: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Timer<'d, T> { + /// Create a new timer driver. + pub fn new(tim: impl Peripheral

+ 'd) -> Self { + into_ref!(tim); + + rcc::enable_and_reset::(); + + Self { _tim: tim } + } + + /// Enable the timer. + pub fn enable(&self) { + T::regs().cr().modify(|w| w.set_enable(true)); + } + + /// Disable the timer. + pub fn disable(&self) { + T::regs().cr().modify(|w| w.set_enable(false)); + } + + /// Start the timer in single pulse mode. + pub fn single_mode_start(&self) { + T::regs().cr().modify(|w| w.set_sngstrt(true)); + } + + /// Start the timer in continuous mode. + pub fn continuous_mode_start(&self) { + T::regs().cr().modify(|w| w.set_cntstrt(true)); + } + + /// Set channel direction. + pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { + T::regs() + .ccmr() + .modify(|w| w.set_ccsel(channel.index(), direction.into())); + } + + /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. + pub fn set_frequency(&self, frequency: Hertz) { + let f = frequency.0; + assert!(f > 0); + + let pclk_f = T::frequency().0; + + let pclk_ticks_per_timer_period = pclk_f / f; + + let psc = Prescaler::from_ticks(pclk_ticks_per_timer_period); + let arr = psc.scale_down(pclk_ticks_per_timer_period); + + T::regs().cfgr().modify(|r| r.set_presc((&psc).into())); + T::regs().arr().modify(|r| r.set_arr(arr.into())); + } + + /// Get the timer frequency. + pub fn get_frequency(&self) -> Hertz { + let pclk_f = T::frequency(); + let arr = T::regs().arr().read().arr(); + let psc = Prescaler::from(T::regs().cfgr().read().presc()); + + pclk_f / psc.scale_up(arr) + } + + /// Get the clock frequency of the timer (before prescaler is applied). + pub fn get_clock_frequency(&self) -> Hertz { + T::frequency() + } + + /// Enable/disable a channel. + pub fn enable_channel(&self, channel: Channel, enable: bool) { + T::regs().ccmr().modify(|w| { + w.set_cce(channel.index(), enable); + }); + } + + /// Get enable/disable state of a channel + pub fn get_channel_enable_state(&self, channel: Channel) -> bool { + T::regs().ccmr().read().cce(channel.index()) + } + + /// Set compare value for a channel. + pub fn set_compare_value(&self, channel: Channel, value: u16) { + T::regs().ccr(channel.index()).modify(|w| w.set_ccr(value)); + } + + /// Get compare value for a channel. + pub fn get_compare_value(&self, channel: Channel) -> u16 { + T::regs().ccr(channel.index()).read().ccr() + } + + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. + pub fn get_max_compare_value(&self) -> u16 { + T::regs().arr().read().arr() + } +} diff --git a/embassy-stm32/src/lptim/traits.rs b/embassy-stm32/src/lptim/traits.rs deleted file mode 100644 index a8f890a78..000000000 --- a/embassy-stm32/src/lptim/traits.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::rcc::RccPeripheral; -use crate::time::Hertz; - -#[repr(u8)] -#[derive(Clone, Copy)] -pub(crate) enum Prescaler { - Div1 = 1, - Div2 = 2, - Div4 = 4, - Div8 = 8, - Div16 = 16, - Div32 = 32, - Div64 = 64, - Div128 = 128, -} - -impl From for u8 { - fn from(val: Prescaler) -> Self { - match val { - Prescaler::Div1 => 0b000, - Prescaler::Div2 => 0b001, - Prescaler::Div4 => 0b010, - Prescaler::Div8 => 0b011, - Prescaler::Div16 => 0b100, - Prescaler::Div32 => 0b101, - Prescaler::Div64 => 0b110, - Prescaler::Div128 => 0b111, - } - } -} - -impl From for Prescaler { - fn from(val: u8) -> Self { - match val { - 0b000 => Prescaler::Div1, - 0b001 => Prescaler::Div2, - 0b010 => Prescaler::Div4, - 0b011 => Prescaler::Div8, - 0b100 => Prescaler::Div16, - 0b101 => Prescaler::Div32, - 0b110 => Prescaler::Div64, - 0b111 => Prescaler::Div128, - _ => unreachable!(), - } - } -} - -impl Prescaler { - pub fn compute_min_high_res(val: u32) -> Self { - *[ - Prescaler::Div1, - Prescaler::Div2, - Prescaler::Div4, - Prescaler::Div8, - Prescaler::Div16, - Prescaler::Div32, - Prescaler::Div64, - Prescaler::Div128, - ] - .iter() - .skip_while(|psc| **psc as u32 <= val) - .next() - .unwrap() - } - - pub fn compute_min_low_res(val: u32) -> Self { - *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] - .iter() - .skip_while(|psc| **psc as u32 <= val) - .next() - .unwrap() - } -} - -pub(crate) trait SealedInstance: RccPeripheral { - fn regs() -> crate::pac::lptim::LptimAdv; -} - -/// LPTIM instance trait. -#[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static {} - -foreach_interrupt! { - ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { - impl SealedInstance for crate::peripherals::$inst { - fn regs() -> crate::pac::lptim::LptimAdv { - crate::pac::$inst - } - } - - impl Instance for crate::peripherals::$inst { - - } - }; -} From b449e04a88d76b41aae91d98bd66bf2754637d03 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 4 Sep 2024 18:06:46 -0400 Subject: [PATCH 175/210] stm32: Temporary fix around incomplete stm32-metapac --- embassy-stm32/src/lptim/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index baedf9fe2..327a1d44b 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -35,7 +35,7 @@ pub(crate) trait SealedInstance: RccPeripheral { #[allow(private_bounds)] pub trait Instance: SealedInstance + 'static {} foreach_interrupt! { - ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { + ($inst:ident, lptim, LPTIM_ADV, GLOBAL, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::lptim::LptimAdv { crate::pac::$inst From 37130f45e4f74f7b4faeb7cac017c4588e5b422a Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 11:39:09 -0400 Subject: [PATCH 176/210] stm32: Use the updated LPTIM pac --- embassy-stm32/src/lptim/mod.rs | 6 +++--- embassy-stm32/src/lptim/pwm.rs | 1 + embassy-stm32/src/lptim/timer.rs | 9 ++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 327a1d44b..dc5f1d5bb 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -28,16 +28,16 @@ pin_trait!(Channel1Pin, Instance); pin_trait!(Channel2Pin, Instance); pub(crate) trait SealedInstance: RccPeripheral { - fn regs() -> crate::pac::lptim::LptimAdv; + fn regs() -> crate::pac::lptim::Lptim; } /// LPTIM instance trait. #[allow(private_bounds)] pub trait Instance: SealedInstance + 'static {} foreach_interrupt! { - ($inst:ident, lptim, LPTIM_ADV, GLOBAL, $irq:ident) => { + ($inst:ident, lptim, LPTIM, UP, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { - fn regs() -> crate::pac::lptim::LptimAdv { + fn regs() -> crate::pac::lptim::Lptim { crate::pac::$inst } } diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 725aa676e..24725f625 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -66,6 +66,7 @@ impl<'d, T: Instance> Pwm<'d, T> { this.inner.enable(); this.set_frequency(freq); + #[cfg(any(lptim_v2a, lptim_v2b))] [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { this.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); }); diff --git a/embassy-stm32/src/lptim/timer.rs b/embassy-stm32/src/lptim/timer.rs index 06392b2e7..b354c1f61 100644 --- a/embassy-stm32/src/lptim/timer.rs +++ b/embassy-stm32/src/lptim/timer.rs @@ -8,6 +8,7 @@ use crate::rcc; use crate::time::Hertz; /// Direction of a low-power timer channel +#[cfg(any(lptim_v2a, lptim_v2b))] pub enum ChannelDirection { /// Use channel as a PWM output OutputPwm, @@ -15,6 +16,7 @@ pub enum ChannelDirection { InputCapture, } +#[cfg(any(lptim_v2a, lptim_v2b))] impl From for vals::Ccsel { fn from(direction: ChannelDirection) -> Self { match direction { @@ -147,9 +149,10 @@ impl<'d, T: Instance> Timer<'d, T> { } /// Set channel direction. + #[cfg(any(lptim_v2a, lptim_v2b))] pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { T::regs() - .ccmr() + .ccmr(0) .modify(|w| w.set_ccsel(channel.index(), direction.into())); } @@ -185,14 +188,14 @@ impl<'d, T: Instance> Timer<'d, T> { /// Enable/disable a channel. pub fn enable_channel(&self, channel: Channel, enable: bool) { - T::regs().ccmr().modify(|w| { + T::regs().ccmr(0).modify(|w| { w.set_cce(channel.index(), enable); }); } /// Get enable/disable state of a channel pub fn get_channel_enable_state(&self, channel: Channel) -> bool { - T::regs().ccmr().read().cce(channel.index()) + T::regs().ccmr(0).read().cce(channel.index()) } /// Set compare value for a channel. From 652133bce48f39ea5f379d056ca46a7f2ca3a99a Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 15:10:39 -0400 Subject: [PATCH 177/210] stm32: Support LPTIM v1 and v2 --- embassy-stm32/build.rs | 1 + embassy-stm32/src/lptim/channel.rs | 18 ++ embassy-stm32/src/lptim/mod.rs | 22 +-- embassy-stm32/src/lptim/pwm.rs | 107 ++++++++---- .../src/lptim/timer/channel_direction.rs | 18 ++ .../src/lptim/{timer.rs => timer/mod.rs} | 156 +++++------------- embassy-stm32/src/lptim/timer/prescaler.rs | 90 ++++++++++ 7 files changed, 245 insertions(+), 167 deletions(-) create mode 100644 embassy-stm32/src/lptim/channel.rs create mode 100644 embassy-stm32/src/lptim/timer/channel_direction.rs rename embassy-stm32/src/lptim/{timer.rs => timer/mod.rs} (53%) create mode 100644 embassy-stm32/src/lptim/timer/prescaler.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 33985a3f4..511eb6d37 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1017,6 +1017,7 @@ fn main() { (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)), (("lptim", "CH2"), quote!(crate::lptim::Channel1Pin)), + (("lptim", "OUT"), quote!(crate::lptim::OutputPin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), diff --git a/embassy-stm32/src/lptim/channel.rs b/embassy-stm32/src/lptim/channel.rs new file mode 100644 index 000000000..17fc2fb86 --- /dev/null +++ b/embassy-stm32/src/lptim/channel.rs @@ -0,0 +1,18 @@ +/// Timer channel. +#[derive(Clone, Copy)] +pub enum Channel { + /// Channel 1. + Ch1, + /// Channel 2. + Ch2, +} + +impl Channel { + /// Get the channel index (0..1) + pub fn index(&self) -> usize { + match self { + Channel::Ch1 => 0, + Channel::Ch2 => 1, + } + } +} diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index dc5f1d5bb..9c10efa43 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -6,24 +6,12 @@ pub mod timer; use crate::rcc::RccPeripheral; /// Timer channel. -#[derive(Clone, Copy)] -pub enum Channel { - /// Channel 1. - Ch1, - /// Channel 2. - Ch2, -} - -impl Channel { - /// Get the channel index (0..1) - pub fn index(&self) -> usize { - match self { - Channel::Ch1 => 0, - Channel::Ch2 => 1, - } - } -} +#[cfg(any(lptim_v2a, lptim_v2b))] +mod channel; +#[cfg(any(lptim_v2a, lptim_v2b))] +pub use channel::Channel; +pin_trait!(OutputPin, Instance); pin_trait!(Channel1Pin, Instance); pin_trait!(Channel2Pin, Instance); diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 24725f625..586148848 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -4,12 +4,18 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; -use super::timer::{ChannelDirection, Timer}; -use super::{Channel, Channel1Pin, Channel2Pin, Instance}; +use super::timer::Timer; +use super::Instance; +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +use super::OutputPin; +#[cfg(any(lptim_v2a, lptim_v2b))] +use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peripheral; +/// Output marker type. +pub enum Output {} /// Channel 1 marker type. pub enum Ch1 {} /// Channel 2 marker type. @@ -45,14 +51,44 @@ macro_rules! channel_impl { }; } +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +channel_impl!(new, Output, OutputPin); +#[cfg(any(lptim_v2a, lptim_v2b))] channel_impl!(new_ch1, Ch1, Channel1Pin); +#[cfg(any(lptim_v2a, lptim_v2b))] channel_impl!(new_ch2, Ch2, Channel2Pin); /// PWM driver. pub struct Pwm<'d, T: Instance> { - inner: Timer<'d, T>, // _inner: PeripheralRef<'d, T>, + inner: Timer<'d, T>, } +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +impl<'d, T: Instance> Pwm<'d, T> { + /// Create a new PWM driver. + pub fn new(tim: impl Peripheral

+ 'd, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self { + Self::new_inner(tim, freq) + } + + /// Set the duty. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn set_duty(&mut self, duty: u16) { + assert!(duty <= self.get_max_duty()); + self.inner.set_compare_value(duty) + } + + /// Get the duty. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn get_duty(&self) -> u16 { + self.inner.get_compare_value() + } + + fn post_init(&mut self) {} +} + +#[cfg(any(lptim_v2a, lptim_v2b))] impl<'d, T: Instance> Pwm<'d, T> { /// Create a new PWM driver. pub fn new( @@ -61,19 +97,7 @@ impl<'d, T: Instance> Pwm<'d, T> { _ch2_pin: Option>, freq: Hertz, ) -> Self { - let mut this = Self { inner: Timer::new(tim) }; - - this.inner.enable(); - this.set_frequency(freq); - - #[cfg(any(lptim_v2a, lptim_v2b))] - [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { - this.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); - }); - - this.inner.continuous_mode_start(); - - this + Self::new_inner(tim, freq) } /// Enable the given channel. @@ -91,21 +115,6 @@ impl<'d, T: Instance> Pwm<'d, T> { self.inner.get_channel_enable_state(channel) } - /// Set PWM frequency. - /// - /// Note: when you call this, the max duty value changes, so you will have to - /// call `set_duty` on all channels with the duty calculated based on the new max duty. - pub fn set_frequency(&mut self, frequency: Hertz) { - self.inner.set_frequency(frequency); - } - - /// Get max duty value. - /// - /// This value depends on the configured frequency and the timer's clock rate from RCC. - pub fn get_max_duty(&self) -> u16 { - self.inner.get_max_compare_value() + 1 - } - /// Set the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. @@ -120,4 +129,40 @@ impl<'d, T: Instance> Pwm<'d, T> { pub fn get_duty(&self, channel: Channel) -> u16 { self.inner.get_compare_value(channel) } + + fn post_init(&mut self) { + [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { + self.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); + }); + } +} + +impl<'d, T: Instance> Pwm<'d, T> { + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.enable(); + this.set_frequency(freq); + + this.post_init(); + + this.inner.continuous_mode_start(); + + this + } + + /// Set PWM frequency. + /// + /// Note: when you call this, the max duty value changes, so you will have to + /// call `set_duty` on all channels with the duty calculated based on the new max duty. + pub fn set_frequency(&mut self, frequency: Hertz) { + self.inner.set_frequency(frequency); + } + + /// Get max duty value. + /// + /// This value depends on the configured frequency and the timer's clock rate from RCC. + pub fn get_max_duty(&self) -> u16 { + self.inner.get_max_compare_value() + 1 + } } diff --git a/embassy-stm32/src/lptim/timer/channel_direction.rs b/embassy-stm32/src/lptim/timer/channel_direction.rs new file mode 100644 index 000000000..a38df63cd --- /dev/null +++ b/embassy-stm32/src/lptim/timer/channel_direction.rs @@ -0,0 +1,18 @@ +use crate::pac::lptim::vals; + +/// Direction of a low-power timer channel +pub enum ChannelDirection { + /// Use channel as a PWM output + OutputPwm, + /// Use channel as an input capture + InputCapture, +} + +impl From for vals::Ccsel { + fn from(direction: ChannelDirection) -> Self { + match direction { + ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE, + ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE, + } + } +} diff --git a/embassy-stm32/src/lptim/timer.rs b/embassy-stm32/src/lptim/timer/mod.rs similarity index 53% rename from embassy-stm32/src/lptim/timer.rs rename to embassy-stm32/src/lptim/timer/mod.rs index b354c1f61..e62fcab49 100644 --- a/embassy-stm32/src/lptim/timer.rs +++ b/embassy-stm32/src/lptim/timer/mod.rs @@ -1,118 +1,20 @@ //! Low-level timer driver. +mod prescaler; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -use super::{Channel, Instance}; -use crate::pac::lptim::vals; +#[cfg(any(lptim_v2a, lptim_v2b))] +use super::channel::Channel; +#[cfg(any(lptim_v2a, lptim_v2b))] +mod channel_direction; +#[cfg(any(lptim_v2a, lptim_v2b))] +pub use channel_direction::ChannelDirection; +use prescaler::Prescaler; + +use super::Instance; use crate::rcc; use crate::time::Hertz; -/// Direction of a low-power timer channel -#[cfg(any(lptim_v2a, lptim_v2b))] -pub enum ChannelDirection { - /// Use channel as a PWM output - OutputPwm, - /// Use channel as an input capture - InputCapture, -} - -#[cfg(any(lptim_v2a, lptim_v2b))] -impl From for vals::Ccsel { - fn from(direction: ChannelDirection) -> Self { - match direction { - ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE, - ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE, - } - } -} - -enum Prescaler { - Div1, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -impl From<&Prescaler> for vals::Presc { - fn from(prescaler: &Prescaler) -> Self { - match prescaler { - Prescaler::Div1 => vals::Presc::DIV1, - Prescaler::Div2 => vals::Presc::DIV2, - Prescaler::Div4 => vals::Presc::DIV4, - Prescaler::Div8 => vals::Presc::DIV8, - Prescaler::Div16 => vals::Presc::DIV16, - Prescaler::Div32 => vals::Presc::DIV32, - Prescaler::Div64 => vals::Presc::DIV64, - Prescaler::Div128 => vals::Presc::DIV128, - } - } -} - -impl From for Prescaler { - fn from(prescaler: vals::Presc) -> Self { - match prescaler { - vals::Presc::DIV1 => Prescaler::Div1, - vals::Presc::DIV2 => Prescaler::Div2, - vals::Presc::DIV4 => Prescaler::Div4, - vals::Presc::DIV8 => Prescaler::Div8, - vals::Presc::DIV16 => Prescaler::Div16, - vals::Presc::DIV32 => Prescaler::Div32, - vals::Presc::DIV64 => Prescaler::Div64, - vals::Presc::DIV128 => Prescaler::Div128, - } - } -} - -impl From<&Prescaler> for u32 { - fn from(prescaler: &Prescaler) -> Self { - match prescaler { - Prescaler::Div1 => 1, - Prescaler::Div2 => 2, - Prescaler::Div4 => 4, - Prescaler::Div8 => 8, - Prescaler::Div16 => 16, - Prescaler::Div32 => 32, - Prescaler::Div64 => 64, - Prescaler::Div128 => 128, - } - } -} - -impl From for Prescaler { - fn from(prescaler: u32) -> Self { - match prescaler { - 1 => Prescaler::Div1, - 2 => Prescaler::Div2, - 4 => Prescaler::Div4, - 8 => Prescaler::Div8, - 16 => Prescaler::Div16, - 32 => Prescaler::Div32, - 64 => Prescaler::Div64, - 128 => Prescaler::Div128, - _ => unreachable!(), - } - } -} - -impl Prescaler { - pub fn from_ticks(ticks: u32) -> Self { - // We need to scale down to a 16-bit range - (ticks >> 16).next_power_of_two().into() - } - - pub fn scale_down(&self, ticks: u32) -> u16 { - (ticks / u32::from(self)).try_into().unwrap() - } - - pub fn scale_up(&self, ticks: u16) -> u32 { - u32::from(self) * ticks as u32 - } -} - /// Low-level timer driver. pub struct Timer<'d, T: Instance> { _tim: PeripheralRef<'d, T>, @@ -148,14 +50,6 @@ impl<'d, T: Instance> Timer<'d, T> { T::regs().cr().modify(|w| w.set_cntstrt(true)); } - /// Set channel direction. - #[cfg(any(lptim_v2a, lptim_v2b))] - pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { - T::regs() - .ccmr(0) - .modify(|w| w.set_ccsel(channel.index(), direction.into())); - } - /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. pub fn set_frequency(&self, frequency: Hertz) { let f = frequency.0; @@ -186,6 +80,14 @@ impl<'d, T: Instance> Timer<'d, T> { T::frequency() } + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. + pub fn get_max_compare_value(&self) -> u16 { + T::regs().arr().read().arr() + } +} + +#[cfg(any(lptim_v2a, lptim_v2b))] +impl<'d, T: Instance> Timer<'d, T> { /// Enable/disable a channel. pub fn enable_channel(&self, channel: Channel, enable: bool) { T::regs().ccmr(0).modify(|w| { @@ -208,8 +110,24 @@ impl<'d, T: Instance> Timer<'d, T> { T::regs().ccr(channel.index()).read().ccr() } - /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. - pub fn get_max_compare_value(&self) -> u16 { - T::regs().arr().read().arr() + /// Set channel direction. + #[cfg(any(lptim_v2a, lptim_v2b))] + pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { + T::regs() + .ccmr(0) + .modify(|w| w.set_ccsel(channel.index(), direction.into())); + } +} + +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +impl<'d, T: Instance> Timer<'d, T> { + /// Set compare value for a channel. + pub fn set_compare_value(&self, value: u16) { + T::regs().cmp().modify(|w| w.set_cmp(value)); + } + + /// Get compare value for a channel. + pub fn get_compare_value(&self) -> u16 { + T::regs().cmp().read().cmp() } } diff --git a/embassy-stm32/src/lptim/timer/prescaler.rs b/embassy-stm32/src/lptim/timer/prescaler.rs new file mode 100644 index 000000000..5d2326faf --- /dev/null +++ b/embassy-stm32/src/lptim/timer/prescaler.rs @@ -0,0 +1,90 @@ +//! Low-level timer driver. + +use crate::pac::lptim::vals; + +pub enum Prescaler { + Div1, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +impl From<&Prescaler> for vals::Presc { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => vals::Presc::DIV1, + Prescaler::Div2 => vals::Presc::DIV2, + Prescaler::Div4 => vals::Presc::DIV4, + Prescaler::Div8 => vals::Presc::DIV8, + Prescaler::Div16 => vals::Presc::DIV16, + Prescaler::Div32 => vals::Presc::DIV32, + Prescaler::Div64 => vals::Presc::DIV64, + Prescaler::Div128 => vals::Presc::DIV128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: vals::Presc) -> Self { + match prescaler { + vals::Presc::DIV1 => Prescaler::Div1, + vals::Presc::DIV2 => Prescaler::Div2, + vals::Presc::DIV4 => Prescaler::Div4, + vals::Presc::DIV8 => Prescaler::Div8, + vals::Presc::DIV16 => Prescaler::Div16, + vals::Presc::DIV32 => Prescaler::Div32, + vals::Presc::DIV64 => Prescaler::Div64, + vals::Presc::DIV128 => Prescaler::Div128, + } + } +} + +impl From<&Prescaler> for u32 { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => 1, + Prescaler::Div2 => 2, + Prescaler::Div4 => 4, + Prescaler::Div8 => 8, + Prescaler::Div16 => 16, + Prescaler::Div32 => 32, + Prescaler::Div64 => 64, + Prescaler::Div128 => 128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: u32) -> Self { + match prescaler { + 1 => Prescaler::Div1, + 2 => Prescaler::Div2, + 4 => Prescaler::Div4, + 8 => Prescaler::Div8, + 16 => Prescaler::Div16, + 32 => Prescaler::Div32, + 64 => Prescaler::Div64, + 128 => Prescaler::Div128, + _ => unreachable!(), + } + } +} + +impl Prescaler { + pub fn from_ticks(ticks: u32) -> Self { + // We need to scale down to a 16-bit range + (ticks >> 16).next_power_of_two().into() + } + + pub fn scale_down(&self, ticks: u32) -> u16 { + (ticks / u32::from(self)).try_into().unwrap() + } + + pub fn scale_up(&self, ticks: u16) -> u32 { + u32::from(self) * ticks as u32 + } +} From ac319970b82e3e613c35d45a11f31423204115e0 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 16:30:45 -0400 Subject: [PATCH 178/210] stm32: Work around LPTIM4 --- embassy-stm32/src/lptim/mod.rs | 25 ++++++++++++++++++------- embassy-stm32/src/lptim/pwm.rs | 4 ++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 9c10efa43..05ed4de44 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -11,17 +11,23 @@ mod channel; #[cfg(any(lptim_v2a, lptim_v2b))] pub use channel::Channel; -pin_trait!(OutputPin, Instance); -pin_trait!(Channel1Pin, Instance); -pin_trait!(Channel2Pin, Instance); +pin_trait!(OutputPin, BasicInstance); +pin_trait!(Channel1Pin, BasicInstance); +pin_trait!(Channel2Pin, BasicInstance); pub(crate) trait SealedInstance: RccPeripheral { fn regs() -> crate::pac::lptim::Lptim; } +pub(crate) trait SealedBasicInstance: RccPeripheral {} + +/// LPTIM basic instance trait. +#[allow(private_bounds)] +pub trait BasicInstance: SealedBasicInstance + 'static {} /// LPTIM instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static {} +pub trait Instance: BasicInstance + SealedInstance + 'static {} + foreach_interrupt! { ($inst:ident, lptim, LPTIM, UP, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { @@ -29,9 +35,14 @@ foreach_interrupt! { crate::pac::$inst } } - - impl Instance for crate::peripherals::$inst { - + impl SealedBasicInstance for crate::peripherals::$inst { } + impl BasicInstance for crate::peripherals::$inst {} + impl Instance for crate::peripherals::$inst {} + }; + ($inst:ident, lptim, LPTIM_BASIC, UP, $irq:ident) => { + impl SealedBasicInstance for crate::peripherals::$inst { + } + impl BasicInstance for crate::peripherals::$inst {} }; } diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 586148848..1f43eb6ee 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -5,11 +5,11 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; use super::timer::Timer; -use super::Instance; #[cfg(not(any(lptim_v2a, lptim_v2b)))] use super::OutputPin; #[cfg(any(lptim_v2a, lptim_v2b))] use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; +use super::{BasicInstance, Instance}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peripheral; @@ -31,7 +31,7 @@ pub struct PwmPin<'d, T, C> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: Instance> PwmPin<'d, T, $channel> { + impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); From 69208daf6dba8ef5285e309219991dd63c38506e Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 17:42:09 -0400 Subject: [PATCH 179/210] stm32: Fixing stupid typo (thanks @dirbaio) --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 511eb6d37..19cf193d9 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1016,7 +1016,7 @@ fn main() { (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)), (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)), - (("lptim", "CH2"), quote!(crate::lptim::Channel1Pin)), + (("lptim", "CH2"), quote!(crate::lptim::Channel2Pin)), (("lptim", "OUT"), quote!(crate::lptim::OutputPin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), From d69f68b8c006dc785652a74fbe730583900d1923 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 6 Sep 2024 20:15:45 -0400 Subject: [PATCH 180/210] stm32: Use a GLOBAL interrupt for lptim --- embassy-stm32/src/lptim/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 05ed4de44..1649cc5b4 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -29,7 +29,7 @@ pub trait BasicInstance: SealedBasicInstance + 'static {} pub trait Instance: BasicInstance + SealedInstance + 'static {} foreach_interrupt! { - ($inst:ident, lptim, LPTIM, UP, $irq:ident) => { + ($inst:ident, lptim, LPTIM, GLOBAL, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::lptim::Lptim { crate::pac::$inst @@ -40,7 +40,7 @@ foreach_interrupt! { impl BasicInstance for crate::peripherals::$inst {} impl Instance for crate::peripherals::$inst {} }; - ($inst:ident, lptim, LPTIM_BASIC, UP, $irq:ident) => { + ($inst:ident, lptim, LPTIM_BASIC, GLOBAL, $irq:ident) => { impl SealedBasicInstance for crate::peripherals::$inst { } impl BasicInstance for crate::peripherals::$inst {} From c739091085eafeb01703626284428905d75aa98f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 11 Sep 2024 01:00:23 +0200 Subject: [PATCH 181/210] Update stm32-metapac. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/mod.rs | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 9a6a5908e..3c6484c96 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" } vcell = "0.1.3" nb = "1.0.0" @@ -99,7 +99,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 2ac0c0083..4ab82c1d9 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -4,7 +4,7 @@ #![allow(missing_docs)] // TODO #![cfg_attr(adc_f3_v2, allow(unused))] -#[cfg(not(adc_f3_v2))] +#[cfg(not(any(adc_f3_v2, adc_u5)))] #[cfg_attr(adc_f1, path = "f1.rs")] #[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] @@ -19,14 +19,16 @@ mod _version; use core::marker::PhantomData; #[allow(unused)] -#[cfg(not(adc_f3_v2))] +#[cfg(not(any(adc_f3_v2, adc_u5)))] pub use _version::*; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; +#[cfg(not(any(adc_u5)))] pub use crate::pac::adc::vals; -#[cfg(not(any(adc_f1, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))] pub use crate::pac::adc::vals::Res as Resolution; +#[cfg(not(any(adc_u5)))] pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; @@ -36,7 +38,7 @@ dma_trait!(RxDma, Instance); pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, - #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] + #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_u5)))] sample_time: SampleTime, } @@ -57,7 +59,7 @@ impl State { trait SealedInstance { #[allow(unused)] fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))] #[allow(unused)] fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] @@ -163,7 +165,7 @@ foreach_adc!( crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { return crate::pac::$common_inst } @@ -200,7 +202,7 @@ macro_rules! impl_adc_pin { /// Get the maximum reading value for this resolution. /// /// This is `2**n - 1`. -#[cfg(not(any(adc_f1, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))] pub const fn resolution_to_max_count(res: Resolution) -> u32 { match res { #[cfg(adc_v4)] From d193c9ef44a61c9de381044fd2968a95ce2ffc75 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Aug 2024 17:45:48 +0200 Subject: [PATCH 182/210] time-driver: clarify docs for set_alarm. --- embassy-time-driver/src/lib.rs | 52 ++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index aab2f626e..8000a9dcb 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -113,24 +113,52 @@ pub trait Driver: Send + Sync + 'static { /// It is UB to make the alarm fire before setting a callback. unsafe fn allocate_alarm(&self) -> Option; - /// Sets the callback function to be called when the alarm triggers. + /// Set the callback function to be called when the alarm triggers. /// The callback may be called from any context (interrupt or thread mode). fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); - /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm - /// timestamp, the provided callback function will be called. + /// Set an alarm at the given timestamp. /// - /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. - /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set, - /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously. - /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the - /// past. This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false` - /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the - /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.) + /// ## Behavior /// - /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. + /// If `timestamp` is in the future, `set_alarm` schedules calling the callback function + /// at that time, and returns `true`. /// - /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. + /// If `timestamp` is in the past, `set_alarm` has two allowed behaviors. Implementations can pick whether to: + /// + /// - Schedule calling the callback function "immediately", as if the requested timestamp was "now+epsilon" and return `true`, or + /// - Not schedule the callback, and return `false`. + /// + /// Callers must ensure to behave correctly with either behavior. + /// + /// When callback is called, it is guaranteed that `now()` will return a value greater than or equal to `timestamp`. + /// + /// ## Reentrancy + /// + /// Calling the callback from `set_alarm` synchronously is not allowed. If the implementation chooses the first option above, + /// it must still call the callback from another context (i.e. an interrupt handler or background thread), it's not allowed + /// to call it synchronously in the context `set_alarm` is running. + /// + /// The reason for the above is callers are explicitly permitted to do both of: + /// - Lock a mutex in the alarm callback. + /// - Call `set_alarm` while having that mutex locked. + /// + /// If `set_alarm` called the callback synchronously, it'd cause a deadlock or panic because it'd cause the + /// mutex to be locked twice reentrantly in the same context. + /// + /// ## Overwriting alarms + /// + /// Only one alarm can be active at a time for each `AlarmHandle`. This overwrites any previously-set alarm if any. + /// + /// ## Unsetting the alarm + /// + /// There is no `unset_alarm` API. Instead, callers can call `set_alarm` with `timestamp` set to `u64::MAX`. + /// + /// This allows for more efficient implementations, since they don't need to distinguish between the "alarm set" and + /// "alarm not set" cases, thanks to the fact "Alarm set for u64::MAX" is effectively equivalent for "alarm not set". + /// + /// This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make `timestamp` + /// be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier. fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; } From 833537231e763c31eeb29fe7aad005a08477189d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=BCha=20=C3=9Cn=C3=BCvar?= <87157627+phycrax@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:50:46 +0800 Subject: [PATCH 183/210] add link to rustybits zero to async video in resources section --- docs/pages/overview.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 7d59d5521..2ebc85f6d 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -77,3 +77,7 @@ For more reading material on async Rust and Embassy: * link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy] * link:https://dev.to/apollolabsbin/series/20707[Tutorials] * link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy] + +Videos: + +* link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust] \ No newline at end of file From 29932c295c44cea1a2ab5ad94c5d0bd16c07243d Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Wed, 11 Sep 2024 10:42:46 +0200 Subject: [PATCH 184/210] fix: `select_slice` is unsound. fixes #3320 --- embassy-futures/src/select.rs | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/embassy-futures/src/select.rs b/embassy-futures/src/select.rs index 97a81a86d..57f0cb41f 100644 --- a/embassy-futures/src/select.rs +++ b/embassy-futures/src/select.rs @@ -237,7 +237,7 @@ impl Future for SelectArray { #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct SelectSlice<'a, Fut> { - inner: &'a mut [Fut], + inner: Pin<&'a mut [Fut]>, } /// Creates a new future which will select over a slice of futures. @@ -247,31 +247,26 @@ pub struct SelectSlice<'a, Fut> { /// future that was ready. /// /// If the slice is empty, the resulting future will be Pending forever. -pub fn select_slice<'a, Fut: Future>(slice: &'a mut [Fut]) -> SelectSlice<'a, Fut> { +pub fn select_slice<'a, Fut: Future>(slice: Pin<&'a mut [Fut]>) -> SelectSlice<'a, Fut> { SelectSlice { inner: slice } } impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> { type Output = (Fut::Output, usize); - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move, - // its elements also cannot move. Therefore it is safe to access `inner` and pin - // references to the contained futures. - let item = unsafe { - self.get_unchecked_mut() - .inner - .iter_mut() - .enumerate() - .find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) { - Poll::Pending => None, - Poll::Ready(e) => Some((i, e)), - }) - }; - - match item { - Some((idx, res)) => Poll::Ready((res, idx)), - None => Poll::Pending, + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Safety: refer to + // https://users.rust-lang.org/t/working-with-pinned-slices-are-there-any-structurally-pinning-vec-like-collection-types/50634/2 + #[inline(always)] + fn pin_iter(slice: Pin<&mut [T]>) -> impl Iterator> { + unsafe { slice.get_unchecked_mut().iter_mut().map(|v| Pin::new_unchecked(v)) } } + for (i, fut) in pin_iter(self.inner.as_mut()).enumerate() { + if let Poll::Ready(res) = fut.poll(cx) { + return Poll::Ready((res, i)); + } + } + + Poll::Pending } } From 3d6a270f30c45eaf394c8eb8bf182dd1a7ec2d7b Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 11 Sep 2024 19:44:11 -0400 Subject: [PATCH 185/210] rp: Fix indexing for pins >31 on rp235xb (#3330) * Fix indexing for pins >31 on rp235xb * fixup knowing that 1<<7 is 128 not 64 --- embassy-rp/src/gpio.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index d0bb7e574..31397172c 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -846,12 +846,12 @@ pub(crate) trait SealedPin: Sized { #[inline] fn _pin(&self) -> u8 { - self.pin_bank() & 0x1f + self.pin_bank() & 0x7f } #[inline] fn _bank(&self) -> Bank { - match self.pin_bank() >> 5 { + match self.pin_bank() >> 7 { #[cfg(feature = "qspi-as-gpio")] 1 => Bank::Qspi, _ => Bank::Bank0, @@ -880,15 +880,27 @@ pub(crate) trait SealedPin: Sized { } fn sio_out(&self) -> pac::sio::Gpio { - SIO.gpio_out(self._bank() as _) + if cfg!(feature = "rp2040") { + SIO.gpio_out(self._bank() as _) + } else { + SIO.gpio_out((self._pin() / 32) as _) + } } fn sio_oe(&self) -> pac::sio::Gpio { - SIO.gpio_oe(self._bank() as _) + if cfg!(feature = "rp2040") { + SIO.gpio_oe(self._bank() as _) + } else { + SIO.gpio_oe((self._pin() / 32) as _) + } } fn sio_in(&self) -> Reg { - SIO.gpio_in(self._bank() as _) + if cfg!(feature = "rp2040") { + SIO.gpio_in(self._bank() as _) + } else { + SIO.gpio_in((self._pin() / 32) as _) + } } fn int_proc(&self) -> pac::io::Int { @@ -953,7 +965,7 @@ macro_rules! impl_pin { impl SealedPin for peripherals::$name { #[inline] fn pin_bank(&self) -> u8 { - ($bank as u8) * 32 + $pin_num + ($bank as u8) * 128 + $pin_num } } From eeda57a4245019ec1acd13afd9d826679d5ebb5e Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 12 Sep 2024 11:37:17 -0400 Subject: [PATCH 186/210] rp2350 pio pin fixes Disable pad isolation on any used pin. Use GPIOBASE and offset pin bases if all pins are > 16, panic if some pins are < 16 and some are > 31 --- embassy-rp/src/pio/mod.rs | 120 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 68b1d6849..0d489763c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -655,6 +655,10 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// Set pin used to signal jump. pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { + #[cfg(feature = "_rp235x")] + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }); self.exec.jmp_pin = pin.pin(); } @@ -664,6 +668,12 @@ impl<'d, PIO: Instance> Config<'d, PIO> { pub fn set_set_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert!(pins.len() <= 5); assert_consecutive(pins); + #[cfg(feature = "_rp235x")] + for pin in pins { + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }) + } self.pins.set_base = pins.first().map_or(0, |p| p.pin()); self.pins.set_count = pins.len() as u8; } @@ -673,6 +683,12 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_out_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); + #[cfg(feature = "_rp235x")] + for pin in pins { + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }) + } self.pins.out_base = pins.first().map_or(0, |p| p.pin()); self.pins.out_count = pins.len() as u8; } @@ -682,6 +698,12 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_in_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); + #[cfg(feature = "_rp235x")] + for pin in pins { + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }) + } self.pins.in_base = pins.first().map_or(0, |p| p.pin()); self.in_count = pins.len() as u8; } @@ -731,6 +753,8 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_autopull(config.shift_out.auto_fill); w.set_autopush(config.shift_in.auto_fill); }); + + #[cfg(feature = "rp2040")] sm.pinctrl().write(|w| { w.set_sideset_count(config.pins.sideset_count); w.set_set_count(config.pins.set_count); @@ -740,6 +764,102 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_set_base(config.pins.set_base); w.set_out_base(config.pins.out_base); }); + + #[cfg(feature = "_rp235x")] + { + let shift_gpio_base = { + match ( + if config.in_count > 0 { + Some(config.pins.in_base) + } else { + None + }, + if config.pins.sideset_count > 0 { + Some(config.pins.sideset_base) + } else { + None + }, + if config.pins.set_count > 0 { + Some(config.pins.set_base) + } else { + None + }, + if config.pins.out_count > 0 { + Some(config.pins.out_base) + } else { + None + }, + ) { + (None, None, None, None) => false, + + (Some(0..31), None, None, None) => false, + (None, Some(0..31), None, None) => false, + (None, None, Some(0..31), None) => false, + (None, None, None, Some(0..31)) => false, + + (Some(0..31), Some(0..31), None, None) => false, + (None, Some(0..31), Some(0..31), None) => false, + (None, None, Some(0..31), Some(0..31)) => false, + (Some(0..31), None, None, Some(0..31)) => false, + + (None, Some(0..31), Some(0..31), Some(0..31)) => false, + (Some(0..31), None, Some(0..31), Some(0..31)) => false, + (Some(0..31), Some(0..31), None, Some(0..31)) => false, + (Some(0..31), Some(0..31), Some(0..31), None) => false, + + (Some(0..31), Some(0..31), Some(0..31), Some(0..31)) => false, + + (Some(16..48), None, None, None) => true, + (None, Some(16..48), None, None) => true, + (None, None, Some(16..48), None) => true, + (None, None, None, Some(16..48)) => true, + + (Some(16..48), Some(16..48), None, None) => true, + (None, Some(16..48), Some(16..48), None) => true, + (None, None, Some(16..48), Some(16..48)) => true, + (Some(16..48), None, None, Some(16..48)) => true, + + (None, Some(16..48), Some(16..48), Some(16..48)) => true, + (Some(16..48), None, Some(16..48), Some(16..48)) => true, + (Some(16..48), Some(16..48), None, Some(16..48)) => true, + (Some(16..48), Some(16..48), Some(16..48), None) => true, + + (Some(16..48), Some(16..48), Some(16..48), Some(16..48)) => true, + + (i, side, set, out) => panic!( + "All pins must either be < 31 or >16, in:{}, side:{}, set:{}, out:{}", + i, side, set, out + ), + } + }; + + info!("shift: {}", shift_gpio_base); + + if shift_gpio_base { + sm.pinctrl().write(|w| { + w.set_sideset_count(config.pins.sideset_count); + w.set_set_count(config.pins.set_count); + w.set_out_count(config.pins.out_count); + w.set_in_base(config.pins.in_base - 16); + w.set_sideset_base(config.pins.sideset_base - 16); + w.set_set_base(config.pins.set_base - 16); + w.set_out_base(config.pins.out_base - 16); + }); + } else { + sm.pinctrl().write(|w| { + w.set_sideset_count(config.pins.sideset_count); + w.set_set_count(config.pins.set_count); + w.set_out_count(config.pins.out_count); + w.set_in_base(config.pins.in_base); + w.set_sideset_base(config.pins.sideset_base); + w.set_set_base(config.pins.set_base); + w.set_out_base(config.pins.out_base); + }); + } + + PIO::PIO.gpiobase().write(|w| w.set_gpiobase(shift_gpio_base)); + } + if let Some(origin) = config.origin { unsafe { instr::exec_jmp(self, origin) } } From 823a82adb7206435794c769be699e1b972d6f966 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 12 Sep 2024 11:43:15 -0400 Subject: [PATCH 187/210] Fixup formatting to work with log --- embassy-rp/src/pio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 0d489763c..ec29a690c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -827,7 +827,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { (Some(16..48), Some(16..48), Some(16..48), Some(16..48)) => true, (i, side, set, out) => panic!( - "All pins must either be < 31 or >16, in:{}, side:{}, set:{}, out:{}", + "All pins must either be < 31 or >16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", i, side, set, out ), } From e359b24121d9747ea8260d8887829b6a97c312f1 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 12 Sep 2024 11:50:36 -0400 Subject: [PATCH 188/210] remove debug print --- embassy-rp/src/pio/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ec29a690c..2b1ed554e 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -833,8 +833,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } }; - info!("shift: {}", shift_gpio_base); - if shift_gpio_base { sm.pinctrl().write(|w| { w.set_sideset_count(config.pins.sideset_count); From ed6cbc7a3a1082b2063162cbf30fb6f9979d81ad Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 15 Sep 2024 20:09:18 -0400 Subject: [PATCH 189/210] Fix upper bound of case where pins should be <=31 --- embassy-rp/src/pio/mod.rs | 54 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 2b1ed554e..e8e411a25 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -792,42 +792,42 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { ) { (None, None, None, None) => false, - (Some(0..31), None, None, None) => false, - (None, Some(0..31), None, None) => false, - (None, None, Some(0..31), None) => false, - (None, None, None, Some(0..31)) => false, + (Some(..32), None, None, None) => false, + (None, Some(..32), None, None) => false, + (None, None, Some(..32), None) => false, + (None, None, None, Some(..32)) => false, - (Some(0..31), Some(0..31), None, None) => false, - (None, Some(0..31), Some(0..31), None) => false, - (None, None, Some(0..31), Some(0..31)) => false, - (Some(0..31), None, None, Some(0..31)) => false, + (Some(..32), Some(..32), None, None) => false, + (None, Some(..32), Some(..32), None) => false, + (None, None, Some(..32), Some(..32)) => false, + (Some(..32), None, None, Some(..32)) => false, - (None, Some(0..31), Some(0..31), Some(0..31)) => false, - (Some(0..31), None, Some(0..31), Some(0..31)) => false, - (Some(0..31), Some(0..31), None, Some(0..31)) => false, - (Some(0..31), Some(0..31), Some(0..31), None) => false, + (None, Some(..32), Some(..32), Some(..32)) => false, + (Some(..32), None, Some(..32), Some(..32)) => false, + (Some(..32), Some(..32), None, Some(..32)) => false, + (Some(..32), Some(..32), Some(..32), None) => false, - (Some(0..31), Some(0..31), Some(0..31), Some(0..31)) => false, + (Some(..32), Some(..32), Some(..32), Some(..32)) => false, - (Some(16..48), None, None, None) => true, - (None, Some(16..48), None, None) => true, - (None, None, Some(16..48), None) => true, - (None, None, None, Some(16..48)) => true, + (Some(16..), None, None, None) => true, + (None, Some(16..), None, None) => true, + (None, None, Some(16..), None) => true, + (None, None, None, Some(16..)) => true, - (Some(16..48), Some(16..48), None, None) => true, - (None, Some(16..48), Some(16..48), None) => true, - (None, None, Some(16..48), Some(16..48)) => true, - (Some(16..48), None, None, Some(16..48)) => true, + (Some(16..), Some(16..), None, None) => true, + (None, Some(16..), Some(16..), None) => true, + (None, None, Some(16..), Some(16..)) => true, + (Some(16..), None, None, Some(16..)) => true, - (None, Some(16..48), Some(16..48), Some(16..48)) => true, - (Some(16..48), None, Some(16..48), Some(16..48)) => true, - (Some(16..48), Some(16..48), None, Some(16..48)) => true, - (Some(16..48), Some(16..48), Some(16..48), None) => true, + (None, Some(16..), Some(16..), Some(16..)) => true, + (Some(16..), None, Some(16..), Some(16..)) => true, + (Some(16..), Some(16..), None, Some(16..)) => true, + (Some(16..), Some(16..), Some(16..), None) => true, - (Some(16..48), Some(16..48), Some(16..48), Some(16..48)) => true, + (Some(16..), Some(16..), Some(16..), Some(16..)) => true, (i, side, set, out) => panic!( - "All pins must either be < 31 or >16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", + "All pins must either be <=31 or >=16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", i, side, set, out ), } From 55c3da5a4f48ea6c66371484c83d6298cde3befe Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 15 Sep 2024 20:48:54 -0400 Subject: [PATCH 190/210] Properly drop pins >30 --- embassy-rp/src/gpio.rs | 4 ++-- embassy-rp/src/pio/mod.rs | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 31397172c..520043b07 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -16,9 +16,9 @@ use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; const NEW_AW: AtomicWaker = AtomicWaker::new(); #[cfg(any(feature = "rp2040", feature = "rp235xa"))] -const BANK0_PIN_COUNT: usize = 30; +pub(crate) const BANK0_PIN_COUNT: usize = 30; #[cfg(feature = "rp235xb")] -const BANK0_PIN_COUNT: usize = 48; +pub(crate) const BANK0_PIN_COUNT: usize = 48; static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT]; #[cfg(feature = "qspi-as-gpio")] diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index e8e411a25..fc940b045 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -5,7 +5,7 @@ use core::pin::Pin as FuturePin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; -use atomic_polyfill::{AtomicU32, AtomicU8}; +use atomic_polyfill::{AtomicU64, AtomicU8}; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use fixed::types::extra::U8; @@ -1305,7 +1305,7 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { // other way. pub struct State { users: AtomicU8, - used_pins: AtomicU32, + used_pins: AtomicU64, } fn on_pio_drop() { @@ -1313,8 +1313,7 @@ fn on_pio_drop() { if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { let used_pins = state.used_pins.load(Ordering::Relaxed); let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; - // we only have 30 pins. don't test the other two since gpio() asserts. - for i in 0..30 { + for i in 0..crate::gpio::BANK0_PIN_COUNT { if used_pins & (1 << i) != 0 { pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); } @@ -1339,7 +1338,7 @@ trait SealedInstance { fn state() -> &'static State { static STATE: State = State { users: AtomicU8::new(0), - used_pins: AtomicU32::new(0), + used_pins: AtomicU64::new(0), }; &STATE From 8519e54461b8d3c3c2a97c88823498c878187ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20H=C3=A9riveaux?= Date: Mon, 16 Sep 2024 11:48:54 +0200 Subject: [PATCH 191/210] fix(boot): return signature error when no features Always return signature error in verify_and_mark_updated when no signature features are enabled. --- embassy-boot/src/firmware_updater/asynch.rs | 12 ++++++++---- embassy-boot/src/firmware_updater/blocking.rs | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 26f65f295..86b441592 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -107,7 +107,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { let mut message = [0; 64]; self.hash::(_update_len, &mut chunk_buf, &mut message).await?; - public_key.verify(&message, &signature).map_err(into_signature_error)? + public_key.verify(&message, &signature).map_err(into_signature_error)?; + return self.state.mark_updated().await; } #[cfg(feature = "ed25519-salty")] { @@ -134,10 +135,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { message, r.is_ok() ); - r.map_err(into_signature_error)? + r.map_err(into_signature_error)?; + return self.state.mark_updated().await; + } + #[cfg(not(any(feature = "ed25519-dalek", feature = "ed25519-salty")))] + { + Err(FirmwareUpdaterError::Signature(signature::Error::new())) } - - self.state.mark_updated().await } /// Verify the update in DFU with any digest. diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 35772a856..d3c723456 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -142,7 +142,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> let mut chunk_buf = [0; 2]; self.hash::(_update_len, &mut chunk_buf, &mut message)?; - public_key.verify(&message, &signature).map_err(into_signature_error)? + public_key.verify(&message, &signature).map_err(into_signature_error)?; + return self.state.mark_updated(); } #[cfg(feature = "ed25519-salty")] { @@ -169,10 +170,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> message, r.is_ok() ); - r.map_err(into_signature_error)? + r.map_err(into_signature_error)?; + return self.state.mark_updated(); + } + #[cfg(not(any(feature = "ed25519-dalek", feature = "ed25519-salty")))] + { + Err(FirmwareUpdaterError::Signature(signature::Error::new())) } - - self.state.mark_updated() } /// Verify the update in DFU with any digest. From 313e76af043c8b2bb2b31f8cc0eba7578ea41357 Mon Sep 17 00:00:00 2001 From: Sebastian Quilitz Date: Mon, 16 Sep 2024 12:26:00 +0200 Subject: [PATCH 192/210] rp: add constructor for tx-only blocking UART --- embassy-rp/src/uart/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index aba4b792a..c94e5e185 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -224,6 +224,17 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { } impl<'d, T: Instance> UartTx<'d, T, Blocking> { + /// Create a new UART TX instance for blocking mode operations. + pub fn new_blocking( + _uart: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + into_ref!(tx); + Uart::::init(Some(tx.map_into()), None, None, None, config); + Self::new_inner(None) + } + /// Convert this uart TX instance into a buffered uart using the provided /// irq and transmit buffer. pub fn into_buffered( From 48fd0550d1569a44a6b58a41423b0f86270fb373 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 12:41:12 -0400 Subject: [PATCH 193/210] Review fixes Don't overflow on subtract Replace giant match with for loop dedupe register write --- embassy-rp/src/pio/mod.rs | 130 +++++++++++++------------------------- 1 file changed, 43 insertions(+), 87 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index fc940b045..ace597f00 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -767,95 +767,51 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { #[cfg(feature = "_rp235x")] { - let shift_gpio_base = { - match ( - if config.in_count > 0 { - Some(config.pins.in_base) - } else { - None - }, - if config.pins.sideset_count > 0 { - Some(config.pins.sideset_base) - } else { - None - }, - if config.pins.set_count > 0 { - Some(config.pins.set_base) - } else { - None - }, - if config.pins.out_count > 0 { - Some(config.pins.out_base) - } else { - None - }, - ) { - (None, None, None, None) => false, - - (Some(..32), None, None, None) => false, - (None, Some(..32), None, None) => false, - (None, None, Some(..32), None) => false, - (None, None, None, Some(..32)) => false, - - (Some(..32), Some(..32), None, None) => false, - (None, Some(..32), Some(..32), None) => false, - (None, None, Some(..32), Some(..32)) => false, - (Some(..32), None, None, Some(..32)) => false, - - (None, Some(..32), Some(..32), Some(..32)) => false, - (Some(..32), None, Some(..32), Some(..32)) => false, - (Some(..32), Some(..32), None, Some(..32)) => false, - (Some(..32), Some(..32), Some(..32), None) => false, - - (Some(..32), Some(..32), Some(..32), Some(..32)) => false, - - (Some(16..), None, None, None) => true, - (None, Some(16..), None, None) => true, - (None, None, Some(16..), None) => true, - (None, None, None, Some(16..)) => true, - - (Some(16..), Some(16..), None, None) => true, - (None, Some(16..), Some(16..), None) => true, - (None, None, Some(16..), Some(16..)) => true, - (Some(16..), None, None, Some(16..)) => true, - - (None, Some(16..), Some(16..), Some(16..)) => true, - (Some(16..), None, Some(16..), Some(16..)) => true, - (Some(16..), Some(16..), None, Some(16..)) => true, - (Some(16..), Some(16..), Some(16..), None) => true, - - (Some(16..), Some(16..), Some(16..), Some(16..)) => true, - - (i, side, set, out) => panic!( - "All pins must either be <=31 or >=16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", - i, side, set, out - ), - } - }; - - if shift_gpio_base { - sm.pinctrl().write(|w| { - w.set_sideset_count(config.pins.sideset_count); - w.set_set_count(config.pins.set_count); - w.set_out_count(config.pins.out_count); - w.set_in_base(config.pins.in_base - 16); - w.set_sideset_base(config.pins.sideset_base - 16); - w.set_set_base(config.pins.set_base - 16); - w.set_out_base(config.pins.out_base - 16); - }); - } else { - sm.pinctrl().write(|w| { - w.set_sideset_count(config.pins.sideset_count); - w.set_set_count(config.pins.set_count); - w.set_out_count(config.pins.out_count); - w.set_in_base(config.pins.in_base); - w.set_sideset_base(config.pins.sideset_base); - w.set_set_base(config.pins.set_base); - w.set_out_base(config.pins.out_base); - }); + let mut low_ok = true; + let mut high_ok = true; + for pin in [ + config.pins.in_base, + config.pins.in_base + config.in_count, + config.pins.sideset_base, + config.pins.sideset_base + config.pins.sideset_count, + config.pins.set_base, + config.pins.set_base + config.pins.set_count, + config.pins.out_base, + config.pins.out_base + config.pins.out_count, + ] + .iter() + .flatten() + { + low_ok &= pin < 32; + high_ok &= pin >= 16; } - PIO::PIO.gpiobase().write(|w| w.set_gpiobase(shift_gpio_base)); + if !low_ok && !high_ok { + panic!( + "All pins must either be <32 or >=16, in:{:?}-{:?}, side:{:?}-{:?}, set:{:?}-{:?}, out:{:?}-{:?}", + config.pins.in_base, + config.pins.in_base + config.in_count, + config.pins.sideset_base, + config.pins.sideset_base + config.pins.sideset_count, + config.pins.set_base, + config.pins.set_base + config.pins.set_count, + config.pins.out_base, + config.pins.out_base + config.pins.out_count, + ) + } + let shift = if low_ok { 0 } else { 16 }; + + sm.pinctrl().write(|w| { + w.set_sideset_count(config.pins.sideset_count); + w.set_set_count(config.pins.set_count); + w.set_out_count(config.pins.out_count); + w.set_in_base(config.pins.in_base.checked_sub(shift).unwrap_or_default()); + w.set_sideset_base(config.pins.sideset_base.checked_sub(shift).unwrap_or_default()); + w.set_set_base(config.pins.set_base.checked_sub(shift).unwrap_or_default()); + w.set_out_base(config.pins.out_base.checked_sub(shift).unwrap_or_default()); + }); + + PIO::PIO.gpiobase().write(|w| w.set_gpiobase(shift == 16)); } if let Some(origin) = config.origin { From 9cfde66446ca5451a6cab80e0f2f783199fbeb62 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 12:47:07 -0400 Subject: [PATCH 194/210] Move pin isolation config to make_pio_pin --- embassy-rp/src/pio/mod.rs | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ace597f00..b08f2df6b 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -655,10 +655,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// Set pin used to signal jump. pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { - #[cfg(feature = "_rp235x")] - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }); self.exec.jmp_pin = pin.pin(); } @@ -668,12 +664,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { pub fn set_set_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert!(pins.len() <= 5); assert_consecutive(pins); - #[cfg(feature = "_rp235x")] - for pin in pins { - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }) - } self.pins.set_base = pins.first().map_or(0, |p| p.pin()); self.pins.set_count = pins.len() as u8; } @@ -683,12 +673,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_out_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); - #[cfg(feature = "_rp235x")] - for pin in pins { - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }) - } self.pins.out_base = pins.first().map_or(0, |p| p.pin()); self.pins.out_count = pins.len() as u8; } @@ -698,12 +682,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_in_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); - #[cfg(feature = "_rp235x")] - for pin in pins { - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }) - } self.pins.in_base = pins.first().map_or(0, |p| p.pin()); self.in_count = pins.len() as u8; } @@ -778,10 +756,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { config.pins.set_base + config.pins.set_count, config.pins.out_base, config.pins.out_base + config.pins.out_count, - ] - .iter() - .flatten() - { + ] { low_ok &= pin < 32; high_ok &= pin >= 16; } @@ -1080,6 +1055,10 @@ impl<'d, PIO: Instance> Common<'d, PIO> { pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); + #[cfg(feature = "_rp235x")] + pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }); // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); Pin { From 6e0c3e25fd8e07ce3ee46e0ba74064a4c4574e16 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 12:58:23 -0400 Subject: [PATCH 195/210] Only check ping groups that have count >0 --- embassy-rp/src/pio/mod.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index b08f2df6b..29a5bfab3 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -743,22 +743,21 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_out_base(config.pins.out_base); }); - #[cfg(feature = "_rp235x")] + //#[cfg(feature = "_rp235x")] { let mut low_ok = true; let mut high_ok = true; - for pin in [ - config.pins.in_base, - config.pins.in_base + config.in_count, - config.pins.sideset_base, - config.pins.sideset_base + config.pins.sideset_count, - config.pins.set_base, - config.pins.set_base + config.pins.set_count, - config.pins.out_base, - config.pins.out_base + config.pins.out_count, - ] { - low_ok &= pin < 32; - high_ok &= pin >= 16; + + let in_pins = config.pins.in_base..config.pins.in_base + config.in_count; + let side_pins = config.pins.sideset_base..config.pins.sideset_base + config.pins.sideset_count; + let set_pins = config.pins.set_base..config.pins.set_base + config.pins.set_count; + let out_pins = config.pins.out_base..config.pins.out_base + config.pins.out_count; + + for pin_range in [in_pins, side_pins, set_pins, out_pins] { + for pin in pin_range { + low_ok &= pin < 32; + high_ok &= pin >= 16; + } } if !low_ok && !high_ok { From 8b34c94ef3640b2ec28b3de3c5d90db40b0b0ecd Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 13:02:35 -0400 Subject: [PATCH 196/210] Improve error message when pin groups are not allowed --- embassy-rp/src/pio/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 29a5bfab3..b2f9abaa0 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -764,13 +764,13 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { panic!( "All pins must either be <32 or >=16, in:{:?}-{:?}, side:{:?}-{:?}, set:{:?}-{:?}, out:{:?}-{:?}", config.pins.in_base, - config.pins.in_base + config.in_count, + config.pins.in_base + config.in_count - 1, config.pins.sideset_base, - config.pins.sideset_base + config.pins.sideset_count, + config.pins.sideset_base + config.pins.sideset_count - 1, config.pins.set_base, - config.pins.set_base + config.pins.set_count, + config.pins.set_base + config.pins.set_count - 1, config.pins.out_base, - config.pins.out_base + config.pins.out_count, + config.pins.out_base + config.pins.out_count - 1, ) } let shift = if low_ok { 0 } else { 16 }; From d1508cc49c9ac029ececb1ae5e4c326ac678d1ec Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 13:07:16 -0400 Subject: [PATCH 197/210] oops --- embassy-rp/src/pio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index b2f9abaa0..72aa8f104 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -743,7 +743,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_out_base(config.pins.out_base); }); - //#[cfg(feature = "_rp235x")] + #[cfg(feature = "_rp235x")] { let mut low_ok = true; let mut high_ok = true; From 2855e65cc6ac5a3a102f3a309b4c450efffe1417 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 13:24:47 -0400 Subject: [PATCH 198/210] Disable pad isolation on clock in/out pins --- embassy-rp/src/clocks.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index ed146844c..f229a5acd 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -847,6 +847,10 @@ impl<'d, T: GpinPin> Gpin<'d, T> { into_ref!(gpin); gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08)); + #[cfg(feature = "_rp235x")] + gpin.pad_ctrl().write(|w| { + w.set_iso(false); + }); Gpin { gpin: gpin.map_into(), @@ -861,6 +865,7 @@ impl<'d, T: GpinPin> Gpin<'d, T> { impl<'d, T: GpinPin> Drop for Gpin<'d, T> { fn drop(&mut self) { + self.gpin.pad_ctrl().write(|_| {}); self.gpin .gpio() .ctrl() @@ -921,11 +926,15 @@ pub struct Gpout<'d, T: GpoutPin> { } impl<'d, T: GpoutPin> Gpout<'d, T> { - /// Create new general purpose cloud output. + /// Create new general purpose clock output. pub fn new(gpout: impl Peripheral

+ 'd) -> Self { into_ref!(gpout); gpout.gpio().ctrl().write(|w| w.set_funcsel(0x08)); + #[cfg(feature = "_rp235x")] + gpout.pad_ctrl().write(|w| { + w.set_iso(false); + }); Self { gpout } } @@ -1005,6 +1014,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { fn drop(&mut self) { self.disable(); + self.gpout.pad_ctrl().write(|_| {}); self.gpout .gpio() .ctrl() From be0d9775e3bcc3c1bd1448e357d7c6cd67b68991 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 11 Sep 2024 22:06:26 +0200 Subject: [PATCH 199/210] net: refactor to simplify lifetimes/generics. --- ci.sh | 2 +- embassy-net/Cargo.toml | 10 +- embassy-net/README.md | 3 +- embassy-net/src/dns.rs | 25 +- embassy-net/src/{device.rs => driver_util.rs} | 2 +- embassy-net/src/lib.rs | 445 ++++++++---------- embassy-net/src/raw.rs | 53 ++- embassy-net/src/tcp.rs | 76 +-- embassy-net/src/udp.rs | 61 +-- .../nrf52840/src/bin/ethernet_enc28j60.rs | 14 +- examples/nrf52840/src/bin/usb_ethernet.rs | 11 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 11 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 16 +- .../rp/src/bin/ethernet_w5500_multisocket.rs | 19 +- .../rp/src/bin/ethernet_w5500_tcp_client.rs | 13 +- .../rp/src/bin/ethernet_w5500_tcp_server.rs | 13 +- examples/rp/src/bin/ethernet_w5500_udp.rs | 13 +- examples/rp/src/bin/usb_ethernet.rs | 11 +- examples/rp/src/bin/wifi_ap_tcp_server.rs | 16 +- examples/rp/src/bin/wifi_scan.rs | 5 +- examples/rp/src/bin/wifi_tcp_server.rs | 16 +- examples/rp/src/bin/wifi_webrequest.rs | 16 +- examples/std/src/bin/net.rs | 11 +- examples/std/src/bin/net_dns.rs | 11 +- examples/std/src/bin/net_ppp.rs | 17 +- examples/std/src/bin/net_udp.rs | 11 +- examples/std/src/bin/tcp_accept.rs | 11 +- examples/stm32f4/src/bin/eth.rs | 13 +- examples/stm32f4/src/bin/eth_w5500.rs | 11 +- examples/stm32f4/src/bin/usb_ethernet.rs | 11 +- examples/stm32f7/src/bin/eth.rs | 13 +- examples/stm32h5/src/bin/eth.rs | 13 +- examples/stm32h7/src/bin/eth.rs | 13 +- examples/stm32h7/src/bin/eth_client.rs | 13 +- examples/stm32h7/src/bin/eth_client_mii.rs | 13 +- .../src/bin/spe_adin1110_http_server.rs | 11 +- examples/stm32l5/src/bin/usb_ethernet.rs | 11 +- tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 11 +- tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 13 +- tests/perf-client/src/lib.rs | 9 +- tests/rp/src/bin/cyw43-perf.rs | 13 +- tests/rp/src/bin/ethernet_w5100s_perf.rs | 13 +- tests/stm32/src/bin/eth.rs | 11 +- 43 files changed, 500 insertions(+), 604 deletions(-) rename embassy-net/src/{device.rs => driver_util.rs} (98%) diff --git a/ci.sh b/ci.sh index 8fef731a4..5e8bddb8c 100755 --- a/ci.sh +++ b/ci.sh @@ -47,7 +47,7 @@ cargo batch \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ - --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,igmp,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 28bac485b..2e21b4231 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -16,11 +16,11 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" -features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] target = "thumbv7em-none-eabi" [package.metadata.docs.rs] -features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] [features] default = [] @@ -60,15 +60,15 @@ medium-ethernet = ["smoltcp/medium-ethernet"] medium-ip = ["smoltcp/medium-ip"] ## Enable the IEEE 802.15.4 medium medium-ieee802154 = ["smoltcp/medium-ieee802154"] -## Enable IGMP support -igmp = ["smoltcp/proto-igmp"] +## Enable multicast support (for both ipv4 and/or ipv6 if enabled) +multicast = ["smoltcp/multicast"] [dependencies] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { version = "0.11.0", default-features = false, features = [ +smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="dd43c8f189178b0ab3bda798ed8578b5b0a6f094", default-features = false, features = [ "socket", "async", ] } diff --git a/embassy-net/README.md b/embassy-net/README.md index 6b7d46934..1722ffc7b 100644 --- a/embassy-net/README.md +++ b/embassy-net/README.md @@ -10,8 +10,9 @@ memory management designed to work well for embedded systems, aiming for a more - IPv4, IPv6 - Ethernet and bare-IP mediums. -- TCP, UDP, DNS, DHCPv4, IGMPv4 +- TCP, UDP, DNS, DHCPv4 - TCP sockets implement the `embedded-io` async traits. +- Multicast See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and unimplemented features of the network protocols. diff --git a/embassy-net/src/dns.rs b/embassy-net/src/dns.rs index 8ccfa4e4f..1fbaea4f0 100644 --- a/embassy-net/src/dns.rs +++ b/embassy-net/src/dns.rs @@ -9,7 +9,7 @@ pub use smoltcp::socket::dns::{DnsQuery, Socket}; pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError}; pub use smoltcp::wire::{DnsQueryType, IpAddress}; -use crate::{Driver, Stack}; +use crate::Stack; /// Errors returned by DnsSocket. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -44,21 +44,15 @@ impl From for Error { /// This exists only for compatibility with crates that use `embedded-nal-async`. /// Prefer using [`Stack::dns_query`](crate::Stack::dns_query) directly if you're /// not using `embedded-nal-async`. -pub struct DnsSocket<'a, D> -where - D: Driver + 'static, -{ - stack: &'a Stack, +pub struct DnsSocket<'a> { + stack: Stack<'a>, } -impl<'a, D> DnsSocket<'a, D> -where - D: Driver + 'static, -{ +impl<'a> DnsSocket<'a> { /// Create a new DNS socket using the provided stack. /// /// NOTE: If using DHCP, make sure it has reconfigured the stack to ensure the DNS servers are updated. - pub fn new(stack: &'a Stack) -> Self { + pub fn new(stack: Stack<'a>) -> Self { Self { stack } } @@ -72,10 +66,7 @@ where } } -impl<'a, D> embedded_nal_async::Dns for DnsSocket<'a, D> -where - D: Driver + 'static, -{ +impl<'a> embedded_nal_async::Dns for DnsSocket<'a> { type Error = Error; async fn get_host_by_name( @@ -124,3 +115,7 @@ where todo!() } } + +fn _assert_covariant<'a, 'b: 'a>(x: DnsSocket<'b>) -> DnsSocket<'a> { + x +} diff --git a/embassy-net/src/device.rs b/embassy-net/src/driver_util.rs similarity index 98% rename from embassy-net/src/device.rs rename to embassy-net/src/driver_util.rs index 3b1d3c47c..b2af1d499 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/driver_util.rs @@ -74,7 +74,7 @@ where { fn consume(self, f: F) -> R where - F: FnOnce(&mut [u8]) -> R, + F: FnOnce(&[u8]) -> R, { self.0.consume(|buf| { #[cfg(feature = "packet-trace")] diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 56321cec9..ef53fb905 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -12,9 +12,9 @@ compile_error!("You must enable at least one of the following features: proto-ip // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -mod device; #[cfg(feature = "dns")] pub mod dns; +mod driver_util; #[cfg(feature = "raw")] pub mod raw; #[cfg(feature = "tcp")] @@ -25,6 +25,7 @@ pub mod udp; use core::cell::RefCell; use core::future::{poll_fn, Future}; +use core::mem::MaybeUninit; use core::pin::pin; use core::task::{Context, Poll}; @@ -36,7 +37,7 @@ use embassy_time::{Instant, Timer}; use heapless::Vec; #[cfg(feature = "dns")] pub use smoltcp::config::DNS_MAX_SERVER_COUNT; -#[cfg(feature = "igmp")] +#[cfg(feature = "multicast")] pub use smoltcp::iface::MulticastError; #[allow(unused_imports)] use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; @@ -57,7 +58,7 @@ pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; #[cfg(feature = "proto-ipv6")] pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; -use crate::device::DriverAdapter; +use crate::driver_util::DriverAdapter; use crate::time::{instant_from_smoltcp, instant_to_smoltcp}; const LOCAL_PORT_MIN: u16 = 1025; @@ -69,33 +70,33 @@ const MAX_HOSTNAME_LEN: usize = 32; /// Memory resources needed for a network stack. pub struct StackResources { - sockets: [SocketStorage<'static>; SOCK], + sockets: MaybeUninit<[SocketStorage<'static>; SOCK]>, + inner: MaybeUninit>, #[cfg(feature = "dns")] - queries: [Option; MAX_QUERIES], + queries: MaybeUninit<[Option; MAX_QUERIES]>, #[cfg(feature = "dhcpv4-hostname")] - hostname: core::cell::UnsafeCell, + hostname: HostnameResources, } #[cfg(feature = "dhcpv4-hostname")] struct HostnameResources { - option: smoltcp::wire::DhcpOption<'static>, - data: [u8; MAX_HOSTNAME_LEN], + option: MaybeUninit>, + data: MaybeUninit<[u8; MAX_HOSTNAME_LEN]>, } impl StackResources { /// Create a new set of stack resources. pub const fn new() -> Self { - #[cfg(feature = "dns")] - const INIT: Option = None; Self { - sockets: [SocketStorage::EMPTY; SOCK], + sockets: MaybeUninit::uninit(), + inner: MaybeUninit::uninit(), #[cfg(feature = "dns")] - queries: [INIT; MAX_QUERIES], + queries: MaybeUninit::uninit(), #[cfg(feature = "dhcpv4-hostname")] - hostname: core::cell::UnsafeCell::new(HostnameResources { - option: smoltcp::wire::DhcpOption { kind: 0, data: &[] }, - data: [0; MAX_HOSTNAME_LEN], - }), + hostname: HostnameResources { + option: MaybeUninit::uninit(), + data: MaybeUninit::uninit(), + }, } } } @@ -239,16 +240,29 @@ pub enum ConfigV6 { Static(StaticConfigV6), } -/// A network stack. +/// Network stack runner. /// -/// This is the main entry point for the network stack. -pub struct Stack { - pub(crate) socket: RefCell, - inner: RefCell>, +/// You must call [`Runner::run()`] in a background task for the network stack to work. +pub struct Runner<'d, D: Driver> { + driver: D, + stack: Stack<'d>, } -struct Inner { - device: D, +/// Network stack handle +/// +/// Use this to create sockets. It's `Copy`, so you can pass +/// it by value instead of by reference. +#[derive(Copy, Clone)] +pub struct Stack<'d> { + inner: &'d RefCell, +} + +pub(crate) struct Inner { + pub(crate) sockets: SocketSet<'static>, // Lifetime type-erased. + pub(crate) iface: Interface, + pub(crate) waker: WakerRegistration, + hardware_address: HardwareAddress, + next_local_port: u16, link_up: bool, #[cfg(feature = "proto-ipv4")] static_v4: Option, @@ -262,14 +276,83 @@ struct Inner { #[cfg(feature = "dns")] dns_waker: WakerRegistration, #[cfg(feature = "dhcpv4-hostname")] - hostname: &'static mut core::cell::UnsafeCell, + hostname: *mut HostnameResources, } -pub(crate) struct SocketStack { - pub(crate) sockets: SocketSet<'static>, - pub(crate) iface: Interface, - pub(crate) waker: WakerRegistration, - next_local_port: u16, +fn _assert_covariant<'a, 'b: 'a>(x: Stack<'b>) -> Stack<'a> { + x +} + +/// Create a new network stack. +pub fn new<'d, D: Driver, const SOCK: usize>( + mut driver: D, + config: Config, + resources: &'d mut StackResources, + random_seed: u64, +) -> (Stack<'d>, Runner<'d, D>) { + let (hardware_address, medium) = to_smoltcp_hardware_address(driver.hardware_address()); + let mut iface_cfg = smoltcp::iface::Config::new(hardware_address); + iface_cfg.random_seed = random_seed; + + let iface = Interface::new( + iface_cfg, + &mut DriverAdapter { + inner: &mut driver, + cx: None, + medium, + }, + instant_to_smoltcp(Instant::now()), + ); + + unsafe fn transmute_slice(x: &mut [T]) -> &'static mut [T] { + core::mem::transmute(x) + } + + let sockets = resources.sockets.write([SocketStorage::EMPTY; SOCK]); + #[allow(unused_mut)] + let mut sockets: SocketSet<'static> = SocketSet::new(unsafe { transmute_slice(sockets) }); + + let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; + + #[cfg(feature = "dns")] + let dns_socket = sockets.add(dns::Socket::new( + &[], + managed::ManagedSlice::Borrowed(unsafe { + transmute_slice(resources.queries.write([const { None }; MAX_QUERIES])) + }), + )); + + let mut inner = Inner { + sockets, + iface, + waker: WakerRegistration::new(), + next_local_port, + hardware_address, + link_up: false, + #[cfg(feature = "proto-ipv4")] + static_v4: None, + #[cfg(feature = "proto-ipv6")] + static_v6: None, + #[cfg(feature = "dhcpv4")] + dhcp_socket: None, + config_waker: WakerRegistration::new(), + #[cfg(feature = "dns")] + dns_socket, + #[cfg(feature = "dns")] + dns_waker: WakerRegistration::new(), + #[cfg(feature = "dhcpv4-hostname")] + hostname: &mut resources.hostname, + }; + + #[cfg(feature = "proto-ipv4")] + inner.set_config_v4(config.ipv4); + #[cfg(feature = "proto-ipv6")] + inner.set_config_v6(config.ipv6); + inner.apply_static_config(); + + let inner = &*resources.inner.write(RefCell::new(inner)); + let stack = Stack { inner }; + (stack, Runner { driver, stack }) } fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) { @@ -292,89 +375,23 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddres } } -impl Stack { - /// Create a new network stack. - pub fn new( - mut device: D, - config: Config, - resources: &'static mut StackResources, - random_seed: u64, - ) -> Self { - let (hardware_addr, medium) = to_smoltcp_hardware_address(device.hardware_address()); - let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr); - iface_cfg.random_seed = random_seed; - - let iface = Interface::new( - iface_cfg, - &mut DriverAdapter { - inner: &mut device, - cx: None, - medium, - }, - instant_to_smoltcp(Instant::now()), - ); - - let sockets = SocketSet::new(&mut resources.sockets[..]); - - let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; - - #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))] - let mut socket = SocketStack { - sockets, - iface, - waker: WakerRegistration::new(), - next_local_port, - }; - - let mut inner = Inner { - device, - link_up: false, - #[cfg(feature = "proto-ipv4")] - static_v4: None, - #[cfg(feature = "proto-ipv6")] - static_v6: None, - #[cfg(feature = "dhcpv4")] - dhcp_socket: None, - config_waker: WakerRegistration::new(), - #[cfg(feature = "dns")] - dns_socket: socket.sockets.add(dns::Socket::new( - &[], - managed::ManagedSlice::Borrowed(&mut resources.queries), - )), - #[cfg(feature = "dns")] - dns_waker: WakerRegistration::new(), - #[cfg(feature = "dhcpv4-hostname")] - hostname: &mut resources.hostname, - }; - - #[cfg(feature = "proto-ipv4")] - inner.set_config_v4(&mut socket, config.ipv4); - #[cfg(feature = "proto-ipv6")] - inner.set_config_v6(&mut socket, config.ipv6); - inner.apply_static_config(&mut socket); - - Self { - socket: RefCell::new(socket), - inner: RefCell::new(inner), - } +impl<'d> Stack<'d> { + fn with(&self, f: impl FnOnce(&Inner) -> R) -> R { + f(&*self.inner.borrow()) } - fn with(&self, f: impl FnOnce(&SocketStack, &Inner) -> R) -> R { - f(&*self.socket.borrow(), &*self.inner.borrow()) - } - - fn with_mut(&self, f: impl FnOnce(&mut SocketStack, &mut Inner) -> R) -> R { - f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut()) + fn with_mut(&self, f: impl FnOnce(&mut Inner) -> R) -> R { + f(&mut *self.inner.borrow_mut()) } /// Get the hardware address of the network interface. pub fn hardware_address(&self) -> HardwareAddress { - self.with(|_s, i| to_smoltcp_hardware_address(i.device.hardware_address()).0) + self.with(|i| i.hardware_address) } /// Get whether the link is up. pub fn is_link_up(&self) -> bool { - self.with(|_s, i| i.link_up) + self.with(|i| i.link_up) } /// Get whether the network stack has a valid IP configuration. @@ -420,15 +437,14 @@ impl Stack { /// // provisioning space for 3 sockets here: one for DHCP, one for DNS, and one for your code (e.g. TCP). /// // If you use more sockets you must increase this. If you don't enable DHCP or DNS you can decrease it. /// static RESOURCES: StaticCell> = StaticCell::new(); - /// static STACK: StaticCell = StaticCell::new(); - /// let stack = &*STACK.init(embassy_net::Stack::new( - /// device, + /// let (stack, runner) = embassy_net::new( + /// driver, /// config, /// RESOURCES.init(embassy_net::StackResources::new()), /// seed - /// )); - /// // Launch network task that runs `stack.run().await` - /// spawner.spawn(net_task(stack)).unwrap(); + /// ); + /// // Launch network task that runs `runner.run().await` + /// spawner.spawn(net_task(runner)).unwrap(); /// // Wait for DHCP config /// stack.wait_config_up().await; /// // use the network stack @@ -448,7 +464,7 @@ impl Stack { // when a config is applied (static or DHCP). trace!("Waiting for config up"); - self.with_mut(|_, i| { + self.with_mut(|i| { i.config_waker.register(cx.waker()); }); @@ -464,45 +480,33 @@ impl Stack { /// acquire an IP address, or Some if it has. #[cfg(feature = "proto-ipv4")] pub fn config_v4(&self) -> Option { - self.with(|_, i| i.static_v4.clone()) + self.with(|i| i.static_v4.clone()) } /// Get the current IPv6 configuration. #[cfg(feature = "proto-ipv6")] pub fn config_v6(&self) -> Option { - self.with(|_, i| i.static_v6.clone()) + self.with(|i| i.static_v6.clone()) } /// Set the IPv4 configuration. #[cfg(feature = "proto-ipv4")] pub fn set_config_v4(&self, config: ConfigV4) { - self.with_mut(|s, i| { - i.set_config_v4(s, config); - i.apply_static_config(s); + self.with_mut(|i| { + i.set_config_v4(config); + i.apply_static_config(); }) } /// Set the IPv6 configuration. #[cfg(feature = "proto-ipv6")] pub fn set_config_v6(&self, config: ConfigV6) { - self.with_mut(|s, i| { - i.set_config_v6(s, config); - i.apply_static_config(s); + self.with_mut(|i| { + i.set_config_v6(config); + i.apply_static_config(); }) } - /// Run the network stack. - /// - /// You must call this in a background task, to process network events. - pub async fn run(&self) -> ! { - poll_fn(|cx| { - self.with_mut(|s, i| i.poll(cx, s)); - Poll::<()>::Pending - }) - .await; - unreachable!() - } - /// Make a query for a given name and return the corresponding IP addresses. #[cfg(feature = "dns")] pub async fn dns_query( @@ -528,11 +532,11 @@ impl Stack { } let query = poll_fn(|cx| { - self.with_mut(|s, i| { - let socket = s.sockets.get_mut::(i.dns_socket); - match socket.start_query(s.iface.context(), name, qtype) { + self.with_mut(|i| { + let socket = i.sockets.get_mut::(i.dns_socket); + match socket.start_query(i.iface.context(), name, qtype) { Ok(handle) => { - s.waker.wake(); + i.waker.wake(); Poll::Ready(Ok(handle)) } Err(dns::StartQueryError::NoFreeSlot) => { @@ -569,17 +573,17 @@ impl Stack { } let drop = OnDrop::new(|| { - self.with_mut(|s, i| { - let socket = s.sockets.get_mut::(i.dns_socket); + self.with_mut(|i| { + let socket = i.sockets.get_mut::(i.dns_socket); socket.cancel_query(query); - s.waker.wake(); + i.waker.wake(); i.dns_waker.wake(); }) }); let res = poll_fn(|cx| { - self.with_mut(|s, i| { - let socket = s.sockets.get_mut::(i.dns_socket); + self.with_mut(|i| { + let socket = i.sockets.get_mut::(i.dns_socket); match socket.get_query_result(query) { Ok(addrs) => { i.dns_waker.wake(); @@ -604,104 +608,34 @@ impl Stack { } } -#[cfg(feature = "igmp")] -impl Stack { +#[cfg(feature = "multicast")] +impl<'d> Stack<'d> { /// Join a multicast group. - pub async fn join_multicast_group(&self, addr: T) -> Result - where - T: Into, - { - let addr = addr.into(); - - poll_fn(move |cx| self.poll_join_multicast_group(addr, cx)).await - } - - /// Join a multicast group. - /// - /// When the send queue is full, this method will return `Poll::Pending` - /// and register the current task to be notified when the queue has space available. - pub fn poll_join_multicast_group(&self, addr: T, cx: &mut Context<'_>) -> Poll> - where - T: Into, - { - let addr = addr.into(); - - self.with_mut(|s, i| { - let (_hardware_addr, medium) = to_smoltcp_hardware_address(i.device.hardware_address()); - let mut smoldev = DriverAdapter { - cx: Some(cx), - inner: &mut i.device, - medium, - }; - - match s - .iface - .join_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now())) - { - Ok(announce_sent) => Poll::Ready(Ok(announce_sent)), - Err(MulticastError::Exhausted) => Poll::Pending, - Err(other) => Poll::Ready(Err(other)), - } - }) + pub fn join_multicast_group(&self, addr: impl Into) -> Result<(), MulticastError> { + self.with_mut(|i| i.iface.join_multicast_group(addr)) } /// Leave a multicast group. - pub async fn leave_multicast_group(&self, addr: T) -> Result - where - T: Into, - { - let addr = addr.into(); - - poll_fn(move |cx| self.poll_leave_multicast_group(addr, cx)).await - } - - /// Leave a multicast group. - /// - /// When the send queue is full, this method will return `Poll::Pending` - /// and register the current task to be notified when the queue has space available. - pub fn poll_leave_multicast_group(&self, addr: T, cx: &mut Context<'_>) -> Poll> - where - T: Into, - { - let addr = addr.into(); - - self.with_mut(|s, i| { - let (_hardware_addr, medium) = to_smoltcp_hardware_address(i.device.hardware_address()); - let mut smoldev = DriverAdapter { - cx: Some(cx), - inner: &mut i.device, - medium, - }; - - match s - .iface - .leave_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now())) - { - Ok(leave_sent) => Poll::Ready(Ok(leave_sent)), - Err(MulticastError::Exhausted) => Poll::Pending, - Err(other) => Poll::Ready(Err(other)), - } - }) + pub fn leave_multicast_group(&self, addr: impl Into) -> Result<(), MulticastError> { + self.with_mut(|i| i.iface.leave_multicast_group(addr)) } /// Get whether the network stack has joined the given multicast group. - pub fn has_multicast_group>(&self, addr: T) -> bool { - self.socket.borrow().iface.has_multicast_group(addr) + pub fn has_multicast_group(&self, addr: impl Into) -> bool { + self.with(|i| i.iface.has_multicast_group(addr)) } } -impl SocketStack { +impl Inner { #[allow(clippy::absurd_extreme_comparisons, dead_code)] pub fn get_local_port(&mut self) -> u16 { let res = self.next_local_port; self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; res } -} -impl Inner { #[cfg(feature = "proto-ipv4")] - pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) { + pub fn set_config_v4(&mut self, config: ConfigV4) { // Handle static config. self.static_v4 = match config.clone() { ConfigV4::None => None, @@ -717,12 +651,12 @@ impl Inner { // Create the socket if it doesn't exist. if self.dhcp_socket.is_none() { let socket = smoltcp::socket::dhcpv4::Socket::new(); - let handle = _s.sockets.add(socket); + let handle = self.sockets.add(socket); self.dhcp_socket = Some(handle); } // Configure it - let socket = _s.sockets.get_mut::(unwrap!(self.dhcp_socket)); + let socket = self.sockets.get_mut::(unwrap!(self.dhcp_socket)); socket.set_ignore_naks(c.ignore_naks); socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); socket.set_ports(c.server_port, c.client_port); @@ -731,19 +665,20 @@ impl Inner { socket.set_outgoing_options(&[]); #[cfg(feature = "dhcpv4-hostname")] if let Some(h) = c.hostname { - // safety: we just did set_outgoing_options([]) so we know the socket is no longer holding a reference. - let hostname = unsafe { &mut *self.hostname.get() }; + // safety: + // - we just did set_outgoing_options([]) so we know the socket is no longer holding a reference. + // - we know this pointer lives for as long as the stack exists, because `new()` borrows + // the resources for `'d`. Therefore it's OK to pass a reference to this to smoltcp. + let hostname = unsafe { &mut *self.hostname }; // create data - // safety: we know the buffer lives forever, new borrows the StackResources for 'static. - // also we won't modify it until next call to this function. - hostname.data[..h.len()].copy_from_slice(h.as_bytes()); - let data: &[u8] = &hostname.data[..h.len()]; - let data: &'static [u8] = unsafe { core::mem::transmute(data) }; + let data = hostname.data.write([0; MAX_HOSTNAME_LEN]); + data[..h.len()].copy_from_slice(h.as_bytes()); + let data: &[u8] = &data[..h.len()]; // set the option. - hostname.option = smoltcp::wire::DhcpOption { data, kind: 12 }; - socket.set_outgoing_options(core::slice::from_ref(&hostname.option)); + let option = hostname.option.write(smoltcp::wire::DhcpOption { data, kind: 12 }); + socket.set_outgoing_options(core::slice::from_ref(option)); } socket.reset(); @@ -751,7 +686,7 @@ impl Inner { _ => { // Remove DHCP socket if any. if let Some(socket) = self.dhcp_socket { - _s.sockets.remove(socket); + self.sockets.remove(socket); self.dhcp_socket = None; } } @@ -759,14 +694,14 @@ impl Inner { } #[cfg(feature = "proto-ipv6")] - pub fn set_config_v6(&mut self, _s: &mut SocketStack, config: ConfigV6) { + pub fn set_config_v6(&mut self, config: ConfigV6) { self.static_v6 = match config { ConfigV6::None => None, ConfigV6::Static(c) => Some(c), }; } - fn apply_static_config(&mut self, s: &mut SocketStack) { + fn apply_static_config(&mut self) { let mut addrs = Vec::new(); #[cfg(feature = "dns")] let mut dns_servers: Vec<_, 6> = Vec::new(); @@ -810,20 +745,20 @@ impl Inner { } // Apply addresses - s.iface.update_ip_addrs(|a| *a = addrs); + self.iface.update_ip_addrs(|a| *a = addrs); // Apply gateways #[cfg(feature = "proto-ipv4")] if let Some(gateway) = gateway_v4 { - unwrap!(s.iface.routes_mut().add_default_ipv4_route(gateway)); + unwrap!(self.iface.routes_mut().add_default_ipv4_route(gateway)); } else { - s.iface.routes_mut().remove_default_ipv4_route(); + self.iface.routes_mut().remove_default_ipv4_route(); } #[cfg(feature = "proto-ipv6")] if let Some(gateway) = gateway_v6 { - unwrap!(s.iface.routes_mut().add_default_ipv6_route(gateway)); + unwrap!(self.iface.routes_mut().add_default_ipv6_route(gateway)); } else { - s.iface.routes_mut().remove_default_ipv6_route(); + self.iface.routes_mut().remove_default_ipv6_route(); } // Apply DNS servers @@ -835,7 +770,7 @@ impl Inner { } else { dns_servers.len() }; - s.sockets + self.sockets .get_mut::(self.dns_socket) .update_servers(&dns_servers[..count]); } @@ -843,10 +778,10 @@ impl Inner { self.config_waker.wake(); } - fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { - s.waker.register(cx.waker()); + fn poll(&mut self, cx: &mut Context<'_>, driver: &mut D) { + self.waker.register(cx.waker()); - let (_hardware_addr, medium) = to_smoltcp_hardware_address(self.device.hardware_address()); + let (_hardware_addr, medium) = to_smoltcp_hardware_address(driver.hardware_address()); #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] { @@ -859,21 +794,21 @@ impl Inner { _ => false, }; if do_set { - s.iface.set_hardware_addr(_hardware_addr); + self.iface.set_hardware_addr(_hardware_addr); } } let timestamp = instant_to_smoltcp(Instant::now()); let mut smoldev = DriverAdapter { cx: Some(cx), - inner: &mut self.device, + inner: driver, medium, }; - s.iface.poll(timestamp, &mut smoldev, &mut s.sockets); + self.iface.poll(timestamp, &mut smoldev, &mut self.sockets); // Update link up let old_link_up = self.link_up; - self.link_up = self.device.link_state(cx) == LinkState::Up; + self.link_up = driver.link_state(cx) == LinkState::Up; // Print when changed if old_link_up != self.link_up { @@ -885,7 +820,7 @@ impl Inner { #[cfg(feature = "dhcpv4")] if let Some(dhcp_handle) = self.dhcp_socket { - let socket = s.sockets.get_mut::(dhcp_handle); + let socket = self.sockets.get_mut::(dhcp_handle); if self.link_up { if old_link_up != self.link_up { @@ -914,10 +849,10 @@ impl Inner { } if apply_config { - self.apply_static_config(s); + self.apply_static_config(); } - if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { + if let Some(poll_at) = self.iface.poll_at(timestamp, &mut self.sockets) { let t = pin!(Timer::at(instant_from_smoltcp(poll_at))); if t.poll(cx).is_ready() { cx.waker().wake_by_ref(); @@ -925,3 +860,17 @@ impl Inner { } } } + +impl<'d, D: Driver> Runner<'d, D> { + /// Run the network stack. + /// + /// You must call this in a background task, to process network events. + pub async fn run(&mut self) -> ! { + poll_fn(|cx| { + self.stack.with_mut(|i| i.poll(cx, &mut self.driver)); + Poll::<()>::Pending + }) + .await; + unreachable!() + } +} diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index 7ecd913e7..1098dc208 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -1,6 +1,5 @@ //! Raw sockets. -use core::cell::RefCell; use core::future::poll_fn; use core::mem; use core::task::{Context, Poll}; @@ -11,7 +10,7 @@ use smoltcp::socket::raw; pub use smoltcp::socket::raw::PacketMetadata; use smoltcp::wire::{IpProtocol, IpVersion}; -use crate::{SocketStack, Stack}; +use crate::Stack; /// Error returned by [`RawSocket::recv`] and [`RawSocket::send`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -23,14 +22,14 @@ pub enum RecvError { /// An Raw socket. pub struct RawSocket<'a> { - stack: &'a RefCell, + stack: Stack<'a>, handle: SocketHandle, } impl<'a> RawSocket<'a> { /// Create a new Raw socket using the provided stack and buffers. pub fn new( - stack: &'a Stack, + stack: Stack<'a>, ip_version: IpVersion, ip_protocol: IpProtocol, rx_meta: &'a mut [PacketMetadata], @@ -38,31 +37,29 @@ impl<'a> RawSocket<'a> { tx_meta: &'a mut [PacketMetadata], tx_buffer: &'a mut [u8], ) -> Self { - let s = &mut *stack.socket.borrow_mut(); + let handle = stack.with_mut(|i| { + let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + i.sockets.add(raw::Socket::new( + ip_version, + ip_protocol, + raw::PacketBuffer::new(rx_meta, rx_buffer), + raw::PacketBuffer::new(tx_meta, tx_buffer), + )) + }); - let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; - let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; - let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; - let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; - let handle = s.sockets.add(raw::Socket::new( - ip_version, - ip_protocol, - raw::PacketBuffer::new(rx_meta, rx_buffer), - raw::PacketBuffer::new(tx_meta, tx_buffer), - )); - - Self { - stack: &stack.socket, - handle, - } + Self { stack, handle } } fn with_mut(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res + self.stack.with_mut(|i| { + let socket = i.sockets.get_mut::(self.handle); + let res = f(socket, &mut i.iface); + i.waker.wake(); + res + }) } /// Receive a datagram. @@ -115,6 +112,10 @@ impl<'a> RawSocket<'a> { impl Drop for RawSocket<'_> { fn drop(&mut self) { - self.stack.borrow_mut().sockets.remove(self.handle); + self.stack.with_mut(|i| i.sockets.remove(self.handle)); } } + +fn _assert_covariant<'a, 'b: 'a>(x: RawSocket<'b>) -> RawSocket<'a> { + x +} diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index b2e3279cc..bcddbc95b 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -8,12 +8,10 @@ //! Incoming connections when no socket is listening are rejected. To accept many incoming //! connections, create many sockets and put them all into listening mode. -use core::cell::RefCell; use core::future::poll_fn; use core::mem; use core::task::Poll; -use embassy_net_driver::Driver; use embassy_time::Duration; use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::tcp; @@ -21,7 +19,7 @@ pub use smoltcp::socket::tcp::State; use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; use crate::time::duration_to_smoltcp; -use crate::{SocketStack, Stack}; +use crate::Stack; /// Error returned by TcpSocket read/write functions. #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -157,20 +155,18 @@ impl<'a> TcpWriter<'a> { impl<'a> TcpSocket<'a> { /// Create a new TCP socket on the given stack, with the given buffers. - pub fn new(stack: &'a Stack, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { - let s = &mut *stack.socket.borrow_mut(); - let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; - let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; - let handle = s.sockets.add(tcp::Socket::new( - tcp::SocketBuffer::new(rx_buffer), - tcp::SocketBuffer::new(tx_buffer), - )); + pub fn new(stack: Stack<'a>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { + let handle = stack.with_mut(|i| { + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + i.sockets.add(tcp::Socket::new( + tcp::SocketBuffer::new(rx_buffer), + tcp::SocketBuffer::new(tx_buffer), + )) + }); Self { - io: TcpIo { - stack: &stack.socket, - handle, - }, + io: TcpIo { stack: stack, handle }, } } @@ -228,7 +224,7 @@ impl<'a> TcpSocket<'a> { where T: Into, { - let local_port = self.io.stack.borrow_mut().get_local_port(); + let local_port = self.io.stack.with_mut(|i| i.get_local_port()); match { self.io @@ -401,31 +397,43 @@ impl<'a> TcpSocket<'a> { impl<'a> Drop for TcpSocket<'a> { fn drop(&mut self) { - self.io.stack.borrow_mut().sockets.remove(self.io.handle); + self.io.stack.with_mut(|i| i.sockets.remove(self.io.handle)); } } +fn _assert_covariant<'a, 'b: 'a>(x: TcpSocket<'b>) -> TcpSocket<'a> { + x +} +fn _assert_covariant_reader<'a, 'b: 'a>(x: TcpReader<'b>) -> TcpReader<'a> { + x +} +fn _assert_covariant_writer<'a, 'b: 'a>(x: TcpWriter<'b>) -> TcpWriter<'a> { + x +} + // ======================= #[derive(Copy, Clone)] struct TcpIo<'a> { - stack: &'a RefCell, + stack: Stack<'a>, handle: SocketHandle, } impl<'d> TcpIo<'d> { fn with(&self, f: impl FnOnce(&tcp::Socket, &Interface) -> R) -> R { - let s = &*self.stack.borrow(); - let socket = s.sockets.get::(self.handle); - f(socket, &s.iface) + self.stack.with(|i| { + let socket = i.sockets.get::(self.handle); + f(socket, &i.iface) + }) } fn with_mut(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res + self.stack.with_mut(|i| { + let socket = i.sockets.get_mut::(self.handle); + let res = f(socket, &mut i.iface); + i.waker.wake(); + res + }) } async fn read(&mut self, buf: &mut [u8]) -> Result { @@ -676,15 +684,15 @@ pub mod client { /// TCP client connection pool compatible with `embedded-nal-async` traits. /// /// The pool is capable of managing up to N concurrent connections with tx and rx buffers according to TX_SZ and RX_SZ. - pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { - stack: &'d Stack, + pub struct TcpClient<'d, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { + stack: Stack<'d>, state: &'d TcpClientState, socket_timeout: Option, } - impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> { + impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, N, TX_SZ, RX_SZ> { /// Create a new `TcpClient`. - pub fn new(stack: &'d Stack, state: &'d TcpClientState) -> Self { + pub fn new(stack: Stack<'d>, state: &'d TcpClientState) -> Self { Self { stack, state, @@ -701,8 +709,8 @@ pub mod client { } } - impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect - for TcpClient<'d, D, N, TX_SZ, RX_SZ> + impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect + for TcpClient<'d, N, TX_SZ, RX_SZ> { type Error = Error; type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm; @@ -722,7 +730,7 @@ pub mod client { IpAddr::V6(_) => panic!("ipv6 support not enabled"), }; let remote_endpoint = (addr, remote.port()); - let mut socket = TcpConnection::new(&self.stack, self.state)?; + let mut socket = TcpConnection::new(self.stack, self.state)?; socket.socket.set_timeout(self.socket_timeout.clone()); socket .socket @@ -741,7 +749,7 @@ pub mod client { } impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnection<'d, N, TX_SZ, RX_SZ> { - fn new(stack: &'d Stack, state: &'d TcpClientState) -> Result { + fn new(stack: Stack<'d>, state: &'d TcpClientState) -> Result { let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?; Ok(Self { socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().1, &mut bufs.as_mut().0) }, diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 1d5360187..3eb6e2f83 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -1,17 +1,15 @@ //! UDP sockets. -use core::cell::RefCell; use core::future::poll_fn; use core::mem; use core::task::{Context, Poll}; -use embassy_net_driver::Driver; use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::udp; pub use smoltcp::socket::udp::{PacketMetadata, UdpMetadata}; use smoltcp::wire::IpListenEndpoint; -use crate::{SocketStack, Stack}; +use crate::Stack; /// Error returned by [`UdpSocket::bind`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -43,34 +41,31 @@ pub enum RecvError { /// An UDP socket. pub struct UdpSocket<'a> { - stack: &'a RefCell, + stack: Stack<'a>, handle: SocketHandle, } impl<'a> UdpSocket<'a> { /// Create a new UDP socket using the provided stack and buffers. - pub fn new( - stack: &'a Stack, + pub fn new( + stack: Stack<'a>, rx_meta: &'a mut [PacketMetadata], rx_buffer: &'a mut [u8], tx_meta: &'a mut [PacketMetadata], tx_buffer: &'a mut [u8], ) -> Self { - let s = &mut *stack.socket.borrow_mut(); + let handle = stack.with_mut(|i| { + let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + i.sockets.add(udp::Socket::new( + udp::PacketBuffer::new(rx_meta, rx_buffer), + udp::PacketBuffer::new(tx_meta, tx_buffer), + )) + }); - let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; - let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; - let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; - let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; - let handle = s.sockets.add(udp::Socket::new( - udp::PacketBuffer::new(rx_meta, rx_buffer), - udp::PacketBuffer::new(tx_meta, tx_buffer), - )); - - Self { - stack: &stack.socket, - handle, - } + Self { stack, handle } } /// Bind the socket to a local endpoint. @@ -82,7 +77,7 @@ impl<'a> UdpSocket<'a> { if endpoint.port == 0 { // If user didn't specify port allocate a dynamic port. - endpoint.port = self.stack.borrow_mut().get_local_port(); + endpoint.port = self.stack.with_mut(|i| i.get_local_port()); } match self.with_mut(|s, _| s.bind(endpoint)) { @@ -93,17 +88,19 @@ impl<'a> UdpSocket<'a> { } fn with(&self, f: impl FnOnce(&udp::Socket, &Interface) -> R) -> R { - let s = &*self.stack.borrow(); - let socket = s.sockets.get::(self.handle); - f(socket, &s.iface) + self.stack.with(|i| { + let socket = i.sockets.get::(self.handle); + f(socket, &i.iface) + }) } fn with_mut(&self, f: impl FnOnce(&mut udp::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res + self.stack.with_mut(|i| { + let socket = i.sockets.get_mut::(self.handle); + let res = f(socket, &mut i.iface); + i.waker.wake(); + res + }) } /// Receive a datagram. @@ -298,6 +295,10 @@ impl<'a> UdpSocket<'a> { impl Drop for UdpSocket<'_> { fn drop(&mut self) { - self.stack.borrow_mut().sockets.remove(self.handle); + self.stack.with_mut(|i| i.sockets.remove(self.handle)); } } + +fn _assert_covariant<'a, 'b: 'a>(x: UdpSocket<'b>) -> UdpSocket<'a> { + x +} diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index 94cf09c88..0946492fe 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_net_enc28j60::Enc28j60; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::rng::Rng; @@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs { #[embassy_executor::task] async fn net_task( - stack: &'static Stack< + mut runner: embassy_net::Runner< + 'static, Enc28j60, Output<'static>, Delay>, Output<'static>>, >, ) -> ! { - stack.run().await + runner.run().await } #[embassy_executor::main] @@ -67,12 +68,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell< - Stack, Output<'static>, Delay>, Output<'static>>>, - > = StaticCell::new(); - let stack = STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index e56b215e3..b07adac1f 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -6,7 +6,7 @@ use core::mem; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_nrf::rng::Rng; use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; @@ -39,8 +39,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -116,10 +116,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell>> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index a3b69a99b..26eaf485e 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; @@ -36,8 +36,8 @@ async fn wifi_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, hosted::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -90,10 +90,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell>> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 5335b6b51..929883884 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -46,15 +46,15 @@ async fn modem_task(runner: Runner<'static>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_nrf91::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::task] async fn control_task( control: &'static context::Control<'static>, config: context::Config<'static>, - stack: &'static Stack>, + stack: Stack<'static>, ) { unwrap!(control.configure(&config).await); unwrap!( @@ -150,15 +150,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell>> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::<2>::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); static CONTROL: StaticCell> = StaticCell::new(); let control = CONTROL.init(context::Control::new(control, 0).await); diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index aaa035a72..12003adbe 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -36,8 +36,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -71,17 +71,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -89,12 +88,12 @@ async fn main(spawner: Spawner) { info!("IP address: {:?}", local_addr); // Create two sockets listening to the same port, to handle simultaneous connections - unwrap!(spawner.spawn(listen_task(&stack, 0, 1234))); - unwrap!(spawner.spawn(listen_task(&stack, 1, 1234))); + unwrap!(spawner.spawn(listen_task(stack, 0, 1234))); + unwrap!(spawner.spawn(listen_task(stack, 1, 1234))); } #[embassy_executor::task(pool_size = 2)] -async fn listen_task(stack: &'static Stack>, id: u8, port: u16) { +async fn listen_task(stack: Stack<'static>, id: u8, port: u16) { let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; let mut buf = [0; 4096]; @@ -131,7 +130,7 @@ async fn listen_task(stack: &'static Stack>, id: u8, port: u16) } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 8e96a114c..d66a43a88 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -38,8 +38,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -74,17 +74,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -119,7 +118,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 40736bf3c..97d9bd4c9 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -37,8 +37,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -73,17 +73,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -128,7 +127,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index c79f01538..b1b5f9758 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -36,8 +36,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -71,17 +71,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -108,7 +107,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 03c510f37..9a15125d4 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_rp::clocks::RoscRng; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; @@ -40,8 +40,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -108,11 +108,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 00f404a9b..4c9651433 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -11,7 +11,7 @@ use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -33,8 +33,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -80,16 +80,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); //control.start_ap_open("cyw43", 5).await; control.start_ap_wpa2("cyw43", "password", 5).await; diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index ab3529112..434f0074c 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -10,7 +10,6 @@ use core::str; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; -use embassy_net::Stack; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIO0}; @@ -28,8 +27,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index b2950d98a..7bf546e01 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -12,7 +12,7 @@ use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -37,8 +37,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -84,16 +84,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); loop { match control diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index b43be8905..1ae909917 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -13,7 +13,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::dns::DnsSocket; use embassy_net::tcp::client::{TcpClient, TcpClientState}; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -40,8 +40,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -87,16 +87,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); loop { match control diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index 310e7264d..cefa5448c 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -1,7 +1,7 @@ use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use embassy_time::Duration; use embedded_io_async::Write; @@ -22,8 +22,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[embassy_executor::task] @@ -50,12 +50,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); // Then we can use it! let mut rx_buffer = [0; 4096]; diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index c9615ef35..a42c5dbb7 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs @@ -1,7 +1,7 @@ use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::dns::DnsQueryType; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; @@ -20,8 +20,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[embassy_executor::task] @@ -49,12 +49,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack: &Stack<_> = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); let host = "example.com"; info!("querying host {:?}...", host); diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index c5c27c4a3..7d0f1327f 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -37,16 +37,12 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_ppp::Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::task] -async fn ppp_task( - stack: &'static Stack>, - mut runner: Runner<'static>, - port: SerialPort, -) -> ! { +async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: SerialPort) -> ! { let port = Async::new(port).unwrap(); let port = BufReader::new(port); let port = adapter::FromFutures::new(port); @@ -97,17 +93,16 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, net_runner) = embassy_net::new( device, Config::default(), // don't configure IP yet RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(net_runner)).unwrap(); spawner.spawn(ppp_task(stack, runner, port)).unwrap(); // Then we can use it! diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index b2ba4915a..02d4d3efb 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs @@ -1,7 +1,7 @@ use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::udp::{PacketMetadata, UdpSocket}; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; @@ -20,8 +20,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[embassy_executor::task] @@ -48,12 +48,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); // Then we can use it! let mut rx_meta = [PacketMetadata::EMPTY; 16]; diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 39b29a449..5d36b739d 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -3,7 +3,7 @@ use core::fmt::Write as _; use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use embassy_time::{Duration, Timer}; use embedded_io_async::Write as _; @@ -24,8 +24,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[derive(Default)] @@ -62,12 +62,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); // Then we can use it! let mut rx_buffer = [0; 4096]; diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 9388c64bf..baed96449 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -88,12 +88,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -105,7 +104,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 4096]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs index 5c3c6c3ba..6e6bef08c 100644 --- a/examples/stm32f4/src/bin/eth_w5500.rs +++ b/examples/stm32f4/src/bin/eth_w5500.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::{Device, Runner, State}; use embassy_stm32::exti::ExtiInput; @@ -31,8 +31,8 @@ async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'st } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -92,12 +92,11 @@ async fn main(spawner: Spawner) -> ! { // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), //}); - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 94e51c338..a9504ec04 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; @@ -31,8 +31,8 @@ async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } bind_interrupts!(struct Irqs { @@ -144,11 +144,10 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 2fd10c8fb..1f1eadf37 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -89,12 +89,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -106,7 +105,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 4096]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 65cfad8c9..eee1632f5 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -92,12 +92,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -109,7 +108,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 1024]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index b2f8ed91e..ec3f2c000 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -91,12 +91,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -108,7 +107,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 1024]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 274c24ab1..24983ca85 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -91,12 +91,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -104,7 +103,7 @@ async fn main(spawner: Spawner) -> ! { info!("Network task initialized"); let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); - let client = TcpClient::new(&stack, &state); + let client = TcpClient::new(stack, &state); loop { // You need to start a server on the host machine, for example: `nc -l 8000` diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index aa6544f41..768d85993 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -97,12 +97,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -110,7 +109,7 @@ async fn main(spawner: Spawner) -> ! { info!("Network task initialized"); let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); - let client = TcpClient::new(&stack, &state); + let client = TcpClient::new(stack, &state); loop { // You need to start a server on the host machine, for example: `nc -l 8000` diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index bd633cecb..be4270ada 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -206,12 +206,11 @@ async fn main(spawner: Spawner) { }; // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); let cfg = wait_for_config(stack).await; let local_addr = cfg.address.address(); @@ -274,7 +273,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config; @@ -323,8 +322,8 @@ async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } // same panicking *behavior* as `panic-probe` but doesn't print a panic message diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index d02bac91d..095d50c73 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::rng::Rng; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; @@ -36,8 +36,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -121,11 +121,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index 304754c0e..ed58627f1 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120); use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_net_enc28j60::Enc28j60; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::rng::Rng; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type MyDriver = Enc28j60, Output<'static>, Delay>, Output<'static>>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -65,11 +65,10 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index 6632442f1..34fb8103b 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120); use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; @@ -40,8 +40,8 @@ async fn wifi_task( type MyDriver = hosted::NetDriver<'static>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -86,16 +86,15 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs index 54762379a..4bd9e5674 100644 --- a/tests/perf-client/src/lib.rs +++ b/tests/perf-client/src/lib.rs @@ -2,7 +2,6 @@ use defmt::{assert, *}; use embassy_futures::join::join; -use embassy_net::driver::Driver; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Stack}; use embassy_time::{with_timeout, Duration, Timer}; @@ -13,7 +12,7 @@ pub struct Expected { pub updown_kbps: usize, } -pub async fn run(stack: &Stack, expected: Expected) { +pub async fn run(stack: Stack<'_>, expected: Expected) { info!("Waiting for DHCP up..."); while stack.config_v4().is_none() { Timer::after_millis(100).await; @@ -38,7 +37,7 @@ const DOWNLOAD_PORT: u16 = 4321; const UPLOAD_PORT: u16 = 4322; const UPLOAD_DOWNLOAD_PORT: u16 = 4323; -async fn test_download(stack: &Stack) -> usize { +async fn test_download(stack: Stack<'_>) -> usize { info!("Testing download..."); let mut rx_buffer = [0; RX_BUFFER_SIZE]; @@ -78,7 +77,7 @@ async fn test_download(stack: &Stack) -> usize { kbps } -async fn test_upload(stack: &Stack) -> usize { +async fn test_upload(stack: Stack<'_>) -> usize { info!("Testing upload..."); let mut rx_buffer = [0; RX_BUFFER_SIZE]; @@ -118,7 +117,7 @@ async fn test_upload(stack: &Stack) -> usize { kbps } -async fn test_upload_download(stack: &Stack) -> usize { +async fn test_upload_download(stack: Stack<'_>) -> usize { info!("Testing upload+download..."); let mut rx_buffer = [0; RX_BUFFER_SIZE]; diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 11c8aa58c..30e4afb07 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -6,7 +6,7 @@ use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; @@ -30,8 +30,8 @@ async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stati } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -70,16 +70,15 @@ async fn main(spawner: Spawner) { let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( net_device, Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); loop { match control diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index f15f33743..ae2adfa55 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -5,7 +5,7 @@ teleprobe_meta::timeout!(120); use defmt::*; use embassy_executor::Spawner; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_net_wiznet::chip::W5100S; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; @@ -32,8 +32,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -67,17 +67,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index 9da514881..bf1922dde 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -6,7 +6,7 @@ mod common; use common::*; use embassy_executor::Spawner; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -32,8 +32,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -99,12 +99,11 @@ async fn main(spawner: Spawner) { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, From 73aa40a9b9ab13655aa39969494dd377f57b699e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 16 Sep 2024 21:27:34 +0200 Subject: [PATCH 200/210] Disable nrf52840 hil tests. --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 5e8bddb8c..50331bdba 100755 --- a/ci.sh +++ b/ci.sh @@ -290,8 +290,9 @@ cargo batch \ $BUILD_EXTRA -# temporarily disabled, bluepill board got bricked +# temporarily disabled, these boards are dead. rm -rf out/tests/stm32f103c8 +rm -rf out/tests/nrf52840-dk rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From 6d89f2729ab7a6ee3dd78ccaef1b16677b5a9eee Mon Sep 17 00:00:00 2001 From: kingofpayne <43875454+kingofpayne@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:07:56 +0200 Subject: [PATCH 201/210] boot: flash-erase-zero (#3344) Allow compatibility with devices whose flash erase set bytes to 0x00 instead of 0xFF, using a new flash-erase-zero feature. See issue #3342. --- docs/pages/bootloader.adoc | 2 ++ embassy-boot/Cargo.toml | 1 + embassy-boot/src/lib.rs | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc index 3b0cdb182..d8d50040b 100644 --- a/docs/pages/bootloader.adoc +++ b/docs/pages/bootloader.adoc @@ -19,6 +19,8 @@ The bootloader supports In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work. +STM32L0x1 devices require the `flash-erase-zero` feature to be enabled. + == Design image::bootloader_flash.png[Bootloader flash layout] diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index d27fe763e..79ba6456a 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -47,6 +47,7 @@ ed25519-dalek = { version = "2", default-features = false, features = ["std", "r [features] ed25519-dalek = ["dep:ed25519-dalek", "_verify"] ed25519-salty = ["dep:salty", "_verify"] +flash-erase-zero = [] #Internal features _verify = [] diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index b4f03e01e..8849055e8 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -14,7 +14,11 @@ mod test_flash; // The expected value of the flash after an erase // TODO: Use the value provided by NorFlash when available +#[cfg(not(feature = "flash-erase-zero"))] pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF; +#[cfg(feature = "flash-erase-zero")] +pub(crate) const STATE_ERASE_VALUE: u8 = 0x00; + pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; pub use firmware_updater::{ BlockingFirmwareState, BlockingFirmwareUpdater, FirmwareState, FirmwareUpdater, FirmwareUpdaterConfig, From 0bfc98a3e526075ad14517589e4879d14f50ad12 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Tue, 17 Sep 2024 19:41:58 +0200 Subject: [PATCH 202/210] rp: Add PIO example for one-wire temperature sensor --- examples/rp/src/bin/pio_onewire.rs | 155 +++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 examples/rp/src/bin/pio_onewire.rs diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs new file mode 100644 index 000000000..5076101ec --- /dev/null +++ b/examples/rp/src/bin/pio_onewire.rs @@ -0,0 +1,155 @@ +//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. + +#![no_std] +#![no_main] +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut pio = Pio::new(p.PIO0, Irqs); + let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); + + loop { + sensor.start().await; // Start a new measurement + Timer::after_secs(1).await; // Allow 1s for the measurement to finish + match sensor.temperature().await { + Ok(temp) => info!("temp = {:?} deg C", temp), + _ => error!("sensor error"), + } + Timer::after_secs(1).await; + } +} + +/// DS18B20 temperature sensor driver +pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { + sm: StateMachine<'d, PIO, SM>, +} + +impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { + /// Create a new instance the driver + pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { + let prg = pio_proc::pio_asm!( + r#" + .wrap_target + again: + pull block + mov x, osr + jmp !x, read + write: + set pindirs, 1 + set pins, 0 + loop1: + jmp x--,loop1 + set pindirs, 0 [31] + wait 1 pin 0 [31] + pull block + mov x, osr + bytes1: + pull block + set y, 7 + set pindirs, 1 + bit1: + set pins, 0 [1] + out pins,1 [31] + set pins, 1 [20] + jmp y--,bit1 + jmp x--,bytes1 + set pindirs, 0 [31] + jmp again + read: + pull block + mov x, osr + bytes2: + set y, 7 + bit2: + set pindirs, 1 + set pins, 0 [1] + set pindirs, 0 [5] + in pins,1 [10] + jmp y--,bit2 + jmp x--,bytes2 + .wrap + "#, + ); + + let pin = common.make_pio_pin(pin); + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&prg.program), &[]); + cfg.set_out_pins(&[&pin]); + cfg.set_in_pins(&[&pin]); + cfg.set_set_pins(&[&pin]); + cfg.shift_in = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Right, + threshold: 8, + }; + cfg.clock_divider = 255_u8.into(); + sm.set_config(&cfg); + sm.set_enable(true); + Self { sm } + } + + /// Write bytes over the wire + async fn write_bytes(&mut self, bytes: &[u8]) { + self.sm.tx().wait_push(250).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes { + self.sm.tx().wait_push(*b as u32).await; + } + } + + /// Read bytes from the wire + async fn read_bytes(&mut self, bytes: &mut [u8]) { + self.sm.tx().wait_push(0).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes.iter_mut() { + *b = (self.sm.rx().wait_pull().await >> 24) as u8; + } + } + + /// Calculate CRC8 of the data + fn crc8(data: &[u8]) -> u8 { + let mut temp; + let mut data_byte; + let mut crc = 0; + for b in data { + data_byte = *b; + for _ in 0..8 { + temp = (crc ^ data_byte) & 0x01; + crc >>= 1; + if temp != 0 { + crc ^= 0x8C; + } + data_byte >>= 1; + } + } + crc + } + + /// Start a new measurement. Allow at least 1000ms before getting `temperature`. + pub async fn start(&mut self) { + self.write_bytes(&[0xCC, 0x44]).await; + } + + /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. + pub async fn temperature(&mut self) -> Result { + self.write_bytes(&[0xCC, 0xBE]).await; + let mut data = [0; 9]; + self.read_bytes(&mut data).await; + match Self::crc8(&data) == 0 { + true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), + false => Err(()), + } + } +} From 2bc49763c6c36026feeaf681078d06106b73e0b0 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 14 Sep 2024 14:57:10 +0200 Subject: [PATCH 203/210] TRNG support for 235x --- embassy-rp/src/lib.rs | 4 + embassy-rp/src/trng.rs | 405 ++++++++++++++++++++++++++++++++++ examples/rp23/src/bin/trng.rs | 64 ++++++ 3 files changed, 473 insertions(+) create mode 100644 embassy-rp/src/trng.rs create mode 100644 examples/rp23/src/bin/trng.rs diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index c357c14c2..d402cf793 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -42,6 +42,8 @@ pub mod rtc; pub mod spi; #[cfg(feature = "time-driver")] pub mod time_driver; +#[cfg(feature = "_rp235x")] +pub mod trng; pub mod uart; pub mod usb; pub mod watchdog; @@ -402,6 +404,8 @@ embassy_hal_internal::peripherals! { WATCHDOG, BOOTSEL, + + TRNG } #[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))] diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs new file mode 100644 index 000000000..9f2f33c4b --- /dev/null +++ b/embassy-rp/src/trng.rs @@ -0,0 +1,405 @@ +//! True Random Number Generator (TRNG) driver. + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ops::Not; +use core::task::Poll; + +use embassy_hal_internal::Peripheral; +use embassy_sync::waitqueue::AtomicWaker; +use rand_core::Error; + +use crate::interrupt::typelevel::{Binding, Interrupt}; +use crate::peripherals::TRNG; +use crate::{interrupt, pac}; + +trait SealedInstance { + fn regs() -> pac::trng::Trng; + fn waker() -> &'static AtomicWaker; +} + +/// TRNG peripheral instance. +#[allow(private_bounds)] +pub trait Instance: SealedInstance { + /// Interrupt for this peripheral. + type Interrupt: Interrupt; +} + +impl SealedInstance for TRNG { + fn regs() -> rp_pac::trng::Trng { + pac::TRNG + } + + fn waker() -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } +} + +impl Instance for TRNG { + type Interrupt = interrupt::typelevel::TRNG_IRQ; +} + +#[derive(Copy, Clone, Debug)] +#[allow(missing_docs)] +/// TRNG ROSC Inverter chain length options. +pub enum InverterChainLength { + None = 0, + One, + Two, + Three, + Four, +} + +impl From for u8 { + fn from(value: InverterChainLength) -> Self { + value as u8 + } +} + +/// Configuration for the TRNG. +/// +/// - Three built in entropy checks +/// - ROSC frequency controlled by selecting one of ROSC chain lengths +/// - Sample period in terms of system clock ticks +/// +/// +/// Default configuration is based on the following from documentation: +/// +/// ---- +/// +/// RP2350 Datasheet 12.12.2 +/// +/// ... +/// +/// When configuring the TRNG block, consider the following principles: +/// • As average generation time increases, result quality increases and failed entropy checks decrease. +/// • A low sample count decreases average generation time, but increases the chance of NIST test-failing results and +/// failed entropy checks. +/// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or +/// 1 and sample count settings of 20-25. +/// +/// --- +/// +/// Note, Pico SDK and Bootrom don't use any of the entropy checks and sample the ROSC directly +/// by setting the sample period to 0. Random data collected this way is then passed through +/// either hardware accelerated SHA256 (Bootrom) or xoroshiro128** (version 1.0!). +#[non_exhaustive] +#[derive(Copy, Clone, Debug)] +pub struct Config { + /// Bypass TRNG autocorrelation test + pub disable_autocorrelation_test: bool, + /// Bypass CRNGT test + pub disable_crngt_test: bool, + /// When set, the Von-Neuman balancer is bypassed (including the + /// 32 consecutive bits test) + pub disable_von_neumann_balancer: bool, + /// Sets the number of rng_clk cycles between two consecutive + /// ring oscillator samples. + /// Note: If the von Neumann decorrelator is bypassed, the minimum value for + /// sample counter must not be less than seventeen + pub sample_count: u32, + /// Selects the number of inverters (out of four possible + /// selections) in the ring oscillator (the entropy source). Higher values select + /// longer inverter chain lengths. + pub inverter_chain_length: InverterChainLength, +} + +impl Default for Config { + fn default() -> Self { + Config { + disable_autocorrelation_test: true, + disable_crngt_test: true, + disable_von_neumann_balancer: true, + sample_count: 25, + inverter_chain_length: InverterChainLength::One, + } + } +} + +/// True Random Number Generator Driver for RP2350 +/// +/// This driver provides async and blocking options. +/// +/// See [Config] for configuration details. +/// +/// Usage example: +/// ```no_run +/// use embassy_executor::Spawner; +/// use embassy_rp::trng::Trng; +/// use embassy_rp::peripherals::TRNG; +/// use embassy_rp::bind_interrupts; +/// +/// bind_interrupts!(struct Irqs { +/// TRNG_IRQ => embassy_rp::trng::InterruptHandler; +/// }); +/// +/// #[embassy_executor::main] +/// async fn main(spawner: Spawner) { +/// let peripherals = embassy_rp::init(Default::default()); +/// let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default()); +/// +/// let mut randomness = [0u8; 58]; +/// loop { +/// trng.fill_bytes(&mut randomness).await; +/// assert_ne!(randomness, [0u8; 58]); +/// } +///} +/// ``` +pub struct Trng<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, +} + +/// 12.12.1. Overview +/// On request, the TRNG block generates a block of 192 entropy bits generated by automatically processing a series of +/// periodic samples from the TRNG block’s internal Ring Oscillator (ROSC). +const TRNG_BLOCK_SIZE_BITS: usize = 192; +const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8; + +impl<'d, T: Instance> Trng<'d, T> { + /// Create a new TRNG driver. + pub fn new( + _trng: impl Peripheral

+ 'd, + _irq: impl Binding> + 'd, + config: Config, + ) -> Self { + let regs = T::regs(); + + regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); + + let trng_config_register = regs.trng_config(); + trng_config_register.write(|w| { + w.set_rnd_src_sel(config.inverter_chain_length.clone().into()); + }); + + let sample_count_register = regs.sample_cnt1(); + sample_count_register.write(|w| { + *w = config.sample_count; + }); + + let debug_control_register = regs.trng_debug_control(); + debug_control_register.write(|w| { + w.set_auto_correlate_bypass(config.disable_autocorrelation_test); + w.set_trng_crngt_bypass(config.disable_crngt_test); + w.set_vnc_bypass(config.disable_von_neumann_balancer) + }); + + Trng { phantom: PhantomData } + } + + fn start_rng(&self) { + let regs = T::regs(); + let source_enable_register = regs.rnd_source_enable(); + // Enable TRNG ROSC + source_enable_register.write(|w| w.set_rnd_src_en(true)); + } + + fn stop_rng(&self) { + let regs = T::regs(); + let source_enable_register = regs.rnd_source_enable(); + source_enable_register.write(|w| w.set_rnd_src_en(false)); + let reset_bits_counter_register = regs.rst_bits_counter(); + reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true)); + } + + fn enable_irq(&self) { + unsafe { T::Interrupt::enable() } + } + + fn disable_irq(&self) { + T::Interrupt::disable(); + } + + fn blocking_wait_for_successful_generation(&self) { + let regs = T::regs(); + + let trng_busy_register = regs.trng_busy(); + let trng_valid_register = regs.trng_valid(); + + let mut success = false; + while success.not() { + while trng_busy_register.read().trng_busy() {} + if trng_valid_register.read().ehr_valid().not() { + if regs.rng_isr().read().autocorr_err() { + regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true)); + } else { + panic!("RNG not busy, but ehr is not valid!") + } + } else { + success = true + } + } + } + + fn read_ehr_registers_into_array(&mut self, buffer: &mut [u8; TRNG_BLOCK_SIZE_BYTES]) { + let regs = T::regs(); + let ehr_data_regs = [ + regs.ehr_data0(), + regs.ehr_data1(), + regs.ehr_data2(), + regs.ehr_data3(), + regs.ehr_data4(), + regs.ehr_data5(), + ]; + + for (i, reg) in ehr_data_regs.iter().enumerate() { + buffer[i * 4..i * 4 + 4].copy_from_slice(®.read().to_ne_bytes()); + } + } + + fn blocking_read_ehr_registers_into_array(&mut self, buffer: &mut [u8; TRNG_BLOCK_SIZE_BYTES]) { + self.blocking_wait_for_successful_generation(); + self.read_ehr_registers_into_array(buffer); + } + + /// Fill the buffer with random bytes, async version. + pub async fn fill_bytes(&mut self, destination: &mut [u8]) { + if destination.is_empty() { + return; // Nothing to fill + } + + self.start_rng(); + self.enable_irq(); + + let mut bytes_transferred = 0usize; + let mut buffer = [0u8; TRNG_BLOCK_SIZE_BYTES]; + + let regs = T::regs(); + + let trng_busy_register = regs.trng_busy(); + let trng_valid_register = regs.trng_valid(); + + let waker = T::waker(); + + let destination_length = destination.len(); + + poll_fn(|context| { + waker.register(context.waker()); + if bytes_transferred == destination_length { + self.stop_rng(); + self.disable_irq(); + Poll::Ready(()) + } else { + if trng_busy_register.read().trng_busy() { + Poll::Pending + } else { + if trng_valid_register.read().ehr_valid().not() { + panic!("RNG not busy, but ehr is not valid!") + } + self.read_ehr_registers_into_array(&mut buffer); + let remaining = destination_length - bytes_transferred; + if remaining > TRNG_BLOCK_SIZE_BYTES { + destination[bytes_transferred..bytes_transferred + TRNG_BLOCK_SIZE_BYTES] + .copy_from_slice(&buffer); + bytes_transferred += TRNG_BLOCK_SIZE_BYTES + } else { + destination[bytes_transferred..bytes_transferred + remaining] + .copy_from_slice(&buffer[0..remaining]); + bytes_transferred += remaining + } + if bytes_transferred == destination_length { + self.stop_rng(); + self.disable_irq(); + Poll::Ready(()) + } else { + Poll::Pending + } + } + } + }) + .await + } + + /// Fill the buffer with random bytes, blocking version. + pub fn blocking_fill_bytes(&mut self, destination: &mut [u8]) { + if destination.is_empty() { + return; // Nothing to fill + } + self.start_rng(); + + let mut buffer = [0u8; TRNG_BLOCK_SIZE_BYTES]; + + for chunk in destination.chunks_mut(TRNG_BLOCK_SIZE_BYTES) { + self.blocking_wait_for_successful_generation(); + self.blocking_read_ehr_registers_into_array(&mut buffer); + chunk.copy_from_slice(&buffer[..chunk.len()]) + } + self.stop_rng() + } + + /// Return a random u32, blocking. + pub fn blocking_next_u32(&mut self) -> u32 { + let regs = T::regs(); + self.start_rng(); + self.blocking_wait_for_successful_generation(); + // 12.12.3 After successful generation, read the last result register, EHR_DATA[5] to + // clear all of the result registers. + let result = regs.ehr_data5().read(); + self.stop_rng(); + result + } + + /// Return a random u64, blocking. + pub fn blocking_next_u64(&mut self) -> u64 { + let regs = T::regs(); + self.start_rng(); + self.blocking_wait_for_successful_generation(); + + let low = regs.ehr_data4().read() as u64; + // 12.12.3 After successful generation, read the last result register, EHR_DATA[5] to + // clear all of the result registers. + let result = (regs.ehr_data5().read() as u64) << 32 | low; + self.stop_rng(); + result + } +} + +impl<'d, T: Instance> rand_core::RngCore for Trng<'d, T> { + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.blocking_fill_bytes(dest); + Ok(()) + } +} +/// TRNG interrupt handler. +pub struct InterruptHandler { + _trng: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let regs = T::regs(); + let isr = regs.rng_isr().read(); + // Clear ehr bit + regs.rng_icr().write(|w| { + w.set_ehr_valid(true); + }); + if isr.ehr_valid() { + T::waker().wake(); + } else { + // 12.12.5. List of Registers + // ... + // TRNG: RNG_ISR Register + // ... + // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row. + // When set, RNG ceases functioning until next reset + if isr.autocorr_err() { + warn!("TRNG Autocorrect error! Resetting TRNG"); + regs.trng_sw_reset().write(|w| { + w.set_trng_sw_reset(true); + }); + } + } + } +} diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp23/src/bin/trng.rs new file mode 100644 index 000000000..e146baa2e --- /dev/null +++ b/examples/rp23/src/bin/trng.rs @@ -0,0 +1,64 @@ +//! This example shows TRNG usage + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::peripherals::TRNG; +use embassy_rp::trng::Trng; +use embassy_time::Timer; +use rand::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +bind_interrupts!(struct Irqs { + TRNG_IRQ => embassy_rp::trng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let peripherals = embassy_rp::init(Default::default()); + + // Initialize the TRNG with default configuration + let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default()); + // A buffer to collect random bytes in. + let mut randomness = [0u8; 58]; + + let mut led = Output::new(peripherals.PIN_25, Level::Low); + + loop { + trng.fill_bytes(&mut randomness).await; + info!("Random bytes async {}", &randomness); + trng.blocking_fill_bytes(&mut randomness); + info!("Random bytes blocking {}", &randomness); + let random_u32 = trng.next_u32(); + let random_u64 = trng.next_u64(); + info!("Random u32 {} u64 {}", random_u32, random_u64); + // Random number of blinks between 0 and 31 + let blinks = random_u32 % 32; + for _ in 0..blinks { + led.set_high(); + Timer::after_millis(20).await; + led.set_low(); + Timer::after_millis(20).await; + } + Timer::after_millis(1000).await; + } +} From a406a01459a5c759c044a181ba992fb2bc9e1150 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 18 Sep 2024 21:24:35 +0200 Subject: [PATCH 204/210] net-esp-hosted: remove useless fn init. --- embassy-net-esp-hosted/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index c78578bf1..f05e2a70a 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -137,7 +137,7 @@ where let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); let state_ch = ch_runner.state_runner(); - let mut runner = Runner { + let runner = Runner { ch: ch_runner, state_ch, shared: &state.shared, @@ -148,7 +148,6 @@ where spi, heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP, }; - runner.init().await; (device, Control::new(state_ch, &state.shared), runner) } @@ -174,8 +173,6 @@ where IN: InputPin + Wait, OUT: OutputPin, { - async fn init(&mut self) {} - /// Run the packet processing. pub async fn run(mut self) -> ! { debug!("resetting..."); From 60f93b42e262dc30bf7bd3767b1912a92f9e0f43 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 18 Sep 2024 21:24:50 +0200 Subject: [PATCH 205/210] net-esp-hosted: set wpa3_supported=true. I've noticed wpa3 still works without this flag, so I'm not sure what this does tbh... --- embassy-net-esp-hosted/src/control.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index c8cea8503..b1838a425 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -120,7 +120,7 @@ impl<'a> Control<'a> { pwd: unwrap!(String::try_from(password)), bssid: String::new(), listen_interval: 3, - is_wpa3_supported: false, + is_wpa3_supported: true, }; ioctl!(self, ReqConnectAp, RespConnectAp, req, resp); self.state_ch.set_link_state(LinkState::Up); From bee53af36a91d984558cd22dd96195537fd61fd6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 18 Sep 2024 21:37:42 +0200 Subject: [PATCH 206/210] net: add all combinations of wait methods for link/config up/down. --- embassy-net/src/lib.rs | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index ef53fb905..a7b7efa87 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -260,7 +260,10 @@ pub struct Stack<'d> { pub(crate) struct Inner { pub(crate) sockets: SocketSet<'static>, // Lifetime type-erased. pub(crate) iface: Interface, + /// Waker used for triggering polls. pub(crate) waker: WakerRegistration, + /// Waker used for waiting for link up or config up. + state_waker: WakerRegistration, hardware_address: HardwareAddress, next_local_port: u16, link_up: bool, @@ -270,7 +273,6 @@ pub(crate) struct Inner { static_v6: Option, #[cfg(feature = "dhcpv4")] dhcp_socket: Option, - config_waker: WakerRegistration, #[cfg(feature = "dns")] dns_socket: SocketHandle, #[cfg(feature = "dns")] @@ -326,6 +328,7 @@ pub fn new<'d, D: Driver, const SOCK: usize>( sockets, iface, waker: WakerRegistration::new(), + state_waker: WakerRegistration::new(), next_local_port, hardware_address, link_up: false, @@ -335,7 +338,6 @@ pub fn new<'d, D: Driver, const SOCK: usize>( static_v6: None, #[cfg(feature = "dhcpv4")] dhcp_socket: None, - config_waker: WakerRegistration::new(), #[cfg(feature = "dns")] dns_socket, #[cfg(feature = "dns")] @@ -421,10 +423,20 @@ impl<'d> Stack<'d> { v4_up || v6_up } + /// Wait for the network device to obtain a link signal. + pub async fn wait_link_up(&self) { + self.wait(|| self.is_link_up()).await + } + + /// Wait for the network device to lose link signal. + pub async fn wait_link_down(&self) { + self.wait(|| !self.is_link_up()).await + } + /// Wait for the network stack to obtain a valid IP configuration. /// /// ## Notes: - /// - Ensure [`Stack::run`] has been called before using this function. + /// - Ensure [`Runner::run`] has been started before using this function. /// /// - This function may never return (e.g. if no configuration is obtained through DHCP). /// The caller is supposed to handle a timeout for this case. @@ -451,13 +463,17 @@ impl<'d> Stack<'d> { /// // ... /// ``` pub async fn wait_config_up(&self) { - // If the config is up already, we can return immediately. - if self.is_config_up() { - return; - } + self.wait(|| self.is_config_up()).await + } - poll_fn(|cx| { - if self.is_config_up() { + /// Wait for the network stack to lose a valid IP configuration. + pub async fn wait_config_down(&self) { + self.wait(|| !self.is_config_up()).await + } + + fn wait<'a>(&'a self, mut predicate: impl FnMut() -> bool + 'a) -> impl Future + 'a { + poll_fn(move |cx| { + if predicate() { Poll::Ready(()) } else { // If the config is not up, we register a waker that is woken up @@ -465,13 +481,12 @@ impl<'d> Stack<'d> { trace!("Waiting for config up"); self.with_mut(|i| { - i.config_waker.register(cx.waker()); + i.state_waker.register(cx.waker()); }); Poll::Pending } }) - .await; } /// Get the current IPv4 configuration. @@ -775,7 +790,7 @@ impl Inner { .update_servers(&dns_servers[..count]); } - self.config_waker.wake(); + self.state_waker.wake(); } fn poll(&mut self, cx: &mut Context<'_>, driver: &mut D) { @@ -813,6 +828,7 @@ impl Inner { // Print when changed if old_link_up != self.link_up { info!("link_up = {:?}", self.link_up); + self.state_waker.wake(); } #[allow(unused_mut)] From b1897c58fa617dbab02b39e7f5e399ed1c9d54b4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 18 Sep 2024 16:14:53 +0200 Subject: [PATCH 207/210] Add revert state in embassy-boot The revert state signals that a firmware revert has taken place, allowing the application to know if a firmware update attempt was reverted. --- embassy-boot/src/boot_loader.rs | 6 ++++-- embassy-boot/src/firmware_updater/asynch.rs | 3 ++- embassy-boot/src/firmware_updater/blocking.rs | 3 ++- embassy-boot/src/lib.rs | 6 ++++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 61d61b96e..5bffdc5ea 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; -use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; /// Errors returned by bootloader #[derive(PartialEq, Eq, Debug)] @@ -276,7 +276,7 @@ impl BootLoader BootLoader FirmwareState<'d, STATE> { // Make sure we are running a booted firmware to avoid reverting to a bad state. async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { - if self.get_state().await? == State::Boot { + let state = self.get_state().await?; + if state == State::Boot || state == State::DfuDetach || state == State::Revert { Ok(()) } else { Err(FirmwareUpdaterError::BadState) diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index d3c723456..5f64b4be9 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -324,7 +324,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { // Make sure we are running a booted firmware to avoid reverting to a bad state. fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { - if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach { + let state = self.get_state()?; + if state == State::Boot || state == State::DfuDetach || state == State::Revert { Ok(()) } else { Err(FirmwareUpdaterError::BadState) diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index 8849055e8..7d5cc58f9 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -25,6 +25,7 @@ pub use firmware_updater::{ FirmwareUpdaterError, }; +pub(crate) const REVERT_MAGIC: u8 = 0xC0; pub(crate) const BOOT_MAGIC: u8 = 0xD0; pub(crate) const SWAP_MAGIC: u8 = 0xF0; pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0; @@ -37,6 +38,8 @@ pub enum State { Boot, /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. Swap, + /// Bootloader has reverted the active partition with the dfu partition and will attempt boot. + Revert, /// Application has received a request to reboot into DFU mode to apply an update. DfuDetach, } @@ -157,6 +160,9 @@ mod tests { // Running again should cause a revert assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); + // Next time we know it was reverted + assert_eq!(State::Revert, bootloader.prepare_boot(&mut page).unwrap()); + let mut read_buf = [0; FIRMWARE_SIZE]; flash.active().read(0, &mut read_buf).unwrap(); assert_eq!(ORIGINAL, read_buf); From ab0a227e4c02137bc3a621907d17ede0ace4cb1d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 19 Sep 2024 09:15:08 +0200 Subject: [PATCH 208/210] Ensure bootloader state is parsed correctly --- embassy-boot/src/firmware_updater/asynch.rs | 7 +------ embassy-boot/src/firmware_updater/blocking.rs | 9 +-------- embassy-boot/src/lib.rs | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index b23857e2f..d9d15b004 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -304,12 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { /// `mark_booted`. pub async fn get_state(&mut self) -> Result { self.state.read(0, &mut self.aligned).await?; - - if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { - Ok(State::Swap) - } else { - Ok(State::Boot) - } + Ok(State::from(&self.aligned)) } /// Mark to trigger firmware swap on next boot. diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 5f64b4be9..08062b0d0 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -339,14 +339,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { /// `mark_booted`. pub fn get_state(&mut self) -> Result { self.state.read(0, &mut self.aligned)?; - - if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { - Ok(State::Swap) - } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) { - Ok(State::DfuDetach) - } else { - Ok(State::Boot) - } + Ok(State::from(&self.aligned)) } /// Mark to trigger firmware swap on next boot. diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index 7d5cc58f9..e2c4cf771 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -44,6 +44,24 @@ pub enum State { DfuDetach, } +impl From for State +where + T: AsRef<[u8]>, +{ + fn from(magic: T) -> State { + let magic = magic.as_ref(); + if !magic.iter().any(|&b| b != SWAP_MAGIC) { + State::Swap + } else if !magic.iter().any(|&b| b != REVERT_MAGIC) { + State::Revert + } else if !magic.iter().any(|&b| b != DFU_DETACH_MAGIC) { + State::DfuDetach + } else { + State::Boot + } + } +} + /// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. #[repr(align(32))] pub struct AlignedBuffer(pub [u8; N]); From df23a77bfc3c8b5d8ab6adbd12842fa4cfe3675d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 19 Sep 2024 09:15:35 +0200 Subject: [PATCH 209/210] Add led to example to demonstrate revert state detection --- examples/boot/application/nrf/src/bin/a.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 851a3d721..60cf3cd1a 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -8,6 +8,7 @@ use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::nvmc::Nvmc; use embassy_nrf::wdt::{self, Watchdog}; +use embassy_boot::State; use embassy_sync::mutex::Mutex; use panic_reset as _; @@ -22,6 +23,7 @@ async fn main(_spawner: Spawner) { let mut button = Input::new(p.P0_11, Pull::Up); let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard); //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); //let mut button = Input::new(p.P1_02, Pull::Up); @@ -53,6 +55,13 @@ async fn main(_spawner: Spawner) { let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); let mut magic = [0; 4]; let mut updater = FirmwareUpdater::new(config, &mut magic); + let state = updater.get_state().await.unwrap(); + if state == State::Revert { + led_reverted.set_low(); + } else { + led_reverted.set_high(); + } + loop { led.set_low(); button.wait_for_any_edge().await; From 4e1efd93fd4dc8dd692daf419d901ae22413e091 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 19 Sep 2024 09:15:55 +0200 Subject: [PATCH 210/210] Fix defmt support for example boot app --- examples/boot/application/nrf/build.rs | 3 +++ examples/boot/application/nrf/src/bin/a.rs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/boot/application/nrf/build.rs b/examples/boot/application/nrf/build.rs index cd1a264c4..e1da69328 100644 --- a/examples/boot/application/nrf/build.rs +++ b/examples/boot/application/nrf/build.rs @@ -31,4 +31,7 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } } diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 60cf3cd1a..2c1d1a7bb 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -2,13 +2,15 @@ #![no_main] #![macro_use] +#[cfg(feature = "defmt")] +use defmt_rtt as _; +use embassy_boot::State; use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::nvmc::Nvmc; use embassy_nrf::wdt::{self, Watchdog}; -use embassy_boot::State; use embassy_sync::mutex::Mutex; use panic_reset as _;