diff options
| author | Peter Krull <[email protected]> | 2024-09-23 19:02:59 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-09-23 19:02:59 +0200 |
| commit | a2c473306f4a7c8e99add2546450ab3a7a97436e (patch) | |
| tree | 5522a708e492db7d4632dc0a56fe5057244f03f0 /examples | |
| parent | e02a987bafd4f0fcf9d80e7c4f6e1504b8b02cec (diff) | |
| parent | 2935290a6222536d6341103f91bfd732165d3862 (diff) | |
Merge branch 'embassy-rs:main' into multi-signal
Diffstat (limited to 'examples')
403 files changed, 17890 insertions, 1389 deletions
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 86f6676cb..93e49faef 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml | |||
| @@ -5,13 +5,13 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | 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"] } | 9 | 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"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } |
| 11 | embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } | 11 | embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } |
| 12 | embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } | 12 | embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } |
| 13 | embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } | 13 | embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] } |
| 14 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 14 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 15 | 15 | ||
| 16 | defmt = { version = "0.3", optional = true } | 16 | defmt = { version = "0.3", optional = true } |
| 17 | defmt-rtt = { version = "0.4", optional = true } | 17 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -25,3 +25,10 @@ cortex-m-rt = "0.7.0" | |||
| 25 | ed25519-dalek = ["embassy-boot/ed25519-dalek"] | 25 | ed25519-dalek = ["embassy-boot/ed25519-dalek"] |
| 26 | ed25519-salty = ["embassy-boot/ed25519-salty"] | 26 | ed25519-salty = ["embassy-boot/ed25519-salty"] |
| 27 | skip-include = [] | 27 | skip-include = [] |
| 28 | defmt = [ | ||
| 29 | "dep:defmt", | ||
| 30 | "dep:defmt-rtt", | ||
| 31 | "embassy-nrf/defmt", | ||
| 32 | "embassy-boot-nrf/defmt", | ||
| 33 | "embassy-sync/defmt", | ||
| 34 | ] | ||
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() { | |||
| 31 | 31 | ||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); |
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); |
| 34 | if env::var("CARGO_FEATURE_DEFMT").is_ok() { | ||
| 35 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 36 | } | ||
| 34 | } | 37 | } |
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 851a3d721..2c1d1a7bb 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![macro_use] | 3 | #![macro_use] |
| 4 | 4 | ||
| 5 | #[cfg(feature = "defmt")] | ||
| 6 | use defmt_rtt as _; | ||
| 7 | use embassy_boot::State; | ||
| 5 | use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; | 8 | use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; |
| 6 | use embassy_embedded_hal::adapter::BlockingAsync; | 9 | use embassy_embedded_hal::adapter::BlockingAsync; |
| 7 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| @@ -22,6 +25,7 @@ async fn main(_spawner: Spawner) { | |||
| 22 | 25 | ||
| 23 | let mut button = Input::new(p.P0_11, Pull::Up); | 26 | let mut button = Input::new(p.P0_11, Pull::Up); |
| 24 | let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); | 27 | let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); |
| 28 | let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard); | ||
| 25 | 29 | ||
| 26 | //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); | 30 | //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); |
| 27 | //let mut button = Input::new(p.P1_02, Pull::Up); | 31 | //let mut button = Input::new(p.P1_02, Pull::Up); |
| @@ -53,6 +57,13 @@ async fn main(_spawner: Spawner) { | |||
| 53 | let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); | 57 | let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); |
| 54 | let mut magic = [0; 4]; | 58 | let mut magic = [0; 4]; |
| 55 | let mut updater = FirmwareUpdater::new(config, &mut magic); | 59 | let mut updater = FirmwareUpdater::new(config, &mut magic); |
| 60 | let state = updater.get_state().await.unwrap(); | ||
| 61 | if state == State::Revert { | ||
| 62 | led_reverted.set_low(); | ||
| 63 | } else { | ||
| 64 | led_reverted.set_high(); | ||
| 65 | } | ||
| 66 | |||
| 56 | loop { | 67 | loop { |
| 57 | led.set_low(); | 68 | led.set_low(); |
| 58 | button.wait_for_any_edge().await; | 69 | button.wait_for_any_edge().await; |
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 70741a0ce..8bb8afdfe 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | 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"] } | 9 | 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"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } |
| 11 | embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } | 11 | embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } |
| 12 | embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } | 12 | embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.4" | 16 | defmt-rtt = "0.4" |
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 1cb143820..1c2934298 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.4", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0" | |||
| 23 | [features] | 23 | [features] |
| 24 | defmt = [ | 24 | defmt = [ |
| 25 | "dep:defmt", | 25 | "dep:defmt", |
| 26 | "dep:defmt-rtt", | ||
| 26 | "embassy-stm32/defmt", | 27 | "embassy-stm32/defmt", |
| 27 | "embassy-boot-stm32/defmt", | 28 | "embassy-boot-stm32/defmt", |
| 28 | "embassy-sync/defmt", | 29 | "embassy-sync/defmt", |
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs index 8858ae3da..b608b2e01 100644 --- a/examples/boot/application/stm32f3/src/bin/a.rs +++ b/examples/boot/application/stm32f3/src/bin/a.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use embassy_embedded_hal::adapter::BlockingAsync; |
diff --git a/examples/boot/application/stm32f3/src/bin/b.rs b/examples/boot/application/stm32f3/src/bin/b.rs index 22ba82d5e..b1a505631 100644 --- a/examples/boot/application/stm32f3/src/bin/b.rs +++ b/examples/boot/application/stm32f3/src/bin/b.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use embassy_stm32::gpio::{Level, Output, Speed}; |
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index c4ae461a5..09e34c7df 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.4", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0" | |||
| 24 | [features] | 24 | [features] |
| 25 | defmt = [ | 25 | defmt = [ |
| 26 | "dep:defmt", | 26 | "dep:defmt", |
| 27 | "dep:defmt-rtt", | ||
| 27 | "embassy-stm32/defmt", | 28 | "embassy-stm32/defmt", |
| 28 | "embassy-boot-stm32/defmt", | 29 | "embassy-boot-stm32/defmt", |
| 29 | "embassy-sync/defmt", | 30 | "embassy-sync/defmt", |
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs index d3df11fe4..172b4c235 100644 --- a/examples/boot/application/stm32f7/src/bin/a.rs +++ b/examples/boot/application/stm32f7/src/bin/a.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use core::cell::RefCell; | 4 | use core::cell::RefCell; |
| 5 | 5 | ||
| 6 | #[cfg(feature = "defmt-rtt")] | 6 | #[cfg(feature = "defmt")] |
| 7 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; | 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
diff --git a/examples/boot/application/stm32f7/src/bin/b.rs b/examples/boot/application/stm32f7/src/bin/b.rs index 190477204..6bc9c9ab8 100644 --- a/examples/boot/application/stm32f7/src/bin/b.rs +++ b/examples/boot/application/stm32f7/src/bin/b.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use embassy_stm32::gpio::{Level, Output, Speed}; |
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 995487cdd..5e7f4d5e7 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.4", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0" | |||
| 24 | [features] | 24 | [features] |
| 25 | defmt = [ | 25 | defmt = [ |
| 26 | "dep:defmt", | 26 | "dep:defmt", |
| 27 | "dep:defmt-rtt", | ||
| 27 | "embassy-stm32/defmt", | 28 | "embassy-stm32/defmt", |
| 28 | "embassy-boot-stm32/defmt", | 29 | "embassy-boot-stm32/defmt", |
| 29 | "embassy-sync/defmt", | 30 | "embassy-sync/defmt", |
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs index f61ac1f71..c1b1a267a 100644 --- a/examples/boot/application/stm32h7/src/bin/a.rs +++ b/examples/boot/application/stm32h7/src/bin/a.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use core::cell::RefCell; | 4 | use core::cell::RefCell; |
| 5 | 5 | ||
| 6 | #[cfg(feature = "defmt-rtt")] | 6 | #[cfg(feature = "defmt")] |
| 7 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; | 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
diff --git a/examples/boot/application/stm32h7/src/bin/b.rs b/examples/boot/application/stm32h7/src/bin/b.rs index 5f3f35207..13bdae1f1 100644 --- a/examples/boot/application/stm32h7/src/bin/b.rs +++ b/examples/boot/application/stm32h7/src/bin/b.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use embassy_stm32::gpio::{Level, Output, Speed}; |
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index b2abc005c..60fdcfafb 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.4", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0" | |||
| 23 | [features] | 23 | [features] |
| 24 | defmt = [ | 24 | defmt = [ |
| 25 | "dep:defmt", | 25 | "dep:defmt", |
| 26 | "dep:defmt-rtt", | ||
| 26 | "embassy-stm32/defmt", | 27 | "embassy-stm32/defmt", |
| 27 | "embassy-boot-stm32/defmt", | 28 | "embassy-boot-stm32/defmt", |
| 28 | "embassy-sync/defmt", | 29 | "embassy-sync/defmt", |
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs index f066c1139..dcc10e5c6 100644 --- a/examples/boot/application/stm32l0/src/bin/a.rs +++ b/examples/boot/application/stm32l0/src/bin/a.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use embassy_embedded_hal::adapter::BlockingAsync; |
diff --git a/examples/boot/application/stm32l0/src/bin/b.rs b/examples/boot/application/stm32l0/src/bin/b.rs index 6bf00f41a..a59c6f540 100644 --- a/examples/boot/application/stm32l0/src/bin/b.rs +++ b/examples/boot/application/stm32l0/src/bin/b.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use embassy_stm32::gpio::{Level, Output, Speed}; |
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 7203e6350..fe3ab2c04 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.4", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0" | |||
| 23 | [features] | 23 | [features] |
| 24 | defmt = [ | 24 | defmt = [ |
| 25 | "dep:defmt", | 25 | "dep:defmt", |
| 26 | "dep:defmt-rtt", | ||
| 26 | "embassy-stm32/defmt", | 27 | "embassy-stm32/defmt", |
| 27 | "embassy-boot-stm32/defmt", | 28 | "embassy-boot-stm32/defmt", |
| 28 | "embassy-sync/defmt", | 29 | "embassy-sync/defmt", |
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs index f066c1139..dcc10e5c6 100644 --- a/examples/boot/application/stm32l1/src/bin/a.rs +++ b/examples/boot/application/stm32l1/src/bin/a.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use embassy_embedded_hal::adapter::BlockingAsync; |
diff --git a/examples/boot/application/stm32l1/src/bin/b.rs b/examples/boot/application/stm32l1/src/bin/b.rs index 6bf00f41a..a59c6f540 100644 --- a/examples/boot/application/stm32l1/src/bin/b.rs +++ b/examples/boot/application/stm32l1/src/bin/b.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use embassy_stm32::gpio::{Level, Output, Speed}; |
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index ec134f394..169856358 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.4", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0" | |||
| 23 | [features] | 23 | [features] |
| 24 | defmt = [ | 24 | defmt = [ |
| 25 | "dep:defmt", | 25 | "dep:defmt", |
| 26 | "dep:defmt-rtt", | ||
| 26 | "embassy-stm32/defmt", | 27 | "embassy-stm32/defmt", |
| 27 | "embassy-boot-stm32/defmt", | 28 | "embassy-boot-stm32/defmt", |
| 28 | "embassy-sync/defmt", | 29 | "embassy-sync/defmt", |
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs index a0079ee33..7f8015c04 100644 --- a/examples/boot/application/stm32l4/src/bin/a.rs +++ b/examples/boot/application/stm32l4/src/bin/a.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use embassy_embedded_hal::adapter::BlockingAsync; |
diff --git a/examples/boot/application/stm32l4/src/bin/b.rs b/examples/boot/application/stm32l4/src/bin/b.rs index 22ba82d5e..b1a505631 100644 --- a/examples/boot/application/stm32l4/src/bin/b.rs +++ b/examples/boot/application/stm32l4/src/bin/b.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | #[cfg(feature = "defmt")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use embassy_stm32::gpio::{Level, Output, Speed}; |
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 0bdf94331..7cef8fe0d 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml | |||
| @@ -5,13 +5,13 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } | 14 | embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" } |
| 15 | embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } | 15 | embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } |
| 16 | 16 | ||
| 17 | defmt = { version = "0.3", optional = true } | 17 | defmt = { version = "0.3", optional = true } |
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 37c3d7d90..0ab99ff90 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use core::cell::RefCell; | 4 | use core::cell::RefCell; |
| 5 | 5 | ||
| 6 | #[cfg(feature = "defmt-rtt")] | 6 | #[cfg(feature = "defmt")] |
| 7 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig}; | 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig}; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| @@ -41,7 +41,6 @@ async fn main(_spawner: Spawner) { | |||
| 41 | config.product = Some("USB-DFU Runtime example"); | 41 | config.product = Some("USB-DFU Runtime example"); |
| 42 | config.serial_number = Some("1235678"); | 42 | config.serial_number = Some("1235678"); |
| 43 | 43 | ||
| 44 | let mut device_descriptor = [0; 256]; | ||
| 45 | let mut config_descriptor = [0; 256]; | 44 | let mut config_descriptor = [0; 256]; |
| 46 | let mut bos_descriptor = [0; 256]; | 45 | let mut bos_descriptor = [0; 256]; |
| 47 | let mut control_buf = [0; 64]; | 46 | let mut control_buf = [0; 64]; |
| @@ -49,7 +48,6 @@ async fn main(_spawner: Spawner) { | |||
| 49 | let mut builder = Builder::new( | 48 | let mut builder = Builder::new( |
| 50 | driver, | 49 | driver, |
| 51 | config, | 50 | config, |
| 52 | &mut device_descriptor, | ||
| 53 | &mut config_descriptor, | 51 | &mut config_descriptor, |
| 54 | &mut bos_descriptor, | 52 | &mut bos_descriptor, |
| 55 | &mut [], | 53 | &mut [], |
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index e38e9f3af..860a835a9 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml | |||
| @@ -5,12 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.4", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| @@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0" | |||
| 23 | [features] | 23 | [features] |
| 24 | defmt = [ | 24 | defmt = [ |
| 25 | "dep:defmt", | 25 | "dep:defmt", |
| 26 | "dep:defmt-rtt", | ||
| 26 | "embassy-stm32/defmt", | 27 | "embassy-stm32/defmt", |
| 27 | "embassy-boot-stm32/defmt", | 28 | "embassy-boot-stm32/defmt", |
| 28 | "embassy-sync/defmt", | 29 | "embassy-sync/defmt", |
diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x index e1d4e7fa8..20109e37e 100644 --- a/examples/boot/application/stm32wl/memory.x +++ b/examples/boot/application/stm32wl/memory.x | |||
| @@ -5,7 +5,8 @@ MEMORY | |||
| 5 | BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K | 5 | BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K |
| 6 | FLASH : ORIGIN = 0x08008000, LENGTH = 64K | 6 | FLASH : ORIGIN = 0x08008000, LENGTH = 64K |
| 7 | DFU : ORIGIN = 0x08018000, LENGTH = 68K | 7 | DFU : ORIGIN = 0x08018000, LENGTH = 68K |
| 8 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K | 8 | SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128 |
| 9 | RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 32K - 128 | ||
| 9 | } | 10 | } |
| 10 | 11 | ||
| 11 | __bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); | 12 | __bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); |
| @@ -13,3 +14,11 @@ __bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - O | |||
| 13 | 14 | ||
| 14 | __bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER); | 15 | __bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER); |
| 15 | __bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER); | 16 | __bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER); |
| 17 | |||
| 18 | SECTIONS | ||
| 19 | { | ||
| 20 | .shared_data : | ||
| 21 | { | ||
| 22 | *(.shared_data) | ||
| 23 | } > SHARED_RAM | ||
| 24 | } | ||
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index 2fb16bdc4..127de0237 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | use core::mem::MaybeUninit; |
| 5 | |||
| 6 | #[cfg(feature = "defmt")] | ||
| 5 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 8 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 9 | use embassy_embedded_hal::adapter::BlockingAsync; |
| @@ -9,6 +11,7 @@ use embassy_executor::Spawner; | |||
| 9 | use embassy_stm32::exti::ExtiInput; | 11 | use embassy_stm32::exti::ExtiInput; |
| 10 | use embassy_stm32::flash::{Flash, WRITE_SIZE}; | 12 | use embassy_stm32::flash::{Flash, WRITE_SIZE}; |
| 11 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | 13 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; |
| 14 | use embassy_stm32::SharedData; | ||
| 12 | use embassy_sync::mutex::Mutex; | 15 | use embassy_sync::mutex::Mutex; |
| 13 | use panic_reset as _; | 16 | use panic_reset as _; |
| 14 | 17 | ||
| @@ -17,9 +20,12 @@ static APP_B: &[u8] = &[0, 1, 2, 3]; | |||
| 17 | #[cfg(not(feature = "skip-include"))] | 20 | #[cfg(not(feature = "skip-include"))] |
| 18 | static APP_B: &[u8] = include_bytes!("../../b.bin"); | 21 | static APP_B: &[u8] = include_bytes!("../../b.bin"); |
| 19 | 22 | ||
| 23 | #[link_section = ".shared_data"] | ||
| 24 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 25 | |||
| 20 | #[embassy_executor::main] | 26 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 27 | async fn main(_spawner: Spawner) { |
| 22 | let p = embassy_stm32::init(Default::default()); | 28 | let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); |
| 23 | let flash = Flash::new_blocking(p.FLASH); | 29 | let flash = Flash::new_blocking(p.FLASH); |
| 24 | let flash = Mutex::new(BlockingAsync::new(flash)); | 30 | let flash = Mutex::new(BlockingAsync::new(flash)); |
| 25 | 31 | ||
diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs index 8dd15d8cd..768dadf8b 100644 --- a/examples/boot/application/stm32wl/src/bin/b.rs +++ b/examples/boot/application/stm32wl/src/bin/b.rs | |||
| @@ -1,16 +1,22 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | #[cfg(feature = "defmt-rtt")] | 4 | use core::mem::MaybeUninit; |
| 5 | |||
| 6 | #[cfg(feature = "defmt")] | ||
| 5 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 9 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 10 | use embassy_stm32::SharedData; | ||
| 8 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| 9 | use panic_reset as _; | 12 | use panic_reset as _; |
| 10 | 13 | ||
| 14 | #[link_section = ".shared_data"] | ||
| 15 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 16 | |||
| 11 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 18 | async fn main(_spawner: Spawner) { |
| 13 | let p = embassy_stm32::init(Default::default()); | 19 | let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); |
| 14 | let mut led = Output::new(p.PB15, Level::High, Speed::Low); | 20 | let mut led = Output::new(p.PB15, Level::High, Speed::Low); |
| 15 | 21 | ||
| 16 | loop { | 22 | loop { |
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 3e41d1479..9d5d51a13 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml | |||
| @@ -12,20 +12,20 @@ defmt-rtt = { version = "0.4", optional = true } | |||
| 12 | embassy-nrf = { path = "../../../../embassy-nrf", features = [] } | 12 | embassy-nrf = { path = "../../../../embassy-nrf", features = [] } |
| 13 | embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } | 13 | embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } |
| 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 15 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 15 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 16 | cortex-m-rt = { version = "0.7" } | 16 | cortex-m-rt = { version = "0.7" } |
| 17 | cfg-if = "1.0.0" | 17 | cfg-if = "1.0.0" |
| 18 | 18 | ||
| 19 | [features] | 19 | [features] |
| 20 | defmt = [ | 20 | defmt = [ |
| 21 | "dep:defmt", | 21 | "dep:defmt", |
| 22 | "dep:defmt-rtt", | ||
| 22 | "embassy-boot-nrf/defmt", | 23 | "embassy-boot-nrf/defmt", |
| 23 | "embassy-nrf/defmt", | 24 | "embassy-nrf/defmt", |
| 24 | ] | 25 | ] |
| 25 | softdevice = [ | 26 | softdevice = [ |
| 26 | "embassy-boot-nrf/softdevice", | 27 | "embassy-boot-nrf/softdevice", |
| 27 | ] | 28 | ] |
| 28 | debug = ["defmt-rtt", "defmt"] | ||
| 29 | 29 | ||
| 30 | [profile.dev] | 30 | [profile.dev] |
| 31 | debug = 2 | 31 | debug = 2 |
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 3cf61a002..9df396e5e 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml | |||
| @@ -9,9 +9,9 @@ license = "MIT OR Apache-2.0" | |||
| 9 | defmt = { version = "0.3", optional = true } | 9 | defmt = { version = "0.3", optional = true } |
| 10 | defmt-rtt = { version = "0.4", optional = true } | 10 | defmt-rtt = { version = "0.4", optional = true } |
| 11 | 11 | ||
| 12 | embassy-rp = { path = "../../../../embassy-rp", features = [] } | 12 | embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] } |
| 13 | embassy-boot-rp = { path = "../../../../embassy-boot-rp" } | 13 | embassy-boot-rp = { path = "../../../../embassy-boot-rp" } |
| 14 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 14 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 15 | embassy-time = { path = "../../../../embassy-time", features = [] } | 15 | embassy-time = { path = "../../../../embassy-time", features = [] } |
| 16 | 16 | ||
| 17 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 17 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| @@ -23,10 +23,10 @@ cfg-if = "1.0.0" | |||
| 23 | [features] | 23 | [features] |
| 24 | defmt = [ | 24 | defmt = [ |
| 25 | "dep:defmt", | 25 | "dep:defmt", |
| 26 | "dep:defmt-rtt", | ||
| 26 | "embassy-boot-rp/defmt", | 27 | "embassy-boot-rp/defmt", |
| 27 | "embassy-rp/defmt", | 28 | "embassy-rp/defmt", |
| 28 | ] | 29 | ] |
| 29 | debug = ["defmt-rtt", "defmt"] | ||
| 30 | 30 | ||
| 31 | [profile.release] | 31 | [profile.release] |
| 32 | debug = true | 32 | debug = true |
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 | |||
| 2 | { | 2 | { |
| 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ | 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ |
| 4 | BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 | 4 | BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 |
| 5 | FLASH : ORIGIN = 0x10000100, LENGTH = 24K | 5 | FLASH : ORIGIN = 0x10000100, LENGTH = 24K - 0x100 |
| 6 | BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K | 6 | BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K |
| 7 | ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K | 7 | ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K |
| 8 | DFU : ORIGIN = 0x10087000, LENGTH = 516K | 8 | DFU : ORIGIN = 0x10087000, LENGTH = 516K |
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index 313187adc..b91b05412 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml | |||
| @@ -15,15 +15,14 @@ cortex-m = { version = "0.7.6", features = [ | |||
| 15 | "inline-asm", | 15 | "inline-asm", |
| 16 | "critical-section-single-core", | 16 | "critical-section-single-core", |
| 17 | ] } | 17 | ] } |
| 18 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 18 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 19 | cortex-m-rt = { version = "0.7" } | 19 | cortex-m-rt = { version = "0.7" } |
| 20 | embedded-storage = "0.3.1" | 20 | embedded-storage = "0.3.1" |
| 21 | embedded-storage-async = "0.4.0" | 21 | embedded-storage-async = "0.4.0" |
| 22 | cfg-if = "1.0.0" | 22 | cfg-if = "1.0.0" |
| 23 | 23 | ||
| 24 | [features] | 24 | [features] |
| 25 | defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] | 25 | defmt = ["dep:defmt", "dep:defmt-rtt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] |
| 26 | debug = ["defmt-rtt", "defmt"] | ||
| 27 | 26 | ||
| 28 | [profile.dev] | 27 | [profile.dev] |
| 29 | debug = 2 | 28 | debug = 2 |
diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md index 3de3171cd..cd6c0bc84 100644 --- a/examples/boot/bootloader/stm32-dual-bank/README.md +++ b/examples/boot/bootloader/stm32-dual-bank/README.md | |||
| @@ -2,16 +2,16 @@ | |||
| 2 | 2 | ||
| 3 | ## Overview | 3 | ## Overview |
| 4 | 4 | ||
| 5 | This bootloader leverages `embassy-boot` to interact with the flash. | 5 | This bootloader leverages `embassy-boot` to interact with the flash. |
| 6 | This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. | 6 | This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. |
| 7 | Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device. | 7 | Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device. |
| 8 | 8 | ||
| 9 | Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions. | 9 | Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions. |
| 10 | 10 | ||
| 11 | ## Memory Configuration | 11 | ## Memory Configuration |
| 12 | 12 | ||
| 13 | In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. | 13 | In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. |
| 14 | For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. | 14 | For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. |
| 15 | 15 | ||
| 16 | ### Symbol Definitions | 16 | ### Symbol Definitions |
| 17 | 17 | ||
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 74c01b0f4..541186949 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml | |||
| @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } | |||
| 12 | embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } | 12 | embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } |
| 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } | 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } |
| 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 15 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 15 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 16 | cortex-m-rt = { version = "0.7" } | 16 | cortex-m-rt = { version = "0.7" } |
| 17 | embedded-storage = "0.3.1" | 17 | embedded-storage = "0.3.1" |
| 18 | embedded-storage-async = "0.4.0" | 18 | embedded-storage-async = "0.4.0" |
| @@ -21,10 +21,10 @@ cfg-if = "1.0.0" | |||
| 21 | [features] | 21 | [features] |
| 22 | defmt = [ | 22 | defmt = [ |
| 23 | "dep:defmt", | 23 | "dep:defmt", |
| 24 | "dep:defmt-rtt", | ||
| 24 | "embassy-boot-stm32/defmt", | 25 | "embassy-boot-stm32/defmt", |
| 25 | "embassy-stm32/defmt", | 26 | "embassy-stm32/defmt", |
| 26 | ] | 27 | ] |
| 27 | debug = ["defmt-rtt", "defmt"] | ||
| 28 | 28 | ||
| 29 | [profile.dev] | 29 | [profile.dev] |
| 30 | debug = 2 | 30 | debug = 2 |
diff --git a/examples/boot/bootloader/stm32/memory.x b/examples/boot/bootloader/stm32/memory.x index b6f185ef7..198290520 100644 --- a/examples/boot/bootloader/stm32/memory.x +++ b/examples/boot/bootloader/stm32/memory.x | |||
| @@ -2,7 +2,7 @@ MEMORY | |||
| 2 | { | 2 | { |
| 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ | 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ |
| 4 | FLASH : ORIGIN = 0x08000000, LENGTH = 24K | 4 | FLASH : ORIGIN = 0x08000000, LENGTH = 24K |
| 5 | BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K | 5 | BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 8K |
| 6 | ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K | 6 | ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K |
| 7 | DFU : ORIGIN = 0x08010000, LENGTH = 36K | 7 | DFU : ORIGIN = 0x08010000, LENGTH = 36K |
| 8 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K | 8 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K |
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 854f94d85..050b672ce 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml | |||
| @@ -12,24 +12,24 @@ defmt-rtt = { version = "0.4", optional = true } | |||
| 12 | embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } | 12 | embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } |
| 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } | 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } |
| 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 15 | embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } | 15 | embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } |
| 16 | cortex-m-rt = { version = "0.7" } | 16 | cortex-m-rt = { version = "0.7" } |
| 17 | embedded-storage = "0.3.1" | 17 | embedded-storage = "0.3.1" |
| 18 | embedded-storage-async = "0.4.0" | 18 | embedded-storage-async = "0.4.0" |
| 19 | cfg-if = "1.0.0" | 19 | cfg-if = "1.0.0" |
| 20 | embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } | 20 | embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } |
| 21 | embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false } | 21 | embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb", default-features = false } |
| 22 | embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } | 22 | embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } |
| 23 | 23 | ||
| 24 | [features] | 24 | [features] |
| 25 | defmt = [ | 25 | defmt = [ |
| 26 | "dep:defmt", | 26 | "dep:defmt", |
| 27 | "dep:defmt-rtt", | ||
| 27 | "embassy-boot-stm32/defmt", | 28 | "embassy-boot-stm32/defmt", |
| 28 | "embassy-stm32/defmt", | 29 | "embassy-stm32/defmt", |
| 29 | "embassy-usb/defmt", | 30 | "embassy-usb/defmt", |
| 30 | "embassy-usb-dfu/defmt" | 31 | "embassy-usb-dfu/defmt" |
| 31 | ] | 32 | ] |
| 32 | debug = ["defmt-rtt", "defmt"] | ||
| 33 | 33 | ||
| 34 | [profile.dev] | 34 | [profile.dev] |
| 35 | debug = 2 | 35 | debug = 2 |
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index d989fbfdf..093b39f9d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs | |||
| @@ -49,7 +49,6 @@ fn main() -> ! { | |||
| 49 | let mut buffer = AlignedBuffer([0; WRITE_SIZE]); | 49 | let mut buffer = AlignedBuffer([0; WRITE_SIZE]); |
| 50 | let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); | 50 | let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]); |
| 51 | 51 | ||
| 52 | let mut device_descriptor = [0; 256]; | ||
| 53 | let mut config_descriptor = [0; 256]; | 52 | let mut config_descriptor = [0; 256]; |
| 54 | let mut bos_descriptor = [0; 256]; | 53 | let mut bos_descriptor = [0; 256]; |
| 55 | let mut control_buf = [0; 4096]; | 54 | let mut control_buf = [0; 4096]; |
| @@ -57,7 +56,6 @@ fn main() -> ! { | |||
| 57 | let mut builder = Builder::new( | 56 | let mut builder = Builder::new( |
| 58 | driver, | 57 | driver, |
| 59 | config, | 58 | config, |
| 60 | &mut device_descriptor, | ||
| 61 | &mut config_descriptor, | 59 | &mut config_descriptor, |
| 62 | &mut bos_descriptor, | 60 | &mut bos_descriptor, |
| 63 | &mut [], | 61 | &mut [], |
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 17210994b..98a678815 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml | |||
| @@ -15,15 +15,14 @@ log = [ | |||
| 15 | ] | 15 | ] |
| 16 | 16 | ||
| 17 | [dependencies] | 17 | [dependencies] |
| 18 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } | 18 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } |
| 19 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } | 19 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } |
| 20 | embassy-time = { version = "0.3.0", path = "../../embassy-time" } | 20 | embassy-time = { version = "0.3.2", path = "../../embassy-time" } |
| 21 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 21 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 22 | 22 | ||
| 23 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 23 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 24 | cortex-m-rt = "0.7.0" | 24 | cortex-m-rt = "0.7.0" |
| 25 | panic-probe = { version = "0.3" } | 25 | panic-probe = { version = "0.3" } |
| 26 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 27 | rand = { version = "0.8.4", default-features = false } | 26 | rand = { version = "0.8.4", default-features = false } |
| 28 | serde = { version = "1.0.136", default-features = false } | 27 | serde = { version = "1.0.136", default-features = false } |
| 29 | rtos-trace = "0.1.3" | 28 | rtos-trace = "0.1.3" |
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 06c3d20cb..93a19bea7 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml | |||
| @@ -5,9 +5,9 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 9 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } | 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } |
| 11 | 11 | ||
| 12 | defmt = "0.3" | 12 | defmt = "0.3" |
| 13 | defmt-rtt = "0.4" | 13 | defmt-rtt = "0.4" |
diff --git a/examples/nrf52810/.cargo/config.toml b/examples/nrf52810/.cargo/config.toml new file mode 100644 index 000000000..917a5364a --- /dev/null +++ b/examples/nrf52810/.cargo/config.toml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace nRF82810_xxAA with your chip as listed in `probe-rs chip list` | ||
| 3 | runner = "probe-rs run --chip nRF52810_xxAA" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv7em-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "trace" | ||
diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml new file mode 100644 index 000000000..0e3e81c3f --- /dev/null +++ b/examples/nrf52810/Cargo.toml | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-nrf52810-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 9 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 10 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | ||
| 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | ||
| 13 | |||
| 14 | defmt = "0.3" | ||
| 15 | defmt-rtt = "0.4" | ||
| 16 | |||
| 17 | fixed = "1.10.0" | ||
| 18 | static_cell = { version = "2" } | ||
| 19 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 20 | cortex-m-rt = "0.7.0" | ||
| 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 22 | |||
| 23 | [profile.release] | ||
| 24 | debug = 2 | ||
diff --git a/examples/nrf52810/build.rs b/examples/nrf52810/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf52810/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/nrf52810/memory.x b/examples/nrf52810/memory.x new file mode 100644 index 000000000..7cf560e44 --- /dev/null +++ b/examples/nrf52810/memory.x | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ | ||
| 4 | FLASH : ORIGIN = 0x00000000, LENGTH = 256K | ||
| 5 | RAM : ORIGIN = 0x20000000, LENGTH = 24K | ||
| 6 | |||
| 7 | } | ||
diff --git a/examples/nrf52810/src/bin/blinky.rs b/examples/nrf52810/src/bin/blinky.rs new file mode 100644 index 000000000..1da039f7d --- /dev/null +++ b/examples/nrf52810/src/bin/blinky.rs | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 6 | use embassy_time::Timer; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = embassy_nrf::init(Default::default()); | ||
| 12 | let mut led = Output::new(p.P0_18, Level::Low, OutputDrive::Standard); | ||
| 13 | |||
| 14 | loop { | ||
| 15 | led.set_high(); | ||
| 16 | Timer::after_millis(300).await; | ||
| 17 | led.set_low(); | ||
| 18 | Timer::after_millis(300).await; | ||
| 19 | } | ||
| 20 | } | ||
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index d91f58d0e..7fae7aefc 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml | |||
| @@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0" | |||
| 8 | rtic = { version = "2", features = ["thumbv7-backend"] } | 8 | rtic = { version = "2", features = ["thumbv7-backend"] } |
| 9 | 9 | ||
| 10 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 10 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 11 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } |
| 13 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 13 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.4" | 16 | defmt-rtt = "0.4" |
| @@ -18,7 +18,6 @@ defmt-rtt = "0.4" | |||
| 18 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 21 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 22 | 21 | ||
| 23 | [profile.release] | 22 | [profile.release] |
| 24 | debug = 2 | 23 | debug = 2 |
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index abb995be6..17fa6234d 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml | |||
| @@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 9 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 11 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } | 15 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } |
| 16 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | 16 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } |
| 17 | embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } | 17 | embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } |
| @@ -25,10 +25,9 @@ static_cell = { version = "2" } | |||
| 25 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 25 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 26 | cortex-m-rt = "0.7.0" | 26 | cortex-m-rt = "0.7.0" |
| 27 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 27 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 28 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 29 | rand = { version = "0.8.4", default-features = false } | 28 | rand = { version = "0.8.4", default-features = false } |
| 30 | embedded-storage = "0.3.1" | 29 | embedded-storage = "0.3.1" |
| 31 | usbd-hid = "0.6.0" | 30 | usbd-hid = "0.8.1" |
| 32 | serde = { version = "1.0.136", default-features = false } | 31 | serde = { version = "1.0.136", default-features = false } |
| 33 | embedded-hal = { version = "1.0" } | 32 | embedded-hal = { version = "1.0" } |
| 34 | embedded-hal-async = { version = "1.0" } | 33 | embedded-hal-async = { version = "1.0" } |
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) { | |||
| 35 | 35 | ||
| 36 | loop { | 36 | loop { |
| 37 | match CHANNEL.receive().await { | 37 | match CHANNEL.receive().await { |
| 38 | LedState::On => led.set_high(), | 38 | LedState::On => led.set_low(), |
| 39 | LedState::Off => led.set_low(), | 39 | LedState::Off => led.set_high(), |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
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 | |||
| 33 | 33 | ||
| 34 | loop { | 34 | loop { |
| 35 | match receiver.receive().await { | 35 | match receiver.receive().await { |
| 36 | LedState::On => led.set_high(), | 36 | LedState::On => led.set_low(), |
| 37 | LedState::Off => led.set_low(), | 37 | LedState::Off => led.set_high(), |
| 38 | } | 38 | } |
| 39 | } | 39 | } |
| 40 | } | 40 | } |
diff --git a/examples/nrf52840/src/bin/egu.rs b/examples/nrf52840/src/bin/egu.rs new file mode 100644 index 000000000..8bf712697 --- /dev/null +++ b/examples/nrf52840/src/bin/egu.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | //! This example shows the use of the EGU peripheral combined with PPI. | ||
| 2 | //! | ||
| 3 | //! It chains events from button -> egu0-trigger0 -> egu0-trigger1 -> led | ||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_nrf::egu::{Egu, TriggerNumber}; | ||
| 9 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | ||
| 10 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity, OutputChannel, OutputChannelPolarity}; | ||
| 11 | use embassy_nrf::peripherals::{PPI_CH0, PPI_CH1, PPI_CH2}; | ||
| 12 | use embassy_nrf::ppi::Ppi; | ||
| 13 | use embassy_time::{Duration, Timer}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let p = embassy_nrf::init(Default::default()); | ||
| 19 | |||
| 20 | let led1 = Output::new(p.P0_13, Level::High, OutputDrive::Standard); | ||
| 21 | let btn1 = Input::new(p.P0_11, Pull::Up); | ||
| 22 | |||
| 23 | let mut egu1 = Egu::new(p.EGU0); | ||
| 24 | let led1 = OutputChannel::new(p.GPIOTE_CH0, led1, OutputChannelPolarity::Toggle); | ||
| 25 | let btn1 = InputChannel::new(p.GPIOTE_CH1, btn1, InputChannelPolarity::LoToHi); | ||
| 26 | |||
| 27 | let trigger0 = egu1.trigger(TriggerNumber::Trigger0); | ||
| 28 | let trigger1 = egu1.trigger(TriggerNumber::Trigger1); | ||
| 29 | |||
| 30 | let mut ppi1: Ppi<PPI_CH0, 1, 1> = Ppi::new_one_to_one(p.PPI_CH0, btn1.event_in(), trigger0.task()); | ||
| 31 | ppi1.enable(); | ||
| 32 | |||
| 33 | let mut ppi2: Ppi<PPI_CH1, 1, 1> = Ppi::new_one_to_one(p.PPI_CH1, trigger0.event(), trigger1.task()); | ||
| 34 | ppi2.enable(); | ||
| 35 | |||
| 36 | let mut ppi3: Ppi<PPI_CH2, 1, 1> = Ppi::new_one_to_one(p.PPI_CH2, trigger1.event(), led1.task_out()); | ||
| 37 | ppi3.enable(); | ||
| 38 | |||
| 39 | defmt::info!("Push the button to toggle the LED"); | ||
| 40 | loop { | ||
| 41 | Timer::after(Duration::from_secs(60)).await; | ||
| 42 | } | ||
| 43 | } | ||
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index 279f32edc..0946492fe 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_net_enc28j60::Enc28j60; | 8 | use embassy_net_enc28j60::Enc28j60; |
| 9 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | 9 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; |
| 10 | use embassy_nrf::rng::Rng; | 10 | use embassy_nrf::rng::Rng; |
| @@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs { | |||
| 23 | 23 | ||
| 24 | #[embassy_executor::task] | 24 | #[embassy_executor::task] |
| 25 | async fn net_task( | 25 | async fn net_task( |
| 26 | stack: &'static Stack< | 26 | mut runner: embassy_net::Runner< |
| 27 | 'static, | ||
| 27 | Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>, | 28 | Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>, |
| 28 | >, | 29 | >, |
| 29 | ) -> ! { | 30 | ) -> ! { |
| 30 | stack.run().await | 31 | runner.run().await |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | #[embassy_executor::main] | 34 | #[embassy_executor::main] |
| @@ -66,18 +67,10 @@ async fn main(spawner: Spawner) { | |||
| 66 | let seed = u64::from_le_bytes(seed); | 67 | let seed = u64::from_le_bytes(seed); |
| 67 | 68 | ||
| 68 | // Init network stack | 69 | // Init network stack |
| 69 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 70 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 70 | static STACK: StaticCell< | 71 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 71 | Stack<Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>>, | 72 | |
| 72 | > = StaticCell::new(); | 73 | unwrap!(spawner.spawn(net_task(runner))); |
| 73 | let stack = STACK.init(Stack::new( | ||
| 74 | device, | ||
| 75 | config, | ||
| 76 | RESOURCES.init(StackResources::<2>::new()), | ||
| 77 | seed, | ||
| 78 | )); | ||
| 79 | |||
| 80 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 81 | 74 | ||
| 82 | // And now we can use it! | 75 | // And now we can use it! |
| 83 | 76 | ||
diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs index e254d613d..dcfe7723a 100644 --- a/examples/nrf52840/src/bin/gpiote_channel.rs +++ b/examples/nrf52840/src/bin/gpiote_channel.rs | |||
| @@ -61,5 +61,5 @@ async fn main(_spawner: Spawner) { | |||
| 61 | } | 61 | } |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | futures::join!(button1, button2, button3, button4); | 64 | embassy_futures::join::join4(button1, button2, button3, button4).await; |
| 65 | } | 65 | } |
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs index b634d8569..797be93a7 100644 --- a/examples/nrf52840/src/bin/multiprio.rs +++ b/examples/nrf52840/src/bin/multiprio.rs | |||
| @@ -80,7 +80,7 @@ async fn run_med() { | |||
| 80 | info!(" [med] Starting long computation"); | 80 | info!(" [med] Starting long computation"); |
| 81 | 81 | ||
| 82 | // Spin-wait to simulate a long CPU computation | 82 | // Spin-wait to simulate a long CPU computation |
| 83 | cortex_m::asm::delay(32_000_000); // ~1 second | 83 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second |
| 84 | 84 | ||
| 85 | let end = Instant::now(); | 85 | let end = Instant::now(); |
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | 86 | let ms = end.duration_since(start).as_ticks() / 33; |
| @@ -97,7 +97,7 @@ async fn run_low() { | |||
| 97 | info!("[low] Starting long computation"); | 97 | info!("[low] Starting long computation"); |
| 98 | 98 | ||
| 99 | // Spin-wait to simulate a long CPU computation | 99 | // Spin-wait to simulate a long CPU computation |
| 100 | cortex_m::asm::delay(64_000_000); // ~2 seconds | 100 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds |
| 101 | 101 | ||
| 102 | let end = Instant::now(); | 102 | let end = Instant::now(); |
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | 103 | let ms = end.duration_since(start).as_ticks() / 33; |
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 3469c6e5f..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; | |||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_net::tcp::TcpSocket; | 8 | use embassy_net::tcp::TcpSocket; |
| 9 | use embassy_net::{Stack, StackResources}; | 9 | use embassy_net::StackResources; |
| 10 | use embassy_nrf::rng::Rng; | 10 | use embassy_nrf::rng::Rng; |
| 11 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | 11 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 12 | use embassy_nrf::usb::Driver; | 12 | use embassy_nrf::usb::Driver; |
| @@ -39,8 +39,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | #[embassy_executor::task] | 41 | #[embassy_executor::task] |
| 42 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 42 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { |
| 43 | stack.run().await | 43 | runner.run().await |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | #[embassy_executor::main] | 46 | #[embassy_executor::main] |
| @@ -70,7 +70,6 @@ async fn main(spawner: Spawner) { | |||
| 70 | config.device_protocol = 0x01; | 70 | config.device_protocol = 0x01; |
| 71 | 71 | ||
| 72 | // Create embassy-usb DeviceBuilder using the driver and config. | 72 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 73 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 74 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 73 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 75 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 74 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 76 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); | 75 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); |
| @@ -78,7 +77,6 @@ async fn main(spawner: Spawner) { | |||
| 78 | let mut builder = Builder::new( | 77 | let mut builder = Builder::new( |
| 79 | driver, | 78 | driver, |
| 80 | config, | 79 | config, |
| 81 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 82 | &mut CONFIG_DESC.init([0; 256])[..], | 80 | &mut CONFIG_DESC.init([0; 256])[..], |
| 83 | &mut BOS_DESC.init([0; 256])[..], | 81 | &mut BOS_DESC.init([0; 256])[..], |
| 84 | &mut MSOS_DESC.init([0; 128])[..], | 82 | &mut MSOS_DESC.init([0; 128])[..], |
| @@ -117,11 +115,10 @@ async fn main(spawner: Spawner) { | |||
| 117 | let seed = u64::from_le_bytes(seed); | 115 | let seed = u64::from_le_bytes(seed); |
| 118 | 116 | ||
| 119 | // Init network stack | 117 | // Init network stack |
| 120 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 118 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 121 | static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); | 119 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 122 | let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); | ||
| 123 | 120 | ||
| 124 | unwrap!(spawner.spawn(net_task(stack))); | 121 | unwrap!(spawner.spawn(net_task(runner))); |
| 125 | 122 | ||
| 126 | // And now we can use it! | 123 | // And now we can use it! |
| 127 | 124 | ||
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 3e86590c4..e33ee5866 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs | |||
| @@ -50,12 +50,11 @@ async fn main(_spawner: Spawner) { | |||
| 50 | 50 | ||
| 51 | // Create embassy-usb DeviceBuilder using the driver and config. | 51 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 52 | // It needs some buffers for building the descriptors. | 52 | // It needs some buffers for building the descriptors. |
| 53 | let mut device_descriptor = [0; 256]; | ||
| 54 | let mut config_descriptor = [0; 256]; | 53 | let mut config_descriptor = [0; 256]; |
| 55 | let mut bos_descriptor = [0; 256]; | 54 | let mut bos_descriptor = [0; 256]; |
| 56 | let mut msos_descriptor = [0; 256]; | 55 | let mut msos_descriptor = [0; 256]; |
| 57 | let mut control_buf = [0; 64]; | 56 | let mut control_buf = [0; 64]; |
| 58 | let request_handler = MyRequestHandler {}; | 57 | let mut request_handler = MyRequestHandler {}; |
| 59 | let mut device_handler = MyDeviceHandler::new(); | 58 | let mut device_handler = MyDeviceHandler::new(); |
| 60 | 59 | ||
| 61 | let mut state = State::new(); | 60 | let mut state = State::new(); |
| @@ -63,7 +62,6 @@ async fn main(_spawner: Spawner) { | |||
| 63 | let mut builder = Builder::new( | 62 | let mut builder = Builder::new( |
| 64 | driver, | 63 | driver, |
| 65 | config, | 64 | config, |
| 66 | &mut device_descriptor, | ||
| 67 | &mut config_descriptor, | 65 | &mut config_descriptor, |
| 68 | &mut bos_descriptor, | 66 | &mut bos_descriptor, |
| 69 | &mut msos_descriptor, | 67 | &mut msos_descriptor, |
| @@ -75,7 +73,7 @@ async fn main(_spawner: Spawner) { | |||
| 75 | // Create classes on the builder. | 73 | // Create classes on the builder. |
| 76 | let config = embassy_usb::class::hid::Config { | 74 | let config = embassy_usb::class::hid::Config { |
| 77 | report_descriptor: KeyboardReport::desc(), | 75 | report_descriptor: KeyboardReport::desc(), |
| 78 | request_handler: Some(&request_handler), | 76 | request_handler: None, |
| 79 | poll_ms: 60, | 77 | poll_ms: 60, |
| 80 | max_packet_size: 64, | 78 | max_packet_size: 64, |
| 81 | }; | 79 | }; |
| @@ -139,7 +137,7 @@ async fn main(_spawner: Spawner) { | |||
| 139 | }; | 137 | }; |
| 140 | 138 | ||
| 141 | let out_fut = async { | 139 | let out_fut = async { |
| 142 | reader.run(false, &request_handler).await; | 140 | reader.run(false, &mut request_handler).await; |
| 143 | }; | 141 | }; |
| 144 | 142 | ||
| 145 | // Run everything concurrently. | 143 | // Run everything concurrently. |
| @@ -150,21 +148,21 @@ async fn main(_spawner: Spawner) { | |||
| 150 | struct MyRequestHandler {} | 148 | struct MyRequestHandler {} |
| 151 | 149 | ||
| 152 | impl RequestHandler for MyRequestHandler { | 150 | impl RequestHandler for MyRequestHandler { |
| 153 | fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | 151 | fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { |
| 154 | info!("Get report for {:?}", id); | 152 | info!("Get report for {:?}", id); |
| 155 | None | 153 | None |
| 156 | } | 154 | } |
| 157 | 155 | ||
| 158 | fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { | 156 | fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { |
| 159 | info!("Set report for {:?}: {=[u8]}", id, data); | 157 | info!("Set report for {:?}: {=[u8]}", id, data); |
| 160 | OutResponse::Accepted | 158 | OutResponse::Accepted |
| 161 | } | 159 | } |
| 162 | 160 | ||
| 163 | fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { | 161 | fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { |
| 164 | info!("Set idle rate for {:?} to {:?}", id, dur); | 162 | info!("Set idle rate for {:?} to {:?}", id, dur); |
| 165 | } | 163 | } |
| 166 | 164 | ||
| 167 | fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { | 165 | fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> { |
| 168 | info!("Get idle rate for {:?}", id); | 166 | info!("Get idle rate for {:?}", id); |
| 169 | None | 167 | None |
| 170 | } | 168 | } |
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 04ad841b7..8076ac283 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs | |||
| @@ -43,19 +43,17 @@ async fn main(_spawner: Spawner) { | |||
| 43 | 43 | ||
| 44 | // Create embassy-usb DeviceBuilder using the driver and config. | 44 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 45 | // It needs some buffers for building the descriptors. | 45 | // It needs some buffers for building the descriptors. |
| 46 | let mut device_descriptor = [0; 256]; | ||
| 47 | let mut config_descriptor = [0; 256]; | 46 | let mut config_descriptor = [0; 256]; |
| 48 | let mut bos_descriptor = [0; 256]; | 47 | let mut bos_descriptor = [0; 256]; |
| 49 | let mut msos_descriptor = [0; 256]; | 48 | let mut msos_descriptor = [0; 256]; |
| 50 | let mut control_buf = [0; 64]; | 49 | let mut control_buf = [0; 64]; |
| 51 | let request_handler = MyRequestHandler {}; | 50 | let mut request_handler = MyRequestHandler {}; |
| 52 | 51 | ||
| 53 | let mut state = State::new(); | 52 | let mut state = State::new(); |
| 54 | 53 | ||
| 55 | let mut builder = Builder::new( | 54 | let mut builder = Builder::new( |
| 56 | driver, | 55 | driver, |
| 57 | config, | 56 | config, |
| 58 | &mut device_descriptor, | ||
| 59 | &mut config_descriptor, | 57 | &mut config_descriptor, |
| 60 | &mut bos_descriptor, | 58 | &mut bos_descriptor, |
| 61 | &mut msos_descriptor, | 59 | &mut msos_descriptor, |
| @@ -65,7 +63,7 @@ async fn main(_spawner: Spawner) { | |||
| 65 | // Create classes on the builder. | 63 | // Create classes on the builder. |
| 66 | let config = embassy_usb::class::hid::Config { | 64 | let config = embassy_usb::class::hid::Config { |
| 67 | report_descriptor: MouseReport::desc(), | 65 | report_descriptor: MouseReport::desc(), |
| 68 | request_handler: Some(&request_handler), | 66 | request_handler: Some(&mut request_handler), |
| 69 | poll_ms: 60, | 67 | poll_ms: 60, |
| 70 | max_packet_size: 8, | 68 | max_packet_size: 8, |
| 71 | }; | 69 | }; |
| @@ -107,21 +105,21 @@ async fn main(_spawner: Spawner) { | |||
| 107 | struct MyRequestHandler {} | 105 | struct MyRequestHandler {} |
| 108 | 106 | ||
| 109 | impl RequestHandler for MyRequestHandler { | 107 | impl RequestHandler for MyRequestHandler { |
| 110 | fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | 108 | fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { |
| 111 | info!("Get report for {:?}", id); | 109 | info!("Get report for {:?}", id); |
| 112 | None | 110 | None |
| 113 | } | 111 | } |
| 114 | 112 | ||
| 115 | fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { | 113 | fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { |
| 116 | info!("Set report for {:?}: {=[u8]}", id, data); | 114 | info!("Set report for {:?}: {=[u8]}", id, data); |
| 117 | OutResponse::Accepted | 115 | OutResponse::Accepted |
| 118 | } | 116 | } |
| 119 | 117 | ||
| 120 | fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { | 118 | fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { |
| 121 | info!("Set idle rate for {:?} to {:?}", id, dur); | 119 | info!("Set idle rate for {:?} to {:?}", id, dur); |
| 122 | } | 120 | } |
| 123 | 121 | ||
| 124 | fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { | 122 | fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> { |
| 125 | info!("Get idle rate for {:?}", id); | 123 | info!("Get idle rate for {:?}", id); |
| 126 | None | 124 | None |
| 127 | } | 125 | } |
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index aff539b1b..02048e692 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs | |||
| @@ -48,7 +48,6 @@ async fn main(_spawner: Spawner) { | |||
| 48 | 48 | ||
| 49 | // Create embassy-usb DeviceBuilder using the driver and config. | 49 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 50 | // It needs some buffers for building the descriptors. | 50 | // It needs some buffers for building the descriptors. |
| 51 | let mut device_descriptor = [0; 256]; | ||
| 52 | let mut config_descriptor = [0; 256]; | 51 | let mut config_descriptor = [0; 256]; |
| 53 | let mut bos_descriptor = [0; 256]; | 52 | let mut bos_descriptor = [0; 256]; |
| 54 | let mut msos_descriptor = [0; 256]; | 53 | let mut msos_descriptor = [0; 256]; |
| @@ -59,7 +58,6 @@ async fn main(_spawner: Spawner) { | |||
| 59 | let mut builder = Builder::new( | 58 | let mut builder = Builder::new( |
| 60 | driver, | 59 | driver, |
| 61 | config, | 60 | config, |
| 62 | &mut device_descriptor, | ||
| 63 | &mut config_descriptor, | 61 | &mut config_descriptor, |
| 64 | &mut bos_descriptor, | 62 | &mut bos_descriptor, |
| 65 | &mut msos_descriptor, | 63 | &mut msos_descriptor, |
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 4e8118fb8..895cca8b9 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs | |||
| @@ -67,7 +67,6 @@ async fn main(spawner: Spawner) { | |||
| 67 | let state = STATE.init(State::new()); | 67 | let state = STATE.init(State::new()); |
| 68 | 68 | ||
| 69 | // Create embassy-usb DeviceBuilder using the driver and config. | 69 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 70 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 71 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 70 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 72 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 71 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 73 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); | 72 | static MSOS_DESC: StaticCell<[u8; 128]> = StaticCell::new(); |
| @@ -75,7 +74,6 @@ async fn main(spawner: Spawner) { | |||
| 75 | let mut builder = Builder::new( | 74 | let mut builder = Builder::new( |
| 76 | driver, | 75 | driver, |
| 77 | config, | 76 | config, |
| 78 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 79 | &mut CONFIG_DESC.init([0; 256])[..], | 77 | &mut CONFIG_DESC.init([0; 256])[..], |
| 80 | &mut BOS_DESC.init([0; 256])[..], | 78 | &mut BOS_DESC.init([0; 256])[..], |
| 81 | &mut MSOS_DESC.init([0; 128])[..], | 79 | &mut MSOS_DESC.init([0; 128])[..], |
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 060f9ba94..c6675a3d3 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs | |||
| @@ -53,7 +53,6 @@ async fn main(_spawner: Spawner) { | |||
| 53 | 53 | ||
| 54 | // Create embassy-usb DeviceBuilder using the driver and config. | 54 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 55 | // It needs some buffers for building the descriptors. | 55 | // It needs some buffers for building the descriptors. |
| 56 | let mut device_descriptor = [0; 256]; | ||
| 57 | let mut config_descriptor = [0; 256]; | 56 | let mut config_descriptor = [0; 256]; |
| 58 | let mut bos_descriptor = [0; 256]; | 57 | let mut bos_descriptor = [0; 256]; |
| 59 | let mut msos_descriptor = [0; 256]; | 58 | let mut msos_descriptor = [0; 256]; |
| @@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | let mut builder = Builder::new( | 63 | let mut builder = Builder::new( |
| 65 | driver, | 64 | driver, |
| 66 | config, | 65 | config, |
| 67 | &mut device_descriptor, | ||
| 68 | &mut config_descriptor, | 66 | &mut config_descriptor, |
| 69 | &mut bos_descriptor, | 67 | &mut bos_descriptor, |
| 70 | &mut msos_descriptor, | 68 | &mut msos_descriptor, |
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index 00bd50081..26eaf485e 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::{info, unwrap, warn}; | 4 | use defmt::{info, unwrap, warn}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | 8 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; |
| 9 | use embassy_nrf::rng::Rng; | 9 | use embassy_nrf::rng::Rng; |
| 10 | use embassy_nrf::spim::{self, Spim}; | 10 | use embassy_nrf::spim::{self, Spim}; |
| @@ -36,8 +36,8 @@ async fn wifi_task( | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | #[embassy_executor::task] | 38 | #[embassy_executor::task] |
| 39 | async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! { | 39 | async fn net_task(mut runner: embassy_net::Runner<'static, hosted::NetDriver<'static>>) -> ! { |
| 40 | stack.run().await | 40 | runner.run().await |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | #[embassy_executor::main] | 43 | #[embassy_executor::main] |
| @@ -89,16 +89,10 @@ async fn main(spawner: Spawner) { | |||
| 89 | let seed = u64::from_le_bytes(seed); | 89 | let seed = u64::from_le_bytes(seed); |
| 90 | 90 | ||
| 91 | // Init network stack | 91 | // Init network stack |
| 92 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 92 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 93 | static STACK: StaticCell<Stack<hosted::NetDriver<'static>>> = StaticCell::new(); | 93 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 94 | let stack = &*STACK.init(Stack::new( | 94 | |
| 95 | device, | 95 | unwrap!(spawner.spawn(net_task(runner))); |
| 96 | config, | ||
| 97 | RESOURCES.init(StackResources::<2>::new()), | ||
| 98 | seed, | ||
| 99 | )); | ||
| 100 | |||
| 101 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 102 | 96 | ||
| 103 | // And now we can use it! | 97 | // And now we can use it! |
| 104 | 98 | ||
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 56b9c8018..0da85be07 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml | |||
| @@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 9 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 11 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embedded-io-async = { version = "0.6.1" } | 15 | embedded-io-async = { version = "0.6.1" } |
| 16 | 16 | ||
| 17 | defmt = "0.3" | 17 | defmt = "0.3" |
| @@ -21,10 +21,9 @@ static_cell = "2" | |||
| 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 22 | cortex-m-rt = "0.7.0" | 22 | cortex-m-rt = "0.7.0" |
| 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 24 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 25 | rand = { version = "0.8.4", default-features = false } | 24 | rand = { version = "0.8.4", default-features = false } |
| 26 | embedded-storage = "0.3.1" | 25 | embedded-storage = "0.3.1" |
| 27 | usbd-hid = "0.6.0" | 26 | usbd-hid = "0.8.1" |
| 28 | serde = { version = "1.0.136", default-features = false } | 27 | serde = { version = "1.0.136", default-features = false } |
| 29 | 28 | ||
| 30 | [profile.release] | 29 | [profile.release] |
diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs index c0a55142f..23f6fca98 100644 --- a/examples/nrf5340/src/bin/gpiote_channel.rs +++ b/examples/nrf5340/src/bin/gpiote_channel.rs | |||
| @@ -61,5 +61,5 @@ async fn main(_spawner: Spawner) { | |||
| 61 | } | 61 | } |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | futures::join!(button1, button2, button3, button4); | 64 | embassy_futures::join::join4(button1, button2, button3, button4).await; |
| 65 | } | 65 | } |
diff --git a/examples/nrf9151/ns/.cargo/config.toml b/examples/nrf9151/ns/.cargo/config.toml new file mode 100644 index 000000000..1444b0cd1 --- /dev/null +++ b/examples/nrf9151/ns/.cargo/config.toml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` | ||
| 3 | runner = "probe-rs run --chip nRF9160_xxAA" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv8m.main-none-eabihf" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "trace" | ||
diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml new file mode 100644 index 000000000..17fe27b67 --- /dev/null +++ b/examples/nrf9151/ns/Cargo.toml | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-nrf9151-non-secure-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 9 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | ||
| 10 | embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | ||
| 11 | |||
| 12 | defmt = "0.3" | ||
| 13 | defmt-rtt = "0.4" | ||
| 14 | |||
| 15 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 16 | cortex-m-rt = "0.7.0" | ||
| 17 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 18 | |||
| 19 | [profile.release] | ||
| 20 | debug = 2 | ||
diff --git a/examples/nrf9151/ns/README.md b/examples/nrf9151/ns/README.md new file mode 100644 index 000000000..a3f81d24e --- /dev/null +++ b/examples/nrf9151/ns/README.md | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | You must flash the TFM before running any non-secure examples. The TFM | ||
| 2 | configures the secure and non-secure execution environments and then loads the | ||
| 3 | non-secure application. A reference TFM is included, and you can use the | ||
| 4 | provided helper script to flash it. | ||
diff --git a/examples/nrf9151/ns/build.rs b/examples/nrf9151/ns/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf9151/ns/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/nrf9151/ns/flash_tfm.sh b/examples/nrf9151/ns/flash_tfm.sh new file mode 100644 index 000000000..29e4e0ed5 --- /dev/null +++ b/examples/nrf9151/ns/flash_tfm.sh | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | nrfjprog --family NRF91 --recover | ||
| 2 | nrfjprog --family NRF91 --chiperase --verify --program tfm.hex | ||
diff --git a/examples/nrf9151/ns/memory.x b/examples/nrf9151/ns/memory.x new file mode 100644 index 000000000..8d7b66fcc --- /dev/null +++ b/examples/nrf9151/ns/memory.x | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | /* Trusted Firmware-M (TF-M) is flashed at the start */ | ||
| 4 | FLASH : ORIGIN = 0x00008000, LENGTH = 0xf8000 | ||
| 5 | RAM (rwx) : ORIGIN = 0x2000C568, LENGTH = 0x33a98 | ||
| 6 | } | ||
| 7 | |||
diff --git a/examples/nrf9151/ns/src/bin/blinky.rs b/examples/nrf9151/ns/src/bin/blinky.rs new file mode 100644 index 000000000..7457a95a3 --- /dev/null +++ b/examples/nrf9151/ns/src/bin/blinky.rs | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 6 | use embassy_time::Timer; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = embassy_nrf::init(Default::default()); | ||
| 12 | let mut led = Output::new(p.P0_00, Level::Low, OutputDrive::Standard); | ||
| 13 | |||
| 14 | loop { | ||
| 15 | led.set_high(); | ||
| 16 | defmt::info!("high"); | ||
| 17 | Timer::after_millis(500).await; | ||
| 18 | led.set_low(); | ||
| 19 | defmt::info!("low"); | ||
| 20 | Timer::after_millis(1000).await; | ||
| 21 | } | ||
| 22 | } | ||
diff --git a/examples/nrf9151/ns/src/bin/uart.rs b/examples/nrf9151/ns/src/bin/uart.rs new file mode 100644 index 000000000..2220dccfb --- /dev/null +++ b/examples/nrf9151/ns/src/bin/uart.rs | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::{bind_interrupts, peripherals, uarte}; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | bind_interrupts!(struct Irqs { | ||
| 10 | SPIM0_SPIS0_TWIM0_TWIS0_UARTE0 => uarte::InterruptHandler<peripherals::SERIAL0>; | ||
| 11 | }); | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let p = embassy_nrf::init(Default::default()); | ||
| 16 | let mut config = uarte::Config::default(); | ||
| 17 | config.parity = uarte::Parity::EXCLUDED; | ||
| 18 | config.baudrate = uarte::Baudrate::BAUD115200; | ||
| 19 | |||
| 20 | let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P0_26, p.P0_27, config); | ||
| 21 | |||
| 22 | info!("uarte initialized!"); | ||
| 23 | |||
| 24 | // Message must be in SRAM | ||
| 25 | let mut buf = [0; 8]; | ||
| 26 | buf.copy_from_slice(b"Hello!\r\n"); | ||
| 27 | |||
| 28 | unwrap!(uart.write(&buf).await); | ||
| 29 | info!("wrote hello in uart!"); | ||
| 30 | |||
| 31 | loop { | ||
| 32 | info!("reading..."); | ||
| 33 | unwrap!(uart.read(&mut buf).await); | ||
| 34 | info!("writing..."); | ||
| 35 | unwrap!(uart.write(&buf).await); | ||
| 36 | } | ||
| 37 | } | ||
diff --git a/examples/nrf9151/ns/tfm.hex b/examples/nrf9151/ns/tfm.hex new file mode 100644 index 000000000..9864a1849 --- /dev/null +++ b/examples/nrf9151/ns/tfm.hex | |||
| @@ -0,0 +1,1543 @@ | |||
| 1 | :10000000F80B0020690600000D070000255A0000CB | ||
| 2 | :10001000455A0000655A0000A55A0000855A0000A4 | ||
| 3 | :100020000000000000000000000000001D2700008C | ||
| 4 | :100030000D070000000000000D0700000D07000084 | ||
| 5 | :10004000000000000000000000000000F13200008D | ||
| 6 | :10005000000000000D07000000000000000000008C | ||
| 7 | :100060000D0700000D0700000D0700000D07000040 | ||
| 8 | :10007000000000000D0700000D0700000D07000044 | ||
| 9 | :100080000D0700000D070000000000000000000048 | ||
| 10 | :100090000D0700000D070000000000000000000038 | ||
| 11 | :1000A0000D07000000000000000000000D07000028 | ||
| 12 | :1000B0000D0700000D0700000D0700000D070000F0 | ||
| 13 | :1000C0000D0700000D0700000D0700000D070000E0 | ||
| 14 | :1000D0000D070000000000000D07000000000000F8 | ||
| 15 | :1000E0000D070000000000000D07000000000000E8 | ||
| 16 | :1000F0000D070000000000000000000000000000EC | ||
| 17 | :10010000000000000D0700000000000000000000DB | ||
| 18 | :1001100000000000000000000000000000000000DF | ||
| 19 | :10012000000000000D0700000000000000000000BB | ||
| 20 | :1001300000000000000000000000000000000000BF | ||
| 21 | :100140000D07000000015F5F00000000FE0B0000D3 | ||
| 22 | :10015000F9270000800600000000000000000000F9 | ||
| 23 | :10016000000000000000000000000000401200201D | ||
| 24 | :100170000000000001015F5F030100001F0100009B | ||
| 25 | :1001800085040000000000000000000001000000E5 | ||
| 26 | :10019000010000000000000000000000000000005E | ||
| 27 | :1001A0000000000070000000CC5E00008000000035 | ||
| 28 | :1001B000000F000001000000D102000001015F5F9C | ||
| 29 | :1001C000040100001F010000F30500000000000012 | ||
| 30 | :1001D000000000000000000001000000000000001E | ||
| 31 | :1001E000000000000000000000000000D75E0000DA | ||
| 32 | :1001F000400000000507000001000000DF040000CF | ||
| 33 | :1002000038B50025054C29462046D4F80024C4F80A | ||
| 34 | :10021000045405F0B0FCC4F8005438BD200C002094 | ||
| 35 | :1002200013B511460022CDE9002242680346382A60 | ||
| 36 | :10023000046844D194F82820022A19D01AB900F091 | ||
| 37 | :1002400047F902B010BD21482468D0F80404013AEF | ||
| 38 | :10025000CDE90040082A35D8DFE802F0050A0E1380 | ||
| 39 | :10026000181D22272C006A46184600F02EF9E8E7F0 | ||
| 40 | :10027000184600F018F9E4E76A46184600F016F947 | ||
| 41 | :10028000DFE76A46184600F00BF9DAE76A461846D7 | ||
| 42 | :1002900000F00FF9D5E76A46184600F00DF9D0E7EF | ||
| 43 | :1002A0006A46184600F00BF9CBE76A46184600F09C | ||
| 44 | :1002B00009F9C6E76A46184600F00EF9C1E76FF083 | ||
| 45 | :1002C0008000BEE76FF08500BBE700BF200C002078 | ||
| 46 | :1002D0002DE9F04F05680446A1B0002D40F0AA803A | ||
| 47 | :1002E0002022294602A805F046FC12AF202229460A | ||
| 48 | :1002F0000AA805F040FC38222946384605F03BFCA8 | ||
| 49 | :10030000E26904F11C039846B2B10426E26A04F1E2 | ||
| 50 | :100310002C03EAB10425EEB96FF08306304621B014 | ||
| 51 | :10032000BDE8F08F002EF1D053F8041D3246013E97 | ||
| 52 | :100330000029F7D01646E9E70326F5E7002DEAD0B5 | ||
| 53 | :1003400053F8041D2A46013D0029F7D01546E2E77F | ||
| 54 | :100350000325F5E738233A460021606805F048FC9C | ||
| 55 | :100360003828D9D14FF00109CDE90270334F0DF192 | ||
| 56 | :10037000080A04F1100B4E45D7F800141CD10DF1FA | ||
| 57 | :1003800028094B46002008EB850EC64533D108B13D | ||
| 58 | :10039000C7F80014A3683146C7F804340AAA2B46EC | ||
| 59 | :1003A00002A8FFF73DFF00270646BD4209F10809F4 | ||
| 60 | :1003B00038D1FFF725FFB1E75BF8043FC1F5806254 | ||
| 61 | :1003C000D81C20F00300904204D9FFF719FF6FF00A | ||
| 62 | :1003D0008C06A3E70844CA19C7F8000449466068B8 | ||
| 63 | :1003E000019205F005FC019ACAF80C0009F1010917 | ||
| 64 | :1003F0004AF8082FBFE758F804CFC1F5806A0CF11E | ||
| 65 | :10040000030222F00302524503F1080305D87818CD | ||
| 66 | :1004100043E9020C11440120B7E70028D5D0C7F802 | ||
| 67 | :100420000014D2E7394659E90223606805F0F5FB6C | ||
| 68 | :100430000137BAE76FF0850670E700BF200C002097 | ||
| 69 | :1004400008B528220021024805F095FB002008BDD0 | ||
| 70 | :100450002810002010B5044C0F222046034905F057 | ||
| 71 | :1004600065FB204610BD00BF51100020F6050000BE | ||
| 72 | :1004700008B50121024803F011FB002008BD00BFB0 | ||
| 73 | :100480005010002008B5FFF7DBFF40B9FFF7E2FF8F | ||
| 74 | :10049000FFF7EEFF18B9BDE8084003F06DBB08BDDB | ||
| 75 | :1004A0006FF0850070476FF0850070476FF0850032 | ||
| 76 | :1004B00070476FF0850070476FF0850070476FF0F0 | ||
| 77 | :1004C000850070476FF0850070476FF085007047BA | ||
| 78 | :1004D000D1E9000103F030BB6FF085007047F0B543 | ||
| 79 | :1004E00003680546B3F57D7FA7B007D040F2F5322B | ||
| 80 | :1004F000934207D06FF0850027B0F0BD01F08EFC6D | ||
| 81 | :100500000020F9E700243C22214607A8CDE9024457 | ||
| 82 | :10051000CDE90444069405F02EFB3C22214617A8A1 | ||
| 83 | :10052000169405F028FBEA69019405F11C0302B357 | ||
| 84 | :100530000426EA6A05F12C033AB30424731E012B46 | ||
| 85 | :1005400052D8012C50D80423002168680DEB030217 | ||
| 86 | :1005500005F04EFB04281AD06FF08000CCE7002E87 | ||
| 87 | :10056000E7D053F8041D3246013E0029F7D0164665 | ||
| 88 | :10057000DFE70326F5E7002CE0D053F8041D224600 | ||
| 89 | :10058000013C0029F7D01446D8E70324F5E7022EF2 | ||
| 90 | :1005900016D16E69402E29D806AF33463A4601215E | ||
| 91 | :1005A000686805F025FB8642D6D1CDE9027602A91E | ||
| 92 | :1005B00044B92246019801F01AFE044620469BE702 | ||
| 93 | :1005C0000021F5E72B6A402BC6D816AACDE90423F3 | ||
| 94 | :1005D000019804AA01F00BFEDDE904230446002182 | ||
| 95 | :1005E000686805F01AFBE9E7012085E76FF08900EC | ||
| 96 | :1005F00082E7002070474D62656420544C532033DD | ||
| 97 | :100600002E352E3000000000000000000000000029 | ||
| 98 | :1006100000000000000000000000000000000000DA | ||
| 99 | :100620005431000001000000407C000080100020D8 | ||
| 100 | :100630004A000000407C0000200C00200000000068 | ||
| 101 | :10064000407C0000000C002000000000A8110020E9 | ||
| 102 | :10065000C4050000200C002018010000000C002040 | ||
| 103 | :100660000800000002F07ABC08B572B61E4A1F4BA3 | ||
| 104 | :100670009A601F4B83F309881E4B83F30A8883F328 | ||
| 105 | :100680000B881D4B16A1D1E90001C3E9000100F060 | ||
| 106 | :1006900089F81A4B1A498B4212D30020194B1A4978 | ||
| 107 | :1006A0008B4218D303F06AF8186850F82240586853 | ||
| 108 | :1006B00040F82240013298688242F5D30C33EAE7D1 | ||
| 109 | :1006C0000022F8E71C6844F8220001325C68A2426C | ||
| 110 | :1006D000F8D30833E4E70022F8E700BFAFF3008067 | ||
| 111 | :1006E000A5EDF5FEA5EDF5FE0000000000ED00E033 | ||
| 112 | :1006F000F80B002000040020F80B00202806000062 | ||
| 113 | :100700004C0600004C06000064060000EFF3088071 | ||
| 114 | :10071000EFF309812DE9F00F6B46724600F038F9CE | ||
| 115 | :1007200008B0FFF79FFFFEE708B5EFF31083012B3A | ||
| 116 | :100730000C4A07D1126ABFF34F8F511C4A424A41FB | ||
| 117 | :10074000104608BD01F0BEFB00B172B6126ABFF3DD | ||
| 118 | :100750004F8F531C5A425A4101F0B4FB0028EFD08E | ||
| 119 | :1007600062B6EDE70080FF0008B5EFF31083012BC0 | ||
| 120 | :100770000B4A06D1D269BFF34F8F02F00102104637 | ||
| 121 | :1007800008BD01F09FFB00B172B6D269BFF34F8F75 | ||
| 122 | :1007900002F0010201F096FB0028F0D062B6EEE70D | ||
| 123 | :1007A0000080FF006F4A10B5D2F8D03043F002034A | ||
| 124 | :1007B000C2F8D03001F086FB30B14FF05023002258 | ||
| 125 | :1007C000C3F81421C3F8182101F08BFB28B10122D2 | ||
| 126 | :1007D000654BC3F8382AC3F878254FF47F02D2F866 | ||
| 127 | :1007E0003031D2F83421BFF34F8FC3F30B03092B01 | ||
| 128 | :1007F00005D1012A1EBF01225B4BC3F8782501F009 | ||
| 129 | :1008000070FB18B10E22594BC3F8E42E01F05AFBCD | ||
| 130 | :1008100030B10022544BC3F80C270122C3F8102733 | ||
| 131 | :100820000022D30003F57F03D3F80013BFF34F8FEB | ||
| 132 | :10083000013108D0D3F800130132D3F80433B2F5F4 | ||
| 133 | :10084000807F0B60EDD1EFF31084FFF78DFF002860 | ||
| 134 | :100850004DD0BFF34F8F464BD3F80024012AFBD174 | ||
| 135 | :10086000C3F80425D3F80024012AFBD1012C03D0BE | ||
| 136 | :1008700001F028FB00B172B6FFF776FF58B13D4A90 | ||
| 137 | :10088000D36923F00103D361BFF34F8F384AD2F805 | ||
| 138 | :100890000034012BFBD1FFF747FF68B1354A136ADB | ||
| 139 | :1008A00023F0FF0343F020031362BFF34F8F304A5E | ||
| 140 | :1008B000D2F80034012BFBD1012C03D001F002FB54 | ||
| 141 | :1008C00000B162B600222A4BC3F80425D3F80024F5 | ||
| 142 | :1008D000012AFBD1BFF34F8F2249274BCA6802F48C | ||
| 143 | :1008E000E0621343CB60BFF34F8F00BFFDE7FFF71C | ||
| 144 | :1008F0001BFF0028ADD11B4AD2F88C3043F4406373 | ||
| 145 | :10090000C2F88C304FF47F03D3F83021D3F8343160 | ||
| 146 | :10091000BFF34F8FC2F30B02092A16D1013B022B02 | ||
| 147 | :1009200002D8164AD35C83B1124815490368104AAD | ||
| 148 | :100930008B420CBF5A230023C2F8103EC36A8B427D | ||
| 149 | :100940000CBF5A230023C2F8003E064AD2F8883072 | ||
| 150 | :1009500043F47003C2F88830BFF34F8FBFF36F8F3B | ||
| 151 | :1009600010BD00BF00ED00E00040005000A00350AB | ||
| 152 | :10097000009003500080FF000400FA05C43300001B | ||
| 153 | :10098000FA50FA507C22014905F0D0B8DC1800205A | ||
| 154 | :1009900038B51D46374B384C5B68C3F308032360FA | ||
| 155 | :1009A000EFF30383C4E901206365C2F3801302F00F | ||
| 156 | :1009B0000C020C2AE16038D10BB9EFF389812022B7 | ||
| 157 | :1009C0002E48216105F0B2F825B1202229462C4895 | ||
| 158 | :1009D00005F0ACF8274B9A6AA265D96AE165986B75 | ||
| 159 | :1009E000206602F400406066586BA06602F080004A | ||
| 160 | :1009F000E0669A62D962D3F8E4202267D3F8E8105F | ||
| 161 | :100A0000616702F04001A167C3F8E42000F06AF8D2 | ||
| 162 | :100A10000E211C4801F077FA2268D31E042B1CD843 | ||
| 163 | :100A2000DFE803F0090F1215180013B9EFF38881FE | ||
| 164 | :100A3000C5E70146C3E70C211348BDE8384001F083 | ||
| 165 | :100A400062BA12211148F8E70B211148F5E70D2190 | ||
| 166 | :100A50001048F2E70E211048EFE70F2A98BF142143 | ||
| 167 | :100A6000BDE8384089BF25210C480D48103A01F0F7 | ||
| 168 | :100A7000F5BB00BF00ED00E0DC180020F0180020FE | ||
| 169 | :100A800010190020C7330000D5330000E133000007 | ||
| 170 | :100A9000F3330000FE3300000B3400001934000073 | ||
| 171 | :100AA0002D3400002DE9F34106460F460C4DD5F8D4 | ||
| 172 | :100AB0002C80C04710F00104FBD1394630466B69E9 | ||
| 173 | :100AC000984740B9C047C307FCD42B6A019302B0D2 | ||
| 174 | :100AD000BDE8F0411847204602B0BDE8F08100BFF4 | ||
| 175 | :100AE0005434000010B5094C0020A36898472369CE | ||
| 176 | :100AF00002209847A46A4FF4E1310120A047234621 | ||
| 177 | :100B0000BDE8104001211520184700BF54340000F3 | ||
| 178 | :100B100010B5044C002023699847E368BDE81040F5 | ||
| 179 | :100B2000184700BF54340000064B82B018680023F9 | ||
| 180 | :100B300082B262F30F03000C60F31F43184602B049 | ||
| 181 | :100B4000704700BF9C340000014B1869704700BF1C | ||
| 182 | :100B500084100020014B5869704700BF84100020AA | ||
| 183 | :100B600038B50C4D0C4695F8203013B94FF0FF30D6 | ||
| 184 | :100B700038BD0A460146284600F06CFF064B9842F5 | ||
| 185 | :100B800005D00B3B9842F1D100206C61F0E76FF08B | ||
| 186 | :100B90000100EDE7841000200B00AD0BF0B51B4EFB | ||
| 187 | :100BA000054696F820300C4691B01BB94FF0FF3047 | ||
| 188 | :100BB00011B0F0BD00F06043B3F1005F21D100231C | ||
| 189 | :100BC0000A460146304600F031FC114B98421AD0DB | ||
| 190 | :100BD0000B3B9842EAD1346111E0A71B402F28BF9C | ||
| 191 | :100BE0004027A9193A46684604F0A0FF39466846EE | ||
| 192 | :100BF000FFF7D4FF0028DBD14036B442EDD8002007 | ||
| 193 | :100C0000D6E70026F9E76FF00100D1E78410002055 | ||
| 194 | :100C10000B00AD0BC3B2012B10B540F096804DF622 | ||
| 195 | :100C2000C023994270D028D8B1F5615F6FD011D838 | ||
| 196 | :100C3000B1F5965F6DD008D8B1F5966F6BD0B1F570 | ||
| 197 | :100C4000166F6BD06FF007005DE0B1F5165FF9D15C | ||
| 198 | :100C5000454B33E047F61223994262D007D8B1F5ED | ||
| 199 | :100C6000964F61D0B1F5E14FECD1404B26E0B1F5A4 | ||
| 200 | :100C7000164FE7D14FF41D0320E03D4B994255D06C | ||
| 201 | :100C800011D8B1F5E13F54D007D8B1F5614F53D039 | ||
| 202 | :100C9000B1F5963FD6D1374B10E0B1F5613FD1D1D8 | ||
| 203 | :100CA0004FF06C730AE0B1F5612F48D0324B994296 | ||
| 204 | :100CB00048D0B1F5E12FC5D14FF0E86310F4E06FF3 | ||
| 205 | :100CC00046D110F4404103D0B1F5804F43D11021FB | ||
| 206 | :100CD00010F4405203D0B2F5805F3FD10E2210F4E1 | ||
| 207 | :100CE000403003D0B0F5403F3BD10120234C20766B | ||
| 208 | :100CF0006276E361A1760A4324681043C4F8243580 | ||
| 209 | :100D0000C4F86C05002010BD4FF46503D6E71C4BFA | ||
| 210 | :100D1000D4E71C4BD2E74FF49E23CFE74FF41D23BB | ||
| 211 | :100D2000CCE74FF40003C9E7174BC7E74FF08063E8 | ||
| 212 | :100D3000C4E74FF0EB73C1E74FF46B03BEE74FF02E | ||
| 213 | :100D40007063BBE74FF08053B8E76FF00300DAE75A | ||
| 214 | :100D50006FF00800D7E76FF00A00D4E76FF00900E2 | ||
| 215 | :100D6000D1E76FF00B00CEE70050270000C0750000 | ||
| 216 | :100D700090D0030000903A0140420F008410002000 | ||
| 217 | :100D800000F03A0000B0130000A04E0010B5114C66 | ||
| 218 | :100D9000204600F0D5FD0021206884F8201000F0E6 | ||
| 219 | :100DA00047FF226842F30732002A11DB0121530971 | ||
| 220 | :100DB0009B0003F1604303F56143D3F8800202F026 | ||
| 221 | :100DC0001F0201FA02F20243C3F88022D3F88032F4 | ||
| 222 | :100DD000002010BD8410002010B5264C0021206892 | ||
| 223 | :100DE0008EB000F017FF226842F30732002A12DBB0 | ||
| 224 | :100DF000012053099B0003F1604303F56143D3F8DD | ||
| 225 | :100E0000801202F01F0200FA02F221EA0202C3F885 | ||
| 226 | :100E10008022D3F880322422002105A804F0ABFE02 | ||
| 227 | :100E2000D4E902124FF0FF33CDE90133CDE90333AA | ||
| 228 | :100E30004FF0EB730B93072301A88DF8363001F0C8 | ||
| 229 | :100E400080F8014600220B4800F03AFA0A4B98421B | ||
| 230 | :100E50000DD10C9B002023831B0CA3760B9BC4E9B4 | ||
| 231 | :100E60000400E361012384F820300EB010BD6FF060 | ||
| 232 | :100E70000100FAE7841000200000AD0B7FB50025CB | ||
| 233 | :100E80000C46C0F808511646D0F80821D0F80022C8 | ||
| 234 | :100E900022F02002C0F80022104AC0F8082301F016 | ||
| 235 | :100EA000A0F8A560256104F14C03D3E8EF1F21F4FD | ||
| 236 | :100EB0007F0121F47041C3E8E21F002AF5D110221E | ||
| 237 | :100EC0002946684604F057FE042368468DF8003032 | ||
| 238 | :100ED0000196D4E90013984704B070BD10020A00CF | ||
| 239 | :100EE00000F01F03400909D1074A02EB8303D3F83E | ||
| 240 | :100EF0000012064A0A40C3F80022704700228033DD | ||
| 241 | :100F000052F82330FFDE00BF00258450F0F8FCFFCC | ||
| 242 | :100F10002DE9F04F804690F804A05020664F0E4611 | ||
| 243 | :100F200000FB0A70416885B049B113F0020304D098 | ||
| 244 | :100F3000836B002B00F0B2800123009300E000914E | ||
| 245 | :100F40004FF0500909FB0A73DB6CD90600F1A6804B | ||
| 246 | :100F50004FF0010BB3180293029BB34200F0A7803D | ||
| 247 | :100F600006F06043039398F80450D8F8004009FB5A | ||
| 248 | :100F700005739A6B9AB9039BB3F1005F40F09980B7 | ||
| 249 | :100F8000019200F0A1FD09FB0572D16C204601F031 | ||
| 250 | :100F9000010100F0F4FF28B900F09EFDE3E7012312 | ||
| 251 | :100FA0000193EEE7516C33460029BCBFD4F84C15D1 | ||
| 252 | :100FB0005164019A42B109FB05713078D1E90E23E1 | ||
| 253 | :100FC000D054D1E90E3213441BB1C4F84435C4F8EF | ||
| 254 | :100FD00048B50022C4F82021D4F82011C4F85821C3 | ||
| 255 | :100FE000D4F85811C4F85021D4F850210822C4F87C | ||
| 256 | :100FF0000025009AE2B14FF48003C4F80433C4F82A | ||
| 257 | :1010000008B000F069FD502303FB0A725168002903 | ||
| 258 | :101010004BD1D26C120748D503FB0A734C33D3E88B | ||
| 259 | :10102000EF1F21F00801C3E8E21F002A36D0F6E7DF | ||
| 260 | :10103000C4F808B0019300F04FFD09FB0572D16CB4 | ||
| 261 | :10104000019B01F001012046019300F098FF8446C6 | ||
| 262 | :10105000019BD4F84C05D4F84425BCF1000F0DD108 | ||
| 263 | :101060009342F0D005EB850507EB0515D1B100F0F3 | ||
| 264 | :101070002BFD2946204600F0F9FFC2E705EB850568 | ||
| 265 | :10108000934207EB0515F1D10028EFD100F01CFDCC | ||
| 266 | :101090002946204600F0EAFF00F01EFD074805B093 | ||
| 267 | :1010A000BDE8F08FC4F80CB0E1E7013654E704481E | ||
| 268 | :1010B000F5E70448F3E700BF581900200800AD0B1E | ||
| 269 | :1010C0000000AD0B0400AD0B430904D10123034A1A | ||
| 270 | :1010D00083409360704700239B60FFDE00258450AF | ||
| 271 | :1010E00000F01F0340090BD1084A02EB8302D2F83B | ||
| 272 | :1010F0000012074B0B4043F00303C2F80032704765 | ||
| 273 | :101100000022803352F82330FFDE00BF00258450D8 | ||
| 274 | :10111000F0F8FCFF2DE9F84391F8303005460C4615 | ||
| 275 | :1011200090F804800F6853BB5023DFF85091781C6F | ||
| 276 | :1011300003FB0893DE6C46F00072DA6404D0384694 | ||
| 277 | :10114000FFF7C2FFFFF7CCFF6068411C01D0FFF73B | ||
| 278 | :10115000C7FE94F82C30012B11D1502303FB0893C8 | ||
| 279 | :10116000E06846F02066421CDE6401D0FFF7B8FE5E | ||
| 280 | :10117000A068431C03D0FFF7A7FFFFF7B1FF94F867 | ||
| 281 | :101180002F0038B950223D4B02FB0833DA6C42F095 | ||
| 282 | :101190008072DA6494F82CC094F82D1094F82EE044 | ||
| 283 | :1011A000A26A2B6841EA0C01E668D4E90198C3F809 | ||
| 284 | :1011B00024254EEA0102C3F86C2550B9BCF1010F99 | ||
| 285 | :1011C000C3F80C75C3F8149504BFC3F80885C3F8B9 | ||
| 286 | :1011D0001065D3F8682503F26458012A08BFDA6065 | ||
| 287 | :1011E000D3F86425012A13D1082149F64046244F3B | ||
| 288 | :1011F000C3F8001547F001075A60D8F800309BBBD0 | ||
| 289 | :101200002B68D3F88024C3F880240022C3F800257B | ||
| 290 | :1012100000212B6894F83220C3F81011D3F8100184 | ||
| 291 | :10122000C3F82011D3F82001C3F82411D3F8240106 | ||
| 292 | :10123000C3F84411D3F84401C3F85811D3F8581136 | ||
| 293 | :1012400043F307335201002BD2B212DB0D49C81809 | ||
| 294 | :1012500080F800230122580903F01F0302FA03F368 | ||
| 295 | :1012600041F82030BDE8F8834020B847013EC4D1A2 | ||
| 296 | :10127000C6E7054903F00F03CA54F3E758190020E5 | ||
| 297 | :10128000A034000000E100E014ED00E000F01F03D6 | ||
| 298 | :1012900040090BD1084A02EB8302D2F80012074B37 | ||
| 299 | :1012A0000B4043F00203C2F8003270470022803343 | ||
| 300 | :1012B00052F82330FFDE00BF00258450F0F8FCFF19 | ||
| 301 | :1012C0002DE9F3479046502290F80490514C02FBD0 | ||
| 302 | :1012D00009FA04EB0A070D4697F84810064600295C | ||
| 303 | :1012E00040F0858009EB890004EB001004F043FC1A | ||
| 304 | :1012F0002B69AA6944F80A306B69BB6302B1013AF1 | ||
| 305 | :10130000502303FB0943DA632A6A042A81BFEA698E | ||
| 306 | :101310009A610022DA6195F83130B8F1000F37D0C8 | ||
| 307 | :1013200083F001073F0233B1502303FB0943DA6C1A | ||
| 308 | :1013300042F00102DA64502303FB09440123C4F89C | ||
| 309 | :10134000048084F848303468D4F84C2112BB294614 | ||
| 310 | :101350003046FFF7DFFE0822002334688DF807309F | ||
| 311 | :10136000C4F800250DF10702C4F84425C4F8483537 | ||
| 312 | :1013700001230A25A360E360D4F85831002B38D14B | ||
| 313 | :10138000254B402043F001039847013DF4D128E06C | ||
| 314 | :101390004746C8E708224FF06409C4F80025636097 | ||
| 315 | :1013A0001D4B43F0010AD4F84431F3B9D4F8243189 | ||
| 316 | :1013B000DBB94FF42070D047B9F10109F3D14B46A6 | ||
| 317 | :1013C0000022C4F84C21D4F84C11C4F81021D4F8F0 | ||
| 318 | :1013D0001011C4F84421D4F84411C4F80025002B9E | ||
| 319 | :1013E000B5D10E4802B0BDE8F0870123E8E70C480C | ||
| 320 | :1013F000F8E70023C4F820319845D4F82021C4F838 | ||
| 321 | :101400000035084B08BF00231F4333680648C3F864 | ||
| 322 | :101410000473E7E758190020A03400000100AD0B69 | ||
| 323 | :101420000C00AD0B10020A000000AD0B2DE9F047D7 | ||
| 324 | :1014300084460F469E4616460579002A51D04FF045 | ||
| 325 | :10144000500ADFF8BC80D0F800900AFB058ADAF871 | ||
| 326 | :10145000044074B96BB9DAF82C50002D43D1CAF8A6 | ||
| 327 | :101460002C20FFF755FD0446CAF82C502046BDE855 | ||
| 328 | :10147000F0871EF0030F07D0734632463946BDE8A9 | ||
| 329 | :10148000F0476046FFF744BD07F06043B3F1005FEB | ||
| 330 | :101490004FF0500414D104FB058400F015FBE26A00 | ||
| 331 | :1014A0001AB1134C00F018FBE0E7C4E90A7605EB2B | ||
| 332 | :1014B0008505484608EB051100F0E3FD0D4CF1E70A | ||
| 333 | :1014C00004FB0584A36B83B100F0FEFAE36A002BF2 | ||
| 334 | :1014D000E7D1E36C012243F00203C4E90A76E36436 | ||
| 335 | :1014E000E5E7054CC2E7024CC0E7044CBEE700BF8D | ||
| 336 | :1014F0000B00AD0B0000AD0B0600AD0B0A00AD0BF1 | ||
| 337 | :10150000581900202DE9F84350230679284D046826 | ||
| 338 | :1015100003FB0653D4F80473DA6AC4F8087322B9DB | ||
| 339 | :101520002448C4F80473BDE8F88306EB860005F18F | ||
| 340 | :101530004C024FEA001802EB0012D2E8EFCF4CF059 | ||
| 341 | :10154000080CC2E8E0CF0028F7D10122E26031B3F5 | ||
| 342 | :10155000D96C01EA02094946204600F010FD002836 | ||
| 343 | :10156000FAD000F0B1FAB9F1000F1CD1D4F8203153 | ||
| 344 | :1015700053B10123E360D4F85831002BFBD020464F | ||
| 345 | :1015800005EB080100F072FD00F0A6FA0023C4F894 | ||
| 346 | :101590002031D4F82021502202FB0655EB62064888 | ||
| 347 | :1015A000C4F80473BFE7D4F85831002BE7D1EBE758 | ||
| 348 | :1015B000581900200500AD0B0000AD0B2DE9F843D4 | ||
| 349 | :1015C00090F80480484F08EB8806360106F14C0578 | ||
| 350 | :1015D00004683D44D5E8EF3F43F48052C5E8E02F6E | ||
| 351 | :1015E0000028F7D1DB047BD4480705D5502303FB43 | ||
| 352 | :1015F00008739B69002B75D03C4B3E44C4F80833FC | ||
| 353 | :101600000823C4F800350023C4F81031D4F81021A1 | ||
| 354 | :10161000C4F84C31D4F84C21C4F844310A03D4F84E | ||
| 355 | :1016200044318B0303F4804302F400524903134313 | ||
| 356 | :1016300001F400410B43D5E8EF2F1A43C5E8E12F31 | ||
| 357 | :101640000029F8D14FF0500909FB0879D9F8083082 | ||
| 358 | :10165000BBB9D9F8043063B9D5E8EF3F23F47F0371 | ||
| 359 | :1016600023F47043C5E8E23F002AF5D12048BDE8E5 | ||
| 360 | :10167000F8830321304600F08FFCD9F80830002BA6 | ||
| 361 | :10168000EAD0D4F80433590713D5502303FB087369 | ||
| 362 | :101690005A6872B1DB6C1A030BD5D5E8EF3F23F41F | ||
| 363 | :1016A0000023C5E8E23F002AF7D10621304600F0CA | ||
| 364 | :1016B00073FC502303FB0873DB6CDB0401D40D487F | ||
| 365 | :1016C000D5E7D4F84C310BB901232360502303FB39 | ||
| 366 | :1016D00008735B68002BF2D0044BC4F80433EEE7C8 | ||
| 367 | :1016E0000548C4E70548C2E75819002010020A005F | ||
| 368 | :1016F0000200AD0B0000AD0B0B00AD0B0800AD0BF5 | ||
| 369 | :101700002DE9F84F056801F06043D5F804A3B3F163 | ||
| 370 | :10171000005F90F804B089461746C5F808A37CD14D | ||
| 371 | :101720005023404E03FB0B639A6852B15B68002B59 | ||
| 372 | :101730005ED1D5F81021002A5AD0C5F81031D5F85D | ||
| 373 | :101740001031502404FB0B64E269C4E90297002ABB | ||
| 374 | :101750003CD00BEB8B0897424FEA081824D24FF08D | ||
| 375 | :10176000000B3A46A1694846C4E902BB04F0DEF921 | ||
| 376 | :10177000E269A069D21BC119E26104F0A1F96368B2 | ||
| 377 | :101780006BB1B04449463A46404600F016FCE36C63 | ||
| 378 | :10179000990404D55A4641462846FFF76FFB224874 | ||
| 379 | :1017A000C5F804A3BDE8F88F4846A16904F0BEF966 | ||
| 380 | :1017B000E36963620023E3611C4B9844D8E8EF3F80 | ||
| 381 | :1017C00043F40023C8E8E23F002AF7D1502303FB8B | ||
| 382 | :1017D0000B63586ADA689968DB6C121A0144C5F821 | ||
| 383 | :1017E0003415C5F83825DA04D9D501232B60D6E79E | ||
| 384 | :1017F000502303FB0B6633698BB9F36CC5F8349542 | ||
| 385 | :101800005B04C6E90497C5F83875C8D5D5F8003229 | ||
| 386 | :1018100043F02003C5F80032C1E70548C0E705489A | ||
| 387 | :10182000BEE700BF581900200000AD0BA41900202E | ||
| 388 | :101830000A00AD0B0B00AD0B50232DE9F0413C4DE0 | ||
| 389 | :1018400090F80480046803FB0853DB6CD4F80002B2 | ||
| 390 | :1018500003F48223B3F5805F68D1D4F80463C4F83D | ||
| 391 | :10186000086309B9830656D4D4F8003223F0200364 | ||
| 392 | :10187000C4F800324FF4842308EB8801090101F118 | ||
| 393 | :101880004C072F44D7E8EF0F1843C7E8EC0FBCF123 | ||
| 394 | :10189000000FF7D12AB9502303FB08535B68002BD4 | ||
| 395 | :1018A00041D1244BC4F8083301236360D4F8443198 | ||
| 396 | :1018B000002BFBD00023C4F84C31D4F84C21C4F8E1 | ||
| 397 | :1018C0001031D4F81021C4F84431D4F844315023F5 | ||
| 398 | :1018D00003FB0853DA6C12F400421FD1DA61204690 | ||
| 399 | :1018E00000F07FFB502303FB08550023AB602B6106 | ||
| 400 | :1018F000D7E8EF3F23F47F0323F47043C7E8E23FC8 | ||
| 401 | :10190000002AF5D126F4202626F404760A48C4F8E5 | ||
| 402 | :101910000463BDE8F0814FF48033ADE720462944ED | ||
| 403 | :1019200000F071FBDBE701236360EFE70348F0E7BA | ||
| 404 | :101930005819002010020A000000AD0B0500AD0B85 | ||
| 405 | :101940002DE9F8432F4A03680679C3F8082343F3C7 | ||
| 406 | :101950000733002B04460DDB01215A0903F01F0356 | ||
| 407 | :10196000994002F12003284A42F82310BFF34F8F19 | ||
| 408 | :10197000BFF36F8F012220461146FFF75DFF012163 | ||
| 409 | :101980002046FFF7BFFD50212279204D236801FB3F | ||
| 410 | :101990000252D46CD3F80C05E201D3F81495D3F8B5 | ||
| 411 | :1019A0000875D3F8108509D54FF0FF32C3F80C2520 | ||
| 412 | :1019B000C3F81425C3F80825C3F81025A30116D5CC | ||
| 413 | :1019C000411C01D0FFF762FCB9F1FF3F02D048464D | ||
| 414 | :1019D000FFF75CFC22010AD5B8F1FF3F02D0404678 | ||
| 415 | :1019E000FFF754FC7B1C02D03846FFF74FFC502316 | ||
| 416 | :1019F000002203FB0653DA6483F848205A60BDE8EE | ||
| 417 | :101A0000F88300BF10034A0000E100E058190020ED | ||
| 418 | :101A100010B5502402790B4B04FB02335B686BB9A1 | ||
| 419 | :101A20000368D3F810211AB9D3F80025082A07D083 | ||
| 420 | :101A300011B1D3F83C350B60034810BD0348FCE7F7 | ||
| 421 | :101A40000348FAE7581900200000AD0B0800AD0B61 | ||
| 422 | :101A50000B00AD0BF7B505461646FFF751FE164BCA | ||
| 423 | :101A60000446984222D1032128462F79FFF7A6FD8C | ||
| 424 | :101A7000124B984201D0A0421BD15022104B02FBC6 | ||
| 425 | :101A800007335B6893B90C4C284601A9FFF7C0FFE8 | ||
| 426 | :101A9000A042F9D1019BB34207D301222846114647 | ||
| 427 | :101AA00003B0BDE8F040FFF7C7BE064C204603B0C8 | ||
| 428 | :101AB000F0BD0446FAE700BF0000AD0B0B00AD0B14 | ||
| 429 | :101AC000581900200800AD0B72B6024A13680133A2 | ||
| 430 | :101AD00013607047A8190020034A1368013B136084 | ||
| 431 | :101AE00003B962B6704700BFA81900200722024B55 | ||
| 432 | :101AF000C3F80423704700BF00300050084BD3F8F0 | ||
| 433 | :101B00000801D3F80021003818BF012080000AB175 | ||
| 434 | :101B100040F00100D3F804310BB140F002007047EF | ||
| 435 | :101B2000003000500022074BC3F80021D3F8001109 | ||
| 436 | :101B3000C3F80421D3F80411C3F80821D3F80831FD | ||
| 437 | :101B4000704700BF0030005000231720094A03F5FA | ||
| 438 | :101B5000C0710133202B42F82100F8D10023172057 | ||
| 439 | :101B6000044A03F5E0710133202B42F82100F8D13B | ||
| 440 | :101B7000704700BF0030005010B59DF80840C00B02 | ||
| 441 | :101B800043EA0423064CC90B43EA0213884200D9F6 | ||
| 442 | :101B900010BDC2B202F5C07244F822300130F5E740 | ||
| 443 | :101BA0000030005010B59DF8084000F1604043EA55 | ||
| 444 | :101BB000042301F16041074C400B490B43EA021337 | ||
| 445 | :101BC000884200D910BDC2B202F5E07244F822305A | ||
| 446 | :101BD0000130F5E700300050C0F30E03C3F50043B9 | ||
| 447 | :101BE000B3FA83F3C3F11B03064AC0F3C730DBB279 | ||
| 448 | :101BF00040F4807043F48073C2F80005C2F80435E5 | ||
| 449 | :101C0000704700BF0030005043030148184470473C | ||
| 450 | :101C1000FF1FF81F054BC0F30730090241F03001E8 | ||
| 451 | :101C200000F5007043F82010704700BF00300050EE | ||
| 452 | :101C3000044BC0F30730090200F5007043F8201090 | ||
| 453 | :101C4000704700BF00300050003A18BF0122003931 | ||
| 454 | :101C500018BF012103688900074841EA420118635F | ||
| 455 | :101C600059605A6842F001025A60BFF34F8FBFF3C8 | ||
| 456 | :101C70006F8F0020704700BF04AAFF0008B5FFF770 | ||
| 457 | :101C80003DFF044B162118600348BDE8084000F0F2 | ||
| 458 | :101C90003AB900BFEC1F0020A63400000C22014915 | ||
| 459 | :101CA00003F044BFEC1F002010B501F006FB044612 | ||
| 460 | :101CB00090B901F097FF044680B90A4A2E21D368F3 | ||
| 461 | :101CC000094823F008031B041B0C43F0BF6343F4D3 | ||
| 462 | :101CD0000033D36000F017F9204610BD45F22354BD | ||
| 463 | :101CE000FAE700BF00ED00E0BC340000024B1860D2 | ||
| 464 | :101CF000024B002019607047FC1F0020F81F0020D5 | ||
| 465 | :101D00001FB5374C426923685A6282699A62C26978 | ||
| 466 | :101D1000DA62026A1A63426A5A63826A9A63C26A20 | ||
| 467 | :101D2000DA63026B1A64426B5A60826B9A60C26B10 | ||
| 468 | :101D3000DA60026C1A61426C5A61826C9A61C26C00 | ||
| 469 | :101D4000DA61026D1A62826D5A65C26D9A65026F20 | ||
| 470 | :101D5000DA65026E1A66826E5A66426F9A66EFF311 | ||
| 471 | :101D600088825A64EFF389829A644268DA64EFF3F6 | ||
| 472 | :101D700094821A65026801A81A67FFF78FFF23682B | ||
| 473 | :101D8000019ADA6601221A70164B1C686408640016 | ||
| 474 | :101D90002046214622462346B7EE000AF7EE000A07 | ||
| 475 | :101DA000B7EE001AF7EE001AB7EE002AF7EE002A97 | ||
| 476 | :101DB000B7EE003AF7EE003AB7EE004AF7EE004A07 | ||
| 477 | :101DC000B7EE005AF7EE005AB7EE006AF7EE006A77 | ||
| 478 | :101DD000B7EE007AF7EE007A03F081FF04B010BD91 | ||
| 479 | :101DE000FC1F0020F81F002000B5A1B001A8FEF7DD | ||
| 480 | :101DF000C9FD029B63B15B060AD4019B23F0020379 | ||
| 481 | :101E0000052B05D1044B1B6813B101A8FFF778FF20 | ||
| 482 | :101E100021B05DF804FB00BFF81F0020BFF34F8F17 | ||
| 483 | :101E20000549064BCA6802F4E0621343CB60BFF376 | ||
| 484 | :101E30004F8F00BFFDE700BF00ED00E00400FA0592 | ||
| 485 | :101E400038B543680C2B30D14B68042B2DD14FF0A3 | ||
| 486 | :101E5000FF3304680D6821682B6031B3A26822B398 | ||
| 487 | :101E60000623012001F081F9F8B96168104B99420D | ||
| 488 | :101E70000DD9A2680F485318834202D9F43883421F | ||
| 489 | :101E800010D8206803F052FE0020286038BD0A4BAD | ||
| 490 | :101E900099420AD9A26809488B188342F1D90730C0 | ||
| 491 | :101EA000814202D906488342EBD90220EEE700BF07 | ||
| 492 | :101EB000FF01FF002C02FF002F01FF003801FF008F | ||
| 493 | :101EC0004C01FF004FF47F03D3F83001D3F83431D5 | ||
| 494 | :101ED000BFF34F8FC0F30B00A0F1090358425841E4 | ||
| 495 | :101EE00070474FF47F02D2F83031D2F83401BFF39B | ||
| 496 | :101EF0004F8FC3F30B03092B03D1431E58425841A4 | ||
| 497 | :101F0000704700207047FEF7CDBD012070476FF08D | ||
| 498 | :101F100003007047002382B00193019802B070471C | ||
| 499 | :101F20006FF003007047002382B00193019802B064 | ||
| 500 | :101F30007047022814BF6FF0030000207047FEF7BF | ||
| 501 | :101F40002DBE30B501EB8202914200D130BD51F877 | ||
| 502 | :101F5000044B04F07F037F2B4FEA144408BF4FF07B | ||
| 503 | :101F6000FF33032CF0D8DFE804F002040608036016 | ||
| 504 | :101F7000EAE74360E8E78360E6E7C360E4E7034637 | ||
| 505 | :101F8000D0F8580130B931B9D3F82001003818BF62 | ||
| 506 | :101F9000012070470120704730B504460D4685B0DA | ||
| 507 | :101FA00010220021684603F0E6FDD4E900136846DC | ||
| 508 | :101FB0008DF80050984705B030BD7FB504460E46F9 | ||
| 509 | :101FC000154600211022684603F0D5FD012368461E | ||
| 510 | :101FD0008DF80030CDE90165D4E90013984704B0CD | ||
| 511 | :101FE00070BD10B50446FFF76FFDD4F8583133B11A | ||
| 512 | :101FF000D4F8043313F4800308BFC4F80035BDE8F7 | ||
| 513 | :102000001040FFF769BD70B50D4604460522AA21B0 | ||
| 514 | :10201000D0F83C65A86903F0AEFD0522AB69C4F8B1 | ||
| 515 | :102020003435C4F838250022C4F81021D4F8101132 | ||
| 516 | :102030000121E162D4F810110029FBD0C4F84C2131 | ||
| 517 | :10204000D4F84C11C4F81021D4F81021D4F83C2550 | ||
| 518 | :102050009642EA6109D15A1E043312F8011FAA29D7 | ||
| 519 | :1020600003D19A42F9D10023EB6170BDD0F8583109 | ||
| 520 | :1020700033B1CB6CC3F30032DB0458BFC0F800258A | ||
| 521 | :10208000704770B5CE6C0D4606F001010446FFF7AF | ||
| 522 | :1020900076FF38B94FF4800346F00406EE64C4F8C6 | ||
| 523 | :1020A000043370BDD5E90A365AB1296CEA6B761A49 | ||
| 524 | :1020B000964228BF164619443246A86B03F036FDF7 | ||
| 525 | :1020C000AB6B4FF0FF326A641BB1C4F84435C4F8FF | ||
| 526 | :1020D00048650023C4F82031D4F82021C4F85831D1 | ||
| 527 | :1020E000D4F85821C4F85031D4F850310823C4F83A | ||
| 528 | :1020F00000354FF48003C4F804330123A360D0E714 | ||
| 529 | :10210000C0037047C00300F5FF407F3070470020D8 | ||
| 530 | :1021100070471F2070474FF40040704700F57F4024 | ||
| 531 | :10212000C03040037047402070475F2070474FF435 | ||
| 532 | :10213000005070474B6830B513F01F052DD1026871 | ||
| 533 | :102140000C681068C0F30720844226D2506855609E | ||
| 534 | :1021500094600C7C23F01F0304F001041C438B7C6F | ||
| 535 | :10216000DB0003F018031C434B7C5B0003F0060309 | ||
| 536 | :102170002343D3608B68013B23F01F04CB685B00D3 | ||
| 537 | :1021800003F00E03234343F0010313615060BFF3D8 | ||
| 538 | :102190004F8FBFF36F8F284630BD0120FCE70368E7 | ||
| 539 | :1021A00000205A68C9B258609960D86018615A60B6 | ||
| 540 | :1021B000704770B50546002403681E68C6F30726FD | ||
| 541 | :1021C000B44201D1002070BD21462846FFF7E7FF49 | ||
| 542 | :1021D0000134F5E70020704708B5FFF705FE72B639 | ||
| 543 | :1021E00020BFFDE7002070470020704770470B4676 | ||
| 544 | :1021F00070B5114618B1032806D0032070BD1846EB | ||
| 545 | :10220000BDE87040FFF71CBE5A68082A01D00220C2 | ||
| 546 | :10221000F4E74C68042CFAD11D684FF0FF330E68C8 | ||
| 547 | :10222000296833600029F2D06B68002BEFD0262399 | ||
| 548 | :102230007422012000F099FF0028E8D122462323D0 | ||
| 549 | :102240000120696800F091FF04460028DFD1D5E93C | ||
| 550 | :102250000001FFF74BFD30602046CFE730B50C465C | ||
| 551 | :10226000154685B038B139B1FFF74DFE041E03DACB | ||
| 552 | :10227000204605B030BD044640F60D23ADF80E30C3 | ||
| 553 | :1022800009230B4901A805F00F028A5C2D091A5495 | ||
| 554 | :10229000013B012BF7D147F630030C21ADF8043098 | ||
| 555 | :1022A000FFF731FE0028B4BF04462418E0E700BF62 | ||
| 556 | :1022B000EA34000008B5194B83F30A88184800F087 | ||
| 557 | :1022C000E7FF40BBFFF7F0FC28BBFFF783FF10BB25 | ||
| 558 | :1022D000FFF788FFD8B9FFF789FF00F067FA3521CB | ||
| 559 | :1022E0001048FFF710FE17210F48FFF70CFE1821CA | ||
| 560 | :1022F0000E48FFF708FE00F03FFC21210C48FFF7D5 | ||
| 561 | :1023000002FE00F03FFA00F0CDFE002008BDFFF70E | ||
| 562 | :102310006BFF0028DFD000F021FEEEE70004002074 | ||
| 563 | :10232000AC190020FA3400002F35000046350000BB | ||
| 564 | :102330005E3500002DE9F04F93B00093574B814676 | ||
| 565 | :10234000D3F800B00BB2002B0D461646C1F302685D | ||
| 566 | :10235000C1F3024A04DA6FF0800013B0BDE8F08FD9 | ||
| 567 | :102360008B42C36001D10020F7E708EB0A03042B7E | ||
| 568 | :10237000F1D8CC0F64014FEAC80731463A46DBF882 | ||
| 569 | :10238000080044F0020300F0F0FE01460028E2D10C | ||
| 570 | :10239000202202A803F0EFFB3A46314602A84FEA9A | ||
| 571 | :1023A000CA0603F0C3FB32460099DBF8080044F08C | ||
| 572 | :1023B000060300F0DAFE07460028CCD101462022B1 | ||
| 573 | :1023C0000AA803F0D8FB324600990AA802AE03F02F | ||
| 574 | :1023D000ADFB33460137B84514D91A46BC460DE06B | ||
| 575 | :1023E000D2F808E0D16818687144884203D259686D | ||
| 576 | :1023F00008448645AFD30CF1010C0832C445EFD137 | ||
| 577 | :102400000833E7E715F0006F18BF202409F118071B | ||
| 578 | :1024100007EB880844F00203474513D1202C26D14E | ||
| 579 | :10242000002D02DBC5F3C0456C0109F128050AAE99 | ||
| 580 | :1024300005EB8A0A44F0060455451AD1009BC9F8F9 | ||
| 581 | :102440007C3090E77268DBF8080056F8081B0193AF | ||
| 582 | :1024500000F08BFE00287FF47EAF56F8042C019B21 | ||
| 583 | :1024600047F8042F56F8082C38633A62D4E7002462 | ||
| 584 | :10247000DBE77268234656F8081BDBF8080000F01B | ||
| 585 | :1024800074FE00287FF467AF56F8043C45F8043F1B | ||
| 586 | :1024900056F8083C28642B63CEE700BFB019002033 | ||
| 587 | :1024A0002DE9F0411F461A4B0D461646D3F8008021 | ||
| 588 | :1024B00000F051FF044608B900F050FDE368002B1E | ||
| 589 | :1024C00001DA00F04BFD032D01D900F047FD04EBCC | ||
| 590 | :1024D0008504E569E36CED1A16D006233A463146C9 | ||
| 591 | :1024E000D8F8080000F041FE08B100F037FDBD4209 | ||
| 592 | :1024F00028BF3D46E36CE16B2A461944304603F0A1 | ||
| 593 | :1025000015FBE36C2B44E3642846BDE8F08100BF73 | ||
| 594 | :10251000B01900202DE9F0411D461A4B0F46164612 | ||
| 595 | :10252000D3F8008000F017FF044608B900F016FD4C | ||
| 596 | :10253000E368002B01DA00F011FD032F01D900F050 | ||
| 597 | :102540000DFD04EB8704E36AE26E9B1AAB4201D2F5 | ||
| 598 | :1025500000F004FD02232A463146D8F8080000F0B6 | ||
| 599 | :1025600004FE08B100F0FAFCE36EE06D2A46314645 | ||
| 600 | :10257000184403F0DBFAE36E00202B44E366BDE869 | ||
| 601 | :10258000F08100BFB01900202DE9F04105464FF061 | ||
| 602 | :1025900001080E4E0E4B37685C681CB92846376040 | ||
| 603 | :1025A000BDE8F0812268936813F400700CD1A36930 | ||
| 604 | :1025B000012B09D0D368346023B19847002801DA91 | ||
| 605 | :1025C00000F0CCFCC4F81880246AE6E7B0190020BB | ||
| 606 | :1025D000B419002038B5044610B96FF0800038BD3A | ||
| 607 | :1025E0008368002BF9D01A68002AF6D05D68002DA8 | ||
| 608 | :1025F000F3D00B4BE861A8691D6020B92B68DB683C | ||
| 609 | :1026000053B90123AB61A36804F10C001B681B697B | ||
| 610 | :10261000984701232360E2E798470028F1DADCE7D6 | ||
| 611 | :10262000B01900204268024B08461A60704700BF8C | ||
| 612 | :10263000B0190020002330B505680446AA68C0E937 | ||
| 613 | :10264000063312F4406F85B01CD012F4006202D041 | ||
| 614 | :1026500000F0C2F90246A96A2B6968460B440731AB | ||
| 615 | :1026600023F0070321F00701CDE9021300930023B3 | ||
| 616 | :1026700005490193EB6800F09FFA684600F04EFEB2 | ||
| 617 | :10268000024B1C6005B030BD89250000B019002048 | ||
| 618 | :1026900001F00C0370B50C2B0CBF154605464A061D | ||
| 619 | :1026A0000C461ED58B0658BF2835AB6913F8026C53 | ||
| 620 | :1026B00084F00803C3F3C003C6F38012934201D031 | ||
| 621 | :1026C00000F04CFC16F0A00F1ED176B1032E17D0EF | ||
| 622 | :1026D00032461C210E48FFF7C1FD6FF083032B60CB | ||
| 623 | :1026E0000CE000F03BFC2026E2E700F03BFB044658 | ||
| 624 | :1026F000FEF70EFA2146074800F00AFE204670BD9C | ||
| 625 | :10270000284600F03FFAF9E732461F210248E2E787 | ||
| 626 | :102710007F350000F80B00209B350000EFF30880A8 | ||
| 627 | :102720007146EFF30982EFF30B830CB406B4FFF7A5 | ||
| 628 | :10273000AFFF8646009900F0080001F00801401A3A | ||
| 629 | :1027400002DC12DB04B070471EF020031CBF2DE931 | ||
| 630 | :10275000F00FBDF1080D0A4C254626462746A04637 | ||
| 631 | :10276000A146A246A34630B4704704B030BC1EF068 | ||
| 632 | :1027700020031CBF1DF1080DBDE8F00F04B0704729 | ||
| 633 | :10278000A5EDF5FE084BDA6882F07F4282F47F0205 | ||
| 634 | :1027900042F48042DA6000221A765A76DA76DA77E4 | ||
| 635 | :1027A000602283F82220704700ED00E0114BD3F83F | ||
| 636 | :1027B000882042F47002C3F88820BFF34F8FBFF324 | ||
| 637 | :1027C0006F8FD3F88C2042F44062C3F88C20D3F88A | ||
| 638 | :1027D000342242F08042C3F83422D3F8342242F04B | ||
| 639 | :1027E0003C42C3F834224FF0E022D36843F4200384 | ||
| 640 | :1027F000D360704700ED00E0009A164B9A4227D153 | ||
| 641 | :1028000001229043014641EC100B41EC110B41ECCD | ||
| 642 | :10281000120B41EC130B41EC140B41EC150B41EC8A | ||
| 643 | :10282000160B41EC170BEFF3148222F0040282F333 | ||
| 644 | :102830001488BFF36F8F02460346044605460646DA | ||
| 645 | :10284000074680468146824683468446864604473C | ||
| 646 | :10285000FEE70000A5EDF5FE2DE9F041044618B9AC | ||
| 647 | :1028600043F6DA30BDE8F0810029F9D0836800250D | ||
| 648 | :1028700013F4406F14BF01230023134F43F00203EE | ||
| 649 | :10288000DFF848800B6000F13006236AAB4201D8C4 | ||
| 650 | :102890000020E7E71421A369E26906EB830301FB4B | ||
| 651 | :1028A00002330C226A4399188968090709D59B5895 | ||
| 652 | :1028B000BB4201D04345D3D1186810B10121FFF7C5 | ||
| 653 | :1028C000A9F90135E1E700BFB4100020AC100020E9 | ||
| 654 | :1028D00070B5324C86B03248FFF76BFC2368012597 | ||
| 655 | :1028E0005A1C01932F4B2260DA681B694FF4407623 | ||
| 656 | :1028F000039300232A4801A902920495ADF81460BD | ||
| 657 | :102900008DF81630FFF716FC18B143F6DA3006B032 | ||
| 658 | :1029100070BD23688DF816005A1C0193224B204885 | ||
| 659 | :102920000293224B01A9CDE903352260ADF8146072 | ||
| 660 | :10293000FFF700FC0028E8D123688DF816005A1C28 | ||
| 661 | :1029400001931B4B164802931A4B01A9CDE903359D | ||
| 662 | :102950002260ADF81460FFF7EDFB0028D5D12368A5 | ||
| 663 | :102960008DF816005A1C0193134B0D480293134B1C | ||
| 664 | :1029700001A903930223049340F201132260ADF8EE | ||
| 665 | :102980001430FFF7D7FB04460028BED12A4629465B | ||
| 666 | :102990000348FFF759F92046B9E700BFBC190020EA | ||
| 667 | :1029A000A81000202C36000060360000005F0000F8 | ||
| 668 | :1029B0002006000020060000000C0020200C002053 | ||
| 669 | :1029C000014B1868704700BF2C360000014B1B6894 | ||
| 670 | :1029D000186870472C360000014B1B685868704718 | ||
| 671 | :1029E0002C36000008B5FFF749F9FFF79BF80A4BB2 | ||
| 672 | :1029F0005A68103AD3B2120609D401215A0903F0D9 | ||
| 673 | :102A00001F03994002F16003044A42F82310BDE815 | ||
| 674 | :102A1000084000F0A3BA00BF00ED00E000E100E0D4 | ||
| 675 | :102A20000020034BD8765A6A42F470225A627047EB | ||
| 676 | :102A300000ED00E00349044BCA68002092B2134342 | ||
| 677 | :102A4000CB60704700ED00E00800FA0500224FF06F | ||
| 678 | :102A5000FF300D4B02F1A0010132102A43F8210092 | ||
| 679 | :102A6000F8D1D3F88022002022F00802C3F8802297 | ||
| 680 | :102A7000D3F88022D3F8802222F40072C3F8802297 | ||
| 681 | :102A8000D3F88032704700BF00E100E008B5FFF7DF | ||
| 682 | :102A90002DF80822024BC3F880211A60002008BDDF | ||
| 683 | :102AA00000E100E0064BD3F8D02022F00102C3F889 | ||
| 684 | :102AB000D020D3F8D02042F00202C3F8D0207047D3 | ||
| 685 | :102AC00000ED00E037B50124FFF73EF8134D224634 | ||
| 686 | :102AD000052347F6FF7100200094FFF74DF82246CA | ||
| 687 | :102AE00007234FF000500E490094FFF75BF8D5E93B | ||
| 688 | :102AF0000101072300220094FFF73EF8072300227C | ||
| 689 | :102B0000084909480094FFF74DF82969E868013938 | ||
| 690 | :102B1000FFF762F8002003B030BD00BF2C36000084 | ||
| 691 | :102B2000FF7F0020FFFF03200080002038B5002435 | ||
| 692 | :102B30000E4D002155F8040B0134FFF779F81C2CD9 | ||
| 693 | :102B4000F7D10020012240F20111094BC3F88004A3 | ||
| 694 | :102B5000C3F88424C3F8C004C3F8C424054AC2F8E7 | ||
| 695 | :102B600040154FF48072C3F8402438BDBC350000D6 | ||
| 696 | :102B700000300050009003500122014B1A60704752 | ||
| 697 | :102B8000C019002010B50446094B228918686168F5 | ||
| 698 | :102B90000623806800F0E9FA28B9064B1B68012B70 | ||
| 699 | :102BA00001D100F087F86FF08603236010BD00BFED | ||
| 700 | :102BB000B0190020C01900202DE9F84305461E4633 | ||
| 701 | :102BC0000068134B9046AA68A0F1080440E902335C | ||
| 702 | :102BD000503890420F4601D200F0C0F9A4F14809E4 | ||
| 703 | :102BE00048220021484602F0C6FF002344E907338B | ||
| 704 | :102BF00044F8143C4FF0807344F8043C6FF0020337 | ||
| 705 | :102C000044E9036744F8208CC5E90093BDE8F883E4 | ||
| 706 | :102C1000A5EDF5FE30B5094C024661680023084673 | ||
| 707 | :102C200040B105686D68954205D11BB1826860604E | ||
| 708 | :102C30009A60816030BD03468068F1E7441A002045 | ||
| 709 | :102C400038B504462AB10B689B68DB0512D5002015 | ||
| 710 | :102C500038BD0B4B1D680DB900F080F900222B68C0 | ||
| 711 | :102C600099692C338A4203D053F8040FA04204D14F | ||
| 712 | :102C70009142ECD16FF0FC00EAE70132F2E700BFCD | ||
| 713 | :102C8000B019002070B504460E46154600213022CA | ||
| 714 | :102C90000C3002F070FF064B20461B68A660636094 | ||
| 715 | :102CA000656100F001FA00232061236070BD00BF60 | ||
| 716 | :102CB000B0190020044B1B681BB11B680BB158688E | ||
| 717 | :102CC00070474FF0FF307047B0190020064B10B529 | ||
| 718 | :102CD0001C680CB900F042F923689B6813F4406F3C | ||
| 719 | :102CE00014BF0120002010BDB01900202DE9F843C9 | ||
| 720 | :102CF000904607460C46FFF7E9FF024624B96FF0FD | ||
| 721 | :102D000080042046BDE8F8836300F8D5144B04F036 | ||
| 722 | :102D10001F0153F82150002DF1D02B682946586827 | ||
| 723 | :102D2000FFF78EFFB0B9C4F30721284600F001FB7E | ||
| 724 | :102D300004460028E3D1EFF3108972B600F0C1F920 | ||
| 725 | :102D4000064689F3108840B142462946FFF79AFFAC | ||
| 726 | :102D50003E60D6E76FF08104D3E76FF08204D0E7DE | ||
| 727 | :102D6000C41900202DE9F04100F0AAF90023134E08 | ||
| 728 | :102D7000134F73607B6000F0E5F8DFF84880304661 | ||
| 729 | :102D800000F022F80446A8B139468023424600F0FC | ||
| 730 | :102D90007FF80546204600F011FB206804F1080189 | ||
| 731 | :102DA000FFF75AFD08B100F0D9F829462046FFF791 | ||
| 732 | :102DB00041FCE4E7BDE8F04100F071B9B41900202E | ||
| 733 | :102DC000441A0020C4190020F8B5054608B900F0DF | ||
| 734 | :102DD000C5F82A4E346814F1290F4CD8284B1968CD | ||
| 735 | :102DE00004F128038B4246D2236AA26903EB430312 | ||
| 736 | :102DF0000C321344606AE269024402EB820213441B | ||
| 737 | :102E00009B00E31801D2994201D200F0A7F8236891 | ||
| 738 | :102E10001C4A1B0C1B04934201D000F09FF823882E | ||
| 739 | :102E2000B3F5817F01D300F099F86368002B01DAD4 | ||
| 740 | :102E300000F094F8144A176807F124031360134A4A | ||
| 741 | :102E40001268934201D900F089F8236AA26903EB62 | ||
| 742 | :102E500043030C32616A1344E2693C600A4402EBAA | ||
| 743 | :102E600082021344326802EB83026B6832603B6279 | ||
| 744 | :102E70006F603846F8BD0027FBE700BFC410002094 | ||
| 745 | :102E80004836000000005F5FC0100020443600009C | ||
| 746 | :102E90002DE9F74F0F4690460646009300B109B959 | ||
| 747 | :102EA00000F05CF8D6F800A0DAF818200AF1300338 | ||
| 748 | :102EB00003EB820BDAF81C40204B1D6854B10C2246 | ||
| 749 | :102EC00002FB04541C601E4B1B689C4201D900F09D | ||
| 750 | :102ED00045F82C4625464FF00009DAF81C204A45F3 | ||
| 751 | :102EE00000D91CB9002003B0BDE8F08F142303FB08 | ||
| 752 | :102EF00009B20023C5E900269268AB60930516D598 | ||
| 753 | :102F0000B8F1000F02D0009B802B03D0019200F09B | ||
| 754 | :102F100025F8019A12F0E00FD0B202D158F8202023 | ||
| 755 | :102F20001AB1019000F01AF8019848F820507A6818 | ||
| 756 | :102F300009F10109AA607D600C35CEE7BC100020C4 | ||
| 757 | :102F40004036000008B5FFF73BFD034B9860FFF7E4 | ||
| 758 | :102F50003DFD80F3888808BD00ED02E0FFF73CB935 | ||
| 759 | :102F60008230012808B506D8FFF7B0FE18B9BDE8D1 | ||
| 760 | :102F70000840FFF7F3BF08BDF8B506460D4600F060 | ||
| 761 | :102F8000EAF9044608B9FFF7E9FFA7680FB9FFF7A8 | ||
| 762 | :102F9000E5FFE368991C20D05A1C21D1A5B315F197 | ||
| 763 | :102FA000820F13D102232360EFF3108672B62946F5 | ||
| 764 | :102FB0002046FFF737FB054686F310882368022B6F | ||
| 765 | :102FC00024D1204600F086F82846F8BD15F1830F7D | ||
| 766 | :102FD000EAD0FFF7C3FF0025E6E702232360FAE704 | ||
| 767 | :102FE000002BF6DB204600F0DAF93B689B689B0576 | ||
| 768 | :102FF00001D50223236015F1810FD5D16369002B20 | ||
| 769 | :10300000D2DBFFF7ABFFCFE73546F4E700232360C1 | ||
| 770 | :10301000DAE708B5FFF7E0F86FF0830008BD2DE9A7 | ||
| 771 | :10302000F3410E46174698460546FFF74FFE00F05F | ||
| 772 | :10303000A6F92946024601A8FFF758FE044660B9E2 | ||
| 773 | :1030400043463A4631460198FFF774F9044640B1C9 | ||
| 774 | :103050006B0002D5019800F03DF8204602B0BDE8B3 | ||
| 775 | :10306000F0810198FFF7B6FA0446F6E740F2011046 | ||
| 776 | :10307000704770B50546FFF729FE06462846FFF75C | ||
| 777 | :10308000C9FD044608B9002070BD014632462846F5 | ||
| 778 | :10309000FFF7D6FD0028F6D12368D868F4E76FF073 | ||
| 779 | :1030A0000200704700DF70474FF480507047B0F562 | ||
| 780 | :1030B000805F03D1EFF30B808038704700207047AA | ||
| 781 | :1030C0007047EFF30B8000F1800383F30B887047A8 | ||
| 782 | :1030D00000207047EFF30B83803B83F30B8870472E | ||
| 783 | :1030E00080EA0000E1EE100A00EE100A00EE900AFD | ||
| 784 | :1030F00001EE100A01EE900A02EE100A02EE900AAA | ||
| 785 | :1031000003EE100A03EE900A04EE100A04EE900A91 | ||
| 786 | :1031100005EE100A05EE900A06EE100A06EE900A79 | ||
| 787 | :1031200007EE100A07EE900A08EE100A08EE900A61 | ||
| 788 | :1031300009EE100A09EE900A0AEE100A0AEE900A49 | ||
| 789 | :103140000BEE100A0BEE900A0CEE100A0CEE900A31 | ||
| 790 | :103150000DEE100A0DEE900A0EEE100A0EEE900A19 | ||
| 791 | :103160000FEE100A0FEE900A70472DE9F0410E465F | ||
| 792 | :103170001546002A4AD0C4074BD480F00204C4F399 | ||
| 793 | :103180004004A40003F00602062A4AD144F00104D8 | ||
| 794 | :1031900022462946304602F077FBB8BB46E800F2EB | ||
| 795 | :1031A00005EB0608100E120208F1FF3747E800F39E | ||
| 796 | :1031B0004FEA136166D51B0264D5884262D046E8A7 | ||
| 797 | :1031C00000F547E800F7FEF7A2FF2D0E85424FEA13 | ||
| 798 | :1031D000176734D3FEF79DFF874230D82846FEF7A5 | ||
| 799 | :1031E00091FF2246C6F101010144304602F04CFB3A | ||
| 800 | :1031F000002847D00135AF4218D83846FEF780FF87 | ||
| 801 | :103200002246A8EB000102F03FFBD8B30020BDE846 | ||
| 802 | :10321000F081EFF39484A40004F0040444F0120459 | ||
| 803 | :10322000B0E7990731D544F00804B1E72846FEF726 | ||
| 804 | :1032300067FF0646FEF76FFF22460146D5E7FEF719 | ||
| 805 | :1032400072FF85421ED3FEF770FF87421AD82846C8 | ||
| 806 | :10325000FEF7DAFC2246C6F101010144304602F0D5 | ||
| 807 | :1032600013FB78B10135AF4203D83846FEF756FF5D | ||
| 808 | :10327000C6E72846FEF752FF0646FEF758FF2246ED | ||
| 809 | :103280000146EBE76FF07F00C1E74CF2DA20BEE7C2 | ||
| 810 | :1032900010B50446FFF706FCFFF714FC10B143F627 | ||
| 811 | :1032A000DA3010BDFFF742FC0028F8D1FFF710FB21 | ||
| 812 | :1032B0000028F4D102232360F3E708B5FFF7B0FB41 | ||
| 813 | :1032C00010B143F6DA3008BDFFF7B4FB0028F8D19F | ||
| 814 | :1032D00000F01CF80028F4D162B6FDF703FCFFF7FC | ||
| 815 | :1032E000B5FB0028EDD1FFF7D1FB0028EBD0E8E7D4 | ||
| 816 | :1032F000EFF30880EFF309812DE9F00F6B4672467A | ||
| 817 | :10330000FDF746FB08B0FFF76DFBFEE700207047B6 | ||
| 818 | :1033100004460D46FFF7E4FEA54628470368283318 | ||
| 819 | :1033200083F30988836883F30B88BFF36F8F40684A | ||
| 820 | :10333000704703689A68DB6812F4806F05D18B428E | ||
| 821 | :103340002CBF00206FF0FA0070478B420CBF0020AA | ||
| 822 | :103350006FF0FA00704710B5FFF7A9FE0446FFF7BB | ||
| 823 | :10336000B7FE50B9FFF7A6FCA3685B681B685B68F3 | ||
| 824 | :10337000834218BF0024204610BD0024FBE738B567 | ||
| 825 | :10338000054648B100F01BF8B5EBD07F044601D0EC | ||
| 826 | :10339000FFF7E4FD204638BDFFF78CFCF4E700237F | ||
| 827 | :1033A00010B500F1280252F8041F19B1C16F146C56 | ||
| 828 | :1033B00019444C600833202BF5D110BD70474FF0F5 | ||
| 829 | :1033C000FF307047000001464154414C20455252A5 | ||
| 830 | :1033D0004F523A2000486172644661756C740D0A60 | ||
| 831 | :1033E000004D656D4D616E616765206661756C7439 | ||
| 832 | :1033F0000D0A004275734661756C740D0A005573B1 | ||
| 833 | :103400006167654661756C740D0A0053656375727A | ||
| 834 | :10341000654661756C740D0A005265736572766558 | ||
| 835 | :103420006420457863657074696F6E2000506C612C | ||
| 836 | :1034300074666F726D2065787465726E616C206958 | ||
| 837 | :103440006E7465727275707420284952516E293AF3 | ||
| 838 | :1034500020000000290B00000B1F0000D90D000008 | ||
| 839 | :103460008D0D0000331F00003F1F0000610B0000A6 | ||
| 840 | :103470000F1F0000490B0000550B0000150C000049 | ||
| 841 | :10348000151F0000211F0000271F00001D00000065 | ||
| 842 | :10349000100004001C0002001100060003020202DA | ||
| 843 | :1034A0000338FDD87047506C6174666F726D2045AB | ||
| 844 | :1034B0007863657074696F6E3A0D0A00416C6C2018 | ||
| 845 | :1034C00070696E732068617665206265656E206341 | ||
| 846 | :1034D0006F6E66696775726564206173206E6F6ECA | ||
| 847 | :1034E0002D7365637572650D0A00303132333435E2 | ||
| 848 | :1034F000363738394142434445461B5B313B333410 | ||
| 849 | :103500006D5B536563205468726561645D2053652B | ||
| 850 | :103510006375726520696D61676520696E6974699C | ||
| 851 | :10352000616C697A696E67211B5B306D0D0A00540E | ||
| 852 | :10353000462D4D20466C6F6174204142493A204827 | ||
| 853 | :103540006172640D0A004C617A7920737461636B57 | ||
| 854 | :10355000696E6720656E61626C65640D0A001B5BB5 | ||
| 855 | :10356000313B33346D426F6F74696E672054462D62 | ||
| 856 | :103570004D2076322E302E301B5B306D0D0A0055FB | ||
| 857 | :103580006E6B6E6F776E2053504D205356432072F2 | ||
| 858 | :1035900065717565737465643A2000556E6B6E6F66 | ||
| 859 | :1035A000776E20535643206E756D6265722072658A | ||
| 860 | :1035B000717565737465643A200000000040005026 | ||
| 861 | :1035C000005000500080005000A0005000B000509B | ||
| 862 | :1035D00000E0005000F000500000015000100150C9 | ||
| 863 | :1035E0000040015000500150007001500080015017 | ||
| 864 | :1035F00000B0015000C0015000D0015000E0015067 | ||
| 865 | :1036000000F0015000000250001002500020025053 | ||
| 866 | :103610000030025000400250006002500080025012 | ||
| 867 | :1036200000A002500090035000258450008000004C | ||
| 868 | :1036300000800000FFFF0F00007C00000080000001 | ||
| 869 | :0C3640002C1200201412002000020000D8 | ||
| 870 | :10366000009A204B9A4208D110B502F0A7FA02F056 | ||
| 871 | :10367000A9F906BC96460C46744702F0E3FA009A94 | ||
| 872 | :10368000184B9A4208D110B502F0A4FA02F09AF948 | ||
| 873 | :1036900006BC96460C46744702F0D4FA0CB4029A63 | ||
| 874 | :1036A000104B9A420CD14FF0004319430CBC10B59B | ||
| 875 | :1036B00000F09EF802F086F906BC96460C46744768 | ||
| 876 | :1036C00002F0C0FA009A074B9A4202D106490868F4 | ||
| 877 | :1036D000744702F0B7FA009A024B9A4200D174473D | ||
| 878 | :1036E00002F0B0FAA5EDF5FE801000200348044B6F | ||
| 879 | :1036F000834202D0034B03B118477047A811002042 | ||
| 880 | :10370000A8110020000000000548064B1B1AD90F25 | ||
| 881 | :1037100001EBA301491002D0034B03B118477047D6 | ||
| 882 | :10372000A8110020A81100200000000010B5064CD0 | ||
| 883 | :10373000237843B9FFF7DAFF044B13B10448AFF322 | ||
| 884 | :1037400000800123237010BDC0180020000000007D | ||
| 885 | :10375000EC5E000008B5044B1BB104490448AFF30C | ||
| 886 | :103760000080BDE80840CFE700000000C41800203A | ||
| 887 | :10377000EC5E0000A3F5803A704700BF174B002BAA | ||
| 888 | :1037800008BF134B9D46FFF7F5FF00218B460F4600 | ||
| 889 | :103790001348144A121A02F0EEF90E4B002B00D017 | ||
| 890 | :1037A00098470D4B002B00D09847002000210400C3 | ||
| 891 | :1037B0000D000D48002802D00C48AFF3008002F045 | ||
| 892 | :1037C000DBF820002900FEF775FD02F0C1F800BF0C | ||
| 893 | :1037D000000008000000000000000000F80B0020BE | ||
| 894 | :1037E000A8110020B8280020000000000000000000 | ||
| 895 | :1037F0002DE9F84304460D4616461F46EFF30583B0 | ||
| 896 | :10380000C3F308030BB1FFF7A9FBDFF834903B4685 | ||
| 897 | :10381000204632462946D9F80080FFF700FCD9F847 | ||
| 898 | :1038200000300446984506D0DB6901461869BDE8BA | ||
| 899 | :10383000F843FFF7A1BBFFF793FB2046BDE8F883F1 | ||
| 900 | :10384000B019002001680E4A0346914215D1C169A2 | ||
| 901 | :10385000A2F11022A2F1EF1291420ED18268012A48 | ||
| 902 | :103860000BD8C26812B101698A4206D0586928B1E2 | ||
| 903 | :103870009B691B1A5842584170470120704700BF8E | ||
| 904 | :1038800055AA00FF0D4B70B59E68A6B13046FFF7F4 | ||
| 905 | :10389000D9FF044678B9F3686BB935690DB920468C | ||
| 906 | :1038A00070BD2846FFF7CEFF28B9EB68B34202D1BE | ||
| 907 | :1038B0002E462D69F2E70124F1E700BF4C1A0020E3 | ||
| 908 | :1038C0002DE9F041394E3468F368D4B1B468C4B11D | ||
| 909 | :1038D000002861D000295FD001FB00F5B5FBF0F0B6 | ||
| 910 | :1038E000884259D1291D57D8AA070DD025F00302C7 | ||
| 911 | :1038F00004321C4603E0616891424FD2A469002C57 | ||
| 912 | :10390000F9D12046BDE8F0812A46F2E7891A232939 | ||
| 913 | :1039100004F12007D4E9050C1AD80123A360A0B153 | ||
| 914 | :10392000C0F818C0A36903B158610023C4E9053386 | ||
| 915 | :103930003369DB0702D5FFF7A5FFA0BB2A460021AC | ||
| 916 | :1039400038463C4602F017F9DBE7C6F80CC0E9E759 | ||
| 917 | :1039500002F1200804EB08032039C3E9011E2169A4 | ||
| 918 | :10396000DFF84CE0DC60196144F808E0AEF1102E9D | ||
| 919 | :10397000AEF1EF1EC3F81CE001B1CB60C3E9050C4A | ||
| 920 | :1039800040B18361996901B14B6101212361C4E9AF | ||
| 921 | :103990000121CAE7F360F5E70024B2E7D4F808E0B4 | ||
| 922 | :1039A000BEF1000FB2D0012001F0D2FF4C1A00206E | ||
| 923 | :1039B00055AA00FFF8B5054600283AD0364E3368C0 | ||
| 924 | :1039C000002B36D0B268002A33D0834203D8726805 | ||
| 925 | :1039D0001344984202D3012001F0BAFFA0F1200461 | ||
| 926 | :1039E0002046FFF72FFF0028F5D155F8183C012B92 | ||
| 927 | :1039F000F1D145F8180C55E90570DFB1BB68CBB9BA | ||
| 928 | :103A000055F81C2C7B68203213447B60386100B170 | ||
| 929 | :103A1000C76020220021204602F0ADF8386908B1C5 | ||
| 930 | :103A200083682BB333699B0703D5FFF72BFF00286F | ||
| 931 | :103A3000D1D1F8BD40B3836833BB42686368134497 | ||
| 932 | :103A4000203363600369D4E90521236192B9B9B9D0 | ||
| 933 | :103A5000426981696261A161A2B19461A26902B106 | ||
| 934 | :103A6000546103B1DC602022002102F084F8D9E720 | ||
| 935 | :103A70003C46E2E79161A1690029E9D04A61E7E7A4 | ||
| 936 | :103A8000F160F8E7F460E9E7F36845F8083C03B152 | ||
| 937 | :103A90005C61F460C6E700BF4C1A002038B50D46E3 | ||
| 938 | :103AA000142200210446124802F065F81149124818 | ||
| 939 | :103AB00000F02CF8232D1AD914F003031FBF043D86 | ||
| 940 | :103AC000ED18C3F10403E4182A460021204602F051 | ||
| 941 | :103AD00052F8074B094AC3E900459C602260A2F1F5 | ||
| 942 | :103AE0001022203DA2F1EF126560E261DC6038BD7A | ||
| 943 | :103AF0004C1A0020B5390000C138000055AA00FF5B | ||
| 944 | :103B0000014B1B68184700BFC8100020024B18600B | ||
| 945 | :103B1000024B002019607047CC100020C810002014 | ||
| 946 | :103B200010B50A46044619B1024B00211B6898479C | ||
| 947 | :103B300010BD00BFD0100020054B0A46197819B1FE | ||
| 948 | :103B40000146181D02F0B8B86FF08800704700BF3A | ||
| 949 | :103B5000601A002010B5074C00F032F8204602F041 | ||
| 950 | :103B6000BCF8201F0821FFF7DBFFBDE8104002F082 | ||
| 951 | :103B7000A0B800BF641A002070B50C4D2B787BB93B | ||
| 952 | :103B800002F095F8044670B90126281D6E7002F007 | ||
| 953 | :103B900091F8044638B900F00BF8044618B92E70B5 | ||
| 954 | :103BA0000024204670BDFFF7D5FFFAE7601A002019 | ||
| 955 | :103BB0000122024B002083F880257047681A0020FC | ||
| 956 | :103BC000F8B5074C2025264601272046276202F03B | ||
| 957 | :103BD0005DF8013D04F12C04F7D186F88055F8BD5D | ||
| 958 | :103BE000681A002010B50C4C236813B10B4B1B68EE | ||
| 959 | :103BF0002BB900F089FC30B90122084B1A6001236F | ||
| 960 | :103C00002360002010BD0138062801D9044810BDEA | ||
| 961 | :103C1000044B53F8200010BD042000200020002099 | ||
| 962 | :103C2000FE8FFFFF545D0000144B2DE9F043002888 | ||
| 963 | :103C300014BF04461C46124F236883B0BB4219D000 | ||
| 964 | :103C400016460D4620464FF4147104F1040900F0A5 | ||
| 965 | :103C500047F804F58E78484600F0CEF8404600F06C | ||
| 966 | :103C600019FA2B464A4640460649009600F034FBB6 | ||
| 967 | :103C700008B92760002003B0BDE8F08308200020C9 | ||
| 968 | :103C8000A5BCC95A7D3E000070B50D4C1D460028EC | ||
| 969 | :103C900014BF064626460B4B306882B098420DD1C1 | ||
| 970 | :103CA00006F58E70002633460096144600F03EFB63 | ||
| 971 | :103CB000002818BF34462C6002B070BD0248FBE7F4 | ||
| 972 | :103CC00008200020A5BCC95AE88FFFFF38B131B1E8 | ||
| 973 | :103CD000002201440346013081421A70FAD1704734 | ||
| 974 | :103CE00038B131B1002201440346013088421A70D4 | ||
| 975 | :103CF000FAD170472DE9F043202B1D460646884631 | ||
| 976 | :103D000091468BB026D8DBB202AF8DF80480B04666 | ||
| 977 | :103D100058F8041B8DF8053021B9404601F038F9F8 | ||
| 978 | :103D2000044640B9012302224046336001A901F054 | ||
| 979 | :103D300043F9044638B138462021FFF7D1FF204629 | ||
| 980 | :103D40000BB0BDE8F0832A464946404601F034F9FD | ||
| 981 | :103D50000446F0E702AF1946104600233A4601F048 | ||
| 982 | :103D6000B1FA04460028E6D12023B9461D46CCE727 | ||
| 983 | :103D70002DE9F041D0F8F830A6B0002BD8BF02AE44 | ||
| 984 | :103D800031DD05460027D0F80C4102AEA4F1010850 | ||
| 985 | :103D90009022D5F8FC403146D0F8000101AB0197E4 | ||
| 986 | :103DA000B8FA88F8A0474FEA5818044620B9019B92 | ||
| 987 | :103DB00053B9B8F1000F16D030469021FFF790FFAD | ||
| 988 | :103DC000204626B0BDE8F081014632462846FFF77E | ||
| 989 | :103DD00091FF58B9D5F80431019A1344C5F804315C | ||
| 990 | :103DE000B8F1000FE8D16FF03C04E5E70446204647 | ||
| 991 | :103DF00026B0BDE8F08100BF70B50025044614224E | ||
| 992 | :103E000004F588762946C0F8F850FC3001F0B3FE7E | ||
| 993 | :103E100008222946304601F0AEFE144B30461B689E | ||
| 994 | :103E20009847204640F8045B01F098F8104B304664 | ||
| 995 | :103E30001B689847C8B9D4F8F830AB420FDC03EBE5 | ||
| 996 | :103E4000830204EB82022021C2F800010120C2E9B2 | ||
| 997 | :103E5000421008490133C2F8FC10C4F8F830064B90 | ||
| 998 | :103E60003046BDE870401B68184770BDF010002058 | ||
| 999 | :103E7000EC100020614E0000E81000202DE9F04712 | ||
| 1000 | :103E8000202A88B07AD83F4B00F5887904461B6811 | ||
| 1001 | :103E900048461746884698470546F8B940F2011645 | ||
| 1002 | :103EA000D4F8F830002B65D02046FFF761FF0546B7 | ||
| 1003 | :103EB00038B9D4F8F830002B14DC013EF2D16FF0A1 | ||
| 1004 | :103EC0003B056E4620213046FFF70AFF2E4B484641 | ||
| 1005 | :103ED0001B689847002818BF6FF01D05284608B0DA | ||
| 1006 | :103EE000BDE8F087D4E94132934203D3D4F80C21E2 | ||
| 1007 | :103EF000012A02D0013ED7D1E1E71F2BFAD96E4645 | ||
| 1008 | :103F000001462022304604F1040A01F034FE314615 | ||
| 1009 | :103F1000504601F07BF805460028D3D1504601F009 | ||
| 1010 | :103F200031F8504601F01AF82946504601F030F8B1 | ||
| 1011 | :103F300005460028C6D150462022314601F03CF803 | ||
| 1012 | :103F400005460028BED1034632462021304601F006 | ||
| 1013 | :103F5000B9F905460028B5D1D4F8F8303A46002B17 | ||
| 1014 | :103F6000C8BF002340463146C8BFC4F8043101F041 | ||
| 1015 | :103F7000DDFDA7E76FF03F056E46A3E76FF03B0559 | ||
| 1016 | :103F8000ACE700BFEC100020E810002070B590B046 | ||
| 1017 | :103F900000287AD03E4C0D46402236210646204667 | ||
| 1018 | :103FA00001F0E9FD40225C21A01801F0E4FD2B1D89 | ||
| 1019 | :103FB000A34203D904F144039D4252D32B682268E3 | ||
| 1020 | :103FC000534023602B68226C534023646B68626803 | ||
| 1021 | :103FD000534063606B68626C53406364AB68A26873 | ||
| 1022 | :103FE0005340A360AB68A26C5340A364EB68E268E3 | ||
| 1023 | :103FF0005340E360EB68E26C5340E3642B69226951 | ||
| 1024 | :1040000053402361226D2B695340236562696B69BC | ||
| 1025 | :10401000534063616B69626D53406365AB69A2692C | ||
| 1026 | :104020005340A361AB69A26D5340A365EB69E2699C | ||
| 1027 | :104030005340E361EB69E26D5340E3650021304694 | ||
| 1028 | :1040400000F0A6FF044628B940223046104900F08F | ||
| 1029 | :10405000B3FF044640216846FFF742FE204610B0F9 | ||
| 1030 | :1040600070BD631E04F13F01013D1F3415F8010FBF | ||
| 1031 | :1040700013F8012F42401A7011F8012F2878A3423B | ||
| 1032 | :1040800082EA00020A70F1D1D8E76FF07304E5E725 | ||
| 1033 | :104090005822002010B54FF49A720021044601F016 | ||
| 1034 | :1040A0006AFD42F21072044BC4F8202104F59670A8 | ||
| 1035 | :1040B0001B68BDE810401847F01000202DE9F04FB4 | ||
| 1036 | :1040C00004468846914695B0002900F0A780002A52 | ||
| 1037 | :1040D0000CBF0126022600238DF80C30002C00F0C6 | ||
| 1038 | :1040E0009F80DFF844A104AF0AF1400B0021204675 | ||
| 1039 | :1040F00000F04EFF034648B1384620210193FFF7F8 | ||
| 1040 | :10410000EFFD019B184615B0BDE8F08F40225146E7 | ||
| 1041 | :10411000204600F051FF03460028EDD104F1F405DC | ||
| 1042 | :1041200020222946204600F047FF03460028E3D11D | ||
| 1043 | :104130000122204603A900F03FFF03460028DBD1FF | ||
| 1044 | :10414000022E62D020460CA900F060FF0346002832 | ||
| 1045 | :10415000D2D10146204600F01BFF03460028CBD1F8 | ||
| 1046 | :1041600040225946204600F027FF03460028C3D1CD | ||
| 1047 | :10417000202220460CA900F01FFF03460028BBD1D7 | ||
| 1048 | :104180003946204600F042FF03460028B4D13946A4 | ||
| 1049 | :104190002046FFF7FBFE03460028ADD1202229462A | ||
| 1050 | :1041A000204600F009FF03460028A5D120460CA9AF | ||
| 1051 | :1041B00000F02CFF034600289ED10146204600F067 | ||
| 1052 | :1041C000E7FE0346002897D140225946204600F0DA | ||
| 1053 | :1041D000F3FE034600288FD1202220460CA900F0D0 | ||
| 1054 | :1041E000EBFE0346002887D12946204600F00EFF4B | ||
| 1055 | :1041F0000346002880D19DF80C200132D2B2B24291 | ||
| 1056 | :104200008DF80C20FFF472AF76E74A46414620460F | ||
| 1057 | :1042100000F0D2FE0346002894D06DE701265AE74D | ||
| 1058 | :104220006FF0730304AF67E7582200202DE9F041D7 | ||
| 1059 | :104230000446884615461F46D0F81801E0B013B171 | ||
| 1060 | :1042400000EB40004008B5F5807F3ED82844B0F52B | ||
| 1061 | :10425000C07F3AD84FF4C0720021684601F08BFC51 | ||
| 1062 | :104260006946D4F82431D4F81821D4F828019847A5 | ||
| 1063 | :1042700070BBD4F8186157B1D4E9493072080DEB1E | ||
| 1064 | :104280000601984720BBD4F8183106EB5306B8F165 | ||
| 1065 | :10429000000F00D08DB9324669462046FFF70EFF69 | ||
| 1066 | :1042A000054610B90123C4F8143131466846FFF7BA | ||
| 1067 | :1042B00017FD284660B0BDE8F0810DEB06004146D1 | ||
| 1068 | :1042C0002A462E4401F032FCE5E76FF00405F0E7E2 | ||
| 1069 | :1042D0006FF00805EDE700BF2DE9F047044604F153 | ||
| 1070 | :1042E000F4050F4691461E46DDF8208000F036FEAC | ||
| 1071 | :1042F00029462046FFF74AFE08B1BDE8F087284668 | ||
| 1072 | :104300002022012101F037FCD4F81831C4F82471BF | ||
| 1073 | :10431000C4F8289113B92023C4F818314246314615 | ||
| 1074 | :104320002046BDE8F0470123FFF780BFB2F5806F5C | ||
| 1075 | :1043300000F295802DE9F04F89B09A46129BB3F5B3 | ||
| 1076 | :10434000807F00F29080D0F82431164604460F4654 | ||
| 1077 | :104350004BB3D0F81C31012B05D0D0F81421D0F884 | ||
| 1078 | :1043600020319A421FDD514600232046129AFFF762 | ||
| 1079 | :104370005DFF014698B900231293002E5ED0DFF84E | ||
| 1080 | :10438000EC9009F1400B0021204600F001FE202EA8 | ||
| 1081 | :104390003546014628BF202504F1F40890B10846AF | ||
| 1082 | :1043A00009B0BDE8F08FBAF1000FE6D0129B002BE8 | ||
| 1083 | :1043B000E1D051461A462046FFF780FE014600280C | ||
| 1084 | :1043C000DBD0ECE749464022204600F0F5FD0146EF | ||
| 1085 | :1043D0000028E4D141462022204600F0EDFD0146B0 | ||
| 1086 | :1043E0000028DCD16946204600F010FE0146002876 | ||
| 1087 | :1043F000D5D1204600F0CCFD01460028CFD159464A | ||
| 1088 | :104400004022204600F0D8FD01460028C7D1694669 | ||
| 1089 | :104410002022204600F0D0FD01460028BFD14146B1 | ||
| 1090 | :10442000204600F0F3FD01460028B8D138462A4660 | ||
| 1091 | :10443000414601F07BFB761B2F44A4D15146204618 | ||
| 1092 | :10444000129AFFF73BFE01460028A8D10846D4F88F | ||
| 1093 | :1044500014310133C4F8143109B0BDE8F08F6FF0A6 | ||
| 1094 | :104460000201084670476FF0040198E758220020C7 | ||
| 1095 | :10447000002130B58DB0282202A8019101F07BFB0C | ||
| 1096 | :1044800002A800F047FF044610B120460DB030BD31 | ||
| 1097 | :10449000174D4FF0FF31286800F042F9044620B173 | ||
| 1098 | :1044A000144800F0D3F9012C18D0002000F068F96E | ||
| 1099 | :1044B000D0B9114A02A901A800F0C4FC04460120A9 | ||
| 1100 | :1044C00000F05EF960B9286800F032F90028DCD00D | ||
| 1101 | :1044D0000A4800F0BBF920460DB030BD0524F2E7D4 | ||
| 1102 | :1044E000074800F0B3F9EEE7064800F0AFF9E0E75F | ||
| 1103 | :1044F000D4100020705D0000D8220020C85D0000AC | ||
| 1104 | :10450000A85D0000885D000030B583B000F05CF865 | ||
| 1105 | :1045100028B100F0ABF80324204603B030BD00F012 | ||
| 1106 | :1045200077F8D8B900F02CF9E0B9224CD4F8283942 | ||
| 1107 | :104530001B0EF02B0AD1D4F8242A1F4B9A4231D0FB | ||
| 1108 | :1045400000F044F8072400F091F8E5E7062400F0B5 | ||
| 1109 | :104550003DF800F08BF8204603B030BD042420461F | ||
| 1110 | :1045600003B030BD00F032F800F080F8FFF780FFB4 | ||
| 1111 | :10457000044698B9114D2B68002BCDD10246014657 | ||
| 1112 | :10458000FFF752FB50B968220D4901ABFFF77CFBE6 | ||
| 1113 | :1045900020B920460B4B2B6003B030BD05242046CC | ||
| 1114 | :1045A00003B030BD012000F0EBF80028DAD1C4F8E8 | ||
| 1115 | :1045B0000C0ADBE7001084500000E020F824002003 | ||
| 1116 | :1045C000FC2400205AEA5A5A002070470020704705 | ||
| 1117 | :1045D000430504D54FF0FF32034BC3F80821024BCB | ||
| 1118 | :1045E000C3F8080A704700BF00108450014BC3F89D | ||
| 1119 | :1045F000040A70470010845008B100F06BB84FF403 | ||
| 1120 | :104600007500704708B100F04FB84FF4750070475F | ||
| 1121 | :1046100010B5114800F070F800B110BD0F4800F05F | ||
| 1122 | :104620006BF80028F9D10E4C204600F065F8002800 | ||
| 1123 | :10463000F3D10C4B0C481C6000F05EF801460028DA | ||
| 1124 | :10464000EBD100F02DF8044608B1204610BD00F073 | ||
| 1125 | :1046500079F82046FAE700BFE4100020E0100020BF | ||
| 1126 | :10466000DC100020D4100020D810002008B5084825 | ||
| 1127 | :1046700000F04CF8074800F049F8074800F046F809 | ||
| 1128 | :10468000064800F043F8BDE8084000F00BB800BF52 | ||
| 1129 | :10469000E4100020E0100020DC100020D8100020E2 | ||
| 1130 | :1046A00000207047704700BF024610B4084CD4F891 | ||
| 1131 | :1046B000003A1342FBD021B1D4F804310B60C4F8A6 | ||
| 1132 | :1046C0000831034B0020C3F8082A5DF8044B7047FB | ||
| 1133 | :1046D00000108450044AD2F8003A1842FBD0C2F8C5 | ||
| 1134 | :1046E000080A0020704700BF0010845001F0E8B9AC | ||
| 1135 | :1046F0000A46002101F03FBA08B5034B02681B6867 | ||
| 1136 | :1047000010689847002008BD1011002008B5034B21 | ||
| 1137 | :1047100002685B6810689847002008BD10110020EF | ||
| 1138 | :10472000024B02689B681068184700BF10110020F8 | ||
| 1139 | :1047300008B5034B0268DB6810689847002008BD85 | ||
| 1140 | :104740001011002070B5094C094D2069AB689847DD | ||
| 1141 | :1047500018B1084B08485B6898470021074AEB6886 | ||
| 1142 | :1047600011602069BDE87040184700BFFC100020B0 | ||
| 1143 | :1047700010110020F4100020E05D000064250020EE | ||
| 1144 | :10478000F8B51A4D1A4E0446B26828699047E8B940 | ||
| 1145 | :10479000184F3B684CB1A3B1012B19D0013B3B60D2 | ||
| 1146 | :1047A0002869F36898470020F8BD43B90121124AEF | ||
| 1147 | :1047B000C2F800151149D1F81029002AFBD10133A4 | ||
| 1148 | :1047C0003B60F368286998470020F8BD0C48F8BDA5 | ||
| 1149 | :1047D0000A4AD2F81039002BFBD1074A6FF07E400D | ||
| 1150 | :1047E000C2F80035FFF702FF3B68D7E7FC10002056 | ||
| 1151 | :1047F0001011002064250020000084500010845017 | ||
| 1152 | :10480000E98FFFFF014B1B68184700BF1011002004 | ||
| 1153 | :10481000014B9B68184700BF10110020014BDB685B | ||
| 1154 | :10482000184700BF10110020BFF34F8F0549064BFA | ||
| 1155 | :10483000CA6802F4E0621343CB60BFF34F8F00BF3E | ||
| 1156 | :10484000FDE700BF00ED00E00400FA0530B44FF0D2 | ||
| 1157 | :10485000FE320025074B084C08494968C3F800247C | ||
| 1158 | :10486000C3F80424C3F80824C3F80C24C4F8005582 | ||
| 1159 | :1048700030BC08470010845000008450F410002021 | ||
| 1160 | :1048800010B5044650B1636813F0685F05D0064A5E | ||
| 1161 | :10489000934202D000236260236010BD034B0448A2 | ||
| 1162 | :1048A0005B689847EFE700BF2C5F5CA9F41000201D | ||
| 1163 | :1048B000005E0000C8B143680D4A934213D013F064 | ||
| 1164 | :1048C000685F0ED0012350E8002F194640E8001C15 | ||
| 1165 | :1048D0009CF0000FF7D1012AF5D0BFF35F8F0020C5 | ||
| 1166 | :1048E000704704487047044870476FF4E0407047D1 | ||
| 1167 | :1048F0002C5F5CA9E98FFFFFEA8FFFFF034680B1C1 | ||
| 1168 | :10490000426809498A420AD012F0685F05D0BFF3B5 | ||
| 1169 | :104910005F8F002210461A607047044870470448B1 | ||
| 1170 | :1049200070476FF4E04070472C5F5CA9E98FFFFF90 | ||
| 1171 | :10493000EA8FFFFF10B5044620B10023034A23602D | ||
| 1172 | :10494000626010BD0248FFF781FFF6E73A00003AC7 | ||
| 1173 | :10495000285E00002DE9F047002878D00C46002999 | ||
| 1174 | :1049600075D01D46002B72D007461AB101220023D4 | ||
| 1175 | :104970002A6003602B68002B64D02946204600F093 | ||
| 1176 | :10498000B7FD804600285FD12146286800F096FDDB | ||
| 1177 | :104990008046002858D12B68082B6CD0042B6DD092 | ||
| 1178 | :1049A000A3F10209B9FA89F94FEA59190121354EE3 | ||
| 1179 | :1049B000C6F8C411C6F84011C6F8C411636AC6F837 | ||
| 1180 | :1049C0003031D6F830219342F6D14FF0000A4FF043 | ||
| 1181 | :1049D000FF30C6F82CA1FFF7FBFD6FF01B0350461C | ||
| 1182 | :1049E000C6F80031FFF702FEC6F80C91D6F8040AAB | ||
| 1183 | :1049F00040F48060FFF7FAFD0A23C6F83831089BBF | ||
| 1184 | :104A0000012B29D02369204AA2FB03231B09626AD8 | ||
| 1185 | :104A1000404602FB03F303EB43031A4ADB039B0903 | ||
| 1186 | :104A2000C2F8D8310123C2F82C313B682A6823F040 | ||
| 1187 | :104A30007F4343EA02633B602A6843EA02233B6008 | ||
| 1188 | :104A4000BDE8F087DFF844804046BDE8F087DFF836 | ||
| 1189 | :104A500040804046BDE8F0874FF47F03D3F80C2C2C | ||
| 1190 | :104A6000013206D0D3F80C3C074AA2FB03231B09F2 | ||
| 1191 | :104A7000CDE71623CBE74FF0030997E74FF0020984 | ||
| 1192 | :104A800094E700BF00108450ABAAAAAA310CF10031 | ||
| 1193 | :104A9000350CF10058B34B1EB3F5047F27D230B567 | ||
| 1194 | :104AA0004FF0000ECD00744671464B0901F01F0C0B | ||
| 1195 | :104AB00050F82330BCF11F0F23FA0CF306D003F09B | ||
| 1196 | :104AC000010319B901211C468E46EEE79C4201F113 | ||
| 1197 | :104AD000010106D01C464FF0010EA942E5D100208D | ||
| 1198 | :104AE00030BD0EF1010E9645F7D1024830BD0148A8 | ||
| 1199 | :104AF000704700BF360CF100C0B32DE9F0434C1EE7 | ||
| 1200 | :104B0000B4F5047F1DD2E3B1DAB100252E46A846E4 | ||
| 1201 | :104B10002C46CF0003F1FF394FEA541C04F01F0E5E | ||
| 1202 | :104B200050F82C10BEF11F0F21FA0EFC0CD00CF027 | ||
| 1203 | :104B3000010C4CB90126E04634463546ECE7964276 | ||
| 1204 | :104B400016D90C48BDE8F083AB420BD0C44508BF72 | ||
| 1205 | :104B50000136A945F3D001350134BC42DCD1002037 | ||
| 1206 | :104B6000BDE8F0830125E0462E46F5E70148704791 | ||
| 1207 | :104B70001D46F1E7370CF1002DE9F04F91B0834667 | ||
| 1208 | :104B8000DDE91B460D46002E6ED10F691C60002327 | ||
| 1209 | :104B90001A990B60002A00F02F819D4B6A6AD3F8A6 | ||
| 1210 | :104BA0003811D3F830319A4269D10A2967D19BF87C | ||
| 1211 | :104BB0000330089304F10803079304230593954BEE | ||
| 1212 | :104BC000934CA3FB07239B0803EB4303A7EB43038F | ||
| 1213 | :104BD000039306971A9B069E1E60002E00F0EA8043 | ||
| 1214 | :104BE00000F096FC00230993BBF1000F00F0D58084 | ||
| 1215 | :104BF00098464FF0010ADDF81C90002D00F0CD80A2 | ||
| 1216 | :104C0000089B002B3DD0284608A900F071FC002825 | ||
| 1217 | :104C100039D0814B984220D0089B082B00F0E480CB | ||
| 1218 | :104C200000225B000893294608AB58460092FFF724 | ||
| 1219 | :104C300091FE7A4B984200F0D38070B9DBF80020E7 | ||
| 1220 | :104C4000130A03F47F03134323F07F43CBF80030B0 | ||
| 1221 | :104C5000059B013B0593BDD10020039000F058FC5B | ||
| 1222 | :104C6000039811B0BDE8F08F4FF47F01D1F80C0C20 | ||
| 1223 | :104C700001300CBF4FF40477D1F80C7C86E768480C | ||
| 1224 | :104C8000EBE76648C5E72946089800F017FC0028BE | ||
| 1225 | :104C9000BFD1089B082B00F0A980042B00F0A9804D | ||
| 1226 | :104CA000A3F10203B3FA83F35B090493C4F8C4A12C | ||
| 1227 | :104CB000C4F840A1C4F8C4A16B6AC4F83031D4F878 | ||
| 1228 | :104CC00030219342F6D100234FF0FF30C4F82C314D | ||
| 1229 | :104CD000FFF77EFC002318466FF01B03C4F8003179 | ||
| 1230 | :104CE000FFF784FC049B4B4FC4F80C31D4F8040A42 | ||
| 1231 | :104CF00040F48060FFF77AFC0A23C4F838312B694E | ||
| 1232 | :104D000009A8A7FB03236A6A1B0902FB03F303EB51 | ||
| 1233 | :104D10004303DB039B09C4F8D831C4F82CA1DBF8AA | ||
| 1234 | :104D20000030089923F07F420B0243EA01631343EA | ||
| 1235 | :104D3000CBF8003000F0B2FB099B03F01A030343E9 | ||
| 1236 | :104D40007FF46AAFA7FB0637D4F81431B8EB970F9E | ||
| 1237 | :104D50000A93D4F818310B93D4F81C310C93D4F87F | ||
| 1238 | :104D600020310D93D4F824310E93D4F828310F93C9 | ||
| 1239 | :104D700001D1039B9BB9484618220AA9183EFFF7A8 | ||
| 1240 | :104D8000B5FC09F1180908F101089EB100F0C0FB5B | ||
| 1241 | :104D900000230993002D7FF433AF224839E74846BA | ||
| 1242 | :104DA0001A46F61A0AA9994408F10108FFF79EFC71 | ||
| 1243 | :104DB000002EEBD1069F079E6A6939463046FFF701 | ||
| 1244 | :104DC00069FEAA6940B94FF4806339463046FFF75F | ||
| 1245 | :104DD00093FE00283FF440AF00231A9A136018E7AF | ||
| 1246 | :104DE0002B6A002B3FF439AF0F4836E703230493B7 | ||
| 1247 | :104DF0005CE70223049359E70122294658460096AE | ||
| 1248 | :104E000008ABFFF7A7FD00283FF4D4AE25E700BFAD | ||
| 1249 | :104E100000108450ABAAAAAA020CF100310CF100D8 | ||
| 1250 | :104E2000300CF100350CF100320CF10030B4DDE94A | ||
| 1251 | :104E3000023402940024049DCDE9035430BCFFF7F2 | ||
| 1252 | :104E40009BBE00BF30B51546012487B005AB00936B | ||
| 1253 | :104E50000022CDE9015404ABFFF78EFE07B030BD50 | ||
| 1254 | :104E6000F0B587B0002966D01E46002B63D01446EB | ||
| 1255 | :104E7000002A60D0314F0D4638684FF0FF31FFF700 | ||
| 1256 | :104E80004FFC00284DD10020FFF77AFC002844D1C8 | ||
| 1257 | :104E90002B4800F03FFAD8B101204FF0FF35FFF763 | ||
| 1258 | :104EA0006FFC002835D14FF408712648FEF70EFF3D | ||
| 1259 | :104EB00004212548FEF70AFF21482821FEF706FFB6 | ||
| 1260 | :104EC0003868FFF735FC00282FD1284607B0F0BD21 | ||
| 1261 | :104ED0001C4A0346029205AA019204AA039000927A | ||
| 1262 | :104EE000174902461848FFF7A1FF03460028D3D10F | ||
| 1263 | :104EF00028461D46059B22469C4228BF1A46049917 | ||
| 1264 | :104F000032600831FFF7F2FB0120FFF739FC00287F | ||
| 1265 | :104F1000C9D00E48FFF79AFCC5E70D48FFF796FC8D | ||
| 1266 | :104F2000B6E70C48FFF792FCADE70B48FFF78EFCA5 | ||
| 1267 | :104F3000284607B0F0BD4FF0FF35C6E7D41000207B | ||
| 1268 | :104F40007C250020A425002078250020A85D0000F5 | ||
| 1269 | :104F5000885D0000705D00004C5E000010B50446E6 | ||
| 1270 | :104F600028B12046BDE81040F421FFF7C1BB04483A | ||
| 1271 | :104F7000FFF76CFC2046BDE81040F421FFF7B8BBFA | ||
| 1272 | :104F8000645E000010B1F421FEF7A0BE704700BFC0 | ||
| 1273 | :104F900008B521B1012908D06FF0360008BD012104 | ||
| 1274 | :104FA00000F058F80028F7D108BD022100F052F8AF | ||
| 1275 | :104FB0000028F9D0F0E700BF30B505468818B0F5F5 | ||
| 1276 | :104FC000801F0B461446A1B001D8802A0CD9B3F536 | ||
| 1277 | :104FD000801F17D922461946284600F07DF804465E | ||
| 1278 | :104FE00084B9204621B030BD6846FFF77FFB2246DA | ||
| 1279 | :104FF0006946284600F070F8802104466846FFF7AD | ||
| 1280 | :1050000077FBEDE76FF03604EBE700BF70B5E8B172 | ||
| 1281 | :105010000E46D9B1044600F031F80546B0B9236810 | ||
| 1282 | :10502000012B0BD0022B01D0284670BD1C2230462C | ||
| 1283 | :1050300004F10801FFF75AFB284670BD20223046D4 | ||
| 1284 | :1050400004F10801FFF752FB284670BD6FF03605EA | ||
| 1285 | :10505000EAE700BF78B138B50D46F0210446FFF706 | ||
| 1286 | :1050600047FB402320462560E36500F091FA0038B5 | ||
| 1287 | :1050700018BF012038BD0120704700BFF0B5056E94 | ||
| 1288 | :10508000A5B0044604AEE5B90023012701933046DC | ||
| 1289 | :105090006760294602AA009300F046FA10B1012089 | ||
| 1290 | :1050A00025B0F0BD2A46204602A900F099FA002852 | ||
| 1291 | :1050B000F5D1204600F0AAFB0028F0D1206625B0EB | ||
| 1292 | :1050C000F0BD802D2A46304628BF802204F16401BD | ||
| 1293 | :1050D000FFF70CFB256ED7E7002800F0AE802DE926 | ||
| 1294 | :1050E000F04F1446A5B0002A3DD00F46002949D004 | ||
| 1295 | :1050F000B2F5803F0546006E20D34FF6FF7805F1EC | ||
| 1296 | :10510000640AEB6D1A1AB2FBF3F103FB1122002AB9 | ||
| 1297 | :1051100065D18342B9464FF6FF7672D0B6FBF3FBFA | ||
| 1298 | :1051200003FB0BFBBBF1000F30D1002E45D1A4F5E2 | ||
| 1299 | :105130007F44FF3CB4F5803F4744E2D2EA6D161A43 | ||
| 1300 | :10514000B6FBF2F302FB1366A64228BF2646002EEA | ||
| 1301 | :1051500075D1824200F08D80B4FBF2F602FB06F6B8 | ||
| 1302 | :105160002EB9002C79D1002025B0BDE8F08F0023A6 | ||
| 1303 | :1051700031463846CDE9003302AA00F0D5F90028BF | ||
| 1304 | :1051800000F09580012025B0BDE8F08F002359463E | ||
| 1305 | :105190004846CDE9003302AA00F0C6F90028F1D153 | ||
| 1306 | :1051A0005A46284602A900F01BFA0028EAD1A6EBCD | ||
| 1307 | :1051B0000B06286ED944002EB9D019304946324624 | ||
| 1308 | :1051C00005EB8000FFF792FAA4F57F44286EFF3CC0 | ||
| 1309 | :1051D0003044B4F5803F4744286692D2AEE742455A | ||
| 1310 | :1051E00028BF4246164639465044FFF77FFA286EDC | ||
| 1311 | :1051F000EB6D3044834207EB06092866A8EB0606F0 | ||
| 1312 | :105200008CD1802B28BF802351461A4604A8FFF773 | ||
| 1313 | :105210006DFA0023E96D02AACDE9003304A800F07D | ||
| 1314 | :1052200083F90028AED12846EA6D02A900F0D8F92A | ||
| 1315 | :105230000028A7D1EB6D286670E70120704705F1C3 | ||
| 1316 | :105240006403394632461844FFF750FA286EEA6D77 | ||
| 1317 | :105250003044A41B374428667BE72B6E2246193363 | ||
| 1318 | :1052600005EB83003946FFF741FA2B6E23442B668A | ||
| 1319 | :1052700079E7802A28BF802205F1640104A8FFF79E | ||
| 1320 | :1052800035FA0023E96D04A8CDE9003302AA00F045 | ||
| 1321 | :105290004BF900287FF476AF2846EA6D02A900F0AA | ||
| 1322 | :1052A0009FF900287FF46EAFEA6D286654E7324616 | ||
| 1323 | :1052B000284602A900F094F900287FF463AF374430 | ||
| 1324 | :1052C000A41B4EE7F8B51C460546114816460F4686 | ||
| 1325 | :1052D000FFF744FE21460E48FFF75AFE044620B170 | ||
| 1326 | :1052E0000B48FFF74FFE2046F8BD3A4629460848CE | ||
| 1327 | :1052F000FFF762FE04460028F2D131460448FFF76A | ||
| 1328 | :1053000085FE04460248FFF73DFE2046F8BD00BF7B | ||
| 1329 | :10531000C42700201C2370B582B001A90546019363 | ||
| 1330 | :1053200000F032F8044638B9019B1C2B07D0144C0E | ||
| 1331 | :105330001C212846FFF7DCF9204602B070BDD5E9F4 | ||
| 1332 | :105340000112131E18BF0123003918BF01210126C5 | ||
| 1333 | :1053500028689B00EA6843EA4103002818BF43F02D | ||
| 1334 | :105360000103EE612AB9C5E90834002BE4D1054CEC | ||
| 1335 | :10537000DEE7204643F00803C5E9083402B070BDFB | ||
| 1336 | :10538000370CF0000E0CF0000346002866D0002910 | ||
| 1337 | :1053900064D00A681C2A61D14FF47F023B49D2F8DD | ||
| 1338 | :1053A000100C88425CD0D2F8101C013158D0D2F8D1 | ||
| 1339 | :1053B000101C4FF47F021960D2F8140C3449884253 | ||
| 1340 | :1053C00060D0D2F8141C01315CD0D2F8141C4FF418 | ||
| 1341 | :1053D0007F025960D2F8181C11F5947F4FD0D2F893 | ||
| 1342 | :1053E000181C01314BD0D2F8181C4FF47F02996081 | ||
| 1343 | :1053F000D2F81C0C274988423ED0D2F81C1C01313F | ||
| 1344 | :105400003AD0D2F81C1C4FF47F02D960D2F8001CAD | ||
| 1345 | :1054100070312FD0D2F8001C01312BD0D2F8001CF3 | ||
| 1346 | :105420004FF47F021961D2F8041CAF3120D0D2F8BA | ||
| 1347 | :10543000041C01311CD0D2F8041C4FF47F025961C6 | ||
| 1348 | :10544000D2F8080C144988420DD0D2F8081C01315A | ||
| 1349 | :1054500009D0D2F8082C00209A61704701207047CB | ||
| 1350 | :1054600040F6FC01A5E740F2373200209A61704710 | ||
| 1351 | :105470005121E2E79021D3E742F60411C3E740F659 | ||
| 1352 | :10548000D861B2E742F2D001A1E700BFFCF8FFFF0C | ||
| 1353 | :10549000D020FFFF0429FFFF37F3FFFF014608B5C7 | ||
| 1354 | :1054A0004FF48060FFF7AEF80022034BC3F8C82129 | ||
| 1355 | :1054B000C3F82C2108BD00BF001084500138072814 | ||
| 1356 | :1054C00005D8DFE800F0100E040A040404060748BB | ||
| 1357 | :1054D0007047CB6800204B6270478B6800204B629E | ||
| 1358 | :1054E00070474B68F6E70B68F4E700BF310CF1003A | ||
| 1359 | :1054F0000B6802E0082B0B6006D8026A13424FEAE1 | ||
| 1360 | :105500004303F7D00020704700487047310CF1008A | ||
| 1361 | :105510000022044B4FF48060C3F82C21C3F8C4214F | ||
| 1362 | :10552000FFF756B800108450F0B5002483B0B0F1F6 | ||
| 1363 | :10553000005F8DF8074025D38C468444BCF1804F32 | ||
| 1364 | :1055400004461FD817461D4601220DF1070300F03F | ||
| 1365 | :1055500097F90646B0B99DF80730099A3C603B714F | ||
| 1366 | :1055600092B14DB10246089928460DF1070300F0AB | ||
| 1367 | :1055700087F938B99DF807303046099A15601371DC | ||
| 1368 | :1055800003B0F0BD4FF47506304603B0F0BD00BF68 | ||
| 1369 | :10559000D8B108B50368012B04D0022B0FD043B15A | ||
| 1370 | :1055A0000B4808BD20220B490830FFF79FF8002068 | ||
| 1371 | :1055B00008BD142208490830FFF798F8F7E72022C1 | ||
| 1372 | :1055C00006490830FFF792F8F1E74FF4730070478F | ||
| 1373 | :1055D0000100F300745E0000B45E0000945E000001 | ||
| 1374 | :1055E0002DE9F843002900F0F9800446002800F076 | ||
| 1375 | :1055F000F98003680F469046002B00F0C380013B02 | ||
| 1376 | :10560000012B00F2D7804FF0FF3178484FF00209AC | ||
| 1377 | :10561000FFF786F8002840F0BF800020FFF7B0F8C1 | ||
| 1378 | :105620000646002840F0C280714AD2F81C39002B8F | ||
| 1379 | :10563000FBD16F4DD5F8203C002BFBD14FF0FF3054 | ||
| 1380 | :10564000FEF7C6FFD5F8040A20F04000FEF7CEFFB3 | ||
| 1381 | :1056500001230722C5F81838C5F80029C5F8C43752 | ||
| 1382 | :10566000A36CC5F8CC37E36CC5F8D037C5F8C09744 | ||
| 1383 | :1056700023685BB1013B012B18D8636AC5F85C361F | ||
| 1384 | :10568000236AC5F85836E369C5F85436A269584B01 | ||
| 1385 | :10569000C3F850266269C3F84C262269C3F848262D | ||
| 1386 | :1056A000E268C3F84426A268C3F84026504AD2F8FC | ||
| 1387 | :1056B0001039002BFBD1B8F1000F5FD06368402098 | ||
| 1388 | :1056C000012B08BFC2F884363A68494BC3F8282C2E | ||
| 1389 | :1056D000C3F82C8CFEF790FF0646454AD2F81039E5 | ||
| 1390 | :1056E000002BFBD1424AD2F8203C002BFBD123688F | ||
| 1391 | :1056F0005BB1013B012B18D8D2F85C366362D2F85B | ||
| 1392 | :1057000058362362D2F85436E361394BD3F8502629 | ||
| 1393 | :10571000A261D3F84C266261D3F848262261D3F8FF | ||
| 1394 | :105720004426E260D3F84036A36000230121304ACA | ||
| 1395 | :10573000D2F8CC07A064D2F8D007E064C2F8C4174E | ||
| 1396 | :10574000C2F88436C2F8C837D2F81039002BFBD122 | ||
| 1397 | :10575000C2F81838002E3BD1254BD3F8040A40F08C | ||
| 1398 | :105760004000FEF743FF0120FFF70AF860BB1F4827 | ||
| 1399 | :10577000FEF7DEFF10BB3046BDE8F8830423C2F815 | ||
| 1400 | :10578000C837AAE74FF0FF3118484FF00109FEF77C | ||
| 1401 | :10579000C7FF00283FF441AF1648FFF757F8002035 | ||
| 1402 | :1057A000FEF7EEFF064600283FF43EAF1248FFF733 | ||
| 1403 | :1057B0004DF839E7114E3046BDE8F8831048FFF741 | ||
| 1404 | :1057C00045F83046BDE8F8830E48FFF73FF8CEE7CE | ||
| 1405 | :1057D000102104F10800FEF78BFFBDE70A4E3046AA | ||
| 1406 | :1057E000BDE8F8834FF47306C5E700BFE41000205E | ||
| 1407 | :1057F00000108450705D0000885D00000100F3001F | ||
| 1408 | :10580000C85D0000A85D00000300F300A0B30346DC | ||
| 1409 | :1058100070B4D0E90240D3E9041226BA05BA0CBA32 | ||
| 1410 | :1058200010BAC3E90440D3E90612986A09BAC3E979 | ||
| 1411 | :10583000026512BA996100BAD3E9084125BA0CBAD7 | ||
| 1412 | :10584000C3E90725D3E90B12C3E9094009BAD86BAC | ||
| 1413 | :1058500012BAD962D3E90D4125BAC3E90C250CBAB5 | ||
| 1414 | :1058600000BAD3E9101209BA12BAC3E90E4019649A | ||
| 1415 | :1058700000205A6470BC70474FF47300704700BF3B | ||
| 1416 | :1058800000201870704700BF431810B501D21F2ABE | ||
| 1417 | :1058900001D9002010BD013902F014030144102B7E | ||
| 1418 | :1058A00080EA01043CD009DC8BB1042BF1D11F2C20 | ||
| 1419 | :1058B00040E840F315D941E840F10EE0142BE8D15F | ||
| 1420 | :1058C0001F2C40E8C0F30CD941E8C0F105E01F2CC3 | ||
| 1421 | :1058D00040E800F305D941E800F11C460B468C4234 | ||
| 1422 | :1058E000D7D122F01402013A0A2AD2D801A151F8E4 | ||
| 1423 | :1058F00022F000BF435900003D5900002F5900001D | ||
| 1424 | :1059000093580000935800009358000093580000EB | ||
| 1425 | :105910004959000043590000375900002F59000031 | ||
| 1426 | :105920001F2C40E880F3DCD941E880F1D5E713F47F | ||
| 1427 | :10593000001FAFD1ADE713F4801FFAE75B02A9D5D2 | ||
| 1428 | :10594000A7E713F4002FF4E713F4802FF1E700BF6B | ||
| 1429 | :1059500008B5074B044613B10021AFF30080054B97 | ||
| 1430 | :105960001868836A03B19847204600F029F800BF01 | ||
| 1431 | :1059700000000000C85E000070B50D4D00260D4C03 | ||
| 1432 | :10598000641BA410A64209D10B4D00260B4C00F05D | ||
| 1433 | :10599000D5F9641BA410A64205D170BD55F8043B8F | ||
| 1434 | :1059A00001369847EEE755F8043B01369847F2E791 | ||
| 1435 | :1059B000A0110020A0110020A0110020A41100209F | ||
| 1436 | :1059C000FEE700BFB7EE000AF7EE000AB7EE001AD6 | ||
| 1437 | :1059D000F7EE001AB7EE002AF7EE002AB7EE003A0B | ||
| 1438 | :1059E000F7EE003AB7EE004AF7EE004AB7EE005A7B | ||
| 1439 | :1059F000F7EE005AB7EE006AF7EE006AB7EE007AEB | ||
| 1440 | :105A0000F7EE007AF1EE10CA40F29F01CFF20001EA | ||
| 1441 | :105A10003CEA010CE1EE10CA002383F300887047D2 | ||
| 1442 | :105A2000FDF79CBAEFF30880EFF309812DE9F00F41 | ||
| 1443 | :105A30006B467246FAF7ACFF08B0FFF7F1FFFEE7DE | ||
| 1444 | :105A4000FDF78CBAEFF30880EFF309812DE9F00F31 | ||
| 1445 | :105A50006B467246FAF79CFF08B0FFF7F1FFFEE7CE | ||
| 1446 | :105A6000FDF77CBAEFF30880EFF309812DE9F00F21 | ||
| 1447 | :105A70006B467246FAF78CFF08B0FFF7F1FFFEE7BE | ||
| 1448 | :105A8000FDF76CBAEFF30880EFF309812DE9F00F11 | ||
| 1449 | :105A90006B467246FAF77CFF08B0FFF7F1FFFEE7AE | ||
| 1450 | :105AA000FDF75CBAEFF30880EFF309812DE9F00F01 | ||
| 1451 | :105AB0006B467246FAF76CFF08B0FFF7F1FFFEE79E | ||
| 1452 | :105AC000814270B40546144602D370BC00F02EB873 | ||
| 1453 | :105AD000821821443CB141EA020313F003030FD1C1 | ||
| 1454 | :105AE000E018032812D86FF00300A30843430020F6 | ||
| 1455 | :105AF00019441A442344984210D1284670BC704778 | ||
| 1456 | :105B000011F8013D013C02F8013DE3E7581850F857 | ||
| 1457 | :105B1000046C981840F8046C043BE1E70C1A14F884 | ||
| 1458 | :105B2000016C141A04F8016C0130E4E770B5044606 | ||
| 1459 | :105B30003AB141EA040313F003030CD1D518032D45 | ||
| 1460 | :105B40000FD822F003031C441944002302F003027F | ||
| 1461 | :105B500093420CD170BD11F8013B013A04F8013BAE | ||
| 1462 | :105B6000E6E7CD1A2E68E51A2E60043BE6E75D5C99 | ||
| 1463 | :105B7000E5540133ECE7F0B5044662B922F00303C3 | ||
| 1464 | :105B8000234402F003021A44934214D1F0BD04F8F6 | ||
| 1465 | :105B9000011B013AF1E7A307F9D115460B0443EACB | ||
| 1466 | :105BA00001630B4343EA01231619032DE6D9771B42 | ||
| 1467 | :105BB0003B60043DF9E703F8011BE5E708B5EFF3A7 | ||
| 1468 | :105BC0000583C3F308030BB1FDF7C8F9BDE808402E | ||
| 1469 | :105BD000FDF74CBA10B50446EFF30583C3F3080391 | ||
| 1470 | :105BE0000BB1FDF7BBF92046BDE81040FDF741BA07 | ||
| 1471 | :105BF0002DE9F04104460D4616461F46EFF3058396 | ||
| 1472 | :105C0000C3F308030BB1FDF7A9F93B463246294619 | ||
| 1473 | :105C10002046BDE8F041FCF743BC2DE9F0410446C5 | ||
| 1474 | :105C20000D4616461F46EFF30583C3F308030BB179 | ||
| 1475 | :105C3000FDF794F93B46324629462046BDE8F0413F | ||
| 1476 | :105C4000FCF768BC08B5EFF30583C3F308030BB199 | ||
| 1477 | :105C5000FDF784F9BDE80840FDF7DBB90020704787 | ||
| 1478 | :105C6000704710B5044608B1FDF75AFF2046BDE85D | ||
| 1479 | :105C70001040FDF745BF10B50446406A10B1A16A57 | ||
| 1480 | :105C8000FFF7EFFF0020C4E9090010BD38B5044656 | ||
| 1481 | :105C9000FFF7F1FF236A2C22012B0CBF05466FF0A2 | ||
| 1482 | :105CA000960500212046FFF766FF284638BD0020F4 | ||
| 1483 | :105CB000704770470020704713B5002001AB1446B1 | ||
| 1484 | :105CC000FDF7E2FF30B9019BA34218BF6FF09300CC | ||
| 1485 | :105CD00002B010BD6FF09200FAE7002070472DE986 | ||
| 1486 | :105CE000E04F2746A046A146A246A346A4462DED76 | ||
| 1487 | :105CF000108B4FF0000545EC185B45EC195A45EC4C | ||
| 1488 | :105D00001A5A45EC1B5A45EC1C5A45EC1D5A45ECF9 | ||
| 1489 | :105D10001E5A45EC1F5AF1EE105A4FF66076C0F647 | ||
| 1490 | :105D2000FF763540E1EE105A84F30088254626467A | ||
| 1491 | :105D3000A447BDEC108BBDE8E08F0000F8B500BFB4 | ||
| 1492 | :105D4000F8BC08BC9E467047F8B500BFF8BC08BC5C | ||
| 1493 | :105D50009E467047FF8FFFFFFF8FFFFFFE8FFFFF05 | ||
| 1494 | :105D6000FE8FFFFFFD8FFFFFFC8FFFFFFC8FFFFF0C | ||
| 1495 | :105D70004661696C20746F2061637175697265207A | ||
| 1496 | :105D80006D757465780A00004661696C20746F2037 | ||
| 1497 | :105D9000696E63726561736520504D20636F756E27 | ||
| 1498 | :105DA0007465720A000000004661696C20746F20FF | ||
| 1499 | :105DB000646563726561736520504D20636F756E15 | ||
| 1500 | :105DC0007465720A000000004661696C20746F20DF | ||
| 1501 | :105DD00072656C65617365206D757465780A000085 | ||
| 1502 | :105DE000436F756C64206E6F74206C6F636B2070F2 | ||
| 1503 | :105DF0006F7765722073617665206D7574657800C4 | ||
| 1504 | :105E00006D757465785F667265652063616C6C653D | ||
| 1505 | :105E1000642077697468204E554C4C207061726123 | ||
| 1506 | :105E20006D6574657200000043616E277420696EB1 | ||
| 1507 | :105E3000697469616C697A65206D757465782C2068 | ||
| 1508 | :105E4000776173204E554C4C0D0A00004661696C19 | ||
| 1509 | :105E500020746F20756E6C6F636B206D7574657840 | ||
| 1510 | :105E60000A0000000A637478206973204E554C4C78 | ||
| 1511 | :105E70000A00000067E6096A85AE67BB72F36E3CF4 | ||
| 1512 | :105E80003AF54FA57F520E518C68059BABD9831F05 | ||
| 1513 | :105E900019CDE05BD89E05C107D57C3617DD703083 | ||
| 1514 | :105EA00039590EF7310BC0FF11155868A78FF964E7 | ||
| 1515 | :105EB000A44FFABE0123456789ABCDEFFEDCBA984B | ||
| 1516 | :105EC00076543210F0E1D2C34011002054464D5FA9 | ||
| 1517 | :105ED00043525950544F0054464D5F504C41544624 | ||
| 1518 | :105EE0004F524D5F53455256494345000000000054 | ||
| 1519 | :105EF00000000000000000000000000000000000A2 | ||
| 1520 | :107C00007FE97FE9FBF72CBD7FE97FE9FBF737BD13 | ||
| 1521 | :107C10007FE97FE9FBF75FBD7FE97FE9FBF752BDB5 | ||
| 1522 | :107C20007FE97FE9FBF73ABD00000000000000009B | ||
| 1523 | :107C30000000000000000000000000000000000044 | ||
| 1524 | :107C40007AFFFFFF00900050000000008C3400001D | ||
| 1525 | :107C50000400000000000000000000000000000020 | ||
| 1526 | :107C6000000000000000000090ED00E000A00350C4 | ||
| 1527 | :107C70007FA60350009000506F9500501412002012 | ||
| 1528 | :107C8000A811002044010000615C00005D5C000060 | ||
| 1529 | :107C9000775B0000DC1000200C1100200411002094 | ||
| 1530 | :107CA00000110020FC1000201D48000011480000B9 | ||
| 1531 | :107CB000054800000000000029480000381100209D | ||
| 1532 | :107CC00030110020281100200000000020110020A9 | ||
| 1533 | :107CD0003549000081480000B5480000FD4800001B | ||
| 1534 | :107CE000682500203A00003A6C2500203A00003A4E | ||
| 1535 | :107CF000702500203A00003A742500203A00003A2E | ||
| 1536 | :107D00000000000000000000000000000000000073 | ||
| 1537 | :107D10000000000000000000000000000000000063 | ||
| 1538 | :107D20000000000000000000000000000000000053 | ||
| 1539 | :107D30000000000000000000000000000000000043 | ||
| 1540 | :107D40000000000000000000000000000000000033 | ||
| 1541 | :107D50000000000000000000000000000000000023 | ||
| 1542 | :087D6000553700002D3700002B | ||
| 1543 | :00000001FF | ||
diff --git a/examples/nrf9151/s/.cargo/config.toml b/examples/nrf9151/s/.cargo/config.toml new file mode 100644 index 000000000..f64c63966 --- /dev/null +++ b/examples/nrf9151/s/.cargo/config.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | runner = "probe-rs run --chip nRF9160_xxAA" | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv8m.main-none-eabihf" | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_LOG = "trace" | ||
diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml new file mode 100644 index 000000000..7253fc4be --- /dev/null +++ b/examples/nrf9151/s/Cargo.toml | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-nrf9151-secure-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 9 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | ||
| 10 | embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | ||
| 11 | |||
| 12 | defmt = "0.3" | ||
| 13 | defmt-rtt = "0.4" | ||
| 14 | |||
| 15 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 16 | cortex-m-rt = "0.7.0" | ||
| 17 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 18 | |||
| 19 | [profile.release] | ||
| 20 | debug = 2 | ||
diff --git a/examples/nrf9151/s/build.rs b/examples/nrf9151/s/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf9151/s/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/nrf9151/s/memory.x b/examples/nrf9151/s/memory.x new file mode 100644 index 000000000..4c7d4ebf0 --- /dev/null +++ b/examples/nrf9151/s/memory.x | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1024K | ||
| 4 | RAM : ORIGIN = 0x20018000, LENGTH = 160K | ||
| 5 | } | ||
diff --git a/examples/nrf9151/s/src/bin/blinky.rs b/examples/nrf9151/s/src/bin/blinky.rs new file mode 100644 index 000000000..7457a95a3 --- /dev/null +++ b/examples/nrf9151/s/src/bin/blinky.rs | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 6 | use embassy_time::Timer; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = embassy_nrf::init(Default::default()); | ||
| 12 | let mut led = Output::new(p.P0_00, Level::Low, OutputDrive::Standard); | ||
| 13 | |||
| 14 | loop { | ||
| 15 | led.set_high(); | ||
| 16 | defmt::info!("high"); | ||
| 17 | Timer::after_millis(500).await; | ||
| 18 | led.set_low(); | ||
| 19 | defmt::info!("low"); | ||
| 20 | Timer::after_millis(1000).await; | ||
| 21 | } | ||
| 22 | } | ||
diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml index 1444b0cd1..6072b8595 100644 --- a/examples/nrf9160/.cargo/config.toml +++ b/examples/nrf9160/.cargo/config.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 2 | # replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` | 2 | # runner = "probe-rs run --chip nRF9160_xxAA" |
| 3 | runner = "probe-rs run --chip nRF9160_xxAA" | 3 | runner = [ "probe-rs", "run", "--chip=nRF9160_xxAA", "--always-print-stacktrace", "--log-format={t} {[{L}]%bold} {s} {{c} {ff}:{l:1}%dimmed}" ] |
| 4 | 4 | ||
| 5 | [build] | 5 | [build] |
| 6 | target = "thumbv8m.main-none-eabihf" | 6 | target = "thumbv8m.main-none-eabihf" |
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index af2385960..9aeb99317 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml | |||
| @@ -5,16 +5,22 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 9 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 11 | embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } | ||
| 12 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } | ||
| 11 | 13 | ||
| 12 | defmt = "0.3" | 14 | defmt = "0.3" |
| 13 | defmt-rtt = "0.4" | 15 | defmt-rtt = "0.4" |
| 14 | 16 | ||
| 17 | heapless = "0.8" | ||
| 15 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 16 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 17 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 21 | static_cell = { version = "2" } | ||
| 22 | embedded-io = "0.6.1" | ||
| 23 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | ||
| 18 | 24 | ||
| 19 | [profile.release] | 25 | [profile.release] |
| 20 | debug = 2 | 26 | 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 @@ | |||
| 1 | MEMORY | 1 | MEMORY |
| 2 | { | 2 | { |
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1024K | 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1024K |
| 4 | RAM : ORIGIN = 0x20018000, LENGTH = 160K | 4 | RAM : ORIGIN = 0x20010000, LENGTH = 192K |
| 5 | IPC : ORIGIN = 0x20000000, LENGTH = 64K | ||
| 5 | } | 6 | } |
| 7 | |||
| 8 | PROVIDE(__start_ipc = ORIGIN(IPC)); | ||
| 9 | 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..929883884 --- /dev/null +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | use core::net::IpAddr; | ||
| 6 | use core::ptr::addr_of_mut; | ||
| 7 | use core::slice; | ||
| 8 | use core::str::FromStr; | ||
| 9 | |||
| 10 | use defmt::{info, unwrap, warn}; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; | ||
| 13 | use embassy_net_nrf91::context::Status; | ||
| 14 | use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; | ||
| 15 | use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; | ||
| 16 | use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; | ||
| 17 | use embassy_nrf::uarte::Baudrate; | ||
| 18 | use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; | ||
| 19 | use embassy_time::{Duration, Timer}; | ||
| 20 | use embedded_io_async::Write; | ||
| 21 | use heapless::Vec; | ||
| 22 | use static_cell::StaticCell; | ||
| 23 | use {defmt_rtt as _, panic_probe as _}; | ||
| 24 | |||
| 25 | #[interrupt] | ||
| 26 | fn IPC() { | ||
| 27 | embassy_net_nrf91::on_ipc_irq(); | ||
| 28 | } | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::task] | ||
| 35 | async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! { | ||
| 36 | let mut rx = [0u8; 1024]; | ||
| 37 | loop { | ||
| 38 | let n = reader.read(&mut rx[..]).await; | ||
| 39 | unwrap!(uart.write_all(&rx[..n]).await); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | #[embassy_executor::task] | ||
| 44 | async fn modem_task(runner: Runner<'static>) -> ! { | ||
| 45 | runner.run().await | ||
| 46 | } | ||
| 47 | |||
| 48 | #[embassy_executor::task] | ||
| 49 | async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_nrf91::NetDriver<'static>>) -> ! { | ||
| 50 | runner.run().await | ||
| 51 | } | ||
| 52 | |||
| 53 | #[embassy_executor::task] | ||
| 54 | async fn control_task( | ||
| 55 | control: &'static context::Control<'static>, | ||
| 56 | config: context::Config<'static>, | ||
| 57 | stack: Stack<'static>, | ||
| 58 | ) { | ||
| 59 | unwrap!(control.configure(&config).await); | ||
| 60 | unwrap!( | ||
| 61 | control | ||
| 62 | .run(|status| { | ||
| 63 | stack.set_config_v4(status_to_config(status)); | ||
| 64 | }) | ||
| 65 | .await | ||
| 66 | ); | ||
| 67 | } | ||
| 68 | |||
| 69 | fn status_to_config(status: &Status) -> embassy_net::ConfigV4 { | ||
| 70 | let Some(IpAddr::V4(addr)) = status.ip else { | ||
| 71 | panic!("Unexpected IP address"); | ||
| 72 | }; | ||
| 73 | let addr = Ipv4Address(addr.octets()); | ||
| 74 | |||
| 75 | let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { | ||
| 76 | Some(Ipv4Address(addr.octets())) | ||
| 77 | } else { | ||
| 78 | None | ||
| 79 | }; | ||
| 80 | |||
| 81 | let mut dns_servers = Vec::new(); | ||
| 82 | for dns in status.dns.iter() { | ||
| 83 | if let IpAddr::V4(ip) = dns { | ||
| 84 | unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { | ||
| 89 | address: Ipv4Cidr::new(addr, 32), | ||
| 90 | gateway, | ||
| 91 | dns_servers, | ||
| 92 | }) | ||
| 93 | } | ||
| 94 | |||
| 95 | #[embassy_executor::task] | ||
| 96 | async fn blink_task(pin: AnyPin) { | ||
| 97 | let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); | ||
| 98 | loop { | ||
| 99 | led.set_high(); | ||
| 100 | Timer::after_millis(1000).await; | ||
| 101 | led.set_low(); | ||
| 102 | Timer::after_millis(1000).await; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | extern "C" { | ||
| 107 | static __start_ipc: u8; | ||
| 108 | static __end_ipc: u8; | ||
| 109 | } | ||
| 110 | |||
| 111 | #[embassy_executor::main] | ||
| 112 | async fn main(spawner: Spawner) { | ||
| 113 | let p = embassy_nrf::init(Default::default()); | ||
| 114 | |||
| 115 | info!("Hello World!"); | ||
| 116 | |||
| 117 | unwrap!(spawner.spawn(blink_task(p.P0_02.degrade()))); | ||
| 118 | |||
| 119 | let ipc_mem = unsafe { | ||
| 120 | let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit<u8>; | ||
| 121 | let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit<u8>; | ||
| 122 | let ipc_len = ipc_end.offset_from(ipc_start) as usize; | ||
| 123 | slice::from_raw_parts_mut(ipc_start, ipc_len) | ||
| 124 | }; | ||
| 125 | |||
| 126 | static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; | ||
| 127 | let mut config = uarte::Config::default(); | ||
| 128 | config.baudrate = Baudrate::BAUD1M; | ||
| 129 | let uart = BufferedUarteTx::new( | ||
| 130 | //let trace_uart = BufferedUarteTx::new( | ||
| 131 | unsafe { peripherals::SERIAL0::steal() }, | ||
| 132 | Irqs, | ||
| 133 | unsafe { peripherals::P0_01::steal() }, | ||
| 134 | //unsafe { peripherals::P0_14::steal() }, | ||
| 135 | config, | ||
| 136 | unsafe { &mut *addr_of_mut!(TRACE_BUF) }, | ||
| 137 | ); | ||
| 138 | |||
| 139 | static STATE: StaticCell<State> = StaticCell::new(); | ||
| 140 | static TRACE: StaticCell<TraceBuffer> = StaticCell::new(); | ||
| 141 | let (device, control, runner, tracer) = | ||
| 142 | embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await; | ||
| 143 | unwrap!(spawner.spawn(modem_task(runner))); | ||
| 144 | unwrap!(spawner.spawn(trace_task(uart, tracer))); | ||
| 145 | |||
| 146 | let config = embassy_net::Config::default(); | ||
| 147 | |||
| 148 | // Generate "random" seed. nRF91 has no RNG, TODO figure out something... | ||
| 149 | let seed = 123456; | ||
| 150 | |||
| 151 | // Init network stack | ||
| 152 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | ||
| 153 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::<2>::new()), seed); | ||
| 154 | |||
| 155 | unwrap!(spawner.spawn(net_task(runner))); | ||
| 156 | |||
| 157 | static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new(); | ||
| 158 | let control = CONTROL.init(context::Control::new(control, 0).await); | ||
| 159 | |||
| 160 | unwrap!(spawner.spawn(control_task( | ||
| 161 | control, | ||
| 162 | context::Config { | ||
| 163 | apn: b"iot.nat.es", | ||
| 164 | auth_prot: context::AuthProt::Pap, | ||
| 165 | auth: Some((b"orange", b"orange")), | ||
| 166 | }, | ||
| 167 | stack | ||
| 168 | ))); | ||
| 169 | |||
| 170 | stack.wait_config_up().await; | ||
| 171 | |||
| 172 | let mut rx_buffer = [0; 4096]; | ||
| 173 | let mut tx_buffer = [0; 4096]; | ||
| 174 | loop { | ||
| 175 | let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 176 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 177 | |||
| 178 | info!("Connecting..."); | ||
| 179 | let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); | ||
| 180 | if let Err(e) = socket.connect((host_addr, 4242)).await { | ||
| 181 | warn!("connect error: {:?}", e); | ||
| 182 | Timer::after_secs(10).await; | ||
| 183 | continue; | ||
| 184 | } | ||
| 185 | info!("Connected to {:?}", socket.remote_endpoint()); | ||
| 186 | |||
| 187 | let msg = b"Hello world!\n"; | ||
| 188 | for _ in 0..10 { | ||
| 189 | if let Err(e) = socket.write_all(msg).await { | ||
| 190 | warn!("write error: {:?}", e); | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | info!("txd: {}", core::str::from_utf8(msg).unwrap()); | ||
| 194 | Timer::after_secs(1).await; | ||
| 195 | } | ||
| 196 | Timer::after_secs(4).await; | ||
| 197 | } | ||
| 198 | } | ||
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index e1092dba4..04b4c6317 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -6,29 +6,37 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | [dependencies] | 8 | [dependencies] |
| 9 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } | 9 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } | 13 | embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | 15 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } |
| 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 18 | embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } | 18 | embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } |
| 19 | cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } | 19 | cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } |
| 20 | cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } | 20 | cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } |
| 21 | 21 | ||
| 22 | defmt = "0.3" | 22 | defmt = "0.3" |
| 23 | defmt-rtt = "0.4" | 23 | defmt-rtt = "0.4" |
| 24 | fixed = "1.23.1" | 24 | fixed = "1.23.1" |
| 25 | fixed-macro = "1.2" | 25 | fixed-macro = "1.2" |
| 26 | 26 | ||
| 27 | # for web request example | ||
| 28 | reqwless = { version = "0.12.0", features = ["defmt",]} | ||
| 29 | serde = { version = "1.0.203", default-features = false, features = ["derive"] } | ||
| 30 | serde-json-core = "0.5.1" | ||
| 31 | |||
| 32 | # for assign resources example | ||
| 33 | assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } | ||
| 34 | |||
| 27 | #cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 35 | #cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 28 | cortex-m = { version = "0.7.6", features = ["inline-asm"] } | 36 | cortex-m = { version = "0.7.6", features = ["inline-asm"] } |
| 29 | cortex-m-rt = "0.7.0" | 37 | cortex-m-rt = "0.7.0" |
| 38 | critical-section = "1.1" | ||
| 30 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 39 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 31 | futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } | ||
| 32 | display-interface-spi = "0.4.1" | 40 | display-interface-spi = "0.4.1" |
| 33 | embedded-graphics = "0.7.1" | 41 | embedded-graphics = "0.7.1" |
| 34 | st7789 = "0.6.1" | 42 | st7789 = "0.6.1" |
| @@ -36,19 +44,39 @@ display-interface = "0.4.1" | |||
| 36 | byte-slice-cast = { version = "1.2.0", default-features = false } | 44 | byte-slice-cast = { version = "1.2.0", default-features = false } |
| 37 | smart-leds = "0.3.0" | 45 | smart-leds = "0.3.0" |
| 38 | heapless = "0.8" | 46 | heapless = "0.8" |
| 39 | usbd-hid = "0.6.1" | 47 | usbd-hid = "0.8.1" |
| 40 | 48 | ||
| 41 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | 49 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } |
| 42 | embedded-hal-async = "1.0" | 50 | embedded-hal-async = "1.0" |
| 43 | embedded-hal-bus = { version = "0.1", features = ["async"] } | 51 | embedded-hal-bus = { version = "0.1", features = ["async"] } |
| 44 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | 52 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } |
| 45 | embedded-storage = { version = "0.3" } | 53 | embedded-storage = { version = "0.3" } |
| 46 | static_cell = "2" | 54 | static_cell = "2.1" |
| 47 | portable-atomic = { version = "1.5", features = ["critical-section"] } | 55 | portable-atomic = { version = "1.5", features = ["critical-section"] } |
| 48 | log = "0.4" | 56 | log = "0.4" |
| 49 | pio-proc = "0.2" | 57 | pio-proc = "0.2" |
| 50 | pio = "0.2.1" | 58 | pio = "0.2.1" |
| 51 | rand = { version = "0.8.5", default-features = false } | 59 | rand = { version = "0.8.5", default-features = false } |
| 60 | embedded-sdmmc = "0.7.0" | ||
| 61 | |||
| 62 | bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } | ||
| 63 | trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } | ||
| 52 | 64 | ||
| 53 | [profile.release] | 65 | [profile.release] |
| 54 | debug = 2 | 66 | debug = 2 |
| 67 | lto = true | ||
| 68 | opt-level = 'z' | ||
| 69 | |||
| 70 | [profile.dev] | ||
| 71 | debug = 2 | ||
| 72 | lto = true | ||
| 73 | opt-level = "z" | ||
| 74 | |||
| 75 | [patch.crates-io] | ||
| 76 | trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } | ||
| 77 | embassy-executor = { path = "../../embassy-executor" } | ||
| 78 | embassy-sync = { path = "../../embassy-sync" } | ||
| 79 | embassy-futures = { path = "../../embassy-futures" } | ||
| 80 | embassy-time = { path = "../../embassy-time" } | ||
| 81 | embassy-time-driver = { path = "../../embassy-time-driver" } | ||
| 82 | embassy-embedded-hal = { path = "../../embassy-embedded-hal" } | ||
diff --git a/examples/rp/src/bin/adc_dma.rs b/examples/rp/src/bin/adc_dma.rs new file mode 100644 index 000000000..f755cf5bf --- /dev/null +++ b/examples/rp/src/bin/adc_dma.rs | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | //! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads. | ||
| 2 | //! For multichannel, the samples are interleaved in the buffer: | ||
| 3 | //! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]` | ||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::gpio::Pull; | ||
| 12 | use embassy_time::{Duration, Ticker}; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) { | ||
| 21 | let p = embassy_rp::init(Default::default()); | ||
| 22 | info!("Here we go!"); | ||
| 23 | |||
| 24 | let mut adc = Adc::new(p.ADC, Irqs, Config::default()); | ||
| 25 | let mut dma = p.DMA_CH0; | ||
| 26 | let mut pin = Channel::new_pin(p.PIN_26, Pull::Up); | ||
| 27 | let mut pins = [ | ||
| 28 | Channel::new_pin(p.PIN_27, Pull::Down), | ||
| 29 | Channel::new_pin(p.PIN_28, Pull::None), | ||
| 30 | Channel::new_pin(p.PIN_29, Pull::Up), | ||
| 31 | Channel::new_temp_sensor(p.ADC_TEMP_SENSOR), | ||
| 32 | ]; | ||
| 33 | |||
| 34 | const BLOCK_SIZE: usize = 100; | ||
| 35 | const NUM_CHANNELS: usize = 4; | ||
| 36 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 37 | loop { | ||
| 38 | // Read 100 samples from a single channel | ||
| 39 | let mut buf = [0_u16; BLOCK_SIZE]; | ||
| 40 | let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) | ||
| 41 | adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); | ||
| 42 | info!("single: {:?} ...etc", buf[..8]); | ||
| 43 | |||
| 44 | // Read 100 samples from 4 channels interleaved | ||
| 45 | let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; | ||
| 46 | let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) | ||
| 47 | adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) | ||
| 48 | .await | ||
| 49 | .unwrap(); | ||
| 50 | info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); | ||
| 51 | |||
| 52 | ticker.next().await; | ||
| 53 | } | ||
| 54 | } | ||
diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs new file mode 100644 index 000000000..ff6eff4a2 --- /dev/null +++ b/examples/rp/src/bin/assign_resources.rs | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | //! This example demonstrates how to assign resources to multiple tasks by splitting up the peripherals. | ||
| 2 | //! 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) | ||
| 3 | //! Of course splitting up resources and sharing resources can be combined, yet this example is only about splitting up resources. | ||
| 4 | //! | ||
| 5 | //! There are basically two ways we demonstrate here: | ||
| 6 | //! 1) Assigning resources to a task by passing parts of the peripherals | ||
| 7 | //! 2) Assigning resources to a task by passing a struct with the split up peripherals, using the assign-resources macro | ||
| 8 | //! | ||
| 9 | //! using four LEDs on Pins 10, 11, 20 and 21 | ||
| 10 | |||
| 11 | #![no_std] | ||
| 12 | #![no_main] | ||
| 13 | |||
| 14 | use assign_resources::assign_resources; | ||
| 15 | use defmt::*; | ||
| 16 | use embassy_executor::Spawner; | ||
| 17 | use embassy_rp::gpio::{Level, Output}; | ||
| 18 | use embassy_rp::peripherals::{self, PIN_20, PIN_21}; | ||
| 19 | use embassy_time::Timer; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | #[embassy_executor::main] | ||
| 23 | async fn main(spawner: Spawner) { | ||
| 24 | // initialize the peripherals | ||
| 25 | let p = embassy_rp::init(Default::default()); | ||
| 26 | |||
| 27 | // 1) Assigning a resource to a task by passing parts of the peripherals. | ||
| 28 | spawner | ||
| 29 | .spawn(double_blinky_manually_assigned(spawner, p.PIN_20, p.PIN_21)) | ||
| 30 | .unwrap(); | ||
| 31 | |||
| 32 | // 2) Using the assign-resources macro to assign resources to a task. | ||
| 33 | // we perform the split, see further below for the definition of the resources struct | ||
| 34 | let r = split_resources!(p); | ||
| 35 | // and then we can use them | ||
| 36 | spawner.spawn(double_blinky_macro_assigned(spawner, r.leds)).unwrap(); | ||
| 37 | } | ||
| 38 | |||
| 39 | // 1) Assigning a resource to a task by passing parts of the peripherals. | ||
| 40 | #[embassy_executor::task] | ||
| 41 | async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { | ||
| 42 | let mut led_20 = Output::new(pin_20, Level::Low); | ||
| 43 | let mut led_21 = Output::new(pin_21, Level::High); | ||
| 44 | |||
| 45 | loop { | ||
| 46 | info!("toggling leds"); | ||
| 47 | led_20.toggle(); | ||
| 48 | led_21.toggle(); | ||
| 49 | Timer::after_secs(1).await; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | // 2) Using the assign-resources macro to assign resources to a task. | ||
| 54 | // first we define the resources we want to assign to the task using the assign_resources! macro | ||
| 55 | // basically this will split up the peripherals struct into smaller structs, that we define here | ||
| 56 | // naming is up to you, make sure your future self understands what you did here | ||
| 57 | assign_resources! { | ||
| 58 | leds: Leds{ | ||
| 59 | led_10: PIN_10, | ||
| 60 | led_11: PIN_11, | ||
| 61 | } | ||
| 62 | // add more resources to more structs if needed, for example defining one struct for each task | ||
| 63 | } | ||
| 64 | // this could be done in another file and imported here, but for the sake of simplicity we do it here | ||
| 65 | // see https://github.com/adamgreig/assign-resources for more information | ||
| 66 | |||
| 67 | // 2) Using the split resources in a task | ||
| 68 | #[embassy_executor::task] | ||
| 69 | async fn double_blinky_macro_assigned(_spawner: Spawner, r: Leds) { | ||
| 70 | let mut led_10 = Output::new(r.led_10, Level::Low); | ||
| 71 | let mut led_11 = Output::new(r.led_11, Level::High); | ||
| 72 | |||
| 73 | loop { | ||
| 74 | info!("toggling leds"); | ||
| 75 | led_10.toggle(); | ||
| 76 | led_11.toggle(); | ||
| 77 | Timer::after_secs(1).await; | ||
| 78 | } | ||
| 79 | } | ||
diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs new file mode 100644 index 000000000..7524e7929 --- /dev/null +++ b/examples/rp/src/bin/bluetooth.rs | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | //! This example test the RP Pico W on board LED. | ||
| 2 | //! | ||
| 3 | //! It does not work with the RP Pico board. See blinky.rs. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use bt_hci::controller::ExternalController; | ||
| 9 | use cyw43_pio::PioSpi; | ||
| 10 | use defmt::*; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_futures::join::join3; | ||
| 13 | use embassy_rp::bind_interrupts; | ||
| 14 | use embassy_rp::gpio::{Level, Output}; | ||
| 15 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | ||
| 16 | use embassy_rp::pio::{InterruptHandler, Pio}; | ||
| 17 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 18 | use embassy_time::{Duration, Timer}; | ||
| 19 | use static_cell::StaticCell; | ||
| 20 | use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE}; | ||
| 21 | use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid}; | ||
| 22 | use trouble_host::gatt::GattEvent; | ||
| 23 | use trouble_host::{Address, BleHost, BleHostResources, PacketQos}; | ||
| 24 | use {defmt_rtt as _, embassy_time as _, panic_probe as _}; | ||
| 25 | |||
| 26 | bind_interrupts!(struct Irqs { | ||
| 27 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 28 | }); | ||
| 29 | |||
| 30 | #[embassy_executor::task] | ||
| 31 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | ||
| 32 | runner.run().await | ||
| 33 | } | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(spawner: Spawner) { | ||
| 37 | let p = embassy_rp::init(Default::default()); | ||
| 38 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); | ||
| 39 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); | ||
| 40 | let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin"); | ||
| 41 | |||
| 42 | // To make flashing faster for development, you may want to flash the firmwares independently | ||
| 43 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | ||
| 44 | // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | ||
| 45 | // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 | ||
| 46 | // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400 | ||
| 47 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; | ||
| 48 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | ||
| 49 | //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) }; | ||
| 50 | |||
| 51 | let pwr = Output::new(p.PIN_23, Level::Low); | ||
| 52 | let cs = Output::new(p.PIN_25, Level::High); | ||
| 53 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 54 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | ||
| 55 | |||
| 56 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | ||
| 57 | let state = STATE.init(cyw43::State::new()); | ||
| 58 | let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await; | ||
| 59 | unwrap!(spawner.spawn(cyw43_task(runner))); | ||
| 60 | control.init(clm).await; | ||
| 61 | |||
| 62 | let controller: ExternalController<_, 10> = ExternalController::new(bt_device); | ||
| 63 | static HOST_RESOURCES: StaticCell<BleHostResources<4, 32, 27>> = StaticCell::new(); | ||
| 64 | let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None)); | ||
| 65 | |||
| 66 | let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources); | ||
| 67 | |||
| 68 | ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff])); | ||
| 69 | let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new(); | ||
| 70 | |||
| 71 | // Generic Access Service (mandatory) | ||
| 72 | let id = b"Pico W Bluetooth"; | ||
| 73 | let appearance = [0x80, 0x07]; | ||
| 74 | let mut bat_level = [0; 1]; | ||
| 75 | let handle = { | ||
| 76 | let mut svc = table.add_service(Service::new(0x1800)); | ||
| 77 | let _ = svc.add_characteristic_ro(0x2a00, id); | ||
| 78 | let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]); | ||
| 79 | svc.build(); | ||
| 80 | |||
| 81 | // Generic attribute service (mandatory) | ||
| 82 | table.add_service(Service::new(0x1801)); | ||
| 83 | |||
| 84 | // Battery service | ||
| 85 | let mut svc = table.add_service(Service::new(0x180f)); | ||
| 86 | |||
| 87 | svc.add_characteristic( | ||
| 88 | 0x2a19, | ||
| 89 | &[CharacteristicProp::Read, CharacteristicProp::Notify], | ||
| 90 | &mut bat_level, | ||
| 91 | ) | ||
| 92 | .build() | ||
| 93 | }; | ||
| 94 | |||
| 95 | let mut adv_data = [0; 31]; | ||
| 96 | AdStructure::encode_slice( | ||
| 97 | &[ | ||
| 98 | AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), | ||
| 99 | AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]), | ||
| 100 | AdStructure::CompleteLocalName(b"Pico W Bluetooth"), | ||
| 101 | ], | ||
| 102 | &mut adv_data[..], | ||
| 103 | ) | ||
| 104 | .unwrap(); | ||
| 105 | |||
| 106 | let server = ble.gatt_server(&table); | ||
| 107 | |||
| 108 | info!("Starting advertising and GATT service"); | ||
| 109 | let _ = join3( | ||
| 110 | ble.run(), | ||
| 111 | async { | ||
| 112 | loop { | ||
| 113 | match server.next().await { | ||
| 114 | Ok(GattEvent::Write { handle, connection: _ }) => { | ||
| 115 | let _ = table.get(handle, |value| { | ||
| 116 | info!("Write event. Value written: {:?}", value); | ||
| 117 | }); | ||
| 118 | } | ||
| 119 | Ok(GattEvent::Read { .. }) => { | ||
| 120 | info!("Read event"); | ||
| 121 | } | ||
| 122 | Err(e) => { | ||
| 123 | error!("Error processing GATT events: {:?}", e); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } | ||
| 127 | }, | ||
| 128 | async { | ||
| 129 | let mut advertiser = ble | ||
| 130 | .advertise( | ||
| 131 | &Default::default(), | ||
| 132 | Advertisement::ConnectableScannableUndirected { | ||
| 133 | adv_data: &adv_data[..], | ||
| 134 | scan_data: &[], | ||
| 135 | }, | ||
| 136 | ) | ||
| 137 | .await | ||
| 138 | .unwrap(); | ||
| 139 | let conn = advertiser.accept().await.unwrap(); | ||
| 140 | // Keep connection alive | ||
| 141 | let mut tick: u8 = 0; | ||
| 142 | loop { | ||
| 143 | Timer::after(Duration::from_secs(10)).await; | ||
| 144 | tick += 1; | ||
| 145 | server.notify(handle, &conn, &[tick]).await.unwrap(); | ||
| 146 | } | ||
| 147 | }, | ||
| 148 | ) | ||
| 149 | .await; | ||
| 150 | } | ||
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index bd52cadca..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( | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | #[embassy_executor::task] | 38 | #[embassy_executor::task] |
| 39 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 39 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { |
| 40 | stack.run().await | 40 | runner.run().await |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | #[embassy_executor::main] | 43 | #[embassy_executor::main] |
| @@ -63,24 +63,24 @@ async fn main(spawner: Spawner) { | |||
| 63 | w5500_int, | 63 | w5500_int, |
| 64 | w5500_reset, | 64 | w5500_reset, |
| 65 | ) | 65 | ) |
| 66 | .await; | 66 | .await |
| 67 | .unwrap(); | ||
| 67 | unwrap!(spawner.spawn(ethernet_task(runner))); | 68 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| 68 | 69 | ||
| 69 | // Generate random seed | 70 | // Generate random seed |
| 70 | let seed = rng.next_u64(); | 71 | let seed = rng.next_u64(); |
| 71 | 72 | ||
| 72 | // Init network stack | 73 | // Init network stack |
| 73 | static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); | ||
| 74 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 74 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 75 | let stack = &*STACK.init(Stack::new( | 75 | let (stack, runner) = embassy_net::new( |
| 76 | device, | 76 | device, |
| 77 | embassy_net::Config::dhcpv4(Default::default()), | 77 | embassy_net::Config::dhcpv4(Default::default()), |
| 78 | RESOURCES.init(StackResources::<3>::new()), | 78 | RESOURCES.init(StackResources::new()), |
| 79 | seed, | 79 | seed, |
| 80 | )); | 80 | ); |
| 81 | 81 | ||
| 82 | // Launch network task | 82 | // Launch network task |
| 83 | unwrap!(spawner.spawn(net_task(&stack))); | 83 | unwrap!(spawner.spawn(net_task(runner))); |
| 84 | 84 | ||
| 85 | info!("Waiting for DHCP..."); | 85 | info!("Waiting for DHCP..."); |
| 86 | let cfg = wait_for_config(stack).await; | 86 | let cfg = wait_for_config(stack).await; |
| @@ -88,12 +88,12 @@ async fn main(spawner: Spawner) { | |||
| 88 | info!("IP address: {:?}", local_addr); | 88 | info!("IP address: {:?}", local_addr); |
| 89 | 89 | ||
| 90 | // Create two sockets listening to the same port, to handle simultaneous connections | 90 | // Create two sockets listening to the same port, to handle simultaneous connections |
| 91 | unwrap!(spawner.spawn(listen_task(&stack, 0, 1234))); | 91 | unwrap!(spawner.spawn(listen_task(stack, 0, 1234))); |
| 92 | unwrap!(spawner.spawn(listen_task(&stack, 1, 1234))); | 92 | unwrap!(spawner.spawn(listen_task(stack, 1, 1234))); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | #[embassy_executor::task(pool_size = 2)] | 95 | #[embassy_executor::task(pool_size = 2)] |
| 96 | async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) { | 96 | async fn listen_task(stack: Stack<'static>, id: u8, port: u16) { |
| 97 | let mut rx_buffer = [0; 4096]; | 97 | let mut rx_buffer = [0; 4096]; |
| 98 | let mut tx_buffer = [0; 4096]; | 98 | let mut tx_buffer = [0; 4096]; |
| 99 | let mut buf = [0; 4096]; | 99 | let mut buf = [0; 4096]; |
| @@ -130,7 +130,7 @@ async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) | |||
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 133 | async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { |
| 134 | loop { | 134 | loop { |
| 135 | if let Some(config) = stack.config_v4() { | 135 | if let Some(config) = stack.config_v4() { |
| 136 | return config.clone(); | 136 | 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 3e4fbd2e6..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( | |||
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | #[embassy_executor::task] | 40 | #[embassy_executor::task] |
| 41 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 41 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { |
| 42 | stack.run().await | 42 | runner.run().await |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | #[embassy_executor::main] | 45 | #[embassy_executor::main] |
| @@ -66,24 +66,24 @@ async fn main(spawner: Spawner) { | |||
| 66 | w5500_int, | 66 | w5500_int, |
| 67 | w5500_reset, | 67 | w5500_reset, |
| 68 | ) | 68 | ) |
| 69 | .await; | 69 | .await |
| 70 | .unwrap(); | ||
| 70 | unwrap!(spawner.spawn(ethernet_task(runner))); | 71 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| 71 | 72 | ||
| 72 | // Generate random seed | 73 | // Generate random seed |
| 73 | let seed = rng.next_u64(); | 74 | let seed = rng.next_u64(); |
| 74 | 75 | ||
| 75 | // Init network stack | 76 | // Init network stack |
| 76 | static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); | 77 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 77 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 78 | let (stack, runner) = embassy_net::new( |
| 78 | let stack = &*STACK.init(Stack::new( | ||
| 79 | device, | 79 | device, |
| 80 | embassy_net::Config::dhcpv4(Default::default()), | 80 | embassy_net::Config::dhcpv4(Default::default()), |
| 81 | RESOURCES.init(StackResources::<2>::new()), | 81 | RESOURCES.init(StackResources::new()), |
| 82 | seed, | 82 | seed, |
| 83 | )); | 83 | ); |
| 84 | 84 | ||
| 85 | // Launch network task | 85 | // Launch network task |
| 86 | unwrap!(spawner.spawn(net_task(&stack))); | 86 | unwrap!(spawner.spawn(net_task(runner))); |
| 87 | 87 | ||
| 88 | info!("Waiting for DHCP..."); | 88 | info!("Waiting for DHCP..."); |
| 89 | let cfg = wait_for_config(stack).await; | 89 | let cfg = wait_for_config(stack).await; |
| @@ -118,7 +118,7 @@ async fn main(spawner: Spawner) { | |||
| 118 | } | 118 | } |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 121 | async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { |
| 122 | loop { | 122 | loop { |
| 123 | if let Some(config) = stack.config_v4() { | 123 | if let Some(config) = stack.config_v4() { |
| 124 | return config.clone(); | 124 | 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 5532851f3..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( | |||
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | #[embassy_executor::task] | 39 | #[embassy_executor::task] |
| 40 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 40 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { |
| 41 | stack.run().await | 41 | runner.run().await |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | #[embassy_executor::main] | 44 | #[embassy_executor::main] |
| @@ -65,24 +65,24 @@ async fn main(spawner: Spawner) { | |||
| 65 | w5500_int, | 65 | w5500_int, |
| 66 | w5500_reset, | 66 | w5500_reset, |
| 67 | ) | 67 | ) |
| 68 | .await; | 68 | .await |
| 69 | .unwrap(); | ||
| 69 | unwrap!(spawner.spawn(ethernet_task(runner))); | 70 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| 70 | 71 | ||
| 71 | // Generate random seed | 72 | // Generate random seed |
| 72 | let seed = rng.next_u64(); | 73 | let seed = rng.next_u64(); |
| 73 | 74 | ||
| 74 | // Init network stack | 75 | // Init network stack |
| 75 | static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); | 76 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 76 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 77 | let (stack, runner) = embassy_net::new( |
| 77 | let stack = &*STACK.init(Stack::new( | ||
| 78 | device, | 78 | device, |
| 79 | embassy_net::Config::dhcpv4(Default::default()), | 79 | embassy_net::Config::dhcpv4(Default::default()), |
| 80 | RESOURCES.init(StackResources::<2>::new()), | 80 | RESOURCES.init(StackResources::new()), |
| 81 | seed, | 81 | seed, |
| 82 | )); | 82 | ); |
| 83 | 83 | ||
| 84 | // Launch network task | 84 | // Launch network task |
| 85 | unwrap!(spawner.spawn(net_task(&stack))); | 85 | unwrap!(spawner.spawn(net_task(runner))); |
| 86 | 86 | ||
| 87 | info!("Waiting for DHCP..."); | 87 | info!("Waiting for DHCP..."); |
| 88 | let cfg = wait_for_config(stack).await; | 88 | let cfg = wait_for_config(stack).await; |
| @@ -127,7 +127,7 @@ async fn main(spawner: Spawner) { | |||
| 127 | } | 127 | } |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 130 | async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { |
| 131 | loop { | 131 | loop { |
| 132 | if let Some(config) = stack.config_v4() { | 132 | if let Some(config) = stack.config_v4() { |
| 133 | return config.clone(); | 133 | return config.clone(); |
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index adb1d8941..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( | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | #[embassy_executor::task] | 38 | #[embassy_executor::task] |
| 39 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 39 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { |
| 40 | stack.run().await | 40 | runner.run().await |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | #[embassy_executor::main] | 43 | #[embassy_executor::main] |
| @@ -63,24 +63,24 @@ async fn main(spawner: Spawner) { | |||
| 63 | w5500_int, | 63 | w5500_int, |
| 64 | w5500_reset, | 64 | w5500_reset, |
| 65 | ) | 65 | ) |
| 66 | .await; | 66 | .await |
| 67 | .unwrap(); | ||
| 67 | unwrap!(spawner.spawn(ethernet_task(runner))); | 68 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| 68 | 69 | ||
| 69 | // Generate random seed | 70 | // Generate random seed |
| 70 | let seed = rng.next_u64(); | 71 | let seed = rng.next_u64(); |
| 71 | 72 | ||
| 72 | // Init network stack | 73 | // Init network stack |
| 73 | static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); | 74 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 74 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 75 | let (stack, runner) = embassy_net::new( |
| 75 | let stack = &*STACK.init(Stack::new( | ||
| 76 | device, | 76 | device, |
| 77 | embassy_net::Config::dhcpv4(Default::default()), | 77 | embassy_net::Config::dhcpv4(Default::default()), |
| 78 | RESOURCES.init(StackResources::<2>::new()), | 78 | RESOURCES.init(StackResources::new()), |
| 79 | seed, | 79 | seed, |
| 80 | )); | 80 | ); |
| 81 | 81 | ||
| 82 | // Launch network task | 82 | // Launch network task |
| 83 | unwrap!(spawner.spawn(net_task(&stack))); | 83 | unwrap!(spawner.spawn(net_task(runner))); |
| 84 | 84 | ||
| 85 | info!("Waiting for DHCP..."); | 85 | info!("Waiting for DHCP..."); |
| 86 | let cfg = wait_for_config(stack).await; | 86 | let cfg = wait_for_config(stack).await; |
| @@ -107,7 +107,7 @@ async fn main(spawner: Spawner) { | |||
| 107 | } | 107 | } |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 110 | async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { |
| 111 | loop { | 111 | loop { |
| 112 | if let Some(config) = stack.config_v4() { | 112 | if let Some(config) = stack.config_v4() { |
| 113 | return config.clone(); | 113 | return config.clone(); |
diff --git a/examples/rp/src/bin/i2c_async_embassy.rs b/examples/rp/src/bin/i2c_async_embassy.rs new file mode 100644 index 000000000..a65b71b9f --- /dev/null +++ b/examples/rp/src/bin/i2c_async_embassy.rs | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | //! This example shows how to communicate asynchronous using i2c with external chip. | ||
| 2 | //! | ||
| 3 | //! It's using embassy's functions directly instead of traits from embedded_hal_async::i2c::I2c. | ||
| 4 | //! While most of i2c devices are addressed using 7 bits, an extension allows 10 bits too. | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_rp::i2c::InterruptHandler; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | // Our anonymous hypotetical temperature sensor could be: | ||
| 14 | // a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C | ||
| 15 | // It requires no configuration or calibration, works with all i2c bus speeds, | ||
| 16 | // never stretches clock or does anything complicated. Replies with one u16. | ||
| 17 | // It requires only one write to take it out of suspend mode, and stays on. | ||
| 18 | // Often result would be just on 12 bits, but here we'll simplify it to 16. | ||
| 19 | |||
| 20 | enum UncomplicatedSensorId { | ||
| 21 | A(UncomplicatedSensorU8), | ||
| 22 | B(UncomplicatedSensorU16), | ||
| 23 | } | ||
| 24 | enum UncomplicatedSensorU8 { | ||
| 25 | First = 0x48, | ||
| 26 | } | ||
| 27 | enum UncomplicatedSensorU16 { | ||
| 28 | Other = 0x0049, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl Into<u16> for UncomplicatedSensorU16 { | ||
| 32 | fn into(self) -> u16 { | ||
| 33 | self as u16 | ||
| 34 | } | ||
| 35 | } | ||
| 36 | impl Into<u16> for UncomplicatedSensorU8 { | ||
| 37 | fn into(self) -> u16 { | ||
| 38 | 0x48 | ||
| 39 | } | ||
| 40 | } | ||
| 41 | impl From<UncomplicatedSensorId> for u16 { | ||
| 42 | fn from(t: UncomplicatedSensorId) -> Self { | ||
| 43 | match t { | ||
| 44 | UncomplicatedSensorId::A(x) => x.into(), | ||
| 45 | UncomplicatedSensorId::B(x) => x.into(), | ||
| 46 | } | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | embassy_rp::bind_interrupts!(struct Irqs { | ||
| 51 | I2C1_IRQ => InterruptHandler<embassy_rp::peripherals::I2C1>; | ||
| 52 | }); | ||
| 53 | |||
| 54 | #[embassy_executor::main] | ||
| 55 | async fn main(_task_spawner: embassy_executor::Spawner) { | ||
| 56 | let p = embassy_rp::init(Default::default()); | ||
| 57 | let sda = p.PIN_14; | ||
| 58 | let scl = p.PIN_15; | ||
| 59 | let config = embassy_rp::i2c::Config::default(); | ||
| 60 | let mut bus = embassy_rp::i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, config); | ||
| 61 | |||
| 62 | const WAKEYWAKEY: u16 = 0xBABE; | ||
| 63 | let mut result: [u8; 2] = [0, 0]; | ||
| 64 | // wait for sensors to initialize | ||
| 65 | embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await; | ||
| 66 | |||
| 67 | let _res_1 = bus | ||
| 68 | .write_async(UncomplicatedSensorU8::First, WAKEYWAKEY.to_be_bytes()) | ||
| 69 | .await; | ||
| 70 | let _res_2 = bus | ||
| 71 | .write_async(UncomplicatedSensorU16::Other, WAKEYWAKEY.to_be_bytes()) | ||
| 72 | .await; | ||
| 73 | |||
| 74 | loop { | ||
| 75 | let s1 = UncomplicatedSensorId::A(UncomplicatedSensorU8::First); | ||
| 76 | let s2 = UncomplicatedSensorId::B(UncomplicatedSensorU16::Other); | ||
| 77 | let sensors = [s1, s2]; | ||
| 78 | for sensor in sensors { | ||
| 79 | if bus.read_async(sensor, &mut result).await.is_ok() { | ||
| 80 | info!("Result {}", u16::from_be_bytes(result.into())); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await; | ||
| 84 | } | ||
| 85 | } | ||
diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs index ac470d2be..9fffb4646 100644 --- a/examples/rp/src/bin/i2c_slave.rs +++ b/examples/rp/src/bin/i2c_slave.rs | |||
| @@ -110,7 +110,7 @@ async fn main(spawner: Spawner) { | |||
| 110 | let c_sda = p.PIN_1; | 110 | let c_sda = p.PIN_1; |
| 111 | let c_scl = p.PIN_0; | 111 | let c_scl = p.PIN_0; |
| 112 | let mut config = i2c::Config::default(); | 112 | let mut config = i2c::Config::default(); |
| 113 | config.frequency = 5_000; | 113 | config.frequency = 1_000_000; |
| 114 | let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); | 114 | let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); |
| 115 | 115 | ||
| 116 | unwrap!(spawner.spawn(controller_task(controller))); | 116 | unwrap!(spawner.spawn(controller_task(controller))); |
diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs new file mode 100644 index 000000000..5b9d7027e --- /dev/null +++ b/examples/rp/src/bin/interrupt.rs | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | //! This example shows how you can use raw interrupt handlers alongside embassy. | ||
| 2 | //! The example also showcases some of the options available for sharing resources/data. | ||
| 3 | //! | ||
| 4 | //! In the example, an ADC reading is triggered every time the PWM wraps around. | ||
| 5 | //! The sample data is sent down a channel, to be processed inside a low priority task. | ||
| 6 | //! The processed data is then used to adjust the PWM duty cycle, once every second. | ||
| 7 | |||
| 8 | #![no_std] | ||
| 9 | #![no_main] | ||
| 10 | |||
| 11 | use core::cell::{Cell, RefCell}; | ||
| 12 | |||
| 13 | use defmt::*; | ||
| 14 | use embassy_executor::Spawner; | ||
| 15 | use embassy_rp::adc::{self, Adc, Blocking}; | ||
| 16 | use embassy_rp::gpio::Pull; | ||
| 17 | use embassy_rp::interrupt; | ||
| 18 | use embassy_rp::pwm::{Config, Pwm}; | ||
| 19 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 20 | use embassy_sync::blocking_mutex::Mutex; | ||
| 21 | use embassy_sync::channel::Channel; | ||
| 22 | use embassy_time::{Duration, Ticker}; | ||
| 23 | use portable_atomic::{AtomicU32, Ordering}; | ||
| 24 | use static_cell::StaticCell; | ||
| 25 | use {defmt_rtt as _, panic_probe as _}; | ||
| 26 | |||
| 27 | static COUNTER: AtomicU32 = AtomicU32::new(0); | ||
| 28 | static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None)); | ||
| 29 | static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> = | ||
| 30 | Mutex::new(RefCell::new(None)); | ||
| 31 | static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new(); | ||
| 32 | |||
| 33 | #[embassy_executor::main] | ||
| 34 | async fn main(spawner: Spawner) { | ||
| 35 | embassy_rp::pac::SIO.spinlock(31).write_value(1); | ||
| 36 | let p = embassy_rp::init(Default::default()); | ||
| 37 | |||
| 38 | let adc = Adc::new_blocking(p.ADC, Default::default()); | ||
| 39 | let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None); | ||
| 40 | ADC.lock(|a| a.borrow_mut().replace((adc, p26))); | ||
| 41 | |||
| 42 | let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default()); | ||
| 43 | PWM.lock(|p| p.borrow_mut().replace(pwm)); | ||
| 44 | |||
| 45 | // Enable the interrupt for pwm slice 4 | ||
| 46 | embassy_rp::pac::PWM.inte().modify(|w| w.set_ch4(true)); | ||
| 47 | unsafe { | ||
| 48 | cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP); | ||
| 49 | } | ||
| 50 | |||
| 51 | // Tasks require their resources to have 'static lifetime | ||
| 52 | // No Mutex needed when sharing within the same executor/prio level | ||
| 53 | static AVG: StaticCell<Cell<u32>> = StaticCell::new(); | ||
| 54 | let avg = AVG.init(Default::default()); | ||
| 55 | spawner.must_spawn(processing(avg)); | ||
| 56 | |||
| 57 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 58 | loop { | ||
| 59 | ticker.next().await; | ||
| 60 | let freq = COUNTER.swap(0, Ordering::Relaxed); | ||
| 61 | info!("pwm freq: {:?} Hz", freq); | ||
| 62 | info!("adc average: {:?}", avg.get()); | ||
| 63 | |||
| 64 | // Update the pwm duty cycle, based on the averaged adc reading | ||
| 65 | let mut config = Config::default(); | ||
| 66 | config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _; | ||
| 67 | PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config)); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | #[embassy_executor::task] | ||
| 72 | async fn processing(avg: &'static Cell<u32>) { | ||
| 73 | let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default(); | ||
| 74 | loop { | ||
| 75 | let val = ADC_VALUES.receive().await; | ||
| 76 | buffer.write(val); | ||
| 77 | let sum: u32 = buffer.iter().map(|x| *x as u32).sum(); | ||
| 78 | avg.set(sum / buffer.len() as u32); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | #[interrupt] | ||
| 83 | fn PWM_IRQ_WRAP() { | ||
| 84 | critical_section::with(|cs| { | ||
| 85 | let mut adc = ADC.borrow(cs).borrow_mut(); | ||
| 86 | let (adc, p26) = adc.as_mut().unwrap(); | ||
| 87 | let val = adc.blocking_read(p26).unwrap(); | ||
| 88 | ADC_VALUES.try_send(val).ok(); | ||
| 89 | |||
| 90 | // Clear the interrupt, so we don't immediately re-enter this irq handler | ||
| 91 | PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped(); | ||
| 92 | }); | ||
| 93 | COUNTER.fetch_add(1, Ordering::Relaxed); | ||
| 94 | } | ||
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index c7b087476..7cb546c91 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs | |||
| @@ -30,10 +30,14 @@ fn main() -> ! { | |||
| 30 | let p = embassy_rp::init(Default::default()); | 30 | let p = embassy_rp::init(Default::default()); |
| 31 | let led = Output::new(p.PIN_25, Level::Low); | 31 | let led = Output::new(p.PIN_25, Level::Low); |
| 32 | 32 | ||
| 33 | spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { | 33 | spawn_core1( |
| 34 | let executor1 = EXECUTOR1.init(Executor::new()); | 34 | p.CORE1, |
| 35 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); | 35 | unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, |
| 36 | }); | 36 | move || { |
| 37 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 38 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); | ||
| 39 | }, | ||
| 40 | ); | ||
| 37 | 41 | ||
| 38 | let executor0 = EXECUTOR0.init(Executor::new()); | 42 | let executor0 = EXECUTOR0.init(Executor::new()); |
| 39 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); | 43 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); |
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs index 26b80c11d..2b397f97d 100644 --- a/examples/rp/src/bin/multiprio.rs +++ b/examples/rp/src/bin/multiprio.rs | |||
| @@ -80,7 +80,7 @@ async fn run_med() { | |||
| 80 | info!(" [med] Starting long computation"); | 80 | info!(" [med] Starting long computation"); |
| 81 | 81 | ||
| 82 | // Spin-wait to simulate a long CPU computation | 82 | // Spin-wait to simulate a long CPU computation |
| 83 | cortex_m::asm::delay(125_000_000); // ~1 second | 83 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second |
| 84 | 84 | ||
| 85 | let end = Instant::now(); | 85 | let end = Instant::now(); |
| 86 | let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; | 86 | let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; |
| @@ -97,7 +97,7 @@ async fn run_low() { | |||
| 97 | info!("[low] Starting long computation"); | 97 | info!("[low] Starting long computation"); |
| 98 | 98 | ||
| 99 | // Spin-wait to simulate a long CPU computation | 99 | // Spin-wait to simulate a long CPU computation |
| 100 | cortex_m::asm::delay(250_000_000); // ~2 seconds | 100 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds |
| 101 | 101 | ||
| 102 | let end = Instant::now(); | 102 | let end = Instant::now(); |
| 103 | let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; | 103 | let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; |
diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs new file mode 100644 index 000000000..0e21d5833 --- /dev/null +++ b/examples/rp/src/bin/orchestrate_tasks.rs | |||
| @@ -0,0 +1,318 @@ | |||
| 1 | //! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system. | ||
| 2 | //! | ||
| 3 | //! We demonstrate how to: | ||
| 4 | //! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. | ||
| 5 | //! - use a signal to terminate a task. | ||
| 6 | //! - use command channels to send commands to another task. | ||
| 7 | //! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures. | ||
| 8 | //! | ||
| 9 | //! There are more patterns to orchestrate tasks, this is just one example. | ||
| 10 | //! | ||
| 11 | //! We will use these tasks to generate example "state information": | ||
| 12 | //! - a task that generates random numbers in intervals of 60s | ||
| 13 | //! - a task that generates random numbers in intervals of 30s | ||
| 14 | //! - a task that generates random numbers in intervals of 90s | ||
| 15 | //! - a task that notifies about being attached/disattached from usb power | ||
| 16 | //! - a task that measures vsys voltage in intervals of 30s | ||
| 17 | //! - a task that consumes the state information and reacts to it | ||
| 18 | |||
| 19 | #![no_std] | ||
| 20 | #![no_main] | ||
| 21 | |||
| 22 | use assign_resources::assign_resources; | ||
| 23 | use defmt::*; | ||
| 24 | use embassy_executor::Spawner; | ||
| 25 | use embassy_futures::select::{select, Either}; | ||
| 26 | use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; | ||
| 27 | use embassy_rp::clocks::RoscRng; | ||
| 28 | use embassy_rp::gpio::{Input, Pull}; | ||
| 29 | use embassy_rp::{bind_interrupts, peripherals}; | ||
| 30 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 31 | use embassy_sync::{channel, signal}; | ||
| 32 | use embassy_time::{Duration, Timer}; | ||
| 33 | use rand::RngCore; | ||
| 34 | use {defmt_rtt as _, panic_probe as _}; | ||
| 35 | |||
| 36 | // 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. | ||
| 37 | // **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 | ||
| 38 | // 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. | ||
| 39 | // For this example it will not matter much, the concept of what we are showing remains valid. | ||
| 40 | assign_resources! { | ||
| 41 | vsys: Vsys { | ||
| 42 | adc: ADC, | ||
| 43 | pin_29: PIN_29, | ||
| 44 | }, | ||
| 45 | vbus: Vbus { | ||
| 46 | pin_24: PIN_24, | ||
| 47 | }, | ||
| 48 | } | ||
| 49 | |||
| 50 | bind_interrupts!(struct Irqs { | ||
| 51 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 52 | }); | ||
| 53 | |||
| 54 | /// This is the type of Events that we will send from the worker tasks to the orchestrating task. | ||
| 55 | enum Events { | ||
| 56 | UsbPowered(bool), | ||
| 57 | VsysVoltage(f32), | ||
| 58 | FirstRandomSeed(u32), | ||
| 59 | SecondRandomSeed(u32), | ||
| 60 | ThirdRandomSeed(u32), | ||
| 61 | ResetFirstRandomSeed, | ||
| 62 | } | ||
| 63 | |||
| 64 | /// This is the type of Commands that we will send from the orchestrating task to the worker tasks. | ||
| 65 | /// Note that we are lazy here and only have one command, you might want to have more. | ||
| 66 | enum Commands { | ||
| 67 | /// This command will stop the appropriate worker task | ||
| 68 | Stop, | ||
| 69 | } | ||
| 70 | |||
| 71 | /// 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. | ||
| 72 | #[derive(Default, Debug, Clone, Format)] | ||
| 73 | struct State { | ||
| 74 | usb_powered: bool, | ||
| 75 | vsys_voltage: f32, | ||
| 76 | first_random_seed: u32, | ||
| 77 | second_random_seed: u32, | ||
| 78 | third_random_seed: u32, | ||
| 79 | times_we_got_first_random_seed: u8, | ||
| 80 | maximum_times_we_want_first_random_seed: u8, | ||
| 81 | } | ||
| 82 | |||
| 83 | impl State { | ||
| 84 | fn new() -> Self { | ||
| 85 | Self { | ||
| 86 | usb_powered: false, | ||
| 87 | vsys_voltage: 0.0, | ||
| 88 | first_random_seed: 0, | ||
| 89 | second_random_seed: 0, | ||
| 90 | third_random_seed: 0, | ||
| 91 | times_we_got_first_random_seed: 0, | ||
| 92 | maximum_times_we_want_first_random_seed: 3, | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | /// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events. | ||
| 98 | /// 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 | ||
| 99 | /// 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 | ||
| 100 | /// 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 | ||
| 101 | /// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting. | ||
| 102 | /// 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. | ||
| 103 | static EVENT_CHANNEL: channel::Channel<CriticalSectionRawMutex, Events, 10> = channel::Channel::new(); | ||
| 104 | |||
| 105 | /// 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. | ||
| 106 | static STOP_FIRST_RANDOM_SIGNAL: signal::Signal<CriticalSectionRawMutex, Commands> = signal::Signal::new(); | ||
| 107 | |||
| 108 | /// 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 | ||
| 109 | /// 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 | ||
| 110 | /// and depends on your use case. | ||
| 111 | static CONSUMER_CHANNEL: channel::Channel<CriticalSectionRawMutex, State, 1> = channel::Channel::new(); | ||
| 112 | |||
| 113 | // And now we can put all this into use | ||
| 114 | |||
| 115 | /// 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 | /// 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. | ||
| 117 | #[embassy_executor::main] | ||
| 118 | async fn main(spawner: Spawner) { | ||
| 119 | // initialize the peripherals | ||
| 120 | let p = embassy_rp::init(Default::default()); | ||
| 121 | // split the resources, for convenience - see above | ||
| 122 | let r = split_resources! {p}; | ||
| 123 | |||
| 124 | // spawn the tasks | ||
| 125 | spawner.spawn(orchestrate(spawner)).unwrap(); | ||
| 126 | spawner.spawn(random_60s(spawner)).unwrap(); | ||
| 127 | spawner.spawn(random_90s(spawner)).unwrap(); | ||
| 128 | spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); | ||
| 129 | spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); | ||
| 130 | spawner.spawn(consumer(spawner)).unwrap(); | ||
| 131 | } | ||
| 132 | |||
| 133 | /// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. | ||
| 134 | #[embassy_executor::task] | ||
| 135 | async fn orchestrate(_spawner: Spawner) { | ||
| 136 | let mut state = State::new(); | ||
| 137 | |||
| 138 | // we need to have a receiver for the events | ||
| 139 | let receiver = EVENT_CHANNEL.receiver(); | ||
| 140 | |||
| 141 | // and we need a sender for the consumer task | ||
| 142 | let state_sender = CONSUMER_CHANNEL.sender(); | ||
| 143 | |||
| 144 | loop { | ||
| 145 | // we await on the receiver, this will block until a new event is available | ||
| 146 | // 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 | ||
| 147 | // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html | ||
| 148 | // The task random_30s does a select, if you want to have a look at that. | ||
| 149 | // 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. | ||
| 150 | // We keep it simple here. | ||
| 151 | let event = receiver.receive().await; | ||
| 152 | |||
| 153 | // react to the events | ||
| 154 | match event { | ||
| 155 | Events::UsbPowered(usb_powered) => { | ||
| 156 | // update the state and/or react to the event here | ||
| 157 | state.usb_powered = usb_powered; | ||
| 158 | info!("Usb powered: {}", usb_powered); | ||
| 159 | } | ||
| 160 | Events::VsysVoltage(voltage) => { | ||
| 161 | // update the state and/or react to the event here | ||
| 162 | state.vsys_voltage = voltage; | ||
| 163 | info!("Vsys voltage: {}", voltage); | ||
| 164 | } | ||
| 165 | Events::FirstRandomSeed(seed) => { | ||
| 166 | // update the state and/or react to the event here | ||
| 167 | state.first_random_seed = seed; | ||
| 168 | // here we change some meta state, we count how many times we got the first random seed | ||
| 169 | state.times_we_got_first_random_seed += 1; | ||
| 170 | info!( | ||
| 171 | "First random seed: {}, and that was iteration {} of receiving this.", | ||
| 172 | seed, &state.times_we_got_first_random_seed | ||
| 173 | ); | ||
| 174 | } | ||
| 175 | Events::SecondRandomSeed(seed) => { | ||
| 176 | // update the state and/or react to the event here | ||
| 177 | state.second_random_seed = seed; | ||
| 178 | info!("Second random seed: {}", seed); | ||
| 179 | } | ||
| 180 | Events::ThirdRandomSeed(seed) => { | ||
| 181 | // update the state and/or react to the event here | ||
| 182 | state.third_random_seed = seed; | ||
| 183 | info!("Third random seed: {}", seed); | ||
| 184 | } | ||
| 185 | Events::ResetFirstRandomSeed => { | ||
| 186 | // update the state and/or react to the event here | ||
| 187 | state.times_we_got_first_random_seed = 0; | ||
| 188 | state.first_random_seed = 0; | ||
| 189 | info!("Resetting the first random seed counter"); | ||
| 190 | } | ||
| 191 | } | ||
| 192 | // we now have an altered state | ||
| 193 | // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here | ||
| 194 | // for now we just keep it simple | ||
| 195 | |||
| 196 | // we send the state to the consumer task | ||
| 197 | // 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 | ||
| 198 | // **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 | ||
| 199 | // 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. | ||
| 200 | // We keep it simple here. | ||
| 201 | state_sender.send(state.clone()).await; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | /// 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 | ||
| 206 | /// and we could have multiple consumer tasks, each reacting to different parts of the state. | ||
| 207 | #[embassy_executor::task] | ||
| 208 | async fn consumer(spawner: Spawner) { | ||
| 209 | // we need to have a receiver for the state | ||
| 210 | let receiver = CONSUMER_CHANNEL.receiver(); | ||
| 211 | let sender = EVENT_CHANNEL.sender(); | ||
| 212 | loop { | ||
| 213 | // we await on the receiver, this will block until a new state is available | ||
| 214 | let state = receiver.receive().await; | ||
| 215 | // react to the state, in this case here we just log it | ||
| 216 | info!("The consumer has reveived this state: {:?}", &state); | ||
| 217 | |||
| 218 | // 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 | ||
| 219 | match state.times_we_got_first_random_seed { | ||
| 220 | max if max == state.maximum_times_we_want_first_random_seed => { | ||
| 221 | info!("Stopping the first random signal task"); | ||
| 222 | // we send a command to the task | ||
| 223 | STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); | ||
| 224 | // we notify the orchestrator that we have sent the command | ||
| 225 | sender.send(Events::ResetFirstRandomSeed).await; | ||
| 226 | } | ||
| 227 | 0 => { | ||
| 228 | // we start the task, which presents us with an interesting problem, because we may return here before the task has started | ||
| 229 | // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully | ||
| 230 | info!("Starting the first random signal task"); | ||
| 231 | match spawner.spawn(random_30s(spawner)) { | ||
| 232 | Ok(_) => info!("Successfully spawned random_30s task"), | ||
| 233 | Err(e) => info!("Failed to spawn random_30s task: {:?}", e), | ||
| 234 | } | ||
| 235 | } | ||
| 236 | _ => {} | ||
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | /// This task will generate random numbers in intervals of 30s | ||
| 242 | /// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. | ||
| 243 | /// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically. | ||
| 244 | #[embassy_executor::task] | ||
| 245 | async fn random_30s(_spawner: Spawner) { | ||
| 246 | let mut rng = RoscRng; | ||
| 247 | let sender = EVENT_CHANNEL.sender(); | ||
| 248 | loop { | ||
| 249 | // we either await on the timer or the signal, whichever comes first. | ||
| 250 | let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await; | ||
| 251 | match futures { | ||
| 252 | Either::First(_) => { | ||
| 253 | // we received are operating on the timer | ||
| 254 | info!("30s are up, generating random number"); | ||
| 255 | let random_number = rng.next_u32(); | ||
| 256 | sender.send(Events::FirstRandomSeed(random_number)).await; | ||
| 257 | } | ||
| 258 | Either::Second(_) => { | ||
| 259 | // we received the signal to stop | ||
| 260 | info!("Received signal to stop, goodbye!"); | ||
| 261 | break; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | /// This task will generate random numbers in intervals of 60s | ||
| 268 | #[embassy_executor::task] | ||
| 269 | async fn random_60s(_spawner: Spawner) { | ||
| 270 | let mut rng = RoscRng; | ||
| 271 | let sender = EVENT_CHANNEL.sender(); | ||
| 272 | loop { | ||
| 273 | Timer::after(Duration::from_secs(60)).await; | ||
| 274 | let random_number = rng.next_u32(); | ||
| 275 | sender.send(Events::SecondRandomSeed(random_number)).await; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | /// This task will generate random numbers in intervals of 90s | ||
| 280 | #[embassy_executor::task] | ||
| 281 | async fn random_90s(_spawner: Spawner) { | ||
| 282 | let mut rng = RoscRng; | ||
| 283 | let sender = EVENT_CHANNEL.sender(); | ||
| 284 | loop { | ||
| 285 | Timer::after(Duration::from_secs(90)).await; | ||
| 286 | let random_number = rng.next_u32(); | ||
| 287 | sender.send(Events::ThirdRandomSeed(random_number)).await; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | /// This task will notify if we are connected to usb power | ||
| 292 | #[embassy_executor::task] | ||
| 293 | pub async fn usb_power(_spawner: Spawner, r: Vbus) { | ||
| 294 | let mut vbus_in = Input::new(r.pin_24, Pull::None); | ||
| 295 | let sender = EVENT_CHANNEL.sender(); | ||
| 296 | loop { | ||
| 297 | sender.send(Events::UsbPowered(vbus_in.is_high())).await; | ||
| 298 | vbus_in.wait_for_any_edge().await; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | /// This task will measure the vsys voltage in intervals of 30s | ||
| 303 | #[embassy_executor::task] | ||
| 304 | pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) { | ||
| 305 | let mut adc = Adc::new(r.adc, Irqs, Config::default()); | ||
| 306 | let vsys_in = r.pin_29; | ||
| 307 | let mut channel = Channel::new_pin(vsys_in, Pull::None); | ||
| 308 | let sender = EVENT_CHANNEL.sender(); | ||
| 309 | loop { | ||
| 310 | // read the adc value | ||
| 311 | let adc_value = adc.read(&mut channel).await.unwrap(); | ||
| 312 | // convert the adc value to voltage. | ||
| 313 | // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc | ||
| 314 | let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0; | ||
| 315 | sender.send(Events::VsysVoltage(voltage)).await; | ||
| 316 | Timer::after(Duration::from_secs(30)).await; | ||
| 317 | } | ||
| 318 | } | ||
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 3fab7b5f2..6c02630e0 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs | |||
| @@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) { | |||
| 35 | // allowing direct connection of the display to the RP2040 without level shifters. | 35 | // allowing direct connection of the display to the RP2040 without level shifters. |
| 36 | let p = embassy_rp::init(Default::default()); | 36 | let p = embassy_rp::init(Default::default()); |
| 37 | 37 | ||
| 38 | let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { | 38 | let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, { |
| 39 | let mut c = pwm::Config::default(); | 39 | let mut c = pwm::Config::default(); |
| 40 | c.divider = 125.into(); | 40 | c.divider = 125.into(); |
| 41 | c.top = 100; | 41 | c.top = 100; |
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 @@ | |||
| 1 | //! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::bind_interrupts; | ||
| 8 | use embassy_rp::peripherals::PIO0; | ||
| 9 | use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async fn main(_spawner: Spawner) { | ||
| 19 | let p = embassy_rp::init(Default::default()); | ||
| 20 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 21 | let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); | ||
| 22 | |||
| 23 | loop { | ||
| 24 | sensor.start().await; // Start a new measurement | ||
| 25 | Timer::after_secs(1).await; // Allow 1s for the measurement to finish | ||
| 26 | match sensor.temperature().await { | ||
| 27 | Ok(temp) => info!("temp = {:?} deg C", temp), | ||
| 28 | _ => error!("sensor error"), | ||
| 29 | } | ||
| 30 | Timer::after_secs(1).await; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | /// DS18B20 temperature sensor driver | ||
| 35 | pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { | ||
| 36 | sm: StateMachine<'d, PIO, SM>, | ||
| 37 | } | ||
| 38 | |||
| 39 | impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { | ||
| 40 | /// Create a new instance the driver | ||
| 41 | pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { | ||
| 42 | let prg = pio_proc::pio_asm!( | ||
| 43 | r#" | ||
| 44 | .wrap_target | ||
| 45 | again: | ||
| 46 | pull block | ||
| 47 | mov x, osr | ||
| 48 | jmp !x, read | ||
| 49 | write: | ||
| 50 | set pindirs, 1 | ||
| 51 | set pins, 0 | ||
| 52 | loop1: | ||
| 53 | jmp x--,loop1 | ||
| 54 | set pindirs, 0 [31] | ||
| 55 | wait 1 pin 0 [31] | ||
| 56 | pull block | ||
| 57 | mov x, osr | ||
| 58 | bytes1: | ||
| 59 | pull block | ||
| 60 | set y, 7 | ||
| 61 | set pindirs, 1 | ||
| 62 | bit1: | ||
| 63 | set pins, 0 [1] | ||
| 64 | out pins,1 [31] | ||
| 65 | set pins, 1 [20] | ||
| 66 | jmp y--,bit1 | ||
| 67 | jmp x--,bytes1 | ||
| 68 | set pindirs, 0 [31] | ||
| 69 | jmp again | ||
| 70 | read: | ||
| 71 | pull block | ||
| 72 | mov x, osr | ||
| 73 | bytes2: | ||
| 74 | set y, 7 | ||
| 75 | bit2: | ||
| 76 | set pindirs, 1 | ||
| 77 | set pins, 0 [1] | ||
| 78 | set pindirs, 0 [5] | ||
| 79 | in pins,1 [10] | ||
| 80 | jmp y--,bit2 | ||
| 81 | jmp x--,bytes2 | ||
| 82 | .wrap | ||
| 83 | "#, | ||
| 84 | ); | ||
| 85 | |||
| 86 | let pin = common.make_pio_pin(pin); | ||
| 87 | let mut cfg = Config::default(); | ||
| 88 | cfg.use_program(&common.load_program(&prg.program), &[]); | ||
| 89 | cfg.set_out_pins(&[&pin]); | ||
| 90 | cfg.set_in_pins(&[&pin]); | ||
| 91 | cfg.set_set_pins(&[&pin]); | ||
| 92 | cfg.shift_in = ShiftConfig { | ||
| 93 | auto_fill: true, | ||
| 94 | direction: ShiftDirection::Right, | ||
| 95 | threshold: 8, | ||
| 96 | }; | ||
| 97 | cfg.clock_divider = 255_u8.into(); | ||
| 98 | sm.set_config(&cfg); | ||
| 99 | sm.set_enable(true); | ||
| 100 | Self { sm } | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Write bytes over the wire | ||
| 104 | async fn write_bytes(&mut self, bytes: &[u8]) { | ||
| 105 | self.sm.tx().wait_push(250).await; | ||
| 106 | self.sm.tx().wait_push(bytes.len() as u32 - 1).await; | ||
| 107 | for b in bytes { | ||
| 108 | self.sm.tx().wait_push(*b as u32).await; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Read bytes from the wire | ||
| 113 | async fn read_bytes(&mut self, bytes: &mut [u8]) { | ||
| 114 | self.sm.tx().wait_push(0).await; | ||
| 115 | self.sm.tx().wait_push(bytes.len() as u32 - 1).await; | ||
| 116 | for b in bytes.iter_mut() { | ||
| 117 | *b = (self.sm.rx().wait_pull().await >> 24) as u8; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | /// Calculate CRC8 of the data | ||
| 122 | fn crc8(data: &[u8]) -> u8 { | ||
| 123 | let mut temp; | ||
| 124 | let mut data_byte; | ||
| 125 | let mut crc = 0; | ||
| 126 | for b in data { | ||
| 127 | data_byte = *b; | ||
| 128 | for _ in 0..8 { | ||
| 129 | temp = (crc ^ data_byte) & 0x01; | ||
| 130 | crc >>= 1; | ||
| 131 | if temp != 0 { | ||
| 132 | crc ^= 0x8C; | ||
| 133 | } | ||
| 134 | data_byte >>= 1; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | crc | ||
| 138 | } | ||
| 139 | |||
| 140 | /// Start a new measurement. Allow at least 1000ms before getting `temperature`. | ||
| 141 | pub async fn start(&mut self) { | ||
| 142 | self.write_bytes(&[0xCC, 0x44]).await; | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. | ||
| 146 | pub async fn temperature(&mut self) -> Result<f32, ()> { | ||
| 147 | self.write_bytes(&[0xCC, 0xBE]).await; | ||
| 148 | let mut data = [0; 9]; | ||
| 149 | self.read_bytes(&mut data).await; | ||
| 150 | match Self::crc8(&data) == 0 { | ||
| 151 | true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), | ||
| 152 | false => Err(()), | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs new file mode 100644 index 000000000..23d63d435 --- /dev/null +++ b/examples/rp/src/bin/pio_pwm.rs | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | //! This example shows how to create a pwm using the PIO module in the RP2040 chip. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use core::time::Duration; | ||
| 6 | |||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::gpio::Level; | ||
| 9 | use embassy_rp::peripherals::PIO0; | ||
| 10 | use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; | ||
| 11 | use embassy_rp::{bind_interrupts, clocks}; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use pio::InstructionOperands; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | const REFRESH_INTERVAL: u64 = 20000; | ||
| 17 | |||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 20 | }); | ||
| 21 | |||
| 22 | pub fn to_pio_cycles(duration: Duration) -> u32 { | ||
| 23 | (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow | ||
| 24 | } | ||
| 25 | |||
| 26 | pub struct PwmPio<'d, T: Instance, const SM: usize> { | ||
| 27 | sm: StateMachine<'d, T, SM>, | ||
| 28 | } | ||
| 29 | |||
| 30 | impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { | ||
| 31 | pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { | ||
| 32 | let prg = pio_proc::pio_asm!( | ||
| 33 | ".side_set 1 opt" | ||
| 34 | "pull noblock side 0" | ||
| 35 | "mov x, osr" | ||
| 36 | "mov y, isr" | ||
| 37 | "countloop:" | ||
| 38 | "jmp x!=y noset" | ||
| 39 | "jmp skip side 1" | ||
| 40 | "noset:" | ||
| 41 | "nop" | ||
| 42 | "skip:" | ||
| 43 | "jmp y-- countloop" | ||
| 44 | ); | ||
| 45 | |||
| 46 | pio.load_program(&prg.program); | ||
| 47 | let pin = pio.make_pio_pin(pin); | ||
| 48 | sm.set_pins(Level::High, &[&pin]); | ||
| 49 | sm.set_pin_dirs(Direction::Out, &[&pin]); | ||
| 50 | |||
| 51 | let mut cfg = Config::default(); | ||
| 52 | cfg.use_program(&pio.load_program(&prg.program), &[&pin]); | ||
| 53 | |||
| 54 | sm.set_config(&cfg); | ||
| 55 | |||
| 56 | Self { sm } | ||
| 57 | } | ||
| 58 | |||
| 59 | pub fn start(&mut self) { | ||
| 60 | self.sm.set_enable(true); | ||
| 61 | } | ||
| 62 | |||
| 63 | pub fn stop(&mut self) { | ||
| 64 | self.sm.set_enable(false); | ||
| 65 | } | ||
| 66 | |||
| 67 | pub fn set_period(&mut self, duration: Duration) { | ||
| 68 | let is_enabled = self.sm.is_enabled(); | ||
| 69 | while !self.sm.tx().empty() {} // Make sure that the queue is empty | ||
| 70 | self.sm.set_enable(false); | ||
| 71 | self.sm.tx().push(to_pio_cycles(duration)); | ||
| 72 | unsafe { | ||
| 73 | self.sm.exec_instr( | ||
| 74 | InstructionOperands::PULL { | ||
| 75 | if_empty: false, | ||
| 76 | block: false, | ||
| 77 | } | ||
| 78 | .encode(), | ||
| 79 | ); | ||
| 80 | self.sm.exec_instr( | ||
| 81 | InstructionOperands::OUT { | ||
| 82 | destination: ::pio::OutDestination::ISR, | ||
| 83 | bit_count: 32, | ||
| 84 | } | ||
| 85 | .encode(), | ||
| 86 | ); | ||
| 87 | }; | ||
| 88 | if is_enabled { | ||
| 89 | self.sm.set_enable(true) // Enable if previously enabled | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | pub fn set_level(&mut self, level: u32) { | ||
| 94 | self.sm.tx().push(level); | ||
| 95 | } | ||
| 96 | |||
| 97 | pub fn write(&mut self, duration: Duration) { | ||
| 98 | self.set_level(to_pio_cycles(duration)); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | #[embassy_executor::main] | ||
| 103 | async fn main(_spawner: Spawner) { | ||
| 104 | let p = embassy_rp::init(Default::default()); | ||
| 105 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); | ||
| 106 | |||
| 107 | // Note that PIN_25 is the led pin on the Pico | ||
| 108 | let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); | ||
| 109 | pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); | ||
| 110 | pwm_pio.start(); | ||
| 111 | |||
| 112 | let mut duration = 0; | ||
| 113 | loop { | ||
| 114 | duration = (duration + 1) % 1000; | ||
| 115 | pwm_pio.write(Duration::from_micros(duration)); | ||
| 116 | Timer::after_millis(1).await; | ||
| 117 | } | ||
| 118 | } | ||
diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs new file mode 100644 index 000000000..a79540479 --- /dev/null +++ b/examples/rp/src/bin/pio_servo.rs | |||
| @@ -0,0 +1,208 @@ | |||
| 1 | //! This example shows how to create a pwm using the PIO module in the RP2040 chip. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use core::time::Duration; | ||
| 6 | |||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::gpio::Level; | ||
| 9 | use embassy_rp::peripherals::PIO0; | ||
| 10 | use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; | ||
| 11 | use embassy_rp::{bind_interrupts, clocks}; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use pio::InstructionOperands; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo | ||
| 17 | const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo | ||
| 18 | const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical | ||
| 19 | const REFRESH_INTERVAL: u64 = 20000; // The period of each cycle | ||
| 20 | |||
| 21 | bind_interrupts!(struct Irqs { | ||
| 22 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 23 | }); | ||
| 24 | |||
| 25 | pub fn to_pio_cycles(duration: Duration) -> u32 { | ||
| 26 | (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow | ||
| 27 | } | ||
| 28 | |||
| 29 | pub struct PwmPio<'d, T: Instance, const SM: usize> { | ||
| 30 | sm: StateMachine<'d, T, SM>, | ||
| 31 | } | ||
| 32 | |||
| 33 | impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { | ||
| 34 | pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { | ||
| 35 | let prg = pio_proc::pio_asm!( | ||
| 36 | ".side_set 1 opt" | ||
| 37 | "pull noblock side 0" | ||
| 38 | "mov x, osr" | ||
| 39 | "mov y, isr" | ||
| 40 | "countloop:" | ||
| 41 | "jmp x!=y noset" | ||
| 42 | "jmp skip side 1" | ||
| 43 | "noset:" | ||
| 44 | "nop" | ||
| 45 | "skip:" | ||
| 46 | "jmp y-- countloop" | ||
| 47 | ); | ||
| 48 | |||
| 49 | pio.load_program(&prg.program); | ||
| 50 | let pin = pio.make_pio_pin(pin); | ||
| 51 | sm.set_pins(Level::High, &[&pin]); | ||
| 52 | sm.set_pin_dirs(Direction::Out, &[&pin]); | ||
| 53 | |||
| 54 | let mut cfg = Config::default(); | ||
| 55 | cfg.use_program(&pio.load_program(&prg.program), &[&pin]); | ||
| 56 | |||
| 57 | sm.set_config(&cfg); | ||
| 58 | |||
| 59 | Self { sm } | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn start(&mut self) { | ||
| 63 | self.sm.set_enable(true); | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn stop(&mut self) { | ||
| 67 | self.sm.set_enable(false); | ||
| 68 | } | ||
| 69 | |||
| 70 | pub fn set_period(&mut self, duration: Duration) { | ||
| 71 | let is_enabled = self.sm.is_enabled(); | ||
| 72 | while !self.sm.tx().empty() {} // Make sure that the queue is empty | ||
| 73 | self.sm.set_enable(false); | ||
| 74 | self.sm.tx().push(to_pio_cycles(duration)); | ||
| 75 | unsafe { | ||
| 76 | self.sm.exec_instr( | ||
| 77 | InstructionOperands::PULL { | ||
| 78 | if_empty: false, | ||
| 79 | block: false, | ||
| 80 | } | ||
| 81 | .encode(), | ||
| 82 | ); | ||
| 83 | self.sm.exec_instr( | ||
| 84 | InstructionOperands::OUT { | ||
| 85 | destination: ::pio::OutDestination::ISR, | ||
| 86 | bit_count: 32, | ||
| 87 | } | ||
| 88 | .encode(), | ||
| 89 | ); | ||
| 90 | }; | ||
| 91 | if is_enabled { | ||
| 92 | self.sm.set_enable(true) // Enable if previously enabled | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | pub fn set_level(&mut self, level: u32) { | ||
| 97 | self.sm.tx().push(level); | ||
| 98 | } | ||
| 99 | |||
| 100 | pub fn write(&mut self, duration: Duration) { | ||
| 101 | self.set_level(to_pio_cycles(duration)); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | pub struct ServoBuilder<'d, T: Instance, const SM: usize> { | ||
| 106 | pwm: PwmPio<'d, T, SM>, | ||
| 107 | period: Duration, | ||
| 108 | min_pulse_width: Duration, | ||
| 109 | max_pulse_width: Duration, | ||
| 110 | max_degree_rotation: u64, | ||
| 111 | } | ||
| 112 | |||
| 113 | impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { | ||
| 114 | pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { | ||
| 115 | Self { | ||
| 116 | pwm, | ||
| 117 | period: Duration::from_micros(REFRESH_INTERVAL), | ||
| 118 | min_pulse_width: Duration::from_micros(DEFAULT_MIN_PULSE_WIDTH), | ||
| 119 | max_pulse_width: Duration::from_micros(DEFAULT_MAX_PULSE_WIDTH), | ||
| 120 | max_degree_rotation: DEFAULT_MAX_DEGREE_ROTATION, | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | pub fn set_period(mut self, duration: Duration) -> Self { | ||
| 125 | self.period = duration; | ||
| 126 | self | ||
| 127 | } | ||
| 128 | |||
| 129 | pub fn set_min_pulse_width(mut self, duration: Duration) -> Self { | ||
| 130 | self.min_pulse_width = duration; | ||
| 131 | self | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn set_max_pulse_width(mut self, duration: Duration) -> Self { | ||
| 135 | self.max_pulse_width = duration; | ||
| 136 | self | ||
| 137 | } | ||
| 138 | |||
| 139 | pub fn set_max_degree_rotation(mut self, degree: u64) -> Self { | ||
| 140 | self.max_degree_rotation = degree; | ||
| 141 | self | ||
| 142 | } | ||
| 143 | |||
| 144 | pub fn build(mut self) -> Servo<'d, T, SM> { | ||
| 145 | self.pwm.set_period(self.period); | ||
| 146 | Servo { | ||
| 147 | pwm: self.pwm, | ||
| 148 | min_pulse_width: self.min_pulse_width, | ||
| 149 | max_pulse_width: self.max_pulse_width, | ||
| 150 | max_degree_rotation: self.max_degree_rotation, | ||
| 151 | } | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | pub struct Servo<'d, T: Instance, const SM: usize> { | ||
| 156 | pwm: PwmPio<'d, T, SM>, | ||
| 157 | min_pulse_width: Duration, | ||
| 158 | max_pulse_width: Duration, | ||
| 159 | max_degree_rotation: u64, | ||
| 160 | } | ||
| 161 | |||
| 162 | impl<'d, T: Instance, const SM: usize> Servo<'d, T, SM> { | ||
| 163 | pub fn start(&mut self) { | ||
| 164 | self.pwm.start(); | ||
| 165 | } | ||
| 166 | |||
| 167 | pub fn stop(&mut self) { | ||
| 168 | self.pwm.stop(); | ||
| 169 | } | ||
| 170 | |||
| 171 | pub fn write_time(&mut self, duration: Duration) { | ||
| 172 | self.pwm.write(duration); | ||
| 173 | } | ||
| 174 | |||
| 175 | pub fn rotate(&mut self, degree: u64) { | ||
| 176 | let degree_per_nano_second = (self.max_pulse_width.as_nanos() as u64 - self.min_pulse_width.as_nanos() as u64) | ||
| 177 | / self.max_degree_rotation; | ||
| 178 | let mut duration = | ||
| 179 | Duration::from_nanos(degree * degree_per_nano_second + self.min_pulse_width.as_nanos() as u64); | ||
| 180 | if self.max_pulse_width < duration { | ||
| 181 | duration = self.max_pulse_width; | ||
| 182 | } | ||
| 183 | |||
| 184 | self.pwm.write(duration); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | #[embassy_executor::main] | ||
| 189 | async fn main(_spawner: Spawner) { | ||
| 190 | let p = embassy_rp::init(Default::default()); | ||
| 191 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); | ||
| 192 | |||
| 193 | let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); | ||
| 194 | let mut servo = ServoBuilder::new(pwm_pio) | ||
| 195 | .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo | ||
| 196 | .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. | ||
| 197 | .set_max_pulse_width(Duration::from_micros(2600)) // Along with this value. | ||
| 198 | .build(); | ||
| 199 | |||
| 200 | servo.start(); | ||
| 201 | |||
| 202 | let mut degree = 0; | ||
| 203 | loop { | ||
| 204 | degree = (degree + 1) % 120; | ||
| 205 | servo.rotate(degree); | ||
| 206 | Timer::after_millis(50).await; | ||
| 207 | } | ||
| 208 | } | ||
diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index ab9ecf623..4952f4fbd 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs | |||
| @@ -69,7 +69,7 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { | |||
| 69 | let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed(); | 69 | let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed(); |
| 70 | assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); | 70 | assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); |
| 71 | assert!(clock_divider >= 1, "clkdiv must be >= 1"); | 71 | assert!(clock_divider >= 1, "clkdiv must be >= 1"); |
| 72 | T::PIO.sm(SM).clkdiv().write(|w| w.0 = clock_divider.to_bits() << 8); | 72 | self.sm.set_clock_divider(clock_divider); |
| 73 | self.sm.clkdiv_restart(); | 73 | self.sm.clkdiv_restart(); |
| 74 | } | 74 | } |
| 75 | 75 | ||
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index a07f1c180..53b696309 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs | |||
| @@ -60,7 +60,6 @@ async fn main(_spawner: Spawner) { | |||
| 60 | 60 | ||
| 61 | // Create embassy-usb DeviceBuilder using the driver and config. | 61 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 62 | // It needs some buffers for building the descriptors. | 62 | // It needs some buffers for building the descriptors. |
| 63 | let mut device_descriptor = [0; 256]; | ||
| 64 | let mut config_descriptor = [0; 256]; | 63 | let mut config_descriptor = [0; 256]; |
| 65 | let mut bos_descriptor = [0; 256]; | 64 | let mut bos_descriptor = [0; 256]; |
| 66 | let mut control_buf = [0; 64]; | 65 | let mut control_buf = [0; 64]; |
| @@ -70,7 +69,6 @@ async fn main(_spawner: Spawner) { | |||
| 70 | let mut builder = Builder::new( | 69 | let mut builder = Builder::new( |
| 71 | driver, | 70 | driver, |
| 72 | config, | 71 | config, |
| 73 | &mut device_descriptor, | ||
| 74 | &mut config_descriptor, | 72 | &mut config_descriptor, |
| 75 | &mut bos_descriptor, | 73 | &mut bos_descriptor, |
| 76 | &mut [], // no msos descriptors | 74 | &mut [], // no msos descriptors |
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index 9a97cb8a7..ac145933c 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs | |||
| @@ -12,7 +12,7 @@ use embassy_rp::pio::{ | |||
| 12 | Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, | 12 | Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, |
| 13 | }; | 13 | }; |
| 14 | use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; | 14 | use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; |
| 15 | use embassy_time::Timer; | 15 | use embassy_time::{Duration, Ticker, Timer}; |
| 16 | use fixed::types::U24F8; | 16 | use fixed::types::U24F8; |
| 17 | use fixed_macro::fixed; | 17 | use fixed_macro::fixed; |
| 18 | use smart_leds::RGB8; | 18 | use smart_leds::RGB8; |
| @@ -107,6 +107,8 @@ impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { | |||
| 107 | 107 | ||
| 108 | // DMA transfer | 108 | // DMA transfer |
| 109 | self.sm.tx().dma_push(self.dma.reborrow(), &words).await; | 109 | self.sm.tx().dma_push(self.dma.reborrow(), &words).await; |
| 110 | |||
| 111 | Timer::after_micros(55).await; | ||
| 110 | } | 112 | } |
| 111 | } | 113 | } |
| 112 | 114 | ||
| @@ -143,6 +145,7 @@ async fn main(_spawner: Spawner) { | |||
| 143 | let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); | 145 | let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); |
| 144 | 146 | ||
| 145 | // Loop forever making RGB values and pushing them out to the WS2812. | 147 | // Loop forever making RGB values and pushing them out to the WS2812. |
| 148 | let mut ticker = Ticker::every(Duration::from_millis(10)); | ||
| 146 | loop { | 149 | loop { |
| 147 | for j in 0..(256 * 5) { | 150 | for j in 0..(256 * 5) { |
| 148 | debug!("New Colors:"); | 151 | debug!("New Colors:"); |
| @@ -152,7 +155,7 @@ async fn main(_spawner: Spawner) { | |||
| 152 | } | 155 | } |
| 153 | ws2812.write(&data).await; | 156 | ws2812.write(&data).await; |
| 154 | 157 | ||
| 155 | Timer::after_millis(10).await; | 158 | ticker.next().await; |
| 156 | } | 159 | } |
| 157 | } | 160 | } |
| 158 | } | 161 | } |
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 4fb62546d..26e233260 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs | |||
| @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { | |||
| 18 | let mut c: Config = Default::default(); | 18 | let mut c: Config = Default::default(); |
| 19 | c.top = 0x8000; | 19 | c.top = 0x8000; |
| 20 | c.compare_b = 8; | 20 | c.compare_b = 8; |
| 21 | let mut pwm = Pwm::new_output_b(p.PWM_CH4, p.PIN_25, c.clone()); | 21 | let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); |
| 22 | 22 | ||
| 23 | loop { | 23 | loop { |
| 24 | info!("current LED duty cycle: {}/32768", c.compare_b); | 24 | info!("current LED duty cycle: {}/32768", c.compare_b); |
diff --git a/examples/rp/src/bin/pwm_input.rs b/examples/rp/src/bin/pwm_input.rs index e7bcbfbd4..bf454a936 100644 --- a/examples/rp/src/bin/pwm_input.rs +++ b/examples/rp/src/bin/pwm_input.rs | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_rp::gpio::Pull; | ||
| 8 | use embassy_rp::pwm::{Config, InputMode, Pwm}; | 9 | use embassy_rp::pwm::{Config, InputMode, Pwm}; |
| 9 | use embassy_time::{Duration, Ticker}; | 10 | use embassy_time::{Duration, Ticker}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -14,7 +15,7 @@ async fn main(_spawner: Spawner) { | |||
| 14 | let p = embassy_rp::init(Default::default()); | 15 | let p = embassy_rp::init(Default::default()); |
| 15 | 16 | ||
| 16 | let cfg: Config = Default::default(); | 17 | let cfg: Config = Default::default(); |
| 17 | let pwm = Pwm::new_input(p.PWM_CH2, p.PIN_5, InputMode::RisingEdge, cfg); | 18 | let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, Pull::None, InputMode::RisingEdge, cfg); |
| 18 | 19 | ||
| 19 | let mut ticker = Ticker::every(Duration::from_secs(1)); | 20 | let mut ticker = Ticker::every(Duration::from_secs(1)); |
| 20 | loop { | 21 | loop { |
diff --git a/examples/rp/src/bin/shared_bus.rs b/examples/rp/src/bin/shared_bus.rs new file mode 100644 index 000000000..c6cb5d64c --- /dev/null +++ b/examples/rp/src/bin/shared_bus.rs | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | //! This example shows how to share (async) I2C and SPI buses between multiple devices. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; | ||
| 8 | use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::gpio::{AnyPin, Level, Output}; | ||
| 12 | use embassy_rp::i2c::{self, I2c, InterruptHandler}; | ||
| 13 | use embassy_rp::peripherals::{I2C1, SPI1}; | ||
| 14 | use embassy_rp::spi::{self, Spi}; | ||
| 15 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 16 | use embassy_sync::mutex::Mutex; | ||
| 17 | use embassy_time::Timer; | ||
| 18 | use static_cell::StaticCell; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | type Spi1Bus = Mutex<NoopRawMutex, Spi<'static, SPI1, spi::Async>>; | ||
| 22 | type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>; | ||
| 23 | |||
| 24 | bind_interrupts!(struct Irqs { | ||
| 25 | I2C1_IRQ => InterruptHandler<I2C1>; | ||
| 26 | }); | ||
| 27 | |||
| 28 | #[embassy_executor::main] | ||
| 29 | async fn main(spawner: Spawner) { | ||
| 30 | let p = embassy_rp::init(Default::default()); | ||
| 31 | info!("Here we go!"); | ||
| 32 | |||
| 33 | // Shared I2C bus | ||
| 34 | let i2c = I2c::new_async(p.I2C1, p.PIN_15, p.PIN_14, Irqs, i2c::Config::default()); | ||
| 35 | static I2C_BUS: StaticCell<I2c1Bus> = StaticCell::new(); | ||
| 36 | let i2c_bus = I2C_BUS.init(Mutex::new(i2c)); | ||
| 37 | |||
| 38 | spawner.must_spawn(i2c_task_a(i2c_bus)); | ||
| 39 | spawner.must_spawn(i2c_task_b(i2c_bus)); | ||
| 40 | |||
| 41 | // Shared SPI bus | ||
| 42 | let spi_cfg = spi::Config::default(); | ||
| 43 | let spi = Spi::new(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, spi_cfg); | ||
| 44 | static SPI_BUS: StaticCell<Spi1Bus> = StaticCell::new(); | ||
| 45 | let spi_bus = SPI_BUS.init(Mutex::new(spi)); | ||
| 46 | |||
| 47 | // Chip select pins for the SPI devices | ||
| 48 | let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); | ||
| 49 | let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); | ||
| 50 | |||
| 51 | spawner.must_spawn(spi_task_a(spi_bus, cs_a)); | ||
| 52 | spawner.must_spawn(spi_task_b(spi_bus, cs_b)); | ||
| 53 | } | ||
| 54 | |||
| 55 | #[embassy_executor::task] | ||
| 56 | async fn i2c_task_a(i2c_bus: &'static I2c1Bus) { | ||
| 57 | let i2c_dev = I2cDevice::new(i2c_bus); | ||
| 58 | let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xC0); | ||
| 59 | loop { | ||
| 60 | info!("i2c task A"); | ||
| 61 | Timer::after_secs(1).await; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | #[embassy_executor::task] | ||
| 66 | async fn i2c_task_b(i2c_bus: &'static I2c1Bus) { | ||
| 67 | let i2c_dev = I2cDevice::new(i2c_bus); | ||
| 68 | let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xDE); | ||
| 69 | loop { | ||
| 70 | info!("i2c task B"); | ||
| 71 | Timer::after_secs(1).await; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | #[embassy_executor::task] | ||
| 76 | async fn spi_task_a(spi_bus: &'static Spi1Bus, cs: Output<'static>) { | ||
| 77 | let spi_dev = SpiDevice::new(spi_bus, cs); | ||
| 78 | let _sensor = DummySpiDeviceDriver::new(spi_dev); | ||
| 79 | loop { | ||
| 80 | info!("spi task A"); | ||
| 81 | Timer::after_secs(1).await; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | #[embassy_executor::task] | ||
| 86 | async fn spi_task_b(spi_bus: &'static Spi1Bus, cs: Output<'static>) { | ||
| 87 | let spi_dev = SpiDevice::new(spi_bus, cs); | ||
| 88 | let _sensor = DummySpiDeviceDriver::new(spi_dev); | ||
| 89 | loop { | ||
| 90 | info!("spi task B"); | ||
| 91 | Timer::after_secs(1).await; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | // Dummy I2C device driver, using `embedded-hal-async` | ||
| 96 | struct DummyI2cDeviceDriver<I2C: embedded_hal_async::i2c::I2c> { | ||
| 97 | _i2c: I2C, | ||
| 98 | } | ||
| 99 | |||
| 100 | impl<I2C: embedded_hal_async::i2c::I2c> DummyI2cDeviceDriver<I2C> { | ||
| 101 | fn new(i2c_dev: I2C, _address: u8) -> Self { | ||
| 102 | Self { _i2c: i2c_dev } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | // Dummy SPI device driver, using `embedded-hal-async` | ||
| 107 | struct DummySpiDeviceDriver<SPI: embedded_hal_async::spi::SpiDevice> { | ||
| 108 | _spi: SPI, | ||
| 109 | } | ||
| 110 | |||
| 111 | impl<SPI: embedded_hal_async::spi::SpiDevice> DummySpiDeviceDriver<SPI> { | ||
| 112 | fn new(spi_dev: SPI) -> Self { | ||
| 113 | Self { _spi: spi_dev } | ||
| 114 | } | ||
| 115 | } | ||
diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs new file mode 100644 index 000000000..5416e20ce --- /dev/null +++ b/examples/rp/src/bin/sharing.rs | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | //! This example shows some common strategies for sharing resources between tasks. | ||
| 2 | //! | ||
| 3 | //! We demonstrate five different ways of sharing, covering different use cases: | ||
| 4 | //! - Atomics: This method is used for simple values, such as bool and u8..u32 | ||
| 5 | //! - Blocking Mutex: This is used for sharing non-async things, using Cell/RefCell for interior mutability. | ||
| 6 | //! - Async Mutex: This is used for sharing async resources, where you need to hold the lock across await points. | ||
| 7 | //! The async Mutex has interior mutability built-in, so no RefCell is needed. | ||
| 8 | //! - Cell: For sharing Copy types between tasks running on the same executor. | ||
| 9 | //! - RefCell: When you want &mut access to a value shared between tasks running on the same executor. | ||
| 10 | //! | ||
| 11 | //! More information: https://embassy.dev/book/#_sharing_peripherals_between_tasks | ||
| 12 | |||
| 13 | #![no_std] | ||
| 14 | #![no_main] | ||
| 15 | |||
| 16 | use core::cell::{Cell, RefCell}; | ||
| 17 | use core::sync::atomic::{AtomicU32, Ordering}; | ||
| 18 | |||
| 19 | use cortex_m_rt::entry; | ||
| 20 | use defmt::info; | ||
| 21 | use embassy_executor::{Executor, InterruptExecutor}; | ||
| 22 | use embassy_rp::clocks::RoscRng; | ||
| 23 | use embassy_rp::interrupt::{InterruptExt, Priority}; | ||
| 24 | use embassy_rp::peripherals::UART0; | ||
| 25 | use embassy_rp::uart::{self, InterruptHandler, UartTx}; | ||
| 26 | use embassy_rp::{bind_interrupts, interrupt}; | ||
| 27 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 28 | use embassy_sync::{blocking_mutex, mutex}; | ||
| 29 | use embassy_time::{Duration, Ticker}; | ||
| 30 | use rand::RngCore; | ||
| 31 | use static_cell::{ConstStaticCell, StaticCell}; | ||
| 32 | use {defmt_rtt as _, panic_probe as _}; | ||
| 33 | |||
| 34 | type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; | ||
| 35 | |||
| 36 | struct MyType { | ||
| 37 | inner: u32, | ||
| 38 | } | ||
| 39 | |||
| 40 | static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new(); | ||
| 41 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | ||
| 42 | |||
| 43 | // Use Atomics for simple values | ||
| 44 | static ATOMIC: AtomicU32 = AtomicU32::new(0); | ||
| 45 | |||
| 46 | // Use blocking Mutex with Cell/RefCell for sharing non-async things | ||
| 47 | static MUTEX_BLOCKING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<MyType>> = | ||
| 48 | blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 })); | ||
| 49 | |||
| 50 | bind_interrupts!(struct Irqs { | ||
| 51 | UART0_IRQ => InterruptHandler<UART0>; | ||
| 52 | }); | ||
| 53 | |||
| 54 | #[interrupt] | ||
| 55 | unsafe fn SWI_IRQ_0() { | ||
| 56 | EXECUTOR_HI.on_interrupt() | ||
| 57 | } | ||
| 58 | |||
| 59 | #[entry] | ||
| 60 | fn main() -> ! { | ||
| 61 | let p = embassy_rp::init(Default::default()); | ||
| 62 | info!("Here we go!"); | ||
| 63 | |||
| 64 | let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default()); | ||
| 65 | // Use the async Mutex for sharing async things (built-in interior mutability) | ||
| 66 | static UART: StaticCell<UartAsyncMutex> = StaticCell::new(); | ||
| 67 | let uart = UART.init(mutex::Mutex::new(uart)); | ||
| 68 | |||
| 69 | // High-priority executor: runs in interrupt mode | ||
| 70 | interrupt::SWI_IRQ_0.set_priority(Priority::P3); | ||
| 71 | let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0); | ||
| 72 | spawner.must_spawn(task_a(uart)); | ||
| 73 | |||
| 74 | // Low priority executor: runs in thread mode | ||
| 75 | let executor = EXECUTOR_LOW.init(Executor::new()); | ||
| 76 | executor.run(|spawner| { | ||
| 77 | // No Mutex needed when sharing between tasks running on the same executor | ||
| 78 | |||
| 79 | // Use Cell for Copy-types | ||
| 80 | static CELL: ConstStaticCell<Cell<[u8; 4]>> = ConstStaticCell::new(Cell::new([0; 4])); | ||
| 81 | let cell = CELL.take(); | ||
| 82 | |||
| 83 | // Use RefCell for &mut access | ||
| 84 | static REF_CELL: ConstStaticCell<RefCell<MyType>> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 })); | ||
| 85 | let ref_cell = REF_CELL.take(); | ||
| 86 | |||
| 87 | spawner.must_spawn(task_b(uart, cell, ref_cell)); | ||
| 88 | spawner.must_spawn(task_c(cell, ref_cell)); | ||
| 89 | }); | ||
| 90 | } | ||
| 91 | |||
| 92 | #[embassy_executor::task] | ||
| 93 | async fn task_a(uart: &'static UartAsyncMutex) { | ||
| 94 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 95 | loop { | ||
| 96 | let random = RoscRng.next_u32(); | ||
| 97 | |||
| 98 | { | ||
| 99 | let mut uart = uart.lock().await; | ||
| 100 | uart.write(b"task a").await.unwrap(); | ||
| 101 | // The uart lock is released when it goes out of scope | ||
| 102 | } | ||
| 103 | |||
| 104 | ATOMIC.store(random, Ordering::Relaxed); | ||
| 105 | |||
| 106 | MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random); | ||
| 107 | |||
| 108 | ticker.next().await; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | #[embassy_executor::task] | ||
| 113 | async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) { | ||
| 114 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 115 | loop { | ||
| 116 | let random = RoscRng.next_u32(); | ||
| 117 | |||
| 118 | uart.lock().await.write(b"task b").await.unwrap(); | ||
| 119 | |||
| 120 | cell.set(random.to_be_bytes()); | ||
| 121 | |||
| 122 | ref_cell.borrow_mut().inner = random; | ||
| 123 | |||
| 124 | ticker.next().await; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | #[embassy_executor::task] | ||
| 129 | async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) { | ||
| 130 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 131 | loop { | ||
| 132 | info!("======================="); | ||
| 133 | |||
| 134 | let atomic_val = ATOMIC.load(Ordering::Relaxed); | ||
| 135 | info!("atomic: {}", atomic_val); | ||
| 136 | |||
| 137 | MUTEX_BLOCKING.lock(|x| { | ||
| 138 | let val = x.borrow().inner; | ||
| 139 | info!("blocking mutex: {}", val); | ||
| 140 | }); | ||
| 141 | |||
| 142 | let cell_val = cell.get(); | ||
| 143 | info!("cell: {:?}", cell_val); | ||
| 144 | |||
| 145 | let ref_cell_val = ref_cell.borrow().inner; | ||
| 146 | info!("ref_cell: {:?}", ref_cell_val); | ||
| 147 | |||
| 148 | ticker.next().await; | ||
| 149 | } | ||
| 150 | } | ||
diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs new file mode 100644 index 000000000..4cbc82f7b --- /dev/null +++ b/examples/rp/src/bin/spi_sdmmc.rs | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | //! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI. | ||
| 2 | //! | ||
| 3 | //! The example will attempt to read a file `MY_FILE.TXT` from the root directory | ||
| 4 | //! of the SD card and print its contents. | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_embedded_hal::SetConfig; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_rp::spi::Spi; | ||
| 13 | use embassy_rp::{gpio, spi}; | ||
| 14 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 15 | use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; | ||
| 16 | use gpio::{Level, Output}; | ||
| 17 | use {defmt_rtt as _, panic_probe as _}; | ||
| 18 | |||
| 19 | struct DummyTimesource(); | ||
| 20 | |||
| 21 | impl embedded_sdmmc::TimeSource for DummyTimesource { | ||
| 22 | fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { | ||
| 23 | embedded_sdmmc::Timestamp { | ||
| 24 | year_since_1970: 0, | ||
| 25 | zero_indexed_month: 0, | ||
| 26 | zero_indexed_day: 0, | ||
| 27 | hours: 0, | ||
| 28 | minutes: 0, | ||
| 29 | seconds: 0, | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | #[embassy_executor::main] | ||
| 35 | async fn main(_spawner: Spawner) { | ||
| 36 | embassy_rp::pac::SIO.spinlock(31).write_value(1); | ||
| 37 | let p = embassy_rp::init(Default::default()); | ||
| 38 | |||
| 39 | // SPI clock needs to be running at <= 400kHz during initialization | ||
| 40 | let mut config = spi::Config::default(); | ||
| 41 | config.frequency = 400_000; | ||
| 42 | let spi = Spi::new_blocking(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, config); | ||
| 43 | // Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons | ||
| 44 | let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin); | ||
| 45 | // Real cs pin | ||
| 46 | let cs = Output::new(p.PIN_16, Level::High); | ||
| 47 | |||
| 48 | let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay); | ||
| 49 | info!("Card size is {} bytes", sdcard.num_bytes().unwrap()); | ||
| 50 | |||
| 51 | // Now that the card is initialized, the SPI clock can go faster | ||
| 52 | let mut config = spi::Config::default(); | ||
| 53 | config.frequency = 16_000_000; | ||
| 54 | sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); | ||
| 55 | |||
| 56 | // Now let's look for volumes (also known as partitions) on our block device. | ||
| 57 | // To do this we need a Volume Manager. It will take ownership of the block device. | ||
| 58 | let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, DummyTimesource()); | ||
| 59 | |||
| 60 | // Try and access Volume 0 (i.e. the first partition). | ||
| 61 | // The volume object holds information about the filesystem on that volume. | ||
| 62 | let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)).unwrap(); | ||
| 63 | info!("Volume 0: {:?}", defmt::Debug2Format(&volume0)); | ||
| 64 | |||
| 65 | // Open the root directory (mutably borrows from the volume). | ||
| 66 | let mut root_dir = volume0.open_root_dir().unwrap(); | ||
| 67 | |||
| 68 | // Open a file called "MY_FILE.TXT" in the root directory | ||
| 69 | // This mutably borrows the directory. | ||
| 70 | let mut my_file = root_dir | ||
| 71 | .open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly) | ||
| 72 | .unwrap(); | ||
| 73 | |||
| 74 | // Print the contents of the file | ||
| 75 | while !my_file.is_eof() { | ||
| 76 | let mut buf = [0u8; 32]; | ||
| 77 | if let Ok(n) = my_file.read(&mut buf) { | ||
| 78 | info!("{:a}", buf[..n]); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | loop {} | ||
| 83 | } | ||
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index fac61aa04..468d2b61a 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs | |||
| @@ -31,7 +31,7 @@ async fn main(spawner: Spawner) { | |||
| 31 | static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); | 31 | static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); |
| 32 | let rx_buf = &mut RX_BUF.init([0; 16])[..]; | 32 | let rx_buf = &mut RX_BUF.init([0; 16])[..]; |
| 33 | let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); | 33 | let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); |
| 34 | let (rx, mut tx) = uart.split(); | 34 | let (mut tx, rx) = uart.split(); |
| 35 | 35 | ||
| 36 | unwrap!(spawner.spawn(reader(rx))); | 36 | unwrap!(spawner.spawn(reader(rx))); |
| 37 | 37 | ||
diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs new file mode 100644 index 000000000..085be280b --- /dev/null +++ b/examples/rp/src/bin/uart_r503.rs | |||
| @@ -0,0 +1,158 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{debug, error, info}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_rp::bind_interrupts; | ||
| 7 | use embassy_rp::peripherals::UART0; | ||
| 8 | use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; | ||
| 9 | use embassy_time::{with_timeout, Duration, Timer}; | ||
| 10 | use heapless::Vec; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | bind_interrupts!(pub struct Irqs { | ||
| 14 | UART0_IRQ => UARTInterruptHandler<UART0>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | const START: u16 = 0xEF01; | ||
| 18 | const ADDRESS: u32 = 0xFFFFFFFF; | ||
| 19 | |||
| 20 | // ================================================================================ | ||
| 21 | |||
| 22 | // Data package format | ||
| 23 | // Name Length Description | ||
| 24 | // ========================================================================================================== | ||
| 25 | // Start 2 bytes Fixed value of 0xEF01; High byte transferred first. | ||
| 26 | // Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command. | ||
| 27 | // High byte transferred first and at wrong adder value, module | ||
| 28 | // will reject to transfer. | ||
| 29 | // PID 1 byte 01H Command packet; | ||
| 30 | // 02H Data packet; Data packet shall not appear alone in executing | ||
| 31 | // processs, must follow command packet or acknowledge packet. | ||
| 32 | // 07H Acknowledge packet; | ||
| 33 | // 08H End of Data packet. | ||
| 34 | // LENGTH 2 bytes Refers to the length of package content (command packets and data packets) | ||
| 35 | // plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes. | ||
| 36 | // And high byte is transferred first. | ||
| 37 | // DATA - It can be commands, data, command’s parameters, acknowledge result, etc. | ||
| 38 | // (fingerprint character value, template are all deemed as data); | ||
| 39 | // SUM 2 bytes The arithmetic sum of package identifier, package length and all package | ||
| 40 | // contens. Overflowing bits are omitted. high byte is transferred first. | ||
| 41 | |||
| 42 | // ================================================================================ | ||
| 43 | |||
| 44 | // Checksum is calculated on 'length (2 bytes) + data (??)'. | ||
| 45 | fn compute_checksum(buf: Vec<u8, 32>) -> u16 { | ||
| 46 | let mut checksum = 0u16; | ||
| 47 | |||
| 48 | let check_end = buf.len(); | ||
| 49 | let checked_bytes = &buf[6..check_end]; | ||
| 50 | for byte in checked_bytes { | ||
| 51 | checksum += (*byte) as u16; | ||
| 52 | } | ||
| 53 | return checksum; | ||
| 54 | } | ||
| 55 | |||
| 56 | #[embassy_executor::main] | ||
| 57 | async fn main(_spawner: Spawner) { | ||
| 58 | info!("Start"); | ||
| 59 | |||
| 60 | let p = embassy_rp::init(Default::default()); | ||
| 61 | |||
| 62 | // Initialize the fingerprint scanner. | ||
| 63 | let mut config = Config::default(); | ||
| 64 | config.baudrate = 57600; | ||
| 65 | config.stop_bits = StopBits::STOP1; | ||
| 66 | config.data_bits = DataBits::DataBits8; | ||
| 67 | config.parity = Parity::ParityNone; | ||
| 68 | |||
| 69 | let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1); | ||
| 70 | let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config); | ||
| 71 | let (mut tx, mut rx) = uart.split(); | ||
| 72 | |||
| 73 | let mut vec_buf: Vec<u8, 32> = heapless::Vec::new(); | ||
| 74 | let mut data: Vec<u8, 32> = heapless::Vec::new(); | ||
| 75 | |||
| 76 | let mut speeds: Vec<u8, 3> = heapless::Vec::new(); | ||
| 77 | let _ = speeds.push(0xC8); // Slow | ||
| 78 | let _ = speeds.push(0x20); // Medium | ||
| 79 | let _ = speeds.push(0x02); // Fast | ||
| 80 | |||
| 81 | // Cycle through the three colours Red, Blue and Purple forever. | ||
| 82 | loop { | ||
| 83 | for colour in 1..=3 { | ||
| 84 | for speed in &speeds { | ||
| 85 | // Set the data first, because the length is dependent on that. | ||
| 86 | // However, we write the length bits before we do the data. | ||
| 87 | data.clear(); | ||
| 88 | let _ = data.push(0x01); // ctrl=Breathing light | ||
| 89 | let _ = data.push(*speed); | ||
| 90 | let _ = data.push(colour as u8); // colour=Red, Blue, Purple | ||
| 91 | let _ = data.push(0x00); // times=Infinite | ||
| 92 | |||
| 93 | // Clear buffers | ||
| 94 | vec_buf.clear(); | ||
| 95 | |||
| 96 | // START | ||
| 97 | let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]); | ||
| 98 | |||
| 99 | // ADDRESS | ||
| 100 | let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]); | ||
| 101 | |||
| 102 | // PID | ||
| 103 | let _ = vec_buf.extend_from_slice(&[0x01]); | ||
| 104 | |||
| 105 | // LENGTH | ||
| 106 | let len: u16 = (1 + data.len() + 2).try_into().unwrap(); | ||
| 107 | let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]); | ||
| 108 | |||
| 109 | // COMMAND | ||
| 110 | let _ = vec_buf.push(0x35); // Command: AuraLedConfig | ||
| 111 | |||
| 112 | // DATA | ||
| 113 | let _ = vec_buf.extend_from_slice(&data); | ||
| 114 | |||
| 115 | // SUM | ||
| 116 | let chk = compute_checksum(vec_buf.clone()); | ||
| 117 | let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]); | ||
| 118 | |||
| 119 | // ===== | ||
| 120 | |||
| 121 | // Send command buffer. | ||
| 122 | let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); | ||
| 123 | debug!(" write='{:?}'", data_write[..]); | ||
| 124 | match tx.write(&data_write).await { | ||
| 125 | Ok(..) => info!("Write successful."), | ||
| 126 | Err(e) => error!("Write error: {:?}", e), | ||
| 127 | } | ||
| 128 | |||
| 129 | // ===== | ||
| 130 | |||
| 131 | // Read command buffer. | ||
| 132 | let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! | ||
| 133 | let mut data_read: Vec<u8, 32> = heapless::Vec::new(); // Save buffer. | ||
| 134 | |||
| 135 | info!("Attempting read."); | ||
| 136 | loop { | ||
| 137 | // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms | ||
| 138 | // for this command. | ||
| 139 | match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await { | ||
| 140 | Ok(..) => { | ||
| 141 | // Extract and save read byte. | ||
| 142 | debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]); | ||
| 143 | let _ = data_read.push(read_buf[0]).unwrap(); | ||
| 144 | } | ||
| 145 | Err(..) => break, // TimeoutError -> Ignore. | ||
| 146 | } | ||
| 147 | } | ||
| 148 | info!("Read successful"); | ||
| 149 | debug!(" read='{:?}'", data_read[..]); | ||
| 150 | |||
| 151 | Timer::after_secs(3).await; | ||
| 152 | info!("Changing speed."); | ||
| 153 | } | ||
| 154 | |||
| 155 | info!("Changing colour."); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 01f0d5967..9a15125d4 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs | |||
| @@ -8,7 +8,8 @@ | |||
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_net::tcp::TcpSocket; | 10 | use embassy_net::tcp::TcpSocket; |
| 11 | use embassy_net::{Stack, StackResources}; | 11 | use embassy_net::StackResources; |
| 12 | use embassy_rp::clocks::RoscRng; | ||
| 12 | use embassy_rp::peripherals::USB; | 13 | use embassy_rp::peripherals::USB; |
| 13 | use embassy_rp::usb::{Driver, InterruptHandler}; | 14 | use embassy_rp::usb::{Driver, InterruptHandler}; |
| 14 | use embassy_rp::{bind_interrupts, peripherals}; | 15 | use embassy_rp::{bind_interrupts, peripherals}; |
| @@ -16,6 +17,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState | |||
| 16 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 17 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 17 | use embassy_usb::{Builder, Config, UsbDevice}; | 18 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 18 | use embedded_io_async::Write; | 19 | use embedded_io_async::Write; |
| 20 | use rand::RngCore; | ||
| 19 | use static_cell::StaticCell; | 21 | use static_cell::StaticCell; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 21 | 23 | ||
| @@ -38,13 +40,14 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { | |||
| 38 | } | 40 | } |
| 39 | 41 | ||
| 40 | #[embassy_executor::task] | 42 | #[embassy_executor::task] |
| 41 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 43 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { |
| 42 | stack.run().await | 44 | runner.run().await |
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | #[embassy_executor::main] | 47 | #[embassy_executor::main] |
| 46 | async fn main(spawner: Spawner) { | 48 | async fn main(spawner: Spawner) { |
| 47 | let p = embassy_rp::init(Default::default()); | 49 | let p = embassy_rp::init(Default::default()); |
| 50 | let mut rng = RoscRng; | ||
| 48 | 51 | ||
| 49 | // Create the driver, from the HAL. | 52 | // Create the driver, from the HAL. |
| 50 | let driver = Driver::new(p.USB, Irqs); | 53 | let driver = Driver::new(p.USB, Irqs); |
| @@ -64,14 +67,12 @@ async fn main(spawner: Spawner) { | |||
| 64 | config.device_protocol = 0x01; | 67 | config.device_protocol = 0x01; |
| 65 | 68 | ||
| 66 | // Create embassy-usb DeviceBuilder using the driver and config. | 69 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 67 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 68 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 70 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 69 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 71 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 70 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 72 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 71 | let mut builder = Builder::new( | 73 | let mut builder = Builder::new( |
| 72 | driver, | 74 | driver, |
| 73 | config, | 75 | config, |
| 74 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 75 | &mut CONFIG_DESC.init([0; 256])[..], | 76 | &mut CONFIG_DESC.init([0; 256])[..], |
| 76 | &mut BOS_DESC.init([0; 256])[..], | 77 | &mut BOS_DESC.init([0; 256])[..], |
| 77 | &mut [], // no msos descriptors | 78 | &mut [], // no msos descriptors |
| @@ -104,19 +105,13 @@ async fn main(spawner: Spawner) { | |||
| 104 | //}); | 105 | //}); |
| 105 | 106 | ||
| 106 | // Generate random seed | 107 | // Generate random seed |
| 107 | let seed = 1234; // guaranteed random, chosen by a fair dice roll | 108 | let seed = rng.next_u64(); |
| 108 | 109 | ||
| 109 | // Init network stack | 110 | // Init network stack |
| 110 | static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); | 111 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 111 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 112 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 112 | let stack = &*STACK.init(Stack::new( | ||
| 113 | device, | ||
| 114 | config, | ||
| 115 | RESOURCES.init(StackResources::<2>::new()), | ||
| 116 | seed, | ||
| 117 | )); | ||
| 118 | 113 | ||
| 119 | unwrap!(spawner.spawn(net_task(stack))); | 114 | unwrap!(spawner.spawn(net_task(runner))); |
| 120 | 115 | ||
| 121 | // And now we can use it! | 116 | // And now we can use it! |
| 122 | 117 | ||
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index b5ac16245..a7cb322d8 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs | |||
| @@ -36,13 +36,12 @@ async fn main(_spawner: Spawner) { | |||
| 36 | 36 | ||
| 37 | // Create embassy-usb DeviceBuilder using the driver and config. | 37 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 38 | // It needs some buffers for building the descriptors. | 38 | // It needs some buffers for building the descriptors. |
| 39 | let mut device_descriptor = [0; 256]; | ||
| 40 | let mut config_descriptor = [0; 256]; | 39 | let mut config_descriptor = [0; 256]; |
| 41 | let mut bos_descriptor = [0; 256]; | 40 | let mut bos_descriptor = [0; 256]; |
| 42 | // You can also add a Microsoft OS descriptor. | 41 | // You can also add a Microsoft OS descriptor. |
| 43 | let mut msos_descriptor = [0; 256]; | 42 | let mut msos_descriptor = [0; 256]; |
| 44 | let mut control_buf = [0; 64]; | 43 | let mut control_buf = [0; 64]; |
| 45 | let request_handler = MyRequestHandler {}; | 44 | let mut request_handler = MyRequestHandler {}; |
| 46 | let mut device_handler = MyDeviceHandler::new(); | 45 | let mut device_handler = MyDeviceHandler::new(); |
| 47 | 46 | ||
| 48 | let mut state = State::new(); | 47 | let mut state = State::new(); |
| @@ -50,7 +49,6 @@ async fn main(_spawner: Spawner) { | |||
| 50 | let mut builder = Builder::new( | 49 | let mut builder = Builder::new( |
| 51 | driver, | 50 | driver, |
| 52 | config, | 51 | config, |
| 53 | &mut device_descriptor, | ||
| 54 | &mut config_descriptor, | 52 | &mut config_descriptor, |
| 55 | &mut bos_descriptor, | 53 | &mut bos_descriptor, |
| 56 | &mut msos_descriptor, | 54 | &mut msos_descriptor, |
| @@ -62,7 +60,7 @@ async fn main(_spawner: Spawner) { | |||
| 62 | // Create classes on the builder. | 60 | // Create classes on the builder. |
| 63 | let config = embassy_usb::class::hid::Config { | 61 | let config = embassy_usb::class::hid::Config { |
| 64 | report_descriptor: KeyboardReport::desc(), | 62 | report_descriptor: KeyboardReport::desc(), |
| 65 | request_handler: Some(&request_handler), | 63 | request_handler: None, |
| 66 | poll_ms: 60, | 64 | poll_ms: 60, |
| 67 | max_packet_size: 64, | 65 | max_packet_size: 64, |
| 68 | }; | 66 | }; |
| @@ -116,7 +114,7 @@ async fn main(_spawner: Spawner) { | |||
| 116 | }; | 114 | }; |
| 117 | 115 | ||
| 118 | let out_fut = async { | 116 | let out_fut = async { |
| 119 | reader.run(false, &request_handler).await; | 117 | reader.run(false, &mut request_handler).await; |
| 120 | }; | 118 | }; |
| 121 | 119 | ||
| 122 | // Run everything concurrently. | 120 | // Run everything concurrently. |
| @@ -127,21 +125,21 @@ async fn main(_spawner: Spawner) { | |||
| 127 | struct MyRequestHandler {} | 125 | struct MyRequestHandler {} |
| 128 | 126 | ||
| 129 | impl RequestHandler for MyRequestHandler { | 127 | impl RequestHandler for MyRequestHandler { |
| 130 | fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | 128 | fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { |
| 131 | info!("Get report for {:?}", id); | 129 | info!("Get report for {:?}", id); |
| 132 | None | 130 | None |
| 133 | } | 131 | } |
| 134 | 132 | ||
| 135 | fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { | 133 | fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { |
| 136 | info!("Set report for {:?}: {=[u8]}", id, data); | 134 | info!("Set report for {:?}: {=[u8]}", id, data); |
| 137 | OutResponse::Accepted | 135 | OutResponse::Accepted |
| 138 | } | 136 | } |
| 139 | 137 | ||
| 140 | fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { | 138 | fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { |
| 141 | info!("Set idle rate for {:?} to {:?}", id, dur); | 139 | info!("Set idle rate for {:?} to {:?}", id, dur); |
| 142 | } | 140 | } |
| 143 | 141 | ||
| 144 | fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { | 142 | fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> { |
| 145 | info!("Get idle rate for {:?}", id); | 143 | info!("Get idle rate for {:?}", id); |
| 146 | None | 144 | None |
| 147 | } | 145 | } |
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs new file mode 100644 index 000000000..5ee650910 --- /dev/null +++ b/examples/rp/src/bin/usb_hid_mouse.rs | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_futures::join::join; | ||
| 9 | use embassy_rp::bind_interrupts; | ||
| 10 | use embassy_rp::clocks::RoscRng; | ||
| 11 | use embassy_rp::peripherals::USB; | ||
| 12 | use embassy_rp::usb::{Driver, InterruptHandler}; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | ||
| 15 | use embassy_usb::control::OutResponse; | ||
| 16 | use embassy_usb::{Builder, Config, Handler}; | ||
| 17 | use rand::Rng; | ||
| 18 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | bind_interrupts!(struct Irqs { | ||
| 22 | USBCTRL_IRQ => InterruptHandler<USB>; | ||
| 23 | }); | ||
| 24 | |||
| 25 | #[embassy_executor::main] | ||
| 26 | async fn main(_spawner: Spawner) { | ||
| 27 | let p = embassy_rp::init(Default::default()); | ||
| 28 | // Create the driver, from the HAL. | ||
| 29 | let driver = Driver::new(p.USB, Irqs); | ||
| 30 | |||
| 31 | // Create embassy-usb Config | ||
| 32 | let mut config = Config::new(0xc0de, 0xcafe); | ||
| 33 | config.manufacturer = Some("Embassy"); | ||
| 34 | config.product = Some("HID keyboard example"); | ||
| 35 | config.serial_number = Some("12345678"); | ||
| 36 | config.max_power = 100; | ||
| 37 | config.max_packet_size_0 = 64; | ||
| 38 | |||
| 39 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 40 | // It needs some buffers for building the descriptors. | ||
| 41 | let mut config_descriptor = [0; 256]; | ||
| 42 | let mut bos_descriptor = [0; 256]; | ||
| 43 | // You can also add a Microsoft OS descriptor. | ||
| 44 | let mut msos_descriptor = [0; 256]; | ||
| 45 | let mut control_buf = [0; 64]; | ||
| 46 | let mut request_handler = MyRequestHandler {}; | ||
| 47 | let mut device_handler = MyDeviceHandler::new(); | ||
| 48 | |||
| 49 | let mut state = State::new(); | ||
| 50 | |||
| 51 | let mut builder = Builder::new( | ||
| 52 | driver, | ||
| 53 | config, | ||
| 54 | &mut config_descriptor, | ||
| 55 | &mut bos_descriptor, | ||
| 56 | &mut msos_descriptor, | ||
| 57 | &mut control_buf, | ||
| 58 | ); | ||
| 59 | |||
| 60 | builder.handler(&mut device_handler); | ||
| 61 | |||
| 62 | // Create classes on the builder. | ||
| 63 | let config = embassy_usb::class::hid::Config { | ||
| 64 | report_descriptor: MouseReport::desc(), | ||
| 65 | request_handler: None, | ||
| 66 | poll_ms: 60, | ||
| 67 | max_packet_size: 64, | ||
| 68 | }; | ||
| 69 | let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); | ||
| 70 | |||
| 71 | // Build the builder. | ||
| 72 | let mut usb = builder.build(); | ||
| 73 | |||
| 74 | // Run the USB device. | ||
| 75 | let usb_fut = usb.run(); | ||
| 76 | |||
| 77 | let (reader, mut writer) = hid.split(); | ||
| 78 | |||
| 79 | // Do stuff with the class! | ||
| 80 | let in_fut = async { | ||
| 81 | let mut rng = RoscRng; | ||
| 82 | |||
| 83 | loop { | ||
| 84 | // every 1 second | ||
| 85 | _ = Timer::after_secs(1).await; | ||
| 86 | let report = MouseReport { | ||
| 87 | buttons: 0, | ||
| 88 | x: rng.gen_range(-100..100), // random small x movement | ||
| 89 | y: rng.gen_range(-100..100), // random small y movement | ||
| 90 | wheel: 0, | ||
| 91 | pan: 0, | ||
| 92 | }; | ||
| 93 | // Send the report. | ||
| 94 | match writer.write_serialize(&report).await { | ||
| 95 | Ok(()) => {} | ||
| 96 | Err(e) => warn!("Failed to send report: {:?}", e), | ||
| 97 | } | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | |||
| 101 | let out_fut = async { | ||
| 102 | reader.run(false, &mut request_handler).await; | ||
| 103 | }; | ||
| 104 | |||
| 105 | // Run everything concurrently. | ||
| 106 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 107 | join(usb_fut, join(in_fut, out_fut)).await; | ||
| 108 | } | ||
| 109 | |||
| 110 | struct MyRequestHandler {} | ||
| 111 | |||
| 112 | impl RequestHandler for MyRequestHandler { | ||
| 113 | fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | ||
| 114 | info!("Get report for {:?}", id); | ||
| 115 | None | ||
| 116 | } | ||
| 117 | |||
| 118 | fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { | ||
| 119 | info!("Set report for {:?}: {=[u8]}", id, data); | ||
| 120 | OutResponse::Accepted | ||
| 121 | } | ||
| 122 | |||
| 123 | fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { | ||
| 124 | info!("Set idle rate for {:?} to {:?}", id, dur); | ||
| 125 | } | ||
| 126 | |||
| 127 | fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> { | ||
| 128 | info!("Get idle rate for {:?}", id); | ||
| 129 | None | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | struct MyDeviceHandler { | ||
| 134 | configured: AtomicBool, | ||
| 135 | } | ||
| 136 | |||
| 137 | impl MyDeviceHandler { | ||
| 138 | fn new() -> Self { | ||
| 139 | MyDeviceHandler { | ||
| 140 | configured: AtomicBool::new(false), | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | impl Handler for MyDeviceHandler { | ||
| 146 | fn enabled(&mut self, enabled: bool) { | ||
| 147 | self.configured.store(false, Ordering::Relaxed); | ||
| 148 | if enabled { | ||
| 149 | info!("Device enabled"); | ||
| 150 | } else { | ||
| 151 | info!("Device disabled"); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | fn reset(&mut self) { | ||
| 156 | self.configured.store(false, Ordering::Relaxed); | ||
| 157 | info!("Bus reset, the Vbus current limit is 100mA"); | ||
| 158 | } | ||
| 159 | |||
| 160 | fn addressed(&mut self, addr: u8) { | ||
| 161 | self.configured.store(false, Ordering::Relaxed); | ||
| 162 | info!("USB address set to: {}", addr); | ||
| 163 | } | ||
| 164 | |||
| 165 | fn configured(&mut self, configured: bool) { | ||
| 166 | self.configured.store(configured, Ordering::Relaxed); | ||
| 167 | if configured { | ||
| 168 | info!("Device configured, it may now draw up to the configured current limit from Vbus.") | ||
| 169 | } else { | ||
| 170 | info!("Device is no longer configured, the Vbus current limit is 100mA."); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs index 95306a35c..11db1b2e1 100644 --- a/examples/rp/src/bin/usb_midi.rs +++ b/examples/rp/src/bin/usb_midi.rs | |||
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | 46 | ||
| 47 | // Create embassy-usb DeviceBuilder using the driver and config. | 47 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 48 | // It needs some buffers for building the descriptors. | 48 | // It needs some buffers for building the descriptors. |
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 49 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 50 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| @@ -54,7 +53,6 @@ async fn main(_spawner: Spawner) { | |||
| 54 | let mut builder = Builder::new( | 53 | let mut builder = Builder::new( |
| 55 | driver, | 54 | driver, |
| 56 | config, | 55 | config, |
| 57 | &mut device_descriptor, | ||
| 58 | &mut config_descriptor, | 56 | &mut config_descriptor, |
| 59 | &mut bos_descriptor, | 57 | &mut bos_descriptor, |
| 60 | &mut [], // no msos descriptors | 58 | &mut [], // no msos descriptors |
diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs index a6c8a5b2e..97e7e0244 100644 --- a/examples/rp/src/bin/usb_raw.rs +++ b/examples/rp/src/bin/usb_raw.rs | |||
| @@ -93,7 +93,6 @@ async fn main(_spawner: Spawner) { | |||
| 93 | 93 | ||
| 94 | // Create embassy-usb DeviceBuilder using the driver and config. | 94 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 95 | // It needs some buffers for building the descriptors. | 95 | // It needs some buffers for building the descriptors. |
| 96 | let mut device_descriptor = [0; 256]; | ||
| 97 | let mut config_descriptor = [0; 256]; | 96 | let mut config_descriptor = [0; 256]; |
| 98 | let mut bos_descriptor = [0; 256]; | 97 | let mut bos_descriptor = [0; 256]; |
| 99 | let mut msos_descriptor = [0; 256]; | 98 | let mut msos_descriptor = [0; 256]; |
| @@ -106,7 +105,6 @@ async fn main(_spawner: Spawner) { | |||
| 106 | let mut builder = Builder::new( | 105 | let mut builder = Builder::new( |
| 107 | driver, | 106 | driver, |
| 108 | config, | 107 | config, |
| 109 | &mut device_descriptor, | ||
| 110 | &mut config_descriptor, | 108 | &mut config_descriptor, |
| 111 | &mut bos_descriptor, | 109 | &mut bos_descriptor, |
| 112 | &mut msos_descriptor, | 110 | &mut msos_descriptor, |
diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs index 0dc8e9f72..331c3da4c 100644 --- a/examples/rp/src/bin/usb_raw_bulk.rs +++ b/examples/rp/src/bin/usb_raw_bulk.rs | |||
| @@ -71,7 +71,6 @@ async fn main(_spawner: Spawner) { | |||
| 71 | 71 | ||
| 72 | // Create embassy-usb DeviceBuilder using the driver and config. | 72 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 73 | // It needs some buffers for building the descriptors. | 73 | // It needs some buffers for building the descriptors. |
| 74 | let mut device_descriptor = [0; 256]; | ||
| 75 | let mut config_descriptor = [0; 256]; | 74 | let mut config_descriptor = [0; 256]; |
| 76 | let mut bos_descriptor = [0; 256]; | 75 | let mut bos_descriptor = [0; 256]; |
| 77 | let mut msos_descriptor = [0; 256]; | 76 | let mut msos_descriptor = [0; 256]; |
| @@ -80,7 +79,6 @@ async fn main(_spawner: Spawner) { | |||
| 80 | let mut builder = Builder::new( | 79 | let mut builder = Builder::new( |
| 81 | driver, | 80 | driver, |
| 82 | config, | 81 | config, |
| 83 | &mut device_descriptor, | ||
| 84 | &mut config_descriptor, | 82 | &mut config_descriptor, |
| 85 | &mut bos_descriptor, | 83 | &mut bos_descriptor, |
| 86 | &mut msos_descriptor, | 84 | &mut msos_descriptor, |
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index ab24a994c..4a802994a 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs | |||
| @@ -5,15 +5,15 @@ | |||
| 5 | #![no_std] | 5 | #![no_std] |
| 6 | #![no_main] | 6 | #![no_main] |
| 7 | 7 | ||
| 8 | use defmt::{info, panic}; | 8 | use defmt::{info, panic, unwrap}; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_futures::join::join; | ||
| 11 | use embassy_rp::bind_interrupts; | 10 | use embassy_rp::bind_interrupts; |
| 12 | use embassy_rp::peripherals::USB; | 11 | use embassy_rp::peripherals::USB; |
| 13 | use embassy_rp::usb::{Driver, Instance, InterruptHandler}; | 12 | use embassy_rp::usb::{Driver, Instance, InterruptHandler}; |
| 14 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 13 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 15 | use embassy_usb::driver::EndpointError; | 14 | use embassy_usb::driver::EndpointError; |
| 16 | use embassy_usb::{Builder, Config}; | 15 | use embassy_usb::UsbDevice; |
| 16 | use static_cell::StaticCell; | ||
| 17 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 18 | ||
| 19 | bind_interrupts!(struct Irqs { | 19 | bind_interrupts!(struct Irqs { |
| @@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs { | |||
| 21 | }); | 21 | }); |
| 22 | 22 | ||
| 23 | #[embassy_executor::main] | 23 | #[embassy_executor::main] |
| 24 | async fn main(_spawner: Spawner) { | 24 | async fn main(spawner: Spawner) { |
| 25 | info!("Hello there!"); | 25 | info!("Hello there!"); |
| 26 | 26 | ||
| 27 | let p = embassy_rp::init(Default::default()); | 27 | let p = embassy_rp::init(Default::default()); |
| @@ -30,61 +30,69 @@ async fn main(_spawner: Spawner) { | |||
| 30 | let driver = Driver::new(p.USB, Irqs); | 30 | let driver = Driver::new(p.USB, Irqs); |
| 31 | 31 | ||
| 32 | // Create embassy-usb Config | 32 | // Create embassy-usb Config |
| 33 | let mut config = Config::new(0xc0de, 0xcafe); | 33 | let config = { |
| 34 | config.manufacturer = Some("Embassy"); | 34 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); |
| 35 | config.product = Some("USB-serial example"); | 35 | config.manufacturer = Some("Embassy"); |
| 36 | config.serial_number = Some("12345678"); | 36 | config.product = Some("USB-serial example"); |
| 37 | config.max_power = 100; | 37 | config.serial_number = Some("12345678"); |
| 38 | config.max_packet_size_0 = 64; | 38 | config.max_power = 100; |
| 39 | 39 | config.max_packet_size_0 = 64; | |
| 40 | // Required for windows compatibility. | 40 | |
| 41 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | 41 | // Required for windows compatibility. |
| 42 | config.device_class = 0xEF; | 42 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help |
| 43 | config.device_sub_class = 0x02; | 43 | config.device_class = 0xEF; |
| 44 | config.device_protocol = 0x01; | 44 | config.device_sub_class = 0x02; |
| 45 | config.composite_with_iads = true; | 45 | config.device_protocol = 0x01; |
| 46 | config.composite_with_iads = true; | ||
| 47 | config | ||
| 48 | }; | ||
| 46 | 49 | ||
| 47 | // Create embassy-usb DeviceBuilder using the driver and config. | 50 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 48 | // It needs some buffers for building the descriptors. | 51 | // It needs some buffers for building the descriptors. |
| 49 | let mut device_descriptor = [0; 256]; | 52 | let mut builder = { |
| 50 | let mut config_descriptor = [0; 256]; | 53 | static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); |
| 51 | let mut bos_descriptor = [0; 256]; | 54 | static BOS_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); |
| 52 | let mut control_buf = [0; 64]; | 55 | static CONTROL_BUF: StaticCell<[u8; 64]> = StaticCell::new(); |
| 53 | 56 | ||
| 54 | let mut state = State::new(); | 57 | let builder = embassy_usb::Builder::new( |
| 55 | 58 | driver, | |
| 56 | let mut builder = Builder::new( | 59 | config, |
| 57 | driver, | 60 | CONFIG_DESCRIPTOR.init([0; 256]), |
| 58 | config, | 61 | BOS_DESCRIPTOR.init([0; 256]), |
| 59 | &mut device_descriptor, | 62 | &mut [], // no msos descriptors |
| 60 | &mut config_descriptor, | 63 | CONTROL_BUF.init([0; 64]), |
| 61 | &mut bos_descriptor, | 64 | ); |
| 62 | &mut [], // no msos descriptors | 65 | builder |
| 63 | &mut control_buf, | 66 | }; |
| 64 | ); | ||
| 65 | 67 | ||
| 66 | // Create classes on the builder. | 68 | // Create classes on the builder. |
| 67 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | 69 | let mut class = { |
| 70 | static STATE: StaticCell<State> = StaticCell::new(); | ||
| 71 | let state = STATE.init(State::new()); | ||
| 72 | CdcAcmClass::new(&mut builder, state, 64) | ||
| 73 | }; | ||
| 68 | 74 | ||
| 69 | // Build the builder. | 75 | // Build the builder. |
| 70 | let mut usb = builder.build(); | 76 | let usb = builder.build(); |
| 71 | 77 | ||
| 72 | // Run the USB device. | 78 | // Run the USB device. |
| 73 | let usb_fut = usb.run(); | 79 | unwrap!(spawner.spawn(usb_task(usb))); |
| 74 | 80 | ||
| 75 | // Do stuff with the class! | 81 | // Do stuff with the class! |
| 76 | let echo_fut = async { | 82 | loop { |
| 77 | loop { | 83 | class.wait_connection().await; |
| 78 | class.wait_connection().await; | 84 | info!("Connected"); |
| 79 | info!("Connected"); | 85 | let _ = echo(&mut class).await; |
| 80 | let _ = echo(&mut class).await; | 86 | info!("Disconnected"); |
| 81 | info!("Disconnected"); | 87 | } |
| 82 | } | 88 | } |
| 83 | }; | 89 | |
| 90 | type MyUsbDriver = Driver<'static, USB>; | ||
| 91 | type MyUsbDevice = UsbDevice<'static, MyUsbDriver>; | ||
| 84 | 92 | ||
| 85 | // Run everything concurrently. | 93 | #[embassy_executor::task] |
| 86 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | 94 | async fn usb_task(mut usb: MyUsbDevice) -> ! { |
| 87 | join(usb_fut, echo_fut).await; | 95 | usb.run().await |
| 88 | } | 96 | } |
| 89 | 97 | ||
| 90 | struct Disconnected {} | 98 | struct Disconnected {} |
diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs index 4ba4fc25c..f9cfdef94 100644 --- a/examples/rp/src/bin/usb_serial_with_logger.rs +++ b/examples/rp/src/bin/usb_serial_with_logger.rs | |||
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | 46 | ||
| 47 | // Create embassy-usb DeviceBuilder using the driver and config. | 47 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 48 | // It needs some buffers for building the descriptors. | 48 | // It needs some buffers for building the descriptors. |
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 49 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 50 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| @@ -57,7 +56,6 @@ async fn main(_spawner: Spawner) { | |||
| 57 | let mut builder = Builder::new( | 56 | let mut builder = Builder::new( |
| 58 | driver, | 57 | driver, |
| 59 | config, | 58 | config, |
| 60 | &mut device_descriptor, | ||
| 61 | &mut config_descriptor, | 59 | &mut config_descriptor, |
| 62 | &mut bos_descriptor, | 60 | &mut bos_descriptor, |
| 63 | &mut [], // no msos descriptors | 61 | &mut [], // no msos descriptors |
diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs new file mode 100644 index 000000000..e73938ac9 --- /dev/null +++ b/examples/rp/src/bin/usb_webusb.rs | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | //! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! This creates a WebUSB capable device that echoes data back to the host. | ||
| 4 | //! | ||
| 5 | //! To test this in the browser (ideally host this on localhost:8080, to test the landing page | ||
| 6 | //! feature): | ||
| 7 | //! ```js | ||
| 8 | //! (async () => { | ||
| 9 | //! const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0xf569 }] }); | ||
| 10 | //! await device.open(); | ||
| 11 | //! await device.claimInterface(1); | ||
| 12 | //! device.transferIn(1, 64).then(data => console.log(data)); | ||
| 13 | //! await device.transferOut(1, new Uint8Array([1,2,3])); | ||
| 14 | //! })(); | ||
| 15 | //! ``` | ||
| 16 | |||
| 17 | #![no_std] | ||
| 18 | #![no_main] | ||
| 19 | |||
| 20 | use defmt::info; | ||
| 21 | use embassy_executor::Spawner; | ||
| 22 | use embassy_futures::join::join; | ||
| 23 | use embassy_rp::bind_interrupts; | ||
| 24 | use embassy_rp::peripherals::USB; | ||
| 25 | use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; | ||
| 26 | use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; | ||
| 27 | use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; | ||
| 28 | use embassy_usb::msos::{self, windows_version}; | ||
| 29 | use embassy_usb::{Builder, Config}; | ||
| 30 | use {defmt_rtt as _, panic_probe as _}; | ||
| 31 | |||
| 32 | bind_interrupts!(struct Irqs { | ||
| 33 | USBCTRL_IRQ => InterruptHandler<USB>; | ||
| 34 | }); | ||
| 35 | |||
| 36 | // This is a randomly generated GUID to allow clients on Windows to find our device | ||
| 37 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"]; | ||
| 38 | |||
| 39 | #[embassy_executor::main] | ||
| 40 | async fn main(_spawner: Spawner) { | ||
| 41 | let p = embassy_rp::init(Default::default()); | ||
| 42 | |||
| 43 | // Create the driver, from the HAL. | ||
| 44 | let driver = UsbDriver::new(p.USB, Irqs); | ||
| 45 | |||
| 46 | // Create embassy-usb Config | ||
| 47 | let mut config = Config::new(0xf569, 0x0001); | ||
| 48 | config.manufacturer = Some("Embassy"); | ||
| 49 | config.product = Some("WebUSB example"); | ||
| 50 | config.serial_number = Some("12345678"); | ||
| 51 | config.max_power = 100; | ||
| 52 | config.max_packet_size_0 = 64; | ||
| 53 | |||
| 54 | // Required for windows compatibility. | ||
| 55 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 56 | config.device_class = 0xff; | ||
| 57 | config.device_sub_class = 0x00; | ||
| 58 | config.device_protocol = 0x00; | ||
| 59 | |||
| 60 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 61 | // It needs some buffers for building the descriptors. | ||
| 62 | let mut config_descriptor = [0; 256]; | ||
| 63 | let mut bos_descriptor = [0; 256]; | ||
| 64 | let mut control_buf = [0; 64]; | ||
| 65 | let mut msos_descriptor = [0; 256]; | ||
| 66 | |||
| 67 | let webusb_config = WebUsbConfig { | ||
| 68 | max_packet_size: 64, | ||
| 69 | vendor_code: 1, | ||
| 70 | // 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. | ||
| 71 | landing_url: Some(Url::new("http://localhost:8080")), | ||
| 72 | }; | ||
| 73 | |||
| 74 | let mut state = State::new(); | ||
| 75 | |||
| 76 | let mut builder = Builder::new( | ||
| 77 | driver, | ||
| 78 | config, | ||
| 79 | &mut config_descriptor, | ||
| 80 | &mut bos_descriptor, | ||
| 81 | &mut msos_descriptor, | ||
| 82 | &mut control_buf, | ||
| 83 | ); | ||
| 84 | |||
| 85 | // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor. | ||
| 86 | // We tell Windows that this entire device is compatible with the "WINUSB" feature, | ||
| 87 | // which causes it to use the built-in WinUSB driver automatically, which in turn | ||
| 88 | // can be used by libusb/rusb software without needing a custom driver or INF file. | ||
| 89 | // In principle you might want to call msos_feature() just on a specific function, | ||
| 90 | // if your device also has other functions that still use standard class drivers. | ||
| 91 | builder.msos_descriptor(windows_version::WIN8_1, 0); | ||
| 92 | builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); | ||
| 93 | builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( | ||
| 94 | "DeviceInterfaceGUIDs", | ||
| 95 | msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), | ||
| 96 | )); | ||
| 97 | |||
| 98 | // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything) | ||
| 99 | WebUsb::configure(&mut builder, &mut state, &webusb_config); | ||
| 100 | // Create some USB bulk endpoints for testing. | ||
| 101 | let mut endpoints = WebEndpoints::new(&mut builder, &webusb_config); | ||
| 102 | |||
| 103 | // Build the builder. | ||
| 104 | let mut usb = builder.build(); | ||
| 105 | |||
| 106 | // Run the USB device. | ||
| 107 | let usb_fut = usb.run(); | ||
| 108 | |||
| 109 | // Do some WebUSB transfers. | ||
| 110 | let webusb_fut = async { | ||
| 111 | loop { | ||
| 112 | endpoints.wait_connected().await; | ||
| 113 | info!("Connected"); | ||
| 114 | endpoints.echo().await; | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | |||
| 118 | // Run everything concurrently. | ||
| 119 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 120 | join(usb_fut, webusb_fut).await; | ||
| 121 | } | ||
| 122 | |||
| 123 | struct WebEndpoints<'d, D: Driver<'d>> { | ||
| 124 | write_ep: D::EndpointIn, | ||
| 125 | read_ep: D::EndpointOut, | ||
| 126 | } | ||
| 127 | |||
| 128 | impl<'d, D: Driver<'d>> WebEndpoints<'d, D> { | ||
| 129 | fn new(builder: &mut Builder<'d, D>, config: &'d WebUsbConfig<'d>) -> Self { | ||
| 130 | let mut func = builder.function(0xff, 0x00, 0x00); | ||
| 131 | let mut iface = func.interface(); | ||
| 132 | let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None); | ||
| 133 | |||
| 134 | let write_ep = alt.endpoint_bulk_in(config.max_packet_size); | ||
| 135 | let read_ep = alt.endpoint_bulk_out(config.max_packet_size); | ||
| 136 | |||
| 137 | WebEndpoints { write_ep, read_ep } | ||
| 138 | } | ||
| 139 | |||
| 140 | // Wait until the device's endpoints are enabled. | ||
| 141 | async fn wait_connected(&mut self) { | ||
| 142 | self.read_ep.wait_enabled().await | ||
| 143 | } | ||
| 144 | |||
| 145 | // Echo data back to the host. | ||
| 146 | async fn echo(&mut self) { | ||
| 147 | let mut buf = [0; 64]; | ||
| 148 | loop { | ||
| 149 | let n = self.read_ep.read(&mut buf).await.unwrap(); | ||
| 150 | let data = &buf[..n]; | ||
| 151 | info!("Data read: {:x}", data); | ||
| 152 | self.write_ep.write(data).await.unwrap(); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index b60852359..4c9651433 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs | |||
| @@ -11,13 +11,15 @@ use cyw43_pio::PioSpi; | |||
| 11 | use defmt::*; | 11 | use defmt::*; |
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_net::tcp::TcpSocket; | 13 | use embassy_net::tcp::TcpSocket; |
| 14 | use embassy_net::{Config, Stack, StackResources}; | 14 | use embassy_net::{Config, StackResources}; |
| 15 | use embassy_rp::bind_interrupts; | 15 | use embassy_rp::bind_interrupts; |
| 16 | use embassy_rp::clocks::RoscRng; | ||
| 16 | use embassy_rp::gpio::{Level, Output}; | 17 | use embassy_rp::gpio::{Level, Output}; |
| 17 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | 18 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; |
| 18 | use embassy_rp::pio::{InterruptHandler, Pio}; | 19 | use embassy_rp::pio::{InterruptHandler, Pio}; |
| 19 | use embassy_time::Duration; | 20 | use embassy_time::Duration; |
| 20 | use embedded_io_async::Write; | 21 | use embedded_io_async::Write; |
| 22 | use rand::RngCore; | ||
| 21 | use static_cell::StaticCell; | 23 | use static_cell::StaticCell; |
| 22 | use {defmt_rtt as _, panic_probe as _}; | 24 | use {defmt_rtt as _, panic_probe as _}; |
| 23 | 25 | ||
| @@ -26,13 +28,13 @@ bind_interrupts!(struct Irqs { | |||
| 26 | }); | 28 | }); |
| 27 | 29 | ||
| 28 | #[embassy_executor::task] | 30 | #[embassy_executor::task] |
| 29 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 31 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 30 | runner.run().await | 32 | runner.run().await |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 33 | #[embassy_executor::task] | 35 | #[embassy_executor::task] |
| 34 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 36 | async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { |
| 35 | stack.run().await | 37 | runner.run().await |
| 36 | } | 38 | } |
| 37 | 39 | ||
| 38 | #[embassy_executor::main] | 40 | #[embassy_executor::main] |
| @@ -40,14 +42,15 @@ async fn main(spawner: Spawner) { | |||
| 40 | info!("Hello World!"); | 42 | info!("Hello World!"); |
| 41 | 43 | ||
| 42 | let p = embassy_rp::init(Default::default()); | 44 | let p = embassy_rp::init(Default::default()); |
| 45 | let mut rng = RoscRng; | ||
| 43 | 46 | ||
| 44 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); | 47 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); |
| 45 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); | 48 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); |
| 46 | 49 | ||
| 47 | // To make flashing faster for development, you may want to flash the firmwares independently | 50 | // To make flashing faster for development, you may want to flash the firmwares independently |
| 48 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | 51 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: |
| 49 | // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | 52 | // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 |
| 50 | // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 | 53 | // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 |
| 51 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; | 54 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; |
| 52 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | 55 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; |
| 53 | 56 | ||
| @@ -59,7 +62,7 @@ async fn main(spawner: Spawner) { | |||
| 59 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 62 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 60 | let state = STATE.init(cyw43::State::new()); | 63 | let state = STATE.init(cyw43::State::new()); |
| 61 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 64 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 62 | unwrap!(spawner.spawn(wifi_task(runner))); | 65 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 63 | 66 | ||
| 64 | control.init(clm).await; | 67 | control.init(clm).await; |
| 65 | control | 68 | control |
| @@ -74,19 +77,13 @@ async fn main(spawner: Spawner) { | |||
| 74 | }); | 77 | }); |
| 75 | 78 | ||
| 76 | // Generate random seed | 79 | // Generate random seed |
| 77 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. | 80 | let seed = rng.next_u64(); |
| 78 | 81 | ||
| 79 | // Init network stack | 82 | // Init network stack |
| 80 | static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new(); | 83 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 81 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 84 | let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); |
| 82 | let stack = &*STACK.init(Stack::new( | 85 | |
| 83 | net_device, | 86 | unwrap!(spawner.spawn(net_task(runner))); |
| 84 | config, | ||
| 85 | RESOURCES.init(StackResources::<2>::new()), | ||
| 86 | seed, | ||
| 87 | )); | ||
| 88 | |||
| 89 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 90 | 87 | ||
| 91 | //control.start_ap_open("cyw43", 5).await; | 88 | //control.start_ap_open("cyw43", 5).await; |
| 92 | control.start_ap_wpa2("cyw43", "password", 5).await; | 89 | control.start_ap_wpa2("cyw43", "password", 5).await; |
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 18eefe41f..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 { | |||
| 21 | }); | 21 | }); |
| 22 | 22 | ||
| 23 | #[embassy_executor::task] | 23 | #[embassy_executor::task] |
| 24 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 24 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 25 | runner.run().await | 25 | runner.run().await |
| 26 | } | 26 | } |
| 27 | 27 | ||
| @@ -33,8 +33,8 @@ async fn main(spawner: Spawner) { | |||
| 33 | 33 | ||
| 34 | // To make flashing faster for development, you may want to flash the firmwares independently | 34 | // To make flashing faster for development, you may want to flash the firmwares independently |
| 35 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | 35 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: |
| 36 | // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | 36 | // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 |
| 37 | // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 | 37 | // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 |
| 38 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; | 38 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; |
| 39 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | 39 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; |
| 40 | 40 | ||
| @@ -46,7 +46,7 @@ async fn main(spawner: Spawner) { | |||
| 46 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 46 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 47 | let state = STATE.init(cyw43::State::new()); | 47 | let state = STATE.init(cyw43::State::new()); |
| 48 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 48 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 49 | unwrap!(spawner.spawn(wifi_task(runner))); | 49 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 50 | 50 | ||
| 51 | control.init(clm).await; | 51 | control.init(clm).await; |
| 52 | control | 52 | control |
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index e0f85a6b0..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; | |||
| 10 | use cyw43_pio::PioSpi; | 10 | use cyw43_pio::PioSpi; |
| 11 | use defmt::*; | 11 | use defmt::*; |
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_net::Stack; | ||
| 14 | use embassy_rp::bind_interrupts; | 13 | use embassy_rp::bind_interrupts; |
| 15 | use embassy_rp::gpio::{Level, Output}; | 14 | use embassy_rp::gpio::{Level, Output}; |
| 16 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | 15 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; |
| @@ -23,13 +22,13 @@ bind_interrupts!(struct Irqs { | |||
| 23 | }); | 22 | }); |
| 24 | 23 | ||
| 25 | #[embassy_executor::task] | 24 | #[embassy_executor::task] |
| 26 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 25 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 27 | runner.run().await | 26 | runner.run().await |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | #[embassy_executor::task] | 29 | #[embassy_executor::task] |
| 31 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 30 | async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { |
| 32 | stack.run().await | 31 | runner.run().await |
| 33 | } | 32 | } |
| 34 | 33 | ||
| 35 | #[embassy_executor::main] | 34 | #[embassy_executor::main] |
| @@ -43,8 +42,8 @@ async fn main(spawner: Spawner) { | |||
| 43 | 42 | ||
| 44 | // To make flashing faster for development, you may want to flash the firmwares independently | 43 | // To make flashing faster for development, you may want to flash the firmwares independently |
| 45 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | 44 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: |
| 46 | // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | 45 | // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 |
| 47 | // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 | 46 | // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 |
| 48 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; | 47 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; |
| 49 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | 48 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; |
| 50 | 49 | ||
| @@ -56,7 +55,7 @@ async fn main(spawner: Spawner) { | |||
| 56 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 55 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 57 | let state = STATE.init(cyw43::State::new()); | 56 | let state = STATE.init(cyw43::State::new()); |
| 58 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 57 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 59 | unwrap!(spawner.spawn(wifi_task(runner))); | 58 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 60 | 59 | ||
| 61 | control.init(clm).await; | 60 | control.init(clm).await; |
| 62 | control | 61 | control |
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index f1afc4a00..7bf546e01 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs | |||
| @@ -7,17 +7,20 @@ | |||
| 7 | 7 | ||
| 8 | use core::str::from_utf8; | 8 | use core::str::from_utf8; |
| 9 | 9 | ||
| 10 | use cyw43::JoinOptions; | ||
| 10 | use cyw43_pio::PioSpi; | 11 | use cyw43_pio::PioSpi; |
| 11 | use defmt::*; | 12 | use defmt::*; |
| 12 | use embassy_executor::Spawner; | 13 | use embassy_executor::Spawner; |
| 13 | use embassy_net::tcp::TcpSocket; | 14 | use embassy_net::tcp::TcpSocket; |
| 14 | use embassy_net::{Config, Stack, StackResources}; | 15 | use embassy_net::{Config, StackResources}; |
| 15 | use embassy_rp::bind_interrupts; | 16 | use embassy_rp::bind_interrupts; |
| 17 | use embassy_rp::clocks::RoscRng; | ||
| 16 | use embassy_rp::gpio::{Level, Output}; | 18 | use embassy_rp::gpio::{Level, Output}; |
| 17 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | 19 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; |
| 18 | use embassy_rp::pio::{InterruptHandler, Pio}; | 20 | use embassy_rp::pio::{InterruptHandler, Pio}; |
| 19 | use embassy_time::{Duration, Timer}; | 21 | use embassy_time::{Duration, Timer}; |
| 20 | use embedded_io_async::Write; | 22 | use embedded_io_async::Write; |
| 23 | use rand::RngCore; | ||
| 21 | use static_cell::StaticCell; | 24 | use static_cell::StaticCell; |
| 22 | use {defmt_rtt as _, panic_probe as _}; | 25 | use {defmt_rtt as _, panic_probe as _}; |
| 23 | 26 | ||
| @@ -25,17 +28,17 @@ bind_interrupts!(struct Irqs { | |||
| 25 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | 28 | PIO0_IRQ_0 => InterruptHandler<PIO0>; |
| 26 | }); | 29 | }); |
| 27 | 30 | ||
| 28 | const WIFI_NETWORK: &str = "EmbassyTest"; | 31 | const WIFI_NETWORK: &str = "LadronDeWifi"; |
| 29 | const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; | 32 | const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8"; |
| 30 | 33 | ||
| 31 | #[embassy_executor::task] | 34 | #[embassy_executor::task] |
| 32 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 35 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 33 | runner.run().await | 36 | runner.run().await |
| 34 | } | 37 | } |
| 35 | 38 | ||
| 36 | #[embassy_executor::task] | 39 | #[embassy_executor::task] |
| 37 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | 40 | async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { |
| 38 | stack.run().await | 41 | runner.run().await |
| 39 | } | 42 | } |
| 40 | 43 | ||
| 41 | #[embassy_executor::main] | 44 | #[embassy_executor::main] |
| @@ -43,14 +46,15 @@ async fn main(spawner: Spawner) { | |||
| 43 | info!("Hello World!"); | 46 | info!("Hello World!"); |
| 44 | 47 | ||
| 45 | let p = embassy_rp::init(Default::default()); | 48 | let p = embassy_rp::init(Default::default()); |
| 49 | let mut rng = RoscRng; | ||
| 46 | 50 | ||
| 47 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); | 51 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); |
| 48 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); | 52 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); |
| 49 | 53 | ||
| 50 | // To make flashing faster for development, you may want to flash the firmwares independently | 54 | // To make flashing faster for development, you may want to flash the firmwares independently |
| 51 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | 55 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: |
| 52 | // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | 56 | // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 |
| 53 | // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 | 57 | // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 |
| 54 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; | 58 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; |
| 55 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | 59 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; |
| 56 | 60 | ||
| @@ -62,7 +66,7 @@ async fn main(spawner: Spawner) { | |||
| 62 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 66 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 63 | let state = STATE.init(cyw43::State::new()); | 67 | let state = STATE.init(cyw43::State::new()); |
| 64 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 68 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 65 | unwrap!(spawner.spawn(wifi_task(runner))); | 69 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 66 | 70 | ||
| 67 | control.init(clm).await; | 71 | control.init(clm).await; |
| 68 | control | 72 | control |
| @@ -77,23 +81,19 @@ async fn main(spawner: Spawner) { | |||
| 77 | //}); | 81 | //}); |
| 78 | 82 | ||
| 79 | // Generate random seed | 83 | // Generate random seed |
| 80 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. | 84 | let seed = rng.next_u64(); |
| 81 | 85 | ||
| 82 | // Init network stack | 86 | // Init network stack |
| 83 | static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new(); | 87 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 84 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 88 | let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); |
| 85 | let stack = &*STACK.init(Stack::new( | ||
| 86 | net_device, | ||
| 87 | config, | ||
| 88 | RESOURCES.init(StackResources::<2>::new()), | ||
| 89 | seed, | ||
| 90 | )); | ||
| 91 | 89 | ||
| 92 | unwrap!(spawner.spawn(net_task(stack))); | 90 | unwrap!(spawner.spawn(net_task(runner))); |
| 93 | 91 | ||
| 94 | loop { | 92 | loop { |
| 95 | //control.join_open(WIFI_NETWORK).await; | 93 | match control |
| 96 | match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { | 94 | .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) |
| 95 | .await | ||
| 96 | { | ||
| 97 | Ok(_) => break, | 97 | Ok(_) => break, |
| 98 | Err(err) => { | 98 | Err(err) => { |
| 99 | info!("join failed with status={}", err.status); | 99 | 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 new file mode 100644 index 000000000..1ae909917 --- /dev/null +++ b/examples/rp/src/bin/wifi_webrequest.rs | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | //! This example uses the RP Pico W board Wifi chip (cyw43). | ||
| 2 | //! Connects to Wifi network and makes a web request to get the current time. | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | #![allow(async_fn_in_trait)] | ||
| 7 | |||
| 8 | use core::str::from_utf8; | ||
| 9 | |||
| 10 | use cyw43::JoinOptions; | ||
| 11 | use cyw43_pio::PioSpi; | ||
| 12 | use defmt::*; | ||
| 13 | use embassy_executor::Spawner; | ||
| 14 | use embassy_net::dns::DnsSocket; | ||
| 15 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; | ||
| 16 | use embassy_net::{Config, StackResources}; | ||
| 17 | use embassy_rp::bind_interrupts; | ||
| 18 | use embassy_rp::clocks::RoscRng; | ||
| 19 | use embassy_rp::gpio::{Level, Output}; | ||
| 20 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | ||
| 21 | use embassy_rp::pio::{InterruptHandler, Pio}; | ||
| 22 | use embassy_time::{Duration, Timer}; | ||
| 23 | use rand::RngCore; | ||
| 24 | use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; | ||
| 25 | use reqwless::request::Method; | ||
| 26 | use serde::Deserialize; | ||
| 27 | use static_cell::StaticCell; | ||
| 28 | use {defmt_rtt as _, panic_probe as _, serde_json_core}; | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | const WIFI_NETWORK: &str = "ssid"; // change to your network SSID | ||
| 35 | const WIFI_PASSWORD: &str = "pwd"; // change to your network password | ||
| 36 | |||
| 37 | #[embassy_executor::task] | ||
| 38 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | ||
| 39 | runner.run().await | ||
| 40 | } | ||
| 41 | |||
| 42 | #[embassy_executor::task] | ||
| 43 | async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { | ||
| 44 | runner.run().await | ||
| 45 | } | ||
| 46 | |||
| 47 | #[embassy_executor::main] | ||
| 48 | async fn main(spawner: Spawner) { | ||
| 49 | info!("Hello World!"); | ||
| 50 | |||
| 51 | let p = embassy_rp::init(Default::default()); | ||
| 52 | let mut rng = RoscRng; | ||
| 53 | |||
| 54 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); | ||
| 55 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); | ||
| 56 | // To make flashing faster for development, you may want to flash the firmwares independently | ||
| 57 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | ||
| 58 | // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 | ||
| 59 | // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 | ||
| 60 | // let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; | ||
| 61 | // let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | ||
| 62 | |||
| 63 | let pwr = Output::new(p.PIN_23, Level::Low); | ||
| 64 | let cs = Output::new(p.PIN_25, Level::High); | ||
| 65 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 66 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | ||
| 67 | |||
| 68 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | ||
| 69 | let state = STATE.init(cyw43::State::new()); | ||
| 70 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | ||
| 71 | unwrap!(spawner.spawn(cyw43_task(runner))); | ||
| 72 | |||
| 73 | control.init(clm).await; | ||
| 74 | control | ||
| 75 | .set_power_management(cyw43::PowerManagementMode::PowerSave) | ||
| 76 | .await; | ||
| 77 | |||
| 78 | let config = Config::dhcpv4(Default::default()); | ||
| 79 | // Use static IP configuration instead of DHCP | ||
| 80 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { | ||
| 81 | // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | ||
| 82 | // dns_servers: Vec::new(), | ||
| 83 | // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | ||
| 84 | //}); | ||
| 85 | |||
| 86 | // Generate random seed | ||
| 87 | let seed = rng.next_u64(); | ||
| 88 | |||
| 89 | // Init network stack | ||
| 90 | static RESOURCES: StaticCell<StackResources<5>> = StaticCell::new(); | ||
| 91 | let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); | ||
| 92 | |||
| 93 | unwrap!(spawner.spawn(net_task(runner))); | ||
| 94 | |||
| 95 | loop { | ||
| 96 | match control | ||
| 97 | .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) | ||
| 98 | .await | ||
| 99 | { | ||
| 100 | Ok(_) => break, | ||
| 101 | Err(err) => { | ||
| 102 | info!("join failed with status={}", err.status); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | // Wait for DHCP, not necessary when using static IP | ||
| 108 | info!("waiting for DHCP..."); | ||
| 109 | while !stack.is_config_up() { | ||
| 110 | Timer::after_millis(100).await; | ||
| 111 | } | ||
| 112 | info!("DHCP is now up!"); | ||
| 113 | |||
| 114 | info!("waiting for link up..."); | ||
| 115 | while !stack.is_link_up() { | ||
| 116 | Timer::after_millis(500).await; | ||
| 117 | } | ||
| 118 | info!("Link is up!"); | ||
| 119 | |||
| 120 | info!("waiting for stack to be up..."); | ||
| 121 | stack.wait_config_up().await; | ||
| 122 | info!("Stack is up!"); | ||
| 123 | |||
| 124 | // And now we can use it! | ||
| 125 | |||
| 126 | loop { | ||
| 127 | let mut rx_buffer = [0; 8192]; | ||
| 128 | let mut tls_read_buffer = [0; 16640]; | ||
| 129 | let mut tls_write_buffer = [0; 16640]; | ||
| 130 | |||
| 131 | let client_state = TcpClientState::<1, 1024, 1024>::new(); | ||
| 132 | let tcp_client = TcpClient::new(stack, &client_state); | ||
| 133 | let dns_client = DnsSocket::new(stack); | ||
| 134 | let tls_config = TlsConfig::new(seed, &mut tls_read_buffer, &mut tls_write_buffer, TlsVerify::None); | ||
| 135 | |||
| 136 | let mut http_client = HttpClient::new_with_tls(&tcp_client, &dns_client, tls_config); | ||
| 137 | let url = "https://worldtimeapi.org/api/timezone/Europe/Berlin"; | ||
| 138 | // for non-TLS requests, use this instead: | ||
| 139 | // let mut http_client = HttpClient::new(&tcp_client, &dns_client); | ||
| 140 | // let url = "http://worldtimeapi.org/api/timezone/Europe/Berlin"; | ||
| 141 | |||
| 142 | info!("connecting to {}", &url); | ||
| 143 | |||
| 144 | let mut request = match http_client.request(Method::GET, &url).await { | ||
| 145 | Ok(req) => req, | ||
| 146 | Err(e) => { | ||
| 147 | error!("Failed to make HTTP request: {:?}", e); | ||
| 148 | return; // handle the error | ||
| 149 | } | ||
| 150 | }; | ||
| 151 | |||
| 152 | let response = match request.send(&mut rx_buffer).await { | ||
| 153 | Ok(resp) => resp, | ||
| 154 | Err(_e) => { | ||
| 155 | error!("Failed to send HTTP request"); | ||
| 156 | return; // handle the error; | ||
| 157 | } | ||
| 158 | }; | ||
| 159 | |||
| 160 | let body = match from_utf8(response.body().read_to_end().await.unwrap()) { | ||
| 161 | Ok(b) => b, | ||
| 162 | Err(_e) => { | ||
| 163 | error!("Failed to read response body"); | ||
| 164 | return; // handle the error | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | info!("Response body: {:?}", &body); | ||
| 168 | |||
| 169 | // parse the response body and update the RTC | ||
| 170 | |||
| 171 | #[derive(Deserialize)] | ||
| 172 | struct ApiResponse<'a> { | ||
| 173 | datetime: &'a str, | ||
| 174 | // other fields as needed | ||
| 175 | } | ||
| 176 | |||
| 177 | let bytes = body.as_bytes(); | ||
| 178 | match serde_json_core::de::from_slice::<ApiResponse>(bytes) { | ||
| 179 | Ok((output, _used)) => { | ||
| 180 | info!("Datetime: {:?}", output.datetime); | ||
| 181 | } | ||
| 182 | Err(_e) => { | ||
| 183 | error!("Failed to parse response body"); | ||
| 184 | return; // handle the error | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | Timer::after(Duration::from_secs(5)).await; | ||
| 189 | } | ||
| 190 | } | ||
diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs new file mode 100644 index 000000000..39f03c8e4 --- /dev/null +++ b/examples/rp/src/bin/zerocopy.rs | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | //! This example shows how to use `zerocopy_channel` from `embassy_sync` for | ||
| 2 | //! sending large values between two tasks without copying. | ||
| 3 | //! The example also shows how to use the RP2040 ADC with DMA. | ||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use core::sync::atomic::{AtomicU16, Ordering}; | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; | ||
| 12 | use embassy_rp::bind_interrupts; | ||
| 13 | use embassy_rp::gpio::Pull; | ||
| 14 | use embassy_rp::peripherals::DMA_CH0; | ||
| 15 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 16 | use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; | ||
| 17 | use embassy_time::{Duration, Ticker, Timer}; | ||
| 18 | use static_cell::StaticCell; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | type SampleBuffer = [u16; 512]; | ||
| 22 | |||
| 23 | bind_interrupts!(struct Irqs { | ||
| 24 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 25 | }); | ||
| 26 | |||
| 27 | const BLOCK_SIZE: usize = 512; | ||
| 28 | const NUM_BLOCKS: usize = 2; | ||
| 29 | static MAX: AtomicU16 = AtomicU16::new(0); | ||
| 30 | |||
| 31 | struct AdcParts { | ||
| 32 | adc: Adc<'static, Async>, | ||
| 33 | pin: adc::Channel<'static>, | ||
| 34 | dma: DMA_CH0, | ||
| 35 | } | ||
| 36 | |||
| 37 | #[embassy_executor::main] | ||
| 38 | async fn main(spawner: Spawner) { | ||
| 39 | let p = embassy_rp::init(Default::default()); | ||
| 40 | info!("Here we go!"); | ||
| 41 | |||
| 42 | let adc_parts = AdcParts { | ||
| 43 | adc: Adc::new(p.ADC, Irqs, Config::default()), | ||
| 44 | pin: adc::Channel::new_pin(p.PIN_29, Pull::None), | ||
| 45 | dma: p.DMA_CH0, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new(); | ||
| 49 | let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]); | ||
| 50 | |||
| 51 | static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new(); | ||
| 52 | let channel = CHANNEL.init(Channel::new(buf)); | ||
| 53 | let (sender, receiver) = channel.split(); | ||
| 54 | |||
| 55 | spawner.must_spawn(consumer(receiver)); | ||
| 56 | spawner.must_spawn(producer(sender, adc_parts)); | ||
| 57 | |||
| 58 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 59 | loop { | ||
| 60 | ticker.next().await; | ||
| 61 | let max = MAX.load(Ordering::Relaxed); | ||
| 62 | info!("latest block's max value: {:?}", max); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[embassy_executor::task] | ||
| 67 | async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) { | ||
| 68 | loop { | ||
| 69 | // Obtain a free buffer from the channel | ||
| 70 | let buf = sender.send().await; | ||
| 71 | |||
| 72 | // Fill it with data | ||
| 73 | adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); | ||
| 74 | |||
| 75 | // Notify the channel that the buffer is now ready to be received | ||
| 76 | sender.send_done(); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | #[embassy_executor::task] | ||
| 81 | async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) { | ||
| 82 | loop { | ||
| 83 | // Receive a buffer from the channel | ||
| 84 | let buf = receiver.receive().await; | ||
| 85 | |||
| 86 | // Simulate using the data, while the producer is filling up the next buffer | ||
| 87 | Timer::after_micros(1000).await; | ||
| 88 | let max = buf.iter().max().unwrap(); | ||
| 89 | MAX.store(*max, Ordering::Relaxed); | ||
| 90 | |||
| 91 | // Notify the channel that the buffer is now ready to be reused | ||
| 92 | receiver.receive_done(); | ||
| 93 | } | ||
| 94 | } | ||
diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml new file mode 100644 index 000000000..9a92b1ce2 --- /dev/null +++ b/examples/rp23/.cargo/config.toml | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | #runner = "probe-rs run --chip RP2040" | ||
| 3 | #runner = "elf2uf2-rs -d" | ||
| 4 | runner = "picotool load -u -v -x -t elf" | ||
| 5 | |||
| 6 | [build] | ||
| 7 | target = "thumbv8m.main-none-eabihf" | ||
| 8 | |||
| 9 | [env] | ||
| 10 | DEFMT_LOG = "debug" | ||
diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml new file mode 100644 index 000000000..087f6fd69 --- /dev/null +++ b/examples/rp23/Cargo.toml | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-rp2350-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } | ||
| 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | ||
| 13 | embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } | ||
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | ||
| 15 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } | ||
| 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | ||
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 18 | embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } | ||
| 19 | cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } | ||
| 20 | cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } | ||
| 21 | |||
| 22 | defmt = "0.3" | ||
| 23 | defmt-rtt = "0.4" | ||
| 24 | fixed = "1.23.1" | ||
| 25 | fixed-macro = "1.2" | ||
| 26 | |||
| 27 | # for web request example | ||
| 28 | reqwless = { version = "0.12.0", features = ["defmt",]} | ||
| 29 | serde = { version = "1.0.203", default-features = false, features = ["derive"] } | ||
| 30 | serde-json-core = "0.5.1" | ||
| 31 | |||
| 32 | # for assign resources example | ||
| 33 | assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } | ||
| 34 | |||
| 35 | #cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | ||
| 36 | cortex-m = { version = "0.7.6", features = ["inline-asm"] } | ||
| 37 | cortex-m-rt = "0.7.0" | ||
| 38 | critical-section = "1.1" | ||
| 39 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 40 | display-interface-spi = "0.4.1" | ||
| 41 | embedded-graphics = "0.7.1" | ||
| 42 | st7789 = "0.6.1" | ||
| 43 | display-interface = "0.4.1" | ||
| 44 | byte-slice-cast = { version = "1.2.0", default-features = false } | ||
| 45 | smart-leds = "0.3.0" | ||
| 46 | heapless = "0.8" | ||
| 47 | usbd-hid = "0.8.1" | ||
| 48 | |||
| 49 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 50 | embedded-hal-async = "1.0" | ||
| 51 | embedded-hal-bus = { version = "0.1", features = ["async"] } | ||
| 52 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | ||
| 53 | embedded-storage = { version = "0.3" } | ||
| 54 | static_cell = "2.1" | ||
| 55 | portable-atomic = { version = "1.5", features = ["critical-section"] } | ||
| 56 | log = "0.4" | ||
| 57 | pio-proc = "0.2" | ||
| 58 | pio = "0.2.1" | ||
| 59 | rand = { version = "0.8.5", default-features = false } | ||
| 60 | embedded-sdmmc = "0.7.0" | ||
| 61 | |||
| 62 | bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } | ||
| 63 | trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } | ||
| 64 | |||
| 65 | [profile.release] | ||
| 66 | debug = 2 | ||
| 67 | |||
| 68 | [profile.dev] | ||
| 69 | lto = true | ||
| 70 | opt-level = "z" | ||
| 71 | |||
| 72 | [patch.crates-io] | ||
| 73 | trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } | ||
| 74 | embassy-executor = { path = "../../embassy-executor" } | ||
| 75 | embassy-sync = { path = "../../embassy-sync" } | ||
| 76 | embassy-futures = { path = "../../embassy-futures" } | ||
| 77 | embassy-time = { path = "../../embassy-time" } | ||
| 78 | embassy-time-driver = { path = "../../embassy-time-driver" } | ||
| 79 | 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 000000000..9733889c5 --- /dev/null +++ b/examples/rp23/assets/ferris.raw | |||
| Binary files differ | |||
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 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
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 @@ | |||
| 1 | MEMORY { | ||
| 2 | /* | ||
| 3 | * The RP2350 has either external or internal flash. | ||
| 4 | * | ||
| 5 | * 2 MiB is a safe default here, although a Pico 2 has 4 MiB. | ||
| 6 | */ | ||
| 7 | FLASH : ORIGIN = 0x10000000, LENGTH = 2048K | ||
| 8 | /* | ||
| 9 | * RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping. | ||
| 10 | * This is usually good for performance, as it distributes load on | ||
| 11 | * those banks evenly. | ||
| 12 | */ | ||
| 13 | RAM : ORIGIN = 0x20000000, LENGTH = 512K | ||
| 14 | /* | ||
| 15 | * RAM banks 8 and 9 use a direct mapping. They can be used to have | ||
| 16 | * memory areas dedicated for some specific job, improving predictability | ||
| 17 | * of access times. | ||
| 18 | * Example: Separate stacks for core0 and core1. | ||
| 19 | */ | ||
| 20 | SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K | ||
| 21 | SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K | ||
| 22 | } | ||
| 23 | |||
| 24 | SECTIONS { | ||
| 25 | /* ### Boot ROM info | ||
| 26 | * | ||
| 27 | * Goes after .vector_table, to keep it in the first 4K of flash | ||
| 28 | * where the Boot ROM (and picotool) can find it | ||
| 29 | */ | ||
| 30 | .start_block : ALIGN(4) | ||
| 31 | { | ||
| 32 | __start_block_addr = .; | ||
| 33 | KEEP(*(.start_block)); | ||
| 34 | } > FLASH | ||
| 35 | |||
| 36 | } INSERT AFTER .vector_table; | ||
| 37 | |||
| 38 | /* move .text to start /after/ the boot info */ | ||
| 39 | _stext = ADDR(.start_block) + SIZEOF(.start_block); | ||
| 40 | |||
| 41 | SECTIONS { | ||
| 42 | /* ### Picotool 'Binary Info' Entries | ||
| 43 | * | ||
| 44 | * Picotool looks through this block (as we have pointers to it in our | ||
| 45 | * header) to find interesting information. | ||
| 46 | */ | ||
| 47 | .bi_entries : ALIGN(4) | ||
| 48 | { | ||
| 49 | /* We put this in the header */ | ||
| 50 | __bi_entries_start = .; | ||
| 51 | /* Here are the entries */ | ||
| 52 | KEEP(*(.bi_entries)); | ||
| 53 | /* Keep this block a nice round size */ | ||
| 54 | . = ALIGN(4); | ||
| 55 | /* We put this in the header */ | ||
| 56 | __bi_entries_end = .; | ||
| 57 | } > FLASH | ||
| 58 | } INSERT AFTER .text; | ||
| 59 | |||
| 60 | SECTIONS { | ||
| 61 | /* ### Boot ROM extra info | ||
| 62 | * | ||
| 63 | * Goes after everything in our program, so it can contain a signature. | ||
| 64 | */ | ||
| 65 | .end_block : ALIGN(4) | ||
| 66 | { | ||
| 67 | __end_block_addr = .; | ||
| 68 | KEEP(*(.end_block)); | ||
| 69 | } > FLASH | ||
| 70 | |||
| 71 | } INSERT AFTER .uninit; | ||
| 72 | |||
| 73 | PROVIDE(start_to_end = __end_block_addr - __start_block_addr); | ||
| 74 | 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..d1f053d39 --- /dev/null +++ b/examples/rp23/src/bin/adc.rs | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | //! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28. | ||
| 2 | //! It also reads the temperature sensor in the chip. | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::block::ImageDef; | ||
| 12 | use embassy_rp::gpio::Pull; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::main] | ||
| 35 | async fn main(_spawner: Spawner) { | ||
| 36 | let p = embassy_rp::init(Default::default()); | ||
| 37 | let mut adc = Adc::new(p.ADC, Irqs, Config::default()); | ||
| 38 | |||
| 39 | let mut p26 = Channel::new_pin(p.PIN_26, Pull::None); | ||
| 40 | let mut p27 = Channel::new_pin(p.PIN_27, Pull::None); | ||
| 41 | let mut p28 = Channel::new_pin(p.PIN_28, Pull::None); | ||
| 42 | let mut ts = Channel::new_temp_sensor(p.ADC_TEMP_SENSOR); | ||
| 43 | |||
| 44 | loop { | ||
| 45 | let level = adc.read(&mut p26).await.unwrap(); | ||
| 46 | info!("Pin 26 ADC: {}", level); | ||
| 47 | let level = adc.read(&mut p27).await.unwrap(); | ||
| 48 | info!("Pin 27 ADC: {}", level); | ||
| 49 | let level = adc.read(&mut p28).await.unwrap(); | ||
| 50 | info!("Pin 28 ADC: {}", level); | ||
| 51 | let temp = adc.read(&mut ts).await.unwrap(); | ||
| 52 | info!("Temp: {} degrees", convert_to_celsius(temp)); | ||
| 53 | Timer::after_secs(1).await; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | fn convert_to_celsius(raw_temp: u16) -> f32 { | ||
| 58 | // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet | ||
| 59 | let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721; | ||
| 60 | let sign = if temp < 0.0 { -1.0 } else { 1.0 }; | ||
| 61 | let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16; | ||
| 62 | (rounded_temp_x10 as f32) / 10.0 | ||
| 63 | } | ||
diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs new file mode 100644 index 000000000..5046e5530 --- /dev/null +++ b/examples/rp23/src/bin/adc_dma.rs | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | //! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads. | ||
| 2 | //! For multichannel, the samples are interleaved in the buffer: | ||
| 3 | //! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]` | ||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::block::ImageDef; | ||
| 12 | use embassy_rp::gpio::Pull; | ||
| 13 | use embassy_time::{Duration, Ticker}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::main] | ||
| 35 | async fn main(_spawner: Spawner) { | ||
| 36 | let p = embassy_rp::init(Default::default()); | ||
| 37 | info!("Here we go!"); | ||
| 38 | |||
| 39 | let mut adc = Adc::new(p.ADC, Irqs, Config::default()); | ||
| 40 | let mut dma = p.DMA_CH0; | ||
| 41 | let mut pin = Channel::new_pin(p.PIN_26, Pull::Up); | ||
| 42 | let mut pins = [ | ||
| 43 | Channel::new_pin(p.PIN_27, Pull::Down), | ||
| 44 | Channel::new_pin(p.PIN_28, Pull::None), | ||
| 45 | Channel::new_pin(p.PIN_29, Pull::Up), | ||
| 46 | Channel::new_temp_sensor(p.ADC_TEMP_SENSOR), | ||
| 47 | ]; | ||
| 48 | |||
| 49 | const BLOCK_SIZE: usize = 100; | ||
| 50 | const NUM_CHANNELS: usize = 4; | ||
| 51 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 52 | loop { | ||
| 53 | // Read 100 samples from a single channel | ||
| 54 | let mut buf = [0_u16; BLOCK_SIZE]; | ||
| 55 | let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) | ||
| 56 | adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); | ||
| 57 | info!("single: {:?} ...etc", buf[..8]); | ||
| 58 | |||
| 59 | // Read 100 samples from 4 channels interleaved | ||
| 60 | let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; | ||
| 61 | let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) | ||
| 62 | adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) | ||
| 63 | .await | ||
| 64 | .unwrap(); | ||
| 65 | info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); | ||
| 66 | |||
| 67 | ticker.next().await; | ||
| 68 | } | ||
| 69 | } | ||
diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs new file mode 100644 index 000000000..2f9783917 --- /dev/null +++ b/examples/rp23/src/bin/assign_resources.rs | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | //! This example demonstrates how to assign resources to multiple tasks by splitting up the peripherals. | ||
| 2 | //! 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) | ||
| 3 | //! Of course splitting up resources and sharing resources can be combined, yet this example is only about splitting up resources. | ||
| 4 | //! | ||
| 5 | //! There are basically two ways we demonstrate here: | ||
| 6 | //! 1) Assigning resources to a task by passing parts of the peripherals | ||
| 7 | //! 2) Assigning resources to a task by passing a struct with the split up peripherals, using the assign-resources macro | ||
| 8 | //! | ||
| 9 | //! using four LEDs on Pins 10, 11, 20 and 21 | ||
| 10 | |||
| 11 | #![no_std] | ||
| 12 | #![no_main] | ||
| 13 | |||
| 14 | use assign_resources::assign_resources; | ||
| 15 | use defmt::*; | ||
| 16 | use embassy_executor::Spawner; | ||
| 17 | use embassy_rp::block::ImageDef; | ||
| 18 | use embassy_rp::gpio::{Level, Output}; | ||
| 19 | use embassy_rp::peripherals::{self, PIN_20, PIN_21}; | ||
| 20 | use embassy_time::Timer; | ||
| 21 | use {defmt_rtt as _, panic_probe as _}; | ||
| 22 | |||
| 23 | #[link_section = ".start_block"] | ||
| 24 | #[used] | ||
| 25 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 26 | |||
| 27 | // Program metadata for `picotool info` | ||
| 28 | #[link_section = ".bi_entries"] | ||
| 29 | #[used] | ||
| 30 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 31 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 32 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 33 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 34 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 35 | ]; | ||
| 36 | |||
| 37 | #[embassy_executor::main] | ||
| 38 | async fn main(spawner: Spawner) { | ||
| 39 | // initialize the peripherals | ||
| 40 | let p = embassy_rp::init(Default::default()); | ||
| 41 | |||
| 42 | // 1) Assigning a resource to a task by passing parts of the peripherals. | ||
| 43 | spawner | ||
| 44 | .spawn(double_blinky_manually_assigned(spawner, p.PIN_20, p.PIN_21)) | ||
| 45 | .unwrap(); | ||
| 46 | |||
| 47 | // 2) Using the assign-resources macro to assign resources to a task. | ||
| 48 | // we perform the split, see further below for the definition of the resources struct | ||
| 49 | let r = split_resources!(p); | ||
| 50 | // and then we can use them | ||
| 51 | spawner.spawn(double_blinky_macro_assigned(spawner, r.leds)).unwrap(); | ||
| 52 | } | ||
| 53 | |||
| 54 | // 1) Assigning a resource to a task by passing parts of the peripherals. | ||
| 55 | #[embassy_executor::task] | ||
| 56 | async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { | ||
| 57 | let mut led_20 = Output::new(pin_20, Level::Low); | ||
| 58 | let mut led_21 = Output::new(pin_21, Level::High); | ||
| 59 | |||
| 60 | loop { | ||
| 61 | info!("toggling leds"); | ||
| 62 | led_20.toggle(); | ||
| 63 | led_21.toggle(); | ||
| 64 | Timer::after_secs(1).await; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | // 2) Using the assign-resources macro to assign resources to a task. | ||
| 69 | // first we define the resources we want to assign to the task using the assign_resources! macro | ||
| 70 | // basically this will split up the peripherals struct into smaller structs, that we define here | ||
| 71 | // naming is up to you, make sure your future self understands what you did here | ||
| 72 | assign_resources! { | ||
| 73 | leds: Leds{ | ||
| 74 | led_10: PIN_10, | ||
| 75 | led_11: PIN_11, | ||
| 76 | } | ||
| 77 | // add more resources to more structs if needed, for example defining one struct for each task | ||
| 78 | } | ||
| 79 | // this could be done in another file and imported here, but for the sake of simplicity we do it here | ||
| 80 | // see https://github.com/adamgreig/assign-resources for more information | ||
| 81 | |||
| 82 | // 2) Using the split resources in a task | ||
| 83 | #[embassy_executor::task] | ||
| 84 | async fn double_blinky_macro_assigned(_spawner: Spawner, r: Leds) { | ||
| 85 | let mut led_10 = Output::new(r.led_10, Level::Low); | ||
| 86 | let mut led_11 = Output::new(r.led_11, Level::High); | ||
| 87 | |||
| 88 | loop { | ||
| 89 | info!("toggling leds"); | ||
| 90 | led_10.toggle(); | ||
| 91 | led_11.toggle(); | ||
| 92 | Timer::after_secs(1).await; | ||
| 93 | } | ||
| 94 | } | ||
diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs new file mode 100644 index 000000000..9e45679c8 --- /dev/null +++ b/examples/rp23/src/bin/blinky.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | //! This example test the RP Pico on board LED. | ||
| 2 | //! | ||
| 3 | //! It does not work with the RP Pico W board. See wifi_blinky.rs. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::gpio; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use gpio::{Level, Output}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | #[embassy_executor::main] | ||
| 31 | async fn main(_spawner: Spawner) { | ||
| 32 | let p = embassy_rp::init(Default::default()); | ||
| 33 | let mut led = Output::new(p.PIN_2, Level::Low); | ||
| 34 | |||
| 35 | loop { | ||
| 36 | info!("led on!"); | ||
| 37 | led.set_high(); | ||
| 38 | Timer::after_millis(250).await; | ||
| 39 | |||
| 40 | info!("led off!"); | ||
| 41 | led.set_low(); | ||
| 42 | Timer::after_millis(250).await; | ||
| 43 | } | ||
| 44 | } | ||
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..87fc58bbc --- /dev/null +++ b/examples/rp23/src/bin/blinky_two_channels.rs | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | /// This example demonstrates how to access a given pin from more than one embassy task | ||
| 4 | /// The on-board LED is toggled by two tasks with slightly different periods, leading to the | ||
| 5 | /// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar | ||
| 6 | /// to interference and the 'beats' you can hear if you play two frequencies close to one another | ||
| 7 | /// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::gpio; | ||
| 12 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||
| 13 | use embassy_sync::channel::{Channel, Sender}; | ||
| 14 | use embassy_time::{Duration, Ticker}; | ||
| 15 | use gpio::{AnyPin, Level, Output}; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | #[link_section = ".start_block"] | ||
| 19 | #[used] | ||
| 20 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 21 | |||
| 22 | // Program metadata for `picotool info` | ||
| 23 | #[link_section = ".bi_entries"] | ||
| 24 | #[used] | ||
| 25 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 26 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 27 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 28 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 29 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 30 | ]; | ||
| 31 | |||
| 32 | enum LedState { | ||
| 33 | Toggle, | ||
| 34 | } | ||
| 35 | static CHANNEL: Channel<ThreadModeRawMutex, LedState, 64> = Channel::new(); | ||
| 36 | |||
| 37 | #[embassy_executor::main] | ||
| 38 | async fn main(spawner: Spawner) { | ||
| 39 | let p = embassy_rp::init(Default::default()); | ||
| 40 | let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); | ||
| 41 | |||
| 42 | let dt = 100 * 1_000_000; | ||
| 43 | let k = 1.003; | ||
| 44 | |||
| 45 | unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt)))); | ||
| 46 | unwrap!(spawner.spawn(toggle_led( | ||
| 47 | CHANNEL.sender(), | ||
| 48 | Duration::from_nanos((dt as f64 * k) as u64) | ||
| 49 | ))); | ||
| 50 | |||
| 51 | loop { | ||
| 52 | match CHANNEL.receive().await { | ||
| 53 | LedState::Toggle => led.toggle(), | ||
| 54 | } | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | #[embassy_executor::task(pool_size = 2)] | ||
| 59 | async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>, delay: Duration) { | ||
| 60 | let mut ticker = Ticker::every(delay); | ||
| 61 | loop { | ||
| 62 | control.send(LedState::Toggle).await; | ||
| 63 | ticker.next().await; | ||
| 64 | } | ||
| 65 | } | ||
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..40236c53b --- /dev/null +++ b/examples/rp23/src/bin/blinky_two_tasks.rs | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | /// This example demonstrates how to access a given pin from more than one embassy task | ||
| 4 | /// The on-board LED is toggled by two tasks with slightly different periods, leading to the | ||
| 5 | /// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar | ||
| 6 | /// to interference and the 'beats' you can hear if you play two frequencies close to one another | ||
| 7 | /// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::gpio; | ||
| 12 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||
| 13 | use embassy_sync::mutex::Mutex; | ||
| 14 | use embassy_time::{Duration, Ticker}; | ||
| 15 | use gpio::{AnyPin, Level, Output}; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | #[link_section = ".start_block"] | ||
| 19 | #[used] | ||
| 20 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 21 | |||
| 22 | // Program metadata for `picotool info` | ||
| 23 | #[link_section = ".bi_entries"] | ||
| 24 | #[used] | ||
| 25 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 26 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 27 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 28 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 29 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 30 | ]; | ||
| 31 | |||
| 32 | type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static>>>; | ||
| 33 | static LED: LedType = Mutex::new(None); | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(spawner: Spawner) { | ||
| 37 | let p = embassy_rp::init(Default::default()); | ||
| 38 | // set the content of the global LED reference to the real LED pin | ||
| 39 | let led = Output::new(AnyPin::from(p.PIN_25), Level::High); | ||
| 40 | // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the | ||
| 41 | // Mutex is released | ||
| 42 | { | ||
| 43 | *(LED.lock().await) = Some(led); | ||
| 44 | } | ||
| 45 | let dt = 100 * 1_000_000; | ||
| 46 | let k = 1.003; | ||
| 47 | |||
| 48 | unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos(dt)))); | ||
| 49 | unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64)))); | ||
| 50 | } | ||
| 51 | |||
| 52 | #[embassy_executor::task(pool_size = 2)] | ||
| 53 | async fn toggle_led(led: &'static LedType, delay: Duration) { | ||
| 54 | let mut ticker = Ticker::every(delay); | ||
| 55 | loop { | ||
| 56 | { | ||
| 57 | let mut led_unlocked = led.lock().await; | ||
| 58 | if let Some(pin_ref) = led_unlocked.as_mut() { | ||
| 59 | pin_ref.toggle(); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | ticker.next().await; | ||
| 63 | } | ||
| 64 | } | ||
diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs new file mode 100644 index 000000000..fb067a370 --- /dev/null +++ b/examples/rp23/src/bin/button.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | //! This example uses the RP Pico on board LED to test input pin 28. This is not the button on the board. | ||
| 2 | //! | ||
| 3 | //! It does not work with the RP Pico W board. Use wifi_blinky.rs and add input pin. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::block::ImageDef; | ||
| 10 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[link_section = ".start_block"] | ||
| 14 | #[used] | ||
| 15 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 16 | |||
| 17 | // Program metadata for `picotool info` | ||
| 18 | #[link_section = ".bi_entries"] | ||
| 19 | #[used] | ||
| 20 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 21 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 22 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 23 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 24 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 25 | ]; | ||
| 26 | |||
| 27 | #[embassy_executor::main] | ||
| 28 | async fn main(_spawner: Spawner) { | ||
| 29 | let p = embassy_rp::init(Default::default()); | ||
| 30 | let mut led = Output::new(p.PIN_25, Level::Low); | ||
| 31 | |||
| 32 | // Use PIN_28, Pin34 on J0 for RP Pico, as a input. | ||
| 33 | // You need to add your own button. | ||
| 34 | let button = Input::new(p.PIN_28, Pull::Up); | ||
| 35 | |||
| 36 | loop { | ||
| 37 | if button.is_high() { | ||
| 38 | led.set_high(); | ||
| 39 | } else { | ||
| 40 | led.set_low(); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | ||
diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs new file mode 100644 index 000000000..e672521ec --- /dev/null +++ b/examples/rp23/src/bin/debounce.rs | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | //! This example shows the ease of debouncing a button with async rust. | ||
| 2 | //! Hook up a button or switch between pin 9 and ground. | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use defmt::info; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::block::ImageDef; | ||
| 10 | use embassy_rp::gpio::{Input, Level, Pull}; | ||
| 11 | use embassy_time::{with_deadline, Duration, Instant, Timer}; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[link_section = ".start_block"] | ||
| 15 | #[used] | ||
| 16 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 17 | |||
| 18 | // Program metadata for `picotool info` | ||
| 19 | #[link_section = ".bi_entries"] | ||
| 20 | #[used] | ||
| 21 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 22 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 23 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 24 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 25 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 26 | ]; | ||
| 27 | |||
| 28 | pub struct Debouncer<'a> { | ||
| 29 | input: Input<'a>, | ||
| 30 | debounce: Duration, | ||
| 31 | } | ||
| 32 | |||
| 33 | impl<'a> Debouncer<'a> { | ||
| 34 | pub fn new(input: Input<'a>, debounce: Duration) -> Self { | ||
| 35 | Self { input, debounce } | ||
| 36 | } | ||
| 37 | |||
| 38 | pub async fn debounce(&mut self) -> Level { | ||
| 39 | loop { | ||
| 40 | let l1 = self.input.get_level(); | ||
| 41 | |||
| 42 | self.input.wait_for_any_edge().await; | ||
| 43 | |||
| 44 | Timer::after(self.debounce).await; | ||
| 45 | |||
| 46 | let l2 = self.input.get_level(); | ||
| 47 | if l1 != l2 { | ||
| 48 | break l2; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | #[embassy_executor::main] | ||
| 55 | async fn main(_spawner: Spawner) { | ||
| 56 | let p = embassy_rp::init(Default::default()); | ||
| 57 | let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20)); | ||
| 58 | |||
| 59 | info!("Debounce Demo"); | ||
| 60 | |||
| 61 | loop { | ||
| 62 | // button pressed | ||
| 63 | btn.debounce().await; | ||
| 64 | let start = Instant::now(); | ||
| 65 | info!("Button Press"); | ||
| 66 | |||
| 67 | match with_deadline(start + Duration::from_secs(1), btn.debounce()).await { | ||
| 68 | // Button Released < 1s | ||
| 69 | Ok(_) => { | ||
| 70 | info!("Button pressed for: {}ms", start.elapsed().as_millis()); | ||
| 71 | continue; | ||
| 72 | } | ||
| 73 | // button held for > 1s | ||
| 74 | Err(_) => { | ||
| 75 | info!("Button Held"); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | match with_deadline(start + Duration::from_secs(5), btn.debounce()).await { | ||
| 80 | // Button released <5s | ||
| 81 | Ok(_) => { | ||
| 82 | info!("Button pressed for: {}ms", start.elapsed().as_millis()); | ||
| 83 | continue; | ||
| 84 | } | ||
| 85 | // button held for > >5s | ||
| 86 | Err(_) => { | ||
| 87 | info!("Button Long Held"); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | // wait for button release before handling another press | ||
| 92 | btn.debounce().await; | ||
| 93 | info!("Button pressed for: {}ms", start.elapsed().as_millis()); | ||
| 94 | } | ||
| 95 | } | ||
diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs new file mode 100644 index 000000000..84011e394 --- /dev/null +++ b/examples/rp23/src/bin/flash.rs | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | //! This example test the flash connected to the RP2040 chip. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE}; | ||
| 10 | use embassy_rp::peripherals::FLASH; | ||
| 11 | use embassy_time::Timer; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[link_section = ".start_block"] | ||
| 15 | #[used] | ||
| 16 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 17 | |||
| 18 | // Program metadata for `picotool info` | ||
| 19 | #[link_section = ".bi_entries"] | ||
| 20 | #[used] | ||
| 21 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 22 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 23 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 24 | embassy_rp::binary_info::rp_program_description!(c"Flash"), | ||
| 25 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 26 | ]; | ||
| 27 | |||
| 28 | const ADDR_OFFSET: u32 = 0x100000; | ||
| 29 | const FLASH_SIZE: usize = 2 * 1024 * 1024; | ||
| 30 | |||
| 31 | #[embassy_executor::main] | ||
| 32 | async fn main(_spawner: Spawner) { | ||
| 33 | let p = embassy_rp::init(Default::default()); | ||
| 34 | info!("Hello World!"); | ||
| 35 | |||
| 36 | // add some delay to give an attached debug probe time to parse the | ||
| 37 | // defmt RTT header. Reading that header might touch flash memory, which | ||
| 38 | // interferes with flash write operations. | ||
| 39 | // https://github.com/knurling-rs/defmt/pull/683 | ||
| 40 | Timer::after_millis(10).await; | ||
| 41 | |||
| 42 | let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); | ||
| 43 | |||
| 44 | erase_write_sector(&mut flash, 0x00); | ||
| 45 | |||
| 46 | multiwrite_bytes(&mut flash, ERASE_SIZE as u32); | ||
| 47 | |||
| 48 | background_read(&mut flash, (ERASE_SIZE * 2) as u32).await; | ||
| 49 | |||
| 50 | info!("Flash Works!"); | ||
| 51 | } | ||
| 52 | |||
| 53 | fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { | ||
| 54 | info!(">>>> [multiwrite_bytes]"); | ||
| 55 | let mut read_buf = [0u8; ERASE_SIZE]; | ||
| 56 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); | ||
| 57 | |||
| 58 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | ||
| 59 | info!("Contents start with {=[u8]}", read_buf[0..4]); | ||
| 60 | |||
| 61 | defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | ||
| 62 | |||
| 63 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); | ||
| 64 | info!("Contents after erase starts with {=[u8]}", read_buf[0..4]); | ||
| 65 | if read_buf.iter().any(|x| *x != 0xFF) { | ||
| 66 | defmt::panic!("unexpected"); | ||
| 67 | } | ||
| 68 | |||
| 69 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &[0x01])); | ||
| 70 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 1, &[0x02])); | ||
| 71 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 2, &[0x03])); | ||
| 72 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 3, &[0x04])); | ||
| 73 | |||
| 74 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); | ||
| 75 | info!("Contents after write starts with {=[u8]}", read_buf[0..4]); | ||
| 76 | if read_buf[0..4] != [0x01, 0x02, 0x03, 0x04] { | ||
| 77 | defmt::panic!("unexpected"); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { | ||
| 82 | info!(">>>> [erase_write_sector]"); | ||
| 83 | let mut buf = [0u8; ERASE_SIZE]; | ||
| 84 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); | ||
| 85 | |||
| 86 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | ||
| 87 | info!("Contents start with {=[u8]}", buf[0..4]); | ||
| 88 | |||
| 89 | defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | ||
| 90 | |||
| 91 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); | ||
| 92 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); | ||
| 93 | if buf.iter().any(|x| *x != 0xFF) { | ||
| 94 | defmt::panic!("unexpected"); | ||
| 95 | } | ||
| 96 | |||
| 97 | for b in buf.iter_mut() { | ||
| 98 | *b = 0xDA; | ||
| 99 | } | ||
| 100 | |||
| 101 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &buf)); | ||
| 102 | |||
| 103 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); | ||
| 104 | info!("Contents after write starts with {=[u8]}", buf[0..4]); | ||
| 105 | if buf.iter().any(|x| *x != 0xDA) { | ||
| 106 | defmt::panic!("unexpected"); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { | ||
| 111 | info!(">>>> [background_read]"); | ||
| 112 | |||
| 113 | let mut buf = [0u32; 8]; | ||
| 114 | defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; | ||
| 115 | |||
| 116 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | ||
| 117 | info!("Contents start with {=u32:x}", buf[0]); | ||
| 118 | |||
| 119 | defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | ||
| 120 | |||
| 121 | defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; | ||
| 122 | info!("Contents after erase starts with {=u32:x}", buf[0]); | ||
| 123 | if buf.iter().any(|x| *x != 0xFFFFFFFF) { | ||
| 124 | defmt::panic!("unexpected"); | ||
| 125 | } | ||
| 126 | |||
| 127 | for b in buf.iter_mut() { | ||
| 128 | *b = 0xDABA1234; | ||
| 129 | } | ||
| 130 | |||
| 131 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, unsafe { | ||
| 132 | core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4) | ||
| 133 | })); | ||
| 134 | |||
| 135 | defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; | ||
| 136 | info!("Contents after write starts with {=u32:x}", buf[0]); | ||
| 137 | if buf.iter().any(|x| *x != 0xDABA1234) { | ||
| 138 | defmt::panic!("unexpected"); | ||
| 139 | } | ||
| 140 | } | ||
diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs new file mode 100644 index 000000000..ff12367bf --- /dev/null +++ b/examples/rp23/src/bin/gpio_async.rs | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | //! This example shows how async gpio can be used with a RP2040. | ||
| 2 | //! | ||
| 3 | //! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::gpio; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use gpio::{Input, Level, Output, Pull}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | /// It requires an external signal to be manually triggered on PIN 16. For | ||
| 31 | /// example, this could be accomplished using an external power source with a | ||
| 32 | /// button so that it is possible to toggle the signal from low to high. | ||
| 33 | /// | ||
| 34 | /// This example will begin with turning on the LED on the board and wait for a | ||
| 35 | /// high signal on PIN 16. Once the high event/signal occurs the program will | ||
| 36 | /// continue and turn off the LED, and then wait for 2 seconds before completing | ||
| 37 | /// the loop and starting over again. | ||
| 38 | #[embassy_executor::main] | ||
| 39 | async fn main(_spawner: Spawner) { | ||
| 40 | let p = embassy_rp::init(Default::default()); | ||
| 41 | let mut led = Output::new(p.PIN_25, Level::Low); | ||
| 42 | let mut async_input = Input::new(p.PIN_16, Pull::None); | ||
| 43 | |||
| 44 | loop { | ||
| 45 | info!("wait_for_high. Turn on LED"); | ||
| 46 | led.set_high(); | ||
| 47 | |||
| 48 | async_input.wait_for_high().await; | ||
| 49 | |||
| 50 | info!("done wait_for_high. Turn off LED"); | ||
| 51 | led.set_low(); | ||
| 52 | |||
| 53 | Timer::after_secs(2).await; | ||
| 54 | } | ||
| 55 | } | ||
diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs new file mode 100644 index 000000000..d2ee55197 --- /dev/null +++ b/examples/rp23/src/bin/gpout.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | //! This example shows how GPOUT (General purpose clock outputs) can toggle a output pin. | ||
| 2 | //! | ||
| 3 | //! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::clocks; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | #[link_section = ".start_block"] | ||
| 16 | #[used] | ||
| 17 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 18 | |||
| 19 | // Program metadata for `picotool info` | ||
| 20 | #[link_section = ".bi_entries"] | ||
| 21 | #[used] | ||
| 22 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 23 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 24 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 25 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 26 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 27 | ]; | ||
| 28 | |||
| 29 | #[embassy_executor::main] | ||
| 30 | async fn main(_spawner: Spawner) { | ||
| 31 | let p = embassy_rp::init(Default::default()); | ||
| 32 | |||
| 33 | let gpout3 = clocks::Gpout::new(p.PIN_25); | ||
| 34 | gpout3.set_div(1000, 0); | ||
| 35 | gpout3.enable(); | ||
| 36 | |||
| 37 | loop { | ||
| 38 | gpout3.set_src(clocks::GpoutSrc::Sys); | ||
| 39 | info!( | ||
| 40 | "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}", | ||
| 41 | gpout3.get_freq() | ||
| 42 | ); | ||
| 43 | Timer::after_secs(2).await; | ||
| 44 | |||
| 45 | gpout3.set_src(clocks::GpoutSrc::Ref); | ||
| 46 | info!( | ||
| 47 | "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}", | ||
| 48 | gpout3.get_freq() | ||
| 49 | ); | ||
| 50 | Timer::after_secs(2).await; | ||
| 51 | } | ||
| 52 | } | ||
diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs new file mode 100644 index 000000000..c8d918b56 --- /dev/null +++ b/examples/rp23/src/bin/i2c_async.rs | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | //! This example shows how to communicate asynchronous using i2c with external chips. | ||
| 2 | //! | ||
| 3 | //! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip. | ||
| 4 | //! (https://www.microchip.com/en-us/product/mcp23017) | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_rp::bind_interrupts; | ||
| 12 | use embassy_rp::block::ImageDef; | ||
| 13 | use embassy_rp::i2c::{self, Config, InterruptHandler}; | ||
| 14 | use embassy_rp::peripherals::I2C1; | ||
| 15 | use embassy_time::Timer; | ||
| 16 | use embedded_hal_async::i2c::I2c; | ||
| 17 | use {defmt_rtt as _, panic_probe as _}; | ||
| 18 | |||
| 19 | #[link_section = ".start_block"] | ||
| 20 | #[used] | ||
| 21 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 22 | |||
| 23 | // Program metadata for `picotool info` | ||
| 24 | #[link_section = ".bi_entries"] | ||
| 25 | #[used] | ||
| 26 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 27 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 28 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 29 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 30 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 31 | ]; | ||
| 32 | |||
| 33 | bind_interrupts!(struct Irqs { | ||
| 34 | I2C1_IRQ => InterruptHandler<I2C1>; | ||
| 35 | }); | ||
| 36 | |||
| 37 | #[allow(dead_code)] | ||
| 38 | mod mcp23017 { | ||
| 39 | pub const ADDR: u8 = 0x20; // default addr | ||
| 40 | |||
| 41 | macro_rules! mcpregs { | ||
| 42 | ($($name:ident : $val:expr),* $(,)?) => { | ||
| 43 | $( | ||
| 44 | pub const $name: u8 = $val; | ||
| 45 | )* | ||
| 46 | |||
| 47 | pub fn regname(reg: u8) -> &'static str { | ||
| 48 | match reg { | ||
| 49 | $( | ||
| 50 | $val => stringify!($name), | ||
| 51 | )* | ||
| 52 | _ => panic!("bad reg"), | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | // These are correct for IOCON.BANK=0 | ||
| 59 | mcpregs! { | ||
| 60 | IODIRA: 0x00, | ||
| 61 | IPOLA: 0x02, | ||
| 62 | GPINTENA: 0x04, | ||
| 63 | DEFVALA: 0x06, | ||
| 64 | INTCONA: 0x08, | ||
| 65 | IOCONA: 0x0A, | ||
| 66 | GPPUA: 0x0C, | ||
| 67 | INTFA: 0x0E, | ||
| 68 | INTCAPA: 0x10, | ||
| 69 | GPIOA: 0x12, | ||
| 70 | OLATA: 0x14, | ||
| 71 | IODIRB: 0x01, | ||
| 72 | IPOLB: 0x03, | ||
| 73 | GPINTENB: 0x05, | ||
| 74 | DEFVALB: 0x07, | ||
| 75 | INTCONB: 0x09, | ||
| 76 | IOCONB: 0x0B, | ||
| 77 | GPPUB: 0x0D, | ||
| 78 | INTFB: 0x0F, | ||
| 79 | INTCAPB: 0x11, | ||
| 80 | GPIOB: 0x13, | ||
| 81 | OLATB: 0x15, | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | #[embassy_executor::main] | ||
| 86 | async fn main(_spawner: Spawner) { | ||
| 87 | let p = embassy_rp::init(Default::default()); | ||
| 88 | |||
| 89 | let sda = p.PIN_14; | ||
| 90 | let scl = p.PIN_15; | ||
| 91 | |||
| 92 | info!("set up i2c "); | ||
| 93 | let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, Config::default()); | ||
| 94 | |||
| 95 | use mcp23017::*; | ||
| 96 | |||
| 97 | info!("init mcp23017 config for IxpandO"); | ||
| 98 | // init - a outputs, b inputs | ||
| 99 | i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap(); | ||
| 100 | i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap(); | ||
| 101 | i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups | ||
| 102 | |||
| 103 | let mut val = 1; | ||
| 104 | loop { | ||
| 105 | let mut portb = [0]; | ||
| 106 | |||
| 107 | i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap(); | ||
| 108 | info!("portb = {:02x}", portb[0]); | ||
| 109 | i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap(); | ||
| 110 | val = val.rotate_left(1); | ||
| 111 | |||
| 112 | // get a register dump | ||
| 113 | info!("getting register dump"); | ||
| 114 | let mut regs = [0; 22]; | ||
| 115 | i2c.write_read(ADDR, &[0], &mut regs).await.unwrap(); | ||
| 116 | // always get the regdump but only display it if portb'0 is set | ||
| 117 | if portb[0] & 1 != 0 { | ||
| 118 | for (idx, reg) in regs.into_iter().enumerate() { | ||
| 119 | info!("{} => {:02x}", regname(idx as u8), reg); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | Timer::after_millis(100).await; | ||
| 124 | } | ||
| 125 | } | ||
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..cce0abcde --- /dev/null +++ b/examples/rp23/src/bin/i2c_async_embassy.rs | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | //! This example shows how to communicate asynchronous using i2c with external chip. | ||
| 2 | //! | ||
| 3 | //! It's using embassy's functions directly instead of traits from embedded_hal_async::i2c::I2c. | ||
| 4 | //! While most of i2c devices are addressed using 7 bits, an extension allows 10 bits too. | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::i2c::InterruptHandler; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[link_section = ".start_block"] | ||
| 15 | #[used] | ||
| 16 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 17 | |||
| 18 | // Program metadata for `picotool info` | ||
| 19 | #[link_section = ".bi_entries"] | ||
| 20 | #[used] | ||
| 21 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 22 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 23 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 24 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 25 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 26 | ]; | ||
| 27 | |||
| 28 | // Our anonymous hypotetical temperature sensor could be: | ||
| 29 | // a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C | ||
| 30 | // It requires no configuration or calibration, works with all i2c bus speeds, | ||
| 31 | // never stretches clock or does anything complicated. Replies with one u16. | ||
| 32 | // It requires only one write to take it out of suspend mode, and stays on. | ||
| 33 | // Often result would be just on 12 bits, but here we'll simplify it to 16. | ||
| 34 | |||
| 35 | enum UncomplicatedSensorId { | ||
| 36 | A(UncomplicatedSensorU8), | ||
| 37 | B(UncomplicatedSensorU16), | ||
| 38 | } | ||
| 39 | enum UncomplicatedSensorU8 { | ||
| 40 | First = 0x48, | ||
| 41 | } | ||
| 42 | enum UncomplicatedSensorU16 { | ||
| 43 | Other = 0x0049, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl Into<u16> for UncomplicatedSensorU16 { | ||
| 47 | fn into(self) -> u16 { | ||
| 48 | self as u16 | ||
| 49 | } | ||
| 50 | } | ||
| 51 | impl Into<u16> for UncomplicatedSensorU8 { | ||
| 52 | fn into(self) -> u16 { | ||
| 53 | 0x48 | ||
| 54 | } | ||
| 55 | } | ||
| 56 | impl From<UncomplicatedSensorId> for u16 { | ||
| 57 | fn from(t: UncomplicatedSensorId) -> Self { | ||
| 58 | match t { | ||
| 59 | UncomplicatedSensorId::A(x) => x.into(), | ||
| 60 | UncomplicatedSensorId::B(x) => x.into(), | ||
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | embassy_rp::bind_interrupts!(struct Irqs { | ||
| 66 | I2C1_IRQ => InterruptHandler<embassy_rp::peripherals::I2C1>; | ||
| 67 | }); | ||
| 68 | |||
| 69 | #[embassy_executor::main] | ||
| 70 | async fn main(_task_spawner: embassy_executor::Spawner) { | ||
| 71 | let p = embassy_rp::init(Default::default()); | ||
| 72 | let sda = p.PIN_14; | ||
| 73 | let scl = p.PIN_15; | ||
| 74 | let config = embassy_rp::i2c::Config::default(); | ||
| 75 | let mut bus = embassy_rp::i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, config); | ||
| 76 | |||
| 77 | const WAKEYWAKEY: u16 = 0xBABE; | ||
| 78 | let mut result: [u8; 2] = [0, 0]; | ||
| 79 | // wait for sensors to initialize | ||
| 80 | embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await; | ||
| 81 | |||
| 82 | let _res_1 = bus | ||
| 83 | .write_async(UncomplicatedSensorU8::First, WAKEYWAKEY.to_be_bytes()) | ||
| 84 | .await; | ||
| 85 | let _res_2 = bus | ||
| 86 | .write_async(UncomplicatedSensorU16::Other, WAKEYWAKEY.to_be_bytes()) | ||
| 87 | .await; | ||
| 88 | |||
| 89 | loop { | ||
| 90 | let s1 = UncomplicatedSensorId::A(UncomplicatedSensorU8::First); | ||
| 91 | let s2 = UncomplicatedSensorId::B(UncomplicatedSensorU16::Other); | ||
| 92 | let sensors = [s1, s2]; | ||
| 93 | for sensor in sensors { | ||
| 94 | if bus.read_async(sensor, &mut result).await.is_ok() { | ||
| 95 | info!("Result {}", u16::from_be_bytes(result.into())); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await; | ||
| 99 | } | ||
| 100 | } | ||
diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs new file mode 100644 index 000000000..85c33bf0d --- /dev/null +++ b/examples/rp23/src/bin/i2c_blocking.rs | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | //! This example shows how to communicate using i2c with external chips. | ||
| 2 | //! | ||
| 3 | //! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip. | ||
| 4 | //! (https://www.microchip.com/en-us/product/mcp23017) | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_rp::block::ImageDef; | ||
| 12 | use embassy_rp::i2c::{self, Config}; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use embedded_hal_1::i2c::I2c; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[link_section = ".start_block"] | ||
| 18 | #[used] | ||
| 19 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 20 | |||
| 21 | // Program metadata for `picotool info` | ||
| 22 | #[link_section = ".bi_entries"] | ||
| 23 | #[used] | ||
| 24 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 25 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 26 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 27 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 28 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 29 | ]; | ||
| 30 | |||
| 31 | #[allow(dead_code)] | ||
| 32 | mod mcp23017 { | ||
| 33 | pub const ADDR: u8 = 0x20; // default addr | ||
| 34 | |||
| 35 | pub const IODIRA: u8 = 0x00; | ||
| 36 | pub const IPOLA: u8 = 0x02; | ||
| 37 | pub const GPINTENA: u8 = 0x04; | ||
| 38 | pub const DEFVALA: u8 = 0x06; | ||
| 39 | pub const INTCONA: u8 = 0x08; | ||
| 40 | pub const IOCONA: u8 = 0x0A; | ||
| 41 | pub const GPPUA: u8 = 0x0C; | ||
| 42 | pub const INTFA: u8 = 0x0E; | ||
| 43 | pub const INTCAPA: u8 = 0x10; | ||
| 44 | pub const GPIOA: u8 = 0x12; | ||
| 45 | pub const OLATA: u8 = 0x14; | ||
| 46 | pub const IODIRB: u8 = 0x01; | ||
| 47 | pub const IPOLB: u8 = 0x03; | ||
| 48 | pub const GPINTENB: u8 = 0x05; | ||
| 49 | pub const DEFVALB: u8 = 0x07; | ||
| 50 | pub const INTCONB: u8 = 0x09; | ||
| 51 | pub const IOCONB: u8 = 0x0B; | ||
| 52 | pub const GPPUB: u8 = 0x0D; | ||
| 53 | pub const INTFB: u8 = 0x0F; | ||
| 54 | pub const INTCAPB: u8 = 0x11; | ||
| 55 | pub const GPIOB: u8 = 0x13; | ||
| 56 | pub const OLATB: u8 = 0x15; | ||
| 57 | } | ||
| 58 | |||
| 59 | #[embassy_executor::main] | ||
| 60 | async fn main(_spawner: Spawner) { | ||
| 61 | let p = embassy_rp::init(Default::default()); | ||
| 62 | |||
| 63 | let sda = p.PIN_14; | ||
| 64 | let scl = p.PIN_15; | ||
| 65 | |||
| 66 | info!("set up i2c "); | ||
| 67 | let mut i2c = i2c::I2c::new_blocking(p.I2C1, scl, sda, Config::default()); | ||
| 68 | |||
| 69 | use mcp23017::*; | ||
| 70 | |||
| 71 | info!("init mcp23017 config for IxpandO"); | ||
| 72 | // init - a outputs, b inputs | ||
| 73 | i2c.write(ADDR, &[IODIRA, 0x00]).unwrap(); | ||
| 74 | i2c.write(ADDR, &[IODIRB, 0xff]).unwrap(); | ||
| 75 | i2c.write(ADDR, &[GPPUB, 0xff]).unwrap(); // pullups | ||
| 76 | |||
| 77 | let mut val = 0xaa; | ||
| 78 | loop { | ||
| 79 | let mut portb = [0]; | ||
| 80 | |||
| 81 | i2c.write(mcp23017::ADDR, &[GPIOA, val]).unwrap(); | ||
| 82 | i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).unwrap(); | ||
| 83 | |||
| 84 | info!("portb = {:02x}", portb[0]); | ||
| 85 | val = !val; | ||
| 86 | |||
| 87 | Timer::after_secs(1).await; | ||
| 88 | } | ||
| 89 | } | ||
diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs new file mode 100644 index 000000000..fb5f3cda1 --- /dev/null +++ b/examples/rp23/src/bin/i2c_slave.rs | |||
| @@ -0,0 +1,132 @@ | |||
| 1 | //! This example shows how to use the 2040 as an i2c slave. | ||
| 2 | #![no_std] | ||
| 3 | #![no_main] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::block::ImageDef; | ||
| 8 | use embassy_rp::peripherals::{I2C0, I2C1}; | ||
| 9 | use embassy_rp::{bind_interrupts, i2c, i2c_slave}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use embedded_hal_async::i2c::I2c; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[link_section = ".start_block"] | ||
| 15 | #[used] | ||
| 16 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 17 | |||
| 18 | // Program metadata for `picotool info` | ||
| 19 | #[link_section = ".bi_entries"] | ||
| 20 | #[used] | ||
| 21 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 22 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 23 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 24 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 25 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 26 | ]; | ||
| 27 | |||
| 28 | bind_interrupts!(struct Irqs { | ||
| 29 | I2C0_IRQ => i2c::InterruptHandler<I2C0>; | ||
| 30 | I2C1_IRQ => i2c::InterruptHandler<I2C1>; | ||
| 31 | }); | ||
| 32 | |||
| 33 | const DEV_ADDR: u8 = 0x42; | ||
| 34 | |||
| 35 | #[embassy_executor::task] | ||
| 36 | async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { | ||
| 37 | info!("Device start"); | ||
| 38 | |||
| 39 | let mut state = 0; | ||
| 40 | |||
| 41 | loop { | ||
| 42 | let mut buf = [0u8; 128]; | ||
| 43 | match dev.listen(&mut buf).await { | ||
| 44 | Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]), | ||
| 45 | Ok(i2c_slave::Command::Read) => loop { | ||
| 46 | match dev.respond_to_read(&[state]).await { | ||
| 47 | Ok(x) => match x { | ||
| 48 | i2c_slave::ReadStatus::Done => break, | ||
| 49 | i2c_slave::ReadStatus::NeedMoreBytes => (), | ||
| 50 | i2c_slave::ReadStatus::LeftoverBytes(x) => { | ||
| 51 | info!("tried to write {} extra bytes", x); | ||
| 52 | break; | ||
| 53 | } | ||
| 54 | }, | ||
| 55 | Err(e) => error!("error while responding {}", e), | ||
| 56 | } | ||
| 57 | }, | ||
| 58 | Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]), | ||
| 59 | Ok(i2c_slave::Command::WriteRead(len)) => { | ||
| 60 | info!("device received write read: {:x}", buf[..len]); | ||
| 61 | match buf[0] { | ||
| 62 | // Set the state | ||
| 63 | 0xC2 => { | ||
| 64 | state = buf[1]; | ||
| 65 | match dev.respond_and_fill(&[state], 0x00).await { | ||
| 66 | Ok(read_status) => info!("response read status {}", read_status), | ||
| 67 | Err(e) => error!("error while responding {}", e), | ||
| 68 | } | ||
| 69 | } | ||
| 70 | // Reset State | ||
| 71 | 0xC8 => { | ||
| 72 | state = 0; | ||
| 73 | match dev.respond_and_fill(&[state], 0x00).await { | ||
| 74 | Ok(read_status) => info!("response read status {}", read_status), | ||
| 75 | Err(e) => error!("error while responding {}", e), | ||
| 76 | } | ||
| 77 | } | ||
| 78 | x => error!("Invalid Write Read {:x}", x), | ||
| 79 | } | ||
| 80 | } | ||
| 81 | Err(e) => error!("{}", e), | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | #[embassy_executor::task] | ||
| 87 | async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) { | ||
| 88 | info!("Controller start"); | ||
| 89 | |||
| 90 | loop { | ||
| 91 | let mut resp_buff = [0u8; 2]; | ||
| 92 | for i in 0..10 { | ||
| 93 | match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await { | ||
| 94 | Ok(_) => info!("write_read response: {}", resp_buff), | ||
| 95 | Err(e) => error!("Error writing {}", e), | ||
| 96 | } | ||
| 97 | |||
| 98 | Timer::after_millis(100).await; | ||
| 99 | } | ||
| 100 | match con.read(DEV_ADDR, &mut resp_buff).await { | ||
| 101 | Ok(_) => info!("read response: {}", resp_buff), | ||
| 102 | Err(e) => error!("Error writing {}", e), | ||
| 103 | } | ||
| 104 | match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await { | ||
| 105 | Ok(_) => info!("write_read response: {}", resp_buff), | ||
| 106 | Err(e) => error!("Error writing {}", e), | ||
| 107 | } | ||
| 108 | Timer::after_millis(100).await; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | #[embassy_executor::main] | ||
| 113 | async fn main(spawner: Spawner) { | ||
| 114 | let p = embassy_rp::init(Default::default()); | ||
| 115 | info!("Hello World!"); | ||
| 116 | |||
| 117 | let d_sda = p.PIN_3; | ||
| 118 | let d_scl = p.PIN_2; | ||
| 119 | let mut config = i2c_slave::Config::default(); | ||
| 120 | config.addr = DEV_ADDR as u16; | ||
| 121 | let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); | ||
| 122 | |||
| 123 | unwrap!(spawner.spawn(device_task(device))); | ||
| 124 | |||
| 125 | let c_sda = p.PIN_1; | ||
| 126 | let c_scl = p.PIN_0; | ||
| 127 | let mut config = i2c::Config::default(); | ||
| 128 | config.frequency = 1_000_000; | ||
| 129 | let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); | ||
| 130 | |||
| 131 | unwrap!(spawner.spawn(controller_task(controller))); | ||
| 132 | } | ||
diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs new file mode 100644 index 000000000..ee3d9bfe7 --- /dev/null +++ b/examples/rp23/src/bin/interrupt.rs | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | //! This example shows how you can use raw interrupt handlers alongside embassy. | ||
| 2 | //! The example also showcases some of the options available for sharing resources/data. | ||
| 3 | //! | ||
| 4 | //! In the example, an ADC reading is triggered every time the PWM wraps around. | ||
| 5 | //! The sample data is sent down a channel, to be processed inside a low priority task. | ||
| 6 | //! The processed data is then used to adjust the PWM duty cycle, once every second. | ||
| 7 | |||
| 8 | #![no_std] | ||
| 9 | #![no_main] | ||
| 10 | |||
| 11 | use core::cell::{Cell, RefCell}; | ||
| 12 | |||
| 13 | use defmt::*; | ||
| 14 | use embassy_executor::Spawner; | ||
| 15 | use embassy_rp::adc::{self, Adc, Blocking}; | ||
| 16 | use embassy_rp::block::ImageDef; | ||
| 17 | use embassy_rp::gpio::Pull; | ||
| 18 | use embassy_rp::interrupt; | ||
| 19 | use embassy_rp::pwm::{Config, Pwm}; | ||
| 20 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 21 | use embassy_sync::blocking_mutex::Mutex; | ||
| 22 | use embassy_sync::channel::Channel; | ||
| 23 | use embassy_time::{Duration, Ticker}; | ||
| 24 | use portable_atomic::{AtomicU32, Ordering}; | ||
| 25 | use static_cell::StaticCell; | ||
| 26 | use {defmt_rtt as _, panic_probe as _}; | ||
| 27 | |||
| 28 | #[link_section = ".start_block"] | ||
| 29 | #[used] | ||
| 30 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 31 | |||
| 32 | // Program metadata for `picotool info` | ||
| 33 | #[link_section = ".bi_entries"] | ||
| 34 | #[used] | ||
| 35 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 36 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 37 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 38 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 39 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 40 | ]; | ||
| 41 | |||
| 42 | static COUNTER: AtomicU32 = AtomicU32::new(0); | ||
| 43 | static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None)); | ||
| 44 | static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> = | ||
| 45 | Mutex::new(RefCell::new(None)); | ||
| 46 | static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new(); | ||
| 47 | |||
| 48 | #[embassy_executor::main] | ||
| 49 | async fn main(spawner: Spawner) { | ||
| 50 | embassy_rp::pac::SIO.spinlock(31).write_value(1); | ||
| 51 | let p = embassy_rp::init(Default::default()); | ||
| 52 | |||
| 53 | let adc = Adc::new_blocking(p.ADC, Default::default()); | ||
| 54 | let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None); | ||
| 55 | ADC.lock(|a| a.borrow_mut().replace((adc, p26))); | ||
| 56 | |||
| 57 | let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default()); | ||
| 58 | PWM.lock(|p| p.borrow_mut().replace(pwm)); | ||
| 59 | |||
| 60 | // Enable the interrupt for pwm slice 4 | ||
| 61 | embassy_rp::pac::PWM.irq0_inte().modify(|w| w.set_ch4(true)); | ||
| 62 | unsafe { | ||
| 63 | cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP_0); | ||
| 64 | } | ||
| 65 | |||
| 66 | // Tasks require their resources to have 'static lifetime | ||
| 67 | // No Mutex needed when sharing within the same executor/prio level | ||
| 68 | static AVG: StaticCell<Cell<u32>> = StaticCell::new(); | ||
| 69 | let avg = AVG.init(Default::default()); | ||
| 70 | spawner.must_spawn(processing(avg)); | ||
| 71 | |||
| 72 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 73 | loop { | ||
| 74 | ticker.next().await; | ||
| 75 | let freq = COUNTER.swap(0, Ordering::Relaxed); | ||
| 76 | info!("pwm freq: {:?} Hz", freq); | ||
| 77 | info!("adc average: {:?}", avg.get()); | ||
| 78 | |||
| 79 | // Update the pwm duty cycle, based on the averaged adc reading | ||
| 80 | let mut config = Config::default(); | ||
| 81 | config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _; | ||
| 82 | PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config)); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | #[embassy_executor::task] | ||
| 87 | async fn processing(avg: &'static Cell<u32>) { | ||
| 88 | let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default(); | ||
| 89 | loop { | ||
| 90 | let val = ADC_VALUES.receive().await; | ||
| 91 | buffer.write(val); | ||
| 92 | let sum: u32 = buffer.iter().map(|x| *x as u32).sum(); | ||
| 93 | avg.set(sum / buffer.len() as u32); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | #[interrupt] | ||
| 98 | fn PWM_IRQ_WRAP_0() { | ||
| 99 | critical_section::with(|cs| { | ||
| 100 | let mut adc = ADC.borrow(cs).borrow_mut(); | ||
| 101 | let (adc, p26) = adc.as_mut().unwrap(); | ||
| 102 | let val = adc.blocking_read(p26).unwrap(); | ||
| 103 | ADC_VALUES.try_send(val).ok(); | ||
| 104 | |||
| 105 | // Clear the interrupt, so we don't immediately re-enter this irq handler | ||
| 106 | PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped(); | ||
| 107 | }); | ||
| 108 | COUNTER.fetch_add(1, Ordering::Relaxed); | ||
| 109 | } | ||
diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs new file mode 100644 index 000000000..9ab43d7a5 --- /dev/null +++ b/examples/rp23/src/bin/multicore.rs | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | //! This example shows how to send messages between the two cores in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Executor; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::gpio::{Level, Output}; | ||
| 12 | use embassy_rp::multicore::{spawn_core1, Stack}; | ||
| 13 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 14 | use embassy_sync::channel::Channel; | ||
| 15 | use embassy_time::Timer; | ||
| 16 | use static_cell::StaticCell; | ||
| 17 | use {defmt_rtt as _, panic_probe as _}; | ||
| 18 | |||
| 19 | #[link_section = ".start_block"] | ||
| 20 | #[used] | ||
| 21 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 22 | |||
| 23 | // Program metadata for `picotool info` | ||
| 24 | #[link_section = ".bi_entries"] | ||
| 25 | #[used] | ||
| 26 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 27 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 28 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 29 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 30 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 31 | ]; | ||
| 32 | |||
| 33 | static mut CORE1_STACK: Stack<4096> = Stack::new(); | ||
| 34 | static EXECUTOR0: StaticCell<Executor> = StaticCell::new(); | ||
| 35 | static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); | ||
| 36 | static CHANNEL: Channel<CriticalSectionRawMutex, LedState, 1> = Channel::new(); | ||
| 37 | |||
| 38 | enum LedState { | ||
| 39 | On, | ||
| 40 | Off, | ||
| 41 | } | ||
| 42 | |||
| 43 | #[cortex_m_rt::entry] | ||
| 44 | fn main() -> ! { | ||
| 45 | let p = embassy_rp::init(Default::default()); | ||
| 46 | let led = Output::new(p.PIN_25, Level::Low); | ||
| 47 | |||
| 48 | spawn_core1( | ||
| 49 | p.CORE1, | ||
| 50 | unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, | ||
| 51 | move || { | ||
| 52 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 53 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led)))); | ||
| 54 | }, | ||
| 55 | ); | ||
| 56 | |||
| 57 | let executor0 = EXECUTOR0.init(Executor::new()); | ||
| 58 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); | ||
| 59 | } | ||
| 60 | |||
| 61 | #[embassy_executor::task] | ||
| 62 | async fn core0_task() { | ||
| 63 | info!("Hello from core 0"); | ||
| 64 | loop { | ||
| 65 | CHANNEL.send(LedState::On).await; | ||
| 66 | Timer::after_millis(100).await; | ||
| 67 | CHANNEL.send(LedState::Off).await; | ||
| 68 | Timer::after_millis(400).await; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | #[embassy_executor::task] | ||
| 73 | async fn core1_task(mut led: Output<'static>) { | ||
| 74 | info!("Hello from core 1"); | ||
| 75 | loop { | ||
| 76 | match CHANNEL.receive().await { | ||
| 77 | LedState::On => led.set_high(), | ||
| 78 | LedState::Off => led.set_low(), | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs new file mode 100644 index 000000000..27cd3656e --- /dev/null +++ b/examples/rp23/src/bin/multiprio.rs | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | //! This example showcases how to create multiple Executor instances to run tasks at | ||
| 2 | //! different priority levels. | ||
| 3 | //! | ||
| 4 | //! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling | ||
| 5 | //! there's work in the queue, and `wfe` for waiting for work. | ||
| 6 | //! | ||
| 7 | //! Medium and high priority executors run in two interrupts with different priorities. | ||
| 8 | //! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since | ||
| 9 | //! when there's work the interrupt will trigger and run the executor. | ||
| 10 | //! | ||
| 11 | //! Sample output below. Note that high priority ticks can interrupt everything else, and | ||
| 12 | //! medium priority computations can interrupt low priority computations, making them to appear | ||
| 13 | //! to take significantly longer time. | ||
| 14 | //! | ||
| 15 | //! ```not_rust | ||
| 16 | //! [med] Starting long computation | ||
| 17 | //! [med] done in 992 ms | ||
| 18 | //! [high] tick! | ||
| 19 | //! [low] Starting long computation | ||
| 20 | //! [med] Starting long computation | ||
| 21 | //! [high] tick! | ||
| 22 | //! [high] tick! | ||
| 23 | //! [med] done in 993 ms | ||
| 24 | //! [med] Starting long computation | ||
| 25 | //! [high] tick! | ||
| 26 | //! [high] tick! | ||
| 27 | //! [med] done in 993 ms | ||
| 28 | //! [low] done in 3972 ms | ||
| 29 | //! [med] Starting long computation | ||
| 30 | //! [high] tick! | ||
| 31 | //! [high] tick! | ||
| 32 | //! [med] done in 993 ms | ||
| 33 | //! ``` | ||
| 34 | //! | ||
| 35 | //! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. | ||
| 36 | //! You will get an output like the following. Note that no computation is ever interrupted. | ||
| 37 | //! | ||
| 38 | //! ```not_rust | ||
| 39 | //! [high] tick! | ||
| 40 | //! [med] Starting long computation | ||
| 41 | //! [med] done in 496 ms | ||
| 42 | //! [low] Starting long computation | ||
| 43 | //! [low] done in 992 ms | ||
| 44 | //! [med] Starting long computation | ||
| 45 | //! [med] done in 496 ms | ||
| 46 | //! [high] tick! | ||
| 47 | //! [low] Starting long computation | ||
| 48 | //! [low] done in 992 ms | ||
| 49 | //! [high] tick! | ||
| 50 | //! [med] Starting long computation | ||
| 51 | //! [med] done in 496 ms | ||
| 52 | //! [high] tick! | ||
| 53 | //! ``` | ||
| 54 | //! | ||
| 55 | |||
| 56 | #![no_std] | ||
| 57 | #![no_main] | ||
| 58 | |||
| 59 | use cortex_m_rt::entry; | ||
| 60 | use defmt::{info, unwrap}; | ||
| 61 | use embassy_executor::{Executor, InterruptExecutor}; | ||
| 62 | use embassy_rp::block::ImageDef; | ||
| 63 | use embassy_rp::interrupt; | ||
| 64 | use embassy_rp::interrupt::{InterruptExt, Priority}; | ||
| 65 | use embassy_time::{Instant, Timer, TICK_HZ}; | ||
| 66 | use static_cell::StaticCell; | ||
| 67 | use {defmt_rtt as _, panic_probe as _}; | ||
| 68 | |||
| 69 | #[link_section = ".start_block"] | ||
| 70 | #[used] | ||
| 71 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 72 | |||
| 73 | // Program metadata for `picotool info` | ||
| 74 | #[link_section = ".bi_entries"] | ||
| 75 | #[used] | ||
| 76 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 77 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 78 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 79 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 80 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 81 | ]; | ||
| 82 | |||
| 83 | #[embassy_executor::task] | ||
| 84 | async fn run_high() { | ||
| 85 | loop { | ||
| 86 | info!(" [high] tick!"); | ||
| 87 | Timer::after_ticks(673740).await; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | #[embassy_executor::task] | ||
| 92 | async fn run_med() { | ||
| 93 | loop { | ||
| 94 | let start = Instant::now(); | ||
| 95 | info!(" [med] Starting long computation"); | ||
| 96 | |||
| 97 | // Spin-wait to simulate a long CPU computation | ||
| 98 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second | ||
| 99 | |||
| 100 | let end = Instant::now(); | ||
| 101 | let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; | ||
| 102 | info!(" [med] done in {} ms", ms); | ||
| 103 | |||
| 104 | Timer::after_ticks(53421).await; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | #[embassy_executor::task] | ||
| 109 | async fn run_low() { | ||
| 110 | loop { | ||
| 111 | let start = Instant::now(); | ||
| 112 | info!("[low] Starting long computation"); | ||
| 113 | |||
| 114 | // Spin-wait to simulate a long CPU computation | ||
| 115 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds | ||
| 116 | |||
| 117 | let end = Instant::now(); | ||
| 118 | let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ; | ||
| 119 | info!("[low] done in {} ms", ms); | ||
| 120 | |||
| 121 | Timer::after_ticks(82983).await; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); | ||
| 126 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); | ||
| 127 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | ||
| 128 | |||
| 129 | #[interrupt] | ||
| 130 | unsafe fn SWI_IRQ_1() { | ||
| 131 | EXECUTOR_HIGH.on_interrupt() | ||
| 132 | } | ||
| 133 | |||
| 134 | #[interrupt] | ||
| 135 | unsafe fn SWI_IRQ_0() { | ||
| 136 | EXECUTOR_MED.on_interrupt() | ||
| 137 | } | ||
| 138 | |||
| 139 | #[entry] | ||
| 140 | fn main() -> ! { | ||
| 141 | info!("Hello World!"); | ||
| 142 | |||
| 143 | let _p = embassy_rp::init(Default::default()); | ||
| 144 | |||
| 145 | // High-priority executor: SWI_IRQ_1, priority level 2 | ||
| 146 | interrupt::SWI_IRQ_1.set_priority(Priority::P2); | ||
| 147 | let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1); | ||
| 148 | unwrap!(spawner.spawn(run_high())); | ||
| 149 | |||
| 150 | // Medium-priority executor: SWI_IRQ_0, priority level 3 | ||
| 151 | interrupt::SWI_IRQ_0.set_priority(Priority::P3); | ||
| 152 | let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0); | ||
| 153 | unwrap!(spawner.spawn(run_med())); | ||
| 154 | |||
| 155 | // Low priority executor: runs in thread mode, using WFE/SEV | ||
| 156 | let executor = EXECUTOR_LOW.init(Executor::new()); | ||
| 157 | executor.run(|spawner| { | ||
| 158 | unwrap!(spawner.spawn(run_low())); | ||
| 159 | }); | ||
| 160 | } | ||
diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs new file mode 100644 index 000000000..106e514ca --- /dev/null +++ b/examples/rp23/src/bin/otp.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | //! This example shows reading the OTP constants on the RP235x. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::otp; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[link_section = ".start_block"] | ||
| 14 | #[used] | ||
| 15 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 16 | |||
| 17 | // Program metadata for `picotool info` | ||
| 18 | #[link_section = ".bi_entries"] | ||
| 19 | #[used] | ||
| 20 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 21 | embassy_rp::binary_info::rp_program_name!(c"OTP Read Example"), | ||
| 22 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 23 | embassy_rp::binary_info::rp_program_description!(c"OTP Read Example"), | ||
| 24 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 25 | ]; | ||
| 26 | |||
| 27 | #[embassy_executor::main] | ||
| 28 | async fn main(_spawner: Spawner) { | ||
| 29 | let _ = embassy_rp::init(Default::default()); | ||
| 30 | // | ||
| 31 | // add some delay to give an attached debug probe time to parse the | ||
| 32 | // defmt RTT header. Reading that header might touch flash memory, which | ||
| 33 | // interferes with flash write operations. | ||
| 34 | // https://github.com/knurling-rs/defmt/pull/683 | ||
| 35 | Timer::after_millis(10).await; | ||
| 36 | |||
| 37 | let chip_id = unwrap!(otp::get_chipid()); | ||
| 38 | info!("Unique id:{:X}", chip_id); | ||
| 39 | |||
| 40 | let private_rand = unwrap!(otp::get_private_random_number()); | ||
| 41 | info!("Private Rand:{:X}", private_rand); | ||
| 42 | |||
| 43 | loop { | ||
| 44 | Timer::after_secs(1).await; | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs new file mode 100644 index 000000000..231afc80e --- /dev/null +++ b/examples/rp23/src/bin/pio_async.rs | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | //! This example shows powerful PIO module in the RP2040 chip. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use defmt::info; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::bind_interrupts; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::peripherals::PIO0; | ||
| 10 | use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; | ||
| 11 | use fixed::traits::ToFixed; | ||
| 12 | use fixed_macro::types::U56F8; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | #[link_section = ".start_block"] | ||
| 16 | #[used] | ||
| 17 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 18 | |||
| 19 | // Program metadata for `picotool info` | ||
| 20 | #[link_section = ".bi_entries"] | ||
| 21 | #[used] | ||
| 22 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 23 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 24 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 25 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 26 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 27 | ]; | ||
| 28 | |||
| 29 | bind_interrupts!(struct Irqs { | ||
| 30 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 31 | }); | ||
| 32 | |||
| 33 | fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { | ||
| 34 | // Setup sm0 | ||
| 35 | |||
| 36 | // Send data serially to pin | ||
| 37 | let prg = pio_proc::pio_asm!( | ||
| 38 | ".origin 16", | ||
| 39 | "set pindirs, 1", | ||
| 40 | ".wrap_target", | ||
| 41 | "out pins,1 [19]", | ||
| 42 | ".wrap", | ||
| 43 | ); | ||
| 44 | |||
| 45 | let mut cfg = Config::default(); | ||
| 46 | cfg.use_program(&pio.load_program(&prg.program), &[]); | ||
| 47 | let out_pin = pio.make_pio_pin(pin); | ||
| 48 | cfg.set_out_pins(&[&out_pin]); | ||
| 49 | cfg.set_set_pins(&[&out_pin]); | ||
| 50 | cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed(); | ||
| 51 | cfg.shift_out.auto_fill = true; | ||
| 52 | sm.set_config(&cfg); | ||
| 53 | } | ||
| 54 | |||
| 55 | #[embassy_executor::task] | ||
| 56 | async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) { | ||
| 57 | sm.set_enable(true); | ||
| 58 | |||
| 59 | let mut v = 0x0f0caffa; | ||
| 60 | loop { | ||
| 61 | sm.tx().wait_push(v).await; | ||
| 62 | v ^= 0xffff; | ||
| 63 | info!("Pushed {:032b} to FIFO", v); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) { | ||
| 68 | // Setupm sm1 | ||
| 69 | |||
| 70 | // Read 0b10101 repeatedly until ISR is full | ||
| 71 | let prg = pio_proc::pio_asm!( | ||
| 72 | // | ||
| 73 | ".origin 8", | ||
| 74 | "set x, 0x15", | ||
| 75 | ".wrap_target", | ||
| 76 | "in x, 5 [31]", | ||
| 77 | ".wrap", | ||
| 78 | ); | ||
| 79 | |||
| 80 | let mut cfg = Config::default(); | ||
| 81 | cfg.use_program(&pio.load_program(&prg.program), &[]); | ||
| 82 | cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); | ||
| 83 | cfg.shift_in.auto_fill = true; | ||
| 84 | cfg.shift_in.direction = ShiftDirection::Right; | ||
| 85 | sm.set_config(&cfg); | ||
| 86 | } | ||
| 87 | |||
| 88 | #[embassy_executor::task] | ||
| 89 | async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) { | ||
| 90 | sm.set_enable(true); | ||
| 91 | loop { | ||
| 92 | let rx = sm.rx().wait_pull().await; | ||
| 93 | info!("Pulled {:032b} from FIFO", rx); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) { | ||
| 98 | // Setup sm2 | ||
| 99 | |||
| 100 | // Repeatedly trigger IRQ 3 | ||
| 101 | let prg = pio_proc::pio_asm!( | ||
| 102 | ".origin 0", | ||
| 103 | ".wrap_target", | ||
| 104 | "set x,10", | ||
| 105 | "delay:", | ||
| 106 | "jmp x-- delay [15]", | ||
| 107 | "irq 3 [15]", | ||
| 108 | ".wrap", | ||
| 109 | ); | ||
| 110 | let mut cfg = Config::default(); | ||
| 111 | cfg.use_program(&pio.load_program(&prg.program), &[]); | ||
| 112 | cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); | ||
| 113 | sm.set_config(&cfg); | ||
| 114 | } | ||
| 115 | |||
| 116 | #[embassy_executor::task] | ||
| 117 | async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) { | ||
| 118 | sm.set_enable(true); | ||
| 119 | loop { | ||
| 120 | irq.wait().await; | ||
| 121 | info!("IRQ trigged"); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | #[embassy_executor::main] | ||
| 126 | async fn main(spawner: Spawner) { | ||
| 127 | let p = embassy_rp::init(Default::default()); | ||
| 128 | let pio = p.PIO0; | ||
| 129 | |||
| 130 | let Pio { | ||
| 131 | mut common, | ||
| 132 | irq3, | ||
| 133 | mut sm0, | ||
| 134 | mut sm1, | ||
| 135 | mut sm2, | ||
| 136 | .. | ||
| 137 | } = Pio::new(pio, Irqs); | ||
| 138 | |||
| 139 | setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0); | ||
| 140 | setup_pio_task_sm1(&mut common, &mut sm1); | ||
| 141 | setup_pio_task_sm2(&mut common, &mut sm2); | ||
| 142 | spawner.spawn(pio_task_sm0(sm0)).unwrap(); | ||
| 143 | spawner.spawn(pio_task_sm1(sm1)).unwrap(); | ||
| 144 | spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap(); | ||
| 145 | } | ||
diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs new file mode 100644 index 000000000..60fbcb83a --- /dev/null +++ b/examples/rp23/src/bin/pio_dma.rs | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | //! This example shows powerful PIO module in the RP2040 chip. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use defmt::info; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_futures::join::join; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::peripherals::PIO0; | ||
| 10 | use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; | ||
| 11 | use embassy_rp::{bind_interrupts, Peripheral}; | ||
| 12 | use fixed::traits::ToFixed; | ||
| 13 | use fixed_macro::types::U56F8; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | fn swap_nibbles(v: u32) -> u32 { | ||
| 35 | let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4; | ||
| 36 | let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8; | ||
| 37 | (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16 | ||
| 38 | } | ||
| 39 | |||
| 40 | #[embassy_executor::main] | ||
| 41 | async fn main(_spawner: Spawner) { | ||
| 42 | let p = embassy_rp::init(Default::default()); | ||
| 43 | let pio = p.PIO0; | ||
| 44 | let Pio { | ||
| 45 | mut common, | ||
| 46 | sm0: mut sm, | ||
| 47 | .. | ||
| 48 | } = Pio::new(pio, Irqs); | ||
| 49 | |||
| 50 | let prg = pio_proc::pio_asm!( | ||
| 51 | ".origin 0", | ||
| 52 | "set pindirs,1", | ||
| 53 | ".wrap_target", | ||
| 54 | "set y,7", | ||
| 55 | "loop:", | ||
| 56 | "out x,4", | ||
| 57 | "in x,4", | ||
| 58 | "jmp y--, loop", | ||
| 59 | ".wrap", | ||
| 60 | ); | ||
| 61 | |||
| 62 | let mut cfg = Config::default(); | ||
| 63 | cfg.use_program(&common.load_program(&prg.program), &[]); | ||
| 64 | cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed(); | ||
| 65 | cfg.shift_in = ShiftConfig { | ||
| 66 | auto_fill: true, | ||
| 67 | threshold: 32, | ||
| 68 | direction: ShiftDirection::Left, | ||
| 69 | }; | ||
| 70 | cfg.shift_out = ShiftConfig { | ||
| 71 | auto_fill: true, | ||
| 72 | threshold: 32, | ||
| 73 | direction: ShiftDirection::Right, | ||
| 74 | }; | ||
| 75 | |||
| 76 | sm.set_config(&cfg); | ||
| 77 | sm.set_enable(true); | ||
| 78 | |||
| 79 | let mut dma_out_ref = p.DMA_CH0.into_ref(); | ||
| 80 | let mut dma_in_ref = p.DMA_CH1.into_ref(); | ||
| 81 | let mut dout = [0x12345678u32; 29]; | ||
| 82 | for i in 1..dout.len() { | ||
| 83 | dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; | ||
| 84 | } | ||
| 85 | let mut din = [0u32; 29]; | ||
| 86 | loop { | ||
| 87 | let (rx, tx) = sm.rx_tx(); | ||
| 88 | join( | ||
| 89 | tx.dma_push(dma_out_ref.reborrow(), &dout), | ||
| 90 | rx.dma_pull(dma_in_ref.reborrow(), &mut din), | ||
| 91 | ) | ||
| 92 | .await; | ||
| 93 | for i in 0..din.len() { | ||
| 94 | assert_eq!(din[i], swap_nibbles(dout[i])); | ||
| 95 | } | ||
| 96 | info!("Swapped {} words", dout.len()); | ||
| 97 | } | ||
| 98 | } | ||
diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs new file mode 100644 index 000000000..92aa858f9 --- /dev/null +++ b/examples/rp23/src/bin/pio_hd44780.rs | |||
| @@ -0,0 +1,255 @@ | |||
| 1 | //! This example shows powerful PIO module in the RP2040 chip to communicate with a HD44780 display. | ||
| 2 | //! See (https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use core::fmt::Write; | ||
| 8 | |||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::dma::{AnyChannel, Channel}; | ||
| 12 | use embassy_rp::peripherals::PIO0; | ||
| 13 | use embassy_rp::pio::{ | ||
| 14 | Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, | ||
| 15 | }; | ||
| 16 | use embassy_rp::pwm::{self, Pwm}; | ||
| 17 | use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; | ||
| 18 | use embassy_time::{Instant, Timer}; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | #[link_section = ".start_block"] | ||
| 22 | #[used] | ||
| 23 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 24 | |||
| 25 | // Program metadata for `picotool info` | ||
| 26 | #[link_section = ".bi_entries"] | ||
| 27 | #[used] | ||
| 28 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 29 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 30 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 31 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 32 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 33 | ]; | ||
| 34 | |||
| 35 | bind_interrupts!(pub struct Irqs { | ||
| 36 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 37 | }); | ||
| 38 | |||
| 39 | #[embassy_executor::main] | ||
| 40 | async fn main(_spawner: Spawner) { | ||
| 41 | // this test assumes a 2x16 HD44780 display attached as follow: | ||
| 42 | // rs = PIN0 | ||
| 43 | // rw = PIN1 | ||
| 44 | // e = PIN2 | ||
| 45 | // db4 = PIN3 | ||
| 46 | // db5 = PIN4 | ||
| 47 | // db6 = PIN5 | ||
| 48 | // db7 = PIN6 | ||
| 49 | // additionally a pwm signal for a bias voltage charge pump is provided on pin 15, | ||
| 50 | // allowing direct connection of the display to the RP2040 without level shifters. | ||
| 51 | let p = embassy_rp::init(Default::default()); | ||
| 52 | |||
| 53 | let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, { | ||
| 54 | let mut c = pwm::Config::default(); | ||
| 55 | c.divider = 125.into(); | ||
| 56 | c.top = 100; | ||
| 57 | c.compare_b = 50; | ||
| 58 | c | ||
| 59 | }); | ||
| 60 | |||
| 61 | let mut hd = HD44780::new( | ||
| 62 | 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, | ||
| 63 | ) | ||
| 64 | .await; | ||
| 65 | |||
| 66 | loop { | ||
| 67 | struct Buf<const N: usize>([u8; N], usize); | ||
| 68 | impl<const N: usize> Write for Buf<N> { | ||
| 69 | fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { | ||
| 70 | for b in s.as_bytes() { | ||
| 71 | if self.1 >= N { | ||
| 72 | return Err(core::fmt::Error); | ||
| 73 | } | ||
| 74 | self.0[self.1] = *b; | ||
| 75 | self.1 += 1; | ||
| 76 | } | ||
| 77 | Ok(()) | ||
| 78 | } | ||
| 79 | } | ||
| 80 | let mut buf = Buf([0; 16], 0); | ||
| 81 | write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap(); | ||
| 82 | hd.add_line(&buf.0[0..buf.1]).await; | ||
| 83 | Timer::after_secs(1).await; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | pub struct HD44780<'l> { | ||
| 88 | dma: PeripheralRef<'l, AnyChannel>, | ||
| 89 | sm: StateMachine<'l, PIO0, 0>, | ||
| 90 | |||
| 91 | buf: [u8; 40], | ||
| 92 | } | ||
| 93 | |||
| 94 | impl<'l> HD44780<'l> { | ||
| 95 | pub async fn new( | ||
| 96 | pio: impl Peripheral<P = PIO0> + 'l, | ||
| 97 | irq: Irqs, | ||
| 98 | dma: impl Peripheral<P = impl Channel> + 'l, | ||
| 99 | rs: impl PioPin, | ||
| 100 | rw: impl PioPin, | ||
| 101 | e: impl PioPin, | ||
| 102 | db4: impl PioPin, | ||
| 103 | db5: impl PioPin, | ||
| 104 | db6: impl PioPin, | ||
| 105 | db7: impl PioPin, | ||
| 106 | ) -> HD44780<'l> { | ||
| 107 | into_ref!(dma); | ||
| 108 | |||
| 109 | let Pio { | ||
| 110 | mut common, | ||
| 111 | mut irq0, | ||
| 112 | mut sm0, | ||
| 113 | .. | ||
| 114 | } = Pio::new(pio, irq); | ||
| 115 | |||
| 116 | // takes command words (<wait:24> <command:4> <0:4>) | ||
| 117 | let prg = pio_proc::pio_asm!( | ||
| 118 | r#" | ||
| 119 | .side_set 1 opt | ||
| 120 | .origin 20 | ||
| 121 | |||
| 122 | loop: | ||
| 123 | out x, 24 | ||
| 124 | delay: | ||
| 125 | jmp x--, delay | ||
| 126 | out pins, 4 side 1 | ||
| 127 | out null, 4 side 0 | ||
| 128 | jmp !osre, loop | ||
| 129 | irq 0 | ||
| 130 | "#, | ||
| 131 | ); | ||
| 132 | |||
| 133 | let rs = common.make_pio_pin(rs); | ||
| 134 | let rw = common.make_pio_pin(rw); | ||
| 135 | let e = common.make_pio_pin(e); | ||
| 136 | let db4 = common.make_pio_pin(db4); | ||
| 137 | let db5 = common.make_pio_pin(db5); | ||
| 138 | let db6 = common.make_pio_pin(db6); | ||
| 139 | let db7 = common.make_pio_pin(db7); | ||
| 140 | |||
| 141 | sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); | ||
| 142 | |||
| 143 | let mut cfg = Config::default(); | ||
| 144 | cfg.use_program(&common.load_program(&prg.program), &[&e]); | ||
| 145 | cfg.clock_divider = 125u8.into(); | ||
| 146 | cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); | ||
| 147 | cfg.shift_out = ShiftConfig { | ||
| 148 | auto_fill: true, | ||
| 149 | direction: ShiftDirection::Left, | ||
| 150 | threshold: 32, | ||
| 151 | }; | ||
| 152 | cfg.fifo_join = FifoJoin::TxOnly; | ||
| 153 | sm0.set_config(&cfg); | ||
| 154 | |||
| 155 | sm0.set_enable(true); | ||
| 156 | // init to 8 bit thrice | ||
| 157 | sm0.tx().push((50000 << 8) | 0x30); | ||
| 158 | sm0.tx().push((5000 << 8) | 0x30); | ||
| 159 | sm0.tx().push((200 << 8) | 0x30); | ||
| 160 | // init 4 bit | ||
| 161 | sm0.tx().push((200 << 8) | 0x20); | ||
| 162 | // set font and lines | ||
| 163 | sm0.tx().push((50 << 8) | 0x20); | ||
| 164 | sm0.tx().push(0b1100_0000); | ||
| 165 | |||
| 166 | irq0.wait().await; | ||
| 167 | sm0.set_enable(false); | ||
| 168 | |||
| 169 | // takes command sequences (<rs:1> <count:7>, data...) | ||
| 170 | // many side sets are only there to free up a delay bit! | ||
| 171 | let prg = pio_proc::pio_asm!( | ||
| 172 | r#" | ||
| 173 | .origin 27 | ||
| 174 | .side_set 1 | ||
| 175 | |||
| 176 | .wrap_target | ||
| 177 | pull side 0 | ||
| 178 | out x 1 side 0 ; !rs | ||
| 179 | out y 7 side 0 ; #data - 1 | ||
| 180 | |||
| 181 | ; rs/rw to e: >= 60ns | ||
| 182 | ; e high time: >= 500ns | ||
| 183 | ; e low time: >= 500ns | ||
| 184 | ; read data valid after e falling: ~5ns | ||
| 185 | ; write data hold after e falling: ~10ns | ||
| 186 | |||
| 187 | loop: | ||
| 188 | pull side 0 | ||
| 189 | jmp !x data side 0 | ||
| 190 | command: | ||
| 191 | set pins 0b00 side 0 | ||
| 192 | jmp shift side 0 | ||
| 193 | data: | ||
| 194 | set pins 0b01 side 0 | ||
| 195 | shift: | ||
| 196 | out pins 4 side 1 [9] | ||
| 197 | nop side 0 [9] | ||
| 198 | out pins 4 side 1 [9] | ||
| 199 | mov osr null side 0 [7] | ||
| 200 | out pindirs 4 side 0 | ||
| 201 | set pins 0b10 side 0 | ||
| 202 | busy: | ||
| 203 | nop side 1 [9] | ||
| 204 | jmp pin more side 0 [9] | ||
| 205 | mov osr ~osr side 1 [9] | ||
| 206 | nop side 0 [4] | ||
| 207 | out pindirs 4 side 0 | ||
| 208 | jmp y-- loop side 0 | ||
| 209 | .wrap | ||
| 210 | more: | ||
| 211 | nop side 1 [9] | ||
| 212 | jmp busy side 0 [9] | ||
| 213 | "# | ||
| 214 | ); | ||
| 215 | |||
| 216 | let mut cfg = Config::default(); | ||
| 217 | cfg.use_program(&common.load_program(&prg.program), &[&e]); | ||
| 218 | cfg.clock_divider = 8u8.into(); // ~64ns/insn | ||
| 219 | cfg.set_jmp_pin(&db7); | ||
| 220 | cfg.set_set_pins(&[&rs, &rw]); | ||
| 221 | cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); | ||
| 222 | cfg.shift_out.direction = ShiftDirection::Left; | ||
| 223 | cfg.fifo_join = FifoJoin::TxOnly; | ||
| 224 | sm0.set_config(&cfg); | ||
| 225 | |||
| 226 | sm0.set_enable(true); | ||
| 227 | |||
| 228 | // display on and cursor on and blinking, reset display | ||
| 229 | sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; | ||
| 230 | |||
| 231 | Self { | ||
| 232 | dma: dma.map_into(), | ||
| 233 | sm: sm0, | ||
| 234 | buf: [0x20; 40], | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | pub async fn add_line(&mut self, s: &[u8]) { | ||
| 239 | // move cursor to 0:0, prepare 16 characters | ||
| 240 | self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); | ||
| 241 | // move line 2 up | ||
| 242 | self.buf.copy_within(22..38, 3); | ||
| 243 | // move cursor to 1:0, prepare 16 characters | ||
| 244 | self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); | ||
| 245 | // file line 2 with spaces | ||
| 246 | self.buf[22..38].fill(0x20); | ||
| 247 | // copy input line | ||
| 248 | let len = s.len().min(16); | ||
| 249 | self.buf[22..22 + len].copy_from_slice(&s[0..len]); | ||
| 250 | // set cursor to 1:15 | ||
| 251 | self.buf[38..].copy_from_slice(&[0x80, 0xcf]); | ||
| 252 | |||
| 253 | self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; | ||
| 254 | } | ||
| 255 | } | ||
diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs new file mode 100644 index 000000000..d6d2d0ade --- /dev/null +++ b/examples/rp23/src/bin/pio_i2s.rs | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | //! This example shows generating audio and sending it to a connected i2s DAC using the PIO | ||
| 2 | //! module of the RP2040. | ||
| 3 | //! | ||
| 4 | //! Connect the i2s DAC as follows: | ||
| 5 | //! bclk : GPIO 18 | ||
| 6 | //! lrc : GPIO 19 | ||
| 7 | //! din : GPIO 20 | ||
| 8 | //! Then hold down the boot select button to trigger a rising triangle waveform. | ||
| 9 | |||
| 10 | #![no_std] | ||
| 11 | #![no_main] | ||
| 12 | |||
| 13 | use core::mem; | ||
| 14 | |||
| 15 | use embassy_executor::Spawner; | ||
| 16 | use embassy_rp::block::ImageDef; | ||
| 17 | use embassy_rp::peripherals::PIO0; | ||
| 18 | use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; | ||
| 19 | use embassy_rp::{bind_interrupts, Peripheral}; | ||
| 20 | use fixed::traits::ToFixed; | ||
| 21 | use static_cell::StaticCell; | ||
| 22 | use {defmt_rtt as _, panic_probe as _}; | ||
| 23 | |||
| 24 | #[link_section = ".start_block"] | ||
| 25 | #[used] | ||
| 26 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 27 | |||
| 28 | // Program metadata for `picotool info` | ||
| 29 | #[link_section = ".bi_entries"] | ||
| 30 | #[used] | ||
| 31 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 32 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 33 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 34 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 35 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 36 | ]; | ||
| 37 | |||
| 38 | bind_interrupts!(struct Irqs { | ||
| 39 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 40 | }); | ||
| 41 | |||
| 42 | const SAMPLE_RATE: u32 = 48_000; | ||
| 43 | |||
| 44 | #[embassy_executor::main] | ||
| 45 | async fn main(_spawner: Spawner) { | ||
| 46 | let p = embassy_rp::init(Default::default()); | ||
| 47 | |||
| 48 | // Setup pio state machine for i2s output | ||
| 49 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 50 | |||
| 51 | #[rustfmt::skip] | ||
| 52 | let pio_program = pio_proc::pio_asm!( | ||
| 53 | ".side_set 2", | ||
| 54 | " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock | ||
| 55 | "left_data:", | ||
| 56 | " out pins, 1 side 0b00", | ||
| 57 | " jmp x-- left_data side 0b01", | ||
| 58 | " out pins 1 side 0b10", | ||
| 59 | " set x, 14 side 0b11", | ||
| 60 | "right_data:", | ||
| 61 | " out pins 1 side 0b10", | ||
| 62 | " jmp x-- right_data side 0b11", | ||
| 63 | " out pins 1 side 0b00", | ||
| 64 | ); | ||
| 65 | |||
| 66 | let bit_clock_pin = p.PIN_18; | ||
| 67 | let left_right_clock_pin = p.PIN_19; | ||
| 68 | let data_pin = p.PIN_20; | ||
| 69 | |||
| 70 | let data_pin = pio.common.make_pio_pin(data_pin); | ||
| 71 | let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); | ||
| 72 | let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); | ||
| 73 | |||
| 74 | let cfg = { | ||
| 75 | let mut cfg = Config::default(); | ||
| 76 | cfg.use_program( | ||
| 77 | &pio.common.load_program(&pio_program.program), | ||
| 78 | &[&bit_clock_pin, &left_right_clock_pin], | ||
| 79 | ); | ||
| 80 | cfg.set_out_pins(&[&data_pin]); | ||
| 81 | const BIT_DEPTH: u32 = 16; | ||
| 82 | const CHANNELS: u32 = 2; | ||
| 83 | let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS; | ||
| 84 | cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); | ||
| 85 | cfg.shift_out = ShiftConfig { | ||
| 86 | threshold: 32, | ||
| 87 | direction: ShiftDirection::Left, | ||
| 88 | auto_fill: true, | ||
| 89 | }; | ||
| 90 | // join fifos to have twice the time to start the next dma transfer | ||
| 91 | cfg.fifo_join = FifoJoin::TxOnly; | ||
| 92 | cfg | ||
| 93 | }; | ||
| 94 | pio.sm0.set_config(&cfg); | ||
| 95 | pio.sm0.set_pin_dirs( | ||
| 96 | embassy_rp::pio::Direction::Out, | ||
| 97 | &[&data_pin, &left_right_clock_pin, &bit_clock_pin], | ||
| 98 | ); | ||
| 99 | |||
| 100 | // create two audio buffers (back and front) which will take turns being | ||
| 101 | // filled with new audio data and being sent to the pio fifo using dma | ||
| 102 | const BUFFER_SIZE: usize = 960; | ||
| 103 | static DMA_BUFFER: StaticCell<[u32; BUFFER_SIZE * 2]> = StaticCell::new(); | ||
| 104 | let dma_buffer = DMA_BUFFER.init_with(|| [0u32; BUFFER_SIZE * 2]); | ||
| 105 | let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); | ||
| 106 | |||
| 107 | // start pio state machine | ||
| 108 | pio.sm0.set_enable(true); | ||
| 109 | let tx = pio.sm0.tx(); | ||
| 110 | let mut dma_ref = p.DMA_CH0.into_ref(); | ||
| 111 | |||
| 112 | let mut fade_value: i32 = 0; | ||
| 113 | let mut phase: i32 = 0; | ||
| 114 | |||
| 115 | loop { | ||
| 116 | // trigger transfer of front buffer data to the pio fifo | ||
| 117 | // but don't await the returned future, yet | ||
| 118 | let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); | ||
| 119 | |||
| 120 | // fade in audio | ||
| 121 | let fade_target = i32::MAX; | ||
| 122 | |||
| 123 | // fill back buffer with fresh audio samples before awaiting the dma future | ||
| 124 | for s in back_buffer.iter_mut() { | ||
| 125 | // exponential approach of fade_value => fade_target | ||
| 126 | fade_value += (fade_target - fade_value) >> 14; | ||
| 127 | // generate triangle wave with amplitude and frequency based on fade value | ||
| 128 | phase = (phase + (fade_value >> 22)) & 0xffff; | ||
| 129 | let triangle_sample = (phase as i16 as i32).abs() - 16384; | ||
| 130 | let sample = (triangle_sample * (fade_value >> 15)) >> 16; | ||
| 131 | // duplicate mono sample into lower and upper half of dma word | ||
| 132 | *s = (sample as u16 as u32) * 0x10001; | ||
| 133 | } | ||
| 134 | |||
| 135 | // now await the dma future. once the dma finishes, the next buffer needs to be queued | ||
| 136 | // within DMA_DEPTH / SAMPLE_RATE = 8 / 48000 seconds = 166us | ||
| 137 | dma_future.await; | ||
| 138 | mem::swap(&mut back_buffer, &mut front_buffer); | ||
| 139 | } | ||
| 140 | } | ||
diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs new file mode 100644 index 000000000..587f91ac3 --- /dev/null +++ b/examples/rp23/src/bin/pio_pwm.rs | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | //! This example shows how to create a pwm using the PIO module in the RP2040 chip. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use core::time::Duration; | ||
| 6 | |||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::gpio::Level; | ||
| 10 | use embassy_rp::peripherals::PIO0; | ||
| 11 | use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; | ||
| 12 | use embassy_rp::{bind_interrupts, clocks}; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use pio::InstructionOperands; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[link_section = ".start_block"] | ||
| 18 | #[used] | ||
| 19 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 20 | |||
| 21 | // Program metadata for `picotool info` | ||
| 22 | #[link_section = ".bi_entries"] | ||
| 23 | #[used] | ||
| 24 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 25 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 26 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 27 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 28 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 29 | ]; | ||
| 30 | |||
| 31 | const REFRESH_INTERVAL: u64 = 20000; | ||
| 32 | |||
| 33 | bind_interrupts!(struct Irqs { | ||
| 34 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 35 | }); | ||
| 36 | |||
| 37 | pub fn to_pio_cycles(duration: Duration) -> u32 { | ||
| 38 | (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow | ||
| 39 | } | ||
| 40 | |||
| 41 | pub struct PwmPio<'d, T: Instance, const SM: usize> { | ||
| 42 | sm: StateMachine<'d, T, SM>, | ||
| 43 | } | ||
| 44 | |||
| 45 | impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { | ||
| 46 | pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { | ||
| 47 | let prg = pio_proc::pio_asm!( | ||
| 48 | ".side_set 1 opt" | ||
| 49 | "pull noblock side 0" | ||
| 50 | "mov x, osr" | ||
| 51 | "mov y, isr" | ||
| 52 | "countloop:" | ||
| 53 | "jmp x!=y noset" | ||
| 54 | "jmp skip side 1" | ||
| 55 | "noset:" | ||
| 56 | "nop" | ||
| 57 | "skip:" | ||
| 58 | "jmp y-- countloop" | ||
| 59 | ); | ||
| 60 | |||
| 61 | pio.load_program(&prg.program); | ||
| 62 | let pin = pio.make_pio_pin(pin); | ||
| 63 | sm.set_pins(Level::High, &[&pin]); | ||
| 64 | sm.set_pin_dirs(Direction::Out, &[&pin]); | ||
| 65 | |||
| 66 | let mut cfg = Config::default(); | ||
| 67 | cfg.use_program(&pio.load_program(&prg.program), &[&pin]); | ||
| 68 | |||
| 69 | sm.set_config(&cfg); | ||
| 70 | |||
| 71 | Self { sm } | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn start(&mut self) { | ||
| 75 | self.sm.set_enable(true); | ||
| 76 | } | ||
| 77 | |||
| 78 | pub fn stop(&mut self) { | ||
| 79 | self.sm.set_enable(false); | ||
| 80 | } | ||
| 81 | |||
| 82 | pub fn set_period(&mut self, duration: Duration) { | ||
| 83 | let is_enabled = self.sm.is_enabled(); | ||
| 84 | while !self.sm.tx().empty() {} // Make sure that the queue is empty | ||
| 85 | self.sm.set_enable(false); | ||
| 86 | self.sm.tx().push(to_pio_cycles(duration)); | ||
| 87 | unsafe { | ||
| 88 | self.sm.exec_instr( | ||
| 89 | InstructionOperands::PULL { | ||
| 90 | if_empty: false, | ||
| 91 | block: false, | ||
| 92 | } | ||
| 93 | .encode(), | ||
| 94 | ); | ||
| 95 | self.sm.exec_instr( | ||
| 96 | InstructionOperands::OUT { | ||
| 97 | destination: ::pio::OutDestination::ISR, | ||
| 98 | bit_count: 32, | ||
| 99 | } | ||
| 100 | .encode(), | ||
| 101 | ); | ||
| 102 | }; | ||
| 103 | if is_enabled { | ||
| 104 | self.sm.set_enable(true) // Enable if previously enabled | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | pub fn set_level(&mut self, level: u32) { | ||
| 109 | self.sm.tx().push(level); | ||
| 110 | } | ||
| 111 | |||
| 112 | pub fn write(&mut self, duration: Duration) { | ||
| 113 | self.set_level(to_pio_cycles(duration)); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | #[embassy_executor::main] | ||
| 118 | async fn main(_spawner: Spawner) { | ||
| 119 | let p = embassy_rp::init(Default::default()); | ||
| 120 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); | ||
| 121 | |||
| 122 | // Note that PIN_25 is the led pin on the Pico | ||
| 123 | let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); | ||
| 124 | pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); | ||
| 125 | pwm_pio.start(); | ||
| 126 | |||
| 127 | let mut duration = 0; | ||
| 128 | loop { | ||
| 129 | duration = (duration + 1) % 1000; | ||
| 130 | pwm_pio.write(Duration::from_micros(duration)); | ||
| 131 | Timer::after_millis(1).await; | ||
| 132 | } | ||
| 133 | } | ||
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..c147351e8 --- /dev/null +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | //! This example shows how to use the PIO module in the RP2040 to read a quadrature rotary encoder. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::info; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::gpio::Pull; | ||
| 10 | use embassy_rp::peripherals::PIO0; | ||
| 11 | use embassy_rp::{bind_interrupts, pio}; | ||
| 12 | use fixed::traits::ToFixed; | ||
| 13 | use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | pub struct PioEncoder<'d, T: Instance, const SM: usize> { | ||
| 35 | sm: StateMachine<'d, T, SM>, | ||
| 36 | } | ||
| 37 | |||
| 38 | impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { | ||
| 39 | pub fn new( | ||
| 40 | pio: &mut Common<'d, T>, | ||
| 41 | mut sm: StateMachine<'d, T, SM>, | ||
| 42 | pin_a: impl PioPin, | ||
| 43 | pin_b: impl PioPin, | ||
| 44 | ) -> Self { | ||
| 45 | let mut pin_a = pio.make_pio_pin(pin_a); | ||
| 46 | let mut pin_b = pio.make_pio_pin(pin_b); | ||
| 47 | pin_a.set_pull(Pull::Up); | ||
| 48 | pin_b.set_pull(Pull::Up); | ||
| 49 | sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); | ||
| 50 | |||
| 51 | let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); | ||
| 52 | |||
| 53 | let mut cfg = Config::default(); | ||
| 54 | cfg.set_in_pins(&[&pin_a, &pin_b]); | ||
| 55 | cfg.fifo_join = FifoJoin::RxOnly; | ||
| 56 | cfg.shift_in.direction = ShiftDirection::Left; | ||
| 57 | cfg.clock_divider = 10_000.to_fixed(); | ||
| 58 | cfg.use_program(&pio.load_program(&prg.program), &[]); | ||
| 59 | sm.set_config(&cfg); | ||
| 60 | sm.set_enable(true); | ||
| 61 | Self { sm } | ||
| 62 | } | ||
| 63 | |||
| 64 | pub async fn read(&mut self) -> Direction { | ||
| 65 | loop { | ||
| 66 | match self.sm.rx().wait_pull().await { | ||
| 67 | 0 => return Direction::CounterClockwise, | ||
| 68 | 1 => return Direction::Clockwise, | ||
| 69 | _ => {} | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | pub enum Direction { | ||
| 76 | Clockwise, | ||
| 77 | CounterClockwise, | ||
| 78 | } | ||
| 79 | |||
| 80 | #[embassy_executor::main] | ||
| 81 | async fn main(_spawner: Spawner) { | ||
| 82 | let p = embassy_rp::init(Default::default()); | ||
| 83 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); | ||
| 84 | |||
| 85 | let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); | ||
| 86 | |||
| 87 | let mut count = 0; | ||
| 88 | loop { | ||
| 89 | info!("Count: {}", count); | ||
| 90 | count += match encoder.read().await { | ||
| 91 | Direction::Clockwise => 1, | ||
| 92 | Direction::CounterClockwise => -1, | ||
| 93 | }; | ||
| 94 | } | ||
| 95 | } | ||
diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs new file mode 100644 index 000000000..5e8714178 --- /dev/null +++ b/examples/rp23/src/bin/pio_servo.rs | |||
| @@ -0,0 +1,223 @@ | |||
| 1 | //! This example shows how to create a pwm using the PIO module in the RP2040 chip. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use core::time::Duration; | ||
| 6 | |||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::gpio::Level; | ||
| 10 | use embassy_rp::peripherals::PIO0; | ||
| 11 | use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; | ||
| 12 | use embassy_rp::{bind_interrupts, clocks}; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use pio::InstructionOperands; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[link_section = ".start_block"] | ||
| 18 | #[used] | ||
| 19 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 20 | |||
| 21 | // Program metadata for `picotool info` | ||
| 22 | #[link_section = ".bi_entries"] | ||
| 23 | #[used] | ||
| 24 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 25 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 26 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 27 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 28 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 29 | ]; | ||
| 30 | |||
| 31 | const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo | ||
| 32 | const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo | ||
| 33 | const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical | ||
| 34 | const REFRESH_INTERVAL: u64 = 20000; // The period of each cycle | ||
| 35 | |||
| 36 | bind_interrupts!(struct Irqs { | ||
| 37 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 38 | }); | ||
| 39 | |||
| 40 | pub fn to_pio_cycles(duration: Duration) -> u32 { | ||
| 41 | (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow | ||
| 42 | } | ||
| 43 | |||
| 44 | pub struct PwmPio<'d, T: Instance, const SM: usize> { | ||
| 45 | sm: StateMachine<'d, T, SM>, | ||
| 46 | } | ||
| 47 | |||
| 48 | impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { | ||
| 49 | pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { | ||
| 50 | let prg = pio_proc::pio_asm!( | ||
| 51 | ".side_set 1 opt" | ||
| 52 | "pull noblock side 0" | ||
| 53 | "mov x, osr" | ||
| 54 | "mov y, isr" | ||
| 55 | "countloop:" | ||
| 56 | "jmp x!=y noset" | ||
| 57 | "jmp skip side 1" | ||
| 58 | "noset:" | ||
| 59 | "nop" | ||
| 60 | "skip:" | ||
| 61 | "jmp y-- countloop" | ||
| 62 | ); | ||
| 63 | |||
| 64 | pio.load_program(&prg.program); | ||
| 65 | let pin = pio.make_pio_pin(pin); | ||
| 66 | sm.set_pins(Level::High, &[&pin]); | ||
| 67 | sm.set_pin_dirs(Direction::Out, &[&pin]); | ||
| 68 | |||
| 69 | let mut cfg = Config::default(); | ||
| 70 | cfg.use_program(&pio.load_program(&prg.program), &[&pin]); | ||
| 71 | |||
| 72 | sm.set_config(&cfg); | ||
| 73 | |||
| 74 | Self { sm } | ||
| 75 | } | ||
| 76 | |||
| 77 | pub fn start(&mut self) { | ||
| 78 | self.sm.set_enable(true); | ||
| 79 | } | ||
| 80 | |||
| 81 | pub fn stop(&mut self) { | ||
| 82 | self.sm.set_enable(false); | ||
| 83 | } | ||
| 84 | |||
| 85 | pub fn set_period(&mut self, duration: Duration) { | ||
| 86 | let is_enabled = self.sm.is_enabled(); | ||
| 87 | while !self.sm.tx().empty() {} // Make sure that the queue is empty | ||
| 88 | self.sm.set_enable(false); | ||
| 89 | self.sm.tx().push(to_pio_cycles(duration)); | ||
| 90 | unsafe { | ||
| 91 | self.sm.exec_instr( | ||
| 92 | InstructionOperands::PULL { | ||
| 93 | if_empty: false, | ||
| 94 | block: false, | ||
| 95 | } | ||
| 96 | .encode(), | ||
| 97 | ); | ||
| 98 | self.sm.exec_instr( | ||
| 99 | InstructionOperands::OUT { | ||
| 100 | destination: ::pio::OutDestination::ISR, | ||
| 101 | bit_count: 32, | ||
| 102 | } | ||
| 103 | .encode(), | ||
| 104 | ); | ||
| 105 | }; | ||
| 106 | if is_enabled { | ||
| 107 | self.sm.set_enable(true) // Enable if previously enabled | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | pub fn set_level(&mut self, level: u32) { | ||
| 112 | self.sm.tx().push(level); | ||
| 113 | } | ||
| 114 | |||
| 115 | pub fn write(&mut self, duration: Duration) { | ||
| 116 | self.set_level(to_pio_cycles(duration)); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | pub struct ServoBuilder<'d, T: Instance, const SM: usize> { | ||
| 121 | pwm: PwmPio<'d, T, SM>, | ||
| 122 | period: Duration, | ||
| 123 | min_pulse_width: Duration, | ||
| 124 | max_pulse_width: Duration, | ||
| 125 | max_degree_rotation: u64, | ||
| 126 | } | ||
| 127 | |||
| 128 | impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { | ||
| 129 | pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { | ||
| 130 | Self { | ||
| 131 | pwm, | ||
| 132 | period: Duration::from_micros(REFRESH_INTERVAL), | ||
| 133 | min_pulse_width: Duration::from_micros(DEFAULT_MIN_PULSE_WIDTH), | ||
| 134 | max_pulse_width: Duration::from_micros(DEFAULT_MAX_PULSE_WIDTH), | ||
| 135 | max_degree_rotation: DEFAULT_MAX_DEGREE_ROTATION, | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | pub fn set_period(mut self, duration: Duration) -> Self { | ||
| 140 | self.period = duration; | ||
| 141 | self | ||
| 142 | } | ||
| 143 | |||
| 144 | pub fn set_min_pulse_width(mut self, duration: Duration) -> Self { | ||
| 145 | self.min_pulse_width = duration; | ||
| 146 | self | ||
| 147 | } | ||
| 148 | |||
| 149 | pub fn set_max_pulse_width(mut self, duration: Duration) -> Self { | ||
| 150 | self.max_pulse_width = duration; | ||
| 151 | self | ||
| 152 | } | ||
| 153 | |||
| 154 | pub fn set_max_degree_rotation(mut self, degree: u64) -> Self { | ||
| 155 | self.max_degree_rotation = degree; | ||
| 156 | self | ||
| 157 | } | ||
| 158 | |||
| 159 | pub fn build(mut self) -> Servo<'d, T, SM> { | ||
| 160 | self.pwm.set_period(self.period); | ||
| 161 | Servo { | ||
| 162 | pwm: self.pwm, | ||
| 163 | min_pulse_width: self.min_pulse_width, | ||
| 164 | max_pulse_width: self.max_pulse_width, | ||
| 165 | max_degree_rotation: self.max_degree_rotation, | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | pub struct Servo<'d, T: Instance, const SM: usize> { | ||
| 171 | pwm: PwmPio<'d, T, SM>, | ||
| 172 | min_pulse_width: Duration, | ||
| 173 | max_pulse_width: Duration, | ||
| 174 | max_degree_rotation: u64, | ||
| 175 | } | ||
| 176 | |||
| 177 | impl<'d, T: Instance, const SM: usize> Servo<'d, T, SM> { | ||
| 178 | pub fn start(&mut self) { | ||
| 179 | self.pwm.start(); | ||
| 180 | } | ||
| 181 | |||
| 182 | pub fn stop(&mut self) { | ||
| 183 | self.pwm.stop(); | ||
| 184 | } | ||
| 185 | |||
| 186 | pub fn write_time(&mut self, duration: Duration) { | ||
| 187 | self.pwm.write(duration); | ||
| 188 | } | ||
| 189 | |||
| 190 | pub fn rotate(&mut self, degree: u64) { | ||
| 191 | let degree_per_nano_second = (self.max_pulse_width.as_nanos() as u64 - self.min_pulse_width.as_nanos() as u64) | ||
| 192 | / self.max_degree_rotation; | ||
| 193 | let mut duration = | ||
| 194 | Duration::from_nanos(degree * degree_per_nano_second + self.min_pulse_width.as_nanos() as u64); | ||
| 195 | if self.max_pulse_width < duration { | ||
| 196 | duration = self.max_pulse_width; | ||
| 197 | } | ||
| 198 | |||
| 199 | self.pwm.write(duration); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | #[embassy_executor::main] | ||
| 204 | async fn main(_spawner: Spawner) { | ||
| 205 | let p = embassy_rp::init(Default::default()); | ||
| 206 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); | ||
| 207 | |||
| 208 | let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); | ||
| 209 | let mut servo = ServoBuilder::new(pwm_pio) | ||
| 210 | .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo | ||
| 211 | .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. | ||
| 212 | .set_max_pulse_width(Duration::from_micros(2600)) // Along with this value. | ||
| 213 | .build(); | ||
| 214 | |||
| 215 | servo.start(); | ||
| 216 | |||
| 217 | let mut degree = 0; | ||
| 218 | loop { | ||
| 219 | degree = (degree + 1) % 120; | ||
| 220 | servo.rotate(degree); | ||
| 221 | Timer::after_millis(50).await; | ||
| 222 | } | ||
| 223 | } | ||
diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs new file mode 100644 index 000000000..24785443b --- /dev/null +++ b/examples/rp23/src/bin/pio_stepper.rs | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | //! This example shows how to use the PIO module in the RP2040 to implement a stepper motor driver | ||
| 2 | //! for a 5-wire stepper such as the 28BYJ-48. You can halt an ongoing rotation by dropping the future. | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | use core::mem::{self, MaybeUninit}; | ||
| 7 | |||
| 8 | use defmt::info; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::block::ImageDef; | ||
| 12 | use embassy_rp::peripherals::PIO0; | ||
| 13 | use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; | ||
| 14 | use embassy_time::{with_timeout, Duration, Timer}; | ||
| 15 | use fixed::traits::ToFixed; | ||
| 16 | use fixed::types::extra::U8; | ||
| 17 | use fixed::FixedU32; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | #[link_section = ".start_block"] | ||
| 21 | #[used] | ||
| 22 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 23 | |||
| 24 | // Program metadata for `picotool info` | ||
| 25 | #[link_section = ".bi_entries"] | ||
| 26 | #[used] | ||
| 27 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 28 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 29 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 30 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 31 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 32 | ]; | ||
| 33 | |||
| 34 | bind_interrupts!(struct Irqs { | ||
| 35 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 36 | }); | ||
| 37 | |||
| 38 | pub struct PioStepper<'d, T: Instance, const SM: usize> { | ||
| 39 | irq: Irq<'d, T, SM>, | ||
| 40 | sm: StateMachine<'d, T, SM>, | ||
| 41 | } | ||
| 42 | |||
| 43 | impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { | ||
| 44 | pub fn new( | ||
| 45 | pio: &mut Common<'d, T>, | ||
| 46 | mut sm: StateMachine<'d, T, SM>, | ||
| 47 | irq: Irq<'d, T, SM>, | ||
| 48 | pin0: impl PioPin, | ||
| 49 | pin1: impl PioPin, | ||
| 50 | pin2: impl PioPin, | ||
| 51 | pin3: impl PioPin, | ||
| 52 | ) -> Self { | ||
| 53 | let prg = pio_proc::pio_asm!( | ||
| 54 | "pull block", | ||
| 55 | "mov x, osr", | ||
| 56 | "pull block", | ||
| 57 | "mov y, osr", | ||
| 58 | "jmp !x end", | ||
| 59 | "loop:", | ||
| 60 | "jmp !osre step", | ||
| 61 | "mov osr, y", | ||
| 62 | "step:", | ||
| 63 | "out pins, 4 [31]" | ||
| 64 | "jmp x-- loop", | ||
| 65 | "end:", | ||
| 66 | "irq 0 rel" | ||
| 67 | ); | ||
| 68 | let pin0 = pio.make_pio_pin(pin0); | ||
| 69 | let pin1 = pio.make_pio_pin(pin1); | ||
| 70 | let pin2 = pio.make_pio_pin(pin2); | ||
| 71 | let pin3 = pio.make_pio_pin(pin3); | ||
| 72 | sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); | ||
| 73 | let mut cfg = Config::default(); | ||
| 74 | cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); | ||
| 75 | cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); | ||
| 76 | cfg.use_program(&pio.load_program(&prg.program), &[]); | ||
| 77 | sm.set_config(&cfg); | ||
| 78 | sm.set_enable(true); | ||
| 79 | Self { irq, sm } | ||
| 80 | } | ||
| 81 | |||
| 82 | // Set pulse frequency | ||
| 83 | pub fn set_frequency(&mut self, freq: u32) { | ||
| 84 | let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed(); | ||
| 85 | assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); | ||
| 86 | assert!(clock_divider >= 1, "clkdiv must be >= 1"); | ||
| 87 | self.sm.set_clock_divider(clock_divider); | ||
| 88 | self.sm.clkdiv_restart(); | ||
| 89 | } | ||
| 90 | |||
| 91 | // Full step, one phase | ||
| 92 | pub async fn step(&mut self, steps: i32) { | ||
| 93 | if steps > 0 { | ||
| 94 | self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await | ||
| 95 | } else { | ||
| 96 | self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | // Full step, two phase | ||
| 101 | pub async fn step2(&mut self, steps: i32) { | ||
| 102 | if steps > 0 { | ||
| 103 | self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await | ||
| 104 | } else { | ||
| 105 | self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | // Half step | ||
| 110 | pub async fn step_half(&mut self, steps: i32) { | ||
| 111 | if steps > 0 { | ||
| 112 | self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await | ||
| 113 | } else { | ||
| 114 | self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | async fn run(&mut self, steps: i32, pattern: u32) { | ||
| 119 | self.sm.tx().wait_push(steps as u32).await; | ||
| 120 | self.sm.tx().wait_push(pattern).await; | ||
| 121 | let drop = OnDrop::new(|| { | ||
| 122 | self.sm.clear_fifos(); | ||
| 123 | unsafe { | ||
| 124 | self.sm.exec_instr( | ||
| 125 | pio::InstructionOperands::JMP { | ||
| 126 | address: 0, | ||
| 127 | condition: pio::JmpCondition::Always, | ||
| 128 | } | ||
| 129 | .encode(), | ||
| 130 | ); | ||
| 131 | } | ||
| 132 | }); | ||
| 133 | self.irq.wait().await; | ||
| 134 | drop.defuse(); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | struct OnDrop<F: FnOnce()> { | ||
| 139 | f: MaybeUninit<F>, | ||
| 140 | } | ||
| 141 | |||
| 142 | impl<F: FnOnce()> OnDrop<F> { | ||
| 143 | pub fn new(f: F) -> Self { | ||
| 144 | Self { f: MaybeUninit::new(f) } | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn defuse(self) { | ||
| 148 | mem::forget(self) | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | impl<F: FnOnce()> Drop for OnDrop<F> { | ||
| 153 | fn drop(&mut self) { | ||
| 154 | unsafe { self.f.as_ptr().read()() } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | #[embassy_executor::main] | ||
| 159 | async fn main(_spawner: Spawner) { | ||
| 160 | let p = embassy_rp::init(Default::default()); | ||
| 161 | let Pio { | ||
| 162 | mut common, irq0, sm0, .. | ||
| 163 | } = Pio::new(p.PIO0, Irqs); | ||
| 164 | |||
| 165 | let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); | ||
| 166 | stepper.set_frequency(120); | ||
| 167 | loop { | ||
| 168 | info!("CW full steps"); | ||
| 169 | stepper.step(1000).await; | ||
| 170 | |||
| 171 | info!("CCW full steps, drop after 1 sec"); | ||
| 172 | if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await { | ||
| 173 | info!("Time's up!"); | ||
| 174 | Timer::after(Duration::from_secs(1)).await; | ||
| 175 | } | ||
| 176 | |||
| 177 | info!("CW half steps"); | ||
| 178 | stepper.step_half(1000).await; | ||
| 179 | |||
| 180 | info!("CCW half steps"); | ||
| 181 | stepper.step_half(-1000).await; | ||
| 182 | } | ||
| 183 | } | ||
diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs new file mode 100644 index 000000000..00fe5e396 --- /dev/null +++ b/examples/rp23/src/bin/pio_ws2812.rs | |||
| @@ -0,0 +1,176 @@ | |||
| 1 | //! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules. | ||
| 2 | //! See (https://www.sparkfun.com/categories/tags/ws2812) | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::block::ImageDef; | ||
| 10 | use embassy_rp::dma::{AnyChannel, Channel}; | ||
| 11 | use embassy_rp::peripherals::PIO0; | ||
| 12 | use embassy_rp::pio::{ | ||
| 13 | Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, | ||
| 14 | }; | ||
| 15 | use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; | ||
| 16 | use embassy_time::{Duration, Ticker, Timer}; | ||
| 17 | use fixed::types::U24F8; | ||
| 18 | use fixed_macro::fixed; | ||
| 19 | use smart_leds::RGB8; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | #[link_section = ".start_block"] | ||
| 23 | #[used] | ||
| 24 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 25 | |||
| 26 | // Program metadata for `picotool info` | ||
| 27 | #[link_section = ".bi_entries"] | ||
| 28 | #[used] | ||
| 29 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 30 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 31 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 32 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 33 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 34 | ]; | ||
| 35 | |||
| 36 | bind_interrupts!(struct Irqs { | ||
| 37 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 38 | }); | ||
| 39 | |||
| 40 | pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { | ||
| 41 | dma: PeripheralRef<'d, AnyChannel>, | ||
| 42 | sm: StateMachine<'d, P, S>, | ||
| 43 | } | ||
| 44 | |||
| 45 | impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { | ||
| 46 | pub fn new( | ||
| 47 | pio: &mut Common<'d, P>, | ||
| 48 | mut sm: StateMachine<'d, P, S>, | ||
| 49 | dma: impl Peripheral<P = impl Channel> + 'd, | ||
| 50 | pin: impl PioPin, | ||
| 51 | ) -> Self { | ||
| 52 | into_ref!(dma); | ||
| 53 | |||
| 54 | // Setup sm0 | ||
| 55 | |||
| 56 | // prepare the PIO program | ||
| 57 | let side_set = pio::SideSet::new(false, 1, false); | ||
| 58 | let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); | ||
| 59 | |||
| 60 | const T1: u8 = 2; // start bit | ||
| 61 | const T2: u8 = 5; // data bit | ||
| 62 | const T3: u8 = 3; // stop bit | ||
| 63 | const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; | ||
| 64 | |||
| 65 | let mut wrap_target = a.label(); | ||
| 66 | let mut wrap_source = a.label(); | ||
| 67 | let mut do_zero = a.label(); | ||
| 68 | a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); | ||
| 69 | a.bind(&mut wrap_target); | ||
| 70 | // Do stop bit | ||
| 71 | a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); | ||
| 72 | // Do start bit | ||
| 73 | a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); | ||
| 74 | // Do data bit = 1 | ||
| 75 | a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); | ||
| 76 | a.bind(&mut do_zero); | ||
| 77 | // Do data bit = 0 | ||
| 78 | a.nop_with_delay_and_side_set(T2 - 1, 0); | ||
| 79 | a.bind(&mut wrap_source); | ||
| 80 | |||
| 81 | let prg = a.assemble_with_wrap(wrap_source, wrap_target); | ||
| 82 | let mut cfg = Config::default(); | ||
| 83 | |||
| 84 | // Pin config | ||
| 85 | let out_pin = pio.make_pio_pin(pin); | ||
| 86 | cfg.set_out_pins(&[&out_pin]); | ||
| 87 | cfg.set_set_pins(&[&out_pin]); | ||
| 88 | |||
| 89 | cfg.use_program(&pio.load_program(&prg), &[&out_pin]); | ||
| 90 | |||
| 91 | // Clock config, measured in kHz to avoid overflows | ||
| 92 | // TODO CLOCK_FREQ should come from embassy_rp | ||
| 93 | let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); | ||
| 94 | let ws2812_freq = fixed!(800: U24F8); | ||
| 95 | let bit_freq = ws2812_freq * CYCLES_PER_BIT; | ||
| 96 | cfg.clock_divider = clock_freq / bit_freq; | ||
| 97 | |||
| 98 | // FIFO config | ||
| 99 | cfg.fifo_join = FifoJoin::TxOnly; | ||
| 100 | cfg.shift_out = ShiftConfig { | ||
| 101 | auto_fill: true, | ||
| 102 | threshold: 24, | ||
| 103 | direction: ShiftDirection::Left, | ||
| 104 | }; | ||
| 105 | |||
| 106 | sm.set_config(&cfg); | ||
| 107 | sm.set_enable(true); | ||
| 108 | |||
| 109 | Self { | ||
| 110 | dma: dma.map_into(), | ||
| 111 | sm, | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | pub async fn write(&mut self, colors: &[RGB8; N]) { | ||
| 116 | // Precompute the word bytes from the colors | ||
| 117 | let mut words = [0u32; N]; | ||
| 118 | for i in 0..N { | ||
| 119 | let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); | ||
| 120 | words[i] = word; | ||
| 121 | } | ||
| 122 | |||
| 123 | // DMA transfer | ||
| 124 | self.sm.tx().dma_push(self.dma.reborrow(), &words).await; | ||
| 125 | |||
| 126 | Timer::after_micros(55).await; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | /// Input a value 0 to 255 to get a color value | ||
| 131 | /// The colours are a transition r - g - b - back to r. | ||
| 132 | fn wheel(mut wheel_pos: u8) -> RGB8 { | ||
| 133 | wheel_pos = 255 - wheel_pos; | ||
| 134 | if wheel_pos < 85 { | ||
| 135 | return (255 - wheel_pos * 3, 0, wheel_pos * 3).into(); | ||
| 136 | } | ||
| 137 | if wheel_pos < 170 { | ||
| 138 | wheel_pos -= 85; | ||
| 139 | return (0, wheel_pos * 3, 255 - wheel_pos * 3).into(); | ||
| 140 | } | ||
| 141 | wheel_pos -= 170; | ||
| 142 | (wheel_pos * 3, 255 - wheel_pos * 3, 0).into() | ||
| 143 | } | ||
| 144 | |||
| 145 | #[embassy_executor::main] | ||
| 146 | async fn main(_spawner: Spawner) { | ||
| 147 | info!("Start"); | ||
| 148 | let p = embassy_rp::init(Default::default()); | ||
| 149 | |||
| 150 | let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); | ||
| 151 | |||
| 152 | // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit | ||
| 153 | // feather boards for the 2040 both have one built in. | ||
| 154 | const NUM_LEDS: usize = 1; | ||
| 155 | let mut data = [RGB8::default(); NUM_LEDS]; | ||
| 156 | |||
| 157 | // Common neopixel pins: | ||
| 158 | // Thing plus: 8 | ||
| 159 | // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 | ||
| 160 | let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); | ||
| 161 | |||
| 162 | // Loop forever making RGB values and pushing them out to the WS2812. | ||
| 163 | let mut ticker = Ticker::every(Duration::from_millis(10)); | ||
| 164 | loop { | ||
| 165 | for j in 0..(256 * 5) { | ||
| 166 | debug!("New Colors:"); | ||
| 167 | for i in 0..NUM_LEDS { | ||
| 168 | data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8); | ||
| 169 | debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b); | ||
| 170 | } | ||
| 171 | ws2812.write(&data).await; | ||
| 172 | |||
| 173 | ticker.next().await; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } | ||
diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs new file mode 100644 index 000000000..bfc2c6f67 --- /dev/null +++ b/examples/rp23/src/bin/pwm.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | //! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::pwm::{Config, Pwm}; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | #[link_section = ".start_block"] | ||
| 16 | #[used] | ||
| 17 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 18 | |||
| 19 | // Program metadata for `picotool info` | ||
| 20 | #[link_section = ".bi_entries"] | ||
| 21 | #[used] | ||
| 22 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 23 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 24 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 25 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 26 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 27 | ]; | ||
| 28 | |||
| 29 | #[embassy_executor::main] | ||
| 30 | async fn main(_spawner: Spawner) { | ||
| 31 | let p = embassy_rp::init(Default::default()); | ||
| 32 | |||
| 33 | let mut c: Config = Default::default(); | ||
| 34 | c.top = 0x8000; | ||
| 35 | c.compare_b = 8; | ||
| 36 | let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); | ||
| 37 | |||
| 38 | loop { | ||
| 39 | info!("current LED duty cycle: {}/32768", c.compare_b); | ||
| 40 | Timer::after_secs(1).await; | ||
| 41 | c.compare_b = c.compare_b.rotate_left(4); | ||
| 42 | pwm.set_config(&c); | ||
| 43 | } | ||
| 44 | } | ||
diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs new file mode 100644 index 000000000..b65f2778b --- /dev/null +++ b/examples/rp23/src/bin/pwm_input.rs | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | //! This example shows how to use the PWM module to measure the frequency of an input signal. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::block::ImageDef; | ||
| 9 | use embassy_rp::gpio::Pull; | ||
| 10 | use embassy_rp::pwm::{Config, InputMode, Pwm}; | ||
| 11 | use embassy_time::{Duration, Ticker}; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[link_section = ".start_block"] | ||
| 15 | #[used] | ||
| 16 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 17 | |||
| 18 | // Program metadata for `picotool info` | ||
| 19 | #[link_section = ".bi_entries"] | ||
| 20 | #[used] | ||
| 21 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 22 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 23 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 24 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 25 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 26 | ]; | ||
| 27 | |||
| 28 | #[embassy_executor::main] | ||
| 29 | async fn main(_spawner: Spawner) { | ||
| 30 | let p = embassy_rp::init(Default::default()); | ||
| 31 | |||
| 32 | let cfg: Config = Default::default(); | ||
| 33 | let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, Pull::None, InputMode::RisingEdge, cfg); | ||
| 34 | |||
| 35 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 36 | loop { | ||
| 37 | info!("Input frequency: {} Hz", pwm.counter()); | ||
| 38 | pwm.set_counter(0); | ||
| 39 | ticker.next().await; | ||
| 40 | } | ||
| 41 | } | ||
diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs new file mode 100644 index 000000000..f65b236b1 --- /dev/null +++ b/examples/rp23/src/bin/rosc.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | //! This example test the RP Pico on board LED. | ||
| 2 | //! | ||
| 3 | //! It does not work with the RP Pico W board. See wifi_blinky.rs. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::{clocks, gpio}; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use gpio::{Level, Output}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | #[embassy_executor::main] | ||
| 31 | async fn main(_spawner: Spawner) { | ||
| 32 | let mut config = embassy_rp::config::Config::default(); | ||
| 33 | config.clocks = clocks::ClockConfig::rosc(); | ||
| 34 | let p = embassy_rp::init(config); | ||
| 35 | let mut led = Output::new(p.PIN_25, Level::Low); | ||
| 36 | |||
| 37 | loop { | ||
| 38 | info!("led on!"); | ||
| 39 | led.set_high(); | ||
| 40 | Timer::after_secs(1).await; | ||
| 41 | |||
| 42 | info!("led off!"); | ||
| 43 | led.set_low(); | ||
| 44 | Timer::after_secs(1).await; | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs new file mode 100644 index 000000000..b3fde13e3 --- /dev/null +++ b/examples/rp23/src/bin/shared_bus.rs | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | //! This example shows how to share (async) I2C and SPI buses between multiple devices. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; | ||
| 8 | use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::block::ImageDef; | ||
| 12 | use embassy_rp::gpio::{AnyPin, Level, Output}; | ||
| 13 | use embassy_rp::i2c::{self, I2c, InterruptHandler}; | ||
| 14 | use embassy_rp::peripherals::{I2C1, SPI1}; | ||
| 15 | use embassy_rp::spi::{self, Spi}; | ||
| 16 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 17 | use embassy_sync::mutex::Mutex; | ||
| 18 | use embassy_time::Timer; | ||
| 19 | use static_cell::StaticCell; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | #[link_section = ".start_block"] | ||
| 23 | #[used] | ||
| 24 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 25 | |||
| 26 | // Program metadata for `picotool info` | ||
| 27 | #[link_section = ".bi_entries"] | ||
| 28 | #[used] | ||
| 29 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 30 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 31 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 32 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 33 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 34 | ]; | ||
| 35 | |||
| 36 | type Spi1Bus = Mutex<NoopRawMutex, Spi<'static, SPI1, spi::Async>>; | ||
| 37 | type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>; | ||
| 38 | |||
| 39 | bind_interrupts!(struct Irqs { | ||
| 40 | I2C1_IRQ => InterruptHandler<I2C1>; | ||
| 41 | }); | ||
| 42 | |||
| 43 | #[embassy_executor::main] | ||
| 44 | async fn main(spawner: Spawner) { | ||
| 45 | let p = embassy_rp::init(Default::default()); | ||
| 46 | info!("Here we go!"); | ||
| 47 | |||
| 48 | // Shared I2C bus | ||
| 49 | let i2c = I2c::new_async(p.I2C1, p.PIN_15, p.PIN_14, Irqs, i2c::Config::default()); | ||
| 50 | static I2C_BUS: StaticCell<I2c1Bus> = StaticCell::new(); | ||
| 51 | let i2c_bus = I2C_BUS.init(Mutex::new(i2c)); | ||
| 52 | |||
| 53 | spawner.must_spawn(i2c_task_a(i2c_bus)); | ||
| 54 | spawner.must_spawn(i2c_task_b(i2c_bus)); | ||
| 55 | |||
| 56 | // Shared SPI bus | ||
| 57 | let spi_cfg = spi::Config::default(); | ||
| 58 | let spi = Spi::new(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, spi_cfg); | ||
| 59 | static SPI_BUS: StaticCell<Spi1Bus> = StaticCell::new(); | ||
| 60 | let spi_bus = SPI_BUS.init(Mutex::new(spi)); | ||
| 61 | |||
| 62 | // Chip select pins for the SPI devices | ||
| 63 | let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); | ||
| 64 | let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); | ||
| 65 | |||
| 66 | spawner.must_spawn(spi_task_a(spi_bus, cs_a)); | ||
| 67 | spawner.must_spawn(spi_task_b(spi_bus, cs_b)); | ||
| 68 | } | ||
| 69 | |||
| 70 | #[embassy_executor::task] | ||
| 71 | async fn i2c_task_a(i2c_bus: &'static I2c1Bus) { | ||
| 72 | let i2c_dev = I2cDevice::new(i2c_bus); | ||
| 73 | let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xC0); | ||
| 74 | loop { | ||
| 75 | info!("i2c task A"); | ||
| 76 | Timer::after_secs(1).await; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | #[embassy_executor::task] | ||
| 81 | async fn i2c_task_b(i2c_bus: &'static I2c1Bus) { | ||
| 82 | let i2c_dev = I2cDevice::new(i2c_bus); | ||
| 83 | let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xDE); | ||
| 84 | loop { | ||
| 85 | info!("i2c task B"); | ||
| 86 | Timer::after_secs(1).await; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | #[embassy_executor::task] | ||
| 91 | async fn spi_task_a(spi_bus: &'static Spi1Bus, cs: Output<'static>) { | ||
| 92 | let spi_dev = SpiDevice::new(spi_bus, cs); | ||
| 93 | let _sensor = DummySpiDeviceDriver::new(spi_dev); | ||
| 94 | loop { | ||
| 95 | info!("spi task A"); | ||
| 96 | Timer::after_secs(1).await; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | #[embassy_executor::task] | ||
| 101 | async fn spi_task_b(spi_bus: &'static Spi1Bus, cs: Output<'static>) { | ||
| 102 | let spi_dev = SpiDevice::new(spi_bus, cs); | ||
| 103 | let _sensor = DummySpiDeviceDriver::new(spi_dev); | ||
| 104 | loop { | ||
| 105 | info!("spi task B"); | ||
| 106 | Timer::after_secs(1).await; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | // Dummy I2C device driver, using `embedded-hal-async` | ||
| 111 | struct DummyI2cDeviceDriver<I2C: embedded_hal_async::i2c::I2c> { | ||
| 112 | _i2c: I2C, | ||
| 113 | } | ||
| 114 | |||
| 115 | impl<I2C: embedded_hal_async::i2c::I2c> DummyI2cDeviceDriver<I2C> { | ||
| 116 | fn new(i2c_dev: I2C, _address: u8) -> Self { | ||
| 117 | Self { _i2c: i2c_dev } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | // Dummy SPI device driver, using `embedded-hal-async` | ||
| 122 | struct DummySpiDeviceDriver<SPI: embedded_hal_async::spi::SpiDevice> { | ||
| 123 | _spi: SPI, | ||
| 124 | } | ||
| 125 | |||
| 126 | impl<SPI: embedded_hal_async::spi::SpiDevice> DummySpiDeviceDriver<SPI> { | ||
| 127 | fn new(spi_dev: SPI) -> Self { | ||
| 128 | Self { _spi: spi_dev } | ||
| 129 | } | ||
| 130 | } | ||
diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs new file mode 100644 index 000000000..4a3301cfd --- /dev/null +++ b/examples/rp23/src/bin/sharing.rs | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | //! This example shows some common strategies for sharing resources between tasks. | ||
| 2 | //! | ||
| 3 | //! We demonstrate five different ways of sharing, covering different use cases: | ||
| 4 | //! - Atomics: This method is used for simple values, such as bool and u8..u32 | ||
| 5 | //! - Blocking Mutex: This is used for sharing non-async things, using Cell/RefCell for interior mutability. | ||
| 6 | //! - Async Mutex: This is used for sharing async resources, where you need to hold the lock across await points. | ||
| 7 | //! The async Mutex has interior mutability built-in, so no RefCell is needed. | ||
| 8 | //! - Cell: For sharing Copy types between tasks running on the same executor. | ||
| 9 | //! - RefCell: When you want &mut access to a value shared between tasks running on the same executor. | ||
| 10 | //! | ||
| 11 | //! More information: https://embassy.dev/book/#_sharing_peripherals_between_tasks | ||
| 12 | |||
| 13 | #![no_std] | ||
| 14 | #![no_main] | ||
| 15 | |||
| 16 | use core::cell::{Cell, RefCell}; | ||
| 17 | use core::sync::atomic::{AtomicU32, Ordering}; | ||
| 18 | |||
| 19 | use cortex_m_rt::entry; | ||
| 20 | use defmt::info; | ||
| 21 | use embassy_executor::{Executor, InterruptExecutor}; | ||
| 22 | use embassy_rp::block::ImageDef; | ||
| 23 | use embassy_rp::clocks::RoscRng; | ||
| 24 | use embassy_rp::interrupt::{InterruptExt, Priority}; | ||
| 25 | use embassy_rp::peripherals::UART0; | ||
| 26 | use embassy_rp::uart::{self, InterruptHandler, UartTx}; | ||
| 27 | use embassy_rp::{bind_interrupts, interrupt}; | ||
| 28 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 29 | use embassy_sync::{blocking_mutex, mutex}; | ||
| 30 | use embassy_time::{Duration, Ticker}; | ||
| 31 | use rand::RngCore; | ||
| 32 | use static_cell::{ConstStaticCell, StaticCell}; | ||
| 33 | use {defmt_rtt as _, panic_probe as _}; | ||
| 34 | |||
| 35 | #[link_section = ".start_block"] | ||
| 36 | #[used] | ||
| 37 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 38 | |||
| 39 | // Program metadata for `picotool info` | ||
| 40 | #[link_section = ".bi_entries"] | ||
| 41 | #[used] | ||
| 42 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 43 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 44 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 45 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 46 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 47 | ]; | ||
| 48 | |||
| 49 | type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; | ||
| 50 | |||
| 51 | struct MyType { | ||
| 52 | inner: u32, | ||
| 53 | } | ||
| 54 | |||
| 55 | static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new(); | ||
| 56 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | ||
| 57 | |||
| 58 | // Use Atomics for simple values | ||
| 59 | static ATOMIC: AtomicU32 = AtomicU32::new(0); | ||
| 60 | |||
| 61 | // Use blocking Mutex with Cell/RefCell for sharing non-async things | ||
| 62 | static MUTEX_BLOCKING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<MyType>> = | ||
| 63 | blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 })); | ||
| 64 | |||
| 65 | bind_interrupts!(struct Irqs { | ||
| 66 | UART0_IRQ => InterruptHandler<UART0>; | ||
| 67 | }); | ||
| 68 | |||
| 69 | #[interrupt] | ||
| 70 | unsafe fn SWI_IRQ_0() { | ||
| 71 | EXECUTOR_HI.on_interrupt() | ||
| 72 | } | ||
| 73 | |||
| 74 | #[entry] | ||
| 75 | fn main() -> ! { | ||
| 76 | let p = embassy_rp::init(Default::default()); | ||
| 77 | info!("Here we go!"); | ||
| 78 | |||
| 79 | let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default()); | ||
| 80 | // Use the async Mutex for sharing async things (built-in interior mutability) | ||
| 81 | static UART: StaticCell<UartAsyncMutex> = StaticCell::new(); | ||
| 82 | let uart = UART.init(mutex::Mutex::new(uart)); | ||
| 83 | |||
| 84 | // High-priority executor: runs in interrupt mode | ||
| 85 | interrupt::SWI_IRQ_0.set_priority(Priority::P3); | ||
| 86 | let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0); | ||
| 87 | spawner.must_spawn(task_a(uart)); | ||
| 88 | |||
| 89 | // Low priority executor: runs in thread mode | ||
| 90 | let executor = EXECUTOR_LOW.init(Executor::new()); | ||
| 91 | executor.run(|spawner| { | ||
| 92 | // No Mutex needed when sharing between tasks running on the same executor | ||
| 93 | |||
| 94 | // Use Cell for Copy-types | ||
| 95 | static CELL: ConstStaticCell<Cell<[u8; 4]>> = ConstStaticCell::new(Cell::new([0; 4])); | ||
| 96 | let cell = CELL.take(); | ||
| 97 | |||
| 98 | // Use RefCell for &mut access | ||
| 99 | static REF_CELL: ConstStaticCell<RefCell<MyType>> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 })); | ||
| 100 | let ref_cell = REF_CELL.take(); | ||
| 101 | |||
| 102 | spawner.must_spawn(task_b(uart, cell, ref_cell)); | ||
| 103 | spawner.must_spawn(task_c(cell, ref_cell)); | ||
| 104 | }); | ||
| 105 | } | ||
| 106 | |||
| 107 | #[embassy_executor::task] | ||
| 108 | async fn task_a(uart: &'static UartAsyncMutex) { | ||
| 109 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 110 | loop { | ||
| 111 | let random = RoscRng.next_u32(); | ||
| 112 | |||
| 113 | { | ||
| 114 | let mut uart = uart.lock().await; | ||
| 115 | uart.write(b"task a").await.unwrap(); | ||
| 116 | // The uart lock is released when it goes out of scope | ||
| 117 | } | ||
| 118 | |||
| 119 | ATOMIC.store(random, Ordering::Relaxed); | ||
| 120 | |||
| 121 | MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random); | ||
| 122 | |||
| 123 | ticker.next().await; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | #[embassy_executor::task] | ||
| 128 | async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) { | ||
| 129 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 130 | loop { | ||
| 131 | let random = RoscRng.next_u32(); | ||
| 132 | |||
| 133 | uart.lock().await.write(b"task b").await.unwrap(); | ||
| 134 | |||
| 135 | cell.set(random.to_be_bytes()); | ||
| 136 | |||
| 137 | ref_cell.borrow_mut().inner = random; | ||
| 138 | |||
| 139 | ticker.next().await; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | #[embassy_executor::task] | ||
| 144 | async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) { | ||
| 145 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 146 | loop { | ||
| 147 | info!("======================="); | ||
| 148 | |||
| 149 | let atomic_val = ATOMIC.load(Ordering::Relaxed); | ||
| 150 | info!("atomic: {}", atomic_val); | ||
| 151 | |||
| 152 | MUTEX_BLOCKING.lock(|x| { | ||
| 153 | let val = x.borrow().inner; | ||
| 154 | info!("blocking mutex: {}", val); | ||
| 155 | }); | ||
| 156 | |||
| 157 | let cell_val = cell.get(); | ||
| 158 | info!("cell: {:?}", cell_val); | ||
| 159 | |||
| 160 | let ref_cell_val = ref_cell.borrow().inner; | ||
| 161 | info!("ref_cell: {:?}", ref_cell_val); | ||
| 162 | |||
| 163 | ticker.next().await; | ||
| 164 | } | ||
| 165 | } | ||
diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs new file mode 100644 index 000000000..924873e60 --- /dev/null +++ b/examples/rp23/src/bin/spi.rs | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | //! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! Example for resistive touch sensor in Waveshare Pico-ResTouch | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::spi::Spi; | ||
| 12 | use embassy_rp::{gpio, spi}; | ||
| 13 | use gpio::{Level, Output}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[link_section = ".start_block"] | ||
| 17 | #[used] | ||
| 18 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 19 | |||
| 20 | // Program metadata for `picotool info` | ||
| 21 | #[link_section = ".bi_entries"] | ||
| 22 | #[used] | ||
| 23 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 24 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 25 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 26 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 27 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 28 | ]; | ||
| 29 | |||
| 30 | #[embassy_executor::main] | ||
| 31 | async fn main(_spawner: Spawner) { | ||
| 32 | let p = embassy_rp::init(Default::default()); | ||
| 33 | info!("Hello World!"); | ||
| 34 | |||
| 35 | // Example for resistive touch sensor in Waveshare Pico-ResTouch | ||
| 36 | |||
| 37 | let miso = p.PIN_12; | ||
| 38 | let mosi = p.PIN_11; | ||
| 39 | let clk = p.PIN_10; | ||
| 40 | let touch_cs = p.PIN_16; | ||
| 41 | |||
| 42 | // create SPI | ||
| 43 | let mut config = spi::Config::default(); | ||
| 44 | config.frequency = 2_000_000; | ||
| 45 | let mut spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, config); | ||
| 46 | |||
| 47 | // Configure CS | ||
| 48 | let mut cs = Output::new(touch_cs, Level::Low); | ||
| 49 | |||
| 50 | loop { | ||
| 51 | cs.set_low(); | ||
| 52 | let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00]; | ||
| 53 | spi.blocking_transfer_in_place(&mut buf).unwrap(); | ||
| 54 | cs.set_high(); | ||
| 55 | |||
| 56 | let x = (buf[1] as u32) << 5 | (buf[2] as u32) >> 3; | ||
| 57 | let y = (buf[4] as u32) << 5 | (buf[5] as u32) >> 3; | ||
| 58 | |||
| 59 | info!("touch: {=u32} {=u32}", x, y); | ||
| 60 | } | ||
| 61 | } | ||
diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs new file mode 100644 index 000000000..4a74f991c --- /dev/null +++ b/examples/rp23/src/bin/spi_async.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | //! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. | ||
| 2 | //! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back. | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::block::ImageDef; | ||
| 10 | use embassy_rp::spi::{Config, Spi}; | ||
| 11 | use embassy_time::Timer; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[link_section = ".start_block"] | ||
| 15 | #[used] | ||
| 16 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 17 | |||
| 18 | // Program metadata for `picotool info` | ||
| 19 | #[link_section = ".bi_entries"] | ||
| 20 | #[used] | ||
| 21 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 22 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 23 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 24 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 25 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 26 | ]; | ||
| 27 | |||
| 28 | #[embassy_executor::main] | ||
| 29 | async fn main(_spawner: Spawner) { | ||
| 30 | let p = embassy_rp::init(Default::default()); | ||
| 31 | info!("Hello World!"); | ||
| 32 | |||
| 33 | let miso = p.PIN_12; | ||
| 34 | let mosi = p.PIN_11; | ||
| 35 | let clk = p.PIN_10; | ||
| 36 | |||
| 37 | let mut spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default()); | ||
| 38 | |||
| 39 | loop { | ||
| 40 | let tx_buf = [1_u8, 2, 3, 4, 5, 6]; | ||
| 41 | let mut rx_buf = [0_u8; 6]; | ||
| 42 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 43 | info!("{:?}", rx_buf); | ||
| 44 | Timer::after_secs(1).await; | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs new file mode 100644 index 000000000..71dd84658 --- /dev/null +++ b/examples/rp23/src/bin/spi_display.rs | |||
| @@ -0,0 +1,327 @@ | |||
| 1 | //! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch | ||
| 4 | //! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8) | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use core::cell::RefCell; | ||
| 10 | |||
| 11 | use defmt::*; | ||
| 12 | use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; | ||
| 13 | use embassy_executor::Spawner; | ||
| 14 | use embassy_rp::block::ImageDef; | ||
| 15 | use embassy_rp::gpio::{Level, Output}; | ||
| 16 | use embassy_rp::spi; | ||
| 17 | use embassy_rp::spi::{Blocking, Spi}; | ||
| 18 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 19 | use embassy_sync::blocking_mutex::Mutex; | ||
| 20 | use embassy_time::Delay; | ||
| 21 | use embedded_graphics::image::{Image, ImageRawLE}; | ||
| 22 | use embedded_graphics::mono_font::ascii::FONT_10X20; | ||
| 23 | use embedded_graphics::mono_font::MonoTextStyle; | ||
| 24 | use embedded_graphics::pixelcolor::Rgb565; | ||
| 25 | use embedded_graphics::prelude::*; | ||
| 26 | use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; | ||
| 27 | use embedded_graphics::text::Text; | ||
| 28 | use st7789::{Orientation, ST7789}; | ||
| 29 | use {defmt_rtt as _, panic_probe as _}; | ||
| 30 | |||
| 31 | #[link_section = ".start_block"] | ||
| 32 | #[used] | ||
| 33 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 34 | |||
| 35 | // Program metadata for `picotool info` | ||
| 36 | #[link_section = ".bi_entries"] | ||
| 37 | #[used] | ||
| 38 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 39 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 40 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 41 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 42 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 43 | ]; | ||
| 44 | |||
| 45 | use crate::my_display_interface::SPIDeviceInterface; | ||
| 46 | use crate::touch::Touch; | ||
| 47 | |||
| 48 | const DISPLAY_FREQ: u32 = 64_000_000; | ||
| 49 | const TOUCH_FREQ: u32 = 200_000; | ||
| 50 | |||
| 51 | #[embassy_executor::main] | ||
| 52 | async fn main(_spawner: Spawner) { | ||
| 53 | let p = embassy_rp::init(Default::default()); | ||
| 54 | info!("Hello World!"); | ||
| 55 | |||
| 56 | let bl = p.PIN_13; | ||
| 57 | let rst = p.PIN_15; | ||
| 58 | let display_cs = p.PIN_9; | ||
| 59 | let dcx = p.PIN_8; | ||
| 60 | let miso = p.PIN_12; | ||
| 61 | let mosi = p.PIN_11; | ||
| 62 | let clk = p.PIN_10; | ||
| 63 | let touch_cs = p.PIN_16; | ||
| 64 | //let touch_irq = p.PIN_17; | ||
| 65 | |||
| 66 | // create SPI | ||
| 67 | let mut display_config = spi::Config::default(); | ||
| 68 | display_config.frequency = DISPLAY_FREQ; | ||
| 69 | display_config.phase = spi::Phase::CaptureOnSecondTransition; | ||
| 70 | display_config.polarity = spi::Polarity::IdleHigh; | ||
| 71 | let mut touch_config = spi::Config::default(); | ||
| 72 | touch_config.frequency = TOUCH_FREQ; | ||
| 73 | touch_config.phase = spi::Phase::CaptureOnSecondTransition; | ||
| 74 | touch_config.polarity = spi::Polarity::IdleHigh; | ||
| 75 | |||
| 76 | let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); | ||
| 77 | let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi)); | ||
| 78 | |||
| 79 | let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); | ||
| 80 | let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config); | ||
| 81 | |||
| 82 | let mut touch = Touch::new(touch_spi); | ||
| 83 | |||
| 84 | let dcx = Output::new(dcx, Level::Low); | ||
| 85 | let rst = Output::new(rst, Level::Low); | ||
| 86 | // dcx: 0 = command, 1 = data | ||
| 87 | |||
| 88 | // Enable LCD backlight | ||
| 89 | let _bl = Output::new(bl, Level::High); | ||
| 90 | |||
| 91 | // display interface abstraction from SPI and DC | ||
| 92 | let di = SPIDeviceInterface::new(display_spi, dcx); | ||
| 93 | |||
| 94 | // create driver | ||
| 95 | let mut display = ST7789::new(di, rst, 240, 320); | ||
| 96 | |||
| 97 | // initialize | ||
| 98 | display.init(&mut Delay).unwrap(); | ||
| 99 | |||
| 100 | // set default orientation | ||
| 101 | display.set_orientation(Orientation::Landscape).unwrap(); | ||
| 102 | |||
| 103 | display.clear(Rgb565::BLACK).unwrap(); | ||
| 104 | |||
| 105 | let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); | ||
| 106 | let ferris = Image::new(&raw_image_data, Point::new(34, 68)); | ||
| 107 | |||
| 108 | // Display the image | ||
| 109 | ferris.draw(&mut display).unwrap(); | ||
| 110 | |||
| 111 | let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN); | ||
| 112 | Text::new( | ||
| 113 | "Hello embedded_graphics \n + embassy + RP2040!", | ||
| 114 | Point::new(20, 200), | ||
| 115 | style, | ||
| 116 | ) | ||
| 117 | .draw(&mut display) | ||
| 118 | .unwrap(); | ||
| 119 | |||
| 120 | loop { | ||
| 121 | if let Some((x, y)) = touch.read() { | ||
| 122 | let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLUE).build(); | ||
| 123 | |||
| 124 | Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3)) | ||
| 125 | .into_styled(style) | ||
| 126 | .draw(&mut display) | ||
| 127 | .unwrap(); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | /// Driver for the XPT2046 resistive touchscreen sensor | ||
| 133 | mod touch { | ||
| 134 | use embedded_hal_1::spi::{Operation, SpiDevice}; | ||
| 135 | |||
| 136 | struct Calibration { | ||
| 137 | x1: i32, | ||
| 138 | x2: i32, | ||
| 139 | y1: i32, | ||
| 140 | y2: i32, | ||
| 141 | sx: i32, | ||
| 142 | sy: i32, | ||
| 143 | } | ||
| 144 | |||
| 145 | const CALIBRATION: Calibration = Calibration { | ||
| 146 | x1: 3880, | ||
| 147 | x2: 340, | ||
| 148 | y1: 262, | ||
| 149 | y2: 3850, | ||
| 150 | sx: 320, | ||
| 151 | sy: 240, | ||
| 152 | }; | ||
| 153 | |||
| 154 | pub struct Touch<SPI: SpiDevice> { | ||
| 155 | spi: SPI, | ||
| 156 | } | ||
| 157 | |||
| 158 | impl<SPI> Touch<SPI> | ||
| 159 | where | ||
| 160 | SPI: SpiDevice, | ||
| 161 | { | ||
| 162 | pub fn new(spi: SPI) -> Self { | ||
| 163 | Self { spi } | ||
| 164 | } | ||
| 165 | |||
| 166 | pub fn read(&mut self) -> Option<(i32, i32)> { | ||
| 167 | let mut x = [0; 2]; | ||
| 168 | let mut y = [0; 2]; | ||
| 169 | self.spi | ||
| 170 | .transaction(&mut [ | ||
| 171 | Operation::Write(&[0x90]), | ||
| 172 | Operation::Read(&mut x), | ||
| 173 | Operation::Write(&[0xd0]), | ||
| 174 | Operation::Read(&mut y), | ||
| 175 | ]) | ||
| 176 | .unwrap(); | ||
| 177 | |||
| 178 | let x = (u16::from_be_bytes(x) >> 3) as i32; | ||
| 179 | let y = (u16::from_be_bytes(y) >> 3) as i32; | ||
| 180 | |||
| 181 | let cal = &CALIBRATION; | ||
| 182 | |||
| 183 | let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx); | ||
| 184 | let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy); | ||
| 185 | if x == 0 && y == 0 { | ||
| 186 | None | ||
| 187 | } else { | ||
| 188 | Some((x, y)) | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | mod my_display_interface { | ||
| 195 | use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; | ||
| 196 | use embedded_hal_1::digital::OutputPin; | ||
| 197 | use embedded_hal_1::spi::SpiDevice; | ||
| 198 | |||
| 199 | /// SPI display interface. | ||
| 200 | /// | ||
| 201 | /// This combines the SPI peripheral and a data/command pin | ||
| 202 | pub struct SPIDeviceInterface<SPI, DC> { | ||
| 203 | spi: SPI, | ||
| 204 | dc: DC, | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<SPI, DC> SPIDeviceInterface<SPI, DC> | ||
| 208 | where | ||
| 209 | SPI: SpiDevice, | ||
| 210 | DC: OutputPin, | ||
| 211 | { | ||
| 212 | /// Create new SPI interface for communciation with a display driver | ||
| 213 | pub fn new(spi: SPI, dc: DC) -> Self { | ||
| 214 | Self { spi, dc } | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC> | ||
| 219 | where | ||
| 220 | SPI: SpiDevice, | ||
| 221 | DC: OutputPin, | ||
| 222 | { | ||
| 223 | fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { | ||
| 224 | // 1 = data, 0 = command | ||
| 225 | self.dc.set_low().map_err(|_| DisplayError::DCError)?; | ||
| 226 | |||
| 227 | send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; | ||
| 228 | Ok(()) | ||
| 229 | } | ||
| 230 | |||
| 231 | fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { | ||
| 232 | // 1 = data, 0 = command | ||
| 233 | self.dc.set_high().map_err(|_| DisplayError::DCError)?; | ||
| 234 | |||
| 235 | send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; | ||
| 236 | Ok(()) | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { | ||
| 241 | match words { | ||
| 242 | DataFormat::U8(slice) => spi.write(slice), | ||
| 243 | DataFormat::U16(slice) => { | ||
| 244 | use byte_slice_cast::*; | ||
| 245 | spi.write(slice.as_byte_slice()) | ||
| 246 | } | ||
| 247 | DataFormat::U16LE(slice) => { | ||
| 248 | use byte_slice_cast::*; | ||
| 249 | for v in slice.as_mut() { | ||
| 250 | *v = v.to_le(); | ||
| 251 | } | ||
| 252 | spi.write(slice.as_byte_slice()) | ||
| 253 | } | ||
| 254 | DataFormat::U16BE(slice) => { | ||
| 255 | use byte_slice_cast::*; | ||
| 256 | for v in slice.as_mut() { | ||
| 257 | *v = v.to_be(); | ||
| 258 | } | ||
| 259 | spi.write(slice.as_byte_slice()) | ||
| 260 | } | ||
| 261 | DataFormat::U8Iter(iter) => { | ||
| 262 | let mut buf = [0; 32]; | ||
| 263 | let mut i = 0; | ||
| 264 | |||
| 265 | for v in iter.into_iter() { | ||
| 266 | buf[i] = v; | ||
| 267 | i += 1; | ||
| 268 | |||
| 269 | if i == buf.len() { | ||
| 270 | spi.write(&buf)?; | ||
| 271 | i = 0; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | if i > 0 { | ||
| 276 | spi.write(&buf[..i])?; | ||
| 277 | } | ||
| 278 | |||
| 279 | Ok(()) | ||
| 280 | } | ||
| 281 | DataFormat::U16LEIter(iter) => { | ||
| 282 | use byte_slice_cast::*; | ||
| 283 | let mut buf = [0; 32]; | ||
| 284 | let mut i = 0; | ||
| 285 | |||
| 286 | for v in iter.map(u16::to_le) { | ||
| 287 | buf[i] = v; | ||
| 288 | i += 1; | ||
| 289 | |||
| 290 | if i == buf.len() { | ||
| 291 | spi.write(&buf.as_byte_slice())?; | ||
| 292 | i = 0; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | if i > 0 { | ||
| 297 | spi.write(&buf[..i].as_byte_slice())?; | ||
| 298 | } | ||
| 299 | |||
| 300 | Ok(()) | ||
| 301 | } | ||
| 302 | DataFormat::U16BEIter(iter) => { | ||
| 303 | use byte_slice_cast::*; | ||
| 304 | let mut buf = [0; 64]; | ||
| 305 | let mut i = 0; | ||
| 306 | let len = buf.len(); | ||
| 307 | |||
| 308 | for v in iter.map(u16::to_be) { | ||
| 309 | buf[i] = v; | ||
| 310 | i += 1; | ||
| 311 | |||
| 312 | if i == len { | ||
| 313 | spi.write(&buf.as_byte_slice())?; | ||
| 314 | i = 0; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | if i > 0 { | ||
| 319 | spi.write(&buf[..i].as_byte_slice())?; | ||
| 320 | } | ||
| 321 | |||
| 322 | Ok(()) | ||
| 323 | } | ||
| 324 | _ => unimplemented!(), | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs new file mode 100644 index 000000000..dabf41ab8 --- /dev/null +++ b/examples/rp23/src/bin/spi_sdmmc.rs | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | //! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI. | ||
| 2 | //! | ||
| 3 | //! The example will attempt to read a file `MY_FILE.TXT` from the root directory | ||
| 4 | //! of the SD card and print its contents. | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_embedded_hal::SetConfig; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_rp::block::ImageDef; | ||
| 13 | use embassy_rp::spi::Spi; | ||
| 14 | use embassy_rp::{gpio, spi}; | ||
| 15 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 16 | use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; | ||
| 17 | use gpio::{Level, Output}; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | #[link_section = ".start_block"] | ||
| 21 | #[used] | ||
| 22 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 23 | |||
| 24 | // Program metadata for `picotool info` | ||
| 25 | #[link_section = ".bi_entries"] | ||
| 26 | #[used] | ||
| 27 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 28 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 29 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 30 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 31 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 32 | ]; | ||
| 33 | |||
| 34 | struct DummyTimesource(); | ||
| 35 | |||
| 36 | impl embedded_sdmmc::TimeSource for DummyTimesource { | ||
| 37 | fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { | ||
| 38 | embedded_sdmmc::Timestamp { | ||
| 39 | year_since_1970: 0, | ||
| 40 | zero_indexed_month: 0, | ||
| 41 | zero_indexed_day: 0, | ||
| 42 | hours: 0, | ||
| 43 | minutes: 0, | ||
| 44 | seconds: 0, | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | #[embassy_executor::main] | ||
| 50 | async fn main(_spawner: Spawner) { | ||
| 51 | embassy_rp::pac::SIO.spinlock(31).write_value(1); | ||
| 52 | let p = embassy_rp::init(Default::default()); | ||
| 53 | |||
| 54 | // SPI clock needs to be running at <= 400kHz during initialization | ||
| 55 | let mut config = spi::Config::default(); | ||
| 56 | config.frequency = 400_000; | ||
| 57 | let spi = Spi::new_blocking(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, config); | ||
| 58 | // Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons | ||
| 59 | let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin); | ||
| 60 | // Real cs pin | ||
| 61 | let cs = Output::new(p.PIN_16, Level::High); | ||
| 62 | |||
| 63 | let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay); | ||
| 64 | info!("Card size is {} bytes", sdcard.num_bytes().unwrap()); | ||
| 65 | |||
| 66 | // Now that the card is initialized, the SPI clock can go faster | ||
| 67 | let mut config = spi::Config::default(); | ||
| 68 | config.frequency = 16_000_000; | ||
| 69 | sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); | ||
| 70 | |||
| 71 | // Now let's look for volumes (also known as partitions) on our block device. | ||
| 72 | // To do this we need a Volume Manager. It will take ownership of the block device. | ||
| 73 | let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, DummyTimesource()); | ||
| 74 | |||
| 75 | // Try and access Volume 0 (i.e. the first partition). | ||
| 76 | // The volume object holds information about the filesystem on that volume. | ||
| 77 | let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)).unwrap(); | ||
| 78 | info!("Volume 0: {:?}", defmt::Debug2Format(&volume0)); | ||
| 79 | |||
| 80 | // Open the root directory (mutably borrows from the volume). | ||
| 81 | let mut root_dir = volume0.open_root_dir().unwrap(); | ||
| 82 | |||
| 83 | // Open a file called "MY_FILE.TXT" in the root directory | ||
| 84 | // This mutably borrows the directory. | ||
| 85 | let mut my_file = root_dir | ||
| 86 | .open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly) | ||
| 87 | .unwrap(); | ||
| 88 | |||
| 89 | // Print the contents of the file | ||
| 90 | while !my_file.is_eof() { | ||
| 91 | let mut buf = [0u8; 32]; | ||
| 92 | if let Ok(n) = my_file.read(&mut buf) { | ||
| 93 | info!("{:a}", buf[..n]); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | loop {} | ||
| 98 | } | ||
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 @@ | |||
| 1 | //! This example shows TRNG usage | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::bind_interrupts; | ||
| 9 | use embassy_rp::block::ImageDef; | ||
| 10 | use embassy_rp::gpio::{Level, Output}; | ||
| 11 | use embassy_rp::peripherals::TRNG; | ||
| 12 | use embassy_rp::trng::Trng; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use rand::RngCore; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[link_section = ".start_block"] | ||
| 18 | #[used] | ||
| 19 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 20 | |||
| 21 | // Program metadata for `picotool info` | ||
| 22 | #[link_section = ".bi_entries"] | ||
| 23 | #[used] | ||
| 24 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 25 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 26 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 27 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 28 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 29 | ]; | ||
| 30 | |||
| 31 | bind_interrupts!(struct Irqs { | ||
| 32 | TRNG_IRQ => embassy_rp::trng::InterruptHandler<TRNG>; | ||
| 33 | }); | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(_spawner: Spawner) { | ||
| 37 | let peripherals = embassy_rp::init(Default::default()); | ||
| 38 | |||
| 39 | // Initialize the TRNG with default configuration | ||
| 40 | let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default()); | ||
| 41 | // A buffer to collect random bytes in. | ||
| 42 | let mut randomness = [0u8; 58]; | ||
| 43 | |||
| 44 | let mut led = Output::new(peripherals.PIN_25, Level::Low); | ||
| 45 | |||
| 46 | loop { | ||
| 47 | trng.fill_bytes(&mut randomness).await; | ||
| 48 | info!("Random bytes async {}", &randomness); | ||
| 49 | trng.blocking_fill_bytes(&mut randomness); | ||
| 50 | info!("Random bytes blocking {}", &randomness); | ||
| 51 | let random_u32 = trng.next_u32(); | ||
| 52 | let random_u64 = trng.next_u64(); | ||
| 53 | info!("Random u32 {} u64 {}", random_u32, random_u64); | ||
| 54 | // Random number of blinks between 0 and 31 | ||
| 55 | let blinks = random_u32 % 32; | ||
| 56 | for _ in 0..blinks { | ||
| 57 | led.set_high(); | ||
| 58 | Timer::after_millis(20).await; | ||
| 59 | led.set_low(); | ||
| 60 | Timer::after_millis(20).await; | ||
| 61 | } | ||
| 62 | Timer::after_millis(1000).await; | ||
| 63 | } | ||
| 64 | } | ||
diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs new file mode 100644 index 000000000..0ffe0b293 --- /dev/null +++ b/examples/rp23/src/bin/uart.rs | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | //! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! No specific hardware is specified in this example. Only output on pin 0 is tested. | ||
| 4 | //! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used | ||
| 5 | //! with its UART port. | ||
| 6 | |||
| 7 | #![no_std] | ||
| 8 | #![no_main] | ||
| 9 | |||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_rp::block::ImageDef; | ||
| 12 | use embassy_rp::uart; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | #[link_section = ".start_block"] | ||
| 16 | #[used] | ||
| 17 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 18 | |||
| 19 | // Program metadata for `picotool info` | ||
| 20 | #[link_section = ".bi_entries"] | ||
| 21 | #[used] | ||
| 22 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 23 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 24 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 25 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 26 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 27 | ]; | ||
| 28 | |||
| 29 | #[embassy_executor::main] | ||
| 30 | async fn main(_spawner: Spawner) { | ||
| 31 | let p = embassy_rp::init(Default::default()); | ||
| 32 | let config = uart::Config::default(); | ||
| 33 | let mut uart = uart::Uart::new_blocking(p.UART1, p.PIN_4, p.PIN_5, config); | ||
| 34 | uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap(); | ||
| 35 | |||
| 36 | loop { | ||
| 37 | uart.blocking_write("hello there!\r\n".as_bytes()).unwrap(); | ||
| 38 | cortex_m::asm::delay(1_000_000); | ||
| 39 | } | ||
| 40 | } | ||
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..4e69a20c4 --- /dev/null +++ b/examples/rp23/src/bin/uart_buffered_split.rs | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | //! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back. | ||
| 4 | //! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used | ||
| 5 | //! with its UART port. | ||
| 6 | |||
| 7 | #![no_std] | ||
| 8 | #![no_main] | ||
| 9 | |||
| 10 | use defmt::*; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_rp::bind_interrupts; | ||
| 13 | use embassy_rp::block::ImageDef; | ||
| 14 | use embassy_rp::peripherals::UART0; | ||
| 15 | use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; | ||
| 16 | use embassy_time::Timer; | ||
| 17 | use embedded_io_async::{Read, Write}; | ||
| 18 | use static_cell::StaticCell; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | #[link_section = ".start_block"] | ||
| 22 | #[used] | ||
| 23 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 24 | |||
| 25 | // Program metadata for `picotool info` | ||
| 26 | #[link_section = ".bi_entries"] | ||
| 27 | #[used] | ||
| 28 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 29 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 30 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 31 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 32 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 33 | ]; | ||
| 34 | |||
| 35 | bind_interrupts!(struct Irqs { | ||
| 36 | UART0_IRQ => BufferedInterruptHandler<UART0>; | ||
| 37 | }); | ||
| 38 | |||
| 39 | #[embassy_executor::main] | ||
| 40 | async fn main(spawner: Spawner) { | ||
| 41 | let p = embassy_rp::init(Default::default()); | ||
| 42 | let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 43 | |||
| 44 | static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); | ||
| 45 | let tx_buf = &mut TX_BUF.init([0; 16])[..]; | ||
| 46 | static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); | ||
| 47 | let rx_buf = &mut RX_BUF.init([0; 16])[..]; | ||
| 48 | let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); | ||
| 49 | let (mut tx, rx) = uart.split(); | ||
| 50 | |||
| 51 | unwrap!(spawner.spawn(reader(rx))); | ||
| 52 | |||
| 53 | info!("Writing..."); | ||
| 54 | loop { | ||
| 55 | let data = [ | ||
| 56 | 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, | ||
| 57 | 29, 30, 31, | ||
| 58 | ]; | ||
| 59 | info!("TX {:?}", data); | ||
| 60 | tx.write_all(&data).await.unwrap(); | ||
| 61 | Timer::after_secs(1).await; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | #[embassy_executor::task] | ||
| 66 | async fn reader(mut rx: BufferedUartRx<'static, UART0>) { | ||
| 67 | info!("Reading..."); | ||
| 68 | loop { | ||
| 69 | let mut buf = [0; 31]; | ||
| 70 | rx.read_exact(&mut buf).await.unwrap(); | ||
| 71 | info!("RX {:?}", buf); | ||
| 72 | } | ||
| 73 | } | ||
diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs new file mode 100644 index 000000000..5ac8839e3 --- /dev/null +++ b/examples/rp23/src/bin/uart_r503.rs | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{debug, error, info}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_rp::bind_interrupts; | ||
| 7 | use embassy_rp::block::ImageDef; | ||
| 8 | use embassy_rp::peripherals::UART0; | ||
| 9 | use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; | ||
| 10 | use embassy_time::{with_timeout, Duration, Timer}; | ||
| 11 | use heapless::Vec; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[link_section = ".start_block"] | ||
| 15 | #[used] | ||
| 16 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 17 | |||
| 18 | // Program metadata for `picotool info` | ||
| 19 | #[link_section = ".bi_entries"] | ||
| 20 | #[used] | ||
| 21 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 22 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 23 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 24 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 25 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 26 | ]; | ||
| 27 | |||
| 28 | bind_interrupts!(pub struct Irqs { | ||
| 29 | UART0_IRQ => UARTInterruptHandler<UART0>; | ||
| 30 | }); | ||
| 31 | |||
| 32 | const START: u16 = 0xEF01; | ||
| 33 | const ADDRESS: u32 = 0xFFFFFFFF; | ||
| 34 | |||
| 35 | // ================================================================================ | ||
| 36 | |||
| 37 | // Data package format | ||
| 38 | // Name Length Description | ||
| 39 | // ========================================================================================================== | ||
| 40 | // Start 2 bytes Fixed value of 0xEF01; High byte transferred first. | ||
| 41 | // Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command. | ||
| 42 | // High byte transferred first and at wrong adder value, module | ||
| 43 | // will reject to transfer. | ||
| 44 | // PID 1 byte 01H Command packet; | ||
| 45 | // 02H Data packet; Data packet shall not appear alone in executing | ||
| 46 | // processs, must follow command packet or acknowledge packet. | ||
| 47 | // 07H Acknowledge packet; | ||
| 48 | // 08H End of Data packet. | ||
| 49 | // LENGTH 2 bytes Refers to the length of package content (command packets and data packets) | ||
| 50 | // plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes. | ||
| 51 | // And high byte is transferred first. | ||
| 52 | // DATA - It can be commands, data, command’s parameters, acknowledge result, etc. | ||
| 53 | // (fingerprint character value, template are all deemed as data); | ||
| 54 | // SUM 2 bytes The arithmetic sum of package identifier, package length and all package | ||
| 55 | // contens. Overflowing bits are omitted. high byte is transferred first. | ||
| 56 | |||
| 57 | // ================================================================================ | ||
| 58 | |||
| 59 | // Checksum is calculated on 'length (2 bytes) + data (??)'. | ||
| 60 | fn compute_checksum(buf: Vec<u8, 32>) -> u16 { | ||
| 61 | let mut checksum = 0u16; | ||
| 62 | |||
| 63 | let check_end = buf.len(); | ||
| 64 | let checked_bytes = &buf[6..check_end]; | ||
| 65 | for byte in checked_bytes { | ||
| 66 | checksum += (*byte) as u16; | ||
| 67 | } | ||
| 68 | return checksum; | ||
| 69 | } | ||
| 70 | |||
| 71 | #[embassy_executor::main] | ||
| 72 | async fn main(_spawner: Spawner) { | ||
| 73 | info!("Start"); | ||
| 74 | |||
| 75 | let p = embassy_rp::init(Default::default()); | ||
| 76 | |||
| 77 | // Initialize the fingerprint scanner. | ||
| 78 | let mut config = Config::default(); | ||
| 79 | config.baudrate = 57600; | ||
| 80 | config.stop_bits = StopBits::STOP1; | ||
| 81 | config.data_bits = DataBits::DataBits8; | ||
| 82 | config.parity = Parity::ParityNone; | ||
| 83 | |||
| 84 | let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1); | ||
| 85 | let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config); | ||
| 86 | let (mut tx, mut rx) = uart.split(); | ||
| 87 | |||
| 88 | let mut vec_buf: Vec<u8, 32> = heapless::Vec::new(); | ||
| 89 | let mut data: Vec<u8, 32> = heapless::Vec::new(); | ||
| 90 | |||
| 91 | let mut speeds: Vec<u8, 3> = heapless::Vec::new(); | ||
| 92 | let _ = speeds.push(0xC8); // Slow | ||
| 93 | let _ = speeds.push(0x20); // Medium | ||
| 94 | let _ = speeds.push(0x02); // Fast | ||
| 95 | |||
| 96 | // Cycle through the three colours Red, Blue and Purple forever. | ||
| 97 | loop { | ||
| 98 | for colour in 1..=3 { | ||
| 99 | for speed in &speeds { | ||
| 100 | // Set the data first, because the length is dependent on that. | ||
| 101 | // However, we write the length bits before we do the data. | ||
| 102 | data.clear(); | ||
| 103 | let _ = data.push(0x01); // ctrl=Breathing light | ||
| 104 | let _ = data.push(*speed); | ||
| 105 | let _ = data.push(colour as u8); // colour=Red, Blue, Purple | ||
| 106 | let _ = data.push(0x00); // times=Infinite | ||
| 107 | |||
| 108 | // Clear buffers | ||
| 109 | vec_buf.clear(); | ||
| 110 | |||
| 111 | // START | ||
| 112 | let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]); | ||
| 113 | |||
| 114 | // ADDRESS | ||
| 115 | let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]); | ||
| 116 | |||
| 117 | // PID | ||
| 118 | let _ = vec_buf.extend_from_slice(&[0x01]); | ||
| 119 | |||
| 120 | // LENGTH | ||
| 121 | let len: u16 = (1 + data.len() + 2).try_into().unwrap(); | ||
| 122 | let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]); | ||
| 123 | |||
| 124 | // COMMAND | ||
| 125 | let _ = vec_buf.push(0x35); // Command: AuraLedConfig | ||
| 126 | |||
| 127 | // DATA | ||
| 128 | let _ = vec_buf.extend_from_slice(&data); | ||
| 129 | |||
| 130 | // SUM | ||
| 131 | let chk = compute_checksum(vec_buf.clone()); | ||
| 132 | let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]); | ||
| 133 | |||
| 134 | // ===== | ||
| 135 | |||
| 136 | // Send command buffer. | ||
| 137 | let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); | ||
| 138 | debug!(" write='{:?}'", data_write[..]); | ||
| 139 | match tx.write(&data_write).await { | ||
| 140 | Ok(..) => info!("Write successful."), | ||
| 141 | Err(e) => error!("Write error: {:?}", e), | ||
| 142 | } | ||
| 143 | |||
| 144 | // ===== | ||
| 145 | |||
| 146 | // Read command buffer. | ||
| 147 | let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! | ||
| 148 | let mut data_read: Vec<u8, 32> = heapless::Vec::new(); // Save buffer. | ||
| 149 | |||
| 150 | info!("Attempting read."); | ||
| 151 | loop { | ||
| 152 | // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms | ||
| 153 | // for this command. | ||
| 154 | match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await { | ||
| 155 | Ok(..) => { | ||
| 156 | // Extract and save read byte. | ||
| 157 | debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]); | ||
| 158 | let _ = data_read.push(read_buf[0]).unwrap(); | ||
| 159 | } | ||
| 160 | Err(..) => break, // TimeoutError -> Ignore. | ||
| 161 | } | ||
| 162 | } | ||
| 163 | info!("Read successful"); | ||
| 164 | debug!(" read='{:?}'", data_read[..]); | ||
| 165 | |||
| 166 | Timer::after_secs(3).await; | ||
| 167 | info!("Changing speed."); | ||
| 168 | } | ||
| 169 | |||
| 170 | info!("Changing colour."); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs new file mode 100644 index 000000000..988e44a79 --- /dev/null +++ b/examples/rp23/src/bin/uart_unidir.rs | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | //! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for | ||
| 4 | //! this to work | ||
| 5 | //! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used | ||
| 6 | //! with its UART port. | ||
| 7 | |||
| 8 | #![no_std] | ||
| 9 | #![no_main] | ||
| 10 | |||
| 11 | use defmt::*; | ||
| 12 | use embassy_executor::Spawner; | ||
| 13 | use embassy_rp::bind_interrupts; | ||
| 14 | use embassy_rp::block::ImageDef; | ||
| 15 | use embassy_rp::peripherals::UART1; | ||
| 16 | use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx}; | ||
| 17 | use embassy_time::Timer; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | #[link_section = ".start_block"] | ||
| 21 | #[used] | ||
| 22 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 23 | |||
| 24 | // Program metadata for `picotool info` | ||
| 25 | #[link_section = ".bi_entries"] | ||
| 26 | #[used] | ||
| 27 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 28 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 29 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 30 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 31 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 32 | ]; | ||
| 33 | |||
| 34 | bind_interrupts!(struct Irqs { | ||
| 35 | UART1_IRQ => InterruptHandler<UART1>; | ||
| 36 | }); | ||
| 37 | |||
| 38 | #[embassy_executor::main] | ||
| 39 | async fn main(spawner: Spawner) { | ||
| 40 | let p = embassy_rp::init(Default::default()); | ||
| 41 | |||
| 42 | let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default()); | ||
| 43 | let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default()); | ||
| 44 | |||
| 45 | unwrap!(spawner.spawn(reader(uart_rx))); | ||
| 46 | |||
| 47 | info!("Writing..."); | ||
| 48 | loop { | ||
| 49 | let data = [1u8, 2, 3, 4, 5, 6, 7, 8]; | ||
| 50 | info!("TX {:?}", data); | ||
| 51 | uart_tx.write(&data).await.unwrap(); | ||
| 52 | Timer::after_secs(1).await; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | #[embassy_executor::task] | ||
| 57 | async fn reader(mut rx: UartRx<'static, UART1, Async>) { | ||
| 58 | info!("Reading..."); | ||
| 59 | loop { | ||
| 60 | // read a total of 4 transmissions (32 / 8) and then print the result | ||
| 61 | let mut buf = [0; 32]; | ||
| 62 | rx.read(&mut buf).await.unwrap(); | ||
| 63 | info!("RX {:?}", buf); | ||
| 64 | } | ||
| 65 | } | ||
diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs new file mode 100644 index 000000000..3ade2226b --- /dev/null +++ b/examples/rp23/src/bin/usb_webusb.rs | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | //! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! This creates a WebUSB capable device that echoes data back to the host. | ||
| 4 | //! | ||
| 5 | //! To test this in the browser (ideally host this on localhost:8080, to test the landing page | ||
| 6 | //! feature): | ||
| 7 | //! ```js | ||
| 8 | //! (async () => { | ||
| 9 | //! const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0xf569 }] }); | ||
| 10 | //! await device.open(); | ||
| 11 | //! await device.claimInterface(1); | ||
| 12 | //! device.transferIn(1, 64).then(data => console.log(data)); | ||
| 13 | //! await device.transferOut(1, new Uint8Array([1,2,3])); | ||
| 14 | //! })(); | ||
| 15 | //! ``` | ||
| 16 | |||
| 17 | #![no_std] | ||
| 18 | #![no_main] | ||
| 19 | |||
| 20 | use defmt::info; | ||
| 21 | use embassy_executor::Spawner; | ||
| 22 | use embassy_futures::join::join; | ||
| 23 | use embassy_rp::bind_interrupts; | ||
| 24 | use embassy_rp::block::ImageDef; | ||
| 25 | use embassy_rp::peripherals::USB; | ||
| 26 | use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; | ||
| 27 | use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; | ||
| 28 | use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; | ||
| 29 | use embassy_usb::msos::{self, windows_version}; | ||
| 30 | use embassy_usb::{Builder, Config}; | ||
| 31 | use {defmt_rtt as _, panic_probe as _}; | ||
| 32 | |||
| 33 | #[link_section = ".start_block"] | ||
| 34 | #[used] | ||
| 35 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 36 | |||
| 37 | // Program metadata for `picotool info` | ||
| 38 | #[link_section = ".bi_entries"] | ||
| 39 | #[used] | ||
| 40 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 41 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 42 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 43 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 44 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 45 | ]; | ||
| 46 | |||
| 47 | bind_interrupts!(struct Irqs { | ||
| 48 | USBCTRL_IRQ => InterruptHandler<USB>; | ||
| 49 | }); | ||
| 50 | |||
| 51 | // This is a randomly generated GUID to allow clients on Windows to find our device | ||
| 52 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"]; | ||
| 53 | |||
| 54 | #[embassy_executor::main] | ||
| 55 | async fn main(_spawner: Spawner) { | ||
| 56 | let p = embassy_rp::init(Default::default()); | ||
| 57 | |||
| 58 | // Create the driver, from the HAL. | ||
| 59 | let driver = UsbDriver::new(p.USB, Irqs); | ||
| 60 | |||
| 61 | // Create embassy-usb Config | ||
| 62 | let mut config = Config::new(0xf569, 0x0001); | ||
| 63 | config.manufacturer = Some("Embassy"); | ||
| 64 | config.product = Some("WebUSB example"); | ||
| 65 | config.serial_number = Some("12345678"); | ||
| 66 | config.max_power = 100; | ||
| 67 | config.max_packet_size_0 = 64; | ||
| 68 | |||
| 69 | // Required for windows compatibility. | ||
| 70 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 71 | config.device_class = 0xff; | ||
| 72 | config.device_sub_class = 0x00; | ||
| 73 | config.device_protocol = 0x00; | ||
| 74 | |||
| 75 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 76 | // It needs some buffers for building the descriptors. | ||
| 77 | let mut config_descriptor = [0; 256]; | ||
| 78 | let mut bos_descriptor = [0; 256]; | ||
| 79 | let mut control_buf = [0; 64]; | ||
| 80 | let mut msos_descriptor = [0; 256]; | ||
| 81 | |||
| 82 | let webusb_config = WebUsbConfig { | ||
| 83 | max_packet_size: 64, | ||
| 84 | vendor_code: 1, | ||
| 85 | // 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. | ||
| 86 | landing_url: Some(Url::new("http://localhost:8080")), | ||
| 87 | }; | ||
| 88 | |||
| 89 | let mut state = State::new(); | ||
| 90 | |||
| 91 | let mut builder = Builder::new( | ||
| 92 | driver, | ||
| 93 | config, | ||
| 94 | &mut config_descriptor, | ||
| 95 | &mut bos_descriptor, | ||
| 96 | &mut msos_descriptor, | ||
| 97 | &mut control_buf, | ||
| 98 | ); | ||
| 99 | |||
| 100 | // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor. | ||
| 101 | // We tell Windows that this entire device is compatible with the "WINUSB" feature, | ||
| 102 | // which causes it to use the built-in WinUSB driver automatically, which in turn | ||
| 103 | // can be used by libusb/rusb software without needing a custom driver or INF file. | ||
| 104 | // In principle you might want to call msos_feature() just on a specific function, | ||
| 105 | // if your device also has other functions that still use standard class drivers. | ||
| 106 | builder.msos_descriptor(windows_version::WIN8_1, 0); | ||
| 107 | builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); | ||
| 108 | builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( | ||
| 109 | "DeviceInterfaceGUIDs", | ||
| 110 | msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), | ||
| 111 | )); | ||
| 112 | |||
| 113 | // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything) | ||
| 114 | WebUsb::configure(&mut builder, &mut state, &webusb_config); | ||
| 115 | // Create some USB bulk endpoints for testing. | ||
| 116 | let mut endpoints = WebEndpoints::new(&mut builder, &webusb_config); | ||
| 117 | |||
| 118 | // Build the builder. | ||
| 119 | let mut usb = builder.build(); | ||
| 120 | |||
| 121 | // Run the USB device. | ||
| 122 | let usb_fut = usb.run(); | ||
| 123 | |||
| 124 | // Do some WebUSB transfers. | ||
| 125 | let webusb_fut = async { | ||
| 126 | loop { | ||
| 127 | endpoints.wait_connected().await; | ||
| 128 | info!("Connected"); | ||
| 129 | endpoints.echo().await; | ||
| 130 | } | ||
| 131 | }; | ||
| 132 | |||
| 133 | // Run everything concurrently. | ||
| 134 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 135 | join(usb_fut, webusb_fut).await; | ||
| 136 | } | ||
| 137 | |||
| 138 | struct WebEndpoints<'d, D: Driver<'d>> { | ||
| 139 | write_ep: D::EndpointIn, | ||
| 140 | read_ep: D::EndpointOut, | ||
| 141 | } | ||
| 142 | |||
| 143 | impl<'d, D: Driver<'d>> WebEndpoints<'d, D> { | ||
| 144 | fn new(builder: &mut Builder<'d, D>, config: &'d WebUsbConfig<'d>) -> Self { | ||
| 145 | let mut func = builder.function(0xff, 0x00, 0x00); | ||
| 146 | let mut iface = func.interface(); | ||
| 147 | let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None); | ||
| 148 | |||
| 149 | let write_ep = alt.endpoint_bulk_in(config.max_packet_size); | ||
| 150 | let read_ep = alt.endpoint_bulk_out(config.max_packet_size); | ||
| 151 | |||
| 152 | WebEndpoints { write_ep, read_ep } | ||
| 153 | } | ||
| 154 | |||
| 155 | // Wait until the device's endpoints are enabled. | ||
| 156 | async fn wait_connected(&mut self) { | ||
| 157 | self.read_ep.wait_enabled().await | ||
| 158 | } | ||
| 159 | |||
| 160 | // Echo data back to the host. | ||
| 161 | async fn echo(&mut self) { | ||
| 162 | let mut buf = [0; 64]; | ||
| 163 | loop { | ||
| 164 | let n = self.read_ep.read(&mut buf).await.unwrap(); | ||
| 165 | let data = &buf[..n]; | ||
| 166 | info!("Data read: {:x}", data); | ||
| 167 | self.write_ep.write(data).await.unwrap(); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs new file mode 100644 index 000000000..a901c1164 --- /dev/null +++ b/examples/rp23/src/bin/watchdog.rs | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | //! This example shows how to use Watchdog in the RP2040 chip. | ||
| 2 | //! | ||
| 3 | //! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::info; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::block::ImageDef; | ||
| 11 | use embassy_rp::gpio; | ||
| 12 | use embassy_rp::watchdog::*; | ||
| 13 | use embassy_time::{Duration, Timer}; | ||
| 14 | use gpio::{Level, Output}; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[link_section = ".start_block"] | ||
| 18 | #[used] | ||
| 19 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 20 | |||
| 21 | // Program metadata for `picotool info` | ||
| 22 | #[link_section = ".bi_entries"] | ||
| 23 | #[used] | ||
| 24 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 25 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 26 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 27 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 28 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 29 | ]; | ||
| 30 | |||
| 31 | #[embassy_executor::main] | ||
| 32 | async fn main(_spawner: Spawner) { | ||
| 33 | let p = embassy_rp::init(Default::default()); | ||
| 34 | info!("Hello world!"); | ||
| 35 | |||
| 36 | let mut watchdog = Watchdog::new(p.WATCHDOG); | ||
| 37 | let mut led = Output::new(p.PIN_25, Level::Low); | ||
| 38 | |||
| 39 | // Set the LED high for 2 seconds so we know when we're about to start the watchdog | ||
| 40 | led.set_high(); | ||
| 41 | Timer::after_secs(2).await; | ||
| 42 | |||
| 43 | // Set to watchdog to reset if it's not fed within 1.05 seconds, and start it | ||
| 44 | watchdog.start(Duration::from_millis(1_050)); | ||
| 45 | info!("Started the watchdog timer"); | ||
| 46 | |||
| 47 | // Blink once a second for 5 seconds, feed the watchdog timer once a second to avoid a reset | ||
| 48 | for _ in 1..=5 { | ||
| 49 | led.set_low(); | ||
| 50 | Timer::after_millis(500).await; | ||
| 51 | led.set_high(); | ||
| 52 | Timer::after_millis(500).await; | ||
| 53 | info!("Feeding watchdog"); | ||
| 54 | watchdog.feed(); | ||
| 55 | } | ||
| 56 | |||
| 57 | info!("Stopped feeding, device will reset in 1.05 seconds"); | ||
| 58 | // Blink 10 times per second, not feeding the watchdog. | ||
| 59 | // The processor should reset in 1.05 seconds. | ||
| 60 | loop { | ||
| 61 | led.set_low(); | ||
| 62 | Timer::after_millis(100).await; | ||
| 63 | led.set_high(); | ||
| 64 | Timer::after_millis(100).await; | ||
| 65 | } | ||
| 66 | } | ||
diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs new file mode 100644 index 000000000..86fca6f12 --- /dev/null +++ b/examples/rp23/src/bin/zerocopy.rs | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | //! This example shows how to use `zerocopy_channel` from `embassy_sync` for | ||
| 2 | //! sending large values between two tasks without copying. | ||
| 3 | //! The example also shows how to use the RP2040 ADC with DMA. | ||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use core::sync::atomic::{AtomicU16, Ordering}; | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; | ||
| 12 | use embassy_rp::bind_interrupts; | ||
| 13 | use embassy_rp::block::ImageDef; | ||
| 14 | use embassy_rp::gpio::Pull; | ||
| 15 | use embassy_rp::peripherals::DMA_CH0; | ||
| 16 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 17 | use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; | ||
| 18 | use embassy_time::{Duration, Ticker, Timer}; | ||
| 19 | use static_cell::StaticCell; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | #[link_section = ".start_block"] | ||
| 23 | #[used] | ||
| 24 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 25 | |||
| 26 | // Program metadata for `picotool info` | ||
| 27 | #[link_section = ".bi_entries"] | ||
| 28 | #[used] | ||
| 29 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 30 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 31 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 32 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 33 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 34 | ]; | ||
| 35 | |||
| 36 | type SampleBuffer = [u16; 512]; | ||
| 37 | |||
| 38 | bind_interrupts!(struct Irqs { | ||
| 39 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 40 | }); | ||
| 41 | |||
| 42 | const BLOCK_SIZE: usize = 512; | ||
| 43 | const NUM_BLOCKS: usize = 2; | ||
| 44 | static MAX: AtomicU16 = AtomicU16::new(0); | ||
| 45 | |||
| 46 | struct AdcParts { | ||
| 47 | adc: Adc<'static, Async>, | ||
| 48 | pin: adc::Channel<'static>, | ||
| 49 | dma: DMA_CH0, | ||
| 50 | } | ||
| 51 | |||
| 52 | #[embassy_executor::main] | ||
| 53 | async fn main(spawner: Spawner) { | ||
| 54 | let p = embassy_rp::init(Default::default()); | ||
| 55 | info!("Here we go!"); | ||
| 56 | |||
| 57 | let adc_parts = AdcParts { | ||
| 58 | adc: Adc::new(p.ADC, Irqs, Config::default()), | ||
| 59 | pin: adc::Channel::new_pin(p.PIN_29, Pull::None), | ||
| 60 | dma: p.DMA_CH0, | ||
| 61 | }; | ||
| 62 | |||
| 63 | static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new(); | ||
| 64 | let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]); | ||
| 65 | |||
| 66 | static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new(); | ||
| 67 | let channel = CHANNEL.init(Channel::new(buf)); | ||
| 68 | let (sender, receiver) = channel.split(); | ||
| 69 | |||
| 70 | spawner.must_spawn(consumer(receiver)); | ||
| 71 | spawner.must_spawn(producer(sender, adc_parts)); | ||
| 72 | |||
| 73 | let mut ticker = Ticker::every(Duration::from_secs(1)); | ||
| 74 | loop { | ||
| 75 | ticker.next().await; | ||
| 76 | let max = MAX.load(Ordering::Relaxed); | ||
| 77 | info!("latest block's max value: {:?}", max); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | #[embassy_executor::task] | ||
| 82 | async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) { | ||
| 83 | loop { | ||
| 84 | // Obtain a free buffer from the channel | ||
| 85 | let buf = sender.send().await; | ||
| 86 | |||
| 87 | // Fill it with data | ||
| 88 | adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); | ||
| 89 | |||
| 90 | // Notify the channel that the buffer is now ready to be received | ||
| 91 | sender.send_done(); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | #[embassy_executor::task] | ||
| 96 | async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) { | ||
| 97 | loop { | ||
| 98 | // Receive a buffer from the channel | ||
| 99 | let buf = receiver.receive().await; | ||
| 100 | |||
| 101 | // Simulate using the data, while the producer is filling up the next buffer | ||
| 102 | Timer::after_micros(1000).await; | ||
| 103 | let max = buf.iter().max().unwrap(); | ||
| 104 | MAX.store(*max, Ordering::Relaxed); | ||
| 105 | |||
| 106 | // Notify the channel that the buffer is now ready to be reused | ||
| 107 | receiver.receive_done(); | ||
| 108 | } | ||
| 109 | } | ||
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index f05565e84..87491b1d2 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml | |||
| @@ -5,9 +5,9 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } | 8 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "std", ] } | 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } |
| 11 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } | 11 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } |
| 12 | embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } | 12 | embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } |
| 13 | embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} | 13 | embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} |
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index dad93d0a1..cefa5448c 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs | |||
| @@ -1,9 +1,7 @@ | |||
| 1 | use std::default::Default; | ||
| 2 | |||
| 3 | use clap::Parser; | 1 | use clap::Parser; |
| 4 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 5 | use embassy_net::tcp::TcpSocket; | 3 | use embassy_net::tcp::TcpSocket; |
| 6 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 7 | use embassy_net_tuntap::TunTapDevice; | 5 | use embassy_net_tuntap::TunTapDevice; |
| 8 | use embassy_time::Duration; | 6 | use embassy_time::Duration; |
| 9 | use embedded_io_async::Write; | 7 | use embedded_io_async::Write; |
| @@ -24,8 +22,8 @@ struct Opts { | |||
| 24 | } | 22 | } |
| 25 | 23 | ||
| 26 | #[embassy_executor::task] | 24 | #[embassy_executor::task] |
| 27 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 25 | async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { |
| 28 | stack.run().await | 26 | runner.run().await |
| 29 | } | 27 | } |
| 30 | 28 | ||
| 31 | #[embassy_executor::task] | 29 | #[embassy_executor::task] |
| @@ -52,17 +50,11 @@ async fn main_task(spawner: Spawner) { | |||
| 52 | let seed = u64::from_le_bytes(seed); | 50 | let seed = u64::from_le_bytes(seed); |
| 53 | 51 | ||
| 54 | // Init network stack | 52 | // Init network stack |
| 55 | static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); | ||
| 56 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 53 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 57 | let stack = &*STACK.init(Stack::new( | 54 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 58 | device, | ||
| 59 | config, | ||
| 60 | RESOURCES.init(StackResources::<3>::new()), | ||
| 61 | seed, | ||
| 62 | )); | ||
| 63 | 55 | ||
| 64 | // Launch network task | 56 | // Launch network task |
| 65 | spawner.spawn(net_task(stack)).unwrap(); | 57 | spawner.spawn(net_task(runner)).unwrap(); |
| 66 | 58 | ||
| 67 | // Then we can use it! | 59 | // Then we can use it! |
| 68 | let mut rx_buffer = [0; 4096]; | 60 | 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 fca1e076e..a42c5dbb7 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs | |||
| @@ -1,9 +1,7 @@ | |||
| 1 | use std::default::Default; | ||
| 2 | |||
| 3 | use clap::Parser; | 1 | use clap::Parser; |
| 4 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 5 | use embassy_net::dns::DnsQueryType; | 3 | use embassy_net::dns::DnsQueryType; |
| 6 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 7 | use embassy_net_tuntap::TunTapDevice; | 5 | use embassy_net_tuntap::TunTapDevice; |
| 8 | use heapless::Vec; | 6 | use heapless::Vec; |
| 9 | use log::*; | 7 | use log::*; |
| @@ -22,8 +20,8 @@ struct Opts { | |||
| 22 | } | 20 | } |
| 23 | 21 | ||
| 24 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 25 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 23 | async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { |
| 26 | stack.run().await | 24 | runner.run().await |
| 27 | } | 25 | } |
| 28 | 26 | ||
| 29 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| @@ -51,17 +49,11 @@ async fn main_task(spawner: Spawner) { | |||
| 51 | let seed = u64::from_le_bytes(seed); | 49 | let seed = u64::from_le_bytes(seed); |
| 52 | 50 | ||
| 53 | // Init network stack | 51 | // Init network stack |
| 54 | static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); | ||
| 55 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 52 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 56 | let stack: &Stack<_> = &*STACK.init(Stack::new( | 53 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 57 | device, | ||
| 58 | config, | ||
| 59 | RESOURCES.init(StackResources::<3>::new()), | ||
| 60 | seed, | ||
| 61 | )); | ||
| 62 | 54 | ||
| 63 | // Launch network task | 55 | // Launch network task |
| 64 | spawner.spawn(net_task(stack)).unwrap(); | 56 | spawner.spawn(net_task(runner)).unwrap(); |
| 65 | 57 | ||
| 66 | let host = "example.com"; | 58 | let host = "example.com"; |
| 67 | info!("querying host {:?}...", host); | 59 | info!("querying host {:?}...", host); |
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index 9ec0ea91f..7d0f1327f 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs | |||
| @@ -37,16 +37,12 @@ struct Opts { | |||
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | #[embassy_executor::task] | 39 | #[embassy_executor::task] |
| 40 | async fn net_task(stack: &'static Stack<embassy_net_ppp::Device<'static>>) -> ! { | 40 | async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_ppp::Device<'static>>) -> ! { |
| 41 | stack.run().await | 41 | runner.run().await |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | #[embassy_executor::task] | 44 | #[embassy_executor::task] |
| 45 | async fn ppp_task( | 45 | async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: SerialPort) -> ! { |
| 46 | stack: &'static Stack<embassy_net_ppp::Device<'static>>, | ||
| 47 | mut runner: Runner<'static>, | ||
| 48 | port: SerialPort, | ||
| 49 | ) -> ! { | ||
| 50 | let port = Async::new(port).unwrap(); | 46 | let port = Async::new(port).unwrap(); |
| 51 | let port = BufReader::new(port); | 47 | let port = BufReader::new(port); |
| 52 | let port = adapter::FromFutures::new(port); | 48 | let port = adapter::FromFutures::new(port); |
| @@ -97,17 +93,16 @@ async fn main_task(spawner: Spawner) { | |||
| 97 | let seed = u64::from_le_bytes(seed); | 93 | let seed = u64::from_le_bytes(seed); |
| 98 | 94 | ||
| 99 | // Init network stack | 95 | // Init network stack |
| 100 | static STACK: StaticCell<Stack<embassy_net_ppp::Device<'static>>> = StaticCell::new(); | ||
| 101 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 96 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 102 | let stack = &*STACK.init(Stack::new( | 97 | let (stack, net_runner) = embassy_net::new( |
| 103 | device, | 98 | device, |
| 104 | Config::default(), // don't configure IP yet | 99 | Config::default(), // don't configure IP yet |
| 105 | RESOURCES.init(StackResources::<3>::new()), | 100 | RESOURCES.init(StackResources::new()), |
| 106 | seed, | 101 | seed, |
| 107 | )); | 102 | ); |
| 108 | 103 | ||
| 109 | // Launch network task | 104 | // Launch network task |
| 110 | spawner.spawn(net_task(stack)).unwrap(); | 105 | spawner.spawn(net_task(net_runner)).unwrap(); |
| 111 | spawner.spawn(ppp_task(stack, runner, port)).unwrap(); | 106 | spawner.spawn(ppp_task(stack, runner, port)).unwrap(); |
| 112 | 107 | ||
| 113 | // Then we can use it! | 108 | // Then we can use it! |
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index bee91990d..02d4d3efb 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | use clap::Parser; | 1 | use clap::Parser; |
| 2 | use embassy_executor::{Executor, Spawner}; | 2 | use embassy_executor::{Executor, Spawner}; |
| 3 | use embassy_net::udp::{PacketMetadata, UdpSocket}; | 3 | use embassy_net::udp::{PacketMetadata, UdpSocket}; |
| 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 4 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 5 | use embassy_net_tuntap::TunTapDevice; | 5 | use embassy_net_tuntap::TunTapDevice; |
| 6 | use heapless::Vec; | 6 | use heapless::Vec; |
| 7 | use log::*; | 7 | use log::*; |
| @@ -20,8 +20,8 @@ struct Opts { | |||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 23 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 23 | async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { |
| 24 | stack.run().await | 24 | runner.run().await |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| @@ -48,17 +48,11 @@ async fn main_task(spawner: Spawner) { | |||
| 48 | let seed = u64::from_le_bytes(seed); | 48 | let seed = u64::from_le_bytes(seed); |
| 49 | 49 | ||
| 50 | // Init network stack | 50 | // Init network stack |
| 51 | static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); | ||
| 52 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 51 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 53 | let stack = &*STACK.init(Stack::new( | 52 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 54 | device, | ||
| 55 | config, | ||
| 56 | RESOURCES.init(StackResources::<3>::new()), | ||
| 57 | seed, | ||
| 58 | )); | ||
| 59 | 53 | ||
| 60 | // Launch network task | 54 | // Launch network task |
| 61 | spawner.spawn(net_task(stack)).unwrap(); | 55 | spawner.spawn(net_task(runner)).unwrap(); |
| 62 | 56 | ||
| 63 | // Then we can use it! | 57 | // Then we can use it! |
| 64 | let mut rx_meta = [PacketMetadata::EMPTY; 16]; | 58 | 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 00ccd83a7..5d36b739d 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | use core::fmt::Write as _; | 1 | use core::fmt::Write as _; |
| 2 | use std::default::Default; | ||
| 3 | 2 | ||
| 4 | use clap::Parser; | 3 | use clap::Parser; |
| 5 | use embassy_executor::{Executor, Spawner}; | 4 | use embassy_executor::{Executor, Spawner}; |
| 6 | use embassy_net::tcp::TcpSocket; | 5 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | 6 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; |
| 8 | use embassy_net_tuntap::TunTapDevice; | 7 | use embassy_net_tuntap::TunTapDevice; |
| 9 | use embassy_time::{Duration, Timer}; | 8 | use embassy_time::{Duration, Timer}; |
| 10 | use embedded_io_async::Write as _; | 9 | use embedded_io_async::Write as _; |
| @@ -25,8 +24,8 @@ struct Opts { | |||
| 25 | } | 24 | } |
| 26 | 25 | ||
| 27 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | 27 | async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { |
| 29 | stack.run().await | 28 | runner.run().await |
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | #[derive(Default)] | 31 | #[derive(Default)] |
| @@ -63,17 +62,11 @@ async fn main_task(spawner: Spawner) { | |||
| 63 | let seed = u64::from_le_bytes(seed); | 62 | let seed = u64::from_le_bytes(seed); |
| 64 | 63 | ||
| 65 | // Init network stack | 64 | // Init network stack |
| 66 | static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); | ||
| 67 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 65 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 68 | let stack = &*STACK.init(Stack::new( | 66 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 69 | device, | ||
| 70 | config, | ||
| 71 | RESOURCES.init(StackResources::<3>::new()), | ||
| 72 | seed, | ||
| 73 | )); | ||
| 74 | 67 | ||
| 75 | // Launch network task | 68 | // Launch network task |
| 76 | spawner.spawn(net_task(stack)).unwrap(); | 69 | spawner.spawn(net_task(runner)).unwrap(); |
| 77 | 70 | ||
| 78 | // Then we can use it! | 71 | // Then we can use it! |
| 79 | let mut rx_buffer = [0; 4096]; | 72 | let mut rx_buffer = [0; 4096]; |
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 7a3e03b75..9102467eb 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml | |||
| @@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32c031c6 to your chip name, if necessary. | 8 | # Change stm32c031c6 to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "0.3" |
| 15 | defmt-rtt = "0.4" | 15 | defmt-rtt = "0.4" |
| @@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | |||
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 21 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 22 | heapless = { version = "0.8", default-features = false } | 21 | heapless = { version = "0.8", default-features = false } |
| 23 | 22 | ||
| 24 | [profile.release] | 23 | [profile.release] |
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index c74980dc4..724efdaff 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml | |||
| @@ -4,8 +4,6 @@ version = "0.1.0" | |||
| 4 | edition = "2021" | 4 | edition = "2021" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
| 8 | |||
| 9 | [dependencies] | 7 | [dependencies] |
| 10 | # Change stm32f091rc to your chip name, if necessary. | 8 | # Change stm32f091rc to your chip name, if necessary. |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } |
| @@ -14,9 +12,9 @@ cortex-m-rt = "0.7.0" | |||
| 14 | defmt = "0.3" | 12 | defmt = "0.3" |
| 15 | defmt-rtt = "0.4" | 13 | defmt-rtt = "0.4" |
| 16 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 14 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 17 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 15 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 18 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 16 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 19 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 17 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 20 | static_cell = "2" | 18 | static_cell = "2" |
| 21 | portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } | 19 | portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } |
| 22 | 20 | ||
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 8fef062b3..8825e2687 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs | |||
| @@ -4,13 +4,13 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | 6 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 7 | use embassy_stm32::peripherals::ADC; | 7 | use embassy_stm32::peripherals::ADC1; |
| 8 | use embassy_stm32::{adc, bind_interrupts}; | 8 | use embassy_stm32::{adc, bind_interrupts}; |
| 9 | use embassy_time::{Delay, Timer}; | 9 | use embassy_time::Timer; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | 12 | bind_interrupts!(struct Irqs { |
| 13 | ADC1_COMP => adc::InterruptHandler<ADC>; | 13 | ADC1_COMP => adc::InterruptHandler<ADC1>; |
| 14 | }); | 14 | }); |
| 15 | 15 | ||
| 16 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| @@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) { | |||
| 18 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(Default::default()); |
| 19 | info!("Hello World!"); | 19 | info!("Hello World!"); |
| 20 | 20 | ||
| 21 | let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); | 21 | let mut adc = Adc::new(p.ADC1, Irqs); |
| 22 | adc.set_sample_time(SampleTime::Cycles71_5); | 22 | adc.set_sample_time(SampleTime::CYCLES71_5); |
| 23 | let mut pin = p.PA1; | 23 | let mut pin = p.PA1; |
| 24 | 24 | ||
| 25 | let mut vrefint = adc.enable_vref(&mut Delay); | 25 | let mut vrefint = adc.enable_vref(); |
| 26 | let vrefint_sample = adc.read(&mut vrefint).await; | 26 | let vrefint_sample = adc.read(&mut vrefint).await; |
| 27 | let convert_to_millivolts = |sample| { | 27 | let convert_to_millivolts = |sample| { |
| 28 | // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf | 28 | // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf |
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs index e49951726..84e4077ef 100644 --- a/examples/stm32f0/src/bin/multiprio.rs +++ b/examples/stm32f0/src/bin/multiprio.rs | |||
| @@ -80,7 +80,7 @@ async fn run_med() { | |||
| 80 | info!(" [med] Starting long computation"); | 80 | info!(" [med] Starting long computation"); |
| 81 | 81 | ||
| 82 | // Spin-wait to simulate a long CPU computation | 82 | // Spin-wait to simulate a long CPU computation |
| 83 | cortex_m::asm::delay(8_000_000); // ~1 second | 83 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second |
| 84 | 84 | ||
| 85 | let end = Instant::now(); | 85 | let end = Instant::now(); |
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | 86 | let ms = end.duration_since(start).as_ticks() / 33; |
| @@ -97,7 +97,7 @@ async fn run_low() { | |||
| 97 | info!("[low] Starting long computation"); | 97 | info!("[low] Starting long computation"); |
| 98 | 98 | ||
| 99 | // Spin-wait to simulate a long CPU computation | 99 | // Spin-wait to simulate a long CPU computation |
| 100 | cortex_m::asm::delay(16_000_000); // ~2 seconds | 100 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds |
| 101 | 101 | ||
| 102 | let end = Instant::now(); | 102 | let end = Instant::now(); |
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | 103 | let ms = end.duration_since(start).as_ticks() / 33; |
| @@ -126,6 +126,11 @@ fn main() -> ! { | |||
| 126 | // Initialize and create handle for devicer peripherals | 126 | // Initialize and create handle for devicer peripherals |
| 127 | let _p = embassy_stm32::init(Default::default()); | 127 | let _p = embassy_stm32::init(Default::default()); |
| 128 | 128 | ||
| 129 | // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as | ||
| 130 | // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. | ||
| 131 | // In this case we’re using UART1 and UART2, but there’s nothing special about them. Any otherwise unused interrupt | ||
| 132 | // vector would work exactly the same. | ||
| 133 | |||
| 129 | // High-priority executor: USART1, priority level 6 | 134 | // High-priority executor: USART1, priority level 6 |
| 130 | interrupt::USART1.set_priority(Priority::P6); | 135 | interrupt::USART1.set_priority(Priority::P6); |
| 131 | let spawner = EXECUTOR_HIGH.start(interrupt::USART1); | 136 | let spawner = EXECUTOR_HIGH.start(interrupt::USART1); |
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index df5d32f70..0084651a3 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml | |||
| @@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32f103c8 to your chip name, if necessary. | 8 | # Change stm32f103c8 to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 15 | 15 | ||
| 16 | defmt = "0.3" | 16 | defmt = "0.3" |
| @@ -20,9 +20,9 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 24 | heapless = { version = "0.8", default-features = false } | 23 | heapless = { version = "0.8", default-features = false } |
| 25 | nb = "1.0.0" | 24 | nb = "1.0.0" |
| 25 | static_cell = "2.0.0" | ||
| 26 | 26 | ||
| 27 | [profile.dev] | 27 | [profile.dev] |
| 28 | opt-level = "s" | 28 | opt-level = "s" |
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index 1440460a9..541ff159e 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs | |||
| @@ -6,7 +6,7 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::adc::Adc; | 6 | use embassy_stm32::adc::Adc; |
| 7 | use embassy_stm32::peripherals::ADC1; | 7 | use embassy_stm32::peripherals::ADC1; |
| 8 | use embassy_stm32::{adc, bind_interrupts}; | 8 | use embassy_stm32::{adc, bind_interrupts}; |
| 9 | use embassy_time::{Delay, Timer}; | 9 | use embassy_time::Timer; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | 12 | bind_interrupts!(struct Irqs { |
| @@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) { | |||
| 18 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(Default::default()); |
| 19 | info!("Hello World!"); | 19 | info!("Hello World!"); |
| 20 | 20 | ||
| 21 | let mut adc = Adc::new(p.ADC1, &mut Delay); | 21 | let mut adc = Adc::new(p.ADC1); |
| 22 | let mut pin = p.PB1; | 22 | let mut pin = p.PB1; |
| 23 | 23 | ||
| 24 | let mut vrefint = adc.enable_vref(&mut Delay); | 24 | let mut vrefint = adc.enable_vref(); |
| 25 | let vrefint_sample = adc.read(&mut vrefint).await; | 25 | let vrefint_sample = adc.read(&mut vrefint).await; |
| 26 | let convert_to_millivolts = |sample| { | 26 | let convert_to_millivolts = |sample| { |
| 27 | // From http://www.st.com/resource/en/datasheet/CD00161566.pdf | 27 | // From http://www.st.com/resource/en/datasheet/CD00161566.pdf |
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index c1c4f8359..ad0c8a5a5 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs | |||
| @@ -3,11 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::can::bxcan::filter::Mask32; | 6 | use embassy_stm32::can::frame::Envelope; |
| 7 | use embassy_stm32::can::bxcan::{Fifo, Frame, Id, StandardId}; | 7 | use embassy_stm32::can::{ |
| 8 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; | 8 | filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, |
| 9 | TxInterruptHandler, | ||
| 10 | }; | ||
| 9 | use embassy_stm32::peripherals::CAN; | 11 | use embassy_stm32::peripherals::CAN; |
| 10 | use embassy_stm32::{bind_interrupts, Config}; | 12 | use embassy_stm32::{bind_interrupts, Config}; |
| 13 | use static_cell::StaticCell; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 15 | ||
| 13 | bind_interrupts!(struct Irqs { | 16 | bind_interrupts!(struct Irqs { |
| @@ -20,6 +23,27 @@ bind_interrupts!(struct Irqs { | |||
| 20 | // This example is configured to work with real CAN transceivers on B8/B9. | 23 | // This example is configured to work with real CAN transceivers on B8/B9. |
| 21 | // See other examples for loopback. | 24 | // See other examples for loopback. |
| 22 | 25 | ||
| 26 | fn handle_frame(env: Envelope, read_mode: &str) { | ||
| 27 | match env.frame.id() { | ||
| 28 | Id::Extended(id) => { | ||
| 29 | defmt::println!( | ||
| 30 | "{} Extended Frame id={:x} {:02x}", | ||
| 31 | read_mode, | ||
| 32 | id.as_raw(), | ||
| 33 | env.frame.data() | ||
| 34 | ); | ||
| 35 | } | ||
| 36 | Id::Standard(id) => { | ||
| 37 | defmt::println!( | ||
| 38 | "{} Standard Frame id={:x} {:02x}", | ||
| 39 | read_mode, | ||
| 40 | id.as_raw(), | ||
| 41 | env.frame.data() | ||
| 42 | ); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 23 | #[embassy_executor::main] | 47 | #[embassy_executor::main] |
| 24 | async fn main(_spawner: Spawner) { | 48 | async fn main(_spawner: Spawner) { |
| 25 | let p = embassy_stm32::init(Config::default()); | 49 | let p = embassy_stm32::init(Config::default()); |
| @@ -27,40 +51,90 @@ async fn main(_spawner: Spawner) { | |||
| 27 | // Set alternate pin mapping to B8/B9 | 51 | // Set alternate pin mapping to B8/B9 |
| 28 | embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); | 52 | embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); |
| 29 | 53 | ||
| 54 | static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new(); | ||
| 55 | static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new(); | ||
| 56 | |||
| 30 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); | 57 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); |
| 31 | 58 | ||
| 32 | can.as_mut() | 59 | can.modify_filters() |
| 33 | .modify_filters() | 60 | .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); |
| 34 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 35 | 61 | ||
| 36 | can.as_mut() | 62 | can.modify_config() |
| 37 | .modify_config() | ||
| 38 | .set_loopback(false) | 63 | .set_loopback(false) |
| 39 | .set_silent(false) | 64 | .set_silent(false) |
| 40 | .leave_disabled(); | 65 | .set_bitrate(250_000); |
| 41 | |||
| 42 | can.set_bitrate(250_000); | ||
| 43 | 66 | ||
| 44 | can.enable().await; | 67 | can.enable().await; |
| 45 | |||
| 46 | let mut i: u8 = 0; | 68 | let mut i: u8 = 0; |
| 47 | loop { | 69 | |
| 48 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); | 70 | /* |
| 49 | can.write(&tx_frame).await; | 71 | // Example for using buffered Tx and Rx without needing to |
| 50 | 72 | // split first as is done below. | |
| 51 | match can.read().await { | 73 | let mut can = can.buffered( |
| 52 | Ok(env) => match env.frame.id() { | 74 | TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()), |
| 53 | Id::Extended(id) => { | 75 | RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); |
| 54 | defmt::println!("Extended Frame id={:x}", id.as_raw()); | 76 | loop { |
| 55 | } | 77 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); |
| 56 | Id::Standard(id) => { | 78 | can.write(&tx_frame).await; |
| 57 | defmt::println!("Standard Frame id={:x}", id.as_raw()); | 79 | |
| 58 | } | 80 | match can.read().await { |
| 59 | }, | 81 | Ok((frame, ts)) => { |
| 82 | handle_frame(Envelope { ts, frame }, "Buf"); | ||
| 83 | } | ||
| 84 | Err(err) => { | ||
| 85 | defmt::println!("Error {}", err); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | i = i.wrapping_add(1); | ||
| 89 | } | ||
| 90 | |||
| 91 | */ | ||
| 92 | let (mut tx, mut rx) = can.split(); | ||
| 93 | |||
| 94 | // This example shows using the wait_not_empty API before try read | ||
| 95 | while i < 3 { | ||
| 96 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 97 | tx.write(&tx_frame).await; | ||
| 98 | |||
| 99 | rx.wait_not_empty().await; | ||
| 100 | let env = rx.try_read().unwrap(); | ||
| 101 | handle_frame(env, "Wait"); | ||
| 102 | i += 1; | ||
| 103 | } | ||
| 104 | |||
| 105 | // This example shows using the full async non-buffered API | ||
| 106 | while i < 6 { | ||
| 107 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 108 | tx.write(&tx_frame).await; | ||
| 109 | |||
| 110 | match rx.read().await { | ||
| 111 | Ok(env) => { | ||
| 112 | handle_frame(env, "NoBuf"); | ||
| 113 | } | ||
| 60 | Err(err) => { | 114 | Err(err) => { |
| 61 | defmt::println!("Error {}", err); | 115 | defmt::println!("Error {}", err); |
| 62 | } | 116 | } |
| 63 | } | 117 | } |
| 64 | i += 1; | 118 | i += 1; |
| 65 | } | 119 | } |
| 120 | |||
| 121 | // This example shows using buffered RX and TX. User passes in desired buffer (size) | ||
| 122 | // It's possible this way to have just RX or TX buffered. | ||
| 123 | let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); | ||
| 124 | let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new())); | ||
| 125 | |||
| 126 | loop { | ||
| 127 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 128 | tx.write(&tx_frame).await; | ||
| 129 | |||
| 130 | match rx.read().await { | ||
| 131 | Ok(envelope) => { | ||
| 132 | handle_frame(envelope, "Buf"); | ||
| 133 | } | ||
| 134 | Err(err) => { | ||
| 135 | defmt::println!("Error {}", err); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | i = i.wrapping_add(1); | ||
| 139 | } | ||
| 66 | } | 140 | } |
diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs index 7b761ecc1..3c295612c 100644 --- a/examples/stm32f1/src/bin/hello.rs +++ b/examples/stm32f1/src/bin/hello.rs | |||
| @@ -3,15 +3,13 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::time::Hertz; | ||
| 7 | use embassy_stm32::Config; | 6 | use embassy_stm32::Config; |
| 8 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 9 | ||
| 11 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) -> ! { | 11 | async fn main(_spawner: Spawner) -> ! { |
| 13 | let mut config = Config::default(); | 12 | let config = Config::default(); |
| 14 | config.rcc.sys_ck = Some(Hertz(36_000_000)); | ||
| 15 | let _p = embassy_stm32::init(config); | 13 | let _p = embassy_stm32::init(config); |
| 16 | 14 | ||
| 17 | loop { | 15 | loop { |
diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs new file mode 100644 index 000000000..5e2dab9e6 --- /dev/null +++ b/examples/stm32f1/src/bin/input_capture.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 7 | use embassy_stm32::time::khz; | ||
| 8 | use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; | ||
| 9 | use embassy_stm32::timer::{self, Channel}; | ||
| 10 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 11 | use embassy_time::Timer; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | /// Connect PA2 and PC13 with a 1k Ohm resistor | ||
| 15 | |||
| 16 | #[embassy_executor::task] | ||
| 17 | async fn blinky(led: peripherals::PC13) { | ||
| 18 | let mut led = Output::new(led, Level::High, Speed::Low); | ||
| 19 | |||
| 20 | loop { | ||
| 21 | info!("high"); | ||
| 22 | led.set_high(); | ||
| 23 | Timer::after_millis(300).await; | ||
| 24 | |||
| 25 | info!("low"); | ||
| 26 | led.set_low(); | ||
| 27 | Timer::after_millis(300).await; | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | bind_interrupts!(struct Irqs { | ||
| 32 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 33 | }); | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(spawner: Spawner) { | ||
| 37 | let p = embassy_stm32::init(Default::default()); | ||
| 38 | info!("Hello World!"); | ||
| 39 | |||
| 40 | unwrap!(spawner.spawn(blinky(p.PC13))); | ||
| 41 | |||
| 42 | let ch3 = CapturePin::new_ch3(p.PA2, Pull::None); | ||
| 43 | let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default()); | ||
| 44 | |||
| 45 | loop { | ||
| 46 | info!("wait for rising edge"); | ||
| 47 | ic.wait_for_rising_edge(Channel::Ch3).await; | ||
| 48 | |||
| 49 | let capture_value = ic.get_capture_value(Channel::Ch3); | ||
| 50 | info!("new capture! {}", capture_value); | ||
| 51 | } | ||
| 52 | } | ||
diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs new file mode 100644 index 000000000..f74853d4e --- /dev/null +++ b/examples/stm32f1/src/bin/pwm_input.rs | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 7 | use embassy_stm32::time::khz; | ||
| 8 | use embassy_stm32::timer::pwm_input::PwmInput; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, timer}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | /// Connect PA0 and PC13 with a 1k Ohm resistor | ||
| 14 | |||
| 15 | #[embassy_executor::task] | ||
| 16 | async fn blinky(led: peripherals::PC13) { | ||
| 17 | let mut led = Output::new(led, Level::High, Speed::Low); | ||
| 18 | |||
| 19 | loop { | ||
| 20 | info!("high"); | ||
| 21 | led.set_high(); | ||
| 22 | Timer::after_millis(300).await; | ||
| 23 | |||
| 24 | info!("low"); | ||
| 25 | led.set_low(); | ||
| 26 | Timer::after_millis(300).await; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::main] | ||
| 35 | async fn main(spawner: Spawner) { | ||
| 36 | let p = embassy_stm32::init(Default::default()); | ||
| 37 | info!("Hello World!"); | ||
| 38 | |||
| 39 | unwrap!(spawner.spawn(blinky(p.PC13))); | ||
| 40 | |||
| 41 | let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(10)); | ||
| 42 | pwm_input.enable(); | ||
| 43 | |||
| 44 | loop { | ||
| 45 | Timer::after_millis(500).await; | ||
| 46 | let period = pwm_input.get_period_ticks(); | ||
| 47 | let width = pwm_input.get_width_ticks(); | ||
| 48 | let duty_cycle = pwm_input.get_duty_cycle(); | ||
| 49 | info!( | ||
| 50 | "period ticks: {} width ticks: {} duty cycle: {}", | ||
| 51 | period, width, duty_cycle | ||
| 52 | ); | ||
| 53 | } | ||
| 54 | } | ||
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index e28381893..ee99acf41 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs | |||
| @@ -21,9 +21,23 @@ bind_interrupts!(struct Irqs { | |||
| 21 | #[embassy_executor::main] | 21 | #[embassy_executor::main] |
| 22 | async fn main(_spawner: Spawner) { | 22 | async fn main(_spawner: Spawner) { |
| 23 | let mut config = Config::default(); | 23 | let mut config = Config::default(); |
| 24 | config.rcc.hse = Some(Hertz(8_000_000)); | 24 | { |
| 25 | config.rcc.sys_ck = Some(Hertz(48_000_000)); | 25 | use embassy_stm32::rcc::*; |
| 26 | config.rcc.pclk1 = Some(Hertz(24_000_000)); | 26 | config.rcc.hse = Some(Hse { |
| 27 | freq: Hertz(8_000_000), | ||
| 28 | // Oscillator for bluepill, Bypass for nucleos. | ||
| 29 | mode: HseMode::Oscillator, | ||
| 30 | }); | ||
| 31 | config.rcc.pll = Some(Pll { | ||
| 32 | src: PllSource::HSE, | ||
| 33 | prediv: PllPreDiv::DIV1, | ||
| 34 | mul: PllMul::MUL9, | ||
| 35 | }); | ||
| 36 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 37 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 38 | config.rcc.apb1_pre = APBPrescaler::DIV2; | ||
| 39 | config.rcc.apb2_pre = APBPrescaler::DIV1; | ||
| 40 | } | ||
| 27 | let mut p = embassy_stm32::init(config); | 41 | let mut p = embassy_stm32::init(config); |
| 28 | 42 | ||
| 29 | info!("Hello World!"); | 43 | info!("Hello World!"); |
| @@ -46,7 +60,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | 60 | ||
| 47 | // Create embassy-usb DeviceBuilder using the driver and config. | 61 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 48 | // It needs some buffers for building the descriptors. | 62 | // It needs some buffers for building the descriptors. |
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 63 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 64 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 7]; | 65 | let mut control_buf = [0; 7]; |
| @@ -56,7 +69,6 @@ async fn main(_spawner: Spawner) { | |||
| 56 | let mut builder = Builder::new( | 69 | let mut builder = Builder::new( |
| 57 | driver, | 70 | driver, |
| 58 | config, | 71 | config, |
| 59 | &mut device_descriptor, | ||
| 60 | &mut config_descriptor, | 72 | &mut config_descriptor, |
| 61 | &mut bos_descriptor, | 73 | &mut bos_descriptor, |
| 62 | &mut [], // no msos descriptors | 74 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 4cbf1dc84..60eb0eb93 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml | |||
| @@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32f207zg to your chip name, if necessary. | 8 | # Change stm32f207zg to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "0.3" |
| 15 | defmt-rtt = "0.4" | 15 | defmt-rtt = "0.4" |
| @@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 21 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 22 | heapless = { version = "0.8", default-features = false } | 21 | heapless = { version = "0.8", default-features = false } |
| 23 | nb = "1.0.0" | 22 | nb = "1.0.0" |
| 24 | 23 | ||
diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index e32f283d1..e39e2daec 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::convert::TryFrom; | ||
| 5 | |||
| 6 | use defmt::*; | 4 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::time::Hertz; | 6 | use embassy_stm32::time::Hertz; |
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 64bb2e560..7fda410d9 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml | |||
| @@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32f303ze to your chip name, if necessary. | 8 | # Change stm32f303ze to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 15 | 15 | ||
| 16 | defmt = "0.3" | 16 | defmt = "0.3" |
| @@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 24 | heapless = { version = "0.8", default-features = false } | 23 | heapless = { version = "0.8", default-features = false } |
| 25 | nb = "1.0.0" | 24 | nb = "1.0.0" |
| 26 | embedded-storage = "0.3.1" | 25 | embedded-storage = "0.3.1" |
diff --git a/examples/stm32f3/src/bin/blocking-tsc.rs b/examples/stm32f3/src/bin/blocking-tsc.rs new file mode 100644 index 000000000..5c8dac94f --- /dev/null +++ b/examples/stm32f3/src/bin/blocking-tsc.rs | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | // Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected. | ||
| 2 | // | ||
| 3 | // Suggested physical setup on STM32F303ZE Nucleo board: | ||
| 4 | // - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor. | ||
| 5 | // - Connect one end of a 1K resistor to pin A1 and leave the other end loose. | ||
| 6 | // The loose end will act as touch sensor which will register your touch. | ||
| 7 | // | ||
| 8 | // Troubleshooting the setup: | ||
| 9 | // - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily, | ||
| 10 | // now the led should light up. Next try using a different value for the sampling capacitor. | ||
| 11 | // Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`. | ||
| 12 | // | ||
| 13 | // All configuration values and sampling capacitor value have been determined experimentally. | ||
| 14 | // Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values. | ||
| 15 | // | ||
| 16 | #![no_std] | ||
| 17 | #![no_main] | ||
| 18 | |||
| 19 | use defmt::*; | ||
| 20 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 21 | use embassy_stm32::tsc::{self, *}; | ||
| 22 | use embassy_time::Timer; | ||
| 23 | use {defmt_rtt as _, panic_probe as _}; | ||
| 24 | |||
| 25 | /// This example is written for the nucleo-stm32f303ze, with a stm32f303ze chip. | ||
| 26 | /// | ||
| 27 | /// Make sure you check/update the following (whether you use the F303ZE or another board): | ||
| 28 | /// | ||
| 29 | /// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32F303ZETx`chip name. | ||
| 30 | /// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for F303ZE it should be `stm32f303ze`. | ||
| 31 | /// * [ ] If your board has a special clock or power configuration, make sure that it is | ||
| 32 | /// set up appropriately. | ||
| 33 | /// * [ ] If your board has different pin mapping, update any pin numbers or peripherals | ||
| 34 | /// to match your schematic | ||
| 35 | /// | ||
| 36 | /// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 37 | /// | ||
| 38 | /// * Which example you are trying to run | ||
| 39 | /// * Which chip and board you are using | ||
| 40 | /// | ||
| 41 | /// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
| 42 | #[embassy_executor::main] | ||
| 43 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 44 | let device_config = embassy_stm32::Config::default(); | ||
| 45 | let context = embassy_stm32::init(device_config); | ||
| 46 | |||
| 47 | let tsc_conf = Config { | ||
| 48 | ct_pulse_high_length: ChargeTransferPulseCycle::_8, | ||
| 49 | ct_pulse_low_length: ChargeTransferPulseCycle::_8, | ||
| 50 | spread_spectrum: false, | ||
| 51 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 52 | spread_spectrum_prescaler: false, | ||
| 53 | pulse_generator_prescaler: PGPrescalerDivider::_32, | ||
| 54 | max_count_value: MaxCount::_255, | ||
| 55 | io_default_mode: false, | ||
| 56 | synchro_pin_polarity: false, | ||
| 57 | acquisition_mode: false, | ||
| 58 | max_count_interrupt: false, | ||
| 59 | channel_ios: TscIOPin::Group1Io1.into(), | ||
| 60 | shield_ios: 0, // no shield | ||
| 61 | sampling_ios: TscIOPin::Group1Io2.into(), | ||
| 62 | }; | ||
| 63 | |||
| 64 | let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | ||
| 65 | g1.set_io1(context.PA0, PinType::Sample); | ||
| 66 | g1.set_io2(context.PA1, PinType::Channel); | ||
| 67 | |||
| 68 | let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, Some(g1), None, None, None, None, None, tsc_conf); | ||
| 69 | |||
| 70 | // LED2 on the STM32F303ZE nucleo-board | ||
| 71 | let mut led = Output::new(context.PB7, Level::High, Speed::Low); | ||
| 72 | |||
| 73 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 74 | let discharge_delay = 5; // ms | ||
| 75 | |||
| 76 | // the interval at which the loop polls for new touch sensor values | ||
| 77 | let polling_interval = 100; // ms | ||
| 78 | |||
| 79 | info!("polling for touch"); | ||
| 80 | loop { | ||
| 81 | touch_controller.start(); | ||
| 82 | touch_controller.poll_for_acquisition(); | ||
| 83 | touch_controller.discharge_io(true); | ||
| 84 | Timer::after_millis(discharge_delay).await; | ||
| 85 | |||
| 86 | let grp1_status = touch_controller.group_get_status(Group::One); | ||
| 87 | match grp1_status { | ||
| 88 | GroupStatus::Complete => { | ||
| 89 | let group_one_val = touch_controller.group_get_value(Group::One); | ||
| 90 | info!("{}", group_one_val); | ||
| 91 | led.set_high(); | ||
| 92 | } | ||
| 93 | GroupStatus::Ongoing => led.set_low(), | ||
| 94 | } | ||
| 95 | |||
| 96 | Timer::after_millis(polling_interval).await; | ||
| 97 | } | ||
| 98 | } | ||
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs index 328447210..b4620888f 100644 --- a/examples/stm32f3/src/bin/multiprio.rs +++ b/examples/stm32f3/src/bin/multiprio.rs | |||
| @@ -80,7 +80,7 @@ async fn run_med() { | |||
| 80 | info!(" [med] Starting long computation"); | 80 | info!(" [med] Starting long computation"); |
| 81 | 81 | ||
| 82 | // Spin-wait to simulate a long CPU computation | 82 | // Spin-wait to simulate a long CPU computation |
| 83 | cortex_m::asm::delay(8_000_000); // ~1 second | 83 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second |
| 84 | 84 | ||
| 85 | let end = Instant::now(); | 85 | let end = Instant::now(); |
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | 86 | let ms = end.duration_since(start).as_ticks() / 33; |
| @@ -97,7 +97,7 @@ async fn run_low() { | |||
| 97 | info!("[low] Starting long computation"); | 97 | info!("[low] Starting long computation"); |
| 98 | 98 | ||
| 99 | // Spin-wait to simulate a long CPU computation | 99 | // Spin-wait to simulate a long CPU computation |
| 100 | cortex_m::asm::delay(16_000_000); // ~2 seconds | 100 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds |
| 101 | 101 | ||
| 102 | let end = Instant::now(); | 102 | let end = Instant::now(); |
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | 103 | let ms = end.duration_since(start).as_ticks() / 33; |
| @@ -127,6 +127,11 @@ fn main() -> ! { | |||
| 127 | 127 | ||
| 128 | let _p = embassy_stm32::init(Default::default()); | 128 | let _p = embassy_stm32::init(Default::default()); |
| 129 | 129 | ||
| 130 | // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as | ||
| 131 | // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. | ||
| 132 | // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt | ||
| 133 | // vector would work exactly the same. | ||
| 134 | |||
| 130 | // High-priority executor: UART4, priority level 6 | 135 | // High-priority executor: UART4, priority level 6 |
| 131 | interrupt::UART4.set_priority(Priority::P6); | 136 | interrupt::UART4.set_priority(Priority::P6); |
| 132 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); | 137 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); |
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 5234e53b9..573a49f19 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs | |||
| @@ -5,7 +5,6 @@ use core::fmt::Write; | |||
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use heapless::String; |
| @@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) { | |||
| 21 | info!("Hello World!"); | 20 | info!("Hello World!"); |
| 22 | 21 | ||
| 23 | let config = Config::default(); | 22 | let config = Config::default(); |
| 24 | let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap(); | 23 | let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, p.DMA1_CH5, config).unwrap(); |
| 25 | 24 | ||
| 26 | for n in 0u32.. { | 25 | for n in 0u32.. { |
| 27 | let mut s: String<128> = String::new(); | 26 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index ee1c43afd..5760f2c1c 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs | |||
| @@ -54,7 +54,6 @@ async fn main(_spawner: Spawner) { | |||
| 54 | 54 | ||
| 55 | // Create embassy-usb DeviceBuilder using the driver and config. | 55 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 56 | // It needs some buffers for building the descriptors. | 56 | // It needs some buffers for building the descriptors. |
| 57 | let mut device_descriptor = [0; 256]; | ||
| 58 | let mut config_descriptor = [0; 256]; | 57 | let mut config_descriptor = [0; 256]; |
| 59 | let mut bos_descriptor = [0; 256]; | 58 | let mut bos_descriptor = [0; 256]; |
| 60 | let mut control_buf = [0; 7]; | 59 | let mut control_buf = [0; 7]; |
| @@ -64,7 +63,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | let mut builder = Builder::new( | 63 | let mut builder = Builder::new( |
| 65 | driver, | 64 | driver, |
| 66 | config, | 65 | config, |
| 67 | &mut device_descriptor, | ||
| 68 | &mut config_descriptor, | 66 | &mut config_descriptor, |
| 69 | &mut bos_descriptor, | 67 | &mut bos_descriptor, |
| 70 | &mut [], // no msos descriptors | 68 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f334/.cargo/config.toml b/examples/stm32f334/.cargo/config.toml index caf947be6..f38c90a31 100644 --- a/examples/stm32f334/.cargo/config.toml +++ b/examples/stm32f334/.cargo/config.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 2 | # replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` | 2 | # replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` |
| 3 | runner = "probe-run --chip STM32F334R8" | 3 | runner = "probe-rs run --chip STM32F334R8" |
| 4 | 4 | ||
| 5 | [build] | 5 | [build] |
| 6 | target = "thumbv7em-none-eabihf" | 6 | target = "thumbv7em-none-eabihf" |
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 3e5a7cc8c..1cc0a97da 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml | |||
| @@ -5,11 +5,11 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| @@ -19,7 +19,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 20 | embedded-hal = "0.2.6" | 20 | embedded-hal = "0.2.6" |
| 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 23 | heapless = { version = "0.8", default-features = false } | 22 | heapless = { version = "0.8", default-features = false } |
| 24 | nb = "1.0.0" | 23 | nb = "1.0.0" |
| 25 | embedded-storage = "0.3.1" | 24 | embedded-storage = "0.3.1" |
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index a9fb7f1a6..0528a9637 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs | |||
| @@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime}; | |||
| 7 | use embassy_stm32::peripherals::ADC1; | 7 | use embassy_stm32::peripherals::ADC1; |
| 8 | use embassy_stm32::time::mhz; | 8 | use embassy_stm32::time::mhz; |
| 9 | use embassy_stm32::{adc, bind_interrupts, Config}; | 9 | use embassy_stm32::{adc, bind_interrupts, Config}; |
| 10 | use embassy_time::{Delay, Timer}; | 10 | use embassy_time::Timer; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 12 | ||
| 13 | bind_interrupts!(struct Irqs { | 13 | bind_interrupts!(struct Irqs { |
| @@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 38 | 38 | ||
| 39 | info!("create adc..."); | 39 | info!("create adc..."); |
| 40 | 40 | ||
| 41 | let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); | 41 | let mut adc = Adc::new(p.ADC1, Irqs); |
| 42 | 42 | ||
| 43 | adc.set_sample_time(SampleTime::Cycles601_5); | 43 | adc.set_sample_time(SampleTime::CYCLES601_5); |
| 44 | 44 | ||
| 45 | info!("enable vrefint..."); | 45 | info!("enable vrefint..."); |
| 46 | 46 | ||
| 47 | let mut vrefint = adc.enable_vref(&mut Delay); | 47 | let mut vrefint = adc.enable_vref(); |
| 48 | let mut temperature = adc.enable_temperature(); | 48 | let mut temperature = adc.enable_temperature(); |
| 49 | 49 | ||
| 50 | loop { | 50 | loop { |
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 6f25191be..2dbf1bdab 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs | |||
| @@ -8,7 +8,7 @@ use embassy_stm32::opamp::{OpAmp, OpAmpGain}; | |||
| 8 | use embassy_stm32::peripherals::ADC2; | 8 | use embassy_stm32::peripherals::ADC2; |
| 9 | use embassy_stm32::time::mhz; | 9 | use embassy_stm32::time::mhz; |
| 10 | use embassy_stm32::{adc, bind_interrupts, Config}; | 10 | use embassy_stm32::{adc, bind_interrupts, Config}; |
| 11 | use embassy_time::{Delay, Timer}; | 11 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| 14 | bind_interrupts!(struct Irqs { | 14 | bind_interrupts!(struct Irqs { |
| @@ -39,14 +39,14 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 39 | 39 | ||
| 40 | info!("create adc..."); | 40 | info!("create adc..."); |
| 41 | 41 | ||
| 42 | let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); | 42 | let mut adc = Adc::new(p.ADC2, Irqs); |
| 43 | let mut opamp = OpAmp::new(p.OPAMP2); | 43 | let mut opamp = OpAmp::new(p.OPAMP2); |
| 44 | 44 | ||
| 45 | adc.set_sample_time(SampleTime::Cycles601_5); | 45 | adc.set_sample_time(SampleTime::CYCLES601_5); |
| 46 | 46 | ||
| 47 | info!("enable vrefint..."); | 47 | info!("enable vrefint..."); |
| 48 | 48 | ||
| 49 | let mut vrefint = adc.enable_vref(&mut Delay); | 49 | let mut vrefint = adc.enable_vref(); |
| 50 | let mut temperature = adc.enable_temperature(); | 50 | let mut temperature = adc.enable_temperature(); |
| 51 | let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); | 51 | let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); |
| 52 | 52 | ||
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 7fc1ea926..e6d1a6c02 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs | |||
| @@ -27,7 +27,8 @@ async fn main(_spawner: Spawner) { | |||
| 27 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 27 | config.rcc.ahb_pre = AHBPrescaler::DIV1; |
| 28 | config.rcc.apb1_pre = APBPrescaler::DIV2; | 28 | config.rcc.apb1_pre = APBPrescaler::DIV2; |
| 29 | config.rcc.apb2_pre = APBPrescaler::DIV1; | 29 | config.rcc.apb2_pre = APBPrescaler::DIV1; |
| 30 | config.rcc.hrtim = HrtimClockSource::PllClk; | 30 | |
| 31 | config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P; | ||
| 31 | } | 32 | } |
| 32 | let p = embassy_stm32::init(config); | 33 | let p = embassy_stm32::init(config); |
| 33 | 34 | ||
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index cd46fc85b..b85361596 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml | |||
| @@ -6,12 +6,14 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32f429zi to your chip name, if necessary. | 8 | # Change stm32f429zi to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } |
| 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } | 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } |
| 15 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | ||
| 16 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 15 | 17 | ||
| 16 | defmt = "0.3" | 18 | defmt = "0.3" |
| 17 | defmt-rtt = "0.4" | 19 | defmt-rtt = "0.4" |
| @@ -19,14 +21,16 @@ defmt-rtt = "0.4" | |||
| 19 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 20 | cortex-m-rt = "0.7.0" | 22 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 23 | embedded-hal = "0.2.6" |
| 24 | embedded-hal-bus = { version = "0.2", features = ["async"] } | ||
| 22 | embedded-io = { version = "0.6.0" } | 25 | embedded-io = { version = "0.6.0" } |
| 23 | embedded-io-async = { version = "0.6.1" } | 26 | embedded-io-async = { version = "0.6.1" } |
| 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 27 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 28 | futures-util = { version = "0.3.30", default-features = false } |
| 26 | heapless = { version = "0.8", default-features = false } | 29 | heapless = { version = "0.8", default-features = false } |
| 27 | nb = "1.0.0" | 30 | nb = "1.0.0" |
| 28 | embedded-storage = "0.3.1" | 31 | embedded-storage = "0.3.1" |
| 29 | micromath = "2.0.0" | 32 | micromath = "2.0.0" |
| 33 | usbd-hid = "0.8.1" | ||
| 30 | static_cell = "2" | 34 | static_cell = "2" |
| 31 | chrono = { version = "^0.4", default-features = false} | 35 | chrono = { version = "^0.4", default-features = false} |
| 32 | 36 | ||
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 699c29c05..423d29225 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs | |||
| @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { | |||
| 14 | info!("Hello World!"); | 14 | info!("Hello World!"); |
| 15 | 15 | ||
| 16 | let mut delay = Delay; | 16 | let mut delay = Delay; |
| 17 | let mut adc = Adc::new(p.ADC1, &mut delay); | 17 | let mut adc = Adc::new(p.ADC1); |
| 18 | let mut pin = p.PC1; | 18 | let mut pin = p.PC1; |
| 19 | 19 | ||
| 20 | let mut vrefint = adc.enable_vrefint(); | 20 | let mut vrefint = adc.enable_vrefint(); |
| @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { | |||
| 23 | // Startup delay can be combined to the maximum of either | 23 | // Startup delay can be combined to the maximum of either |
| 24 | delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); | 24 | delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); |
| 25 | 25 | ||
| 26 | let vrefint_sample = adc.read(&mut vrefint); | 26 | let vrefint_sample = adc.blocking_read(&mut vrefint); |
| 27 | 27 | ||
| 28 | let convert_to_millivolts = |sample| { | 28 | let convert_to_millivolts = |sample| { |
| 29 | // From http://www.st.com/resource/en/datasheet/DM00071990.pdf | 29 | // From http://www.st.com/resource/en/datasheet/DM00071990.pdf |
| @@ -50,16 +50,16 @@ async fn main(_spawner: Spawner) { | |||
| 50 | 50 | ||
| 51 | loop { | 51 | loop { |
| 52 | // Read pin | 52 | // Read pin |
| 53 | let v = adc.read(&mut pin); | 53 | let v = adc.blocking_read(&mut pin); |
| 54 | info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); | 54 | info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); |
| 55 | 55 | ||
| 56 | // Read internal temperature | 56 | // Read internal temperature |
| 57 | let v = adc.read(&mut temp); | 57 | let v = adc.blocking_read(&mut temp); |
| 58 | let celcius = convert_to_celcius(v); | 58 | let celcius = convert_to_celcius(v); |
| 59 | info!("Internal temp: {} ({} C)", v, celcius); | 59 | info!("Internal temp: {} ({} C)", v, celcius); |
| 60 | 60 | ||
| 61 | // Read internal voltage reference | 61 | // Read internal voltage reference |
| 62 | let v = adc.read(&mut vrefint); | 62 | let v = adc.blocking_read(&mut vrefint); |
| 63 | info!("VrefInt: {}", v); | 63 | info!("VrefInt: {}", v); |
| 64 | 64 | ||
| 65 | Timer::after_millis(100).await; | 65 | Timer::after_millis(100).await; |
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs new file mode 100644 index 000000000..43a761e6d --- /dev/null +++ b/examples/stm32f4/src/bin/adc_dma.rs | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | use cortex_m::singleton; | ||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; | ||
| 7 | use embassy_stm32::Peripherals; | ||
| 8 | use embassy_time::Instant; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(spawner: Spawner) { | ||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | spawner.must_spawn(adc_task(p)); | ||
| 15 | } | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async fn adc_task(mut p: Peripherals) { | ||
| 19 | const ADC_BUF_SIZE: usize = 1024; | ||
| 20 | let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); | ||
| 21 | let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); | ||
| 22 | |||
| 23 | let adc = Adc::new(p.ADC1); | ||
| 24 | let adc2 = Adc::new(p.ADC2); | ||
| 25 | |||
| 26 | let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_data); | ||
| 27 | let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(p.DMA2_CH2, adc_data2); | ||
| 28 | |||
| 29 | adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); | ||
| 30 | adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112); | ||
| 31 | adc2.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112); | ||
| 32 | adc2.set_sample_sequence(Sequence::Two, &mut p.PA3, SampleTime::CYCLES112); | ||
| 33 | |||
| 34 | // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around | ||
| 35 | // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of | ||
| 36 | // what channel is at what index is lost. The buffer must be cleared and reset. This *is* handled here, but allowing this to happen will cause | ||
| 37 | // a reduction of performance as each time the buffer is reset, the adc & dma buffer must be restarted. | ||
| 38 | |||
| 39 | // An interrupt executor with a higher priority than other tasks may be a good approach here, allowing this task to wake and read the buffer most | ||
| 40 | // frequently. | ||
| 41 | let mut tic = Instant::now(); | ||
| 42 | let mut buffer1 = [0u16; 512]; | ||
| 43 | let mut buffer2 = [0u16; 512]; | ||
| 44 | let _ = adc.start(); | ||
| 45 | let _ = adc2.start(); | ||
| 46 | loop { | ||
| 47 | match adc.read(&mut buffer1).await { | ||
| 48 | Ok(_data) => { | ||
| 49 | let toc = Instant::now(); | ||
| 50 | info!( | ||
| 51 | "\n adc1: {} dt = {}, n = {}", | ||
| 52 | buffer1[0..16], | ||
| 53 | (toc - tic).as_micros(), | ||
| 54 | _data | ||
| 55 | ); | ||
| 56 | tic = toc; | ||
| 57 | } | ||
| 58 | Err(e) => { | ||
| 59 | warn!("Error: {:?}", e); | ||
| 60 | buffer1 = [0u16; 512]; | ||
| 61 | let _ = adc.start(); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | match adc2.read(&mut buffer2).await { | ||
| 66 | Ok(_data) => { | ||
| 67 | let toc = Instant::now(); | ||
| 68 | info!( | ||
| 69 | "\n adc2: {} dt = {}, n = {}", | ||
| 70 | buffer2[0..16], | ||
| 71 | (toc - tic).as_micros(), | ||
| 72 | _data | ||
| 73 | ); | ||
| 74 | tic = toc; | ||
| 75 | } | ||
| 76 | Err(e) => { | ||
| 77 | warn!("Error: {:?}", e); | ||
| 78 | buffer2 = [0u16; 512]; | ||
| 79 | let _ = adc2.start(); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index d074b4265..8e3beee24 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs | |||
| @@ -4,9 +4,10 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::bind_interrupts; | 6 | use embassy_stm32::bind_interrupts; |
| 7 | use embassy_stm32::can::bxcan::filter::Mask32; | 7 | use embassy_stm32::can::filter::Mask32; |
| 8 | use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; | 8 | use embassy_stm32::can::{ |
| 9 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; | 9 | Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler, |
| 10 | }; | ||
| 10 | use embassy_stm32::gpio::{Input, Pull}; | 11 | use embassy_stm32::gpio::{Input, Pull}; |
| 11 | use embassy_stm32::peripherals::CAN1; | 12 | use embassy_stm32::peripherals::CAN1; |
| 12 | use embassy_time::Instant; | 13 | use embassy_time::Instant; |
| @@ -34,23 +35,18 @@ async fn main(_spawner: Spawner) { | |||
| 34 | 35 | ||
| 35 | let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); | 36 | let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); |
| 36 | 37 | ||
| 37 | can.as_mut() | 38 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 38 | .modify_filters() | ||
| 39 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 40 | 39 | ||
| 41 | can.as_mut() | 40 | can.modify_config() |
| 42 | .modify_config() | ||
| 43 | .set_loopback(true) // Receive own frames | 41 | .set_loopback(true) // Receive own frames |
| 44 | .set_silent(true) | 42 | .set_silent(true) |
| 45 | .leave_disabled(); | 43 | .set_bitrate(1_000_000); |
| 46 | |||
| 47 | can.set_bitrate(1_000_000); | ||
| 48 | 44 | ||
| 49 | can.enable().await; | 45 | can.enable().await; |
| 50 | 46 | ||
| 51 | let mut i: u8 = 0; | 47 | let mut i: u8 = 0; |
| 52 | loop { | 48 | loop { |
| 53 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); | 49 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap(); |
| 54 | let tx_ts = Instant::now(); | 50 | let tx_ts = Instant::now(); |
| 55 | can.write(&tx_frame).await; | 51 | can.write(&tx_frame).await; |
| 56 | 52 | ||
| @@ -64,9 +60,9 @@ async fn main(_spawner: Spawner) { | |||
| 64 | 60 | ||
| 65 | info!( | 61 | info!( |
| 66 | "loopback frame {=u8}, latency: {} us", | 62 | "loopback frame {=u8}, latency: {} us", |
| 67 | unwrap!(envelope.frame.data())[0], | 63 | envelope.frame.data()[0], |
| 68 | latency.as_micros() | 64 | latency.as_micros() |
| 69 | ); | 65 | ); |
| 70 | i += 1; | 66 | i = i.wrapping_add(1); |
| 71 | } | 67 | } |
| 72 | } | 68 | } |
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs index 9c7754c4f..dd2a45718 100644 --- a/examples/stm32f4/src/bin/dac.rs +++ b/examples/stm32f4/src/bin/dac.rs | |||
| @@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 12 | let p = embassy_stm32::init(Default::default()); | 12 | let p = embassy_stm32::init(Default::default()); |
| 13 | info!("Hello World, dude!"); | 13 | info!("Hello World, dude!"); |
| 14 | 14 | ||
| 15 | let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4); | 15 | let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); |
| 16 | 16 | ||
| 17 | loop { | 17 | loop { |
| 18 | for v in 0..=255 { | 18 | for v in 0..=255 { |
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 7f5c8fdb1..baed96449 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { | |||
| 24 | type Device = Ethernet<'static, ETH, GenericSMI>; | 24 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 25 | 25 | ||
| 26 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 27 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 27 | async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { |
| 28 | stack.run().await | 28 | runner.run().await |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | #[embassy_executor::main] | 31 | #[embassy_executor::main] |
| @@ -62,9 +62,9 @@ async fn main(spawner: Spawner) -> ! { | |||
| 62 | 62 | ||
| 63 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 63 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 64 | 64 | ||
| 65 | static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); | 65 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); |
| 66 | let device = Ethernet::new( | 66 | let device = Ethernet::new( |
| 67 | PACKETS.init(PacketQueue::<16, 16>::new()), | 67 | PACKETS.init(PacketQueue::<4, 4>::new()), |
| 68 | p.ETH, | 68 | p.ETH, |
| 69 | Irqs, | 69 | Irqs, |
| 70 | p.PA1, | 70 | p.PA1, |
| @@ -88,17 +88,11 @@ async fn main(spawner: Spawner) -> ! { | |||
| 88 | //}); | 88 | //}); |
| 89 | 89 | ||
| 90 | // Init network stack | 90 | // Init network stack |
| 91 | static STACK: StaticCell<Stack<Device>> = StaticCell::new(); | 91 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 92 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 92 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 93 | let stack = &*STACK.init(Stack::new( | ||
| 94 | device, | ||
| 95 | config, | ||
| 96 | RESOURCES.init(StackResources::<2>::new()), | ||
| 97 | seed, | ||
| 98 | )); | ||
| 99 | 93 | ||
| 100 | // Launch network task | 94 | // Launch network task |
| 101 | unwrap!(spawner.spawn(net_task(stack))); | 95 | unwrap!(spawner.spawn(net_task(runner))); |
| 102 | 96 | ||
| 103 | // Ensure DHCP configuration is up before trying connect | 97 | // Ensure DHCP configuration is up before trying connect |
| 104 | stack.wait_config_up().await; | 98 | stack.wait_config_up().await; |
| @@ -110,7 +104,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 110 | let mut tx_buffer = [0; 4096]; | 104 | let mut tx_buffer = [0; 4096]; |
| 111 | 105 | ||
| 112 | loop { | 106 | loop { |
| 113 | let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); | 107 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); |
| 114 | 108 | ||
| 115 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); | 109 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); |
| 116 | 110 | ||
diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs new file mode 100644 index 000000000..5946fed79 --- /dev/null +++ b/examples/stm32f4/src/bin/eth_compliance_test.rs | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::eth::generic_smi::GenericSMI; | ||
| 7 | use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement}; | ||
| 8 | use embassy_stm32::time::Hertz; | ||
| 9 | use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use static_cell::StaticCell; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | ETH => eth::InterruptHandler; | ||
| 16 | HASH_RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) -> ! { | ||
| 21 | let mut config = Config::default(); | ||
| 22 | { | ||
| 23 | use embassy_stm32::rcc::*; | ||
| 24 | config.rcc.hse = Some(Hse { | ||
| 25 | freq: Hertz(8_000_000), | ||
| 26 | mode: HseMode::Bypass, | ||
| 27 | }); | ||
| 28 | config.rcc.pll_src = PllSource::HSE; | ||
| 29 | config.rcc.pll = Some(Pll { | ||
| 30 | prediv: PllPreDiv::DIV4, | ||
| 31 | mul: PllMul::MUL180, | ||
| 32 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. | ||
| 33 | divq: None, | ||
| 34 | divr: None, | ||
| 35 | }); | ||
| 36 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 37 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 38 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 39 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 40 | } | ||
| 41 | let p = embassy_stm32::init(config); | ||
| 42 | |||
| 43 | info!("Hello Compliance World!"); | ||
| 44 | |||
| 45 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | ||
| 46 | |||
| 47 | const PHY_ADDR: u8 = 0; | ||
| 48 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); | ||
| 49 | let mut device = Ethernet::new( | ||
| 50 | PACKETS.init(PacketQueue::<4, 4>::new()), | ||
| 51 | p.ETH, | ||
| 52 | Irqs, | ||
| 53 | p.PA1, | ||
| 54 | p.PA2, | ||
| 55 | p.PC1, | ||
| 56 | p.PA7, | ||
| 57 | p.PC4, | ||
| 58 | p.PC5, | ||
| 59 | p.PG13, | ||
| 60 | p.PB13, | ||
| 61 | p.PG11, | ||
| 62 | GenericSMI::new(PHY_ADDR), | ||
| 63 | mac_addr, | ||
| 64 | ); | ||
| 65 | |||
| 66 | let sm = unsafe { device.station_management() }; | ||
| 67 | |||
| 68 | // Just an example. Exact register settings depend on the specific PHY and test. | ||
| 69 | sm.smi_write(PHY_ADDR, 0, 0x2100); | ||
| 70 | sm.smi_write(PHY_ADDR, 11, 0xA000); | ||
| 71 | |||
| 72 | // NB: Remember to reset the PHY after testing before starting the networking stack | ||
| 73 | |||
| 74 | loop { | ||
| 75 | Timer::after_secs(1).await; | ||
| 76 | } | ||
| 77 | } | ||
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs new file mode 100644 index 000000000..6e6bef08c --- /dev/null +++ b/examples/stm32f4/src/bin/eth_w5500.rs | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_net::tcp::TcpSocket; | ||
| 7 | use embassy_net::{Ipv4Address, StackResources}; | ||
| 8 | use embassy_net_wiznet::chip::W5500; | ||
| 9 | use embassy_net_wiznet::{Device, Runner, State}; | ||
| 10 | use embassy_stm32::exti::ExtiInput; | ||
| 11 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 12 | use embassy_stm32::mode::Async; | ||
| 13 | use embassy_stm32::rng::Rng; | ||
| 14 | use embassy_stm32::spi::Spi; | ||
| 15 | use embassy_stm32::time::Hertz; | ||
| 16 | use embassy_stm32::{bind_interrupts, peripherals, rng, spi, Config}; | ||
| 17 | use embassy_time::{Delay, Timer}; | ||
| 18 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 19 | use embedded_io_async::Write; | ||
| 20 | use static_cell::StaticCell; | ||
| 21 | use {defmt_rtt as _, panic_probe as _}; | ||
| 22 | |||
| 23 | bind_interrupts!(struct Irqs { | ||
| 24 | HASH_RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 25 | }); | ||
| 26 | |||
| 27 | type EthernetSPI = ExclusiveDevice<Spi<'static, Async>, Output<'static>, Delay>; | ||
| 28 | #[embassy_executor::task] | ||
| 29 | async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! { | ||
| 30 | runner.run().await | ||
| 31 | } | ||
| 32 | |||
| 33 | #[embassy_executor::task] | ||
| 34 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { | ||
| 35 | runner.run().await | ||
| 36 | } | ||
| 37 | |||
| 38 | #[embassy_executor::main] | ||
| 39 | async fn main(spawner: Spawner) -> ! { | ||
| 40 | let mut config = Config::default(); | ||
| 41 | { | ||
| 42 | use embassy_stm32::rcc::*; | ||
| 43 | config.rcc.hse = Some(Hse { | ||
| 44 | freq: Hertz(8_000_000), | ||
| 45 | mode: HseMode::Bypass, | ||
| 46 | }); | ||
| 47 | config.rcc.pll_src = PllSource::HSE; | ||
| 48 | config.rcc.pll = Some(Pll { | ||
| 49 | prediv: PllPreDiv::DIV4, | ||
| 50 | mul: PllMul::MUL180, | ||
| 51 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. | ||
| 52 | divq: None, | ||
| 53 | divr: None, | ||
| 54 | }); | ||
| 55 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 56 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 57 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 58 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 59 | } | ||
| 60 | let p = embassy_stm32::init(config); | ||
| 61 | |||
| 62 | info!("Hello World!"); | ||
| 63 | |||
| 64 | // Generate random seed | ||
| 65 | let mut rng = Rng::new(p.RNG, Irqs); | ||
| 66 | let mut seed = [0; 8]; | ||
| 67 | unwrap!(rng.async_fill_bytes(&mut seed).await); | ||
| 68 | let seed = u64::from_le_bytes(seed); | ||
| 69 | |||
| 70 | let mut spi_cfg = spi::Config::default(); | ||
| 71 | spi_cfg.frequency = Hertz(50_000_000); // up to 50m works | ||
| 72 | let (miso, mosi, clk) = (p.PA6, p.PA7, p.PA5); | ||
| 73 | let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA2_CH3, p.DMA2_CH0, spi_cfg); | ||
| 74 | let cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); | ||
| 75 | let spi = unwrap!(ExclusiveDevice::new(spi, cs, Delay)); | ||
| 76 | |||
| 77 | let w5500_int = ExtiInput::new(p.PB0, p.EXTI0, Pull::Up); | ||
| 78 | let w5500_reset = Output::new(p.PB1, Level::High, Speed::VeryHigh); | ||
| 79 | |||
| 80 | let mac_addr = [0x02, 234, 3, 4, 82, 231]; | ||
| 81 | static STATE: StaticCell<State<2, 2>> = StaticCell::new(); | ||
| 82 | let state = STATE.init(State::<2, 2>::new()); | ||
| 83 | let (device, runner) = embassy_net_wiznet::new(mac_addr, state, spi, w5500_int, w5500_reset) | ||
| 84 | .await | ||
| 85 | .unwrap(); | ||
| 86 | unwrap!(spawner.spawn(ethernet_task(runner))); | ||
| 87 | |||
| 88 | let config = embassy_net::Config::dhcpv4(Default::default()); | ||
| 89 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { | ||
| 90 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | ||
| 91 | // dns_servers: Vec::new(), | ||
| 92 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | ||
| 93 | //}); | ||
| 94 | |||
| 95 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | ||
| 96 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); | ||
| 97 | |||
| 98 | // Launch network task | ||
| 99 | unwrap!(spawner.spawn(net_task(runner))); | ||
| 100 | |||
| 101 | // Ensure DHCP configuration is up before trying connect | ||
| 102 | stack.wait_config_up().await; | ||
| 103 | |||
| 104 | info!("Network task initialized"); | ||
| 105 | |||
| 106 | // Then we can use it! | ||
| 107 | let mut rx_buffer = [0; 1024]; | ||
| 108 | let mut tx_buffer = [0; 1024]; | ||
| 109 | |||
| 110 | loop { | ||
| 111 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 112 | |||
| 113 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); | ||
| 114 | |||
| 115 | let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000); | ||
| 116 | info!("connecting..."); | ||
| 117 | let r = socket.connect(remote_endpoint).await; | ||
| 118 | if let Err(e) = r { | ||
| 119 | info!("connect error: {:?}", e); | ||
| 120 | Timer::after_secs(1).await; | ||
| 121 | continue; | ||
| 122 | } | ||
| 123 | info!("connected!"); | ||
| 124 | let buf = [0; 1024]; | ||
| 125 | loop { | ||
| 126 | let r = socket.write_all(&buf).await; | ||
| 127 | if let Err(e) = r { | ||
| 128 | info!("write error: {:?}", e); | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | Timer::after_secs(1).await; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | } | ||
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs index 4b5da774d..4a96357a4 100644 --- a/examples/stm32f4/src/bin/i2c.rs +++ b/examples/stm32f4/src/bin/i2c.rs | |||
| @@ -3,35 +3,19 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::i2c::{Error, I2c}; | 6 | use embassy_stm32::i2c::{Error, I2c}; |
| 8 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 9 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 9 | ||
| 12 | const ADDRESS: u8 = 0x5F; | 10 | const ADDRESS: u8 = 0x5F; |
| 13 | const WHOAMI: u8 = 0x0F; | 11 | const WHOAMI: u8 = 0x0F; |
| 14 | 12 | ||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||
| 17 | I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||
| 18 | }); | ||
| 19 | |||
| 20 | #[embassy_executor::main] | 13 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 14 | async fn main(_spawner: Spawner) { |
| 22 | info!("Hello world!"); | 15 | info!("Hello world!"); |
| 23 | let p = embassy_stm32::init(Default::default()); | 16 | let p = embassy_stm32::init(Default::default()); |
| 24 | 17 | ||
| 25 | let mut i2c = I2c::new( | 18 | let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); |
| 26 | p.I2C2, | ||
| 27 | p.PB10, | ||
| 28 | p.PB11, | ||
| 29 | Irqs, | ||
| 30 | NoDma, | ||
| 31 | NoDma, | ||
| 32 | Hertz(100_000), | ||
| 33 | Default::default(), | ||
| 34 | ); | ||
| 35 | 19 | ||
| 36 | let mut data = [0u8; 1]; | 20 | let mut data = [0u8; 1]; |
| 37 | 21 | ||
diff --git a/examples/stm32f4/src/bin/i2c_comparison.rs b/examples/stm32f4/src/bin/i2c_comparison.rs index 30cfbdf57..55c4891e3 100644 --- a/examples/stm32f4/src/bin/i2c_comparison.rs +++ b/examples/stm32f4/src/bin/i2c_comparison.rs | |||
| @@ -13,7 +13,7 @@ use embassy_stm32::i2c::I2c; | |||
| 13 | use embassy_stm32::time::Hertz; | 13 | use embassy_stm32::time::Hertz; |
| 14 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | 14 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; |
| 15 | use embassy_time::Instant; | 15 | use embassy_time::Instant; |
| 16 | use futures::future::try_join3; | 16 | use futures_util::future::try_join3; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 18 | ||
| 19 | const ADDRESS: u8 = 96; | 19 | const ADDRESS: u8 = 96; |
diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs index 97a04b2aa..27b165f1b 100644 --- a/examples/stm32f4/src/bin/i2s_dma.rs +++ b/examples/stm32f4/src/bin/i2s_dma.rs | |||
| @@ -15,14 +15,13 @@ async fn main(_spawner: Spawner) { | |||
| 15 | let p = embassy_stm32::init(Default::default()); | 15 | let p = embassy_stm32::init(Default::default()); |
| 16 | info!("Hello World!"); | 16 | info!("Hello World!"); |
| 17 | 17 | ||
| 18 | let mut i2s = I2S::new( | 18 | let mut i2s = I2S::new_txonly( |
| 19 | p.SPI2, | 19 | p.SPI2, |
| 20 | p.PC3, // sd | 20 | p.PC3, // sd |
| 21 | p.PB12, // ws | 21 | p.PB12, // ws |
| 22 | p.PB10, // ck | 22 | p.PB10, // ck |
| 23 | p.PC6, // mck | 23 | p.PC6, // mck |
| 24 | p.DMA1_CH4, | 24 | p.DMA1_CH4, |
| 25 | p.DMA1_CH3, | ||
| 26 | Hertz(1_000_000), | 25 | Hertz(1_000_000), |
| 27 | Config::default(), | 26 | Config::default(), |
| 28 | ); | 27 | ); |
diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs new file mode 100644 index 000000000..49de33d2b --- /dev/null +++ b/examples/stm32f4/src/bin/input_capture.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 7 | use embassy_stm32::time::khz; | ||
| 8 | use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; | ||
| 9 | use embassy_stm32::timer::{self, Channel}; | ||
| 10 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 11 | use embassy_time::Timer; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | /// Connect PB2 and PB10 with a 1k Ohm resistor | ||
| 15 | |||
| 16 | #[embassy_executor::task] | ||
| 17 | async fn blinky(led: peripherals::PB2) { | ||
| 18 | let mut led = Output::new(led, Level::High, Speed::Low); | ||
| 19 | |||
| 20 | loop { | ||
| 21 | info!("high"); | ||
| 22 | led.set_high(); | ||
| 23 | Timer::after_millis(300).await; | ||
| 24 | |||
| 25 | info!("low"); | ||
| 26 | led.set_low(); | ||
| 27 | Timer::after_millis(300).await; | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | bind_interrupts!(struct Irqs { | ||
| 32 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 33 | }); | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(spawner: Spawner) { | ||
| 37 | let p = embassy_stm32::init(Default::default()); | ||
| 38 | info!("Hello World!"); | ||
| 39 | |||
| 40 | unwrap!(spawner.spawn(blinky(p.PB2))); | ||
| 41 | |||
| 42 | let ch3 = CapturePin::new_ch3(p.PB10, Pull::None); | ||
| 43 | let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default()); | ||
| 44 | |||
| 45 | loop { | ||
| 46 | info!("wait for risign edge"); | ||
| 47 | ic.wait_for_rising_edge(Channel::Ch3).await; | ||
| 48 | |||
| 49 | let capture_value = ic.get_capture_value(Channel::Ch3); | ||
| 50 | info!("new capture! {}", capture_value); | ||
| 51 | } | ||
| 52 | } | ||
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 328447210..b4620888f 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs | |||
| @@ -80,7 +80,7 @@ async fn run_med() { | |||
| 80 | info!(" [med] Starting long computation"); | 80 | info!(" [med] Starting long computation"); |
| 81 | 81 | ||
| 82 | // Spin-wait to simulate a long CPU computation | 82 | // Spin-wait to simulate a long CPU computation |
| 83 | cortex_m::asm::delay(8_000_000); // ~1 second | 83 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second |
| 84 | 84 | ||
| 85 | let end = Instant::now(); | 85 | let end = Instant::now(); |
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | 86 | let ms = end.duration_since(start).as_ticks() / 33; |
| @@ -97,7 +97,7 @@ async fn run_low() { | |||
| 97 | info!("[low] Starting long computation"); | 97 | info!("[low] Starting long computation"); |
| 98 | 98 | ||
| 99 | // Spin-wait to simulate a long CPU computation | 99 | // Spin-wait to simulate a long CPU computation |
| 100 | cortex_m::asm::delay(16_000_000); // ~2 seconds | 100 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds |
| 101 | 101 | ||
| 102 | let end = Instant::now(); | 102 | let end = Instant::now(); |
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | 103 | let ms = end.duration_since(start).as_ticks() / 33; |
| @@ -127,6 +127,11 @@ fn main() -> ! { | |||
| 127 | 127 | ||
| 128 | let _p = embassy_stm32::init(Default::default()); | 128 | let _p = embassy_stm32::init(Default::default()); |
| 129 | 129 | ||
| 130 | // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as | ||
| 131 | // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. | ||
| 132 | // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt | ||
| 133 | // vector would work exactly the same. | ||
| 134 | |||
| 130 | // High-priority executor: UART4, priority level 6 | 135 | // High-priority executor: UART4, priority level 6 |
| 131 | interrupt::UART4.set_priority(Priority::P6); | 136 | interrupt::UART4.set_priority(Priority::P6); |
| 132 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); | 137 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); |
diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs new file mode 100644 index 000000000..ce200549d --- /dev/null +++ b/examples/stm32f4/src/bin/pwm_input.rs | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 7 | use embassy_stm32::time::khz; | ||
| 8 | use embassy_stm32::timer::pwm_input::PwmInput; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, timer}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | /// Connect PB2 and PA6 with a 1k Ohm resistor | ||
| 14 | |||
| 15 | #[embassy_executor::task] | ||
| 16 | async fn blinky(led: peripherals::PB2) { | ||
| 17 | let mut led = Output::new(led, Level::High, Speed::Low); | ||
| 18 | |||
| 19 | loop { | ||
| 20 | info!("high"); | ||
| 21 | led.set_high(); | ||
| 22 | Timer::after_millis(300).await; | ||
| 23 | |||
| 24 | info!("low"); | ||
| 25 | led.set_low(); | ||
| 26 | Timer::after_millis(300).await; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::main] | ||
| 35 | async fn main(spawner: Spawner) { | ||
| 36 | let p = embassy_stm32::init(Default::default()); | ||
| 37 | info!("Hello World!"); | ||
| 38 | |||
| 39 | unwrap!(spawner.spawn(blinky(p.PB2))); | ||
| 40 | |||
| 41 | let mut pwm_input = PwmInput::new(p.TIM3, p.PA6, Pull::None, khz(10)); | ||
| 42 | pwm_input.enable(); | ||
| 43 | |||
| 44 | loop { | ||
| 45 | Timer::after_millis(500).await; | ||
| 46 | let period = pwm_input.get_period_ticks(); | ||
| 47 | let width = pwm_input.get_width_ticks(); | ||
| 48 | let duty_cycle = pwm_input.get_duty_cycle(); | ||
| 49 | info!( | ||
| 50 | "period ticks: {} width ticks: {} duty cycle: {}", | ||
| 51 | period, width, duty_cycle | ||
| 52 | ); | ||
| 53 | } | ||
| 54 | } | ||
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index abab07b6b..82d8a37ba 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs | |||
| @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { | |||
| 28 | loop { | 28 | loop { |
| 29 | let now: NaiveDateTime = rtc.now().unwrap().into(); | 29 | let now: NaiveDateTime = rtc.now().unwrap().into(); |
| 30 | 30 | ||
| 31 | info!("{}", now.timestamp()); | 31 | info!("{}", now.and_utc().timestamp()); |
| 32 | 32 | ||
| 33 | Timer::after_millis(1000).await; | 33 | Timer::after_millis(1000).await; |
| 34 | } | 34 | } |
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index dc9141c62..970d819fc 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| @@ -18,7 +17,7 @@ fn main() -> ! { | |||
| 18 | let mut spi_config = Config::default(); | 17 | let mut spi_config = Config::default(); |
| 19 | spi_config.frequency = Hertz(1_000_000); | 18 | spi_config.frequency = Hertz(1_000_000); |
| 20 | 19 | ||
| 21 | let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); | 20 | let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); |
| 22 | 21 | ||
| 23 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); | 22 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); |
| 24 | 23 | ||
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 40d9d70f1..991bf6673 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | 6 | use embassy_stm32::usart::{Config, Uart}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 7 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -19,7 +18,7 @@ fn main() -> ! { | |||
| 19 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(Default::default()); |
| 20 | 19 | ||
| 21 | let config = Config::default(); | 20 | let config = Config::default(); |
| 22 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap(); | 21 | let mut usart = Uart::new_blocking(p.USART3, p.PD9, p.PD8, config).unwrap(); |
| 23 | 22 | ||
| 24 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 23 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 25 | info!("wrote Hello, starting echo"); | 24 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index dd6de599c..aaf8d6c4f 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs | |||
| @@ -5,7 +5,6 @@ use core::fmt::Write; | |||
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use heapless::String; |
| @@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) { | |||
| 21 | info!("Hello World!"); | 20 | info!("Hello World!"); |
| 22 | 21 | ||
| 23 | let config = Config::default(); | 22 | let config = Config::default(); |
| 24 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); | 23 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, p.DMA1_CH1, config).unwrap(); |
| 25 | 24 | ||
| 26 | for n in 0u32.. { | 25 | for n in 0u32.. { |
| 27 | let mut s: String<128> = String::new(); | 26 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index a196259a8..a9504ec04 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs | |||
| @@ -4,11 +4,11 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::rng::{self, Rng}; | 8 | use embassy_stm32::rng::{self, Rng}; |
| 9 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_stm32::usb_otg::Driver; | 10 | use embassy_stm32::usb::Driver; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 11 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 12 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | 12 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; |
| 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 14 | use embassy_usb::{Builder, UsbDevice}; | 14 | use embassy_usb::{Builder, UsbDevice}; |
| @@ -31,15 +31,20 @@ async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! { | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | #[embassy_executor::task] | 33 | #[embassy_executor::task] |
| 34 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 34 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { |
| 35 | stack.run().await | 35 | runner.run().await |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | bind_interrupts!(struct Irqs { | 38 | bind_interrupts!(struct Irqs { |
| 39 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 39 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 40 | HASH_RNG => rng::InterruptHandler<peripherals::RNG>; | 40 | HASH_RNG => rng::InterruptHandler<peripherals::RNG>; |
| 41 | }); | 41 | }); |
| 42 | 42 | ||
| 43 | // If you are trying this and your USB device doesn't connect, the most | ||
| 44 | // common issues are the RCC config and vbus_detection | ||
| 45 | // | ||
| 46 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 47 | // for more information. | ||
| 43 | #[embassy_executor::main] | 48 | #[embassy_executor::main] |
| 44 | async fn main(spawner: Spawner) { | 49 | async fn main(spawner: Spawner) { |
| 45 | info!("Hello World!"); | 50 | info!("Hello World!"); |
| @@ -63,14 +68,21 @@ async fn main(spawner: Spawner) { | |||
| 63 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 68 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 64 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 69 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 65 | config.rcc.sys = Sysclk::PLL1_P; | 70 | config.rcc.sys = Sysclk::PLL1_P; |
| 71 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 66 | } | 72 | } |
| 67 | let p = embassy_stm32::init(config); | 73 | let p = embassy_stm32::init(config); |
| 68 | 74 | ||
| 69 | // Create the driver, from the HAL. | 75 | // Create the driver, from the HAL. |
| 70 | static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); | 76 | static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); |
| 71 | let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; | 77 | let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; |
| 72 | let mut config = embassy_stm32::usb_otg::Config::default(); | 78 | let mut config = embassy_stm32::usb::Config::default(); |
| 73 | config.vbus_detection = true; | 79 | |
| 80 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 81 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 82 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 83 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 84 | config.vbus_detection = false; | ||
| 85 | |||
| 74 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); | 86 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); |
| 75 | 87 | ||
| 76 | // Create embassy-usb Config | 88 | // Create embassy-usb Config |
| @@ -88,14 +100,12 @@ async fn main(spawner: Spawner) { | |||
| 88 | config.device_protocol = 0x01; | 100 | config.device_protocol = 0x01; |
| 89 | 101 | ||
| 90 | // Create embassy-usb DeviceBuilder using the driver and config. | 102 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 91 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 92 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 103 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 93 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 104 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 94 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 105 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 95 | let mut builder = Builder::new( | 106 | let mut builder = Builder::new( |
| 96 | driver, | 107 | driver, |
| 97 | config, | 108 | config, |
| 98 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 99 | &mut CONFIG_DESC.init([0; 256])[..], | 109 | &mut CONFIG_DESC.init([0; 256])[..], |
| 100 | &mut BOS_DESC.init([0; 256])[..], | 110 | &mut BOS_DESC.init([0; 256])[..], |
| 101 | &mut [], // no msos descriptors | 111 | &mut [], // no msos descriptors |
| @@ -134,16 +144,10 @@ async fn main(spawner: Spawner) { | |||
| 134 | let seed = u64::from_le_bytes(seed); | 144 | let seed = u64::from_le_bytes(seed); |
| 135 | 145 | ||
| 136 | // Init network stack | 146 | // Init network stack |
| 137 | static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); | 147 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 138 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 148 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 139 | let stack = &*STACK.init(Stack::new( | ||
| 140 | device, | ||
| 141 | config, | ||
| 142 | RESOURCES.init(StackResources::<2>::new()), | ||
| 143 | seed, | ||
| 144 | )); | ||
| 145 | 149 | ||
| 146 | unwrap!(spawner.spawn(net_task(stack))); | 150 | unwrap!(spawner.spawn(net_task(runner))); |
| 147 | 151 | ||
| 148 | // And now we can use it! | 152 | // And now we can use it! |
| 149 | 153 | ||
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs new file mode 100644 index 000000000..1270995c4 --- /dev/null +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_futures::join::join; | ||
| 9 | use embassy_stm32::exti::ExtiInput; | ||
| 10 | use embassy_stm32::gpio::Pull; | ||
| 11 | use embassy_stm32::time::Hertz; | ||
| 12 | use embassy_stm32::usb::Driver; | ||
| 13 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||
| 14 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | ||
| 15 | use embassy_usb::control::OutResponse; | ||
| 16 | use embassy_usb::{Builder, Handler}; | ||
| 17 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | bind_interrupts!(struct Irqs { | ||
| 21 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; | ||
| 22 | }); | ||
| 23 | |||
| 24 | // If you are trying this and your USB device doesn't connect, the most | ||
| 25 | // common issues are the RCC config and vbus_detection | ||
| 26 | // | ||
| 27 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 28 | // for more information. | ||
| 29 | #[embassy_executor::main] | ||
| 30 | async fn main(_spawner: Spawner) { | ||
| 31 | let mut config = Config::default(); | ||
| 32 | { | ||
| 33 | use embassy_stm32::rcc::*; | ||
| 34 | config.rcc.hse = Some(Hse { | ||
| 35 | freq: Hertz(8_000_000), | ||
| 36 | mode: HseMode::Bypass, | ||
| 37 | }); | ||
| 38 | config.rcc.pll_src = PllSource::HSE; | ||
| 39 | config.rcc.pll = Some(Pll { | ||
| 40 | prediv: PllPreDiv::DIV4, | ||
| 41 | mul: PllMul::MUL168, | ||
| 42 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | ||
| 43 | divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | ||
| 44 | divr: None, | ||
| 45 | }); | ||
| 46 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 47 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 48 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 49 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 50 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 51 | } | ||
| 52 | let p = embassy_stm32::init(config); | ||
| 53 | |||
| 54 | // Create the driver, from the HAL. | ||
| 55 | let mut ep_out_buffer = [0u8; 256]; | ||
| 56 | let mut config = embassy_stm32::usb::Config::default(); | ||
| 57 | |||
| 58 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 59 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 60 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 61 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 62 | config.vbus_detection = false; | ||
| 63 | |||
| 64 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||
| 65 | |||
| 66 | // Create embassy-usb Config | ||
| 67 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 68 | config.manufacturer = Some("Embassy"); | ||
| 69 | config.product = Some("HID keyboard example"); | ||
| 70 | config.serial_number = Some("12345678"); | ||
| 71 | config.max_power = 100; | ||
| 72 | config.max_packet_size_0 = 64; | ||
| 73 | |||
| 74 | // Required for windows compatibility. | ||
| 75 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 76 | config.device_class = 0xEF; | ||
| 77 | config.device_sub_class = 0x02; | ||
| 78 | config.device_protocol = 0x01; | ||
| 79 | config.composite_with_iads = true; | ||
| 80 | |||
| 81 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 82 | // It needs some buffers for building the descriptors. | ||
| 83 | let mut config_descriptor = [0; 256]; | ||
| 84 | let mut bos_descriptor = [0; 256]; | ||
| 85 | // You can also add a Microsoft OS descriptor. | ||
| 86 | let mut msos_descriptor = [0; 256]; | ||
| 87 | let mut control_buf = [0; 64]; | ||
| 88 | |||
| 89 | let mut request_handler = MyRequestHandler {}; | ||
| 90 | let mut device_handler = MyDeviceHandler::new(); | ||
| 91 | |||
| 92 | let mut state = State::new(); | ||
| 93 | |||
| 94 | let mut builder = Builder::new( | ||
| 95 | driver, | ||
| 96 | config, | ||
| 97 | &mut config_descriptor, | ||
| 98 | &mut bos_descriptor, | ||
| 99 | &mut msos_descriptor, | ||
| 100 | &mut control_buf, | ||
| 101 | ); | ||
| 102 | |||
| 103 | builder.handler(&mut device_handler); | ||
| 104 | |||
| 105 | // Create classes on the builder. | ||
| 106 | let config = embassy_usb::class::hid::Config { | ||
| 107 | report_descriptor: KeyboardReport::desc(), | ||
| 108 | request_handler: None, | ||
| 109 | poll_ms: 60, | ||
| 110 | max_packet_size: 8, | ||
| 111 | }; | ||
| 112 | |||
| 113 | let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); | ||
| 114 | |||
| 115 | // Build the builder. | ||
| 116 | let mut usb = builder.build(); | ||
| 117 | |||
| 118 | // Run the USB device. | ||
| 119 | let usb_fut = usb.run(); | ||
| 120 | |||
| 121 | let (reader, mut writer) = hid.split(); | ||
| 122 | |||
| 123 | let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); | ||
| 124 | |||
| 125 | // Do stuff with the class! | ||
| 126 | let in_fut = async { | ||
| 127 | loop { | ||
| 128 | button.wait_for_rising_edge().await; | ||
| 129 | // signal_pin.wait_for_high().await; | ||
| 130 | info!("Button pressed!"); | ||
| 131 | // Create a report with the A key pressed. (no shift modifier) | ||
| 132 | let report = KeyboardReport { | ||
| 133 | keycodes: [4, 0, 0, 0, 0, 0], | ||
| 134 | leds: 0, | ||
| 135 | modifier: 0, | ||
| 136 | reserved: 0, | ||
| 137 | }; | ||
| 138 | // Send the report. | ||
| 139 | match writer.write_serialize(&report).await { | ||
| 140 | Ok(()) => {} | ||
| 141 | Err(e) => warn!("Failed to send report: {:?}", e), | ||
| 142 | }; | ||
| 143 | |||
| 144 | button.wait_for_falling_edge().await; | ||
| 145 | // signal_pin.wait_for_low().await; | ||
| 146 | info!("Button released!"); | ||
| 147 | let report = KeyboardReport { | ||
| 148 | keycodes: [0, 0, 0, 0, 0, 0], | ||
| 149 | leds: 0, | ||
| 150 | modifier: 0, | ||
| 151 | reserved: 0, | ||
| 152 | }; | ||
| 153 | match writer.write_serialize(&report).await { | ||
| 154 | Ok(()) => {} | ||
| 155 | Err(e) => warn!("Failed to send report: {:?}", e), | ||
| 156 | }; | ||
| 157 | } | ||
| 158 | }; | ||
| 159 | |||
| 160 | let out_fut = async { | ||
| 161 | reader.run(false, &mut request_handler).await; | ||
| 162 | }; | ||
| 163 | |||
| 164 | // Run everything concurrently. | ||
| 165 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 166 | join(usb_fut, join(in_fut, out_fut)).await; | ||
| 167 | } | ||
| 168 | |||
| 169 | struct MyRequestHandler {} | ||
| 170 | |||
| 171 | impl RequestHandler for MyRequestHandler { | ||
| 172 | fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | ||
| 173 | info!("Get report for {:?}", id); | ||
| 174 | None | ||
| 175 | } | ||
| 176 | |||
| 177 | fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { | ||
| 178 | info!("Set report for {:?}: {=[u8]}", id, data); | ||
| 179 | OutResponse::Accepted | ||
| 180 | } | ||
| 181 | |||
| 182 | fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { | ||
| 183 | info!("Set idle rate for {:?} to {:?}", id, dur); | ||
| 184 | } | ||
| 185 | |||
| 186 | fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> { | ||
| 187 | info!("Get idle rate for {:?}", id); | ||
| 188 | None | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | struct MyDeviceHandler { | ||
| 193 | configured: AtomicBool, | ||
| 194 | } | ||
| 195 | |||
| 196 | impl MyDeviceHandler { | ||
| 197 | fn new() -> Self { | ||
| 198 | MyDeviceHandler { | ||
| 199 | configured: AtomicBool::new(false), | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | impl Handler for MyDeviceHandler { | ||
| 205 | fn enabled(&mut self, enabled: bool) { | ||
| 206 | self.configured.store(false, Ordering::Relaxed); | ||
| 207 | if enabled { | ||
| 208 | info!("Device enabled"); | ||
| 209 | } else { | ||
| 210 | info!("Device disabled"); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | fn reset(&mut self) { | ||
| 215 | self.configured.store(false, Ordering::Relaxed); | ||
| 216 | info!("Bus reset, the Vbus current limit is 100mA"); | ||
| 217 | } | ||
| 218 | |||
| 219 | fn addressed(&mut self, addr: u8) { | ||
| 220 | self.configured.store(false, Ordering::Relaxed); | ||
| 221 | info!("USB address set to: {}", addr); | ||
| 222 | } | ||
| 223 | |||
| 224 | fn configured(&mut self, configured: bool) { | ||
| 225 | self.configured.store(configured, Ordering::Relaxed); | ||
| 226 | if configured { | ||
| 227 | info!("Device configured, it may now draw up to the configured current limit from Vbus.") | ||
| 228 | } else { | ||
| 229 | info!("Device is no longer configured, the Vbus current limit is 100mA."); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | } | ||
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs new file mode 100644 index 000000000..45136f965 --- /dev/null +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs | |||
| @@ -0,0 +1,158 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_futures::join::join; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::usb::Driver; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | ||
| 12 | use embassy_usb::control::OutResponse; | ||
| 13 | use embassy_usb::Builder; | ||
| 14 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; | ||
| 19 | }); | ||
| 20 | |||
| 21 | // If you are trying this and your USB device doesn't connect, the most | ||
| 22 | // common issues are the RCC config and vbus_detection | ||
| 23 | // | ||
| 24 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 25 | // for more information. | ||
| 26 | #[embassy_executor::main] | ||
| 27 | async fn main(_spawner: Spawner) { | ||
| 28 | let mut config = Config::default(); | ||
| 29 | { | ||
| 30 | use embassy_stm32::rcc::*; | ||
| 31 | config.rcc.hse = Some(Hse { | ||
| 32 | freq: Hertz(8_000_000), | ||
| 33 | mode: HseMode::Bypass, | ||
| 34 | }); | ||
| 35 | config.rcc.pll_src = PllSource::HSE; | ||
| 36 | config.rcc.pll = Some(Pll { | ||
| 37 | prediv: PllPreDiv::DIV4, | ||
| 38 | mul: PllMul::MUL168, | ||
| 39 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | ||
| 40 | divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | ||
| 41 | divr: None, | ||
| 42 | }); | ||
| 43 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 44 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 45 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 46 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 47 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 48 | } | ||
| 49 | let p = embassy_stm32::init(config); | ||
| 50 | |||
| 51 | // Create the driver, from the HAL. | ||
| 52 | let mut ep_out_buffer = [0u8; 256]; | ||
| 53 | let mut config = embassy_stm32::usb::Config::default(); | ||
| 54 | |||
| 55 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 56 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 57 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 58 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 59 | config.vbus_detection = false; | ||
| 60 | |||
| 61 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||
| 62 | |||
| 63 | // Create embassy-usb Config | ||
| 64 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 65 | config.manufacturer = Some("Embassy"); | ||
| 66 | config.product = Some("HID mouse example"); | ||
| 67 | config.serial_number = Some("12345678"); | ||
| 68 | |||
| 69 | // Required for windows compatibility. | ||
| 70 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 71 | config.device_class = 0xEF; | ||
| 72 | config.device_sub_class = 0x02; | ||
| 73 | config.device_protocol = 0x01; | ||
| 74 | config.composite_with_iads = true; | ||
| 75 | |||
| 76 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 77 | // It needs some buffers for building the descriptors. | ||
| 78 | let mut config_descriptor = [0; 256]; | ||
| 79 | let mut bos_descriptor = [0; 256]; | ||
| 80 | let mut control_buf = [0; 64]; | ||
| 81 | |||
| 82 | let mut request_handler = MyRequestHandler {}; | ||
| 83 | |||
| 84 | let mut state = State::new(); | ||
| 85 | |||
| 86 | let mut builder = Builder::new( | ||
| 87 | driver, | ||
| 88 | config, | ||
| 89 | &mut config_descriptor, | ||
| 90 | &mut bos_descriptor, | ||
| 91 | &mut [], // no msos descriptors | ||
| 92 | &mut control_buf, | ||
| 93 | ); | ||
| 94 | |||
| 95 | // Create classes on the builder. | ||
| 96 | let config = embassy_usb::class::hid::Config { | ||
| 97 | report_descriptor: MouseReport::desc(), | ||
| 98 | request_handler: Some(&mut request_handler), | ||
| 99 | poll_ms: 60, | ||
| 100 | max_packet_size: 8, | ||
| 101 | }; | ||
| 102 | |||
| 103 | let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); | ||
| 104 | |||
| 105 | // Build the builder. | ||
| 106 | let mut usb = builder.build(); | ||
| 107 | |||
| 108 | // Run the USB device. | ||
| 109 | let usb_fut = usb.run(); | ||
| 110 | |||
| 111 | // Do stuff with the class! | ||
| 112 | let hid_fut = async { | ||
| 113 | let mut y: i8 = 5; | ||
| 114 | loop { | ||
| 115 | Timer::after_millis(500).await; | ||
| 116 | |||
| 117 | y = -y; | ||
| 118 | let report = MouseReport { | ||
| 119 | buttons: 0, | ||
| 120 | x: 0, | ||
| 121 | y, | ||
| 122 | wheel: 0, | ||
| 123 | pan: 0, | ||
| 124 | }; | ||
| 125 | match writer.write_serialize(&report).await { | ||
| 126 | Ok(()) => {} | ||
| 127 | Err(e) => warn!("Failed to send report: {:?}", e), | ||
| 128 | } | ||
| 129 | } | ||
| 130 | }; | ||
| 131 | |||
| 132 | // Run everything concurrently. | ||
| 133 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 134 | join(usb_fut, hid_fut).await; | ||
| 135 | } | ||
| 136 | |||
| 137 | struct MyRequestHandler {} | ||
| 138 | |||
| 139 | impl RequestHandler for MyRequestHandler { | ||
| 140 | fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | ||
| 141 | info!("Get report for {:?}", id); | ||
| 142 | None | ||
| 143 | } | ||
| 144 | |||
| 145 | fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { | ||
| 146 | info!("Set report for {:?}: {=[u8]}", id, data); | ||
| 147 | OutResponse::Accepted | ||
| 148 | } | ||
| 149 | |||
| 150 | fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { | ||
| 151 | info!("Set idle rate for {:?} to {:?}", id, dur); | ||
| 152 | } | ||
| 153 | |||
| 154 | fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> { | ||
| 155 | info!("Get idle rate for {:?}", id); | ||
| 156 | None | ||
| 157 | } | ||
| 158 | } | ||
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index afff55187..b2d706208 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs | |||
| @@ -52,8 +52,8 @@ | |||
| 52 | use defmt::*; | 52 | use defmt::*; |
| 53 | use embassy_executor::Spawner; | 53 | use embassy_executor::Spawner; |
| 54 | use embassy_stm32::time::Hertz; | 54 | use embassy_stm32::time::Hertz; |
| 55 | use embassy_stm32::usb_otg::Driver; | 55 | use embassy_stm32::usb::Driver; |
| 56 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 56 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 57 | use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; | 57 | use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; |
| 58 | use embassy_usb::msos::{self, windows_version}; | 58 | use embassy_usb::msos::{self, windows_version}; |
| 59 | use embassy_usb::types::InterfaceNumber; | 59 | use embassy_usb::types::InterfaceNumber; |
| @@ -66,9 +66,14 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 66 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"]; | 66 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{DAC2087C-63FA-458D-A55D-827C0762DEC7}"]; |
| 67 | 67 | ||
| 68 | bind_interrupts!(struct Irqs { | 68 | bind_interrupts!(struct Irqs { |
| 69 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 69 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 70 | }); | 70 | }); |
| 71 | 71 | ||
| 72 | // If you are trying this and your USB device doesn't connect, the most | ||
| 73 | // common issues are the RCC config and vbus_detection | ||
| 74 | // | ||
| 75 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 76 | // for more information. | ||
| 72 | #[embassy_executor::main] | 77 | #[embassy_executor::main] |
| 73 | async fn main(_spawner: Spawner) { | 78 | async fn main(_spawner: Spawner) { |
| 74 | info!("Hello World!"); | 79 | info!("Hello World!"); |
| @@ -92,13 +97,20 @@ async fn main(_spawner: Spawner) { | |||
| 92 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 97 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 93 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 98 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 94 | config.rcc.sys = Sysclk::PLL1_P; | 99 | config.rcc.sys = Sysclk::PLL1_P; |
| 100 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 95 | } | 101 | } |
| 96 | let p = embassy_stm32::init(config); | 102 | let p = embassy_stm32::init(config); |
| 97 | 103 | ||
| 98 | // Create the driver, from the HAL. | 104 | // Create the driver, from the HAL. |
| 99 | let mut ep_out_buffer = [0u8; 256]; | 105 | let mut ep_out_buffer = [0u8; 256]; |
| 100 | let mut config = embassy_stm32::usb_otg::Config::default(); | 106 | let mut config = embassy_stm32::usb::Config::default(); |
| 101 | config.vbus_detection = true; | 107 | |
| 108 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 109 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 110 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 111 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 112 | config.vbus_detection = false; | ||
| 113 | |||
| 102 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 114 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 103 | 115 | ||
| 104 | // Create embassy-usb Config | 116 | // Create embassy-usb Config |
| @@ -116,7 +128,6 @@ async fn main(_spawner: Spawner) { | |||
| 116 | 128 | ||
| 117 | // Create embassy-usb DeviceBuilder using the driver and config. | 129 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 118 | // It needs some buffers for building the descriptors. | 130 | // It needs some buffers for building the descriptors. |
| 119 | let mut device_descriptor = [0; 256]; | ||
| 120 | let mut config_descriptor = [0; 256]; | 131 | let mut config_descriptor = [0; 256]; |
| 121 | let mut bos_descriptor = [0; 256]; | 132 | let mut bos_descriptor = [0; 256]; |
| 122 | let mut msos_descriptor = [0; 256]; | 133 | let mut msos_descriptor = [0; 256]; |
| @@ -129,7 +140,6 @@ async fn main(_spawner: Spawner) { | |||
| 129 | let mut builder = Builder::new( | 140 | let mut builder = Builder::new( |
| 130 | driver, | 141 | driver, |
| 131 | config, | 142 | config, |
| 132 | &mut device_descriptor, | ||
| 133 | &mut config_descriptor, | 143 | &mut config_descriptor, |
| 134 | &mut bos_descriptor, | 144 | &mut bos_descriptor, |
| 135 | &mut msos_descriptor, | 145 | &mut msos_descriptor, |
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 58d994a61..328b5effe 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs | |||
| @@ -3,19 +3,24 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | ||
| 6 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 7 | use embassy_stm32::usb_otg::{Driver, Instance}; | 8 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 10 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| 11 | use embassy_usb::Builder; | 12 | use embassy_usb::Builder; |
| 12 | use futures::future::join; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 16 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 17 | }); | 17 | }); |
| 18 | 18 | ||
| 19 | // If you are trying this and your USB device doesn't connect, the most | ||
| 20 | // common issues are the RCC config and vbus_detection | ||
| 21 | // | ||
| 22 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 23 | // for more information. | ||
| 19 | #[embassy_executor::main] | 24 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) { | 25 | async fn main(_spawner: Spawner) { |
| 21 | info!("Hello World!"); | 26 | info!("Hello World!"); |
| @@ -39,13 +44,20 @@ async fn main(_spawner: Spawner) { | |||
| 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 44 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 45 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 41 | config.rcc.sys = Sysclk::PLL1_P; | 46 | config.rcc.sys = Sysclk::PLL1_P; |
| 47 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 42 | } | 48 | } |
| 43 | let p = embassy_stm32::init(config); | 49 | let p = embassy_stm32::init(config); |
| 44 | 50 | ||
| 45 | // Create the driver, from the HAL. | 51 | // Create the driver, from the HAL. |
| 46 | let mut ep_out_buffer = [0u8; 256]; | 52 | let mut ep_out_buffer = [0u8; 256]; |
| 47 | let mut config = embassy_stm32::usb_otg::Config::default(); | 53 | let mut config = embassy_stm32::usb::Config::default(); |
| 48 | config.vbus_detection = true; | 54 | |
| 55 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 56 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 57 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 58 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 59 | config.vbus_detection = false; | ||
| 60 | |||
| 49 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 61 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 50 | 62 | ||
| 51 | // Create embassy-usb Config | 63 | // Create embassy-usb Config |
| @@ -63,7 +75,6 @@ async fn main(_spawner: Spawner) { | |||
| 63 | 75 | ||
| 64 | // Create embassy-usb DeviceBuilder using the driver and config. | 76 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 65 | // It needs some buffers for building the descriptors. | 77 | // It needs some buffers for building the descriptors. |
| 66 | let mut device_descriptor = [0; 256]; | ||
| 67 | let mut config_descriptor = [0; 256]; | 78 | let mut config_descriptor = [0; 256]; |
| 68 | let mut bos_descriptor = [0; 256]; | 79 | let mut bos_descriptor = [0; 256]; |
| 69 | let mut control_buf = [0; 64]; | 80 | let mut control_buf = [0; 64]; |
| @@ -73,7 +84,6 @@ async fn main(_spawner: Spawner) { | |||
| 73 | let mut builder = Builder::new( | 84 | let mut builder = Builder::new( |
| 74 | driver, | 85 | driver, |
| 75 | config, | 86 | config, |
| 76 | &mut device_descriptor, | ||
| 77 | &mut config_descriptor, | 87 | &mut config_descriptor, |
| 78 | &mut bos_descriptor, | 88 | &mut bos_descriptor, |
| 79 | &mut [], // no msos descriptors | 89 | &mut [], // no msos descriptors |
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 6122cea2d..cbaff75fc 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs | |||
| @@ -15,8 +15,9 @@ | |||
| 15 | use embassy_executor::Spawner; | 15 | use embassy_executor::Spawner; |
| 16 | use embassy_stm32::gpio::OutputType; | 16 | use embassy_stm32::gpio::OutputType; |
| 17 | use embassy_stm32::time::khz; | 17 | use embassy_stm32::time::khz; |
| 18 | use embassy_stm32::timer::low_level::CountingMode; | ||
| 18 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; | 19 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; |
| 19 | use embassy_stm32::timer::{Channel, CountingMode}; | 20 | use embassy_stm32::timer::Channel; |
| 20 | use embassy_time::{Duration, Ticker, Timer}; | 21 | use embassy_time::{Duration, Ticker, Timer}; |
| 21 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 22 | 23 | ||
| @@ -60,7 +61,7 @@ async fn main(_spawner: Spawner) { | |||
| 60 | // construct ws2812 non-return-to-zero (NRZ) code bit by bit | 61 | // construct ws2812 non-return-to-zero (NRZ) code bit by bit |
| 61 | // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low | 62 | // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low |
| 62 | 63 | ||
| 63 | let max_duty = ws2812_pwm.get_max_duty(); | 64 | let max_duty = ws2812_pwm.get_max_duty() as u16; |
| 64 | let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing | 65 | let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing |
| 65 | let n1 = 2 * n0; // ws2812 Bit 1 high level timing | 66 | let n1 = 2 * n0; // ws2812 Bit 1 high level timing |
| 66 | 67 | ||
diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs index a280a3b77..e00d14327 100644 --- a/examples/stm32f4/src/bin/ws2812_spi.rs +++ b/examples/stm32f4/src/bin/ws2812_spi.rs | |||
| @@ -8,13 +8,13 @@ | |||
| 8 | // If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA. | 8 | // If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA. |
| 9 | // | 9 | // |
| 10 | // Warning: | 10 | // Warning: |
| 11 | // DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. | 11 | // DO NOT stare at ws2812 directly (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. |
| 12 | 12 | ||
| 13 | #![no_std] | 13 | #![no_std] |
| 14 | #![no_main] | 14 | #![no_main] |
| 15 | 15 | ||
| 16 | use embassy_stm32::spi; | ||
| 16 | use embassy_stm32::time::khz; | 17 | use embassy_stm32::time::khz; |
| 17 | use embassy_stm32::{dma, spi}; | ||
| 18 | use embassy_time::{Duration, Ticker, Timer}; | 18 | use embassy_time::{Duration, Ticker, Timer}; |
| 19 | use {defmt_rtt as _, panic_probe as _}; | 19 | use {defmt_rtt as _, panic_probe as _}; |
| 20 | 20 | ||
| @@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) { | |||
| 78 | spi_config.frequency = khz(12_800); | 78 | spi_config.frequency = khz(12_800); |
| 79 | 79 | ||
| 80 | // Since we only output waveform, then the Rx and Sck and RxDma it is not considered | 80 | // Since we only output waveform, then the Rx and Sck and RxDma it is not considered |
| 81 | let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); | 81 | let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, spi_config); |
| 82 | 82 | ||
| 83 | // flip color at 2 Hz | 83 | // flip color at 2 Hz |
| 84 | let mut ticker = Ticker::every(Duration::from_millis(500)); | 84 | let mut ticker = Ticker::every(Duration::from_millis(500)); |
diff --git a/examples/stm32f469/.cargo/config.toml b/examples/stm32f469/.cargo/config.toml new file mode 100644 index 000000000..05250954f --- /dev/null +++ b/examples/stm32f469/.cargo/config.toml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` | ||
| 3 | runner = "probe-rs run --chip STM32F469NIHx" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv7em-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml new file mode 100644 index 000000000..6a5bd0b29 --- /dev/null +++ b/examples/stm32f469/Cargo.toml | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32f469-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | # Specific examples only for stm32f469 | ||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } | ||
| 10 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 12 | |||
| 13 | defmt = "0.3" | ||
| 14 | defmt-rtt = "0.4" | ||
| 15 | |||
| 16 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 17 | cortex-m-rt = "0.7.0" | ||
| 18 | embedded-hal = "1.0.0" | ||
| 19 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 20 | |||
| 21 | [profile.release] | ||
| 22 | debug = 2 | ||
diff --git a/examples/stm32f469/build.rs b/examples/stm32f469/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32f469/build.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | fn main() { | ||
| 2 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 3 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 4 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 5 | } | ||
diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs new file mode 100644 index 000000000..e4e9e9c01 --- /dev/null +++ b/examples/stm32f469/src/bin/dsi_bsp.rs | |||
| @@ -0,0 +1,694 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::dsihost::{blocking_delay_ms, DsiHost, PacketType}; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 8 | use embassy_stm32::ltdc::Ltdc; | ||
| 9 | use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1}; | ||
| 10 | use embassy_stm32::pac::ltdc::vals::{Bf1, Bf2, Depol, Hspol, Imr, Pcpol, Pf, Vspol}; | ||
| 11 | use embassy_stm32::pac::{DSIHOST, LTDC}; | ||
| 12 | use embassy_stm32::rcc::{ | ||
| 13 | AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk, | ||
| 14 | }; | ||
| 15 | use embassy_stm32::time::mhz; | ||
| 16 | use embassy_time::Timer; | ||
| 17 | use {defmt_rtt as _, panic_probe as _}; | ||
| 18 | |||
| 19 | enum _Orientation { | ||
| 20 | Landscape, | ||
| 21 | Portrait, | ||
| 22 | } | ||
| 23 | |||
| 24 | const _LCD_ORIENTATION: _Orientation = _Orientation::Landscape; | ||
| 25 | const LCD_X_SIZE: u16 = 800; | ||
| 26 | const LCD_Y_SIZE: u16 = 480; | ||
| 27 | |||
| 28 | static FERRIS_IMAGE: &[u8; 1536000] = include_bytes!("ferris.bin"); | ||
| 29 | |||
| 30 | // This example allows to display an image on the STM32F469NI-DISCO boards | ||
| 31 | // with the Revision C, that is at least the boards marked DK32F469I$AU1. | ||
| 32 | // These boards have the NT35510 display driver. This example does not work | ||
| 33 | // for the older revisions with OTM8009A, though there are lots of C-examples | ||
| 34 | // available online where the correct config for the OTM8009A could be gotten from. | ||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(_spawner: Spawner) { | ||
| 37 | let mut config = embassy_stm32::Config::default(); | ||
| 38 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 39 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 40 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 41 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 42 | |||
| 43 | // HSE is on and ready | ||
| 44 | config.rcc.hse = Some(Hse { | ||
| 45 | freq: mhz(8), | ||
| 46 | mode: HseMode::Oscillator, | ||
| 47 | }); | ||
| 48 | config.rcc.pll_src = PllSource::HSE; | ||
| 49 | |||
| 50 | config.rcc.pll = Some(Pll { | ||
| 51 | prediv: PllPreDiv::DIV8, // PLLM | ||
| 52 | mul: PllMul::MUL360, // PLLN | ||
| 53 | divp: Some(PllPDiv::DIV2), | ||
| 54 | divq: Some(PllQDiv::DIV7), // was DIV4, but STM BSP example uses 7 | ||
| 55 | divr: Some(PllRDiv::DIV6), | ||
| 56 | }); | ||
| 57 | |||
| 58 | // This seems to be working, the values in the RCC.PLLSAICFGR are correct according to the debugger. Also on and ready according to CR | ||
| 59 | config.rcc.pllsai = Some(Pll { | ||
| 60 | prediv: PllPreDiv::DIV8, // Actually ignored | ||
| 61 | mul: PllMul::MUL384, // PLLN | ||
| 62 | divp: None, // PLLP | ||
| 63 | divq: None, // PLLQ | ||
| 64 | divr: Some(PllRDiv::DIV7), // PLLR (Sai actually has special clockdiv register) | ||
| 65 | }); | ||
| 66 | |||
| 67 | let p = embassy_stm32::init(config); | ||
| 68 | info!("Starting..."); | ||
| 69 | |||
| 70 | let mut led = Output::new(p.PG6, Level::High, Speed::Low); | ||
| 71 | |||
| 72 | // According to UM for the discovery kit, PH7 is an active-low reset for the LCD and touchsensor | ||
| 73 | let mut reset = Output::new(p.PH7, Level::Low, Speed::High); | ||
| 74 | |||
| 75 | // CubeMX example waits 20 ms before de-asserting reset | ||
| 76 | embassy_time::block_for(embassy_time::Duration::from_millis(20)); | ||
| 77 | |||
| 78 | // Disable the reset signal and wait 140ms as in the Linux driver (CubeMX waits only 20) | ||
| 79 | reset.set_high(); | ||
| 80 | embassy_time::block_for(embassy_time::Duration::from_millis(140)); | ||
| 81 | |||
| 82 | let mut ltdc = Ltdc::new(p.LTDC); | ||
| 83 | let mut dsi = DsiHost::new(p.DSIHOST, p.PJ2); | ||
| 84 | let version = dsi.get_version(); | ||
| 85 | defmt::warn!("en: {:x}", version); | ||
| 86 | |||
| 87 | // Disable the DSI wrapper | ||
| 88 | dsi.disable_wrapper_dsi(); | ||
| 89 | |||
| 90 | // Disable the DSI host | ||
| 91 | dsi.disable(); | ||
| 92 | |||
| 93 | // D-PHY clock and digital disable | ||
| 94 | DSIHOST.pctlr().modify(|w| { | ||
| 95 | w.set_cke(false); | ||
| 96 | w.set_den(false) | ||
| 97 | }); | ||
| 98 | |||
| 99 | // Turn off the DSI PLL | ||
| 100 | DSIHOST.wrpcr().modify(|w| w.set_pllen(false)); | ||
| 101 | |||
| 102 | // Disable the regulator | ||
| 103 | DSIHOST.wrpcr().write(|w| w.set_regen(false)); | ||
| 104 | |||
| 105 | // Enable regulator | ||
| 106 | info!("DSIHOST: enabling regulator"); | ||
| 107 | DSIHOST.wrpcr().write(|w| w.set_regen(true)); | ||
| 108 | |||
| 109 | for _ in 1..1000 { | ||
| 110 | // The regulator status (ready or not) can be monitored with the RRS flag in the DSI_WISR register. | ||
| 111 | // Once it is set, we stop waiting. | ||
| 112 | if DSIHOST.wisr().read().rrs() { | ||
| 113 | info!("DSIHOST Regulator ready"); | ||
| 114 | break; | ||
| 115 | } | ||
| 116 | embassy_time::block_for(embassy_time::Duration::from_millis(1)); | ||
| 117 | } | ||
| 118 | |||
| 119 | if !DSIHOST.wisr().read().rrs() { | ||
| 120 | defmt::panic!("DSIHOST: enabling regulator FAILED"); | ||
| 121 | } | ||
| 122 | |||
| 123 | // Set up PLL and enable it | ||
| 124 | DSIHOST.wrpcr().modify(|w| { | ||
| 125 | w.set_pllen(true); | ||
| 126 | w.set_ndiv(125); // PLL loop division factor set to 125 | ||
| 127 | w.set_idf(2); // PLL input divided by 2 | ||
| 128 | w.set_odf(0); // PLL output divided by 1 | ||
| 129 | }); | ||
| 130 | |||
| 131 | /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */ | ||
| 132 | const LANE_BYTE_CLK_K_HZ: u16 = 62500; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L224C21-L224C26 | ||
| 133 | |||
| 134 | const _LCD_CLOCK: u16 = 27429; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L183 | ||
| 135 | |||
| 136 | /* TX_ESCAPE_CKDIV = f(LaneByteClk)/15.62 = 4 */ | ||
| 137 | const TX_ESCAPE_CKDIV: u8 = (LANE_BYTE_CLK_K_HZ / 15620) as u8; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L230 | ||
| 138 | |||
| 139 | for _ in 1..1000 { | ||
| 140 | embassy_time::block_for(embassy_time::Duration::from_millis(1)); | ||
| 141 | // The PLL status (lock or unlock) can be monitored with the PLLLS flag in the DSI_WISR register. | ||
| 142 | // Once it is set, we stop waiting. | ||
| 143 | if DSIHOST.wisr().read().pllls() { | ||
| 144 | info!("DSIHOST PLL locked"); | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | if !DSIHOST.wisr().read().pllls() { | ||
| 150 | defmt::panic!("DSIHOST: enabling PLL FAILED"); | ||
| 151 | } | ||
| 152 | |||
| 153 | // Set the PHY parameters | ||
| 154 | |||
| 155 | // D-PHY clock and digital enable | ||
| 156 | DSIHOST.pctlr().write(|w| { | ||
| 157 | w.set_cke(true); | ||
| 158 | w.set_den(true); | ||
| 159 | }); | ||
| 160 | |||
| 161 | // Set Clock lane to high-speed mode and disable automatic clock lane control | ||
| 162 | DSIHOST.clcr().modify(|w| { | ||
| 163 | w.set_dpcc(true); | ||
| 164 | w.set_acr(false); | ||
| 165 | }); | ||
| 166 | |||
| 167 | // Set number of active data lanes to two (lanes 0 and 1) | ||
| 168 | DSIHOST.pconfr().modify(|w| w.set_nl(1)); | ||
| 169 | |||
| 170 | // Set the DSI clock parameters | ||
| 171 | |||
| 172 | // Set the TX escape clock division factor to 4 | ||
| 173 | DSIHOST.ccr().modify(|w| w.set_txeckdiv(TX_ESCAPE_CKDIV)); | ||
| 174 | |||
| 175 | // Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4) | ||
| 176 | // The equation is : UIX4 = IntegerPart( (1000/F_PHY_Mhz) * 4 ) | ||
| 177 | // Where : F_PHY_Mhz = (NDIV * HSE_Mhz) / (IDF * ODF) | ||
| 178 | // Set the bit period in high-speed mode | ||
| 179 | DSIHOST.wpcr0().modify(|w| w.set_uix4(8)); // 8 is set in the BSP example (confirmed with Debugger) | ||
| 180 | |||
| 181 | // Disable all error interrupts and reset the Error Mask | ||
| 182 | DSIHOST.ier0().write_value(Ier0(0)); | ||
| 183 | DSIHOST.ier1().write_value(Ier1(0)); | ||
| 184 | |||
| 185 | // Enable this to fix read timeout | ||
| 186 | DSIHOST.pcr().modify(|w| w.set_btae(true)); | ||
| 187 | |||
| 188 | const DSI_PIXEL_FORMAT_RGB888: u8 = 0x05; | ||
| 189 | const _DSI_PIXEL_FORMAT_ARGB888: u8 = 0x00; | ||
| 190 | |||
| 191 | const HACT: u16 = LCD_X_SIZE; | ||
| 192 | const VACT: u16 = LCD_Y_SIZE; | ||
| 193 | |||
| 194 | const VSA: u16 = 120; | ||
| 195 | const VBP: u16 = 150; | ||
| 196 | const VFP: u16 = 150; | ||
| 197 | const HSA: u16 = 2; | ||
| 198 | const HBP: u16 = 34; | ||
| 199 | const HFP: u16 = 34; | ||
| 200 | |||
| 201 | const VIRTUAL_CHANNEL_ID: u8 = 0; | ||
| 202 | |||
| 203 | const COLOR_CODING: u8 = DSI_PIXEL_FORMAT_RGB888; | ||
| 204 | const VS_POLARITY: bool = false; // DSI_VSYNC_ACTIVE_HIGH == 0 | ||
| 205 | const HS_POLARITY: bool = false; // DSI_HSYNC_ACTIVE_HIGH == 0 | ||
| 206 | const DE_POLARITY: bool = false; // DSI_DATA_ENABLE_ACTIVE_HIGH == 0 | ||
| 207 | const MODE: u8 = 2; // DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */ | ||
| 208 | const NULL_PACKET_SIZE: u16 = 0xFFF; | ||
| 209 | const NUMBER_OF_CHUNKS: u16 = 0; | ||
| 210 | const PACKET_SIZE: u16 = HACT; /* Value depending on display orientation choice portrait/landscape */ | ||
| 211 | const HORIZONTAL_SYNC_ACTIVE: u16 = 4; // ((HSA as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; | ||
| 212 | const HORIZONTAL_BACK_PORCH: u16 = 77; //((HBP as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32) as u16; | ||
| 213 | const HORIZONTAL_LINE: u16 = 1982; //(((HACT + HSA + HBP + HFP) as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; /* Value depending on display orientation choice portrait/landscape */ | ||
| 214 | // FIXME: Make depend on orientation | ||
| 215 | const VERTICAL_SYNC_ACTIVE: u16 = VSA; | ||
| 216 | const VERTICAL_BACK_PORCH: u16 = VBP; | ||
| 217 | const VERTICAL_FRONT_PORCH: u16 = VFP; | ||
| 218 | const VERTICAL_ACTIVE: u16 = VACT; | ||
| 219 | const LP_COMMAND_ENABLE: bool = true; /* Enable sending commands in mode LP (Low Power) */ | ||
| 220 | |||
| 221 | /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */ | ||
| 222 | /* Only useful when sending LP packets is allowed while streaming is active in video mode */ | ||
| 223 | const LP_LARGEST_PACKET_SIZE: u8 = 16; | ||
| 224 | |||
| 225 | /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */ | ||
| 226 | /* Only useful when sending LP packets is allowed while streaming is active in video mode */ | ||
| 227 | const LPVACT_LARGEST_PACKET_SIZE: u8 = 0; | ||
| 228 | |||
| 229 | const LPHORIZONTAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HFP period */ | ||
| 230 | const LPHORIZONTAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HBP period */ | ||
| 231 | const LPVERTICAL_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VACT period */ | ||
| 232 | const LPVERTICAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VFP period */ | ||
| 233 | const LPVERTICAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VBP period */ | ||
| 234 | const LPVERTICAL_SYNC_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VSync = VSA period */ | ||
| 235 | const FRAME_BTAACKNOWLEDGE_ENABLE: bool = false; /* Frame bus-turn-around acknowledge enable => false according to debugger */ | ||
| 236 | |||
| 237 | /* Select video mode by resetting CMDM and DSIM bits */ | ||
| 238 | DSIHOST.mcr().modify(|w| w.set_cmdm(false)); | ||
| 239 | DSIHOST.wcfgr().modify(|w| w.set_dsim(false)); | ||
| 240 | |||
| 241 | /* Configure the video mode transmission type */ | ||
| 242 | DSIHOST.vmcr().modify(|w| w.set_vmt(MODE)); | ||
| 243 | |||
| 244 | /* Configure the video packet size */ | ||
| 245 | DSIHOST.vpcr().modify(|w| w.set_vpsize(PACKET_SIZE)); | ||
| 246 | |||
| 247 | /* Set the chunks number to be transmitted through the DSI link */ | ||
| 248 | DSIHOST.vccr().modify(|w| w.set_numc(NUMBER_OF_CHUNKS)); | ||
| 249 | |||
| 250 | /* Set the size of the null packet */ | ||
| 251 | DSIHOST.vnpcr().modify(|w| w.set_npsize(NULL_PACKET_SIZE)); | ||
| 252 | |||
| 253 | /* Select the virtual channel for the LTDC interface traffic */ | ||
| 254 | DSIHOST.lvcidr().modify(|w| w.set_vcid(VIRTUAL_CHANNEL_ID)); | ||
| 255 | |||
| 256 | /* Configure the polarity of control signals */ | ||
| 257 | DSIHOST.lpcr().modify(|w| { | ||
| 258 | w.set_dep(DE_POLARITY); | ||
| 259 | w.set_hsp(HS_POLARITY); | ||
| 260 | w.set_vsp(VS_POLARITY); | ||
| 261 | }); | ||
| 262 | |||
| 263 | /* Select the color coding for the host */ | ||
| 264 | DSIHOST.lcolcr().modify(|w| w.set_colc(COLOR_CODING)); | ||
| 265 | |||
| 266 | /* Select the color coding for the wrapper */ | ||
| 267 | DSIHOST.wcfgr().modify(|w| w.set_colmux(COLOR_CODING)); | ||
| 268 | |||
| 269 | /* Set the Horizontal Synchronization Active (HSA) in lane byte clock cycles */ | ||
| 270 | DSIHOST.vhsacr().modify(|w| w.set_hsa(HORIZONTAL_SYNC_ACTIVE)); | ||
| 271 | |||
| 272 | /* Set the Horizontal Back Porch (HBP) in lane byte clock cycles */ | ||
| 273 | DSIHOST.vhbpcr().modify(|w| w.set_hbp(HORIZONTAL_BACK_PORCH)); | ||
| 274 | |||
| 275 | /* Set the total line time (HLINE=HSA+HBP+HACT+HFP) in lane byte clock cycles */ | ||
| 276 | DSIHOST.vlcr().modify(|w| w.set_hline(HORIZONTAL_LINE)); | ||
| 277 | |||
| 278 | /* Set the Vertical Synchronization Active (VSA) */ | ||
| 279 | DSIHOST.vvsacr().modify(|w| w.set_vsa(VERTICAL_SYNC_ACTIVE)); | ||
| 280 | |||
| 281 | /* Set the Vertical Back Porch (VBP)*/ | ||
| 282 | DSIHOST.vvbpcr().modify(|w| w.set_vbp(VERTICAL_BACK_PORCH)); | ||
| 283 | |||
| 284 | /* Set the Vertical Front Porch (VFP)*/ | ||
| 285 | DSIHOST.vvfpcr().modify(|w| w.set_vfp(VERTICAL_FRONT_PORCH)); | ||
| 286 | |||
| 287 | /* Set the Vertical Active period*/ | ||
| 288 | DSIHOST.vvacr().modify(|w| w.set_va(VERTICAL_ACTIVE)); | ||
| 289 | |||
| 290 | /* Configure the command transmission mode */ | ||
| 291 | DSIHOST.vmcr().modify(|w| w.set_lpce(LP_COMMAND_ENABLE)); | ||
| 292 | |||
| 293 | /* Low power largest packet size */ | ||
| 294 | DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE)); | ||
| 295 | |||
| 296 | /* Low power VACT largest packet size */ | ||
| 297 | DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE)); | ||
| 298 | DSIHOST.lpmcr().modify(|w| w.set_vlpsize(LPVACT_LARGEST_PACKET_SIZE)); | ||
| 299 | |||
| 300 | /* Enable LP transition in HFP period */ | ||
| 301 | DSIHOST.vmcr().modify(|w| w.set_lphfpe(LPHORIZONTAL_FRONT_PORCH_ENABLE)); | ||
| 302 | |||
| 303 | /* Enable LP transition in HBP period */ | ||
| 304 | DSIHOST.vmcr().modify(|w| w.set_lphbpe(LPHORIZONTAL_BACK_PORCH_ENABLE)); | ||
| 305 | |||
| 306 | /* Enable LP transition in VACT period */ | ||
| 307 | DSIHOST.vmcr().modify(|w| w.set_lpvae(LPVERTICAL_ACTIVE_ENABLE)); | ||
| 308 | |||
| 309 | /* Enable LP transition in VFP period */ | ||
| 310 | DSIHOST.vmcr().modify(|w| w.set_lpvfpe(LPVERTICAL_FRONT_PORCH_ENABLE)); | ||
| 311 | |||
| 312 | /* Enable LP transition in VBP period */ | ||
| 313 | DSIHOST.vmcr().modify(|w| w.set_lpvbpe(LPVERTICAL_BACK_PORCH_ENABLE)); | ||
| 314 | |||
| 315 | /* Enable LP transition in vertical sync period */ | ||
| 316 | DSIHOST.vmcr().modify(|w| w.set_lpvsae(LPVERTICAL_SYNC_ACTIVE_ENABLE)); | ||
| 317 | |||
| 318 | /* Enable the request for an acknowledge response at the end of a frame */ | ||
| 319 | DSIHOST.vmcr().modify(|w| w.set_fbtaae(FRAME_BTAACKNOWLEDGE_ENABLE)); | ||
| 320 | |||
| 321 | /* Configure DSI PHY HS2LP and LP2HS timings */ | ||
| 322 | const CLOCK_LANE_HS2_LPTIME: u16 = 35; | ||
| 323 | const CLOCK_LANE_LP2_HSTIME: u16 = 35; | ||
| 324 | const DATA_LANE_HS2_LPTIME: u8 = 35; | ||
| 325 | const DATA_LANE_LP2_HSTIME: u8 = 35; | ||
| 326 | const DATA_LANE_MAX_READ_TIME: u16 = 0; | ||
| 327 | const STOP_WAIT_TIME: u8 = 10; | ||
| 328 | |||
| 329 | const MAX_TIME: u16 = if CLOCK_LANE_HS2_LPTIME > CLOCK_LANE_LP2_HSTIME { | ||
| 330 | CLOCK_LANE_HS2_LPTIME | ||
| 331 | } else { | ||
| 332 | CLOCK_LANE_LP2_HSTIME | ||
| 333 | }; | ||
| 334 | |||
| 335 | /* Clock lane timer configuration */ | ||
| 336 | |||
| 337 | /* In Automatic Clock Lane control mode, the DSI Host can turn off the clock lane between two | ||
| 338 | High-Speed transmission. | ||
| 339 | To do so, the DSI Host calculates the time required for the clock lane to change from HighSpeed | ||
| 340 | to Low-Power and from Low-Power to High-Speed. | ||
| 341 | This timings are configured by the HS2LP_TIME and LP2HS_TIME in the DSI Host Clock Lane Timer Configuration | ||
| 342 | Register (DSI_CLTCR). | ||
| 343 | But the DSI Host is not calculating LP2HS_TIME + HS2LP_TIME but 2 x HS2LP_TIME. | ||
| 344 | |||
| 345 | Workaround : Configure HS2LP_TIME and LP2HS_TIME with the same value being the max of HS2LP_TIME or LP2HS_TIME. | ||
| 346 | */ | ||
| 347 | |||
| 348 | DSIHOST.cltcr().modify(|w| { | ||
| 349 | w.set_hs2lp_time(MAX_TIME); | ||
| 350 | w.set_lp2hs_time(MAX_TIME) | ||
| 351 | }); | ||
| 352 | |||
| 353 | // Data lane timer configuration | ||
| 354 | DSIHOST.dltcr().modify(|w| { | ||
| 355 | w.set_hs2lp_time(DATA_LANE_HS2_LPTIME); | ||
| 356 | w.set_lp2hs_time(DATA_LANE_LP2_HSTIME); | ||
| 357 | w.set_mrd_time(DATA_LANE_MAX_READ_TIME); | ||
| 358 | }); | ||
| 359 | |||
| 360 | // Configure the wait period to request HS transmission after a stop state | ||
| 361 | DSIHOST.pconfr().modify(|w| w.set_sw_time(STOP_WAIT_TIME)); | ||
| 362 | |||
| 363 | const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0 | ||
| 364 | |||
| 365 | const LTDC_DE_POLARITY: Depol = if !DE_POLARITY { | ||
| 366 | Depol::ACTIVELOW | ||
| 367 | } else { | ||
| 368 | Depol::ACTIVEHIGH | ||
| 369 | }; | ||
| 370 | const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY { | ||
| 371 | Vspol::ACTIVEHIGH | ||
| 372 | } else { | ||
| 373 | Vspol::ACTIVELOW | ||
| 374 | }; | ||
| 375 | |||
| 376 | const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY { | ||
| 377 | Hspol::ACTIVEHIGH | ||
| 378 | } else { | ||
| 379 | Hspol::ACTIVELOW | ||
| 380 | }; | ||
| 381 | |||
| 382 | /* Timing Configuration */ | ||
| 383 | const HORIZONTAL_SYNC: u16 = HSA - 1; | ||
| 384 | const VERTICAL_SYNC: u16 = VERTICAL_SYNC_ACTIVE - 1; | ||
| 385 | const ACCUMULATED_HBP: u16 = HSA + HBP - 1; | ||
| 386 | const ACCUMULATED_VBP: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH - 1; | ||
| 387 | const ACCUMULATED_ACTIVE_W: u16 = LCD_X_SIZE + HSA + HBP - 1; | ||
| 388 | const ACCUMULATED_ACTIVE_H: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE - 1; | ||
| 389 | const TOTAL_WIDTH: u16 = LCD_X_SIZE + HSA + HBP + HFP - 1; | ||
| 390 | const TOTAL_HEIGHT: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE + VERTICAL_FRONT_PORCH - 1; | ||
| 391 | |||
| 392 | // DISABLE LTDC before making changes | ||
| 393 | ltdc.disable(); | ||
| 394 | |||
| 395 | // Configure the HS, VS, DE and PC polarity | ||
| 396 | LTDC.gcr().modify(|w| { | ||
| 397 | w.set_hspol(LTDC_HS_POLARITY); | ||
| 398 | w.set_vspol(LTDC_VS_POLARITY); | ||
| 399 | w.set_depol(LTDC_DE_POLARITY); | ||
| 400 | w.set_pcpol(Pcpol::RISINGEDGE); | ||
| 401 | }); | ||
| 402 | |||
| 403 | // Set Synchronization size | ||
| 404 | LTDC.sscr().modify(|w| { | ||
| 405 | w.set_hsw(HORIZONTAL_SYNC); | ||
| 406 | w.set_vsh(VERTICAL_SYNC) | ||
| 407 | }); | ||
| 408 | |||
| 409 | // Set Accumulated Back porch | ||
| 410 | LTDC.bpcr().modify(|w| { | ||
| 411 | w.set_ahbp(ACCUMULATED_HBP); | ||
| 412 | w.set_avbp(ACCUMULATED_VBP); | ||
| 413 | }); | ||
| 414 | |||
| 415 | // Set Accumulated Active Width | ||
| 416 | LTDC.awcr().modify(|w| { | ||
| 417 | w.set_aah(ACCUMULATED_ACTIVE_H); | ||
| 418 | w.set_aaw(ACCUMULATED_ACTIVE_W); | ||
| 419 | }); | ||
| 420 | |||
| 421 | // Set Total Width | ||
| 422 | LTDC.twcr().modify(|w| { | ||
| 423 | w.set_totalh(TOTAL_HEIGHT); | ||
| 424 | w.set_totalw(TOTAL_WIDTH); | ||
| 425 | }); | ||
| 426 | |||
| 427 | // Set the background color value | ||
| 428 | LTDC.bccr().modify(|w| { | ||
| 429 | w.set_bcred(0); | ||
| 430 | w.set_bcgreen(0); | ||
| 431 | w.set_bcblue(0) | ||
| 432 | }); | ||
| 433 | |||
| 434 | // Enable the Transfer Error and FIFO underrun interrupts | ||
| 435 | LTDC.ier().modify(|w| { | ||
| 436 | w.set_terrie(true); | ||
| 437 | w.set_fuie(true); | ||
| 438 | }); | ||
| 439 | |||
| 440 | // ENABLE LTDC after making changes | ||
| 441 | ltdc.enable(); | ||
| 442 | |||
| 443 | dsi.enable(); | ||
| 444 | dsi.enable_wrapper_dsi(); | ||
| 445 | |||
| 446 | // First, delay 120 ms (reason unknown, STM32 Cube Example does it) | ||
| 447 | blocking_delay_ms(120); | ||
| 448 | |||
| 449 | // 1 to 26 | ||
| 450 | dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap(); | ||
| 451 | dsi.write_cmd(0, NT35510_WRITES_1[0], &NT35510_WRITES_1[1..]).unwrap(); | ||
| 452 | dsi.write_cmd(0, NT35510_WRITES_2[0], &NT35510_WRITES_2[1..]).unwrap(); | ||
| 453 | dsi.write_cmd(0, NT35510_WRITES_3[0], &NT35510_WRITES_3[1..]).unwrap(); | ||
| 454 | dsi.write_cmd(0, NT35510_WRITES_4[0], &NT35510_WRITES_4[1..]).unwrap(); | ||
| 455 | dsi.write_cmd(0, NT35510_WRITES_5[0], &NT35510_WRITES_5[1..]).unwrap(); | ||
| 456 | dsi.write_cmd(0, NT35510_WRITES_6[0], &NT35510_WRITES_6[1..]).unwrap(); | ||
| 457 | dsi.write_cmd(0, NT35510_WRITES_7[0], &NT35510_WRITES_7[1..]).unwrap(); | ||
| 458 | dsi.write_cmd(0, NT35510_WRITES_8[0], &NT35510_WRITES_8[1..]).unwrap(); | ||
| 459 | dsi.write_cmd(0, NT35510_WRITES_9[0], &NT35510_WRITES_9[1..]).unwrap(); | ||
| 460 | dsi.write_cmd(0, NT35510_WRITES_10[0], &NT35510_WRITES_10[1..]).unwrap(); | ||
| 461 | // 11 missing | ||
| 462 | dsi.write_cmd(0, NT35510_WRITES_12[0], &NT35510_WRITES_12[1..]).unwrap(); | ||
| 463 | dsi.write_cmd(0, NT35510_WRITES_13[0], &NT35510_WRITES_13[1..]).unwrap(); | ||
| 464 | dsi.write_cmd(0, NT35510_WRITES_14[0], &NT35510_WRITES_14[1..]).unwrap(); | ||
| 465 | dsi.write_cmd(0, NT35510_WRITES_15[0], &NT35510_WRITES_15[1..]).unwrap(); | ||
| 466 | dsi.write_cmd(0, NT35510_WRITES_16[0], &NT35510_WRITES_16[1..]).unwrap(); | ||
| 467 | dsi.write_cmd(0, NT35510_WRITES_17[0], &NT35510_WRITES_17[1..]).unwrap(); | ||
| 468 | dsi.write_cmd(0, NT35510_WRITES_18[0], &NT35510_WRITES_18[1..]).unwrap(); | ||
| 469 | dsi.write_cmd(0, NT35510_WRITES_19[0], &NT35510_WRITES_19[1..]).unwrap(); | ||
| 470 | dsi.write_cmd(0, NT35510_WRITES_20[0], &NT35510_WRITES_20[1..]).unwrap(); | ||
| 471 | dsi.write_cmd(0, NT35510_WRITES_21[0], &NT35510_WRITES_21[1..]).unwrap(); | ||
| 472 | dsi.write_cmd(0, NT35510_WRITES_22[0], &NT35510_WRITES_22[1..]).unwrap(); | ||
| 473 | dsi.write_cmd(0, NT35510_WRITES_23[0], &NT35510_WRITES_23[1..]).unwrap(); | ||
| 474 | dsi.write_cmd(0, NT35510_WRITES_24[0], &NT35510_WRITES_24[1..]).unwrap(); | ||
| 475 | |||
| 476 | // Tear on | ||
| 477 | dsi.write_cmd(0, NT35510_WRITES_26[0], &NT35510_WRITES_26[1..]).unwrap(); | ||
| 478 | |||
| 479 | // Set Pixel color format to RGB888 | ||
| 480 | dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); | ||
| 481 | |||
| 482 | // Add a delay, otherwise MADCTL not taken | ||
| 483 | blocking_delay_ms(200); | ||
| 484 | |||
| 485 | // Configure orientation as landscape | ||
| 486 | dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..]) | ||
| 487 | .unwrap(); | ||
| 488 | dsi.write_cmd(0, NT35510_CASET_LANDSCAPE[0], &NT35510_CASET_LANDSCAPE[1..]) | ||
| 489 | .unwrap(); | ||
| 490 | dsi.write_cmd(0, NT35510_RASET_LANDSCAPE[0], &NT35510_RASET_LANDSCAPE[1..]) | ||
| 491 | .unwrap(); | ||
| 492 | |||
| 493 | // Sleep out | ||
| 494 | dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap(); | ||
| 495 | |||
| 496 | // Wait for sleep out exit | ||
| 497 | blocking_delay_ms(120); | ||
| 498 | |||
| 499 | // Configure COLOR_CODING | ||
| 500 | dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); | ||
| 501 | |||
| 502 | /* CABC : Content Adaptive Backlight Control section start >> */ | ||
| 503 | /* Note : defaut is 0 (lowest Brightness), 0xFF is highest Brightness, try 0x7F : intermediate value */ | ||
| 504 | dsi.write_cmd(0, NT35510_WRITES_31[0], &NT35510_WRITES_31[1..]).unwrap(); | ||
| 505 | /* defaut is 0, try 0x2C - Brightness Control Block, Display Dimming & BackLight on */ | ||
| 506 | dsi.write_cmd(0, NT35510_WRITES_32[0], &NT35510_WRITES_32[1..]).unwrap(); | ||
| 507 | /* defaut is 0, try 0x02 - image Content based Adaptive Brightness [Still Picture] */ | ||
| 508 | dsi.write_cmd(0, NT35510_WRITES_33[0], &NT35510_WRITES_33[1..]).unwrap(); | ||
| 509 | /* defaut is 0 (lowest Brightness), 0xFF is highest Brightness */ | ||
| 510 | dsi.write_cmd(0, NT35510_WRITES_34[0], &NT35510_WRITES_34[1..]).unwrap(); | ||
| 511 | /* CABC : Content Adaptive Backlight Control section end << */ | ||
| 512 | /* Display on */ | ||
| 513 | dsi.write_cmd(0, NT35510_WRITES_30[0], &NT35510_WRITES_30[1..]).unwrap(); | ||
| 514 | |||
| 515 | /* Send Command GRAM memory write (no parameters) : this initiates frame write via other DSI commands sent by */ | ||
| 516 | /* DSI host from LTDC incoming pixels in video mode */ | ||
| 517 | dsi.write_cmd(0, NT35510_WRITES_35[0], &NT35510_WRITES_35[1..]).unwrap(); | ||
| 518 | |||
| 519 | /* Initialize the LCD pixel width and pixel height */ | ||
| 520 | const WINDOW_X0: u16 = 0; | ||
| 521 | const WINDOW_X1: u16 = LCD_X_SIZE; // 480 for ferris | ||
| 522 | const WINDOW_Y0: u16 = 0; | ||
| 523 | const WINDOW_Y1: u16 = LCD_Y_SIZE; // 800 for ferris | ||
| 524 | const PIXEL_FORMAT: Pf = Pf::ARGB8888; | ||
| 525 | //const FBStartAdress: u16 = FB_Address; | ||
| 526 | const ALPHA: u8 = 255; | ||
| 527 | const ALPHA0: u8 = 0; | ||
| 528 | const BACKCOLOR_BLUE: u8 = 0; | ||
| 529 | const BACKCOLOR_GREEN: u8 = 0; | ||
| 530 | const BACKCOLOR_RED: u8 = 0; | ||
| 531 | const IMAGE_WIDTH: u16 = LCD_X_SIZE; // 480 for ferris | ||
| 532 | const IMAGE_HEIGHT: u16 = LCD_Y_SIZE; // 800 for ferris | ||
| 533 | |||
| 534 | const PIXEL_SIZE: u8 = match PIXEL_FORMAT { | ||
| 535 | Pf::ARGB8888 => 4, | ||
| 536 | Pf::RGB888 => 3, | ||
| 537 | Pf::ARGB4444 | Pf::RGB565 | Pf::ARGB1555 | Pf::AL88 => 2, | ||
| 538 | _ => 1, | ||
| 539 | }; | ||
| 540 | |||
| 541 | // Configure the horizontal start and stop position | ||
| 542 | LTDC.layer(0).whpcr().write(|w| { | ||
| 543 | w.set_whstpos(LTDC.bpcr().read().ahbp() + 1 + WINDOW_X0); | ||
| 544 | w.set_whsppos(LTDC.bpcr().read().ahbp() + WINDOW_X1); | ||
| 545 | }); | ||
| 546 | |||
| 547 | // Configures the vertical start and stop position | ||
| 548 | LTDC.layer(0).wvpcr().write(|w| { | ||
| 549 | w.set_wvstpos(LTDC.bpcr().read().avbp() + 1 + WINDOW_Y0); | ||
| 550 | w.set_wvsppos(LTDC.bpcr().read().avbp() + WINDOW_Y1); | ||
| 551 | }); | ||
| 552 | |||
| 553 | // Specify the pixel format | ||
| 554 | LTDC.layer(0).pfcr().write(|w| w.set_pf(PIXEL_FORMAT)); | ||
| 555 | |||
| 556 | // Configures the default color values as zero | ||
| 557 | LTDC.layer(0).dccr().modify(|w| { | ||
| 558 | w.set_dcblue(BACKCOLOR_BLUE); | ||
| 559 | w.set_dcgreen(BACKCOLOR_GREEN); | ||
| 560 | w.set_dcred(BACKCOLOR_RED); | ||
| 561 | w.set_dcalpha(ALPHA0); | ||
| 562 | }); | ||
| 563 | |||
| 564 | // Specifies the constant ALPHA value | ||
| 565 | LTDC.layer(0).cacr().write(|w| w.set_consta(ALPHA)); | ||
| 566 | |||
| 567 | // Specifies the blending factors | ||
| 568 | LTDC.layer(0).bfcr().write(|w| { | ||
| 569 | w.set_bf1(Bf1::CONSTANT); | ||
| 570 | w.set_bf2(Bf2::CONSTANT); | ||
| 571 | }); | ||
| 572 | |||
| 573 | // Configure the color frame buffer start address | ||
| 574 | let fb_start_address: u32 = &FERRIS_IMAGE[0] as *const _ as u32; | ||
| 575 | info!("Setting Framebuffer Start Address: {:010x}", fb_start_address); | ||
| 576 | LTDC.layer(0).cfbar().write(|w| w.set_cfbadd(fb_start_address)); | ||
| 577 | |||
| 578 | // Configures the color frame buffer pitch in byte | ||
| 579 | LTDC.layer(0).cfblr().write(|w| { | ||
| 580 | w.set_cfbp(IMAGE_WIDTH * PIXEL_SIZE as u16); | ||
| 581 | w.set_cfbll(((WINDOW_X1 - WINDOW_X0) * PIXEL_SIZE as u16) + 3); | ||
| 582 | }); | ||
| 583 | |||
| 584 | // Configures the frame buffer line number | ||
| 585 | LTDC.layer(0).cfblnr().write(|w| w.set_cfblnbr(IMAGE_HEIGHT)); | ||
| 586 | |||
| 587 | // Enable LTDC_Layer by setting LEN bit | ||
| 588 | LTDC.layer(0).cr().modify(|w| w.set_len(true)); | ||
| 589 | |||
| 590 | //LTDC->SRCR = LTDC_SRCR_IMR; | ||
| 591 | LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD)); | ||
| 592 | |||
| 593 | blocking_delay_ms(5000); | ||
| 594 | |||
| 595 | const READ_SIZE: u16 = 1; | ||
| 596 | let mut data = [1u8; READ_SIZE as usize]; | ||
| 597 | dsi.read(0, PacketType::DcsShortPktRead(0xDA), READ_SIZE, &mut data) | ||
| 598 | .unwrap(); | ||
| 599 | info!("Display ID1: {:#04x}", data); | ||
| 600 | |||
| 601 | dsi.read(0, PacketType::DcsShortPktRead(0xDB), READ_SIZE, &mut data) | ||
| 602 | .unwrap(); | ||
| 603 | info!("Display ID2: {:#04x}", data); | ||
| 604 | |||
| 605 | dsi.read(0, PacketType::DcsShortPktRead(0xDC), READ_SIZE, &mut data) | ||
| 606 | .unwrap(); | ||
| 607 | info!("Display ID3: {:#04x}", data); | ||
| 608 | |||
| 609 | blocking_delay_ms(500); | ||
| 610 | |||
| 611 | info!("Config done, start blinking LED"); | ||
| 612 | loop { | ||
| 613 | led.set_high(); | ||
| 614 | Timer::after_millis(1000).await; | ||
| 615 | |||
| 616 | // Increase screen brightness | ||
| 617 | dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0xFF]).unwrap(); | ||
| 618 | |||
| 619 | led.set_low(); | ||
| 620 | Timer::after_millis(1000).await; | ||
| 621 | |||
| 622 | // Reduce screen brightness | ||
| 623 | dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0x50]).unwrap(); | ||
| 624 | } | ||
| 625 | } | ||
| 626 | |||
| 627 | const NT35510_WRITES_0: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01]; // LV2: Page 1 enable | ||
| 628 | const NT35510_WRITES_1: &[u8] = &[0xB0, 0x03, 0x03, 0x03]; // AVDD: 5.2V | ||
| 629 | const NT35510_WRITES_2: &[u8] = &[0xB6, 0x46, 0x46, 0x46]; // AVDD: Ratio | ||
| 630 | const NT35510_WRITES_3: &[u8] = &[0xB1, 0x03, 0x03, 0x03]; // AVEE: -5.2V | ||
| 631 | const NT35510_WRITES_4: &[u8] = &[0xB7, 0x36, 0x36, 0x36]; // AVEE: Ratio | ||
| 632 | const NT35510_WRITES_5: &[u8] = &[0xB2, 0x00, 0x00, 0x02]; // VCL: -2.5V | ||
| 633 | const NT35510_WRITES_6: &[u8] = &[0xB8, 0x26, 0x26, 0x26]; // VCL: Ratio | ||
| 634 | const NT35510_WRITES_7: &[u8] = &[0xBF, 0x01]; // VGH: 15V (Free Pump) | ||
| 635 | const NT35510_WRITES_8: &[u8] = &[0xB3, 0x09, 0x09, 0x09]; | ||
| 636 | const NT35510_WRITES_9: &[u8] = &[0xB9, 0x36, 0x36, 0x36]; // VGH: Ratio | ||
| 637 | const NT35510_WRITES_10: &[u8] = &[0xB5, 0x08, 0x08, 0x08]; // VGL_REG: -10V | ||
| 638 | const NT35510_WRITES_12: &[u8] = &[0xBA, 0x26, 0x26, 0x26]; // VGLX: Ratio | ||
| 639 | const NT35510_WRITES_13: &[u8] = &[0xBC, 0x00, 0x80, 0x00]; // VGMP/VGSP: 4.5V/0V | ||
| 640 | const NT35510_WRITES_14: &[u8] = &[0xBD, 0x00, 0x80, 0x00]; // VGMN/VGSN:-4.5V/0V | ||
| 641 | const NT35510_WRITES_15: &[u8] = &[0xBE, 0x00, 0x50]; // VCOM: -1.325V | ||
| 642 | const NT35510_WRITES_16: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00]; // LV2: Page 0 enable | ||
| 643 | const NT35510_WRITES_17: &[u8] = &[0xB1, 0xFC, 0x00]; // Display control | ||
| 644 | const NT35510_WRITES_18: &[u8] = &[0xB6, 0x03]; // Src hold time | ||
| 645 | const NT35510_WRITES_19: &[u8] = &[0xB5, 0x51]; | ||
| 646 | const NT35510_WRITES_20: &[u8] = &[0x00, 0x00, 0xB7]; // Gate EQ control | ||
| 647 | const NT35510_WRITES_21: &[u8] = &[0xB8, 0x01, 0x02, 0x02, 0x02]; // Src EQ control(Mode2) | ||
| 648 | const NT35510_WRITES_22: &[u8] = &[0xBC, 0x00, 0x00, 0x00]; // Inv. mode(2-dot) | ||
| 649 | const NT35510_WRITES_23: &[u8] = &[0xCC, 0x03, 0x00, 0x00]; | ||
| 650 | const NT35510_WRITES_24: &[u8] = &[0xBA, 0x01]; | ||
| 651 | |||
| 652 | const _NT35510_MADCTL_PORTRAIT: &[u8] = &[NT35510_CMD_MADCTL, 0x00]; | ||
| 653 | const _NT35510_CASET_PORTRAIT: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x01, 0xDF]; | ||
| 654 | const _NT35510_RASET_PORTRAIT: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x03, 0x1F]; | ||
| 655 | const NT35510_MADCTL_LANDSCAPE: &[u8] = &[NT35510_CMD_MADCTL, 0x60]; | ||
| 656 | const NT35510_CASET_LANDSCAPE: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x03, 0x1F]; | ||
| 657 | const NT35510_RASET_LANDSCAPE: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x01, 0xDF]; | ||
| 658 | |||
| 659 | const NT35510_WRITES_26: &[u8] = &[NT35510_CMD_TEEON, 0x00]; // Tear on | ||
| 660 | const NT35510_WRITES_27: &[u8] = &[NT35510_CMD_SLPOUT, 0x00]; // Sleep out | ||
| 661 | // 28,29 missing | ||
| 662 | const NT35510_WRITES_30: &[u8] = &[NT35510_CMD_DISPON, 0x00]; // Display on | ||
| 663 | |||
| 664 | const NT35510_WRITES_31: &[u8] = &[NT35510_CMD_WRDISBV, 0x7F]; | ||
| 665 | const NT35510_WRITES_32: &[u8] = &[NT35510_CMD_WRCTRLD, 0x2C]; | ||
| 666 | const NT35510_WRITES_33: &[u8] = &[NT35510_CMD_WRCABC, 0x02]; | ||
| 667 | const NT35510_WRITES_34: &[u8] = &[NT35510_CMD_WRCABCMB, 0xFF]; | ||
| 668 | const NT35510_WRITES_35: &[u8] = &[NT35510_CMD_RAMWR, 0x00]; | ||
| 669 | |||
| 670 | //const NT35510_WRITES_36: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB565]; // FIXME: Example sets it to 888 but rest of the code seems to configure DSI for 565 | ||
| 671 | const NT35510_WRITES_37: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB888]; | ||
| 672 | |||
| 673 | // More of these: https://elixir.bootlin.com/linux/latest/source/include/video/mipi_display.h#L83 | ||
| 674 | const _NT35510_CMD_TEEON_GET_DISPLAY_ID: u8 = 0x04; | ||
| 675 | |||
| 676 | const NT35510_CMD_TEEON: u8 = 0x35; | ||
| 677 | const NT35510_CMD_MADCTL: u8 = 0x36; | ||
| 678 | |||
| 679 | const NT35510_CMD_SLPOUT: u8 = 0x11; | ||
| 680 | const NT35510_CMD_DISPON: u8 = 0x29; | ||
| 681 | const NT35510_CMD_CASET: u8 = 0x2A; | ||
| 682 | const NT35510_CMD_RASET: u8 = 0x2B; | ||
| 683 | const NT35510_CMD_RAMWR: u8 = 0x2C; /* Memory write */ | ||
| 684 | const NT35510_CMD_COLMOD: u8 = 0x3A; | ||
| 685 | |||
| 686 | const NT35510_CMD_WRDISBV: u8 = 0x51; /* Write display brightness */ | ||
| 687 | const _NT35510_CMD_RDDISBV: u8 = 0x52; /* Read display brightness */ | ||
| 688 | const NT35510_CMD_WRCTRLD: u8 = 0x53; /* Write CTRL display */ | ||
| 689 | const _NT35510_CMD_RDCTRLD: u8 = 0x54; /* Read CTRL display value */ | ||
| 690 | const NT35510_CMD_WRCABC: u8 = 0x55; /* Write content adaptative brightness control */ | ||
| 691 | const NT35510_CMD_WRCABCMB: u8 = 0x5E; /* Write CABC minimum brightness */ | ||
| 692 | |||
| 693 | const _NT35510_COLMOD_RGB565: u8 = 0x55; | ||
| 694 | const NT35510_COLMOD_RGB888: u8 = 0x77; | ||
diff --git a/examples/stm32f469/src/bin/ferris.bin b/examples/stm32f469/src/bin/ferris.bin new file mode 100644 index 000000000..ae1c466be --- /dev/null +++ b/examples/stm32f469/src/bin/ferris.bin | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������f���2��� | ||
| 2 | ��� | ||
| 3 | ��� | ||
| 4 | �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������=��� | ||
| 5 | �������������������������������������������������������������������������������������������������������������������������������I��� | ||
| 6 | ��� | ||
| 7 | �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%��� | ||
| 8 | ��� | ||
| 9 | ��� | ||
| 10 | ��� | ||
| 11 | ���������������������������������������������������������������������������������������������������������������������������T��� | ||
| 12 | ���������������������������������������������������������������������������������������������������2��� | ||
| 13 | ���=���c�����������������������������������G��� | ||
| 14 | |||
| 15 | |||
| 16 | � | ||
| 17 | e�� | ||
| 18 | |||
| 19 | |||
| 20 | �������������������������������������������������������������������������������������������������������������������������hhh� | ||
| 21 | _�� | ||
| 22 | _�� | ||
| 23 | � | ||
| 24 | (� | ||
| 25 | � | ||
| 26 | .� | ||
| 27 | 1� | ||
| 28 | -� | ||
| 29 | � | ||
| 30 | .�� | ||
| 31 | .��Yb�������������� | ||
| 32 | M�� | ||
| 33 | .��S]���������������������������������� | ||
| 34 | .�� | ||
| 35 | .�� | ||
| 36 | -� | ||
| 37 | .�� | ||
| 38 | .�� | ||
| 39 | .��v{������������������������������_f��%9��,�� | ||
| 40 | 5� | ||
| 41 | .�� | ||
| 42 | L���������������������������������������������������������������������������������������������� | ||
| 43 | .��|������������������������������������������������������������������ | ||
| 44 | -� | ||
| 45 | .�� | ||
| 46 | � | ||
| 47 | � | ||
| 48 | M�� | ||
| 49 | 3� | ||
| 50 | -� | ||
| 51 | 0� | ||
| 52 | 2� | ||
| 53 | .� | ||
| 54 | '� | ||
| 55 | .����������������������������������������������������������������������������������������������%T�� | ||
| 56 | M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������lx�� | ||
| 57 | 6� | ||
| 58 | M��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fu�� | ||
| 59 | 3� | ||
| 60 | M�� | ||
| 61 | /� | ||
| 62 | 2� | ||
| 63 | J�� | ||
| 64 | .�� | ||
| 65 | .����������������������������������������������������������������������������������������������������������Sl�� | ||
| 66 | H�� | ||
| 67 | M�� | ||
| 68 | .�� | ||
| 69 | M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������q|��O�� | ||
| 70 | M������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(T�� | ||
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index a612c2554..8c591ebd2 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml | |||
| @@ -7,12 +7,13 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32f777zi to your chip name, if necessary. | 8 | # Change stm32f777zi to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } |
| 14 | embedded-io-async = { version = "0.6.1" } | 14 | embedded-io-async = { version = "0.6.1" } |
| 15 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 16 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 16 | 17 | ||
| 17 | defmt = "0.3" | 18 | defmt = "0.3" |
| 18 | defmt-rtt = "0.4" | 19 | defmt-rtt = "0.4" |
| @@ -21,7 +22,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 21 | cortex-m-rt = "0.7.0" | 22 | cortex-m-rt = "0.7.0" |
| 22 | embedded-hal = "0.2.6" | 23 | embedded-hal = "0.2.6" |
| 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 24 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 25 | heapless = { version = "0.8", default-features = false } | 25 | heapless = { version = "0.8", default-features = false } |
| 26 | nb = "1.0.0" | 26 | nb = "1.0.0" |
| 27 | rand_core = "0.6.3" | 27 | rand_core = "0.6.3" |
| @@ -29,6 +29,8 @@ critical-section = "1.1" | |||
| 29 | embedded-storage = "0.3.1" | 29 | embedded-storage = "0.3.1" |
| 30 | static_cell = "2" | 30 | static_cell = "2" |
| 31 | sha2 = { version = "0.10.8", default-features = false } | 31 | sha2 = { version = "0.10.8", default-features = false } |
| 32 | hmac = "0.12.1" | ||
| 33 | aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } | ||
| 32 | 34 | ||
| 33 | [profile.release] | 35 | [profile.release] |
| 34 | debug = 2 | 36 | debug = 2 |
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index f8d7b691f..6689e3b5d 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::Adc; | 6 | use embassy_stm32::adc::Adc; |
| 7 | use embassy_time::{Delay, Timer}; | 7 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| 10 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| @@ -12,11 +12,11 @@ async fn main(_spawner: Spawner) { | |||
| 12 | let p = embassy_stm32::init(Default::default()); | 12 | let p = embassy_stm32::init(Default::default()); |
| 13 | info!("Hello World!"); | 13 | info!("Hello World!"); |
| 14 | 14 | ||
| 15 | let mut adc = Adc::new(p.ADC1, &mut Delay); | 15 | let mut adc = Adc::new(p.ADC1); |
| 16 | let mut pin = p.PA3; | 16 | let mut pin = p.PA3; |
| 17 | 17 | ||
| 18 | let mut vrefint = adc.enable_vrefint(); | 18 | let mut vrefint = adc.enable_vrefint(); |
| 19 | let vrefint_sample = adc.read(&mut vrefint); | 19 | let vrefint_sample = adc.blocking_read(&mut vrefint); |
| 20 | let convert_to_millivolts = |sample| { | 20 | let convert_to_millivolts = |sample| { |
| 21 | // From http://www.st.com/resource/en/datasheet/DM00273119.pdf | 21 | // From http://www.st.com/resource/en/datasheet/DM00273119.pdf |
| 22 | // 6.3.27 Reference voltage | 22 | // 6.3.27 Reference voltage |
| @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) { | |||
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | loop { | 28 | loop { |
| 29 | let v = adc.read(&mut pin); | 29 | let v = adc.blocking_read(&mut pin); |
| 30 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); | 30 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); |
| 31 | Timer::after_millis(100).await; | 31 | Timer::after_millis(100).await; |
| 32 | } | 32 | } |
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index bcfdb67a8..a82e335a9 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs | |||
| @@ -1,16 +1,18 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::num::{NonZeroU16, NonZeroU8}; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::bind_interrupts; | 8 | use embassy_stm32::can::filter::Mask32; |
| 7 | use embassy_stm32::can::bxcan::filter::Mask32; | ||
| 8 | use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; | ||
| 9 | use embassy_stm32::can::{ | 9 | use embassy_stm32::can::{ |
| 10 | Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, | 10 | Can, CanTx, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, |
| 11 | TxInterruptHandler, | ||
| 11 | }; | 12 | }; |
| 12 | use embassy_stm32::gpio::{Input, Pull}; | 13 | use embassy_stm32::gpio::{Input, Pull}; |
| 13 | use embassy_stm32::peripherals::CAN3; | 14 | use embassy_stm32::peripherals::CAN3; |
| 15 | use embassy_stm32::{bind_interrupts, can}; | ||
| 14 | use static_cell::StaticCell; | 16 | use static_cell::StaticCell; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 18 | ||
| @@ -22,9 +24,9 @@ bind_interrupts!(struct Irqs { | |||
| 22 | }); | 24 | }); |
| 23 | 25 | ||
| 24 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 25 | pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) { | 27 | pub async fn send_can_message(tx: &'static mut CanTx<'static>) { |
| 26 | loop { | 28 | loop { |
| 27 | let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); | 29 | let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap(); |
| 28 | tx.write(&frame).await; | 30 | tx.write(&frame).await; |
| 29 | embassy_time::Timer::after_secs(1).await; | 31 | embassy_time::Timer::after_secs(1).await; |
| 30 | } | 32 | } |
| @@ -43,21 +45,24 @@ async fn main(spawner: Spawner) { | |||
| 43 | let rx_pin = Input::new(&mut p.PA15, Pull::Up); | 45 | let rx_pin = Input::new(&mut p.PA15, Pull::Up); |
| 44 | core::mem::forget(rx_pin); | 46 | core::mem::forget(rx_pin); |
| 45 | 47 | ||
| 46 | static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); | 48 | static CAN: StaticCell<Can<'static>> = StaticCell::new(); |
| 47 | let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); | 49 | let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); |
| 48 | can.as_mut() | 50 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 49 | .modify_filters() | 51 | |
| 50 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | 52 | can.modify_config() |
| 53 | .set_bit_timing(can::util::NominalBitTiming { | ||
| 54 | prescaler: NonZeroU16::new(2).unwrap(), | ||
| 55 | seg1: NonZeroU8::new(13).unwrap(), | ||
| 56 | seg2: NonZeroU8::new(2).unwrap(), | ||
| 57 | sync_jump_width: NonZeroU8::new(1).unwrap(), | ||
| 58 | }) // http://www.bittiming.can-wiki.info/ | ||
| 59 | .set_loopback(true); | ||
| 51 | 60 | ||
| 52 | can.as_mut() | 61 | can.enable().await; |
| 53 | .modify_config() | ||
| 54 | .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/ | ||
| 55 | .set_loopback(true) | ||
| 56 | .enable(); | ||
| 57 | 62 | ||
| 58 | let (tx, mut rx) = can.split(); | 63 | let (tx, mut rx) = can.split(); |
| 59 | 64 | ||
| 60 | static CAN_TX: StaticCell<CanTx<'static, 'static, CAN3>> = StaticCell::new(); | 65 | static CAN_TX: StaticCell<CanTx<'static>> = StaticCell::new(); |
| 61 | let tx = CAN_TX.init(tx); | 66 | let tx = CAN_TX.init(tx); |
| 62 | spawner.spawn(send_can_message(tx)).unwrap(); | 67 | spawner.spawn(send_can_message(tx)).unwrap(); |
| 63 | 68 | ||
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs new file mode 100644 index 000000000..235853cb9 --- /dev/null +++ b/examples/stm32f7/src/bin/cryp.rs | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use aes_gcm::aead::heapless::Vec; | ||
| 5 | use aes_gcm::aead::{AeadInPlace, KeyInit}; | ||
| 6 | use aes_gcm::Aes128Gcm; | ||
| 7 | use defmt::info; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_stm32::cryp::{self, *}; | ||
| 10 | use embassy_stm32::{bind_interrupts, peripherals, Config}; | ||
| 11 | use embassy_time::Instant; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | CRYP => cryp::InterruptHandler<peripherals::CRYP>; | ||
| 16 | }); | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async fn main(_spawner: Spawner) -> ! { | ||
| 20 | let config = Config::default(); | ||
| 21 | let p = embassy_stm32::init(config); | ||
| 22 | |||
| 23 | let payload: &[u8] = b"hello world"; | ||
| 24 | let aad: &[u8] = b"additional data"; | ||
| 25 | |||
| 26 | let mut hw_cryp = Cryp::new(p.CRYP, p.DMA2_CH6, p.DMA2_CH5, Irqs); | ||
| 27 | let key: [u8; 16] = [0; 16]; | ||
| 28 | let mut ciphertext: [u8; 11] = [0; 11]; | ||
| 29 | let mut plaintext: [u8; 11] = [0; 11]; | ||
| 30 | let iv: [u8; 12] = [0; 12]; | ||
| 31 | |||
| 32 | let hw_start_time = Instant::now(); | ||
| 33 | |||
| 34 | // Encrypt in hardware using AES-GCM 128-bit | ||
| 35 | let aes_gcm = AesGcm::new(&key, &iv); | ||
| 36 | let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt).await; | ||
| 37 | hw_cryp.aad(&mut gcm_encrypt, aad, true).await; | ||
| 38 | hw_cryp.payload(&mut gcm_encrypt, payload, &mut ciphertext, true).await; | ||
| 39 | let encrypt_tag = hw_cryp.finish(gcm_encrypt).await; | ||
| 40 | |||
| 41 | // Decrypt in hardware using AES-GCM 128-bit | ||
| 42 | let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt).await; | ||
| 43 | hw_cryp.aad(&mut gcm_decrypt, aad, true).await; | ||
| 44 | hw_cryp | ||
| 45 | .payload(&mut gcm_decrypt, &ciphertext, &mut plaintext, true) | ||
| 46 | .await; | ||
| 47 | let decrypt_tag = hw_cryp.finish(gcm_decrypt).await; | ||
| 48 | |||
| 49 | let hw_end_time = Instant::now(); | ||
| 50 | let hw_execution_time = hw_end_time - hw_start_time; | ||
| 51 | |||
| 52 | info!("AES-GCM Ciphertext: {:?}", ciphertext); | ||
| 53 | info!("AES-GCM Plaintext: {:?}", plaintext); | ||
| 54 | assert_eq!(payload, plaintext); | ||
| 55 | assert_eq!(encrypt_tag, decrypt_tag); | ||
| 56 | |||
| 57 | let sw_start_time = Instant::now(); | ||
| 58 | |||
| 59 | // Encrypt in software using AES-GCM 128-bit | ||
| 60 | let mut payload_vec: Vec<u8, 32> = Vec::from_slice(&payload).unwrap(); | ||
| 61 | let cipher = Aes128Gcm::new(&key.into()); | ||
| 62 | let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); | ||
| 63 | |||
| 64 | assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]); | ||
| 65 | assert_eq!( | ||
| 66 | encrypt_tag, | ||
| 67 | payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()] | ||
| 68 | ); | ||
| 69 | |||
| 70 | // Decrypt in software using AES-GCM 128-bit | ||
| 71 | let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); | ||
| 72 | |||
| 73 | let sw_end_time = Instant::now(); | ||
| 74 | let sw_execution_time = sw_end_time - sw_start_time; | ||
| 75 | |||
| 76 | info!("Hardware Execution Time: {:?}", hw_execution_time); | ||
| 77 | info!("Software Execution Time: {:?}", sw_execution_time); | ||
| 78 | |||
| 79 | loop {} | ||
| 80 | } | ||
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 9a608e909..1f1eadf37 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { | |||
| 25 | type Device = Ethernet<'static, ETH, GenericSMI>; | 25 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 28 | async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { |
| 29 | stack.run().await | 29 | runner.run().await |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | #[embassy_executor::main] | 32 | #[embassy_executor::main] |
| @@ -63,9 +63,9 @@ async fn main(spawner: Spawner) -> ! { | |||
| 63 | 63 | ||
| 64 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 64 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 65 | 65 | ||
| 66 | static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); | 66 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); |
| 67 | let device = Ethernet::new( | 67 | let device = Ethernet::new( |
| 68 | PACKETS.init(PacketQueue::<16, 16>::new()), | 68 | PACKETS.init(PacketQueue::<4, 4>::new()), |
| 69 | p.ETH, | 69 | p.ETH, |
| 70 | Irqs, | 70 | Irqs, |
| 71 | p.PA1, | 71 | p.PA1, |
| @@ -89,17 +89,11 @@ async fn main(spawner: Spawner) -> ! { | |||
| 89 | //}); | 89 | //}); |
| 90 | 90 | ||
| 91 | // Init network stack | 91 | // Init network stack |
| 92 | static STACK: StaticCell<Stack<Device>> = StaticCell::new(); | 92 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 93 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 93 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 94 | let stack = &*STACK.init(Stack::new( | ||
| 95 | device, | ||
| 96 | config, | ||
| 97 | RESOURCES.init(StackResources::<2>::new()), | ||
| 98 | seed, | ||
| 99 | )); | ||
| 100 | 94 | ||
| 101 | // Launch network task | 95 | // Launch network task |
| 102 | unwrap!(spawner.spawn(net_task(stack))); | 96 | unwrap!(spawner.spawn(net_task(runner))); |
| 103 | 97 | ||
| 104 | // Ensure DHCP configuration is up before trying connect | 98 | // Ensure DHCP configuration is up before trying connect |
| 105 | stack.wait_config_up().await; | 99 | stack.wait_config_up().await; |
| @@ -111,7 +105,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 111 | let mut tx_buffer = [0; 4096]; | 105 | let mut tx_buffer = [0; 4096]; |
| 112 | 106 | ||
| 113 | loop { | 107 | loop { |
| 114 | let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); | 108 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); |
| 115 | 109 | ||
| 116 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); | 110 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); |
| 117 | 111 | ||
diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index 96e50f84b..c2d1a7158 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs | |||
| @@ -6,9 +6,12 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::hash::*; | 6 | use embassy_stm32::hash::*; |
| 7 | use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; | 7 | use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; |
| 8 | use embassy_time::Instant; | 8 | use embassy_time::Instant; |
| 9 | use hmac::{Hmac, Mac}; | ||
| 9 | use sha2::{Digest, Sha256}; | 10 | use sha2::{Digest, Sha256}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 12 | ||
| 13 | type HmacSha256 = Hmac<Sha256>; | ||
| 14 | |||
| 12 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 13 | HASH_RNG => hash::InterruptHandler<peripherals::HASH>; | 16 | HASH_RNG => hash::InterruptHandler<peripherals::HASH>; |
| 14 | }); | 17 | }); |
| @@ -26,7 +29,7 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 26 | let hw_start_time = Instant::now(); | 29 | let hw_start_time = Instant::now(); |
| 27 | 30 | ||
| 28 | // Compute a digest in hardware. | 31 | // Compute a digest in hardware. |
| 29 | let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); | 32 | let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None); |
| 30 | hw_hasher.update(&mut context, test_1).await; | 33 | hw_hasher.update(&mut context, test_1).await; |
| 31 | hw_hasher.update(&mut context, test_2).await; | 34 | hw_hasher.update(&mut context, test_2).await; |
| 32 | let mut hw_digest: [u8; 32] = [0; 32]; | 35 | let mut hw_digest: [u8; 32] = [0; 32]; |
| @@ -52,5 +55,24 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 52 | info!("Software Execution Time: {:?}", sw_execution_time); | 55 | info!("Software Execution Time: {:?}", sw_execution_time); |
| 53 | assert_eq!(hw_digest, sw_digest[..]); | 56 | assert_eq!(hw_digest, sw_digest[..]); |
| 54 | 57 | ||
| 58 | let hmac_key: [u8; 64] = [0x55; 64]; | ||
| 59 | |||
| 60 | // Compute HMAC in hardware. | ||
| 61 | let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key)); | ||
| 62 | hw_hasher.update(&mut sha256hmac_context, test_1).await; | ||
| 63 | hw_hasher.update(&mut sha256hmac_context, test_2).await; | ||
| 64 | let mut hw_hmac: [u8; 32] = [0; 32]; | ||
| 65 | hw_hasher.finish(sha256hmac_context, &mut hw_hmac).await; | ||
| 66 | |||
| 67 | // Compute HMAC in software. | ||
| 68 | let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap(); | ||
| 69 | sw_mac.update(test_1); | ||
| 70 | sw_mac.update(test_2); | ||
| 71 | let sw_hmac = sw_mac.finalize().into_bytes(); | ||
| 72 | |||
| 73 | info!("Hardware HMAC: {:?}", hw_hmac); | ||
| 74 | info!("Software HMAC: {:?}", sw_hmac[..]); | ||
| 75 | assert_eq!(hw_hmac, sw_hmac[..]); | ||
| 76 | |||
| 55 | loop {} | 77 | loop {} |
| 56 | } | 78 | } |
diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs new file mode 100644 index 000000000..90d319b7a --- /dev/null +++ b/examples/stm32f7/src/bin/qspi.rs | |||
| @@ -0,0 +1,301 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![allow(dead_code)] // Allow dead code as not all commands are used in the example | ||
| 4 | |||
| 5 | use defmt::info; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::mode::Async; | ||
| 8 | use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; | ||
| 9 | use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; | ||
| 10 | use embassy_stm32::time::mhz; | ||
| 11 | use embassy_stm32::Config as StmCfg; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | const MEMORY_PAGE_SIZE: usize = 256; | ||
| 15 | |||
| 16 | const CMD_READ: u8 = 0x03; | ||
| 17 | const CMD_HS_READ: u8 = 0x0B; | ||
| 18 | const CMD_QUAD_READ: u8 = 0x6B; | ||
| 19 | |||
| 20 | const CMD_WRITE_PG: u8 = 0xF2; | ||
| 21 | const CMD_QUAD_WRITE_PG: u8 = 0x32; | ||
| 22 | |||
| 23 | const CMD_READ_ID: u8 = 0x9F; | ||
| 24 | const CMD_READ_UUID: u8 = 0x4B; | ||
| 25 | |||
| 26 | const CMD_ENABLE_RESET: u8 = 0x66; | ||
| 27 | const CMD_RESET: u8 = 0x99; | ||
| 28 | |||
| 29 | const CMD_WRITE_ENABLE: u8 = 0x06; | ||
| 30 | const CMD_WRITE_DISABLE: u8 = 0x04; | ||
| 31 | |||
| 32 | const CMD_CHIP_ERASE: u8 = 0xC7; | ||
| 33 | const CMD_SECTOR_ERASE: u8 = 0x20; | ||
| 34 | const CMD_BLOCK_ERASE_32K: u8 = 0x52; | ||
| 35 | const CMD_BLOCK_ERASE_64K: u8 = 0xD8; | ||
| 36 | |||
| 37 | const CMD_READ_SR: u8 = 0x05; | ||
| 38 | const CMD_READ_CR: u8 = 0x35; | ||
| 39 | |||
| 40 | const CMD_WRITE_SR: u8 = 0x01; | ||
| 41 | const CMD_WRITE_CR: u8 = 0x31; | ||
| 42 | const MEMORY_ADDR: u32 = 0x00000000u32; | ||
| 43 | |||
| 44 | /// Implementation of access to flash chip. | ||
| 45 | /// Chip commands are hardcoded as it depends on used chip. | ||
| 46 | /// This implementation is using chip GD25Q64C from Giga Device | ||
| 47 | pub struct FlashMemory<I: Instance> { | ||
| 48 | qspi: Qspi<'static, I, Async>, | ||
| 49 | } | ||
| 50 | |||
| 51 | impl<I: Instance> FlashMemory<I> { | ||
| 52 | pub fn new(qspi: Qspi<'static, I, Async>) -> Self { | ||
| 53 | let mut memory = Self { qspi }; | ||
| 54 | |||
| 55 | memory.reset_memory(); | ||
| 56 | memory.enable_quad(); | ||
| 57 | |||
| 58 | memory | ||
| 59 | } | ||
| 60 | |||
| 61 | fn enable_quad(&mut self) { | ||
| 62 | let cr = self.read_cr(); | ||
| 63 | self.write_cr(cr | 0x02); | ||
| 64 | } | ||
| 65 | |||
| 66 | fn exec_command(&mut self, cmd: u8) { | ||
| 67 | let transaction = TransferConfig { | ||
| 68 | iwidth: QspiWidth::SING, | ||
| 69 | awidth: QspiWidth::NONE, | ||
| 70 | dwidth: QspiWidth::NONE, | ||
| 71 | instruction: cmd, | ||
| 72 | address: None, | ||
| 73 | dummy: DummyCycles::_0, | ||
| 74 | }; | ||
| 75 | self.qspi.command(transaction); | ||
| 76 | } | ||
| 77 | |||
| 78 | pub fn reset_memory(&mut self) { | ||
| 79 | self.exec_command(CMD_ENABLE_RESET); | ||
| 80 | self.exec_command(CMD_RESET); | ||
| 81 | self.wait_write_finish(); | ||
| 82 | } | ||
| 83 | |||
| 84 | pub fn enable_write(&mut self) { | ||
| 85 | self.exec_command(CMD_WRITE_ENABLE); | ||
| 86 | } | ||
| 87 | |||
| 88 | pub fn read_id(&mut self) -> [u8; 3] { | ||
| 89 | let mut buffer = [0; 3]; | ||
| 90 | let transaction: TransferConfig = TransferConfig { | ||
| 91 | iwidth: QspiWidth::SING, | ||
| 92 | awidth: QspiWidth::NONE, | ||
| 93 | dwidth: QspiWidth::SING, | ||
| 94 | instruction: CMD_READ_ID, | ||
| 95 | address: None, | ||
| 96 | dummy: DummyCycles::_0, | ||
| 97 | }; | ||
| 98 | self.qspi.blocking_read(&mut buffer, transaction); | ||
| 99 | buffer | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn read_uuid(&mut self) -> [u8; 16] { | ||
| 103 | let mut buffer = [0; 16]; | ||
| 104 | let transaction: TransferConfig = TransferConfig { | ||
| 105 | iwidth: QspiWidth::SING, | ||
| 106 | awidth: QspiWidth::SING, | ||
| 107 | dwidth: QspiWidth::SING, | ||
| 108 | instruction: CMD_READ_UUID, | ||
| 109 | address: Some(0), | ||
| 110 | dummy: DummyCycles::_8, | ||
| 111 | }; | ||
| 112 | self.qspi.blocking_read(&mut buffer, transaction); | ||
| 113 | buffer | ||
| 114 | } | ||
| 115 | |||
| 116 | pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) { | ||
| 117 | let transaction = TransferConfig { | ||
| 118 | iwidth: QspiWidth::SING, | ||
| 119 | awidth: QspiWidth::SING, | ||
| 120 | dwidth: QspiWidth::QUAD, | ||
| 121 | instruction: CMD_QUAD_READ, | ||
| 122 | address: Some(addr), | ||
| 123 | dummy: DummyCycles::_8, | ||
| 124 | }; | ||
| 125 | if use_dma { | ||
| 126 | self.qspi.blocking_read_dma(buffer, transaction); | ||
| 127 | } else { | ||
| 128 | self.qspi.blocking_read(buffer, transaction); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | fn wait_write_finish(&mut self) { | ||
| 133 | while (self.read_sr() & 0x01) != 0 {} | ||
| 134 | } | ||
| 135 | |||
| 136 | fn perform_erase(&mut self, addr: u32, cmd: u8) { | ||
| 137 | let transaction = TransferConfig { | ||
| 138 | iwidth: QspiWidth::SING, | ||
| 139 | awidth: QspiWidth::SING, | ||
| 140 | dwidth: QspiWidth::NONE, | ||
| 141 | instruction: cmd, | ||
| 142 | address: Some(addr), | ||
| 143 | dummy: DummyCycles::_0, | ||
| 144 | }; | ||
| 145 | self.enable_write(); | ||
| 146 | self.qspi.command(transaction); | ||
| 147 | self.wait_write_finish(); | ||
| 148 | } | ||
| 149 | |||
| 150 | pub fn erase_sector(&mut self, addr: u32) { | ||
| 151 | self.perform_erase(addr, CMD_SECTOR_ERASE); | ||
| 152 | } | ||
| 153 | |||
| 154 | pub fn erase_block_32k(&mut self, addr: u32) { | ||
| 155 | self.perform_erase(addr, CMD_BLOCK_ERASE_32K); | ||
| 156 | } | ||
| 157 | |||
| 158 | pub fn erase_block_64k(&mut self, addr: u32) { | ||
| 159 | self.perform_erase(addr, CMD_BLOCK_ERASE_64K); | ||
| 160 | } | ||
| 161 | |||
| 162 | pub fn erase_chip(&mut self) { | ||
| 163 | self.exec_command(CMD_CHIP_ERASE); | ||
| 164 | } | ||
| 165 | |||
| 166 | fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { | ||
| 167 | assert!( | ||
| 168 | (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, | ||
| 169 | "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", | ||
| 170 | len, | ||
| 171 | addr | ||
| 172 | ); | ||
| 173 | |||
| 174 | let transaction = TransferConfig { | ||
| 175 | iwidth: QspiWidth::SING, | ||
| 176 | awidth: QspiWidth::SING, | ||
| 177 | dwidth: QspiWidth::QUAD, | ||
| 178 | instruction: CMD_QUAD_WRITE_PG, | ||
| 179 | address: Some(addr), | ||
| 180 | dummy: DummyCycles::_0, | ||
| 181 | }; | ||
| 182 | self.enable_write(); | ||
| 183 | if use_dma { | ||
| 184 | self.qspi.blocking_write_dma(buffer, transaction); | ||
| 185 | } else { | ||
| 186 | self.qspi.blocking_write(buffer, transaction); | ||
| 187 | } | ||
| 188 | self.wait_write_finish(); | ||
| 189 | } | ||
| 190 | |||
| 191 | pub fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { | ||
| 192 | let mut left = buffer.len(); | ||
| 193 | let mut place = addr; | ||
| 194 | let mut chunk_start = 0; | ||
| 195 | |||
| 196 | while left > 0 { | ||
| 197 | let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; | ||
| 198 | let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; | ||
| 199 | let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; | ||
| 200 | self.write_page(place, chunk, chunk_size, use_dma); | ||
| 201 | place += chunk_size as u32; | ||
| 202 | left -= chunk_size; | ||
| 203 | chunk_start += chunk_size; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | fn read_register(&mut self, cmd: u8) -> u8 { | ||
| 208 | let mut buffer = [0; 1]; | ||
| 209 | let transaction: TransferConfig = TransferConfig { | ||
| 210 | iwidth: QspiWidth::SING, | ||
| 211 | awidth: QspiWidth::NONE, | ||
| 212 | dwidth: QspiWidth::SING, | ||
| 213 | instruction: cmd, | ||
| 214 | address: None, | ||
| 215 | dummy: DummyCycles::_0, | ||
| 216 | }; | ||
| 217 | self.qspi.blocking_read(&mut buffer, transaction); | ||
| 218 | buffer[0] | ||
| 219 | } | ||
| 220 | |||
| 221 | fn write_register(&mut self, cmd: u8, value: u8) { | ||
| 222 | let buffer = [value; 1]; | ||
| 223 | let transaction: TransferConfig = TransferConfig { | ||
| 224 | iwidth: QspiWidth::SING, | ||
| 225 | awidth: QspiWidth::NONE, | ||
| 226 | dwidth: QspiWidth::SING, | ||
| 227 | instruction: cmd, | ||
| 228 | address: None, | ||
| 229 | dummy: DummyCycles::_0, | ||
| 230 | }; | ||
| 231 | self.qspi.blocking_write(&buffer, transaction); | ||
| 232 | } | ||
| 233 | |||
| 234 | pub fn read_sr(&mut self) -> u8 { | ||
| 235 | self.read_register(CMD_READ_SR) | ||
| 236 | } | ||
| 237 | |||
| 238 | pub fn read_cr(&mut self) -> u8 { | ||
| 239 | self.read_register(CMD_READ_CR) | ||
| 240 | } | ||
| 241 | |||
| 242 | pub fn write_sr(&mut self, value: u8) { | ||
| 243 | self.write_register(CMD_WRITE_SR, value); | ||
| 244 | } | ||
| 245 | |||
| 246 | pub fn write_cr(&mut self, value: u8) { | ||
| 247 | self.write_register(CMD_WRITE_CR, value); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | #[embassy_executor::main] | ||
| 252 | async fn main(_spawner: Spawner) -> ! { | ||
| 253 | let mut config = StmCfg::default(); | ||
| 254 | { | ||
| 255 | use embassy_stm32::rcc::*; | ||
| 256 | config.rcc.hse = Some(Hse { | ||
| 257 | freq: mhz(8), | ||
| 258 | mode: HseMode::Oscillator, | ||
| 259 | }); | ||
| 260 | config.rcc.pll_src = PllSource::HSE; | ||
| 261 | config.rcc.pll = Some(Pll { | ||
| 262 | prediv: PllPreDiv::DIV4, | ||
| 263 | mul: PllMul::MUL216, | ||
| 264 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz | ||
| 265 | divq: None, | ||
| 266 | divr: None, | ||
| 267 | }); | ||
| 268 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 269 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 270 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 271 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 272 | } | ||
| 273 | let p = embassy_stm32::init(config); | ||
| 274 | info!("Embassy initialized"); | ||
| 275 | |||
| 276 | let config = QspiCfg { | ||
| 277 | memory_size: MemorySize::_8MiB, | ||
| 278 | address_size: AddressSize::_24bit, | ||
| 279 | prescaler: 16, | ||
| 280 | cs_high_time: ChipSelectHighTime::_1Cycle, | ||
| 281 | fifo_threshold: FIFOThresholdLevel::_16Bytes, | ||
| 282 | }; | ||
| 283 | let driver = Qspi::new_bank1( | ||
| 284 | p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config, | ||
| 285 | ); | ||
| 286 | let mut flash = FlashMemory::new(driver); | ||
| 287 | let flash_id = flash.read_id(); | ||
| 288 | info!("FLASH ID: {:?}", flash_id); | ||
| 289 | let mut wr_buf = [0u8; 256]; | ||
| 290 | for i in 0..256 { | ||
| 291 | wr_buf[i] = i as u8; | ||
| 292 | } | ||
| 293 | let mut rd_buf = [0u8; 256]; | ||
| 294 | flash.erase_sector(MEMORY_ADDR); | ||
| 295 | flash.write_memory(MEMORY_ADDR, &wr_buf, true); | ||
| 296 | flash.read_memory(MEMORY_ADDR, &mut rd_buf, true); | ||
| 297 | info!("WRITE BUF: {:?}", wr_buf); | ||
| 298 | info!("READ BUF: {:?}", rd_buf); | ||
| 299 | info!("End of Program, proceed to empty endless loop"); | ||
| 300 | loop {} | ||
| 301 | } | ||
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index fb604b34f..47456adf2 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs | |||
| @@ -5,7 +5,6 @@ use core::fmt::Write; | |||
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use heapless::String; |
| @@ -19,7 +18,7 @@ bind_interrupts!(struct Irqs { | |||
| 19 | async fn main(_spawner: Spawner) { | 18 | async fn main(_spawner: Spawner) { |
| 20 | let p = embassy_stm32::init(Default::default()); | 19 | let p = embassy_stm32::init(Default::default()); |
| 21 | let config = Config::default(); | 20 | let config = Config::default(); |
| 22 | let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap(); | 21 | let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, p.DMA1_CH3, config).unwrap(); |
| 23 | 22 | ||
| 24 | for n in 0u32.. { | 23 | for n in 0u32.. { |
| 25 | let mut s: String<128> = String::new(); | 24 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 97daf6bd1..1906b28ed 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs | |||
| @@ -3,19 +3,24 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | ||
| 6 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 7 | use embassy_stm32::usb_otg::{Driver, Instance}; | 8 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 10 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| 11 | use embassy_usb::Builder; | 12 | use embassy_usb::Builder; |
| 12 | use futures::future::join; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 16 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 17 | }); | 17 | }); |
| 18 | 18 | ||
| 19 | // If you are trying this and your USB device doesn't connect, the most | ||
| 20 | // common issues are the RCC config and vbus_detection | ||
| 21 | // | ||
| 22 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 23 | // for more information. | ||
| 19 | #[embassy_executor::main] | 24 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) { | 25 | async fn main(_spawner: Spawner) { |
| 21 | info!("Hello World!"); | 26 | info!("Hello World!"); |
| @@ -39,13 +44,20 @@ async fn main(_spawner: Spawner) { | |||
| 39 | config.rcc.apb1_pre = APBPrescaler::DIV4; | 44 | config.rcc.apb1_pre = APBPrescaler::DIV4; |
| 40 | config.rcc.apb2_pre = APBPrescaler::DIV2; | 45 | config.rcc.apb2_pre = APBPrescaler::DIV2; |
| 41 | config.rcc.sys = Sysclk::PLL1_P; | 46 | config.rcc.sys = Sysclk::PLL1_P; |
| 47 | config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; | ||
| 42 | } | 48 | } |
| 43 | let p = embassy_stm32::init(config); | 49 | let p = embassy_stm32::init(config); |
| 44 | 50 | ||
| 45 | // Create the driver, from the HAL. | 51 | // Create the driver, from the HAL. |
| 46 | let mut ep_out_buffer = [0u8; 256]; | 52 | let mut ep_out_buffer = [0u8; 256]; |
| 47 | let mut config = embassy_stm32::usb_otg::Config::default(); | 53 | let mut config = embassy_stm32::usb::Config::default(); |
| 48 | config.vbus_detection = true; | 54 | |
| 55 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 56 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 57 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 58 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 59 | config.vbus_detection = false; | ||
| 60 | |||
| 49 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 61 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 50 | 62 | ||
| 51 | // Create embassy-usb Config | 63 | // Create embassy-usb Config |
| @@ -63,7 +75,6 @@ async fn main(_spawner: Spawner) { | |||
| 63 | 75 | ||
| 64 | // Create embassy-usb DeviceBuilder using the driver and config. | 76 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 65 | // It needs some buffers for building the descriptors. | 77 | // It needs some buffers for building the descriptors. |
| 66 | let mut device_descriptor = [0; 256]; | ||
| 67 | let mut config_descriptor = [0; 256]; | 78 | let mut config_descriptor = [0; 256]; |
| 68 | let mut bos_descriptor = [0; 256]; | 79 | let mut bos_descriptor = [0; 256]; |
| 69 | let mut control_buf = [0; 64]; | 80 | let mut control_buf = [0; 64]; |
| @@ -73,7 +84,6 @@ async fn main(_spawner: Spawner) { | |||
| 73 | let mut builder = Builder::new( | 84 | let mut builder = Builder::new( |
| 74 | driver, | 85 | driver, |
| 75 | config, | 86 | config, |
| 76 | &mut device_descriptor, | ||
| 77 | &mut config_descriptor, | 87 | &mut config_descriptor, |
| 78 | &mut bos_descriptor, | 88 | &mut bos_descriptor, |
| 79 | &mut [], // no msos descriptors | 89 | &mut [], // no msos descriptors |
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 6ce3418e5..a50074ce0 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml | |||
| @@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32g0b1re to your chip name, if necessary. | 8 | # Change stm32g0b1re to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 15 | 15 | ||
| 16 | defmt = "0.3" | 16 | defmt = "0.3" |
| @@ -20,9 +20,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 24 | heapless = { version = "0.8", default-features = false } | 23 | heapless = { version = "0.8", default-features = false } |
| 25 | portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } | 24 | portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } |
| 26 | 25 | ||
| 26 | embedded-io-async = { version = "0.6.1" } | ||
| 27 | |||
| 27 | [profile.release] | 28 | [profile.release] |
| 28 | debug = 2 | 29 | debug = 2 |
diff --git a/examples/stm32g0/src/bin/adc.rs b/examples/stm32g0/src/bin/adc.rs new file mode 100644 index 000000000..6c7f3b48a --- /dev/null +++ b/examples/stm32g0/src/bin/adc.rs | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let mut adc = Adc::new(p.ADC1); | ||
| 16 | adc.set_sample_time(SampleTime::CYCLES79_5); | ||
| 17 | let mut pin = p.PA1; | ||
| 18 | |||
| 19 | let mut vrefint = adc.enable_vrefint(); | ||
| 20 | let vrefint_sample = adc.blocking_read(&mut vrefint); | ||
| 21 | let convert_to_millivolts = |sample| { | ||
| 22 | // From https://www.st.com/resource/en/datasheet/stm32g031g8.pdf | ||
| 23 | // 6.3.3 Embedded internal reference voltage | ||
| 24 | const VREFINT_MV: u32 = 1212; // mV | ||
| 25 | |||
| 26 | (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 | ||
| 27 | }; | ||
| 28 | |||
| 29 | loop { | ||
| 30 | let v = adc.blocking_read(&mut pin); | ||
| 31 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); | ||
| 32 | Timer::after_millis(100).await; | ||
| 33 | } | ||
| 34 | } | ||
diff --git a/examples/stm32g0/src/bin/adc_dma.rs b/examples/stm32g0/src/bin/adc_dma.rs new file mode 100644 index 000000000..3713e5a21 --- /dev/null +++ b/examples/stm32g0/src/bin/adc_dma.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | static mut DMA_BUF: [u16; 2] = [0; 2]; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let mut read_buffer = unsafe { &mut DMA_BUF[..] }; | ||
| 15 | |||
| 16 | let p = embassy_stm32::init(Default::default()); | ||
| 17 | |||
| 18 | info!("Hello World!"); | ||
| 19 | |||
| 20 | let mut adc = Adc::new(p.ADC1); | ||
| 21 | |||
| 22 | let mut dma = p.DMA1_CH1; | ||
| 23 | let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); | ||
| 24 | let mut pa0 = p.PA0.degrade_adc(); | ||
| 25 | |||
| 26 | loop { | ||
| 27 | adc.read( | ||
| 28 | &mut dma, | ||
| 29 | [ | ||
| 30 | (&mut vrefint_channel, SampleTime::CYCLES160_5), | ||
| 31 | (&mut pa0, SampleTime::CYCLES160_5), | ||
| 32 | ] | ||
| 33 | .into_iter(), | ||
| 34 | &mut read_buffer, | ||
| 35 | ) | ||
| 36 | .await; | ||
| 37 | |||
| 38 | let vrefint = read_buffer[0]; | ||
| 39 | let measured = read_buffer[1]; | ||
| 40 | info!("vrefint: {}", vrefint); | ||
| 41 | info!("measured: {}", measured); | ||
| 42 | Timer::after_millis(500).await; | ||
| 43 | } | ||
| 44 | } | ||
diff --git a/examples/stm32g0/src/bin/adc_oversampling.rs b/examples/stm32g0/src/bin/adc_oversampling.rs new file mode 100644 index 000000000..9c5dd872a --- /dev/null +++ b/examples/stm32g0/src/bin/adc_oversampling.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | //! adc oversampling example | ||
| 2 | //! | ||
| 3 | //! This example uses adc oversampling to achieve 16bit data | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 11 | use embassy_time::Timer; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) { | ||
| 16 | let p = embassy_stm32::init(Default::default()); | ||
| 17 | info!("Adc oversample test"); | ||
| 18 | |||
| 19 | let mut adc = Adc::new(p.ADC1); | ||
| 20 | adc.set_sample_time(SampleTime::CYCLES1_5); | ||
| 21 | let mut pin = p.PA1; | ||
| 22 | |||
| 23 | // From https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf | ||
| 24 | // page373 15.8 Oversampler | ||
| 25 | // Table 76. Maximum output results vs N and M. Grayed values indicates truncation | ||
| 26 | // 0x00 oversampling ratio X2 | ||
| 27 | // 0x01 oversampling ratio X4 | ||
| 28 | // 0x02 oversampling ratio X8 | ||
| 29 | // 0x03 oversampling ratio X16 | ||
| 30 | // 0x04 oversampling ratio X32 | ||
| 31 | // 0x05 oversampling ratio X64 | ||
| 32 | // 0x06 oversampling ratio X128 | ||
| 33 | // 0x07 oversampling ratio X256 | ||
| 34 | adc.set_oversampling_ratio(0x03); | ||
| 35 | adc.set_oversampling_shift(0b0000); | ||
| 36 | adc.oversampling_enable(true); | ||
| 37 | |||
| 38 | loop { | ||
| 39 | let v = adc.blocking_read(&mut pin); | ||
| 40 | info!("--> {} ", v); //max 65520 = 0xFFF0 | ||
| 41 | Timer::after_millis(100).await; | ||
| 42 | } | ||
| 43 | } | ||
diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 78a779e29..3ea06cdee 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs | |||
| @@ -4,37 +4,36 @@ | |||
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::gpio::OutputType; | 6 | use embassy_stm32::gpio::OutputType; |
| 7 | use embassy_stm32::pac::rcc::vals::Tim1sel; | ||
| 8 | use embassy_stm32::rcc::{ClockSrc, Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr}; | ||
| 9 | use embassy_stm32::time::khz; | 7 | use embassy_stm32::time::khz; |
| 10 | use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; | 8 | use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; |
| 11 | use embassy_stm32::timer::simple_pwm::PwmPin; | 9 | use embassy_stm32::timer::simple_pwm::PwmPin; |
| 12 | use embassy_stm32::timer::Channel; | 10 | use embassy_stm32::timer::Channel; |
| 13 | use embassy_stm32::{pac, Config as PeripheralConfig}; | 11 | use embassy_stm32::Config as PeripheralConfig; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 13 | ||
| 16 | #[embassy_executor::main] | 14 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 15 | async fn main(_spawner: Spawner) { |
| 18 | let mut rcc_config = RccConfig::default(); | 16 | let mut config = PeripheralConfig::default(); |
| 19 | rcc_config.mux = ClockSrc::PLL(PllConfig { | 17 | { |
| 20 | source: PllSource::HSI, | 18 | use embassy_stm32::rcc::*; |
| 21 | m: Pllm::DIV1, | 19 | config.rcc.hsi = true; |
| 22 | n: Plln::MUL16, | 20 | config.rcc.pll = Some(Pll { |
| 23 | r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) | 21 | source: PllSource::HSI, |
| 24 | q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) | 22 | prediv: PllPreDiv::DIV1, |
| 25 | p: None, | 23 | mul: PllMul::MUL16, |
| 26 | }); | 24 | divp: None, |
| 27 | 25 | divq: Some(PllQDiv::DIV2), // 16 / 1 * 16 / 2 = 128 Mhz | |
| 28 | let mut peripheral_config = PeripheralConfig::default(); | 26 | divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz |
| 29 | peripheral_config.rcc = rcc_config; | 27 | }); |
| 30 | 28 | config.rcc.sys = Sysclk::PLL1_R; | |
| 31 | let p = embassy_stm32::init(peripheral_config); | 29 | |
| 32 | 30 | // configure TIM1 mux to select PLLQ as clock source | |
| 33 | // configure TIM1 mux to select PLLQ as clock source | 31 | // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf |
| 34 | // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf | 32 | // RM0444 page 210 |
| 35 | // RM0444 page 210 | 33 | // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 |
| 36 | // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1 | 34 | config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q; |
| 37 | pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q)); | 35 | } |
| 36 | let p = embassy_stm32::init(config); | ||
| 38 | 37 | ||
| 39 | let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); | 38 | let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); |
| 40 | let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); | 39 | let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); |
diff --git a/examples/stm32g0/src/bin/i2c_async.rs b/examples/stm32g0/src/bin/i2c_async.rs new file mode 100644 index 000000000..7e3189b05 --- /dev/null +++ b/examples/stm32g0/src/bin/i2c_async.rs | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::i2c::{self, I2c}; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | const TMP117_ADDR: u8 = 0x48; | ||
| 17 | const TMP117_TEMP_RESULT: u8 = 0x00; | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) { | ||
| 21 | info!("Hello world"); | ||
| 22 | |||
| 23 | let p = embassy_stm32::init(Default::default()); | ||
| 24 | |||
| 25 | let mut data = [0u8; 2]; | ||
| 26 | let mut i2c = I2c::new( | ||
| 27 | p.I2C1, | ||
| 28 | p.PB8, | ||
| 29 | p.PB9, | ||
| 30 | Irqs, | ||
| 31 | p.DMA1_CH1, | ||
| 32 | p.DMA1_CH2, | ||
| 33 | Hertz(100_000), | ||
| 34 | Default::default(), | ||
| 35 | ); | ||
| 36 | |||
| 37 | loop { | ||
| 38 | match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data).await { | ||
| 39 | Ok(()) => { | ||
| 40 | let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0; | ||
| 41 | info!("Temperature {}", temp); | ||
| 42 | } | ||
| 43 | Err(_) => error!("I2C Error"), | ||
| 44 | } | ||
| 45 | |||
| 46 | Timer::after(Duration::from_millis(1000)).await; | ||
| 47 | } | ||
| 48 | } | ||
diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs new file mode 100644 index 000000000..69fdae96d --- /dev/null +++ b/examples/stm32g0/src/bin/input_capture.rs | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | //! Input capture example | ||
| 2 | //! | ||
| 3 | //! This example showcases how to use the input capture feature of the timer peripheral. | ||
| 4 | //! Connect PB1 and PA6 with a 1k Ohm resistor or Connect PB1 and PA8 with a 1k Ohm resistor | ||
| 5 | //! to see the output. | ||
| 6 | //! When connecting PB1 (software pwm) and PA6 the output is around 10000 (it will be a bit bigger, around 10040) | ||
| 7 | //! Output is 1000 when connecting PB1 (PWMOUT) and PA6. | ||
| 8 | //! | ||
| 9 | #![no_std] | ||
| 10 | #![no_main] | ||
| 11 | |||
| 12 | use defmt::*; | ||
| 13 | use embassy_executor::Spawner; | ||
| 14 | use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; | ||
| 15 | use embassy_stm32::time::khz; | ||
| 16 | use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; | ||
| 17 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; | ||
| 18 | use embassy_stm32::timer::Channel; | ||
| 19 | use embassy_stm32::{bind_interrupts, peripherals, timer}; | ||
| 20 | use embassy_time::Timer; | ||
| 21 | use {defmt_rtt as _, panic_probe as _}; | ||
| 22 | |||
| 23 | // Connect PB1 and PA6 with a 1k Ohm resistor | ||
| 24 | |||
| 25 | #[embassy_executor::task] | ||
| 26 | async fn blinky(led: peripherals::PB1) { | ||
| 27 | let mut led = Output::new(led, Level::High, Speed::Low); | ||
| 28 | |||
| 29 | loop { | ||
| 30 | led.set_high(); | ||
| 31 | Timer::after_millis(50).await; | ||
| 32 | |||
| 33 | led.set_low(); | ||
| 34 | Timer::after_millis(50).await; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | bind_interrupts!(struct Irqs { | ||
| 39 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 40 | }); | ||
| 41 | |||
| 42 | #[embassy_executor::main] | ||
| 43 | async fn main(spawner: Spawner) { | ||
| 44 | let p = embassy_stm32::init(Default::default()); | ||
| 45 | info!("Hello World!"); | ||
| 46 | |||
| 47 | unwrap!(spawner.spawn(blinky(p.PB1))); | ||
| 48 | |||
| 49 | // Connect PB1 and PA8 with a 1k Ohm resistor | ||
| 50 | let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); | ||
| 51 | let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default()); | ||
| 52 | pwm.enable(Channel::Ch1); | ||
| 53 | pwm.set_duty(Channel::Ch1, 50); | ||
| 54 | |||
| 55 | let ch1 = CapturePin::new_ch1(p.PA0, Pull::None); | ||
| 56 | let mut ic = InputCapture::new(p.TIM2, Some(ch1), None, None, None, Irqs, khz(1000), Default::default()); | ||
| 57 | |||
| 58 | let mut old_capture = 0; | ||
| 59 | |||
| 60 | loop { | ||
| 61 | ic.wait_for_rising_edge(Channel::Ch1).await; | ||
| 62 | |||
| 63 | let capture_value = ic.get_capture_value(Channel::Ch1); | ||
| 64 | info!("{}", capture_value - old_capture); | ||
| 65 | old_capture = capture_value; | ||
| 66 | } | ||
| 67 | } | ||
diff --git a/examples/stm32g0/src/bin/pwm_complementary.rs b/examples/stm32g0/src/bin/pwm_complementary.rs new file mode 100644 index 000000000..97b163c40 --- /dev/null +++ b/examples/stm32g0/src/bin/pwm_complementary.rs | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | //! PWM complementary example | ||
| 2 | //! | ||
| 3 | //! This example uses two complementary pwm outputs from TIM1 with different duty cycles | ||
| 4 | //! ___ ___ | ||
| 5 | //! |_________| |_________| PA8 | ||
| 6 | //! _________ _________ | ||
| 7 | //! ___| |___| | PA7 | ||
| 8 | //! _________ _________ | ||
| 9 | //! |___| |___| PB3 | ||
| 10 | //! ___ ___ | ||
| 11 | //! _________| |_________| | PB0 | ||
| 12 | |||
| 13 | #![no_std] | ||
| 14 | #![no_main] | ||
| 15 | |||
| 16 | use defmt::info; | ||
| 17 | use embassy_executor::Spawner; | ||
| 18 | use embassy_stm32::gpio::OutputType; | ||
| 19 | use embassy_stm32::time::khz; | ||
| 20 | use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; | ||
| 21 | use embassy_stm32::timer::simple_pwm::PwmPin; | ||
| 22 | use embassy_stm32::timer::Channel; | ||
| 23 | use {defmt_rtt as _, panic_probe as _}; | ||
| 24 | |||
| 25 | #[embassy_executor::main] | ||
| 26 | async fn main(_spawner: Spawner) { | ||
| 27 | let p = embassy_stm32::init(Default::default()); | ||
| 28 | |||
| 29 | let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); | ||
| 30 | let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull); | ||
| 31 | let ch2 = PwmPin::new_ch2(p.PB3, OutputType::PushPull); | ||
| 32 | let ch2n = ComplementaryPwmPin::new_ch2(p.PB0, OutputType::PushPull); | ||
| 33 | |||
| 34 | let mut pwm = ComplementaryPwm::new( | ||
| 35 | p.TIM1, | ||
| 36 | Some(ch1), | ||
| 37 | Some(ch1n), | ||
| 38 | Some(ch2), | ||
| 39 | Some(ch2n), | ||
| 40 | None, | ||
| 41 | None, | ||
| 42 | None, | ||
| 43 | None, | ||
| 44 | khz(100), | ||
| 45 | Default::default(), | ||
| 46 | ); | ||
| 47 | |||
| 48 | let max = pwm.get_max_duty(); | ||
| 49 | info!("Max duty: {}", max); | ||
| 50 | |||
| 51 | pwm.set_duty(Channel::Ch1, max / 4); | ||
| 52 | pwm.enable(Channel::Ch1); | ||
| 53 | pwm.set_duty(Channel::Ch2, max * 3 / 4); | ||
| 54 | pwm.enable(Channel::Ch2); | ||
| 55 | |||
| 56 | loop {} | ||
| 57 | } | ||
diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs new file mode 100644 index 000000000..152ecda86 --- /dev/null +++ b/examples/stm32g0/src/bin/pwm_input.rs | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | //! PWM input example | ||
| 2 | //! | ||
| 3 | //! This program demonstrates how to capture the parameters of the input waveform (frequency, width and duty cycle) | ||
| 4 | //! Connect PB1 and PA6 with a 1k Ohm resistor or Connect PB1 and PA8 with a 1k Ohm resistor | ||
| 5 | //! to see the output. | ||
| 6 | //! | ||
| 7 | |||
| 8 | #![no_std] | ||
| 9 | #![no_main] | ||
| 10 | |||
| 11 | use defmt::*; | ||
| 12 | use embassy_executor::Spawner; | ||
| 13 | use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; | ||
| 14 | use embassy_stm32::time::khz; | ||
| 15 | use embassy_stm32::timer::pwm_input::PwmInput; | ||
| 16 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; | ||
| 17 | use embassy_stm32::timer::Channel; | ||
| 18 | use embassy_stm32::{bind_interrupts, peripherals, timer}; | ||
| 19 | use embassy_time::Timer; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | // Connect PB1 and PA6 with a 1k Ohm resistor | ||
| 23 | #[embassy_executor::task] | ||
| 24 | async fn blinky(led: peripherals::PB1) { | ||
| 25 | let mut led = Output::new(led, Level::High, Speed::Low); | ||
| 26 | |||
| 27 | loop { | ||
| 28 | led.set_high(); | ||
| 29 | Timer::after_millis(50).await; | ||
| 30 | |||
| 31 | led.set_low(); | ||
| 32 | Timer::after_millis(50).await; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | bind_interrupts!(struct Irqs { | ||
| 37 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 38 | }); | ||
| 39 | |||
| 40 | #[embassy_executor::main] | ||
| 41 | async fn main(spawner: Spawner) { | ||
| 42 | let p = embassy_stm32::init(Default::default()); | ||
| 43 | |||
| 44 | unwrap!(spawner.spawn(blinky(p.PB1))); | ||
| 45 | // Connect PA8 and PA6 with a 1k Ohm resistor | ||
| 46 | let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); | ||
| 47 | let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default()); | ||
| 48 | let max = pwm.get_max_duty(); | ||
| 49 | pwm.set_duty(Channel::Ch1, max / 4); | ||
| 50 | pwm.enable(Channel::Ch1); | ||
| 51 | |||
| 52 | let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(1000)); | ||
| 53 | pwm_input.enable(); | ||
| 54 | |||
| 55 | loop { | ||
| 56 | Timer::after_millis(500).await; | ||
| 57 | let period = pwm_input.get_period_ticks(); | ||
| 58 | let width = pwm_input.get_width_ticks(); | ||
| 59 | let duty_cycle = pwm_input.get_duty_cycle(); | ||
| 60 | info!( | ||
| 61 | "period ticks: {} width ticks: {} duty cycle: {}", | ||
| 62 | period, width, duty_cycle | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | } | ||
diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs new file mode 100644 index 000000000..c02c1ecd7 --- /dev/null +++ b/examples/stm32g0/src/bin/rtc.rs | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig}; | ||
| 7 | use embassy_stm32::Config; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner) { | ||
| 13 | let config = Config::default(); | ||
| 14 | let p = embassy_stm32::init(config); | ||
| 15 | |||
| 16 | info!("Hello World!"); | ||
| 17 | |||
| 18 | let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10); | ||
| 19 | |||
| 20 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 21 | |||
| 22 | rtc.set_datetime(now.unwrap()).expect("datetime not set"); | ||
| 23 | |||
| 24 | loop { | ||
| 25 | let now: DateTime = rtc.now().unwrap().into(); | ||
| 26 | |||
| 27 | info!("{}:{}:{}", now.hour(), now.minute(), now.second()); | ||
| 28 | |||
| 29 | Timer::after_millis(1000).await; | ||
| 30 | } | ||
| 31 | } | ||
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs index c5ea51721..edcae74f7 100644 --- a/examples/stm32g0/src/bin/spi_neopixel.rs +++ b/examples/stm32g0/src/bin/spi_neopixel.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::word::U5; | 6 | use embassy_stm32::dma::word::U5; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| @@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) { | |||
| 77 | 76 | ||
| 78 | let mut config = Config::default(); | 77 | let mut config = Config::default(); |
| 79 | config.frequency = Hertz(4_000_000); | 78 | config.frequency = Hertz(4_000_000); |
| 80 | let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, config); | 79 | let mut spi = Spi::new_txonly(p.SPI1, p.PB3, p.PB5, p.DMA1_CH3, config); // SCK is unused. |
| 81 | 80 | ||
| 82 | let mut neopixels = Ws2812::new(); | 81 | let mut neopixels = Ws2812::new(); |
| 83 | 82 | ||
diff --git a/examples/stm32g0/src/bin/usart.rs b/examples/stm32g0/src/bin/usart.rs new file mode 100644 index 000000000..037a5c833 --- /dev/null +++ b/examples/stm32g0/src/bin/usart.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_stm32::usart::{Config, Uart}; | ||
| 6 | use {defmt_rtt as _, panic_probe as _}; | ||
| 7 | |||
| 8 | #[cortex_m_rt::entry] | ||
| 9 | fn main() -> ! { | ||
| 10 | info!("Hello World!"); | ||
| 11 | |||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | |||
| 14 | let config = Config::default(); | ||
| 15 | let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap(); | ||
| 16 | |||
| 17 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||
| 18 | info!("wrote Hello, starting echo"); | ||
| 19 | |||
| 20 | let mut buf = [0u8; 1]; | ||
| 21 | loop { | ||
| 22 | unwrap!(usart.blocking_read(&mut buf)); | ||
| 23 | unwrap!(usart.blocking_write(&buf)); | ||
| 24 | } | ||
| 25 | } | ||
diff --git a/examples/stm32g0/src/bin/usart_buffered.rs b/examples/stm32g0/src/bin/usart_buffered.rs new file mode 100644 index 000000000..c097a0c5a --- /dev/null +++ b/examples/stm32g0/src/bin/usart_buffered.rs | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::usart::{BufferedUart, Config}; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 8 | use embedded_io_async::{Read, Write}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | USART1 => usart::BufferedInterruptHandler<peripherals::USART1>; | ||
| 13 | }); | ||
| 14 | |||
| 15 | #[embassy_executor::main] | ||
| 16 | async fn main(_spawner: Spawner) { | ||
| 17 | let p = embassy_stm32::init(Default::default()); | ||
| 18 | info!("Hi!"); | ||
| 19 | |||
| 20 | let mut config = Config::default(); | ||
| 21 | config.baudrate = 115200; | ||
| 22 | let mut tx_buf = [0u8; 256]; | ||
| 23 | let mut rx_buf = [0u8; 256]; | ||
| 24 | let mut usart = BufferedUart::new(p.USART1, Irqs, p.PB7, p.PB6, &mut tx_buf, &mut rx_buf, config).unwrap(); | ||
| 25 | |||
| 26 | usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); | ||
| 27 | info!("wrote Hello, starting echo"); | ||
| 28 | |||
| 29 | let mut buf = [0; 4]; | ||
| 30 | loop { | ||
| 31 | usart.read_exact(&mut buf[..]).await.unwrap(); | ||
| 32 | usart.write_all(&buf[..]).await.unwrap(); | ||
| 33 | } | ||
| 34 | } | ||
diff --git a/examples/stm32g0/src/bin/usart_dma.rs b/examples/stm32g0/src/bin/usart_dma.rs new file mode 100644 index 000000000..8212153ab --- /dev/null +++ b/examples/stm32g0/src/bin/usart_dma.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::usart::{Config, Uart}; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | USART1 => usart::InterruptHandler<peripherals::USART1>; | ||
| 12 | }); | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) { | ||
| 16 | let p = embassy_stm32::init(Default::default()); | ||
| 17 | let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default()).unwrap(); | ||
| 18 | |||
| 19 | usart.write(b"Hello Embassy World!\r\n").await.unwrap(); | ||
| 20 | info!("wrote Hello, starting echo"); | ||
| 21 | |||
| 22 | let mut buf = [0; 5]; | ||
| 23 | loop { | ||
| 24 | usart.read(&mut buf[..]).await.unwrap(); | ||
| 25 | usart.write(&buf[..]).await.unwrap(); | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs index f5aaa5624..162dfd86b 100644 --- a/examples/stm32g0/src/bin/usb_serial.rs +++ b/examples/stm32g0/src/bin/usb_serial.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::rcc::{Hsi48Config, UsbSrc}; | ||
| 8 | use embassy_stm32::usb::{Driver, Instance}; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| @@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs { | |||
| 19 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) { | 19 | async fn main(_spawner: Spawner) { |
| 21 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 22 | config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config { | 21 | { |
| 23 | sync_from_usb: true, | 22 | use embassy_stm32::rcc::*; |
| 24 | ..Default::default() | 23 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); |
| 25 | })); | 24 | config.rcc.mux.usbsel = mux::Usbsel::HSI48; |
| 25 | } | ||
| 26 | let p = embassy_stm32::init(config); | 26 | let p = embassy_stm32::init(config); |
| 27 | 27 | ||
| 28 | info!("Hello World!"); | 28 | info!("Hello World!"); |
| @@ -36,7 +36,6 @@ async fn main(_spawner: Spawner) { | |||
| 36 | 36 | ||
| 37 | // Create embassy-usb DeviceBuilder using the driver and config. | 37 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 38 | // It needs some buffers for building the descriptors. | 38 | // It needs some buffers for building the descriptors. |
| 39 | let mut device_descriptor = [0; 256]; | ||
| 40 | let mut config_descriptor = [0; 256]; | 39 | let mut config_descriptor = [0; 256]; |
| 41 | let mut bos_descriptor = [0; 256]; | 40 | let mut bos_descriptor = [0; 256]; |
| 42 | let mut control_buf = [0; 7]; | 41 | let mut control_buf = [0; 7]; |
| @@ -46,7 +45,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | let mut builder = Builder::new( | 45 | let mut builder = Builder::new( |
| 47 | driver, | 46 | driver, |
| 48 | config, | 47 | config, |
| 49 | &mut device_descriptor, | ||
| 50 | &mut config_descriptor, | 48 | &mut config_descriptor, |
| 51 | &mut bos_descriptor, | 49 | &mut bos_descriptor, |
| 52 | &mut [], // no msos descriptors | 50 | &mut [], // no msos descriptors |
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 895ad3e7c..2768147a1 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml | |||
| @@ -7,12 +7,12 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32g491re to your chip name, if necessary. | 8 | # Change stm32g491re to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 15 | usbd-hid = "0.6.0" | 15 | usbd-hid = "0.8.1" |
| 16 | 16 | ||
| 17 | defmt = "0.3" | 17 | defmt = "0.3" |
| 18 | defmt-rtt = "0.4" | 18 | defmt-rtt = "0.4" |
| @@ -20,9 +20,10 @@ defmt-rtt = "0.4" | |||
| 20 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 20 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 21 | cortex-m-rt = "0.7.0" | 21 | cortex-m-rt = "0.7.0" |
| 22 | embedded-hal = "0.2.6" | 22 | embedded-hal = "0.2.6" |
| 23 | embedded-can = { version = "0.4" } | ||
| 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 24 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 25 | heapless = { version = "0.8", default-features = false } | 25 | heapless = { version = "0.8", default-features = false } |
| 26 | static_cell = "2.0.0" | ||
| 26 | 27 | ||
| 27 | [profile.release] | 28 | [profile.release] |
| 28 | debug = 2 | 29 | debug = 2 |
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 35324d931..adca846d8 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs | |||
| @@ -4,36 +4,35 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | 6 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 7 | use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSource}; | ||
| 8 | use embassy_stm32::Config; | 7 | use embassy_stm32::Config; |
| 9 | use embassy_time::{Delay, Timer}; | 8 | use embassy_time::Timer; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 10 | ||
| 12 | #[embassy_executor::main] | 11 | #[embassy_executor::main] |
| 13 | async fn main(_spawner: Spawner) { | 12 | async fn main(_spawner: Spawner) { |
| 14 | let mut config = Config::default(); | 13 | let mut config = Config::default(); |
| 15 | 14 | { | |
| 16 | config.rcc.pll = Some(Pll { | 15 | use embassy_stm32::rcc::*; |
| 17 | source: PllSource::HSI, | 16 | config.rcc.pll = Some(Pll { |
| 18 | prediv_m: PllM::DIV4, | 17 | source: PllSource::HSI, |
| 19 | mul_n: PllN::MUL85, | 18 | prediv: PllPreDiv::DIV4, |
| 20 | div_p: None, | 19 | mul: PllMul::MUL85, |
| 21 | div_q: None, | 20 | divp: None, |
| 22 | // Main system clock at 170 MHz | 21 | divq: None, |
| 23 | div_r: Some(PllR::DIV2), | 22 | // Main system clock at 170 MHz |
| 24 | }); | 23 | divr: Some(PllRDiv::DIV2), |
| 25 | 24 | }); | |
| 26 | config.rcc.adc12_clock_source = AdcClockSource::SYS; | 25 | config.rcc.mux.adc12sel = mux::Adcsel::SYS; |
| 27 | config.rcc.mux = ClockSrc::PLL; | 26 | config.rcc.sys = Sysclk::PLL1_R; |
| 28 | 27 | } | |
| 29 | let mut p = embassy_stm32::init(config); | 28 | let mut p = embassy_stm32::init(config); |
| 30 | info!("Hello World!"); | 29 | info!("Hello World!"); |
| 31 | 30 | ||
| 32 | let mut adc = Adc::new(p.ADC2, &mut Delay); | 31 | let mut adc = Adc::new(p.ADC2); |
| 33 | adc.set_sample_time(SampleTime::Cycles32_5); | 32 | adc.set_sample_time(SampleTime::CYCLES24_5); |
| 34 | 33 | ||
| 35 | loop { | 34 | loop { |
| 36 | let measured = adc.read(&mut p.PA7); | 35 | let measured = adc.blocking_read(&mut p.PA7); |
| 37 | info!("measured: {}", measured); | 36 | info!("measured: {}", measured); |
| 38 | Timer::after_millis(500).await; | 37 | Timer::after_millis(500).await; |
| 39 | } | 38 | } |
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 @@ | |||
| 1 | //! adc differential mode example | ||
| 2 | //! | ||
| 3 | //! This example uses adc1 in differential mode | ||
| 4 | //! p:pa0 n:pa1 | ||
| 5 | |||
| 6 | #![no_std] | ||
| 7 | #![no_main] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 12 | use embassy_stm32::Config; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = Config::default(); | ||
| 19 | { | ||
| 20 | use embassy_stm32::rcc::*; | ||
| 21 | config.rcc.pll = Some(Pll { | ||
| 22 | source: PllSource::HSI, | ||
| 23 | prediv: PllPreDiv::DIV4, | ||
| 24 | mul: PllMul::MUL85, | ||
| 25 | divp: None, | ||
| 26 | divq: None, | ||
| 27 | // Main system clock at 170 MHz | ||
| 28 | divr: Some(PllRDiv::DIV2), | ||
| 29 | }); | ||
| 30 | config.rcc.mux.adc12sel = mux::Adcsel::SYS; | ||
| 31 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 32 | } | ||
| 33 | let mut p = embassy_stm32::init(config); | ||
| 34 | |||
| 35 | let mut adc = Adc::new(p.ADC1); | ||
| 36 | adc.set_sample_time(SampleTime::CYCLES247_5); | ||
| 37 | adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1 | ||
| 38 | |||
| 39 | // can also use | ||
| 40 | // adc.set_differential_channel(1, true); | ||
| 41 | info!("adc initialized"); | ||
| 42 | loop { | ||
| 43 | let measured = adc.blocking_read(&mut p.PA0); | ||
| 44 | info!("data: {}", measured); | ||
| 45 | Timer::after_millis(500).await; | ||
| 46 | } | ||
| 47 | } | ||
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 @@ | |||
| 1 | //! adc oversampling example | ||
| 2 | //! | ||
| 3 | //! This example uses adc oversampling to achieve 16bit data | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_stm32::adc::vals::{Rovsm, Trovs}; | ||
| 11 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 12 | use embassy_stm32::Config; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = Config::default(); | ||
| 19 | { | ||
| 20 | use embassy_stm32::rcc::*; | ||
| 21 | config.rcc.pll = Some(Pll { | ||
| 22 | source: PllSource::HSI, | ||
| 23 | prediv: PllPreDiv::DIV4, | ||
| 24 | mul: PllMul::MUL85, | ||
| 25 | divp: None, | ||
| 26 | divq: None, | ||
| 27 | // Main system clock at 170 MHz | ||
| 28 | divr: Some(PllRDiv::DIV2), | ||
| 29 | }); | ||
| 30 | config.rcc.mux.adc12sel = mux::Adcsel::SYS; | ||
| 31 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 32 | } | ||
| 33 | let mut p = embassy_stm32::init(config); | ||
| 34 | |||
| 35 | let mut adc = Adc::new(p.ADC1); | ||
| 36 | adc.set_sample_time(SampleTime::CYCLES6_5); | ||
| 37 | // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf | ||
| 38 | // page652 Oversampler | ||
| 39 | // Table 172. Maximum output results vs N and M. Grayed values indicates truncation | ||
| 40 | // 0x00 oversampling ratio X2 | ||
| 41 | // 0x01 oversampling ratio X4 | ||
| 42 | // 0x02 oversampling ratio X8 | ||
| 43 | // 0x03 oversampling ratio X16 | ||
| 44 | // 0x04 oversampling ratio X32 | ||
| 45 | // 0x05 oversampling ratio X64 | ||
| 46 | // 0x06 oversampling ratio X128 | ||
| 47 | // 0x07 oversampling ratio X256 | ||
| 48 | adc.set_oversampling_ratio(0x03); // ratio X3 | ||
| 49 | adc.set_oversampling_shift(0b0000); // no shift | ||
| 50 | adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true); | ||
| 51 | |||
| 52 | loop { | ||
| 53 | let measured = adc.blocking_read(&mut p.PA0); | ||
| 54 | info!("data: 0x{:X}", measured); //max 0xFFF0 -> 65520 | ||
| 55 | Timer::after_millis(500).await; | ||
| 56 | } | ||
| 57 | } | ||
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 727921fba..90004f874 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs | |||
| @@ -3,8 +3,10 @@ | |||
| 3 | use defmt::*; | 3 | use defmt::*; |
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_stm32::peripherals::*; | 5 | use embassy_stm32::peripherals::*; |
| 6 | use embassy_stm32::time::Hertz; | ||
| 6 | use embassy_stm32::{bind_interrupts, can, Config}; | 7 | use embassy_stm32::{bind_interrupts, can, Config}; |
| 7 | use embassy_time::Timer; | 8 | use embassy_time::Timer; |
| 9 | use static_cell::StaticCell; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 11 | ||
| 10 | bind_interrupts!(struct Irqs { | 12 | bind_interrupts!(struct Irqs { |
| @@ -14,43 +16,219 @@ bind_interrupts!(struct Irqs { | |||
| 14 | 16 | ||
| 15 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
| 16 | async fn main(_spawner: Spawner) { | 18 | async fn main(_spawner: Spawner) { |
| 17 | let config = Config::default(); | 19 | let mut config = Config::default(); |
| 18 | 20 | { | |
| 21 | use embassy_stm32::rcc::*; | ||
| 22 | config.rcc.hse = Some(Hse { | ||
| 23 | freq: Hertz(24_000_000), | ||
| 24 | mode: HseMode::Oscillator, | ||
| 25 | }); | ||
| 26 | config.rcc.pll = Some(Pll { | ||
| 27 | source: PllSource::HSE, | ||
| 28 | prediv: PllPreDiv::DIV6, | ||
| 29 | mul: PllMul::MUL85, | ||
| 30 | divp: None, | ||
| 31 | divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan. | ||
| 32 | divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz | ||
| 33 | }); | ||
| 34 | config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q; | ||
| 35 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 36 | } | ||
| 19 | let peripherals = embassy_stm32::init(config); | 37 | let peripherals = embassy_stm32::init(config); |
| 20 | 38 | ||
| 21 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 39 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 40 | |||
| 41 | can.properties().set_extended_filter( | ||
| 42 | can::filter::ExtendedFilterSlot::_0, | ||
| 43 | can::filter::ExtendedFilter::accept_all_into_fifo1(), | ||
| 44 | ); | ||
| 22 | 45 | ||
| 23 | // 250k bps | 46 | // 250k bps |
| 24 | can.set_bitrate(250_000); | 47 | can.set_bitrate(250_000); |
| 25 | 48 | ||
| 49 | let use_fd = false; | ||
| 50 | |||
| 51 | // 1M bps | ||
| 52 | if use_fd { | ||
| 53 | can.set_fd_data_bitrate(1_000_000, false); | ||
| 54 | } | ||
| 55 | |||
| 26 | info!("Configured"); | 56 | info!("Configured"); |
| 27 | 57 | ||
| 28 | //let mut can = can.into_external_loopback_mode(); | 58 | let mut can = can.start(match use_fd { |
| 29 | let mut can = can.into_normal_mode(); | 59 | true => can::OperatingMode::InternalLoopbackMode, |
| 60 | false => can::OperatingMode::NormalOperationMode, | ||
| 61 | }); | ||
| 30 | 62 | ||
| 31 | let mut i = 0; | 63 | let mut i = 0; |
| 64 | let mut last_read_ts = embassy_time::Instant::now(); | ||
| 65 | |||
| 32 | loop { | 66 | loop { |
| 33 | let frame = can::TxFrame::new( | 67 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 34 | can::TxFrameHeader { | ||
| 35 | len: 1, | ||
| 36 | frame_format: can::FrameFormat::Standard, | ||
| 37 | id: can::StandardId::new(0x123).unwrap().into(), | ||
| 38 | bit_rate_switching: false, | ||
| 39 | marker: None, | ||
| 40 | }, | ||
| 41 | &[i], | ||
| 42 | ) | ||
| 43 | .unwrap(); | ||
| 44 | info!("Writing frame"); | 68 | info!("Writing frame"); |
| 69 | |||
| 45 | _ = can.write(&frame).await; | 70 | _ = can.write(&frame).await; |
| 46 | 71 | ||
| 47 | match can.read().await { | 72 | match can.read().await { |
| 48 | Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), | 73 | Ok(envelope) => { |
| 74 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 75 | let delta = (ts - last_read_ts).as_millis(); | ||
| 76 | last_read_ts = ts; | ||
| 77 | info!( | ||
| 78 | "Rx: {} {:02x} --- {}ms", | ||
| 79 | rx_frame.header().len(), | ||
| 80 | rx_frame.data()[0..rx_frame.header().len() as usize], | ||
| 81 | delta, | ||
| 82 | ) | ||
| 83 | } | ||
| 84 | Err(_err) => error!("Error in frame"), | ||
| 85 | } | ||
| 86 | |||
| 87 | Timer::after_millis(250).await; | ||
| 88 | |||
| 89 | i += 1; | ||
| 90 | if i > 2 { | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | // Use the FD API's even if we don't get FD packets. | ||
| 96 | |||
| 97 | loop { | ||
| 98 | if use_fd { | ||
| 99 | let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap(); | ||
| 100 | info!("Writing frame using FD API"); | ||
| 101 | _ = can.write_fd(&frame).await; | ||
| 102 | } else { | ||
| 103 | let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 104 | info!("Writing frame using FD API"); | ||
| 105 | _ = can.write_fd(&frame).await; | ||
| 106 | } | ||
| 107 | |||
| 108 | match can.read_fd().await { | ||
| 109 | Ok(envelope) => { | ||
| 110 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 111 | let delta = (ts - last_read_ts).as_millis(); | ||
| 112 | last_read_ts = ts; | ||
| 113 | info!( | ||
| 114 | "Rx: {} {:02x} --- using FD API {}ms", | ||
| 115 | rx_frame.header().len(), | ||
| 116 | rx_frame.data()[0..rx_frame.header().len() as usize], | ||
| 117 | delta, | ||
| 118 | ) | ||
| 119 | } | ||
| 49 | Err(_err) => error!("Error in frame"), | 120 | Err(_err) => error!("Error in frame"), |
| 50 | } | 121 | } |
| 51 | 122 | ||
| 52 | Timer::after_millis(250).await; | 123 | Timer::after_millis(250).await; |
| 53 | 124 | ||
| 54 | i += 1; | 125 | i += 1; |
| 126 | if i > 4 { | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | i = 0; | ||
| 131 | let (mut tx, mut rx, _props) = can.split(); | ||
| 132 | // With split | ||
| 133 | loop { | ||
| 134 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 135 | info!("Writing frame"); | ||
| 136 | _ = tx.write(&frame).await; | ||
| 137 | |||
| 138 | match rx.read().await { | ||
| 139 | Ok(envelope) => { | ||
| 140 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 141 | let delta = (ts - last_read_ts).as_millis(); | ||
| 142 | last_read_ts = ts; | ||
| 143 | info!( | ||
| 144 | "Rx: {} {:02x} --- {}ms", | ||
| 145 | rx_frame.header().len(), | ||
| 146 | rx_frame.data()[0..rx_frame.header().len() as usize], | ||
| 147 | delta, | ||
| 148 | ) | ||
| 149 | } | ||
| 150 | Err(_err) => error!("Error in frame"), | ||
| 151 | } | ||
| 152 | |||
| 153 | Timer::after_millis(250).await; | ||
| 154 | |||
| 155 | i += 1; | ||
| 156 | |||
| 157 | if i > 2 { | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | let can = can::Can::join(tx, rx); | ||
| 163 | |||
| 164 | info!("\n\n\nBuffered\n"); | ||
| 165 | if use_fd { | ||
| 166 | static TX_BUF: StaticCell<can::TxFdBuf<8>> = StaticCell::new(); | ||
| 167 | static RX_BUF: StaticCell<can::RxFdBuf<10>> = StaticCell::new(); | ||
| 168 | let mut can = can.buffered_fd( | ||
| 169 | TX_BUF.init(can::TxFdBuf::<8>::new()), | ||
| 170 | RX_BUF.init(can::RxFdBuf::<10>::new()), | ||
| 171 | ); | ||
| 172 | loop { | ||
| 173 | let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap(); | ||
| 174 | info!("Writing frame"); | ||
| 175 | |||
| 176 | _ = can.write(frame).await; | ||
| 177 | |||
| 178 | match can.read().await { | ||
| 179 | Ok(envelope) => { | ||
| 180 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 181 | let delta = (ts - last_read_ts).as_millis(); | ||
| 182 | last_read_ts = ts; | ||
| 183 | info!( | ||
| 184 | "Rx: {} {:02x} --- {}ms", | ||
| 185 | rx_frame.header().len(), | ||
| 186 | rx_frame.data()[0..rx_frame.header().len() as usize], | ||
| 187 | delta, | ||
| 188 | ) | ||
| 189 | } | ||
| 190 | Err(_err) => error!("Error in frame"), | ||
| 191 | } | ||
| 192 | |||
| 193 | Timer::after_millis(250).await; | ||
| 194 | |||
| 195 | i = i.wrapping_add(1); | ||
| 196 | } | ||
| 197 | } else { | ||
| 198 | static TX_BUF: StaticCell<can::TxBuf<8>> = StaticCell::new(); | ||
| 199 | static RX_BUF: StaticCell<can::RxBuf<10>> = StaticCell::new(); | ||
| 200 | let mut can = can.buffered( | ||
| 201 | TX_BUF.init(can::TxBuf::<8>::new()), | ||
| 202 | RX_BUF.init(can::RxBuf::<10>::new()), | ||
| 203 | ); | ||
| 204 | loop { | ||
| 205 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 206 | info!("Writing frame"); | ||
| 207 | |||
| 208 | // You can use any of these approaches to send. The writer makes it | ||
| 209 | // easy to share sending from multiple tasks. | ||
| 210 | //_ = can.write(frame).await; | ||
| 211 | //can.writer().try_write(frame).unwrap(); | ||
| 212 | can.writer().write(frame).await; | ||
| 213 | |||
| 214 | match can.read().await { | ||
| 215 | Ok(envelope) => { | ||
| 216 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 217 | let delta = (ts - last_read_ts).as_millis(); | ||
| 218 | last_read_ts = ts; | ||
| 219 | info!( | ||
| 220 | "Rx: {} {:02x} --- {}ms", | ||
| 221 | rx_frame.header().len(), | ||
| 222 | rx_frame.data()[0..rx_frame.header().len() as usize], | ||
| 223 | delta, | ||
| 224 | ) | ||
| 225 | } | ||
| 226 | Err(_err) => error!("Error in frame"), | ||
| 227 | } | ||
| 228 | |||
| 229 | Timer::after_millis(250).await; | ||
| 230 | |||
| 231 | i = i.wrapping_add(1); | ||
| 232 | } | ||
| 55 | } | 233 | } |
| 56 | } | 234 | } |
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index 46ebe0b0d..08ed95b34 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSource}; | ||
| 7 | use embassy_stm32::Config; | 6 | use embassy_stm32::Config; |
| 8 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -11,19 +10,20 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 11 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 11 | async fn main(_spawner: Spawner) { |
| 13 | let mut config = Config::default(); | 12 | let mut config = Config::default(); |
| 14 | 13 | { | |
| 15 | config.rcc.pll = Some(Pll { | 14 | use embassy_stm32::rcc::*; |
| 16 | source: PllSource::HSI, | 15 | config.rcc.hsi = true; |
| 17 | prediv_m: PllM::DIV4, | 16 | config.rcc.pll = Some(Pll { |
| 18 | mul_n: PllN::MUL85, | 17 | source: PllSource::HSI, |
| 19 | div_p: None, | 18 | prediv: PllPreDiv::DIV4, |
| 20 | div_q: None, | 19 | mul: PllMul::MUL85, |
| 21 | // Main system clock at 170 MHz | 20 | divp: None, |
| 22 | div_r: Some(PllR::DIV2), | 21 | divq: None, |
| 23 | }); | 22 | // Main system clock at 170 MHz |
| 24 | 23 | divr: Some(PllRDiv::DIV2), | |
| 25 | config.rcc.mux = ClockSrc::PLL; | 24 | }); |
| 26 | 25 | config.rcc.sys = Sysclk::PLL1_R; | |
| 26 | } | ||
| 27 | let _p = embassy_stm32::init(config); | 27 | let _p = embassy_stm32::init(config); |
| 28 | info!("Hello World!"); | 28 | info!("Hello World!"); |
| 29 | 29 | ||
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs new file mode 100644 index 000000000..2e87d3931 --- /dev/null +++ b/examples/stm32g4/src/bin/usb_c_pd.rs | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{error, info, Format}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, Config}; | ||
| 8 | use embassy_time::{with_timeout, Duration}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | UCPD1 => ucpd::InterruptHandler<peripherals::UCPD1>; | ||
| 13 | }); | ||
| 14 | |||
| 15 | #[derive(Debug, Format)] | ||
| 16 | enum CableOrientation { | ||
| 17 | Normal, | ||
| 18 | Flipped, | ||
| 19 | DebugAccessoryMode, | ||
| 20 | } | ||
| 21 | |||
| 22 | // Returns true when the cable | ||
| 23 | async fn wait_attached<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation { | ||
| 24 | loop { | ||
| 25 | let (cc1, cc2) = cc_phy.vstate(); | ||
| 26 | if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST { | ||
| 27 | // Detached, wait until attached by monitoring the CC lines. | ||
| 28 | cc_phy.wait_for_vstate_change().await; | ||
| 29 | continue; | ||
| 30 | } | ||
| 31 | |||
| 32 | // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms). | ||
| 33 | if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change()) | ||
| 34 | .await | ||
| 35 | .is_ok() | ||
| 36 | { | ||
| 37 | // State has changed, restart detection procedure. | ||
| 38 | continue; | ||
| 39 | }; | ||
| 40 | |||
| 41 | // State was stable for the complete debounce period, check orientation. | ||
| 42 | return match (cc1, cc2) { | ||
| 43 | (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected | ||
| 44 | (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected | ||
| 45 | _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable) | ||
| 46 | }; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | #[embassy_executor::main] | ||
| 51 | async fn main(_spawner: Spawner) { | ||
| 52 | let mut config = Config::default(); | ||
| 53 | config.enable_ucpd1_dead_battery = true; | ||
| 54 | let p = embassy_stm32::init(config); | ||
| 55 | |||
| 56 | info!("Hello World!"); | ||
| 57 | |||
| 58 | let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default()); | ||
| 59 | ucpd.cc_phy().set_pull(CcPull::Sink); | ||
| 60 | |||
| 61 | info!("Waiting for USB connection..."); | ||
| 62 | let cable_orientation = wait_attached(ucpd.cc_phy()).await; | ||
| 63 | info!("USB cable connected, orientation: {}", cable_orientation); | ||
| 64 | |||
| 65 | let cc_sel = match cable_orientation { | ||
| 66 | CableOrientation::Normal => { | ||
| 67 | info!("Starting PD communication on CC1 pin"); | ||
| 68 | CcSel::CC1 | ||
| 69 | } | ||
| 70 | CableOrientation::Flipped => { | ||
| 71 | info!("Starting PD communication on CC2 pin"); | ||
| 72 | CcSel::CC2 | ||
| 73 | } | ||
| 74 | CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), | ||
| 75 | }; | ||
| 76 | let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel); | ||
| 77 | |||
| 78 | loop { | ||
| 79 | // Enough space for the longest non-extended data message. | ||
| 80 | let mut buf = [0_u8; 30]; | ||
| 81 | match pd_phy.receive(buf.as_mut()).await { | ||
| 82 | Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]), | ||
| 83 | Err(e) => error!("USB PD RX: {}", e), | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index c26fa76b7..ed2ac7fac 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs | |||
| @@ -3,14 +3,13 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, Hsi48Config, Pll, PllM, PllN, PllQ, PllR, PllSource}; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 8 | use embassy_stm32::usb::{self, Driver, Instance}; | 8 | use embassy_stm32::usb::{self, Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 11 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| 12 | use embassy_usb::Builder; | 12 | use embassy_usb::Builder; |
| 13 | use futures::future::join; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 14 | ||
| 16 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| @@ -20,31 +19,27 @@ bind_interrupts!(struct Irqs { | |||
| 20 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 20 | async fn main(_spawner: Spawner) { |
| 22 | let mut config = Config::default(); | 21 | let mut config = Config::default(); |
| 23 | 22 | { | |
| 24 | // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. | 23 | use embassy_stm32::rcc::*; |
| 25 | const USE_HSI48: bool = true; | ||
| 26 | |||
| 27 | let plldivq = if USE_HSI48 { None } else { Some(PllQ::DIV6) }; | ||
| 28 | |||
| 29 | config.rcc.pll = Some(Pll { | ||
| 30 | source: PllSource::HSE(Hertz(8_000_000)), | ||
| 31 | prediv_m: PllM::DIV2, | ||
| 32 | mul_n: PllN::MUL72, | ||
| 33 | div_p: None, | ||
| 34 | div_q: plldivq, | ||
| 35 | // Main system clock at 144 MHz | ||
| 36 | div_r: Some(PllR::DIV2), | ||
| 37 | }); | ||
| 38 | |||
| 39 | config.rcc.mux = ClockSrc::PLL; | ||
| 40 | |||
| 41 | if USE_HSI48 { | ||
| 42 | // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. | 24 | // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. |
| 43 | config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true })); | 25 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); |
| 44 | } else { | 26 | config.rcc.hse = Some(Hse { |
| 45 | config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ); | 27 | freq: Hertz(8_000_000), |
| 28 | mode: HseMode::Oscillator, | ||
| 29 | }); | ||
| 30 | config.rcc.pll = Some(Pll { | ||
| 31 | source: PllSource::HSE, | ||
| 32 | prediv: PllPreDiv::DIV2, | ||
| 33 | mul: PllMul::MUL72, | ||
| 34 | divp: None, | ||
| 35 | divq: Some(PllQDiv::DIV6), // 48mhz | ||
| 36 | divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz | ||
| 37 | }); | ||
| 38 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 39 | config.rcc.boost = true; // BOOST! | ||
| 40 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 41 | //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead. | ||
| 46 | } | 42 | } |
| 47 | |||
| 48 | let p = embassy_stm32::init(config); | 43 | let p = embassy_stm32::init(config); |
| 49 | 44 | ||
| 50 | info!("Hello World!"); | 45 | info!("Hello World!"); |
| @@ -61,7 +56,6 @@ async fn main(_spawner: Spawner) { | |||
| 61 | config.device_protocol = 0x01; | 56 | config.device_protocol = 0x01; |
| 62 | config.composite_with_iads = true; | 57 | config.composite_with_iads = true; |
| 63 | 58 | ||
| 64 | let mut device_descriptor = [0; 256]; | ||
| 65 | let mut config_descriptor = [0; 256]; | 59 | let mut config_descriptor = [0; 256]; |
| 66 | let mut bos_descriptor = [0; 256]; | 60 | let mut bos_descriptor = [0; 256]; |
| 67 | let mut control_buf = [0; 64]; | 61 | let mut control_buf = [0; 64]; |
| @@ -71,7 +65,6 @@ async fn main(_spawner: Spawner) { | |||
| 71 | let mut builder = Builder::new( | 65 | let mut builder = Builder::new( |
| 72 | driver, | 66 | driver, |
| 73 | config, | 67 | config, |
| 74 | &mut device_descriptor, | ||
| 75 | &mut config_descriptor, | 68 | &mut config_descriptor, |
| 76 | &mut bos_descriptor, | 69 | &mut bos_descriptor, |
| 77 | &mut [], // no msos descriptors | 70 | &mut [], // no msos descriptors |
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index c9f08d24e..30b1d2be9 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml | |||
| @@ -6,12 +6,13 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32h563zi to your chip name, if necessary. | 8 | # Change stm32h563zi to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } | 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 15 | 16 | ||
| 16 | defmt = "0.3" | 17 | defmt = "0.3" |
| 17 | defmt-rtt = "0.4" | 18 | defmt-rtt = "0.4" |
| @@ -24,7 +25,6 @@ embedded-hal-async = { version = "1.0" } | |||
| 24 | embedded-io-async = { version = "0.6.1" } | 25 | embedded-io-async = { version = "0.6.1" } |
| 25 | embedded-nal-async = { version = "0.7.1" } | 26 | embedded-nal-async = { version = "0.7.1" } |
| 26 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 27 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 27 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 28 | heapless = { version = "0.8", default-features = false } | 28 | heapless = { version = "0.8", default-features = false } |
| 29 | rand_core = "0.6.3" | 29 | rand_core = "0.6.3" |
| 30 | critical-section = "1.1" | 30 | critical-section = "1.1" |
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 2906d1576..194239d47 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs | |||
| @@ -16,59 +16,83 @@ bind_interrupts!(struct Irqs { | |||
| 16 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 18 | let mut config = Config::default(); | 18 | let mut config = Config::default(); |
| 19 | 19 | config.rcc.hse = Some(rcc::Hse { | |
| 20 | // configure FDCAN to use PLL1_Q at 64 MHz | 20 | freq: embassy_stm32::time::Hertz(25_000_000), |
| 21 | config.rcc.pll1 = Some(rcc::Pll { | 21 | mode: rcc::HseMode::Oscillator, |
| 22 | source: rcc::PllSource::HSI, | ||
| 23 | prediv: rcc::PllPreDiv::DIV4, | ||
| 24 | mul: rcc::PllMul::MUL8, | ||
| 25 | divp: None, | ||
| 26 | divq: Some(rcc::PllDiv::DIV2), | ||
| 27 | divr: None, | ||
| 28 | }); | 22 | }); |
| 29 | config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; | 23 | config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE; |
| 30 | 24 | ||
| 31 | let peripherals = embassy_stm32::init(config); | 25 | let peripherals = embassy_stm32::init(config); |
| 32 | 26 | ||
| 33 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 34 | 28 | ||
| 35 | can.can.apply_config( | 29 | // 250k bps |
| 36 | can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { | 30 | can.set_bitrate(250_000); |
| 37 | sync_jump_width: 1.try_into().unwrap(), | ||
| 38 | prescaler: 8.try_into().unwrap(), | ||
| 39 | seg1: 13.try_into().unwrap(), | ||
| 40 | seg2: 2.try_into().unwrap(), | ||
| 41 | }), | ||
| 42 | ); | ||
| 43 | 31 | ||
| 44 | info!("Configured"); | 32 | //let mut can = can.into_internal_loopback_mode(); |
| 33 | let mut can = can.into_normal_mode(); | ||
| 45 | 34 | ||
| 46 | let mut can = can.into_external_loopback_mode(); | 35 | info!("CAN Configured"); |
| 47 | //let mut can = can.into_normal_mode(); | ||
| 48 | 36 | ||
| 49 | let mut i = 0; | 37 | let mut i = 0; |
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | ||
| 39 | |||
| 50 | loop { | 40 | loop { |
| 51 | let frame = can::TxFrame::new( | 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 52 | can::TxFrameHeader { | ||
| 53 | len: 1, | ||
| 54 | frame_format: can::FrameFormat::Standard, | ||
| 55 | id: can::StandardId::new(0x123).unwrap().into(), | ||
| 56 | bit_rate_switching: false, | ||
| 57 | marker: None, | ||
| 58 | }, | ||
| 59 | &[i], | ||
| 60 | ) | ||
| 61 | .unwrap(); | ||
| 62 | info!("Writing frame"); | 42 | info!("Writing frame"); |
| 63 | _ = can.write(&frame).await; | 43 | _ = can.write(&frame).await; |
| 64 | 44 | ||
| 65 | match can.read().await { | 45 | match can.read().await { |
| 66 | Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), | 46 | Ok(envelope) => { |
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 48 | let delta = (ts - last_read_ts).as_millis(); | ||
| 49 | last_read_ts = ts; | ||
| 50 | info!( | ||
| 51 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 52 | rx_frame.data()[0], | ||
| 53 | rx_frame.data()[1], | ||
| 54 | rx_frame.data()[2], | ||
| 55 | rx_frame.data()[3], | ||
| 56 | delta, | ||
| 57 | ) | ||
| 58 | } | ||
| 67 | Err(_err) => error!("Error in frame"), | 59 | Err(_err) => error!("Error in frame"), |
| 68 | } | 60 | } |
| 69 | 61 | ||
| 70 | Timer::after_millis(250).await; | 62 | Timer::after_millis(250).await; |
| 71 | 63 | ||
| 72 | i += 1; | 64 | i += 1; |
| 65 | if i > 3 { | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | let (mut tx, mut rx, _props) = can.split(); | ||
| 71 | // With split | ||
| 72 | loop { | ||
| 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 74 | info!("Writing frame"); | ||
| 75 | _ = tx.write(&frame).await; | ||
| 76 | |||
| 77 | match rx.read().await { | ||
| 78 | Ok(envelope) => { | ||
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 80 | let delta = (ts - last_read_ts).as_millis(); | ||
| 81 | last_read_ts = ts; | ||
| 82 | info!( | ||
| 83 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 84 | rx_frame.data()[0], | ||
| 85 | rx_frame.data()[1], | ||
| 86 | rx_frame.data()[2], | ||
| 87 | rx_frame.data()[3], | ||
| 88 | delta, | ||
| 89 | ) | ||
| 90 | } | ||
| 91 | Err(_err) => error!("Error in frame"), | ||
| 92 | } | ||
| 93 | |||
| 94 | Timer::after_millis(250).await; | ||
| 95 | |||
| 96 | i = i.wrapping_add(1); | ||
| 73 | } | 97 | } |
| 74 | } | 98 | } |
diff --git a/examples/stm32h5/src/bin/cordic.rs b/examples/stm32h5/src/bin/cordic.rs new file mode 100644 index 000000000..73e873574 --- /dev/null +++ b/examples/stm32h5/src/bin/cordic.rs | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::cordic::{self, utils}; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let mut dp = embassy_stm32::init(Default::default()); | ||
| 12 | |||
| 13 | let mut cordic = cordic::Cordic::new( | ||
| 14 | &mut dp.CORDIC, | ||
| 15 | unwrap!(cordic::Config::new( | ||
| 16 | cordic::Function::Sin, | ||
| 17 | Default::default(), | ||
| 18 | Default::default(), | ||
| 19 | )), | ||
| 20 | ); | ||
| 21 | |||
| 22 | // for output buf, the length is not that strict, larger than minimal required is ok. | ||
| 23 | let mut output_f64 = [0f64; 19]; | ||
| 24 | let mut output_u32 = [0u32; 21]; | ||
| 25 | |||
| 26 | // tips: | ||
| 27 | // CORDIC peripheral has some strict on input value, you can also use ".check_argX_fXX()" methods | ||
| 28 | // to make sure your input values are compatible with current CORDIC setup. | ||
| 29 | let arg1 = [-1.0, -0.5, 0.0, 0.5, 1.0]; // for trigonometric function, the ARG1 value [-pi, pi] should be map to [-1, 1] | ||
| 30 | let arg2 = [0.5]; // and for Sin function, ARG2 should be in [0, 1] | ||
| 31 | |||
| 32 | let mut input_buf = [0u32; 9]; | ||
| 33 | |||
| 34 | // convert input from floating point to fixed point | ||
| 35 | input_buf[0] = unwrap!(utils::f64_to_q1_31(arg1[0])); | ||
| 36 | input_buf[1] = unwrap!(utils::f64_to_q1_31(arg2[0])); | ||
| 37 | |||
| 38 | // If input length is small, blocking mode can be used to minimize overhead. | ||
| 39 | let cnt0 = unwrap!(cordic.blocking_calc_32bit( | ||
| 40 | &input_buf[..2], // input length is strict, since driver use its length to detect calculation count | ||
| 41 | &mut output_u32, | ||
| 42 | false, | ||
| 43 | false | ||
| 44 | )); | ||
| 45 | |||
| 46 | // convert result from fixed point into floating point | ||
| 47 | for (&u32_val, f64_val) in output_u32[..cnt0].iter().zip(output_f64.iter_mut()) { | ||
| 48 | *f64_val = utils::q1_31_to_f64(u32_val); | ||
| 49 | } | ||
| 50 | |||
| 51 | // convert input from floating point to fixed point | ||
| 52 | // | ||
| 53 | // first value from arg1 is used, so truncate to arg1[1..] | ||
| 54 | for (&f64_val, u32_val) in arg1[1..].iter().zip(input_buf.iter_mut()) { | ||
| 55 | *u32_val = unwrap!(utils::f64_to_q1_31(f64_val)); | ||
| 56 | } | ||
| 57 | |||
| 58 | // If calculation is a little longer, async mode can make use of DMA, and let core do some other stuff. | ||
| 59 | let cnt1 = unwrap!( | ||
| 60 | cordic | ||
| 61 | .async_calc_32bit( | ||
| 62 | &mut dp.GPDMA1_CH0, | ||
| 63 | &mut dp.GPDMA1_CH1, | ||
| 64 | &input_buf[..arg1.len() - 1], // limit input buf to its actual length | ||
| 65 | &mut output_u32, | ||
| 66 | true, | ||
| 67 | false | ||
| 68 | ) | ||
| 69 | .await | ||
| 70 | ); | ||
| 71 | |||
| 72 | // convert result from fixed point into floating point | ||
| 73 | for (&u32_val, f64_val) in output_u32[..cnt1].iter().zip(output_f64[cnt0..cnt0 + cnt1].iter_mut()) { | ||
| 74 | *f64_val = utils::q1_31_to_f64(u32_val); | ||
| 75 | } | ||
| 76 | |||
| 77 | println!("result: {}", output_f64[..cnt0 + cnt1]); | ||
| 78 | } | ||
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 2370656e6..eee1632f5 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs { | |||
| 28 | type Device = Ethernet<'static, ETH, GenericSMI>; | 28 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 29 | 29 | ||
| 30 | #[embassy_executor::task] | 30 | #[embassy_executor::task] |
| 31 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 31 | async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { |
| 32 | stack.run().await | 32 | runner.run().await |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | #[embassy_executor::main] | 35 | #[embassy_executor::main] |
| @@ -92,17 +92,11 @@ async fn main(spawner: Spawner) -> ! { | |||
| 92 | //}); | 92 | //}); |
| 93 | 93 | ||
| 94 | // Init network stack | 94 | // Init network stack |
| 95 | static STACK: StaticCell<Stack<Device>> = StaticCell::new(); | 95 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 96 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 96 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 97 | let stack = &*STACK.init(Stack::new( | ||
| 98 | device, | ||
| 99 | config, | ||
| 100 | RESOURCES.init(StackResources::<2>::new()), | ||
| 101 | seed, | ||
| 102 | )); | ||
| 103 | 97 | ||
| 104 | // Launch network task | 98 | // Launch network task |
| 105 | unwrap!(spawner.spawn(net_task(&stack))); | 99 | unwrap!(spawner.spawn(net_task(runner))); |
| 106 | 100 | ||
| 107 | // Ensure DHCP configuration is up before trying connect | 101 | // Ensure DHCP configuration is up before trying connect |
| 108 | stack.wait_config_up().await; | 102 | stack.wait_config_up().await; |
| @@ -114,7 +108,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 114 | let mut tx_buffer = [0; 1024]; | 108 | let mut tx_buffer = [0; 1024]; |
| 115 | 109 | ||
| 116 | loop { | 110 | loop { |
| 117 | let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); | 111 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); |
| 118 | 112 | ||
| 119 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); | 113 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); |
| 120 | 114 | ||
diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs new file mode 100644 index 000000000..0d14c0668 --- /dev/null +++ b/examples/stm32h5/src/bin/stop.rs | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | // Notice: | ||
| 2 | // the MCU might need an extra reset to make the code actually running | ||
| 3 | |||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | ||
| 10 | use embassy_stm32::low_power::Executor; | ||
| 11 | use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; | ||
| 12 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 13 | use embassy_stm32::Config; | ||
| 14 | use embassy_time::Timer; | ||
| 15 | use static_cell::StaticCell; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | #[cortex_m_rt::entry] | ||
| 19 | fn main() -> ! { | ||
| 20 | Executor::take().run(|spawner| { | ||
| 21 | unwrap!(spawner.spawn(async_main(spawner))); | ||
| 22 | }) | ||
| 23 | } | ||
| 24 | |||
| 25 | #[embassy_executor::task] | ||
| 26 | async fn async_main(spawner: Spawner) { | ||
| 27 | defmt::info!("Program Start"); | ||
| 28 | |||
| 29 | let mut config = Config::default(); | ||
| 30 | |||
| 31 | // System Clock seems need to be equal or lower than 16 MHz | ||
| 32 | config.rcc.hsi = Some(HSIPrescaler::DIV4); | ||
| 33 | |||
| 34 | config.rcc.ls = LsConfig::default_lsi(); | ||
| 35 | // when enabled the power-consumption is much higher during stop, but debugging and RTT is working | ||
| 36 | // if you wan't to measure the power-consumption, or for production: uncomment this line | ||
| 37 | // config.enable_debug_during_sleep = false; | ||
| 38 | let p = embassy_stm32::init(config); | ||
| 39 | |||
| 40 | // give the RTC to the executor... | ||
| 41 | let rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 42 | static RTC: StaticCell<Rtc> = StaticCell::new(); | ||
| 43 | let rtc = RTC.init(rtc); | ||
| 44 | embassy_stm32::low_power::stop_with_rtc(rtc); | ||
| 45 | |||
| 46 | unwrap!(spawner.spawn(blinky(p.PB4.into()))); | ||
| 47 | unwrap!(spawner.spawn(timeout())); | ||
| 48 | } | ||
| 49 | |||
| 50 | #[embassy_executor::task] | ||
| 51 | async fn blinky(led: AnyPin) { | ||
| 52 | let mut led = Output::new(led, Level::Low, Speed::Low); | ||
| 53 | loop { | ||
| 54 | info!("high"); | ||
| 55 | led.set_high(); | ||
| 56 | Timer::after_millis(300).await; | ||
| 57 | |||
| 58 | info!("low"); | ||
| 59 | led.set_low(); | ||
| 60 | Timer::after_millis(300).await; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | // when enable_debug_during_sleep is false, it is more difficult to reprogram the MCU | ||
| 65 | // therefore we block the MCU after 30s to be able to reprogram it easily | ||
| 66 | #[embassy_executor::task] | ||
| 67 | async fn timeout() -> ! { | ||
| 68 | Timer::after_secs(30).await; | ||
| 69 | #[allow(clippy::empty_loop)] | ||
| 70 | loop {} | ||
| 71 | } | ||
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs index f9cbad6af..cc49c2fdb 100644 --- a/examples/stm32h5/src/bin/usart.rs +++ b/examples/stm32h5/src/bin/usart.rs | |||
| @@ -4,22 +4,16 @@ | |||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Executor; | 6 | use embassy_executor::Executor; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::usart::{Config, Uart}; | 7 | use embassy_stm32::usart::{Config, Uart}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 10 | use static_cell::StaticCell; | 8 | use static_cell::StaticCell; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 10 | ||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | #[embassy_executor::task] | 11 | #[embassy_executor::task] |
| 18 | async fn main_task() { | 12 | async fn main_task() { |
| 19 | let p = embassy_stm32::init(Default::default()); | 13 | let p = embassy_stm32::init(Default::default()); |
| 20 | 14 | ||
| 21 | let config = Config::default(); | 15 | let config = Config::default(); |
| 22 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); | 16 | let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); |
| 23 | 17 | ||
| 24 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 18 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 25 | info!("wrote Hello, starting echo"); | 19 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs index caae0dd18..c644e84bd 100644 --- a/examples/stm32h5/src/bin/usart_dma.rs +++ b/examples/stm32h5/src/bin/usart_dma.rs | |||
| @@ -6,7 +6,6 @@ use core::fmt::Write; | |||
| 6 | use cortex_m_rt::entry; | 6 | use cortex_m_rt::entry; |
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Executor; | 8 | use embassy_executor::Executor; |
| 9 | use embassy_stm32::dma::NoDma; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 9 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 12 | use heapless::String; | 11 | use heapless::String; |
| @@ -22,7 +21,7 @@ async fn main_task() { | |||
| 22 | let p = embassy_stm32::init(Default::default()); | 21 | let p = embassy_stm32::init(Default::default()); |
| 23 | 22 | ||
| 24 | let config = Config::default(); | 23 | let config = Config::default(); |
| 25 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap(); | 24 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); |
| 26 | 25 | ||
| 27 | for n in 0u32.. { | 26 | for n in 0u32.. { |
| 28 | let mut s: String<128> = String::new(); | 27 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs index 92047de8d..d26c5003c 100644 --- a/examples/stm32h5/src/bin/usart_split.rs +++ b/examples/stm32h5/src/bin/usart_split.rs | |||
| @@ -3,8 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | 6 | use embassy_stm32::mode::Async; |
| 7 | use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; | ||
| 8 | use embassy_stm32::usart::{Config, Uart, UartRx}; | 7 | use embassy_stm32::usart::{Config, Uart, UartRx}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 9 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| @@ -15,18 +14,6 @@ bind_interrupts!(struct Irqs { | |||
| 15 | UART7 => usart::InterruptHandler<peripherals::UART7>; | 14 | UART7 => usart::InterruptHandler<peripherals::UART7>; |
| 16 | }); | 15 | }); |
| 17 | 16 | ||
| 18 | #[embassy_executor::task] | ||
| 19 | async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { | ||
| 20 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||
| 21 | info!("wrote Hello, starting echo"); | ||
| 22 | |||
| 23 | let mut buf = [0u8; 1]; | ||
| 24 | loop { | ||
| 25 | unwrap!(usart.blocking_read(&mut buf)); | ||
| 26 | unwrap!(usart.blocking_write(&buf)); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | 17 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); |
| 31 | 18 | ||
| 32 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| @@ -50,7 +37,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 50 | } | 37 | } |
| 51 | 38 | ||
| 52 | #[embassy_executor::task] | 39 | #[embassy_executor::task] |
| 53 | async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) { | 40 | async fn reader(mut rx: UartRx<'static, Async>) { |
| 54 | let mut buf = [0; 8]; | 41 | let mut buf = [0; 8]; |
| 55 | loop { | 42 | loop { |
| 56 | info!("reading..."); | 43 | info!("reading..."); |
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 208493d8c..fbcbdb5f9 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs | |||
| @@ -3,13 +3,13 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | ||
| 6 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 7 | use embassy_stm32::usb::{Driver, Instance}; | 8 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 10 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| 11 | use embassy_usb::Builder; | 12 | use embassy_usb::Builder; |
| 12 | use futures::future::join; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| @@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) { | |||
| 41 | config.rcc.apb3_pre = APBPrescaler::DIV4; | 41 | config.rcc.apb3_pre = APBPrescaler::DIV4; |
| 42 | config.rcc.sys = Sysclk::PLL1_P; | 42 | config.rcc.sys = Sysclk::PLL1_P; |
| 43 | config.rcc.voltage_scale = VoltageScale::Scale0; | 43 | config.rcc.voltage_scale = VoltageScale::Scale0; |
| 44 | config.rcc.mux.usbsel = mux::Usbsel::HSI48; | ||
| 44 | } | 45 | } |
| 45 | let p = embassy_stm32::init(config); | 46 | let p = embassy_stm32::init(config); |
| 46 | 47 | ||
| 47 | info!("Hello World!"); | 48 | info!("Hello World!"); |
| 48 | 49 | ||
| 49 | pac::RCC.ccipr4().write(|w| { | ||
| 50 | w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); | ||
| 51 | }); | ||
| 52 | |||
| 53 | // Create the driver, from the HAL. | 50 | // Create the driver, from the HAL. |
| 54 | let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | 51 | let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); |
| 55 | 52 | ||
| @@ -68,7 +65,6 @@ async fn main(_spawner: Spawner) { | |||
| 68 | 65 | ||
| 69 | // Create embassy-usb DeviceBuilder using the driver and config. | 66 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 70 | // It needs some buffers for building the descriptors. | 67 | // It needs some buffers for building the descriptors. |
| 71 | let mut device_descriptor = [0; 256]; | ||
| 72 | let mut config_descriptor = [0; 256]; | 68 | let mut config_descriptor = [0; 256]; |
| 73 | let mut bos_descriptor = [0; 256]; | 69 | let mut bos_descriptor = [0; 256]; |
| 74 | let mut control_buf = [0; 64]; | 70 | let mut control_buf = [0; 64]; |
| @@ -78,7 +74,6 @@ async fn main(_spawner: Spawner) { | |||
| 78 | let mut builder = Builder::new( | 74 | let mut builder = Builder::new( |
| 79 | driver, | 75 | driver, |
| 80 | config, | 76 | config, |
| 81 | &mut device_descriptor, | ||
| 82 | &mut config_descriptor, | 77 | &mut config_descriptor, |
| 83 | &mut bos_descriptor, | 78 | &mut bos_descriptor, |
| 84 | &mut [], // no msos descriptors | 79 | &mut [], // no msos descriptors |
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index d9ea2626d..13fce7dc7 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml | |||
| @@ -6,12 +6,14 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32h743bi to your chip name, if necessary. | 8 | # Change stm32h743bi to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 16 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 15 | 17 | ||
| 16 | defmt = "0.3" | 18 | defmt = "0.3" |
| 17 | defmt-rtt = "0.4" | 19 | defmt-rtt = "0.4" |
| @@ -24,7 +26,6 @@ embedded-hal-async = { version = "1.0" } | |||
| 24 | embedded-nal-async = { version = "0.7.1" } | 26 | embedded-nal-async = { version = "0.7.1" } |
| 25 | embedded-io-async = { version = "0.6.1" } | 27 | embedded-io-async = { version = "0.6.1" } |
| 26 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 28 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 27 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 28 | heapless = { version = "0.8", default-features = false } | 29 | heapless = { version = "0.8", default-features = false } |
| 29 | rand_core = "0.6.3" | 30 | rand_core = "0.6.3" |
| 30 | critical-section = "1.1" | 31 | critical-section = "1.1" |
| @@ -33,6 +34,7 @@ stm32-fmc = "0.3.0" | |||
| 33 | embedded-storage = "0.3.1" | 34 | embedded-storage = "0.3.1" |
| 34 | static_cell = "2" | 35 | static_cell = "2" |
| 35 | chrono = { version = "^0.4", default-features = false } | 36 | chrono = { version = "^0.4", default-features = false } |
| 37 | grounded = "0.2.0" | ||
| 36 | 38 | ||
| 37 | # cargo build/run | 39 | # cargo build/run |
| 38 | [profile.dev] | 40 | [profile.dev] |
diff --git a/examples/stm32h7/build.rs b/examples/stm32h7/build.rs index 8cd32d7ed..30691aa97 100644 --- a/examples/stm32h7/build.rs +++ b/examples/stm32h7/build.rs | |||
| @@ -1,4 +1,34 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 1 | fn main() { | 16 | fn main() { |
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 2 | println!("cargo:rustc-link-arg-bins=--nmagic"); | 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); |
| 3 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); |
| 4 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); |
diff --git a/examples/stm32h7/memory.x b/examples/stm32h7/memory.x new file mode 100644 index 000000000..e5ab1f62c --- /dev/null +++ b/examples/stm32h7/memory.x | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x08000000, LENGTH = 2048K /* BANK_1 + BANK_2 */ | ||
| 4 | RAM : ORIGIN = 0x24000000, LENGTH = 512K /* SRAM */ | ||
| 5 | RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */ | ||
| 6 | } | ||
| 7 | |||
| 8 | SECTIONS | ||
| 9 | { | ||
| 10 | .ram_d3 : | ||
| 11 | { | ||
| 12 | *(.ram_d3) | ||
| 13 | } > RAM_D3 | ||
| 14 | } \ No newline at end of file | ||
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index fe6fe69a1..98504ddf6 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs | |||
| @@ -5,7 +5,7 @@ use defmt::*; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | 6 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 7 | use embassy_stm32::Config; | 7 | use embassy_stm32::Config; |
| 8 | use embassy_time::{Delay, Timer}; | 8 | use embassy_time::Timer; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| 11 | #[embassy_executor::main] | 11 | #[embassy_executor::main] |
| @@ -38,22 +38,22 @@ async fn main(_spawner: Spawner) { | |||
| 38 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | 38 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz |
| 39 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | 39 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz |
| 40 | config.rcc.voltage_scale = VoltageScale::Scale1; | 40 | config.rcc.voltage_scale = VoltageScale::Scale1; |
| 41 | config.rcc.adc_clock_source = AdcClockSource::PLL2_P; | 41 | config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; |
| 42 | } | 42 | } |
| 43 | let mut p = embassy_stm32::init(config); | 43 | let mut p = embassy_stm32::init(config); |
| 44 | 44 | ||
| 45 | info!("Hello World!"); | 45 | info!("Hello World!"); |
| 46 | 46 | ||
| 47 | let mut adc = Adc::new(p.ADC3, &mut Delay); | 47 | let mut adc = Adc::new(p.ADC3); |
| 48 | 48 | ||
| 49 | adc.set_sample_time(SampleTime::Cycles32_5); | 49 | adc.set_sample_time(SampleTime::CYCLES32_5); |
| 50 | 50 | ||
| 51 | let mut vrefint_channel = adc.enable_vrefint(); | 51 | let mut vrefint_channel = adc.enable_vrefint(); |
| 52 | 52 | ||
| 53 | loop { | 53 | loop { |
| 54 | let vrefint = adc.read_internal(&mut vrefint_channel); | 54 | let vrefint = adc.blocking_read(&mut vrefint_channel); |
| 55 | info!("vrefint: {}", vrefint); | 55 | info!("vrefint: {}", vrefint); |
| 56 | let measured = adc.read(&mut p.PC0); | 56 | let measured = adc.blocking_read(&mut p.PC0); |
| 57 | info!("measured: {}", measured); | 57 | info!("measured: {}", measured); |
| 58 | Timer::after_millis(500).await; | 58 | Timer::after_millis(500).await; |
| 59 | } | 59 | } |
diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs new file mode 100644 index 000000000..0b905d227 --- /dev/null +++ b/examples/stm32h7/src/bin/adc_dma.rs | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; | ||
| 7 | use embassy_stm32::Config; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[link_section = ".ram_d3"] | ||
| 12 | static mut DMA_BUF: [u16; 2] = [0; 2]; | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) { | ||
| 16 | let mut read_buffer = unsafe { &mut DMA_BUF[..] }; | ||
| 17 | |||
| 18 | let mut config = Config::default(); | ||
| 19 | { | ||
| 20 | use embassy_stm32::rcc::*; | ||
| 21 | config.rcc.hsi = Some(HSIPrescaler::DIV1); | ||
| 22 | config.rcc.csi = true; | ||
| 23 | config.rcc.pll1 = Some(Pll { | ||
| 24 | source: PllSource::HSI, | ||
| 25 | prediv: PllPreDiv::DIV4, | ||
| 26 | mul: PllMul::MUL50, | ||
| 27 | divp: Some(PllDiv::DIV2), | ||
| 28 | divq: Some(PllDiv::DIV8), // SPI1 cksel defaults to pll1_q | ||
| 29 | divr: None, | ||
| 30 | }); | ||
| 31 | config.rcc.pll2 = Some(Pll { | ||
| 32 | source: PllSource::HSI, | ||
| 33 | prediv: PllPreDiv::DIV4, | ||
| 34 | mul: PllMul::MUL50, | ||
| 35 | divp: Some(PllDiv::DIV8), // 100mhz | ||
| 36 | divq: None, | ||
| 37 | divr: None, | ||
| 38 | }); | ||
| 39 | config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz | ||
| 40 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz | ||
| 41 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 42 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 43 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 44 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 45 | config.rcc.voltage_scale = VoltageScale::Scale1; | ||
| 46 | config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; | ||
| 47 | } | ||
| 48 | let p = embassy_stm32::init(config); | ||
| 49 | |||
| 50 | info!("Hello World!"); | ||
| 51 | |||
| 52 | let mut adc = Adc::new(p.ADC3); | ||
| 53 | |||
| 54 | let mut dma = p.DMA1_CH1; | ||
| 55 | let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); | ||
| 56 | let mut pc0 = p.PC0.degrade_adc(); | ||
| 57 | |||
| 58 | loop { | ||
| 59 | adc.read( | ||
| 60 | &mut dma, | ||
| 61 | [ | ||
| 62 | (&mut vrefint_channel, SampleTime::CYCLES387_5), | ||
| 63 | (&mut pc0, SampleTime::CYCLES810_5), | ||
| 64 | ] | ||
| 65 | .into_iter(), | ||
| 66 | &mut read_buffer, | ||
| 67 | ) | ||
| 68 | .await; | ||
| 69 | |||
| 70 | let vrefint = read_buffer[0]; | ||
| 71 | let measured = read_buffer[1]; | ||
| 72 | info!("vrefint: {}", vrefint); | ||
| 73 | info!("measured: {}", measured); | ||
| 74 | Timer::after_millis(500).await; | ||
| 75 | } | ||
| 76 | } | ||
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index e5a104baf..170a5aa28 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs | |||
| @@ -78,9 +78,9 @@ async fn main(_spawner: Spawner) { | |||
| 78 | ); | 78 | ); |
| 79 | 79 | ||
| 80 | defmt::info!("attempting capture"); | 80 | defmt::info!("attempting capture"); |
| 81 | defmt::unwrap!(dcmi.capture(unsafe { &mut FRAME }).await); | 81 | defmt::unwrap!(dcmi.capture(unsafe { &mut *core::ptr::addr_of_mut!(FRAME) }).await); |
| 82 | 82 | ||
| 83 | defmt::info!("captured frame: {:x}", unsafe { &FRAME }); | 83 | defmt::info!("captured frame: {:x}", unsafe { &*core::ptr::addr_of!(FRAME) }); |
| 84 | 84 | ||
| 85 | defmt::info!("main loop running"); | 85 | defmt::info!("main loop running"); |
| 86 | loop { | 86 | loop { |
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 2906d1576..0af11ef3e 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs | |||
| @@ -16,59 +16,83 @@ bind_interrupts!(struct Irqs { | |||
| 16 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 18 | let mut config = Config::default(); | 18 | let mut config = Config::default(); |
| 19 | 19 | config.rcc.hse = Some(rcc::Hse { | |
| 20 | // configure FDCAN to use PLL1_Q at 64 MHz | 20 | freq: embassy_stm32::time::Hertz(25_000_000), |
| 21 | config.rcc.pll1 = Some(rcc::Pll { | 21 | mode: rcc::HseMode::Oscillator, |
| 22 | source: rcc::PllSource::HSI, | ||
| 23 | prediv: rcc::PllPreDiv::DIV4, | ||
| 24 | mul: rcc::PllMul::MUL8, | ||
| 25 | divp: None, | ||
| 26 | divq: Some(rcc::PllDiv::DIV2), | ||
| 27 | divr: None, | ||
| 28 | }); | 22 | }); |
| 29 | config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; | 23 | config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; |
| 30 | 24 | ||
| 31 | let peripherals = embassy_stm32::init(config); | 25 | let peripherals = embassy_stm32::init(config); |
| 32 | 26 | ||
| 33 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 34 | 28 | ||
| 35 | can.can.apply_config( | 29 | // 250k bps |
| 36 | can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { | 30 | can.set_bitrate(250_000); |
| 37 | sync_jump_width: 1.try_into().unwrap(), | ||
| 38 | prescaler: 8.try_into().unwrap(), | ||
| 39 | seg1: 13.try_into().unwrap(), | ||
| 40 | seg2: 2.try_into().unwrap(), | ||
| 41 | }), | ||
| 42 | ); | ||
| 43 | 31 | ||
| 44 | info!("Configured"); | 32 | //let mut can = can.into_internal_loopback_mode(); |
| 33 | let mut can = can.into_normal_mode(); | ||
| 45 | 34 | ||
| 46 | let mut can = can.into_external_loopback_mode(); | 35 | info!("CAN Configured"); |
| 47 | //let mut can = can.into_normal_mode(); | ||
| 48 | 36 | ||
| 49 | let mut i = 0; | 37 | let mut i = 0; |
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | ||
| 39 | |||
| 50 | loop { | 40 | loop { |
| 51 | let frame = can::TxFrame::new( | 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 52 | can::TxFrameHeader { | ||
| 53 | len: 1, | ||
| 54 | frame_format: can::FrameFormat::Standard, | ||
| 55 | id: can::StandardId::new(0x123).unwrap().into(), | ||
| 56 | bit_rate_switching: false, | ||
| 57 | marker: None, | ||
| 58 | }, | ||
| 59 | &[i], | ||
| 60 | ) | ||
| 61 | .unwrap(); | ||
| 62 | info!("Writing frame"); | 42 | info!("Writing frame"); |
| 63 | _ = can.write(&frame).await; | 43 | _ = can.write(&frame).await; |
| 64 | 44 | ||
| 65 | match can.read().await { | 45 | match can.read().await { |
| 66 | Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), | 46 | Ok(envelope) => { |
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 48 | let delta = (ts - last_read_ts).as_millis(); | ||
| 49 | last_read_ts = ts; | ||
| 50 | info!( | ||
| 51 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 52 | rx_frame.data()[0], | ||
| 53 | rx_frame.data()[1], | ||
| 54 | rx_frame.data()[2], | ||
| 55 | rx_frame.data()[3], | ||
| 56 | delta, | ||
| 57 | ) | ||
| 58 | } | ||
| 67 | Err(_err) => error!("Error in frame"), | 59 | Err(_err) => error!("Error in frame"), |
| 68 | } | 60 | } |
| 69 | 61 | ||
| 70 | Timer::after_millis(250).await; | 62 | Timer::after_millis(250).await; |
| 71 | 63 | ||
| 72 | i += 1; | 64 | i += 1; |
| 65 | if i > 3 { | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | let (mut tx, mut rx, _props) = can.split(); | ||
| 71 | // With split | ||
| 72 | loop { | ||
| 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 74 | info!("Writing frame"); | ||
| 75 | _ = tx.write(&frame).await; | ||
| 76 | |||
| 77 | match rx.read().await { | ||
| 78 | Ok(envelope) => { | ||
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 80 | let delta = (ts - last_read_ts).as_millis(); | ||
| 81 | last_read_ts = ts; | ||
| 82 | info!( | ||
| 83 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 84 | rx_frame.data()[0], | ||
| 85 | rx_frame.data()[1], | ||
| 86 | rx_frame.data()[2], | ||
| 87 | rx_frame.data()[3], | ||
| 88 | delta, | ||
| 89 | ) | ||
| 90 | } | ||
| 91 | Err(_err) => error!("Error in frame"), | ||
| 92 | } | ||
| 93 | |||
| 94 | Timer::after_millis(250).await; | ||
| 95 | |||
| 96 | i = i.wrapping_add(1); | ||
| 73 | } | 97 | } |
| 74 | } | 98 | } |
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index a9bf46de0..a6f969aba 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs | |||
| @@ -40,7 +40,7 @@ fn main() -> ! { | |||
| 40 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | 40 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz |
| 41 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | 41 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz |
| 42 | config.rcc.voltage_scale = VoltageScale::Scale1; | 42 | config.rcc.voltage_scale = VoltageScale::Scale1; |
| 43 | config.rcc.adc_clock_source = AdcClockSource::PLL2_P; | 43 | config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; |
| 44 | } | 44 | } |
| 45 | let p = embassy_stm32::init(config); | 45 | let p = embassy_stm32::init(config); |
| 46 | 46 | ||
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index d88bd838f..3a9887e3c 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs | |||
| @@ -6,9 +6,9 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; | 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; |
| 7 | use embassy_stm32::pac::timer::vals::Mms; | 7 | use embassy_stm32::pac::timer::vals::Mms; |
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::frequency; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::BasicInstance; | 11 | use embassy_stm32::timer::low_level::Timer; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| @@ -42,7 +42,7 @@ async fn main(spawner: Spawner) { | |||
| 42 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | 42 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz |
| 43 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | 43 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz |
| 44 | config.rcc.voltage_scale = VoltageScale::Scale1; | 44 | config.rcc.voltage_scale = VoltageScale::Scale1; |
| 45 | config.rcc.adc_clock_source = AdcClockSource::PLL2_P; | 45 | config.rcc.mux.adcsel = mux::Adcsel::PLL2_P; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | // Initialize the board and obtain a Peripherals instance | 48 | // Initialize the board and obtain a Peripherals instance |
| @@ -51,19 +51,19 @@ async fn main(spawner: Spawner) { | |||
| 51 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) | 51 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) |
| 52 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); | 52 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); |
| 53 | 53 | ||
| 54 | spawner.spawn(dac_task1(dac_ch1)).ok(); | 54 | spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); |
| 55 | spawner.spawn(dac_task2(dac_ch2)).ok(); | 55 | spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | #[embassy_executor::task] | 58 | #[embassy_executor::task] |
| 59 | async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | 59 | async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { |
| 60 | let data: &[u8; 256] = &calculate_array::<256>(); | 60 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 61 | 61 | ||
| 62 | info!("TIM6 frequency is {}", TIM6::frequency()); | 62 | info!("TIM6 frequency is {}", frequency::<TIM6>()); |
| 63 | const FREQUENCY: Hertz = Hertz::hz(200); | 63 | const FREQUENCY: Hertz = Hertz::hz(200); |
| 64 | 64 | ||
| 65 | // Compute the reload value such that we obtain the FREQUENCY for the sine | 65 | // Compute the reload value such that we obtain the FREQUENCY for the sine |
| 66 | let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; | 66 | let reload: u32 = (frequency::<TIM6>().0 / FREQUENCY.0) / data.len() as u32; |
| 67 | 67 | ||
| 68 | // Depends on your clock and on the specific chip used, you may need higher or lower values here | 68 | // Depends on your clock and on the specific chip used, you may need higher or lower values here |
| 69 | if reload < 10 { | 69 | if reload < 10 { |
| @@ -74,17 +74,17 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 74 | dac.set_triggering(true); | 74 | dac.set_triggering(true); |
| 75 | dac.enable(); | 75 | dac.enable(); |
| 76 | 76 | ||
| 77 | TIM6::enable_and_reset(); | 77 | let tim = Timer::new(tim); |
| 78 | TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 78 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 79 | TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 79 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 80 | TIM6::regs_basic().cr1().modify(|w| { | 80 | tim.regs_basic().cr1().modify(|w| { |
| 81 | w.set_opm(false); | 81 | w.set_opm(false); |
| 82 | w.set_cen(true); | 82 | w.set_cen(true); |
| 83 | }); | 83 | }); |
| 84 | 84 | ||
| 85 | debug!( | 85 | debug!( |
| 86 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 86 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 87 | TIM6::frequency(), | 87 | frequency::<TIM6>(), |
| 88 | FREQUENCY, | 88 | FREQUENCY, |
| 89 | reload, | 89 | reload, |
| 90 | reload as u16, | 90 | reload as u16, |
| @@ -99,22 +99,22 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | #[embassy_executor::task] | 101 | #[embassy_executor::task] |
| 102 | async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | 102 | async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { |
| 103 | let data: &[u8; 256] = &calculate_array::<256>(); | 103 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 104 | 104 | ||
| 105 | info!("TIM7 frequency is {}", TIM7::frequency()); | 105 | info!("TIM7 frequency is {}", frequency::<TIM6>()); |
| 106 | 106 | ||
| 107 | const FREQUENCY: Hertz = Hertz::hz(600); | 107 | const FREQUENCY: Hertz = Hertz::hz(600); |
| 108 | let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; | 108 | let reload: u32 = (frequency::<TIM7>().0 / FREQUENCY.0) / data.len() as u32; |
| 109 | 109 | ||
| 110 | if reload < 10 { | 110 | if reload < 10 { |
| 111 | error!("Reload value {} below threshold!", reload); | 111 | error!("Reload value {} below threshold!", reload); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | TIM7::enable_and_reset(); | 114 | let tim = Timer::new(tim); |
| 115 | TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 115 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 116 | TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 116 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 117 | TIM7::regs_basic().cr1().modify(|w| { | 117 | tim.regs_basic().cr1().modify(|w| { |
| 118 | w.set_opm(false); | 118 | w.set_opm(false); |
| 119 | w.set_cen(true); | 119 | w.set_cen(true); |
| 120 | }); | 120 | }); |
| @@ -125,7 +125,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | |||
| 125 | 125 | ||
| 126 | debug!( | 126 | debug!( |
| 127 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 127 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 128 | TIM7::frequency(), | 128 | frequency::<TIM7>(), |
| 129 | FREQUENCY, | 129 | FREQUENCY, |
| 130 | reload, | 130 | reload, |
| 131 | reload as u16, | 131 | reload as u16, |
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index cd9a27fcd..ec3f2c000 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { | |||
| 24 | type Device = Ethernet<'static, ETH, GenericSMI>; | 24 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 25 | 25 | ||
| 26 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 27 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 27 | async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { |
| 28 | stack.run().await | 28 | runner.run().await |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | #[embassy_executor::main] | 31 | #[embassy_executor::main] |
| @@ -64,19 +64,21 @@ async fn main(spawner: Spawner) -> ! { | |||
| 64 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 64 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 65 | 65 | ||
| 66 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); | 66 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); |
| 67 | // warning: Not all STM32H7 devices have the exact same pins here | ||
| 68 | // for STM32H747XIH, replace p.PB13 for PG12 | ||
| 67 | let device = Ethernet::new( | 69 | let device = Ethernet::new( |
| 68 | PACKETS.init(PacketQueue::<4, 4>::new()), | 70 | PACKETS.init(PacketQueue::<4, 4>::new()), |
| 69 | p.ETH, | 71 | p.ETH, |
| 70 | Irqs, | 72 | Irqs, |
| 71 | p.PA1, | 73 | p.PA1, // ref_clk |
| 72 | p.PA2, | 74 | p.PA2, // mdio |
| 73 | p.PC1, | 75 | p.PC1, // eth_mdc |
| 74 | p.PA7, | 76 | p.PA7, // CRS_DV: Carrier Sense |
| 75 | p.PC4, | 77 | p.PC4, // RX_D0: Received Bit 0 |
| 76 | p.PC5, | 78 | p.PC5, // RX_D1: Received Bit 1 |
| 77 | p.PG13, | 79 | p.PG13, // TX_D0: Transmit Bit 0 |
| 78 | p.PB13, | 80 | p.PB13, // TX_D1: Transmit Bit 1 |
| 79 | p.PG11, | 81 | p.PG11, // TX_EN: Transmit Enable |
| 80 | GenericSMI::new(0), | 82 | GenericSMI::new(0), |
| 81 | mac_addr, | 83 | mac_addr, |
| 82 | ); | 84 | ); |
| @@ -89,17 +91,11 @@ async fn main(spawner: Spawner) -> ! { | |||
| 89 | //}); | 91 | //}); |
| 90 | 92 | ||
| 91 | // Init network stack | 93 | // Init network stack |
| 92 | static STACK: StaticCell<Stack<Device>> = StaticCell::new(); | ||
| 93 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 94 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 94 | let stack = &*STACK.init(Stack::new( | 95 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 95 | device, | ||
| 96 | config, | ||
| 97 | RESOURCES.init(StackResources::<3>::new()), | ||
| 98 | seed, | ||
| 99 | )); | ||
| 100 | 96 | ||
| 101 | // Launch network task | 97 | // Launch network task |
| 102 | unwrap!(spawner.spawn(net_task(&stack))); | 98 | unwrap!(spawner.spawn(net_task(runner))); |
| 103 | 99 | ||
| 104 | // Ensure DHCP configuration is up before trying connect | 100 | // Ensure DHCP configuration is up before trying connect |
| 105 | stack.wait_config_up().await; | 101 | stack.wait_config_up().await; |
| @@ -111,7 +107,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 111 | let mut tx_buffer = [0; 1024]; | 107 | let mut tx_buffer = [0; 1024]; |
| 112 | 108 | ||
| 113 | loop { | 109 | loop { |
| 114 | let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); | 110 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); |
| 115 | 111 | ||
| 116 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); | 112 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); |
| 117 | 113 | ||
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index aeb169e19..24983ca85 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; | 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { | |||
| 25 | type Device = Ethernet<'static, ETH, GenericSMI>; | 25 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 28 | async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { |
| 29 | stack.run().await | 29 | runner.run().await |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | #[embassy_executor::main] | 32 | #[embassy_executor::main] |
| @@ -64,10 +64,10 @@ async fn main(spawner: Spawner) -> ! { | |||
| 64 | 64 | ||
| 65 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 65 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 66 | 66 | ||
| 67 | static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); | 67 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); |
| 68 | 68 | ||
| 69 | let device = Ethernet::new( | 69 | let device = Ethernet::new( |
| 70 | PACKETS.init(PacketQueue::<16, 16>::new()), | 70 | PACKETS.init(PacketQueue::<4, 4>::new()), |
| 71 | p.ETH, | 71 | p.ETH, |
| 72 | Irqs, | 72 | Irqs, |
| 73 | p.PA1, | 73 | p.PA1, |
| @@ -91,17 +91,11 @@ async fn main(spawner: Spawner) -> ! { | |||
| 91 | //}); | 91 | //}); |
| 92 | 92 | ||
| 93 | // Init network stack | 93 | // Init network stack |
| 94 | static STACK: StaticCell<Stack<Device>> = StaticCell::new(); | ||
| 95 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 94 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 96 | let stack = &*STACK.init(Stack::new( | 95 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 97 | device, | ||
| 98 | config, | ||
| 99 | RESOURCES.init(StackResources::<3>::new()), | ||
| 100 | seed, | ||
| 101 | )); | ||
| 102 | 96 | ||
| 103 | // Launch network task | 97 | // Launch network task |
| 104 | unwrap!(spawner.spawn(net_task(stack))); | 98 | unwrap!(spawner.spawn(net_task(runner))); |
| 105 | 99 | ||
| 106 | // Ensure DHCP configuration is up before trying connect | 100 | // Ensure DHCP configuration is up before trying connect |
| 107 | stack.wait_config_up().await; | 101 | stack.wait_config_up().await; |
| @@ -109,7 +103,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 109 | info!("Network task initialized"); | 103 | info!("Network task initialized"); |
| 110 | 104 | ||
| 111 | let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); | 105 | let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); |
| 112 | let client = TcpClient::new(&stack, &state); | 106 | let client = TcpClient::new(stack, &state); |
| 113 | 107 | ||
| 114 | loop { | 108 | loop { |
| 115 | // You need to start a server on the host machine, for example: `nc -l 8000` | 109 | // 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 de6ea522a..768d85993 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; | 6 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::eth::generic_smi::GenericSMI; | 8 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 9 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 10 | use embassy_stm32::peripherals::ETH; | 10 | use embassy_stm32::peripherals::ETH; |
| @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { | |||
| 25 | type Device = Ethernet<'static, ETH, GenericSMI>; | 25 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 26 | 26 | ||
| 27 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 28 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 28 | async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { |
| 29 | stack.run().await | 29 | runner.run().await |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | #[embassy_executor::main] | 32 | #[embassy_executor::main] |
| @@ -64,10 +64,10 @@ async fn main(spawner: Spawner) -> ! { | |||
| 64 | 64 | ||
| 65 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 65 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 66 | 66 | ||
| 67 | static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new(); | 67 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); |
| 68 | 68 | ||
| 69 | let device = Ethernet::new_mii( | 69 | let device = Ethernet::new_mii( |
| 70 | PACKETS.init(PacketQueue::<16, 16>::new()), | 70 | PACKETS.init(PacketQueue::<4, 4>::new()), |
| 71 | p.ETH, | 71 | p.ETH, |
| 72 | Irqs, | 72 | Irqs, |
| 73 | p.PA1, | 73 | p.PA1, |
| @@ -97,17 +97,11 @@ async fn main(spawner: Spawner) -> ! { | |||
| 97 | //}); | 97 | //}); |
| 98 | 98 | ||
| 99 | // Init network stack | 99 | // Init network stack |
| 100 | static STACK: StaticCell<Stack<Device>> = StaticCell::new(); | ||
| 101 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); | 100 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 102 | let stack = &*STACK.init(Stack::new( | 101 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 103 | device, | ||
| 104 | config, | ||
| 105 | RESOURCES.init(StackResources::<3>::new()), | ||
| 106 | seed, | ||
| 107 | )); | ||
| 108 | 102 | ||
| 109 | // Launch network task | 103 | // Launch network task |
| 110 | unwrap!(spawner.spawn(net_task(stack))); | 104 | unwrap!(spawner.spawn(net_task(runner))); |
| 111 | 105 | ||
| 112 | // Ensure DHCP configuration is up before trying connect | 106 | // Ensure DHCP configuration is up before trying connect |
| 113 | stack.wait_config_up().await; | 107 | stack.wait_config_up().await; |
| @@ -115,7 +109,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 115 | info!("Network task initialized"); | 109 | info!("Network task initialized"); |
| 116 | 110 | ||
| 117 | let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); | 111 | let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); |
| 118 | let client = TcpClient::new(&stack, &state); | 112 | let client = TcpClient::new(stack, &state); |
| 119 | 113 | ||
| 120 | loop { | 114 | loop { |
| 121 | // You need to start a server on the host machine, for example: `nc -l 8000` | 115 | // You need to start a server on the host machine, for example: `nc -l 8000` |
diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs new file mode 100644 index 000000000..6f4815582 --- /dev/null +++ b/examples/stm32h7/src/bin/i2c_shared.rs | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::cell::RefCell; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_stm32::i2c::{self, I2c}; | ||
| 10 | use embassy_stm32::mode::Async; | ||
| 11 | use embassy_stm32::time::Hertz; | ||
| 12 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 13 | use embassy_sync::blocking_mutex::NoopMutex; | ||
| 14 | use embassy_time::{Duration, Timer}; | ||
| 15 | use static_cell::StaticCell; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | const TMP117_ADDR: u8 = 0x48; | ||
| 19 | const TMP117_TEMP_RESULT: u8 = 0x00; | ||
| 20 | |||
| 21 | const SHTC3_ADDR: u8 = 0x70; | ||
| 22 | const SHTC3_WAKEUP: [u8; 2] = [0x35, 0x17]; | ||
| 23 | const SHTC3_MEASURE_RH_FIRST: [u8; 2] = [0x5c, 0x24]; | ||
| 24 | const SHTC3_SLEEP: [u8; 2] = [0xb0, 0x98]; | ||
| 25 | |||
| 26 | static I2C_BUS: StaticCell<NoopMutex<RefCell<I2c<'static, Async>>>> = StaticCell::new(); | ||
| 27 | |||
| 28 | bind_interrupts!(struct Irqs { | ||
| 29 | I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>; | ||
| 30 | I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||
| 31 | }); | ||
| 32 | |||
| 33 | #[embassy_executor::task] | ||
| 34 | async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { | ||
| 35 | let mut data = [0u8; 2]; | ||
| 36 | |||
| 37 | loop { | ||
| 38 | match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data) { | ||
| 39 | Ok(()) => { | ||
| 40 | let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0; | ||
| 41 | info!("Temperature {}", temp); | ||
| 42 | } | ||
| 43 | Err(_) => error!("I2C Error"), | ||
| 44 | } | ||
| 45 | |||
| 46 | Timer::after(Duration::from_millis(1000)).await; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | #[embassy_executor::task] | ||
| 51 | async fn humidity(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { | ||
| 52 | let mut data = [0u8; 6]; | ||
| 53 | |||
| 54 | loop { | ||
| 55 | // Wakeup | ||
| 56 | match i2c.write(SHTC3_ADDR, &SHTC3_WAKEUP) { | ||
| 57 | Ok(()) => Timer::after(Duration::from_millis(20)).await, | ||
| 58 | Err(_) => error!("I2C Error"), | ||
| 59 | } | ||
| 60 | |||
| 61 | // Measurement | ||
| 62 | match i2c.write(SHTC3_ADDR, &SHTC3_MEASURE_RH_FIRST) { | ||
| 63 | Ok(()) => Timer::after(Duration::from_millis(5)).await, | ||
| 64 | Err(_) => error!("I2C Error"), | ||
| 65 | } | ||
| 66 | |||
| 67 | // Result | ||
| 68 | match i2c.read(SHTC3_ADDR, &mut data) { | ||
| 69 | Ok(()) => Timer::after(Duration::from_millis(5)).await, | ||
| 70 | Err(_) => error!("I2C Error"), | ||
| 71 | } | ||
| 72 | |||
| 73 | // Sleep | ||
| 74 | match i2c.write(SHTC3_ADDR, &SHTC3_SLEEP) { | ||
| 75 | Ok(()) => { | ||
| 76 | let (bytes, _) = data.split_at(core::mem::size_of::<i16>()); | ||
| 77 | let rh = f32::from(u16::from_be_bytes(bytes.try_into().unwrap())) * 100.0 / 65536.0; | ||
| 78 | info!("Humidity: {}", rh); | ||
| 79 | } | ||
| 80 | Err(_) => error!("I2C Error"), | ||
| 81 | } | ||
| 82 | |||
| 83 | Timer::after(Duration::from_millis(1000)).await; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | #[embassy_executor::main] | ||
| 88 | async fn main(spawner: Spawner) { | ||
| 89 | let p = embassy_stm32::init(Default::default()); | ||
| 90 | |||
| 91 | let i2c = I2c::new( | ||
| 92 | p.I2C1, | ||
| 93 | p.PB8, | ||
| 94 | p.PB9, | ||
| 95 | Irqs, | ||
| 96 | p.DMA1_CH4, | ||
| 97 | p.DMA1_CH5, | ||
| 98 | Hertz(100_000), | ||
| 99 | Default::default(), | ||
| 100 | ); | ||
| 101 | let i2c_bus = NoopMutex::new(RefCell::new(i2c)); | ||
| 102 | let i2c_bus = I2C_BUS.init(i2c_bus); | ||
| 103 | |||
| 104 | // Device 1, using embedded-hal-async compatible driver for TMP117 | ||
| 105 | let i2c_dev1 = I2cDevice::new(i2c_bus); | ||
| 106 | spawner.spawn(temperature(i2c_dev1)).unwrap(); | ||
| 107 | |||
| 108 | // Device 2, using embedded-hal-async compatible driver for SHTC3 | ||
| 109 | let i2c_dev2 = I2cDevice::new(i2c_bus); | ||
| 110 | spawner.spawn(humidity(i2c_dev2)).unwrap(); | ||
| 111 | } | ||
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index cc508c3cf..b796996ea 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs | |||
| @@ -3,11 +3,11 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::gpio::low_level::AFType; | 6 | use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed}; |
| 7 | use embassy_stm32::gpio::Speed; | ||
| 8 | use embassy_stm32::time::{khz, Hertz}; | 7 | use embassy_stm32::time::{khz, Hertz}; |
| 9 | use embassy_stm32::timer::*; | 8 | use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; |
| 10 | use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; | 9 | use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; |
| 10 | use embassy_stm32::{into_ref, Config, Peripheral}; | ||
| 11 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| @@ -56,11 +56,15 @@ async fn main(_spawner: Spawner) { | |||
| 56 | Timer::after_millis(300).await; | 56 | Timer::after_millis(300).await; |
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { | 59 | pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> { |
| 60 | inner: PeripheralRef<'d, T>, | 60 | tim: LLTimer<'d, T>, |
| 61 | _ch1: Flex<'d>, | ||
| 62 | _ch2: Flex<'d>, | ||
| 63 | _ch3: Flex<'d>, | ||
| 64 | _ch4: Flex<'d>, | ||
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | 67 | impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { |
| 64 | pub fn new( | 68 | pub fn new( |
| 65 | tim: impl Peripheral<P = T> + 'd, | 69 | tim: impl Peripheral<P = T> + 'd, |
| 66 | ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, | 70 | ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, |
| @@ -69,25 +73,33 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 69 | ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, | 73 | ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, |
| 70 | freq: Hertz, | 74 | freq: Hertz, |
| 71 | ) -> Self { | 75 | ) -> Self { |
| 72 | into_ref!(tim, ch1, ch2, ch3, ch4); | 76 | into_ref!(ch1, ch2, ch3, ch4); |
| 73 | 77 | ||
| 74 | T::enable_and_reset(); | 78 | let af1 = ch1.af_num(); |
| 75 | 79 | let af2 = ch2.af_num(); | |
| 76 | ch1.set_speed(Speed::VeryHigh); | 80 | let af3 = ch3.af_num(); |
| 77 | ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 81 | let af4 = ch4.af_num(); |
| 78 | ch2.set_speed(Speed::VeryHigh); | 82 | let mut ch1 = Flex::new(ch1); |
| 79 | ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 83 | let mut ch2 = Flex::new(ch2); |
| 80 | ch3.set_speed(Speed::VeryHigh); | 84 | let mut ch3 = Flex::new(ch3); |
| 81 | ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 85 | let mut ch4 = Flex::new(ch4); |
| 82 | ch4.set_speed(Speed::VeryHigh); | 86 | ch1.set_as_af_unchecked(af1, AfType::output(OutputType::PushPull, Speed::VeryHigh)); |
| 83 | ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 87 | ch2.set_as_af_unchecked(af2, AfType::output(OutputType::PushPull, Speed::VeryHigh)); |
| 84 | 88 | ch3.set_as_af_unchecked(af3, AfType::output(OutputType::PushPull, Speed::VeryHigh)); | |
| 85 | let mut this = Self { inner: tim }; | 89 | ch4.set_as_af_unchecked(af4, AfType::output(OutputType::PushPull, Speed::VeryHigh)); |
| 90 | |||
| 91 | let mut this = Self { | ||
| 92 | tim: LLTimer::new(tim), | ||
| 93 | _ch1: ch1, | ||
| 94 | _ch2: ch2, | ||
| 95 | _ch3: ch3, | ||
| 96 | _ch4: ch4, | ||
| 97 | }; | ||
| 86 | 98 | ||
| 87 | this.set_frequency(freq); | 99 | this.set_frequency(freq); |
| 88 | this.inner.start(); | 100 | this.tim.start(); |
| 89 | 101 | ||
| 90 | let r = T::regs_gp32(); | 102 | let r = this.tim.regs_gp32(); |
| 91 | r.ccmr_output(0) | 103 | r.ccmr_output(0) |
| 92 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | 104 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); |
| 93 | r.ccmr_output(0) | 105 | r.ccmr_output(0) |
| @@ -101,23 +113,26 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 101 | } | 113 | } |
| 102 | 114 | ||
| 103 | pub fn enable(&mut self, channel: Channel) { | 115 | pub fn enable(&mut self, channel: Channel) { |
| 104 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); | 116 | self.tim.regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); |
| 105 | } | 117 | } |
| 106 | 118 | ||
| 107 | pub fn disable(&mut self, channel: Channel) { | 119 | pub fn disable(&mut self, channel: Channel) { |
| 108 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); | 120 | self.tim |
| 121 | .regs_gp32() | ||
| 122 | .ccer() | ||
| 123 | .modify(|w| w.set_cce(channel.index(), false)); | ||
| 109 | } | 124 | } |
| 110 | 125 | ||
| 111 | pub fn set_frequency(&mut self, freq: Hertz) { | 126 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 112 | <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); | 127 | self.tim.set_frequency(freq); |
| 113 | } | 128 | } |
| 114 | 129 | ||
| 115 | pub fn get_max_duty(&self) -> u32 { | 130 | pub fn get_max_duty(&self) -> u32 { |
| 116 | T::regs_gp32().arr().read().arr() | 131 | self.tim.regs_gp32().arr().read() |
| 117 | } | 132 | } |
| 118 | 133 | ||
| 119 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { | 134 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 120 | defmt::assert!(duty < self.get_max_duty()); | 135 | defmt::assert!(duty < self.get_max_duty()); |
| 121 | T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty)) | 136 | self.tim.regs_gp32().ccr(channel.index()).write_value(duty) |
| 122 | } | 137 | } |
| 123 | } | 138 | } |
diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs new file mode 100644 index 000000000..b4620888f --- /dev/null +++ b/examples/stm32h7/src/bin/multiprio.rs | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | //! This example showcases how to create multiple Executor instances to run tasks at | ||
| 2 | //! different priority levels. | ||
| 3 | //! | ||
| 4 | //! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling | ||
| 5 | //! there's work in the queue, and `wfe` for waiting for work. | ||
| 6 | //! | ||
| 7 | //! Medium and high priority executors run in two interrupts with different priorities. | ||
| 8 | //! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since | ||
| 9 | //! when there's work the interrupt will trigger and run the executor. | ||
| 10 | //! | ||
| 11 | //! Sample output below. Note that high priority ticks can interrupt everything else, and | ||
| 12 | //! medium priority computations can interrupt low priority computations, making them to appear | ||
| 13 | //! to take significantly longer time. | ||
| 14 | //! | ||
| 15 | //! ```not_rust | ||
| 16 | //! [med] Starting long computation | ||
| 17 | //! [med] done in 992 ms | ||
| 18 | //! [high] tick! | ||
| 19 | //! [low] Starting long computation | ||
| 20 | //! [med] Starting long computation | ||
| 21 | //! [high] tick! | ||
| 22 | //! [high] tick! | ||
| 23 | //! [med] done in 993 ms | ||
| 24 | //! [med] Starting long computation | ||
| 25 | //! [high] tick! | ||
| 26 | //! [high] tick! | ||
| 27 | //! [med] done in 993 ms | ||
| 28 | //! [low] done in 3972 ms | ||
| 29 | //! [med] Starting long computation | ||
| 30 | //! [high] tick! | ||
| 31 | //! [high] tick! | ||
| 32 | //! [med] done in 993 ms | ||
| 33 | //! ``` | ||
| 34 | //! | ||
| 35 | //! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. | ||
| 36 | //! You will get an output like the following. Note that no computation is ever interrupted. | ||
| 37 | //! | ||
| 38 | //! ```not_rust | ||
| 39 | //! [high] tick! | ||
| 40 | //! [med] Starting long computation | ||
| 41 | //! [med] done in 496 ms | ||
| 42 | //! [low] Starting long computation | ||
| 43 | //! [low] done in 992 ms | ||
| 44 | //! [med] Starting long computation | ||
| 45 | //! [med] done in 496 ms | ||
| 46 | //! [high] tick! | ||
| 47 | //! [low] Starting long computation | ||
| 48 | //! [low] done in 992 ms | ||
| 49 | //! [high] tick! | ||
| 50 | //! [med] Starting long computation | ||
| 51 | //! [med] done in 496 ms | ||
| 52 | //! [high] tick! | ||
| 53 | //! ``` | ||
| 54 | //! | ||
| 55 | |||
| 56 | #![no_std] | ||
| 57 | #![no_main] | ||
| 58 | |||
| 59 | use cortex_m_rt::entry; | ||
| 60 | use defmt::*; | ||
| 61 | use embassy_executor::{Executor, InterruptExecutor}; | ||
| 62 | use embassy_stm32::interrupt; | ||
| 63 | use embassy_stm32::interrupt::{InterruptExt, Priority}; | ||
| 64 | use embassy_time::{Instant, Timer}; | ||
| 65 | use static_cell::StaticCell; | ||
| 66 | use {defmt_rtt as _, panic_probe as _}; | ||
| 67 | |||
| 68 | #[embassy_executor::task] | ||
| 69 | async fn run_high() { | ||
| 70 | loop { | ||
| 71 | info!(" [high] tick!"); | ||
| 72 | Timer::after_ticks(27374).await; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | #[embassy_executor::task] | ||
| 77 | async fn run_med() { | ||
| 78 | loop { | ||
| 79 | let start = Instant::now(); | ||
| 80 | info!(" [med] Starting long computation"); | ||
| 81 | |||
| 82 | // Spin-wait to simulate a long CPU computation | ||
| 83 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second | ||
| 84 | |||
| 85 | let end = Instant::now(); | ||
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 87 | info!(" [med] done in {} ms", ms); | ||
| 88 | |||
| 89 | Timer::after_ticks(23421).await; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | #[embassy_executor::task] | ||
| 94 | async fn run_low() { | ||
| 95 | loop { | ||
| 96 | let start = Instant::now(); | ||
| 97 | info!("[low] Starting long computation"); | ||
| 98 | |||
| 99 | // Spin-wait to simulate a long CPU computation | ||
| 100 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds | ||
| 101 | |||
| 102 | let end = Instant::now(); | ||
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 104 | info!("[low] done in {} ms", ms); | ||
| 105 | |||
| 106 | Timer::after_ticks(32983).await; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); | ||
| 111 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); | ||
| 112 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | ||
| 113 | |||
| 114 | #[interrupt] | ||
| 115 | unsafe fn UART4() { | ||
| 116 | EXECUTOR_HIGH.on_interrupt() | ||
| 117 | } | ||
| 118 | |||
| 119 | #[interrupt] | ||
| 120 | unsafe fn UART5() { | ||
| 121 | EXECUTOR_MED.on_interrupt() | ||
| 122 | } | ||
| 123 | |||
| 124 | #[entry] | ||
| 125 | fn main() -> ! { | ||
| 126 | info!("Hello World!"); | ||
| 127 | |||
| 128 | let _p = embassy_stm32::init(Default::default()); | ||
| 129 | |||
| 130 | // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as | ||
| 131 | // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. | ||
| 132 | // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt | ||
| 133 | // vector would work exactly the same. | ||
| 134 | |||
| 135 | // High-priority executor: UART4, priority level 6 | ||
| 136 | interrupt::UART4.set_priority(Priority::P6); | ||
| 137 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); | ||
| 138 | unwrap!(spawner.spawn(run_high())); | ||
| 139 | |||
| 140 | // Medium-priority executor: UART5, priority level 7 | ||
| 141 | interrupt::UART5.set_priority(Priority::P7); | ||
| 142 | let spawner = EXECUTOR_MED.start(interrupt::UART5); | ||
| 143 | unwrap!(spawner.spawn(run_med())); | ||
| 144 | |||
| 145 | // Low priority executor: runs in thread mode, using WFE/SEV | ||
| 146 | let executor = EXECUTOR_LOW.init(Executor::new()); | ||
| 147 | executor.run(|spawner| { | ||
| 148 | unwrap!(spawner.spawn(run_low())); | ||
| 149 | }); | ||
| 150 | } | ||
diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs index c6b9cf57e..0adb48877 100644 --- a/examples/stm32h7/src/bin/rtc.rs +++ b/examples/stm32h7/src/bin/rtc.rs | |||
| @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { | |||
| 24 | .unwrap(); | 24 | .unwrap(); |
| 25 | 25 | ||
| 26 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 26 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 27 | info!("Got RTC! {:?}", now.timestamp()); | 27 | info!("Got RTC! {:?}", now.and_utc().timestamp()); |
| 28 | 28 | ||
| 29 | rtc.set_datetime(now.into()).expect("datetime not set"); | 29 | rtc.set_datetime(now.into()).expect("datetime not set"); |
| 30 | 30 | ||
| @@ -32,5 +32,5 @@ async fn main(_spawner: Spawner) { | |||
| 32 | Timer::after_millis(20000).await; | 32 | Timer::after_millis(20000).await; |
| 33 | 33 | ||
| 34 | let then: NaiveDateTime = rtc.now().unwrap().into(); | 34 | let then: NaiveDateTime = rtc.now().unwrap().into(); |
| 35 | info!("Got RTC! {:?}", then.timestamp()); | 35 | info!("Got RTC! {:?}", then.and_utc().timestamp()); |
| 36 | } | 36 | } |
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs new file mode 100644 index 000000000..f6735e235 --- /dev/null +++ b/examples/stm32h7/src/bin/sai.rs | |||
| @@ -0,0 +1,186 @@ | |||
| 1 | //! Daisy Seed rev.7(with PCM3060 codec) | ||
| 2 | //! https://electro-smith.com/products/daisy-seed | ||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use grounded::uninit::GroundedArrayCell; | ||
| 8 | use hal::rcc::*; | ||
| 9 | use hal::sai::*; | ||
| 10 | use hal::time::Hertz; | ||
| 11 | use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _}; | ||
| 12 | |||
| 13 | const BLOCK_LENGTH: usize = 32; // 32 samples | ||
| 14 | const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * 2; // 2 channels | ||
| 15 | const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks | ||
| 16 | const SAMPLE_RATE: u32 = 48000; | ||
| 17 | |||
| 18 | //DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions | ||
| 19 | #[link_section = ".sram1_bss"] | ||
| 20 | static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); | ||
| 21 | #[link_section = ".sram1_bss"] | ||
| 22 | static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit(); | ||
| 23 | |||
| 24 | #[embassy_executor::main] | ||
| 25 | async fn main(_spawner: Spawner) { | ||
| 26 | let mut config = hal::Config::default(); | ||
| 27 | config.rcc.pll1 = Some(Pll { | ||
| 28 | source: PllSource::HSE, | ||
| 29 | prediv: PllPreDiv::DIV4, | ||
| 30 | mul: PllMul::MUL200, | ||
| 31 | divp: Some(PllDiv::DIV2), | ||
| 32 | divq: Some(PllDiv::DIV5), | ||
| 33 | divr: Some(PllDiv::DIV2), | ||
| 34 | }); | ||
| 35 | config.rcc.pll3 = Some(Pll { | ||
| 36 | source: PllSource::HSE, | ||
| 37 | prediv: PllPreDiv::DIV6, | ||
| 38 | mul: PllMul::MUL295, | ||
| 39 | divp: Some(PllDiv::DIV16), | ||
| 40 | divq: Some(PllDiv::DIV4), | ||
| 41 | divr: Some(PllDiv::DIV32), | ||
| 42 | }); | ||
| 43 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 44 | config.rcc.mux.sai1sel = hal::pac::rcc::vals::Saisel::PLL3_P; | ||
| 45 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz | ||
| 46 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 47 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 48 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 49 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 50 | config.rcc.hse = Some(Hse { | ||
| 51 | freq: Hertz::mhz(16), | ||
| 52 | mode: HseMode::Oscillator, | ||
| 53 | }); | ||
| 54 | |||
| 55 | let p = hal::init(config); | ||
| 56 | |||
| 57 | let (sub_block_tx, sub_block_rx) = hal::sai::split_subblocks(p.SAI1); | ||
| 58 | let kernel_clock = hal::rcc::frequency::<hal::peripherals::SAI1>().0; | ||
| 59 | let mclk_div = mclk_div_from_u8((kernel_clock / (SAMPLE_RATE * 256)) as u8); | ||
| 60 | |||
| 61 | let mut tx_config = hal::sai::Config::default(); | ||
| 62 | tx_config.mode = Mode::Master; | ||
| 63 | tx_config.tx_rx = TxRx::Transmitter; | ||
| 64 | tx_config.sync_output = true; | ||
| 65 | tx_config.clock_strobe = ClockStrobe::Falling; | ||
| 66 | tx_config.master_clock_divider = mclk_div; | ||
| 67 | tx_config.stereo_mono = StereoMono::Stereo; | ||
| 68 | tx_config.data_size = DataSize::Data24; | ||
| 69 | tx_config.bit_order = BitOrder::MsbFirst; | ||
| 70 | tx_config.frame_sync_polarity = FrameSyncPolarity::ActiveHigh; | ||
| 71 | tx_config.frame_sync_offset = FrameSyncOffset::OnFirstBit; | ||
| 72 | tx_config.frame_length = 64; | ||
| 73 | tx_config.frame_sync_active_level_length = embassy_stm32::sai::word::U7(32); | ||
| 74 | tx_config.fifo_threshold = FifoThreshold::Quarter; | ||
| 75 | |||
| 76 | let mut rx_config = tx_config.clone(); | ||
| 77 | rx_config.mode = Mode::Slave; | ||
| 78 | rx_config.tx_rx = TxRx::Receiver; | ||
| 79 | rx_config.sync_input = SyncInput::Internal; | ||
| 80 | rx_config.clock_strobe = ClockStrobe::Rising; | ||
| 81 | rx_config.sync_output = false; | ||
| 82 | |||
| 83 | let tx_buffer: &mut [u32] = unsafe { | ||
| 84 | TX_BUFFER.initialize_all_copied(0); | ||
| 85 | let (ptr, len) = TX_BUFFER.get_ptr_len(); | ||
| 86 | core::slice::from_raw_parts_mut(ptr, len) | ||
| 87 | }; | ||
| 88 | |||
| 89 | let mut sai_transmitter = Sai::new_asynchronous_with_mclk( | ||
| 90 | sub_block_tx, | ||
| 91 | p.PE5, | ||
| 92 | p.PE6, | ||
| 93 | p.PE4, | ||
| 94 | p.PE2, | ||
| 95 | p.DMA1_CH0, | ||
| 96 | tx_buffer, | ||
| 97 | tx_config, | ||
| 98 | ); | ||
| 99 | |||
| 100 | let rx_buffer: &mut [u32] = unsafe { | ||
| 101 | RX_BUFFER.initialize_all_copied(0); | ||
| 102 | let (ptr, len) = RX_BUFFER.get_ptr_len(); | ||
| 103 | core::slice::from_raw_parts_mut(ptr, len) | ||
| 104 | }; | ||
| 105 | |||
| 106 | let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config); | ||
| 107 | |||
| 108 | sai_receiver.start(); | ||
| 109 | sai_transmitter.start(); | ||
| 110 | |||
| 111 | let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; | ||
| 112 | |||
| 113 | loop { | ||
| 114 | sai_receiver.read(&mut buf).await.unwrap(); | ||
| 115 | sai_transmitter.write(&buf).await.unwrap(); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | const fn mclk_div_from_u8(v: u8) -> MasterClockDivider { | ||
| 120 | match v { | ||
| 121 | 1 => MasterClockDivider::Div1, | ||
| 122 | 2 => MasterClockDivider::Div2, | ||
| 123 | 3 => MasterClockDivider::Div3, | ||
| 124 | 4 => MasterClockDivider::Div4, | ||
| 125 | 5 => MasterClockDivider::Div5, | ||
| 126 | 6 => MasterClockDivider::Div6, | ||
| 127 | 7 => MasterClockDivider::Div7, | ||
| 128 | 8 => MasterClockDivider::Div8, | ||
| 129 | 9 => MasterClockDivider::Div9, | ||
| 130 | 10 => MasterClockDivider::Div10, | ||
| 131 | 11 => MasterClockDivider::Div11, | ||
| 132 | 12 => MasterClockDivider::Div12, | ||
| 133 | 13 => MasterClockDivider::Div13, | ||
| 134 | 14 => MasterClockDivider::Div14, | ||
| 135 | 15 => MasterClockDivider::Div15, | ||
| 136 | 16 => MasterClockDivider::Div16, | ||
| 137 | 17 => MasterClockDivider::Div17, | ||
| 138 | 18 => MasterClockDivider::Div18, | ||
| 139 | 19 => MasterClockDivider::Div19, | ||
| 140 | 20 => MasterClockDivider::Div20, | ||
| 141 | 21 => MasterClockDivider::Div21, | ||
| 142 | 22 => MasterClockDivider::Div22, | ||
| 143 | 23 => MasterClockDivider::Div23, | ||
| 144 | 24 => MasterClockDivider::Div24, | ||
| 145 | 25 => MasterClockDivider::Div25, | ||
| 146 | 26 => MasterClockDivider::Div26, | ||
| 147 | 27 => MasterClockDivider::Div27, | ||
| 148 | 28 => MasterClockDivider::Div28, | ||
| 149 | 29 => MasterClockDivider::Div29, | ||
| 150 | 30 => MasterClockDivider::Div30, | ||
| 151 | 31 => MasterClockDivider::Div31, | ||
| 152 | 32 => MasterClockDivider::Div32, | ||
| 153 | 33 => MasterClockDivider::Div33, | ||
| 154 | 34 => MasterClockDivider::Div34, | ||
| 155 | 35 => MasterClockDivider::Div35, | ||
| 156 | 36 => MasterClockDivider::Div36, | ||
| 157 | 37 => MasterClockDivider::Div37, | ||
| 158 | 38 => MasterClockDivider::Div38, | ||
| 159 | 39 => MasterClockDivider::Div39, | ||
| 160 | 40 => MasterClockDivider::Div40, | ||
| 161 | 41 => MasterClockDivider::Div41, | ||
| 162 | 42 => MasterClockDivider::Div42, | ||
| 163 | 43 => MasterClockDivider::Div43, | ||
| 164 | 44 => MasterClockDivider::Div44, | ||
| 165 | 45 => MasterClockDivider::Div45, | ||
| 166 | 46 => MasterClockDivider::Div46, | ||
| 167 | 47 => MasterClockDivider::Div47, | ||
| 168 | 48 => MasterClockDivider::Div48, | ||
| 169 | 49 => MasterClockDivider::Div49, | ||
| 170 | 50 => MasterClockDivider::Div50, | ||
| 171 | 51 => MasterClockDivider::Div51, | ||
| 172 | 52 => MasterClockDivider::Div52, | ||
| 173 | 53 => MasterClockDivider::Div53, | ||
| 174 | 54 => MasterClockDivider::Div54, | ||
| 175 | 55 => MasterClockDivider::Div55, | ||
| 176 | 56 => MasterClockDivider::Div56, | ||
| 177 | 57 => MasterClockDivider::Div57, | ||
| 178 | 58 => MasterClockDivider::Div58, | ||
| 179 | 59 => MasterClockDivider::Div59, | ||
| 180 | 60 => MasterClockDivider::Div60, | ||
| 181 | 61 => MasterClockDivider::Div61, | ||
| 182 | 62 => MasterClockDivider::Div62, | ||
| 183 | 63 => MasterClockDivider::Div63, | ||
| 184 | _ => panic!(), | ||
| 185 | } | ||
| 186 | } | ||
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index aed27723a..ad4a8aaf7 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs | |||
| @@ -7,8 +7,7 @@ use core::str::from_utf8; | |||
| 7 | use cortex_m_rt::entry; | 7 | use cortex_m_rt::entry; |
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Executor; | 9 | use embassy_executor::Executor; |
| 10 | use embassy_stm32::dma::NoDma; | 10 | use embassy_stm32::mode::Blocking; |
| 11 | use embassy_stm32::peripherals::SPI3; | ||
| 12 | use embassy_stm32::time::mhz; | 11 | use embassy_stm32::time::mhz; |
| 13 | use embassy_stm32::{spi, Config}; | 12 | use embassy_stm32::{spi, Config}; |
| 14 | use heapless::String; | 13 | use heapless::String; |
| @@ -16,7 +15,7 @@ use static_cell::StaticCell; | |||
| 16 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | 16 | ||
| 18 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 19 | async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) { | 18 | async fn main_task(mut spi: spi::Spi<'static, Blocking>) { |
| 20 | for n in 0u32.. { | 19 | for n in 0u32.. { |
| 21 | let mut write: String<128> = String::new(); | 20 | let mut write: String<128> = String::new(); |
| 22 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | 21 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); |
| @@ -62,7 +61,7 @@ fn main() -> ! { | |||
| 62 | let mut spi_config = spi::Config::default(); | 61 | let mut spi_config = spi::Config::default(); |
| 63 | spi_config.frequency = mhz(1); | 62 | spi_config.frequency = mhz(1); |
| 64 | 63 | ||
| 65 | let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, NoDma, NoDma, spi_config); | 64 | let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config); |
| 66 | 65 | ||
| 67 | let executor = EXECUTOR.init(Executor::new()); | 66 | let executor = EXECUTOR.init(Executor::new()); |
| 68 | 67 | ||
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs new file mode 100644 index 000000000..43fb6b41c --- /dev/null +++ b/examples/stm32h7/src/bin/spi_bdma.rs | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::fmt::Write; | ||
| 5 | use core::str::from_utf8; | ||
| 6 | |||
| 7 | use cortex_m_rt::entry; | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Executor; | ||
| 10 | use embassy_stm32::mode::Async; | ||
| 11 | use embassy_stm32::time::mhz; | ||
| 12 | use embassy_stm32::{spi, Config}; | ||
| 13 | use grounded::uninit::GroundedArrayCell; | ||
| 14 | use heapless::String; | ||
| 15 | use static_cell::StaticCell; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | // Defined in memory.x | ||
| 19 | #[link_section = ".ram_d3"] | ||
| 20 | static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit(); | ||
| 21 | |||
| 22 | #[embassy_executor::task] | ||
| 23 | async fn main_task(mut spi: spi::Spi<'static, Async>) { | ||
| 24 | let (read_buffer, write_buffer) = unsafe { | ||
| 25 | RAM_D3.initialize_all_copied(0); | ||
| 26 | ( | ||
| 27 | RAM_D3.get_subslice_mut_unchecked(0, 128), | ||
| 28 | RAM_D3.get_subslice_mut_unchecked(128, 128), | ||
| 29 | ) | ||
| 30 | }; | ||
| 31 | |||
| 32 | for n in 0u32.. { | ||
| 33 | let mut write: String<128> = String::new(); | ||
| 34 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 35 | let read_buffer = &mut read_buffer[..write.len()]; | ||
| 36 | let write_buffer = &mut write_buffer[..write.len()]; | ||
| 37 | // copy data to write_buffer which is located in D3 domain, accessable by BDMA | ||
| 38 | write_buffer.clone_from_slice(write.as_bytes()); | ||
| 39 | |||
| 40 | spi.transfer(read_buffer, write_buffer).await.ok(); | ||
| 41 | info!("read via spi+dma: {}", from_utf8(read_buffer).unwrap()); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 46 | |||
| 47 | #[entry] | ||
| 48 | fn main() -> ! { | ||
| 49 | info!("Hello World!"); | ||
| 50 | |||
| 51 | let mut config = Config::default(); | ||
| 52 | { | ||
| 53 | use embassy_stm32::rcc::*; | ||
| 54 | config.rcc.hsi = Some(HSIPrescaler::DIV1); | ||
| 55 | config.rcc.csi = true; | ||
| 56 | config.rcc.pll1 = Some(Pll { | ||
| 57 | source: PllSource::HSI, | ||
| 58 | prediv: PllPreDiv::DIV4, | ||
| 59 | mul: PllMul::MUL50, | ||
| 60 | divp: Some(PllDiv::DIV2), | ||
| 61 | divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz. | ||
| 62 | divr: None, | ||
| 63 | }); | ||
| 64 | config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz | ||
| 65 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz | ||
| 66 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 67 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 68 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 69 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 70 | config.rcc.voltage_scale = VoltageScale::Scale1; | ||
| 71 | } | ||
| 72 | let p = embassy_stm32::init(config); | ||
| 73 | |||
| 74 | let mut spi_config = spi::Config::default(); | ||
| 75 | spi_config.frequency = mhz(1); | ||
| 76 | |||
| 77 | let spi = spi::Spi::new(p.SPI6, p.PA5, p.PA7, p.PA6, p.BDMA_CH1, p.BDMA_CH0, spi_config); | ||
| 78 | |||
| 79 | let executor = EXECUTOR.init(Executor::new()); | ||
| 80 | |||
| 81 | executor.run(|spawner| { | ||
| 82 | unwrap!(spawner.spawn(main_task(spi))); | ||
| 83 | }) | ||
| 84 | } | ||
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 54d4d7656..731c7fef5 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs | |||
| @@ -7,7 +7,7 @@ use core::str::from_utf8; | |||
| 7 | use cortex_m_rt::entry; | 7 | use cortex_m_rt::entry; |
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Executor; | 9 | use embassy_executor::Executor; |
| 10 | use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3}; | 10 | use embassy_stm32::mode::Async; |
| 11 | use embassy_stm32::time::mhz; | 11 | use embassy_stm32::time::mhz; |
| 12 | use embassy_stm32::{spi, Config}; | 12 | use embassy_stm32::{spi, Config}; |
| 13 | use heapless::String; | 13 | use heapless::String; |
| @@ -15,7 +15,7 @@ use static_cell::StaticCell; | |||
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 18 | async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) { | 18 | async fn main_task(mut spi: spi::Spi<'static, Async>) { |
| 19 | for n in 0u32.. { | 19 | for n in 0u32.. { |
| 20 | let mut write: String<128> = String::new(); | 20 | let mut write: String<128> = String::new(); |
| 21 | let mut read = [0; 128]; | 21 | let mut read = [0; 128]; |
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index f9cbad6af..cc49c2fdb 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs | |||
| @@ -4,22 +4,16 @@ | |||
| 4 | use cortex_m_rt::entry; | 4 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Executor; | 6 | use embassy_executor::Executor; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::usart::{Config, Uart}; | 7 | use embassy_stm32::usart::{Config, Uart}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 10 | use static_cell::StaticCell; | 8 | use static_cell::StaticCell; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 10 | ||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | #[embassy_executor::task] | 11 | #[embassy_executor::task] |
| 18 | async fn main_task() { | 12 | async fn main_task() { |
| 19 | let p = embassy_stm32::init(Default::default()); | 13 | let p = embassy_stm32::init(Default::default()); |
| 20 | 14 | ||
| 21 | let config = Config::default(); | 15 | let config = Config::default(); |
| 22 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); | 16 | let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); |
| 23 | 17 | ||
| 24 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 18 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 25 | info!("wrote Hello, starting echo"); | 19 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index ae1f3a2e9..6f340d40a 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs | |||
| @@ -6,7 +6,6 @@ use core::fmt::Write; | |||
| 6 | use cortex_m_rt::entry; | 6 | use cortex_m_rt::entry; |
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Executor; | 8 | use embassy_executor::Executor; |
| 9 | use embassy_stm32::dma::NoDma; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 9 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 12 | use heapless::String; | 11 | use heapless::String; |
| @@ -22,7 +21,7 @@ async fn main_task() { | |||
| 22 | let p = embassy_stm32::init(Default::default()); | 21 | let p = embassy_stm32::init(Default::default()); |
| 23 | 22 | ||
| 24 | let config = Config::default(); | 23 | let config = Config::default(); |
| 25 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap(); | 24 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap(); |
| 26 | 25 | ||
| 27 | for n in 0u32.. { | 26 | for n in 0u32.. { |
| 28 | let mut s: String<128> = String::new(); | 27 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index b98c40877..2bb58be5e 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs | |||
| @@ -3,8 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | 6 | use embassy_stm32::mode::Async; |
| 7 | use embassy_stm32::peripherals::{DMA1_CH1, UART7}; | ||
| 8 | use embassy_stm32::usart::{Config, Uart, UartRx}; | 7 | use embassy_stm32::usart::{Config, Uart, UartRx}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 9 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| @@ -15,18 +14,6 @@ bind_interrupts!(struct Irqs { | |||
| 15 | UART7 => usart::InterruptHandler<peripherals::UART7>; | 14 | UART7 => usart::InterruptHandler<peripherals::UART7>; |
| 16 | }); | 15 | }); |
| 17 | 16 | ||
| 18 | #[embassy_executor::task] | ||
| 19 | async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { | ||
| 20 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||
| 21 | info!("wrote Hello, starting echo"); | ||
| 22 | |||
| 23 | let mut buf = [0u8; 1]; | ||
| 24 | loop { | ||
| 25 | unwrap!(usart.blocking_read(&mut buf)); | ||
| 26 | unwrap!(usart.blocking_write(&buf)); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | 17 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); |
| 31 | 18 | ||
| 32 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| @@ -50,7 +37,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 50 | } | 37 | } |
| 51 | 38 | ||
| 52 | #[embassy_executor::task] | 39 | #[embassy_executor::task] |
| 53 | async fn reader(mut rx: UartRx<'static, UART7, DMA1_CH1>) { | 40 | async fn reader(mut rx: UartRx<'static, Async>) { |
| 54 | let mut buf = [0; 8]; | 41 | let mut buf = [0; 8]; |
| 55 | loop { | 42 | loop { |
| 56 | info!("reading..."); | 43 | info!("reading..."); |
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index d81efb541..65ae597d4 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs | |||
| @@ -3,18 +3,23 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::usb_otg::{Driver, Instance}; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||
| 8 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 9 | use embassy_usb::driver::EndpointError; | 10 | use embassy_usb::driver::EndpointError; |
| 10 | use embassy_usb::Builder; | 11 | use embassy_usb::Builder; |
| 11 | use futures::future::join; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| 14 | bind_interrupts!(struct Irqs { | 14 | bind_interrupts!(struct Irqs { |
| 15 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 15 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 16 | }); | 16 | }); |
| 17 | 17 | ||
| 18 | // If you are trying this and your USB device doesn't connect, the most | ||
| 19 | // common issues are the RCC config and vbus_detection | ||
| 20 | // | ||
| 21 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 22 | // for more information. | ||
| 18 | #[embassy_executor::main] | 23 | #[embassy_executor::main] |
| 19 | async fn main(_spawner: Spawner) { | 24 | async fn main(_spawner: Spawner) { |
| 20 | info!("Hello World!"); | 25 | info!("Hello World!"); |
| @@ -40,13 +45,20 @@ async fn main(_spawner: Spawner) { | |||
| 40 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | 45 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz |
| 41 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | 46 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz |
| 42 | config.rcc.voltage_scale = VoltageScale::Scale1; | 47 | config.rcc.voltage_scale = VoltageScale::Scale1; |
| 48 | config.rcc.mux.usbsel = mux::Usbsel::HSI48; | ||
| 43 | } | 49 | } |
| 44 | let p = embassy_stm32::init(config); | 50 | let p = embassy_stm32::init(config); |
| 45 | 51 | ||
| 46 | // Create the driver, from the HAL. | 52 | // Create the driver, from the HAL. |
| 47 | let mut ep_out_buffer = [0u8; 256]; | 53 | let mut ep_out_buffer = [0u8; 256]; |
| 48 | let mut config = embassy_stm32::usb_otg::Config::default(); | 54 | let mut config = embassy_stm32::usb::Config::default(); |
| 49 | config.vbus_detection = true; | 55 | |
| 56 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 57 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 58 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 59 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 60 | config.vbus_detection = false; | ||
| 61 | |||
| 50 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 62 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 51 | 63 | ||
| 52 | // Create embassy-usb Config | 64 | // Create embassy-usb Config |
| @@ -64,7 +76,6 @@ async fn main(_spawner: Spawner) { | |||
| 64 | 76 | ||
| 65 | // Create embassy-usb DeviceBuilder using the driver and config. | 77 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 66 | // It needs some buffers for building the descriptors. | 78 | // It needs some buffers for building the descriptors. |
| 67 | let mut device_descriptor = [0; 256]; | ||
| 68 | let mut config_descriptor = [0; 256]; | 79 | let mut config_descriptor = [0; 256]; |
| 69 | let mut bos_descriptor = [0; 256]; | 80 | let mut bos_descriptor = [0; 256]; |
| 70 | let mut control_buf = [0; 64]; | 81 | let mut control_buf = [0; 64]; |
| @@ -74,7 +85,6 @@ async fn main(_spawner: Spawner) { | |||
| 74 | let mut builder = Builder::new( | 85 | let mut builder = Builder::new( |
| 75 | driver, | 86 | driver, |
| 76 | config, | 87 | config, |
| 77 | &mut device_descriptor, | ||
| 78 | &mut config_descriptor, | 88 | &mut config_descriptor, |
| 79 | &mut bos_descriptor, | 89 | &mut bos_descriptor, |
| 80 | &mut [], // no msos descriptors | 90 | &mut [], // no msos descriptors |
diff --git a/examples/stm32h735/.cargo/config.toml b/examples/stm32h735/.cargo/config.toml new file mode 100644 index 000000000..95536c6a8 --- /dev/null +++ b/examples/stm32h735/.cargo/config.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [target.thumbv7em-none-eabihf] | ||
| 2 | runner = 'probe-rs run --chip STM32H735IGKx' | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml new file mode 100644 index 000000000..93e9575b6 --- /dev/null +++ b/examples/stm32h735/Cargo.toml | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32h735-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | ||
| 9 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 10 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | ||
| 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 14 | |||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | |||
| 18 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 19 | cortex-m-rt = "0.7.0" | ||
| 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 21 | heapless = { version = "0.8", default-features = false } | ||
| 22 | embedded-graphics = { version = "0.8.1" } | ||
| 23 | tinybmp = { version = "0.5" } | ||
| 24 | |||
| 25 | # cargo build/run | ||
| 26 | [profile.dev] | ||
| 27 | codegen-units = 1 | ||
| 28 | debug = 2 | ||
| 29 | debug-assertions = true # <- | ||
| 30 | incremental = false | ||
| 31 | opt-level = 3 # <- | ||
| 32 | overflow-checks = true # <- | ||
| 33 | |||
| 34 | # cargo test | ||
| 35 | [profile.test] | ||
| 36 | codegen-units = 1 | ||
| 37 | debug = 2 | ||
| 38 | debug-assertions = true # <- | ||
| 39 | incremental = false | ||
| 40 | opt-level = 3 # <- | ||
| 41 | overflow-checks = true # <- | ||
| 42 | |||
| 43 | # cargo build/run --release | ||
| 44 | [profile.release] | ||
| 45 | codegen-units = 1 | ||
| 46 | debug = 2 | ||
| 47 | debug-assertions = false # <- | ||
| 48 | incremental = false | ||
| 49 | lto = 'fat' | ||
| 50 | opt-level = 3 # <- | ||
| 51 | overflow-checks = false # <- | ||
| 52 | |||
| 53 | # cargo test --release | ||
| 54 | [profile.bench] | ||
| 55 | codegen-units = 1 | ||
| 56 | debug = 2 | ||
| 57 | debug-assertions = false # <- | ||
| 58 | incremental = false | ||
| 59 | lto = 'fat' | ||
| 60 | opt-level = 3 # <- | ||
| 61 | overflow-checks = false # <- | ||
diff --git a/examples/stm32h735/build.rs b/examples/stm32h735/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/stm32h735/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/stm32h735/memory.x b/examples/stm32h735/memory.x new file mode 100644 index 000000000..3a70d24d2 --- /dev/null +++ b/examples/stm32h735/memory.x | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x08000000, LENGTH = 1024K | ||
| 4 | RAM : ORIGIN = 0x24000000, LENGTH = 320K | ||
| 5 | } \ No newline at end of file | ||
diff --git a/examples/stm32h735/src/bin/ferris.bmp b/examples/stm32h735/src/bin/ferris.bmp new file mode 100644 index 000000000..7a222ab84 --- /dev/null +++ b/examples/stm32h735/src/bin/ferris.bmp | |||
| Binary files differ | |||
diff --git a/examples/stm32h735/src/bin/ltdc.rs b/examples/stm32h735/src/bin/ltdc.rs new file mode 100644 index 000000000..a36fdef2c --- /dev/null +++ b/examples/stm32h735/src/bin/ltdc.rs | |||
| @@ -0,0 +1,467 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![macro_use] | ||
| 4 | #![allow(static_mut_refs)] | ||
| 5 | |||
| 6 | /// This example demonstrates the LTDC lcd display peripheral and was tested to run on an stm32h735g-dk (embassy-stm32 feature "stm32h735ig" and probe-rs chip "STM32H735IGKx") | ||
| 7 | /// Even though the dev kit has 16MB of attached PSRAM this example uses the 320KB of internal AXIS RAM found on the mcu itself to make the example more standalone and portable. | ||
| 8 | /// For this reason a 256 color lookup table had to be used to keep the memory requirement down to an acceptable level. | ||
| 9 | /// The example bounces a ferris crab bitmap around the screen while blinking an led on another task | ||
| 10 | /// | ||
| 11 | use bouncy_box::BouncyBox; | ||
| 12 | use defmt::{info, unwrap}; | ||
| 13 | use embassy_executor::Spawner; | ||
| 14 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 15 | use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge}; | ||
| 16 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 17 | use embassy_time::{Duration, Timer}; | ||
| 18 | use embedded_graphics::draw_target::DrawTarget; | ||
| 19 | use embedded_graphics::geometry::{OriginDimensions, Point, Size}; | ||
| 20 | use embedded_graphics::image::Image; | ||
| 21 | use embedded_graphics::pixelcolor::raw::RawU24; | ||
| 22 | use embedded_graphics::pixelcolor::Rgb888; | ||
| 23 | use embedded_graphics::prelude::*; | ||
| 24 | use embedded_graphics::primitives::Rectangle; | ||
| 25 | use embedded_graphics::Pixel; | ||
| 26 | use heapless::{Entry, FnvIndexMap}; | ||
| 27 | use tinybmp::Bmp; | ||
| 28 | use {defmt_rtt as _, panic_probe as _}; | ||
| 29 | |||
| 30 | const DISPLAY_WIDTH: usize = 480; | ||
| 31 | const DISPLAY_HEIGHT: usize = 272; | ||
| 32 | const MY_TASK_POOL_SIZE: usize = 2; | ||
| 33 | |||
| 34 | // the following two display buffers consume 261120 bytes that just about fits into axis ram found on the mcu | ||
| 35 | pub static mut FB1: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT]; | ||
| 36 | pub static mut FB2: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT]; | ||
| 37 | |||
| 38 | bind_interrupts!(struct Irqs { | ||
| 39 | LTDC => ltdc::InterruptHandler<peripherals::LTDC>; | ||
| 40 | }); | ||
| 41 | |||
| 42 | const NUM_COLORS: usize = 256; | ||
| 43 | |||
| 44 | #[embassy_executor::main] | ||
| 45 | async fn main(spawner: Spawner) { | ||
| 46 | let p = rcc_setup::stm32h735g_init(); | ||
| 47 | |||
| 48 | // blink the led on another task | ||
| 49 | let led = Output::new(p.PC3, Level::High, Speed::Low); | ||
| 50 | unwrap!(spawner.spawn(led_task(led))); | ||
| 51 | |||
| 52 | // numbers from STMicroelectronics/STM32CubeH7 STM32H735G-DK C-based example | ||
| 53 | const RK043FN48H_HSYNC: u16 = 41; // Horizontal synchronization | ||
| 54 | const RK043FN48H_HBP: u16 = 13; // Horizontal back porch | ||
| 55 | const RK043FN48H_HFP: u16 = 32; // Horizontal front porch | ||
| 56 | const RK043FN48H_VSYNC: u16 = 10; // Vertical synchronization | ||
| 57 | const RK043FN48H_VBP: u16 = 2; // Vertical back porch | ||
| 58 | const RK043FN48H_VFP: u16 = 2; // Vertical front porch | ||
| 59 | |||
| 60 | let ltdc_config = LtdcConfiguration { | ||
| 61 | active_width: DISPLAY_WIDTH as _, | ||
| 62 | active_height: DISPLAY_HEIGHT as _, | ||
| 63 | h_back_porch: RK043FN48H_HBP - 11, // -11 from MX_LTDC_Init | ||
| 64 | h_front_porch: RK043FN48H_HFP, | ||
| 65 | v_back_porch: RK043FN48H_VBP, | ||
| 66 | v_front_porch: RK043FN48H_VFP, | ||
| 67 | h_sync: RK043FN48H_HSYNC, | ||
| 68 | v_sync: RK043FN48H_VSYNC, | ||
| 69 | h_sync_polarity: PolarityActive::ActiveLow, | ||
| 70 | v_sync_polarity: PolarityActive::ActiveLow, | ||
| 71 | data_enable_polarity: PolarityActive::ActiveHigh, | ||
| 72 | pixel_clock_polarity: PolarityEdge::FallingEdge, | ||
| 73 | }; | ||
| 74 | |||
| 75 | info!("init ltdc"); | ||
| 76 | let mut ltdc = Ltdc::new_with_pins( | ||
| 77 | p.LTDC, Irqs, p.PG7, p.PC6, p.PA4, p.PG14, p.PD0, p.PD6, p.PA8, p.PE12, p.PA3, p.PB8, p.PB9, p.PB1, p.PB0, | ||
| 78 | p.PA6, p.PE11, p.PH15, p.PH4, p.PC7, p.PD3, p.PE0, p.PH3, p.PH8, p.PH9, p.PH10, p.PH11, p.PE1, p.PE15, | ||
| 79 | ); | ||
| 80 | ltdc.init(<dc_config); | ||
| 81 | |||
| 82 | // we only need to draw on one layer for this example (not to be confused with the double buffer) | ||
| 83 | info!("enable bottom layer"); | ||
| 84 | let layer_config = LtdcLayerConfig { | ||
| 85 | pixel_format: ltdc::PixelFormat::L8, // 1 byte per pixel | ||
| 86 | layer: LtdcLayer::Layer1, | ||
| 87 | window_x0: 0, | ||
| 88 | window_x1: DISPLAY_WIDTH as _, | ||
| 89 | window_y0: 0, | ||
| 90 | window_y1: DISPLAY_HEIGHT as _, | ||
| 91 | }; | ||
| 92 | |||
| 93 | let ferris_bmp: Bmp<Rgb888> = Bmp::from_slice(include_bytes!("./ferris.bmp")).unwrap(); | ||
| 94 | let color_map = build_color_lookup_map(&ferris_bmp); | ||
| 95 | let clut = build_clut(&color_map); | ||
| 96 | |||
| 97 | // enable the bottom layer with a 256 color lookup table | ||
| 98 | ltdc.init_layer(&layer_config, Some(&clut)); | ||
| 99 | |||
| 100 | // Safety: the DoubleBuffer controls access to the statically allocated frame buffers | ||
| 101 | // and it is the only thing that mutates their content | ||
| 102 | let mut double_buffer = DoubleBuffer::new( | ||
| 103 | unsafe { FB1.as_mut() }, | ||
| 104 | unsafe { FB2.as_mut() }, | ||
| 105 | layer_config, | ||
| 106 | color_map, | ||
| 107 | ); | ||
| 108 | |||
| 109 | // this allows us to perform some simple animation for every frame | ||
| 110 | let mut bouncy_box = BouncyBox::new( | ||
| 111 | ferris_bmp.bounding_box(), | ||
| 112 | Rectangle::new(Point::zero(), Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32)), | ||
| 113 | 2, | ||
| 114 | ); | ||
| 115 | |||
| 116 | loop { | ||
| 117 | // cpu intensive drawing to the buffer that is NOT currently being copied to the LCD screen | ||
| 118 | double_buffer.clear(); | ||
| 119 | let position = bouncy_box.next_point(); | ||
| 120 | let ferris = Image::new(&ferris_bmp, position); | ||
| 121 | unwrap!(ferris.draw(&mut double_buffer)); | ||
| 122 | |||
| 123 | // perform async dma data transfer to the lcd screen | ||
| 124 | unwrap!(double_buffer.swap(&mut ltdc).await); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | /// builds the color look-up table from all unique colors found in the bitmap. This should be a 256 color indexed bitmap to work. | ||
| 129 | fn build_color_lookup_map(bmp: &Bmp<Rgb888>) -> FnvIndexMap<u32, u8, NUM_COLORS> { | ||
| 130 | let mut color_map: FnvIndexMap<u32, u8, NUM_COLORS> = heapless::FnvIndexMap::new(); | ||
| 131 | let mut counter: u8 = 0; | ||
| 132 | |||
| 133 | // add black to position 0 | ||
| 134 | color_map.insert(Rgb888::new(0, 0, 0).into_storage(), counter).unwrap(); | ||
| 135 | counter += 1; | ||
| 136 | |||
| 137 | for Pixel(_point, color) in bmp.pixels() { | ||
| 138 | let raw = color.into_storage(); | ||
| 139 | if let Entry::Vacant(v) = color_map.entry(raw) { | ||
| 140 | v.insert(counter).expect("more than 256 colors detected"); | ||
| 141 | counter += 1; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | color_map | ||
| 145 | } | ||
| 146 | |||
| 147 | /// builds the color look-up table from the color map provided | ||
| 148 | fn build_clut(color_map: &FnvIndexMap<u32, u8, NUM_COLORS>) -> [ltdc::RgbColor; NUM_COLORS] { | ||
| 149 | let mut clut = [ltdc::RgbColor::default(); NUM_COLORS]; | ||
| 150 | for (color, index) in color_map.iter() { | ||
| 151 | let color = Rgb888::from(RawU24::new(*color)); | ||
| 152 | clut[*index as usize] = ltdc::RgbColor { | ||
| 153 | red: color.r(), | ||
| 154 | green: color.g(), | ||
| 155 | blue: color.b(), | ||
| 156 | }; | ||
| 157 | } | ||
| 158 | |||
| 159 | clut | ||
| 160 | } | ||
| 161 | |||
| 162 | #[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)] | ||
| 163 | async fn led_task(mut led: Output<'static>) { | ||
| 164 | let mut counter = 0; | ||
| 165 | loop { | ||
| 166 | info!("blink: {}", counter); | ||
| 167 | counter += 1; | ||
| 168 | |||
| 169 | // on | ||
| 170 | led.set_low(); | ||
| 171 | Timer::after(Duration::from_millis(50)).await; | ||
| 172 | |||
| 173 | // off | ||
| 174 | led.set_high(); | ||
| 175 | Timer::after(Duration::from_millis(450)).await; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | pub type TargetPixelType = u8; | ||
| 180 | |||
| 181 | // A simple double buffer | ||
| 182 | pub struct DoubleBuffer { | ||
| 183 | buf0: &'static mut [TargetPixelType], | ||
| 184 | buf1: &'static mut [TargetPixelType], | ||
| 185 | is_buf0: bool, | ||
| 186 | layer_config: LtdcLayerConfig, | ||
| 187 | color_map: FnvIndexMap<u32, u8, NUM_COLORS>, | ||
| 188 | } | ||
| 189 | |||
| 190 | impl DoubleBuffer { | ||
| 191 | pub fn new( | ||
| 192 | buf0: &'static mut [TargetPixelType], | ||
| 193 | buf1: &'static mut [TargetPixelType], | ||
| 194 | layer_config: LtdcLayerConfig, | ||
| 195 | color_map: FnvIndexMap<u32, u8, NUM_COLORS>, | ||
| 196 | ) -> Self { | ||
| 197 | Self { | ||
| 198 | buf0, | ||
| 199 | buf1, | ||
| 200 | is_buf0: true, | ||
| 201 | layer_config, | ||
| 202 | color_map, | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | pub fn current(&mut self) -> (&FnvIndexMap<u32, u8, NUM_COLORS>, &mut [TargetPixelType]) { | ||
| 207 | if self.is_buf0 { | ||
| 208 | (&self.color_map, self.buf0) | ||
| 209 | } else { | ||
| 210 | (&self.color_map, self.buf1) | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | pub async fn swap<T: ltdc::Instance>(&mut self, ltdc: &mut Ltdc<'_, T>) -> Result<(), ltdc::Error> { | ||
| 215 | let (_, buf) = self.current(); | ||
| 216 | let frame_buffer = buf.as_ptr(); | ||
| 217 | self.is_buf0 = !self.is_buf0; | ||
| 218 | ltdc.set_buffer(self.layer_config.layer, frame_buffer as *const _).await | ||
| 219 | } | ||
| 220 | |||
| 221 | /// Clears the buffer | ||
| 222 | pub fn clear(&mut self) { | ||
| 223 | let (color_map, buf) = self.current(); | ||
| 224 | let black = Rgb888::new(0, 0, 0).into_storage(); | ||
| 225 | let color_index = color_map.get(&black).expect("no black found in the color map"); | ||
| 226 | |||
| 227 | for a in buf.iter_mut() { | ||
| 228 | *a = *color_index; // solid black | ||
| 229 | } | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | // Implement DrawTarget for | ||
| 234 | impl DrawTarget for DoubleBuffer { | ||
| 235 | type Color = Rgb888; | ||
| 236 | type Error = (); | ||
| 237 | |||
| 238 | /// Draw a pixel | ||
| 239 | fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error> | ||
| 240 | where | ||
| 241 | I: IntoIterator<Item = Pixel<Self::Color>>, | ||
| 242 | { | ||
| 243 | let size = self.size(); | ||
| 244 | let width = size.width as i32; | ||
| 245 | let height = size.height as i32; | ||
| 246 | let (color_map, buf) = self.current(); | ||
| 247 | |||
| 248 | for pixel in pixels { | ||
| 249 | let Pixel(point, color) = pixel; | ||
| 250 | |||
| 251 | if point.x >= 0 && point.y >= 0 && point.x < width && point.y < height { | ||
| 252 | let index = point.y * width + point.x; | ||
| 253 | let raw_color = color.into_storage(); | ||
| 254 | |||
| 255 | match color_map.get(&raw_color) { | ||
| 256 | Some(x) => { | ||
| 257 | buf[index as usize] = *x; | ||
| 258 | } | ||
| 259 | None => panic!("color not found in color map: {}", raw_color), | ||
| 260 | }; | ||
| 261 | } else { | ||
| 262 | // Ignore invalid points | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | Ok(()) | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | impl OriginDimensions for DoubleBuffer { | ||
| 271 | /// Return the size of the display | ||
| 272 | fn size(&self) -> Size { | ||
| 273 | Size::new( | ||
| 274 | (self.layer_config.window_x1 - self.layer_config.window_x0) as _, | ||
| 275 | (self.layer_config.window_y1 - self.layer_config.window_y0) as _, | ||
| 276 | ) | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | mod rcc_setup { | ||
| 281 | |||
| 282 | use embassy_stm32::rcc::{Hse, HseMode, *}; | ||
| 283 | use embassy_stm32::time::Hertz; | ||
| 284 | use embassy_stm32::{Config, Peripherals}; | ||
| 285 | |||
| 286 | /// Sets up clocks for the stm32h735g mcu | ||
| 287 | /// change this if you plan to use a different microcontroller | ||
| 288 | pub fn stm32h735g_init() -> Peripherals { | ||
| 289 | /* | ||
| 290 | https://github.com/STMicroelectronics/STM32CubeH7/blob/master/Projects/STM32H735G-DK/Examples/GPIO/GPIO_EXTI/Src/main.c | ||
| 291 | @brief System Clock Configuration | ||
| 292 | The system Clock is configured as follow : | ||
| 293 | System Clock source = PLL (HSE) | ||
| 294 | SYSCLK(Hz) = 520000000 (CPU Clock) | ||
| 295 | HCLK(Hz) = 260000000 (AXI and AHBs Clock) | ||
| 296 | AHB Prescaler = 2 | ||
| 297 | D1 APB3 Prescaler = 2 (APB3 Clock 130MHz) | ||
| 298 | D2 APB1 Prescaler = 2 (APB1 Clock 130MHz) | ||
| 299 | D2 APB2 Prescaler = 2 (APB2 Clock 130MHz) | ||
| 300 | D3 APB4 Prescaler = 2 (APB4 Clock 130MHz) | ||
| 301 | HSE Frequency(Hz) = 25000000 | ||
| 302 | PLL_M = 5 | ||
| 303 | PLL_N = 104 | ||
| 304 | PLL_P = 1 | ||
| 305 | PLL_Q = 4 | ||
| 306 | PLL_R = 2 | ||
| 307 | VDD(V) = 3.3 | ||
| 308 | Flash Latency(WS) = 3 | ||
| 309 | */ | ||
| 310 | |||
| 311 | // setup power and clocks for an stm32h735g-dk run from an external 25 Mhz external oscillator | ||
| 312 | let mut config = Config::default(); | ||
| 313 | config.rcc.hse = Some(Hse { | ||
| 314 | freq: Hertz::mhz(25), | ||
| 315 | mode: HseMode::Oscillator, | ||
| 316 | }); | ||
| 317 | config.rcc.hsi = None; | ||
| 318 | config.rcc.csi = false; | ||
| 319 | config.rcc.pll1 = Some(Pll { | ||
| 320 | source: PllSource::HSE, | ||
| 321 | prediv: PllPreDiv::DIV5, // PLL_M | ||
| 322 | mul: PllMul::MUL104, // PLL_N | ||
| 323 | divp: Some(PllDiv::DIV1), | ||
| 324 | divq: Some(PllDiv::DIV4), | ||
| 325 | divr: Some(PllDiv::DIV2), | ||
| 326 | }); | ||
| 327 | // numbers adapted from Drivers/BSP/STM32H735G-DK/stm32h735g_discovery_ospi.c | ||
| 328 | // MX_OSPI_ClockConfig | ||
| 329 | config.rcc.pll2 = Some(Pll { | ||
| 330 | source: PllSource::HSE, | ||
| 331 | prediv: PllPreDiv::DIV5, // PLL_M | ||
| 332 | mul: PllMul::MUL80, // PLL_N | ||
| 333 | divp: Some(PllDiv::DIV5), | ||
| 334 | divq: Some(PllDiv::DIV2), | ||
| 335 | divr: Some(PllDiv::DIV2), | ||
| 336 | }); | ||
| 337 | // numbers adapted from Drivers/BSP/STM32H735G-DK/stm32h735g_discovery_lcd.c | ||
| 338 | // MX_LTDC_ClockConfig | ||
| 339 | config.rcc.pll3 = Some(Pll { | ||
| 340 | source: PllSource::HSE, | ||
| 341 | prediv: PllPreDiv::DIV5, // PLL_M | ||
| 342 | mul: PllMul::MUL160, // PLL_N | ||
| 343 | divp: Some(PllDiv::DIV2), | ||
| 344 | divq: Some(PllDiv::DIV2), | ||
| 345 | divr: Some(PllDiv::DIV83), | ||
| 346 | }); | ||
| 347 | config.rcc.voltage_scale = VoltageScale::Scale0; | ||
| 348 | config.rcc.supply_config = SupplyConfig::DirectSMPS; | ||
| 349 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 350 | config.rcc.ahb_pre = AHBPrescaler::DIV2; | ||
| 351 | config.rcc.apb1_pre = APBPrescaler::DIV2; | ||
| 352 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 353 | config.rcc.apb3_pre = APBPrescaler::DIV2; | ||
| 354 | config.rcc.apb4_pre = APBPrescaler::DIV2; | ||
| 355 | embassy_stm32::init(config) | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | mod bouncy_box { | ||
| 360 | use embedded_graphics::geometry::Point; | ||
| 361 | use embedded_graphics::primitives::Rectangle; | ||
| 362 | |||
| 363 | enum Direction { | ||
| 364 | DownLeft, | ||
| 365 | DownRight, | ||
| 366 | UpLeft, | ||
| 367 | UpRight, | ||
| 368 | } | ||
| 369 | |||
| 370 | pub struct BouncyBox { | ||
| 371 | direction: Direction, | ||
| 372 | child_rect: Rectangle, | ||
| 373 | parent_rect: Rectangle, | ||
| 374 | current_point: Point, | ||
| 375 | move_by: usize, | ||
| 376 | } | ||
| 377 | |||
| 378 | // This calculates the coordinates of a chile rectangle bounced around inside a parent bounded box | ||
| 379 | impl BouncyBox { | ||
| 380 | pub fn new(child_rect: Rectangle, parent_rect: Rectangle, move_by: usize) -> Self { | ||
| 381 | let center_box = parent_rect.center(); | ||
| 382 | let center_img = child_rect.center(); | ||
| 383 | let current_point = Point::new(center_box.x - center_img.x / 2, center_box.y - center_img.y / 2); | ||
| 384 | Self { | ||
| 385 | direction: Direction::DownRight, | ||
| 386 | child_rect, | ||
| 387 | parent_rect, | ||
| 388 | current_point, | ||
| 389 | move_by, | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | pub fn next_point(&mut self) -> Point { | ||
| 394 | let direction = &self.direction; | ||
| 395 | let img_height = self.child_rect.size.height as i32; | ||
| 396 | let box_height = self.parent_rect.size.height as i32; | ||
| 397 | let img_width = self.child_rect.size.width as i32; | ||
| 398 | let box_width = self.parent_rect.size.width as i32; | ||
| 399 | let move_by = self.move_by as i32; | ||
| 400 | |||
| 401 | match direction { | ||
| 402 | Direction::DownLeft => { | ||
| 403 | self.current_point.x -= move_by; | ||
| 404 | self.current_point.y += move_by; | ||
| 405 | |||
| 406 | let x_out_of_bounds = self.current_point.x < 0; | ||
| 407 | let y_out_of_bounds = (self.current_point.y + img_height) > box_height; | ||
| 408 | |||
| 409 | if x_out_of_bounds && y_out_of_bounds { | ||
| 410 | self.direction = Direction::UpRight | ||
| 411 | } else if x_out_of_bounds && !y_out_of_bounds { | ||
| 412 | self.direction = Direction::DownRight | ||
| 413 | } else if !x_out_of_bounds && y_out_of_bounds { | ||
| 414 | self.direction = Direction::UpLeft | ||
| 415 | } | ||
| 416 | } | ||
| 417 | Direction::DownRight => { | ||
| 418 | self.current_point.x += move_by; | ||
| 419 | self.current_point.y += move_by; | ||
| 420 | |||
| 421 | let x_out_of_bounds = (self.current_point.x + img_width) > box_width; | ||
| 422 | let y_out_of_bounds = (self.current_point.y + img_height) > box_height; | ||
| 423 | |||
| 424 | if x_out_of_bounds && y_out_of_bounds { | ||
| 425 | self.direction = Direction::UpLeft | ||
| 426 | } else if x_out_of_bounds && !y_out_of_bounds { | ||
| 427 | self.direction = Direction::DownLeft | ||
| 428 | } else if !x_out_of_bounds && y_out_of_bounds { | ||
| 429 | self.direction = Direction::UpRight | ||
| 430 | } | ||
| 431 | } | ||
| 432 | Direction::UpLeft => { | ||
| 433 | self.current_point.x -= move_by; | ||
| 434 | self.current_point.y -= move_by; | ||
| 435 | |||
| 436 | let x_out_of_bounds = self.current_point.x < 0; | ||
| 437 | let y_out_of_bounds = self.current_point.y < 0; | ||
| 438 | |||
| 439 | if x_out_of_bounds && y_out_of_bounds { | ||
| 440 | self.direction = Direction::DownRight | ||
| 441 | } else if x_out_of_bounds && !y_out_of_bounds { | ||
| 442 | self.direction = Direction::UpRight | ||
| 443 | } else if !x_out_of_bounds && y_out_of_bounds { | ||
| 444 | self.direction = Direction::DownLeft | ||
| 445 | } | ||
| 446 | } | ||
| 447 | Direction::UpRight => { | ||
| 448 | self.current_point.x += move_by; | ||
| 449 | self.current_point.y -= move_by; | ||
| 450 | |||
| 451 | let x_out_of_bounds = (self.current_point.x + img_width) > box_width; | ||
| 452 | let y_out_of_bounds = self.current_point.y < 0; | ||
| 453 | |||
| 454 | if x_out_of_bounds && y_out_of_bounds { | ||
| 455 | self.direction = Direction::DownLeft | ||
| 456 | } else if x_out_of_bounds && !y_out_of_bounds { | ||
| 457 | self.direction = Direction::UpLeft | ||
| 458 | } else if !x_out_of_bounds && y_out_of_bounds { | ||
| 459 | self.direction = Direction::DownRight | ||
| 460 | } | ||
| 461 | } | ||
| 462 | } | ||
| 463 | |||
| 464 | self.current_point | ||
| 465 | } | ||
| 466 | } | ||
| 467 | } | ||
diff --git a/examples/stm32h755cm4/.cargo/config.toml b/examples/stm32h755cm4/.cargo/config.toml new file mode 100644 index 000000000..193e6bbc3 --- /dev/null +++ b/examples/stm32h755cm4/.cargo/config.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [target.thumbv7em-none-eabihf] | ||
| 2 | runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace' | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml new file mode 100644 index 000000000..7a42fbdaa --- /dev/null +++ b/examples/stm32h755cm4/Cargo.toml | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32h755cm4-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | # Change stm32h755zi-cm4 to your chip name, if necessary. | ||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | ||
| 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | ||
| 12 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 13 | embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | ||
| 15 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | ||
| 16 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 17 | |||
| 18 | defmt = "0.3" | ||
| 19 | defmt-rtt = "0.4" | ||
| 20 | |||
| 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 22 | cortex-m-rt = "0.7.0" | ||
| 23 | embedded-hal = "0.2.6" | ||
| 24 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 25 | embedded-hal-async = { version = "1.0" } | ||
| 26 | embedded-nal-async = { version = "0.7.1" } | ||
| 27 | embedded-io-async = { version = "0.6.1" } | ||
| 28 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 29 | heapless = { version = "0.8", default-features = false } | ||
| 30 | rand_core = "0.6.3" | ||
| 31 | critical-section = "1.1" | ||
| 32 | micromath = "2.0.0" | ||
| 33 | stm32-fmc = "0.3.0" | ||
| 34 | embedded-storage = "0.3.1" | ||
| 35 | static_cell = "2" | ||
| 36 | chrono = { version = "^0.4", default-features = false } | ||
| 37 | grounded = "0.2.0" | ||
| 38 | |||
| 39 | # cargo build/run | ||
| 40 | [profile.dev] | ||
| 41 | codegen-units = 1 | ||
| 42 | debug = 2 | ||
| 43 | debug-assertions = true # <- | ||
| 44 | incremental = false | ||
| 45 | opt-level = 3 # <- | ||
| 46 | overflow-checks = true # <- | ||
| 47 | |||
| 48 | # cargo test | ||
| 49 | [profile.test] | ||
| 50 | codegen-units = 1 | ||
| 51 | debug = 2 | ||
| 52 | debug-assertions = true # <- | ||
| 53 | incremental = false | ||
| 54 | opt-level = 3 # <- | ||
| 55 | overflow-checks = true # <- | ||
| 56 | |||
| 57 | # cargo build/run --release | ||
| 58 | [profile.release] | ||
| 59 | codegen-units = 1 | ||
| 60 | debug = 2 | ||
| 61 | debug-assertions = false # <- | ||
| 62 | incremental = false | ||
| 63 | lto = 'fat' | ||
| 64 | opt-level = 3 # <- | ||
| 65 | overflow-checks = false # <- | ||
| 66 | |||
| 67 | # cargo test --release | ||
| 68 | [profile.bench] | ||
| 69 | codegen-units = 1 | ||
| 70 | debug = 2 | ||
| 71 | debug-assertions = false # <- | ||
| 72 | incremental = false | ||
| 73 | lto = 'fat' | ||
| 74 | opt-level = 3 # <- | ||
| 75 | 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 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/stm32h755cm4/memory.x b/examples/stm32h755cm4/memory.x new file mode 100644 index 000000000..7d60354e3 --- /dev/null +++ b/examples/stm32h755cm4/memory.x | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x08100000, LENGTH = 1024K /* BANK_2 */ | ||
| 4 | RAM : ORIGIN = 0x10000000, LENGTH = 128K /* SRAM1 */ | ||
| 5 | RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */ | ||
| 6 | } | ||
| 7 | |||
| 8 | SECTIONS | ||
| 9 | { | ||
| 10 | .ram_d3 : | ||
| 11 | { | ||
| 12 | *(.ram_d3.shared_data) | ||
| 13 | *(.ram_d3) | ||
| 14 | } > RAM_D3 | ||
| 15 | } \ 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..b5c547839 --- /dev/null +++ b/examples/stm32h755cm4/src/bin/blinky.rs | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 9 | use embassy_stm32::SharedData; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[link_section = ".ram_d3.shared_data"] | ||
| 14 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let p = embassy_stm32::init_secondary(&SHARED_DATA); | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | let mut led = Output::new(p.PE1, Level::High, Speed::Low); | ||
| 22 | |||
| 23 | loop { | ||
| 24 | info!("high"); | ||
| 25 | led.set_high(); | ||
| 26 | Timer::after_millis(250).await; | ||
| 27 | |||
| 28 | info!("low"); | ||
| 29 | led.set_low(); | ||
| 30 | Timer::after_millis(250).await; | ||
| 31 | } | ||
| 32 | } | ||
diff --git a/examples/stm32h755cm7/.cargo/config.toml b/examples/stm32h755cm7/.cargo/config.toml new file mode 100644 index 000000000..193e6bbc3 --- /dev/null +++ b/examples/stm32h755cm7/.cargo/config.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [target.thumbv7em-none-eabihf] | ||
| 2 | runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace' | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml new file mode 100644 index 000000000..4f0f69c3f --- /dev/null +++ b/examples/stm32h755cm7/Cargo.toml | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32h755cm7-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | # Change stm32h743bi to your chip name, if necessary. | ||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } | ||
| 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | ||
| 12 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 13 | embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | ||
| 15 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | ||
| 16 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 17 | |||
| 18 | defmt = "0.3" | ||
| 19 | defmt-rtt = "0.4" | ||
| 20 | |||
| 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 22 | cortex-m-rt = "0.7.0" | ||
| 23 | embedded-hal = "0.2.6" | ||
| 24 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 25 | embedded-hal-async = { version = "1.0" } | ||
| 26 | embedded-nal-async = { version = "0.7.1" } | ||
| 27 | embedded-io-async = { version = "0.6.1" } | ||
| 28 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 29 | heapless = { version = "0.8", default-features = false } | ||
| 30 | rand_core = "0.6.3" | ||
| 31 | critical-section = "1.1" | ||
| 32 | micromath = "2.0.0" | ||
| 33 | stm32-fmc = "0.3.0" | ||
| 34 | embedded-storage = "0.3.1" | ||
| 35 | static_cell = "2" | ||
| 36 | chrono = { version = "^0.4", default-features = false } | ||
| 37 | grounded = "0.2.0" | ||
| 38 | |||
| 39 | # cargo build/run | ||
| 40 | [profile.dev] | ||
| 41 | codegen-units = 1 | ||
| 42 | debug = 2 | ||
| 43 | debug-assertions = true # <- | ||
| 44 | incremental = false | ||
| 45 | opt-level = 3 # <- | ||
| 46 | overflow-checks = true # <- | ||
| 47 | |||
| 48 | # cargo test | ||
| 49 | [profile.test] | ||
| 50 | codegen-units = 1 | ||
| 51 | debug = 2 | ||
| 52 | debug-assertions = true # <- | ||
| 53 | incremental = false | ||
| 54 | opt-level = 3 # <- | ||
| 55 | overflow-checks = true # <- | ||
| 56 | |||
| 57 | # cargo build/run --release | ||
| 58 | [profile.release] | ||
| 59 | codegen-units = 1 | ||
| 60 | debug = 2 | ||
| 61 | debug-assertions = false # <- | ||
| 62 | incremental = false | ||
| 63 | lto = 'fat' | ||
| 64 | opt-level = 3 # <- | ||
| 65 | overflow-checks = false # <- | ||
| 66 | |||
| 67 | # cargo test --release | ||
| 68 | [profile.bench] | ||
| 69 | codegen-units = 1 | ||
| 70 | debug = 2 | ||
| 71 | debug-assertions = false # <- | ||
| 72 | incremental = false | ||
| 73 | lto = 'fat' | ||
| 74 | opt-level = 3 # <- | ||
| 75 | 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 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/stm32h755cm7/memory.x b/examples/stm32h755cm7/memory.x new file mode 100644 index 000000000..ef884796a --- /dev/null +++ b/examples/stm32h755cm7/memory.x | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x08000000, LENGTH = 1024K /* BANK_1 */ | ||
| 4 | RAM : ORIGIN = 0x24000000, LENGTH = 512K /* AXIRAM */ | ||
| 5 | RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */ | ||
| 6 | } | ||
| 7 | |||
| 8 | SECTIONS | ||
| 9 | { | ||
| 10 | .ram_d3 : | ||
| 11 | { | ||
| 12 | *(.ram_d3.shared_data) | ||
| 13 | *(.ram_d3) | ||
| 14 | } > RAM_D3 | ||
| 15 | } \ 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..94d2226c0 --- /dev/null +++ b/examples/stm32h755cm7/src/bin/blinky.rs | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 9 | use embassy_stm32::SharedData; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[link_section = ".ram_d3.shared_data"] | ||
| 14 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = embassy_stm32::Config::default(); | ||
| 19 | { | ||
| 20 | use embassy_stm32::rcc::*; | ||
| 21 | config.rcc.hsi = Some(HSIPrescaler::DIV1); | ||
| 22 | config.rcc.csi = true; | ||
| 23 | config.rcc.pll1 = Some(Pll { | ||
| 24 | source: PllSource::HSI, | ||
| 25 | prediv: PllPreDiv::DIV4, | ||
| 26 | mul: PllMul::MUL50, | ||
| 27 | divp: Some(PllDiv::DIV2), | ||
| 28 | divq: Some(PllDiv::DIV8), // 100mhz | ||
| 29 | divr: None, | ||
| 30 | }); | ||
| 31 | config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz | ||
| 32 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz | ||
| 33 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 34 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 35 | config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 36 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz | ||
| 37 | config.rcc.voltage_scale = VoltageScale::Scale1; | ||
| 38 | config.rcc.supply_config = SupplyConfig::DirectSMPS; | ||
| 39 | } | ||
| 40 | let p = embassy_stm32::init_primary(config, &SHARED_DATA); | ||
| 41 | info!("Hello World!"); | ||
| 42 | |||
| 43 | let mut led = Output::new(p.PB14, Level::High, Speed::Low); | ||
| 44 | |||
| 45 | loop { | ||
| 46 | info!("high"); | ||
| 47 | led.set_high(); | ||
| 48 | Timer::after_millis(500).await; | ||
| 49 | |||
| 50 | info!("low"); | ||
| 51 | led.set_low(); | ||
| 52 | Timer::after_millis(500).await; | ||
| 53 | } | ||
| 54 | } | ||
diff --git a/examples/stm32h7rs/.cargo/config.toml b/examples/stm32h7rs/.cargo/config.toml new file mode 100644 index 000000000..44dbda94f --- /dev/null +++ b/examples/stm32h7rs/.cargo/config.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [target.thumbv7em-none-eabihf] | ||
| 2 | runner = 'probe-rs run --chip STM32H7S3L8Hx' | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml new file mode 100644 index 000000000..f97dfd722 --- /dev/null +++ b/examples/stm32h7rs/Cargo.toml | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32h7rs-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | # Change stm32h743bi to your chip name, if necessary. | ||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | ||
| 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | ||
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | ||
| 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 16 | |||
| 17 | defmt = "0.3" | ||
| 18 | defmt-rtt = "0.4" | ||
| 19 | |||
| 20 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 21 | cortex-m-rt = "0.7.0" | ||
| 22 | embedded-hal = "0.2.6" | ||
| 23 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 24 | embedded-hal-async = { version = "1.0" } | ||
| 25 | embedded-nal-async = { version = "0.7.1" } | ||
| 26 | embedded-io-async = { version = "0.6.1" } | ||
| 27 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 28 | heapless = { version = "0.8", default-features = false } | ||
| 29 | rand_core = "0.6.3" | ||
| 30 | critical-section = "1.1" | ||
| 31 | micromath = "2.0.0" | ||
| 32 | stm32-fmc = "0.3.0" | ||
| 33 | embedded-storage = "0.3.1" | ||
| 34 | static_cell = "2" | ||
| 35 | chrono = { version = "^0.4", default-features = false } | ||
| 36 | |||
| 37 | # cargo build/run | ||
| 38 | [profile.dev] | ||
| 39 | codegen-units = 1 | ||
| 40 | debug = 2 | ||
| 41 | debug-assertions = true # <- | ||
| 42 | incremental = false | ||
| 43 | opt-level = 3 # <- | ||
| 44 | overflow-checks = true # <- | ||
| 45 | |||
| 46 | # cargo test | ||
| 47 | [profile.test] | ||
| 48 | codegen-units = 1 | ||
| 49 | debug = 2 | ||
| 50 | debug-assertions = true # <- | ||
| 51 | incremental = false | ||
| 52 | opt-level = 3 # <- | ||
| 53 | overflow-checks = true # <- | ||
| 54 | |||
| 55 | # cargo build/run --release | ||
| 56 | [profile.release] | ||
| 57 | codegen-units = 1 | ||
| 58 | debug = 2 | ||
| 59 | debug-assertions = false # <- | ||
| 60 | incremental = false | ||
| 61 | lto = 'fat' | ||
| 62 | opt-level = 3 # <- | ||
| 63 | overflow-checks = false # <- | ||
| 64 | |||
| 65 | # cargo test --release | ||
| 66 | [profile.bench] | ||
| 67 | codegen-units = 1 | ||
| 68 | debug = 2 | ||
| 69 | debug-assertions = false # <- | ||
| 70 | incremental = false | ||
| 71 | lto = 'fat' | ||
| 72 | opt-level = 3 # <- | ||
| 73 | overflow-checks = false # <- | ||
diff --git a/examples/stm32h7rs/build.rs b/examples/stm32h7rs/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32h7rs/build.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | fn main() { | ||
| 2 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 3 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 4 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 5 | } | ||
diff --git a/examples/stm32h7rs/src/bin/blinky.rs b/examples/stm32h7rs/src/bin/blinky.rs new file mode 100644 index 000000000..137c585b7 --- /dev/null +++ b/examples/stm32h7rs/src/bin/blinky.rs | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::Config; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let mut config = Config::default(); | ||
| 15 | { | ||
| 16 | use embassy_stm32::rcc::*; | ||
| 17 | config.rcc.hse = Some(Hse { | ||
| 18 | freq: Hertz(24_000_000), | ||
| 19 | mode: HseMode::Oscillator, | ||
| 20 | }); | ||
| 21 | config.rcc.pll1 = Some(Pll { | ||
| 22 | source: PllSource::HSE, | ||
| 23 | prediv: PllPreDiv::DIV3, | ||
| 24 | mul: PllMul::MUL150, | ||
| 25 | divp: Some(PllDiv::DIV2), | ||
| 26 | divq: None, | ||
| 27 | divr: None, | ||
| 28 | }); | ||
| 29 | config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz | ||
| 30 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz | ||
| 31 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 32 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 33 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 34 | config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 35 | config.rcc.voltage_scale = VoltageScale::HIGH; | ||
| 36 | } | ||
| 37 | let p = embassy_stm32::init(config); | ||
| 38 | info!("Hello World!"); | ||
| 39 | |||
| 40 | let mut led = Output::new(p.PD10, Level::High, Speed::Low); | ||
| 41 | |||
| 42 | loop { | ||
| 43 | info!("high"); | ||
| 44 | led.set_high(); | ||
| 45 | Timer::after_millis(500).await; | ||
| 46 | |||
| 47 | info!("low"); | ||
| 48 | led.set_low(); | ||
| 49 | Timer::after_millis(500).await; | ||
| 50 | } | ||
| 51 | } | ||
diff --git a/examples/stm32h7rs/src/bin/button_exti.rs b/examples/stm32h7rs/src/bin/button_exti.rs new file mode 100644 index 000000000..34a08bbc6 --- /dev/null +++ b/examples/stm32h7rs/src/bin/button_exti.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::exti::ExtiInput; | ||
| 7 | use embassy_stm32::gpio::Pull; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); | ||
| 16 | |||
| 17 | info!("Press the USER button..."); | ||
| 18 | |||
| 19 | loop { | ||
| 20 | button.wait_for_falling_edge().await; | ||
| 21 | info!("Pressed!"); | ||
| 22 | button.wait_for_rising_edge().await; | ||
| 23 | info!("Released!"); | ||
| 24 | } | ||
| 25 | } | ||
diff --git a/examples/stm32h7rs/src/bin/can.rs b/examples/stm32h7rs/src/bin/can.rs new file mode 100644 index 000000000..0af11ef3e --- /dev/null +++ b/examples/stm32h7rs/src/bin/can.rs | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::peripherals::*; | ||
| 7 | use embassy_stm32::{bind_interrupts, can, rcc, Config}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | ||
| 13 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = Config::default(); | ||
| 19 | config.rcc.hse = Some(rcc::Hse { | ||
| 20 | freq: embassy_stm32::time::Hertz(25_000_000), | ||
| 21 | mode: rcc::HseMode::Oscillator, | ||
| 22 | }); | ||
| 23 | config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | ||
| 24 | |||
| 25 | let peripherals = embassy_stm32::init(config); | ||
| 26 | |||
| 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||
| 28 | |||
| 29 | // 250k bps | ||
| 30 | can.set_bitrate(250_000); | ||
| 31 | |||
| 32 | //let mut can = can.into_internal_loopback_mode(); | ||
| 33 | let mut can = can.into_normal_mode(); | ||
| 34 | |||
| 35 | info!("CAN Configured"); | ||
| 36 | |||
| 37 | let mut i = 0; | ||
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | ||
| 39 | |||
| 40 | loop { | ||
| 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 42 | info!("Writing frame"); | ||
| 43 | _ = can.write(&frame).await; | ||
| 44 | |||
| 45 | match can.read().await { | ||
| 46 | Ok(envelope) => { | ||
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 48 | let delta = (ts - last_read_ts).as_millis(); | ||
| 49 | last_read_ts = ts; | ||
| 50 | info!( | ||
| 51 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 52 | rx_frame.data()[0], | ||
| 53 | rx_frame.data()[1], | ||
| 54 | rx_frame.data()[2], | ||
| 55 | rx_frame.data()[3], | ||
| 56 | delta, | ||
| 57 | ) | ||
| 58 | } | ||
| 59 | Err(_err) => error!("Error in frame"), | ||
| 60 | } | ||
| 61 | |||
| 62 | Timer::after_millis(250).await; | ||
| 63 | |||
| 64 | i += 1; | ||
| 65 | if i > 3 { | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | let (mut tx, mut rx, _props) = can.split(); | ||
| 71 | // With split | ||
| 72 | loop { | ||
| 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 74 | info!("Writing frame"); | ||
| 75 | _ = tx.write(&frame).await; | ||
| 76 | |||
| 77 | match rx.read().await { | ||
| 78 | Ok(envelope) => { | ||
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 80 | let delta = (ts - last_read_ts).as_millis(); | ||
| 81 | last_read_ts = ts; | ||
| 82 | info!( | ||
| 83 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 84 | rx_frame.data()[0], | ||
| 85 | rx_frame.data()[1], | ||
| 86 | rx_frame.data()[2], | ||
| 87 | rx_frame.data()[3], | ||
| 88 | delta, | ||
| 89 | ) | ||
| 90 | } | ||
| 91 | Err(_err) => error!("Error in frame"), | ||
| 92 | } | ||
| 93 | |||
| 94 | Timer::after_millis(250).await; | ||
| 95 | |||
| 96 | i = i.wrapping_add(1); | ||
| 97 | } | ||
| 98 | } | ||
diff --git a/examples/stm32h7rs/src/bin/i2c.rs b/examples/stm32h7rs/src/bin/i2c.rs new file mode 100644 index 000000000..31e83cbb5 --- /dev/null +++ b/examples/stm32h7rs/src/bin/i2c.rs | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::i2c::{Error, I2c}; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | const ADDRESS: u8 = 0x5F; | ||
| 12 | const WHOAMI: u8 = 0x0F; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||
| 16 | I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) { | ||
| 21 | info!("Hello world!"); | ||
| 22 | let p = embassy_stm32::init(Default::default()); | ||
| 23 | |||
| 24 | let mut i2c = I2c::new( | ||
| 25 | p.I2C2, | ||
| 26 | p.PB10, | ||
| 27 | p.PB11, | ||
| 28 | Irqs, | ||
| 29 | p.GPDMA1_CH4, | ||
| 30 | p.GPDMA1_CH5, | ||
| 31 | Hertz(100_000), | ||
| 32 | Default::default(), | ||
| 33 | ); | ||
| 34 | |||
| 35 | let mut data = [0u8; 1]; | ||
| 36 | |||
| 37 | match i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { | ||
| 38 | Ok(()) => info!("Whoami: {}", data[0]), | ||
| 39 | Err(Error::Timeout) => error!("Operation timed out"), | ||
| 40 | Err(e) => error!("I2c Error: {:?}", e), | ||
| 41 | } | ||
| 42 | } | ||
diff --git a/examples/stm32h7rs/src/bin/mco.rs b/examples/stm32h7rs/src/bin/mco.rs new file mode 100644 index 000000000..a6ee27625 --- /dev/null +++ b/examples/stm32h7rs/src/bin/mco.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 7 | use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner) { | ||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | info!("Hello World!"); | ||
| 15 | |||
| 16 | let mut led = Output::new(p.PB14, Level::High, Speed::Low); | ||
| 17 | |||
| 18 | let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); | ||
| 19 | |||
| 20 | loop { | ||
| 21 | info!("high"); | ||
| 22 | led.set_high(); | ||
| 23 | Timer::after_millis(500).await; | ||
| 24 | |||
| 25 | info!("low"); | ||
| 26 | led.set_low(); | ||
| 27 | Timer::after_millis(500).await; | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/examples/stm32h7rs/src/bin/multiprio.rs b/examples/stm32h7rs/src/bin/multiprio.rs new file mode 100644 index 000000000..b4620888f --- /dev/null +++ b/examples/stm32h7rs/src/bin/multiprio.rs | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | //! This example showcases how to create multiple Executor instances to run tasks at | ||
| 2 | //! different priority levels. | ||
| 3 | //! | ||
| 4 | //! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling | ||
| 5 | //! there's work in the queue, and `wfe` for waiting for work. | ||
| 6 | //! | ||
| 7 | //! Medium and high priority executors run in two interrupts with different priorities. | ||
| 8 | //! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since | ||
| 9 | //! when there's work the interrupt will trigger and run the executor. | ||
| 10 | //! | ||
| 11 | //! Sample output below. Note that high priority ticks can interrupt everything else, and | ||
| 12 | //! medium priority computations can interrupt low priority computations, making them to appear | ||
| 13 | //! to take significantly longer time. | ||
| 14 | //! | ||
| 15 | //! ```not_rust | ||
| 16 | //! [med] Starting long computation | ||
| 17 | //! [med] done in 992 ms | ||
| 18 | //! [high] tick! | ||
| 19 | //! [low] Starting long computation | ||
| 20 | //! [med] Starting long computation | ||
| 21 | //! [high] tick! | ||
| 22 | //! [high] tick! | ||
| 23 | //! [med] done in 993 ms | ||
| 24 | //! [med] Starting long computation | ||
| 25 | //! [high] tick! | ||
| 26 | //! [high] tick! | ||
| 27 | //! [med] done in 993 ms | ||
| 28 | //! [low] done in 3972 ms | ||
| 29 | //! [med] Starting long computation | ||
| 30 | //! [high] tick! | ||
| 31 | //! [high] tick! | ||
| 32 | //! [med] done in 993 ms | ||
| 33 | //! ``` | ||
| 34 | //! | ||
| 35 | //! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. | ||
| 36 | //! You will get an output like the following. Note that no computation is ever interrupted. | ||
| 37 | //! | ||
| 38 | //! ```not_rust | ||
| 39 | //! [high] tick! | ||
| 40 | //! [med] Starting long computation | ||
| 41 | //! [med] done in 496 ms | ||
| 42 | //! [low] Starting long computation | ||
| 43 | //! [low] done in 992 ms | ||
| 44 | //! [med] Starting long computation | ||
| 45 | //! [med] done in 496 ms | ||
| 46 | //! [high] tick! | ||
| 47 | //! [low] Starting long computation | ||
| 48 | //! [low] done in 992 ms | ||
| 49 | //! [high] tick! | ||
| 50 | //! [med] Starting long computation | ||
| 51 | //! [med] done in 496 ms | ||
| 52 | //! [high] tick! | ||
| 53 | //! ``` | ||
| 54 | //! | ||
| 55 | |||
| 56 | #![no_std] | ||
| 57 | #![no_main] | ||
| 58 | |||
| 59 | use cortex_m_rt::entry; | ||
| 60 | use defmt::*; | ||
| 61 | use embassy_executor::{Executor, InterruptExecutor}; | ||
| 62 | use embassy_stm32::interrupt; | ||
| 63 | use embassy_stm32::interrupt::{InterruptExt, Priority}; | ||
| 64 | use embassy_time::{Instant, Timer}; | ||
| 65 | use static_cell::StaticCell; | ||
| 66 | use {defmt_rtt as _, panic_probe as _}; | ||
| 67 | |||
| 68 | #[embassy_executor::task] | ||
| 69 | async fn run_high() { | ||
| 70 | loop { | ||
| 71 | info!(" [high] tick!"); | ||
| 72 | Timer::after_ticks(27374).await; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | #[embassy_executor::task] | ||
| 77 | async fn run_med() { | ||
| 78 | loop { | ||
| 79 | let start = Instant::now(); | ||
| 80 | info!(" [med] Starting long computation"); | ||
| 81 | |||
| 82 | // Spin-wait to simulate a long CPU computation | ||
| 83 | embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second | ||
| 84 | |||
| 85 | let end = Instant::now(); | ||
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 87 | info!(" [med] done in {} ms", ms); | ||
| 88 | |||
| 89 | Timer::after_ticks(23421).await; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | #[embassy_executor::task] | ||
| 94 | async fn run_low() { | ||
| 95 | loop { | ||
| 96 | let start = Instant::now(); | ||
| 97 | info!("[low] Starting long computation"); | ||
| 98 | |||
| 99 | // Spin-wait to simulate a long CPU computation | ||
| 100 | embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds | ||
| 101 | |||
| 102 | let end = Instant::now(); | ||
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 104 | info!("[low] done in {} ms", ms); | ||
| 105 | |||
| 106 | Timer::after_ticks(32983).await; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); | ||
| 111 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); | ||
| 112 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | ||
| 113 | |||
| 114 | #[interrupt] | ||
| 115 | unsafe fn UART4() { | ||
| 116 | EXECUTOR_HIGH.on_interrupt() | ||
| 117 | } | ||
| 118 | |||
| 119 | #[interrupt] | ||
| 120 | unsafe fn UART5() { | ||
| 121 | EXECUTOR_MED.on_interrupt() | ||
| 122 | } | ||
| 123 | |||
| 124 | #[entry] | ||
| 125 | fn main() -> ! { | ||
| 126 | info!("Hello World!"); | ||
| 127 | |||
| 128 | let _p = embassy_stm32::init(Default::default()); | ||
| 129 | |||
| 130 | // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as | ||
| 131 | // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. | ||
| 132 | // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt | ||
| 133 | // vector would work exactly the same. | ||
| 134 | |||
| 135 | // High-priority executor: UART4, priority level 6 | ||
| 136 | interrupt::UART4.set_priority(Priority::P6); | ||
| 137 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); | ||
| 138 | unwrap!(spawner.spawn(run_high())); | ||
| 139 | |||
| 140 | // Medium-priority executor: UART5, priority level 7 | ||
| 141 | interrupt::UART5.set_priority(Priority::P7); | ||
| 142 | let spawner = EXECUTOR_MED.start(interrupt::UART5); | ||
| 143 | unwrap!(spawner.spawn(run_med())); | ||
| 144 | |||
| 145 | // Low priority executor: runs in thread mode, using WFE/SEV | ||
| 146 | let executor = EXECUTOR_LOW.init(Executor::new()); | ||
| 147 | executor.run(|spawner| { | ||
| 148 | unwrap!(spawner.spawn(run_low())); | ||
| 149 | }); | ||
| 150 | } | ||
diff --git a/examples/stm32h7rs/src/bin/rng.rs b/examples/stm32h7rs/src/bin/rng.rs new file mode 100644 index 000000000..a9ef7200d --- /dev/null +++ b/examples/stm32h7rs/src/bin/rng.rs | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::rng::Rng; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 12 | }); | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) { | ||
| 16 | let mut config = Config::default(); | ||
| 17 | config.rcc.hsi48 = Some(Default::default()); // needed for RNG | ||
| 18 | let p = embassy_stm32::init(config); | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | let mut rng = Rng::new(p.RNG, Irqs); | ||
| 22 | |||
| 23 | let mut buf = [0u8; 16]; | ||
| 24 | unwrap!(rng.async_fill_bytes(&mut buf).await); | ||
| 25 | info!("random bytes: {:02x}", buf); | ||
| 26 | } | ||
diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs new file mode 100644 index 000000000..0adb48877 --- /dev/null +++ b/examples/stm32h7rs/src/bin/rtc.rs | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use chrono::{NaiveDate, NaiveDateTime}; | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::rcc::LsConfig; | ||
| 8 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 9 | use embassy_stm32::Config; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let mut config = Config::default(); | ||
| 16 | config.rcc.ls = LsConfig::default_lse(); | ||
| 17 | |||
| 18 | let p = embassy_stm32::init(config); | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) | ||
| 22 | .unwrap() | ||
| 23 | .and_hms_opt(10, 30, 15) | ||
| 24 | .unwrap(); | ||
| 25 | |||
| 26 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 27 | info!("Got RTC! {:?}", now.and_utc().timestamp()); | ||
| 28 | |||
| 29 | rtc.set_datetime(now.into()).expect("datetime not set"); | ||
| 30 | |||
| 31 | // In reality the delay would be much longer | ||
| 32 | Timer::after_millis(20000).await; | ||
| 33 | |||
| 34 | let then: NaiveDateTime = rtc.now().unwrap().into(); | ||
| 35 | info!("Got RTC! {:?}", then.and_utc().timestamp()); | ||
| 36 | } | ||
diff --git a/examples/stm32h7rs/src/bin/signal.rs b/examples/stm32h7rs/src/bin/signal.rs new file mode 100644 index 000000000..b73360f32 --- /dev/null +++ b/examples/stm32h7rs/src/bin/signal.rs | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 7 | use embassy_sync::signal::Signal; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new(); | ||
| 12 | |||
| 13 | #[embassy_executor::task] | ||
| 14 | async fn my_sending_task() { | ||
| 15 | let mut counter: u32 = 0; | ||
| 16 | |||
| 17 | loop { | ||
| 18 | Timer::after_secs(1).await; | ||
| 19 | |||
| 20 | SIGNAL.signal(counter); | ||
| 21 | |||
| 22 | counter = counter.wrapping_add(1); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | #[embassy_executor::main] | ||
| 27 | async fn main(spawner: Spawner) { | ||
| 28 | let _p = embassy_stm32::init(Default::default()); | ||
| 29 | unwrap!(spawner.spawn(my_sending_task())); | ||
| 30 | |||
| 31 | loop { | ||
| 32 | let received_counter = SIGNAL.wait().await; | ||
| 33 | |||
| 34 | info!("signalled, counter: {}", received_counter); | ||
| 35 | } | ||
| 36 | } | ||
diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs new file mode 100644 index 000000000..8d6ccc58b --- /dev/null +++ b/examples/stm32h7rs/src/bin/spi.rs | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::fmt::Write; | ||
| 5 | use core::str::from_utf8; | ||
| 6 | |||
| 7 | use cortex_m_rt::entry; | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Executor; | ||
| 10 | use embassy_stm32::mode::Blocking; | ||
| 11 | use embassy_stm32::spi; | ||
| 12 | use embassy_stm32::time::mhz; | ||
| 13 | use heapless::String; | ||
| 14 | use static_cell::StaticCell; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async fn main_task(mut spi: spi::Spi<'static, Blocking>) { | ||
| 19 | for n in 0u32.. { | ||
| 20 | let mut write: String<128> = String::new(); | ||
| 21 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 22 | unsafe { | ||
| 23 | let result = spi.blocking_transfer_in_place(write.as_bytes_mut()); | ||
| 24 | if let Err(_) = result { | ||
| 25 | defmt::panic!("crap"); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | info!("read via spi: {}", from_utf8(write.as_bytes()).unwrap()); | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 33 | |||
| 34 | #[entry] | ||
| 35 | fn main() -> ! { | ||
| 36 | info!("Hello World!"); | ||
| 37 | let p = embassy_stm32::init(Default::default()); | ||
| 38 | |||
| 39 | let mut spi_config = spi::Config::default(); | ||
| 40 | spi_config.frequency = mhz(1); | ||
| 41 | |||
| 42 | let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config); | ||
| 43 | |||
| 44 | let executor = EXECUTOR.init(Executor::new()); | ||
| 45 | |||
| 46 | executor.run(|spawner| { | ||
| 47 | unwrap!(spawner.spawn(main_task(spi))); | ||
| 48 | }) | ||
| 49 | } | ||
diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs new file mode 100644 index 000000000..cb305351b --- /dev/null +++ b/examples/stm32h7rs/src/bin/spi_dma.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::fmt::Write; | ||
| 5 | use core::str::from_utf8; | ||
| 6 | |||
| 7 | use cortex_m_rt::entry; | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Executor; | ||
| 10 | use embassy_stm32::mode::Async; | ||
| 11 | use embassy_stm32::spi; | ||
| 12 | use embassy_stm32::time::mhz; | ||
| 13 | use heapless::String; | ||
| 14 | use static_cell::StaticCell; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async fn main_task(mut spi: spi::Spi<'static, Async>) { | ||
| 19 | for n in 0u32.. { | ||
| 20 | let mut write: String<128> = String::new(); | ||
| 21 | let mut read = [0; 128]; | ||
| 22 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 23 | // transfer will slice the &mut read down to &write's actual length. | ||
| 24 | spi.transfer(&mut read, write.as_bytes()).await.ok(); | ||
| 25 | info!("read via spi+dma: {}", from_utf8(&read).unwrap()); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 30 | |||
| 31 | #[entry] | ||
| 32 | fn main() -> ! { | ||
| 33 | info!("Hello World!"); | ||
| 34 | let p = embassy_stm32::init(Default::default()); | ||
| 35 | |||
| 36 | let mut spi_config = spi::Config::default(); | ||
| 37 | spi_config.frequency = mhz(1); | ||
| 38 | |||
| 39 | let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, p.GPDMA1_CH0, p.GPDMA1_CH1, spi_config); | ||
| 40 | |||
| 41 | let executor = EXECUTOR.init(Executor::new()); | ||
| 42 | |||
| 43 | executor.run(|spawner| { | ||
| 44 | unwrap!(spawner.spawn(main_task(spi))); | ||
| 45 | }) | ||
| 46 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usart.rs b/examples/stm32h7rs/src/bin/usart.rs new file mode 100644 index 000000000..cc49c2fdb --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart.rs | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use cortex_m_rt::entry; | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Executor; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | ||
| 8 | use static_cell::StaticCell; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::task] | ||
| 12 | async fn main_task() { | ||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | |||
| 15 | let config = Config::default(); | ||
| 16 | let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); | ||
| 17 | |||
| 18 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||
| 19 | info!("wrote Hello, starting echo"); | ||
| 20 | |||
| 21 | let mut buf = [0u8; 1]; | ||
| 22 | loop { | ||
| 23 | unwrap!(usart.blocking_read(&mut buf)); | ||
| 24 | unwrap!(usart.blocking_write(&buf)); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 29 | |||
| 30 | #[entry] | ||
| 31 | fn main() -> ! { | ||
| 32 | info!("Hello World!"); | ||
| 33 | |||
| 34 | let executor = EXECUTOR.init(Executor::new()); | ||
| 35 | |||
| 36 | executor.run(|spawner| { | ||
| 37 | unwrap!(spawner.spawn(main_task())); | ||
| 38 | }) | ||
| 39 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usart_dma.rs b/examples/stm32h7rs/src/bin/usart_dma.rs new file mode 100644 index 000000000..c644e84bd --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart_dma.rs | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::fmt::Write; | ||
| 5 | |||
| 6 | use cortex_m_rt::entry; | ||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Executor; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | ||
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 11 | use heapless::String; | ||
| 12 | use static_cell::StaticCell; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::task] | ||
| 20 | async fn main_task() { | ||
| 21 | let p = embassy_stm32::init(Default::default()); | ||
| 22 | |||
| 23 | let config = Config::default(); | ||
| 24 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); | ||
| 25 | |||
| 26 | for n in 0u32.. { | ||
| 27 | let mut s: String<128> = String::new(); | ||
| 28 | core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 29 | |||
| 30 | usart.write(s.as_bytes()).await.ok(); | ||
| 31 | |||
| 32 | info!("wrote DMA"); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 37 | |||
| 38 | #[entry] | ||
| 39 | fn main() -> ! { | ||
| 40 | info!("Hello World!"); | ||
| 41 | |||
| 42 | let executor = EXECUTOR.init(Executor::new()); | ||
| 43 | |||
| 44 | executor.run(|spawner| { | ||
| 45 | unwrap!(spawner.spawn(main_task())); | ||
| 46 | }) | ||
| 47 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usart_split.rs b/examples/stm32h7rs/src/bin/usart_split.rs new file mode 100644 index 000000000..d26c5003c --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart_split.rs | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::mode::Async; | ||
| 7 | use embassy_stm32::usart::{Config, Uart, UartRx}; | ||
| 8 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 9 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||
| 10 | use embassy_sync::channel::Channel; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(spawner: Spawner) -> ! { | ||
| 21 | let p = embassy_stm32::init(Default::default()); | ||
| 22 | info!("Hello World!"); | ||
| 23 | |||
| 24 | let config = Config::default(); | ||
| 25 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); | ||
| 26 | unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); | ||
| 27 | |||
| 28 | let (mut tx, rx) = usart.split(); | ||
| 29 | |||
| 30 | unwrap!(spawner.spawn(reader(rx))); | ||
| 31 | |||
| 32 | loop { | ||
| 33 | let buf = CHANNEL.receive().await; | ||
| 34 | info!("writing..."); | ||
| 35 | unwrap!(tx.write(&buf).await); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | #[embassy_executor::task] | ||
| 40 | async fn reader(mut rx: UartRx<'static, Async>) { | ||
| 41 | let mut buf = [0; 8]; | ||
| 42 | loop { | ||
| 43 | info!("reading..."); | ||
| 44 | unwrap!(rx.read(&mut buf).await); | ||
| 45 | CHANNEL.send(buf).await; | ||
| 46 | } | ||
| 47 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs new file mode 100644 index 000000000..6773f7843 --- /dev/null +++ b/examples/stm32h7rs/src/bin/usb_serial.rs | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{panic, *}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_futures::join::join; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::usb::{Driver, Instance}; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 11 | use embassy_usb::driver::EndpointError; | ||
| 12 | use embassy_usb::Builder; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | // If you are trying this and your USB device doesn't connect, the most | ||
| 20 | // common issues are the RCC config and vbus_detection | ||
| 21 | // | ||
| 22 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 23 | // for more information. | ||
| 24 | #[embassy_executor::main] | ||
| 25 | async fn main(_spawner: Spawner) { | ||
| 26 | info!("Hello World!"); | ||
| 27 | |||
| 28 | let mut config = Config::default(); | ||
| 29 | |||
| 30 | { | ||
| 31 | use embassy_stm32::rcc::*; | ||
| 32 | config.rcc.hse = Some(Hse { | ||
| 33 | freq: Hertz(24_000_000), | ||
| 34 | mode: HseMode::Oscillator, | ||
| 35 | }); | ||
| 36 | config.rcc.pll1 = Some(Pll { | ||
| 37 | source: PllSource::HSE, | ||
| 38 | prediv: PllPreDiv::DIV12, | ||
| 39 | mul: PllMul::MUL300, | ||
| 40 | divp: Some(PllDiv::DIV1), //600 MHz | ||
| 41 | divq: Some(PllDiv::DIV2), // 300 MHz | ||
| 42 | divr: Some(PllDiv::DIV2), // 300 MHz | ||
| 43 | }); | ||
| 44 | config.rcc.sys = Sysclk::PLL1_P; // 600 MHz | ||
| 45 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz | ||
| 46 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 47 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 48 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 49 | config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 50 | config.rcc.voltage_scale = VoltageScale::HIGH; | ||
| 51 | config.rcc.mux.usbphycsel = mux::Usbphycsel::HSE; | ||
| 52 | } | ||
| 53 | |||
| 54 | let p = embassy_stm32::init(config); | ||
| 55 | |||
| 56 | // Create the driver, from the HAL. | ||
| 57 | let mut ep_out_buffer = [0u8; 256]; | ||
| 58 | let mut config = embassy_stm32::usb::Config::default(); | ||
| 59 | |||
| 60 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 61 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 62 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 63 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 64 | config.vbus_detection = false; | ||
| 65 | |||
| 66 | let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PM6, p.PM5, &mut ep_out_buffer, config); | ||
| 67 | |||
| 68 | // Create embassy-usb Config | ||
| 69 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 70 | config.manufacturer = Some("Embassy"); | ||
| 71 | config.product = Some("USB-serial example"); | ||
| 72 | config.serial_number = Some("12345678"); | ||
| 73 | // Required for windows compatibility. | ||
| 74 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 75 | config.device_class = 0xEF; | ||
| 76 | config.device_sub_class = 0x02; | ||
| 77 | config.device_protocol = 0x01; | ||
| 78 | config.composite_with_iads = true; | ||
| 79 | |||
| 80 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 81 | // It needs some buffers for building the descriptors. | ||
| 82 | let mut config_descriptor = [0; 256]; | ||
| 83 | let mut bos_descriptor = [0; 256]; | ||
| 84 | let mut control_buf = [0; 64]; | ||
| 85 | |||
| 86 | let mut state = State::new(); | ||
| 87 | |||
| 88 | let mut builder = Builder::new( | ||
| 89 | driver, | ||
| 90 | config, | ||
| 91 | &mut config_descriptor, | ||
| 92 | &mut bos_descriptor, | ||
| 93 | &mut [], // no msos descriptors | ||
| 94 | &mut control_buf, | ||
| 95 | ); | ||
| 96 | |||
| 97 | // Create classes on the builder. | ||
| 98 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | ||
| 99 | |||
| 100 | // Build the builder. | ||
| 101 | let mut usb = builder.build(); | ||
| 102 | |||
| 103 | // Run the USB device. | ||
| 104 | let usb_fut = usb.run(); | ||
| 105 | |||
| 106 | // Do stuff with the class! | ||
| 107 | let echo_fut = async { | ||
| 108 | loop { | ||
| 109 | class.wait_connection().await; | ||
| 110 | info!("Connected"); | ||
| 111 | let _ = echo(&mut class).await; | ||
| 112 | info!("Disconnected"); | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | |||
| 116 | // Run everything concurrently. | ||
| 117 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 118 | join(usb_fut, echo_fut).await; | ||
| 119 | } | ||
| 120 | |||
| 121 | struct Disconnected {} | ||
| 122 | |||
| 123 | impl From<EndpointError> for Disconnected { | ||
| 124 | fn from(val: EndpointError) -> Self { | ||
| 125 | match val { | ||
| 126 | EndpointError::BufferOverflow => panic!("Buffer overflow"), | ||
| 127 | EndpointError::Disabled => Disconnected {}, | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { | ||
| 133 | let mut buf = [0; 64]; | ||
| 134 | loop { | ||
| 135 | let n = class.read_packet(&mut buf).await?; | ||
| 136 | let data = &buf[..n]; | ||
| 137 | info!("data: {:x}", data); | ||
| 138 | class.write_packet(data).await?; | ||
| 139 | } | ||
| 140 | } | ||
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index dd9097c9b..2577f19e0 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml | |||
| @@ -6,10 +6,10 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32l072cz to your chip name, if necessary. | 8 | # Change stm32l072cz to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "0.3" |
| 15 | defmt-rtt = "0.4" | 15 | defmt-rtt = "0.4" |
| @@ -21,7 +21,6 @@ embedded-io-async = { version = "0.6.1" } | |||
| 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 21 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 22 | cortex-m-rt = "0.7.0" | 22 | cortex-m-rt = "0.7.0" |
| 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 23 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 24 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 25 | heapless = { version = "0.8", default-features = false } | 24 | heapless = { version = "0.8", default-features = false } |
| 26 | embedded-hal = "0.2.6" | 25 | embedded-hal = "0.2.6" |
| 27 | static_cell = { version = "2" } | 26 | static_cell = { version = "2" } |
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index adeaa208a..9dd09bc45 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs | |||
| @@ -4,13 +4,13 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | 6 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 7 | use embassy_stm32::peripherals::ADC; | 7 | use embassy_stm32::peripherals::ADC1; |
| 8 | use embassy_stm32::{adc, bind_interrupts}; | 8 | use embassy_stm32::{adc, bind_interrupts}; |
| 9 | use embassy_time::{Delay, Timer}; | 9 | use embassy_time::Timer; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | 12 | bind_interrupts!(struct Irqs { |
| 13 | ADC1_COMP => adc::InterruptHandler<ADC>; | 13 | ADC1_COMP => adc::InterruptHandler<ADC1>; |
| 14 | }); | 14 | }); |
| 15 | 15 | ||
| 16 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| @@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) { | |||
| 18 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(Default::default()); |
| 19 | info!("Hello World!"); | 19 | info!("Hello World!"); |
| 20 | 20 | ||
| 21 | let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); | 21 | let mut adc = Adc::new(p.ADC1, Irqs); |
| 22 | adc.set_sample_time(SampleTime::Cycles79_5); | 22 | adc.set_sample_time(SampleTime::CYCLES79_5); |
| 23 | let mut pin = p.PA1; | 23 | let mut pin = p.PA1; |
| 24 | 24 | ||
| 25 | let mut vrefint = adc.enable_vref(&mut Delay); | 25 | let mut vrefint = adc.enable_vref(); |
| 26 | let vrefint_sample = adc.read(&mut vrefint).await; | 26 | let vrefint_sample = adc.read(&mut vrefint).await; |
| 27 | let convert_to_millivolts = |sample| { | 27 | let convert_to_millivolts = |sample| { |
| 28 | // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf | 28 | // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf |
diff --git a/examples/stm32l0/src/bin/async-tsc.rs b/examples/stm32l0/src/bin/async-tsc.rs new file mode 100644 index 000000000..c40b86af9 --- /dev/null +++ b/examples/stm32l0/src/bin/async-tsc.rs | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | // Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected. | ||
| 2 | // | ||
| 3 | // Suggested physical setup on STM32L073RZ Nucleo board: | ||
| 4 | // - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor. | ||
| 5 | // - Connect one end of a 1K resistor to pin A1 and leave the other end loose. | ||
| 6 | // The loose end will act as touch sensor which will register your touch. | ||
| 7 | // | ||
| 8 | // Troubleshooting the setup: | ||
| 9 | // - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily, | ||
| 10 | // now the led should light up. Next try using a different value for the sampling capacitor. | ||
| 11 | // Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`. | ||
| 12 | // | ||
| 13 | // All configuration values and sampling capacitor value have been determined experimentally. | ||
| 14 | // Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values. | ||
| 15 | // | ||
| 16 | #![no_std] | ||
| 17 | #![no_main] | ||
| 18 | |||
| 19 | use defmt::*; | ||
| 20 | use embassy_stm32::bind_interrupts; | ||
| 21 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 22 | use embassy_stm32::tsc::{self, *}; | ||
| 23 | use embassy_time::Timer; | ||
| 24 | use {defmt_rtt as _, panic_probe as _}; | ||
| 25 | |||
| 26 | bind_interrupts!(struct Irqs { | ||
| 27 | TSC => InterruptHandler<embassy_stm32::peripherals::TSC>; | ||
| 28 | }); | ||
| 29 | |||
| 30 | #[cortex_m_rt::exception] | ||
| 31 | unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! { | ||
| 32 | cortex_m::peripheral::SCB::sys_reset(); | ||
| 33 | } | ||
| 34 | |||
| 35 | /// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip. | ||
| 36 | /// | ||
| 37 | /// Make sure you check/update the following (whether you use the L073RZ or another board): | ||
| 38 | /// | ||
| 39 | /// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name. | ||
| 40 | /// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`. | ||
| 41 | /// * [ ] If your board has a special clock or power configuration, make sure that it is | ||
| 42 | /// set up appropriately. | ||
| 43 | /// * [ ] If your board has different pin mapping, update any pin numbers or peripherals | ||
| 44 | /// to match your schematic | ||
| 45 | /// | ||
| 46 | /// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 47 | /// | ||
| 48 | /// * Which example you are trying to run | ||
| 49 | /// * Which chip and board you are using | ||
| 50 | /// | ||
| 51 | /// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
| 52 | #[embassy_executor::main] | ||
| 53 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 54 | let device_config = embassy_stm32::Config::default(); | ||
| 55 | let context = embassy_stm32::init(device_config); | ||
| 56 | |||
| 57 | let config = tsc::Config { | ||
| 58 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 59 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 60 | spread_spectrum: false, | ||
| 61 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 62 | spread_spectrum_prescaler: false, | ||
| 63 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 64 | max_count_value: MaxCount::_255, | ||
| 65 | io_default_mode: false, | ||
| 66 | synchro_pin_polarity: false, | ||
| 67 | acquisition_mode: false, | ||
| 68 | max_count_interrupt: false, | ||
| 69 | channel_ios: TscIOPin::Group1Io1.into(), | ||
| 70 | shield_ios: 0, // no shield | ||
| 71 | sampling_ios: TscIOPin::Group1Io2.into(), | ||
| 72 | }; | ||
| 73 | |||
| 74 | let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | ||
| 75 | g1.set_io1(context.PA0, PinType::Sample); | ||
| 76 | g1.set_io2(context.PA1, PinType::Channel); | ||
| 77 | |||
| 78 | let mut touch_controller = tsc::Tsc::new_async( | ||
| 79 | context.TSC, | ||
| 80 | Some(g1), | ||
| 81 | None, | ||
| 82 | None, | ||
| 83 | None, | ||
| 84 | None, | ||
| 85 | None, | ||
| 86 | None, | ||
| 87 | None, | ||
| 88 | config, | ||
| 89 | Irqs, | ||
| 90 | ); | ||
| 91 | |||
| 92 | // Check if TSC is ready | ||
| 93 | if touch_controller.get_state() != State::Ready { | ||
| 94 | info!("TSC not ready!"); | ||
| 95 | loop {} // Halt execution | ||
| 96 | } | ||
| 97 | info!("TSC initialized successfully"); | ||
| 98 | |||
| 99 | // LED2 on the STM32L073RZ nucleo-board (PA5) | ||
| 100 | let mut led = Output::new(context.PA5, Level::High, Speed::Low); | ||
| 101 | |||
| 102 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 103 | let discharge_delay = 5; // ms | ||
| 104 | |||
| 105 | info!("Starting touch_controller interface"); | ||
| 106 | loop { | ||
| 107 | touch_controller.start(); | ||
| 108 | touch_controller.pend_for_acquisition().await; | ||
| 109 | touch_controller.discharge_io(true); | ||
| 110 | Timer::after_millis(discharge_delay).await; | ||
| 111 | |||
| 112 | let grp1_status = touch_controller.group_get_status(Group::One); | ||
| 113 | match grp1_status { | ||
| 114 | GroupStatus::Complete => { | ||
| 115 | let group_one_val = touch_controller.group_get_value(Group::One); | ||
| 116 | info!("{}", group_one_val); | ||
| 117 | led.set_high(); | ||
| 118 | } | ||
| 119 | GroupStatus::Ongoing => led.set_low(), | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
diff --git a/examples/stm32l0/src/bin/blocking-tsc.rs b/examples/stm32l0/src/bin/blocking-tsc.rs new file mode 100644 index 000000000..7e4f40946 --- /dev/null +++ b/examples/stm32l0/src/bin/blocking-tsc.rs | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | // Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected. | ||
| 2 | // | ||
| 3 | // Suggested physical setup on STM32L073RZ Nucleo board: | ||
| 4 | // - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor. | ||
| 5 | // - Connect one end of a 1K resistor to pin A1 and leave the other end loose. | ||
| 6 | // The loose end will act as touch sensor which will register your touch. | ||
| 7 | // | ||
| 8 | // Troubleshooting the setup: | ||
| 9 | // - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily, | ||
| 10 | // now the led should light up. Next try using a different value for the sampling capacitor. | ||
| 11 | // Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`. | ||
| 12 | // | ||
| 13 | // All configuration values and sampling capacitor value have been determined experimentally. | ||
| 14 | // Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values. | ||
| 15 | // | ||
| 16 | #![no_std] | ||
| 17 | #![no_main] | ||
| 18 | |||
| 19 | use defmt::*; | ||
| 20 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 21 | use embassy_stm32::tsc::{self, *}; | ||
| 22 | use embassy_time::Timer; | ||
| 23 | use {defmt_rtt as _, panic_probe as _}; | ||
| 24 | |||
| 25 | /// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip. | ||
| 26 | /// | ||
| 27 | /// Make sure you check/update the following (whether you use the L073RZ or another board): | ||
| 28 | /// | ||
| 29 | /// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name. | ||
| 30 | /// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`. | ||
| 31 | /// * [ ] If your board has a special clock or power configuration, make sure that it is | ||
| 32 | /// set up appropriately. | ||
| 33 | /// * [ ] If your board has different pin mapping, update any pin numbers or peripherals | ||
| 34 | /// to match your schematic | ||
| 35 | /// | ||
| 36 | /// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 37 | /// | ||
| 38 | /// * Which example you are trying to run | ||
| 39 | /// * Which chip and board you are using | ||
| 40 | /// | ||
| 41 | /// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
| 42 | #[embassy_executor::main] | ||
| 43 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 44 | let device_config = embassy_stm32::Config::default(); | ||
| 45 | let context = embassy_stm32::init(device_config); | ||
| 46 | |||
| 47 | let tsc_conf = Config { | ||
| 48 | ct_pulse_high_length: ChargeTransferPulseCycle::_4, | ||
| 49 | ct_pulse_low_length: ChargeTransferPulseCycle::_4, | ||
| 50 | spread_spectrum: false, | ||
| 51 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 52 | spread_spectrum_prescaler: false, | ||
| 53 | pulse_generator_prescaler: PGPrescalerDivider::_16, | ||
| 54 | max_count_value: MaxCount::_255, | ||
| 55 | io_default_mode: false, | ||
| 56 | synchro_pin_polarity: false, | ||
| 57 | acquisition_mode: false, | ||
| 58 | max_count_interrupt: false, | ||
| 59 | channel_ios: TscIOPin::Group1Io1.into(), | ||
| 60 | shield_ios: 0, // no shield | ||
| 61 | sampling_ios: TscIOPin::Group1Io2.into(), | ||
| 62 | }; | ||
| 63 | |||
| 64 | let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | ||
| 65 | g1.set_io1(context.PA0, PinType::Sample); | ||
| 66 | g1.set_io2(context.PA1, PinType::Channel); | ||
| 67 | |||
| 68 | let mut touch_controller = tsc::Tsc::new_blocking( | ||
| 69 | context.TSC, | ||
| 70 | Some(g1), | ||
| 71 | None, | ||
| 72 | None, | ||
| 73 | None, | ||
| 74 | None, | ||
| 75 | None, | ||
| 76 | None, | ||
| 77 | None, | ||
| 78 | tsc_conf, | ||
| 79 | ); | ||
| 80 | |||
| 81 | // Check if TSC is ready | ||
| 82 | if touch_controller.get_state() != State::Ready { | ||
| 83 | info!("TSC not ready!"); | ||
| 84 | loop {} // Halt execution | ||
| 85 | } | ||
| 86 | info!("TSC initialized successfully"); | ||
| 87 | |||
| 88 | // LED2 on the STM32L073RZ nucleo-board (PA5) | ||
| 89 | let mut led = Output::new(context.PA5, Level::High, Speed::Low); | ||
| 90 | |||
| 91 | // smaller sample capacitor discharge faster and can be used with shorter delay. | ||
| 92 | let discharge_delay = 5; // ms | ||
| 93 | |||
| 94 | // the interval at which the loop polls for new touch sensor values | ||
| 95 | let polling_interval = 100; // ms | ||
| 96 | |||
| 97 | info!("polling for touch"); | ||
| 98 | loop { | ||
| 99 | touch_controller.start(); | ||
| 100 | touch_controller.poll_for_acquisition(); | ||
| 101 | touch_controller.discharge_io(true); | ||
| 102 | Timer::after_millis(discharge_delay).await; | ||
| 103 | |||
| 104 | let grp1_status = touch_controller.group_get_status(Group::One); | ||
| 105 | match grp1_status { | ||
| 106 | GroupStatus::Complete => { | ||
| 107 | let group_one_val = touch_controller.group_get_value(Group::One); | ||
| 108 | info!("{}", group_one_val); | ||
| 109 | led.set_high(); | ||
| 110 | } | ||
| 111 | GroupStatus::Ongoing => led.set_low(), | ||
| 112 | } | ||
| 113 | |||
| 114 | Timer::after_millis(polling_interval).await; | ||
| 115 | } | ||
| 116 | } | ||
diff --git a/examples/stm32l0/src/bin/dds.rs b/examples/stm32l0/src/bin/dds.rs new file mode 100644 index 000000000..a54b28a93 --- /dev/null +++ b/examples/stm32l0/src/bin/dds.rs | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::option::Option::Some; | ||
| 5 | |||
| 6 | use defmt::info; | ||
| 7 | use defmt_rtt as _; // global logger | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_stm32::gpio::OutputType; | ||
| 10 | use embassy_stm32::rcc::*; | ||
| 11 | use embassy_stm32::time::hz; | ||
| 12 | use embassy_stm32::timer::low_level::{Timer as LLTimer, *}; | ||
| 13 | use embassy_stm32::timer::simple_pwm::PwmPin; | ||
| 14 | use embassy_stm32::timer::Channel; | ||
| 15 | use embassy_stm32::{interrupt, pac, Config}; | ||
| 16 | use panic_probe as _; | ||
| 17 | |||
| 18 | const DDS_SINE_DATA: [u8; 256] = [ | ||
| 19 | 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, 0x98, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xae, 0xb0, 0xb3, 0xb6, | ||
| 20 | 0xb9, 0xbc, 0xbf, 0xc1, 0xc4, 0xc7, 0xc9, 0xcc, 0xce, 0xd1, 0xd3, 0xd5, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, | ||
| 21 | 0xe6, 0xe8, 0xea, 0xec, 0xed, 0xef, 0xf0, 0xf2, 0xf3, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, | ||
| 22 | 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb, | ||
| 23 | 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf3, 0xf2, 0xf0, 0xef, 0xed, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde, | ||
| 24 | 0xdc, 0xda, 0xd8, 0xd5, 0xd3, 0xd1, 0xce, 0xcc, 0xc9, 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xb9, 0xb6, 0xb3, 0xb0, 0xae, | ||
| 25 | 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x98, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x83, 0x80, 0x7c, 0x79, 0x76, 0x73, | ||
| 26 | 0x70, 0x6d, 0x6a, 0x67, 0x63, 0x60, 0x5d, 0x5a, 0x57, 0x54, 0x51, 0x4f, 0x4c, 0x49, 0x46, 0x43, 0x40, 0x3e, 0x3b, | ||
| 27 | 0x38, 0x36, 0x33, 0x31, 0x2e, 0x2c, 0x2a, 0x27, 0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x12, | ||
| 28 | 0x10, 0x0f, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
| 29 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, | ||
| 30 | 0x0a, 0x0c, 0x0d, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f, 0x21, 0x23, 0x25, 0x27, 0x2a, 0x2c, | ||
| 31 | 0x2e, 0x31, 0x33, 0x36, 0x38, 0x3b, 0x3e, 0x40, 0x43, 0x46, 0x49, 0x4c, 0x4f, 0x51, 0x54, 0x57, 0x5a, 0x5d, 0x60, | ||
| 32 | 0x63, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76, 0x79, 0x7c, | ||
| 33 | ]; | ||
| 34 | |||
| 35 | // frequency: 15625/(256/(DDS_INCR/2**24)) = 999,99999Hz | ||
| 36 | static mut DDS_INCR: u32 = 0x10624DD2; | ||
| 37 | |||
| 38 | // fractional phase accumulator | ||
| 39 | static mut DDS_AKKU: u32 = 0x00000000; | ||
| 40 | |||
| 41 | #[interrupt] | ||
| 42 | fn TIM2() { | ||
| 43 | unsafe { | ||
| 44 | // get next value of DDS | ||
| 45 | DDS_AKKU = DDS_AKKU.wrapping_add(DDS_INCR); | ||
| 46 | let value = (DDS_SINE_DATA[(DDS_AKKU >> 24) as usize] as u16) << 3; | ||
| 47 | |||
| 48 | // set new output compare value | ||
| 49 | pac::TIM2.ccr(2).modify(|w| w.set_ccr(value)); | ||
| 50 | |||
| 51 | // reset interrupt flag | ||
| 52 | pac::TIM2.sr().modify(|r| r.set_uif(false)); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | #[embassy_executor::main] | ||
| 57 | async fn main(_spawner: Spawner) { | ||
| 58 | info!("Hello World!"); | ||
| 59 | |||
| 60 | // configure for 32MHz (HSI16 * 6 / 3) | ||
| 61 | let mut config = Config::default(); | ||
| 62 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 63 | config.rcc.hsi = true; | ||
| 64 | config.rcc.pll = Some(Pll { | ||
| 65 | source: PllSource::HSI, | ||
| 66 | div: PllDiv::DIV3, | ||
| 67 | mul: PllMul::MUL6, | ||
| 68 | }); | ||
| 69 | |||
| 70 | let p = embassy_stm32::init(config); | ||
| 71 | |||
| 72 | // setup PWM pin in AF mode | ||
| 73 | let _ch3 = PwmPin::new_ch3(p.PA2, OutputType::PushPull); | ||
| 74 | |||
| 75 | // initialize timer | ||
| 76 | // we cannot use SimplePWM here because the Time is privately encapsulated | ||
| 77 | let timer = LLTimer::new(p.TIM2); | ||
| 78 | |||
| 79 | // set counting mode | ||
| 80 | timer.set_counting_mode(CountingMode::EdgeAlignedUp); | ||
| 81 | |||
| 82 | // set pwm sample frequency | ||
| 83 | timer.set_frequency(hz(15625)); | ||
| 84 | |||
| 85 | // enable outputs | ||
| 86 | timer.enable_outputs(); | ||
| 87 | |||
| 88 | // start timer | ||
| 89 | timer.start(); | ||
| 90 | |||
| 91 | // set output compare mode | ||
| 92 | timer.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | ||
| 93 | |||
| 94 | // set output compare preload | ||
| 95 | timer.set_output_compare_preload(Channel::Ch3, true); | ||
| 96 | |||
| 97 | // set output polarity | ||
| 98 | timer.set_output_polarity(Channel::Ch3, OutputPolarity::ActiveHigh); | ||
| 99 | |||
| 100 | // set compare value | ||
| 101 | timer.set_compare_value(Channel::Ch3, timer.get_max_compare_value() / 2); | ||
| 102 | |||
| 103 | // enable pwm channel | ||
| 104 | timer.enable_channel(Channel::Ch3, true); | ||
| 105 | |||
| 106 | // enable timer interrupts | ||
| 107 | timer.enable_update_interrupt(true); | ||
| 108 | unsafe { cortex_m::peripheral::NVIC::unmask(interrupt::TIM2) }; | ||
| 109 | |||
| 110 | async { | ||
| 111 | loop { | ||
| 112 | embassy_time::Timer::after_millis(5000).await; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | .await; | ||
| 116 | } | ||
diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs index f23a537b8..8e0cfdedb 100644 --- a/examples/stm32l0/src/bin/spi.rs +++ b/examples/stm32l0/src/bin/spi.rs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| @@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) { | |||
| 17 | let mut spi_config = Config::default(); | 16 | let mut spi_config = Config::default(); |
| 18 | spi_config.frequency = Hertz(1_000_000); | 17 | spi_config.frequency = Hertz(1_000_000); |
| 19 | 18 | ||
| 20 | let mut spi = Spi::new(p.SPI1, p.PB3, p.PA7, p.PA6, NoDma, NoDma, spi_config); | 19 | let mut spi = Spi::new_blocking(p.SPI1, p.PB3, p.PA7, p.PA6, spi_config); |
| 21 | 20 | ||
| 22 | let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); | 21 | let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); |
| 23 | 22 | ||
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 322c41262..062044f32 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml | |||
| @@ -5,11 +5,12 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 13 | 14 | ||
| 14 | defmt = "0.3" | 15 | defmt = "0.3" |
| 15 | defmt-rtt = "0.4" | 16 | defmt-rtt = "0.4" |
| @@ -18,7 +19,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 18 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 20 | embedded-hal = "0.2.6" |
| 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 21 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 22 | heapless = { version = "0.8", default-features = false } | 22 | heapless = { version = "0.8", default-features = false } |
| 23 | embedded-storage = "0.3.1" | 23 | embedded-storage = "0.3.1" |
| 24 | 24 | ||
diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs index 8be686c5a..eabf1bac2 100644 --- a/examples/stm32l1/src/bin/spi.rs +++ b/examples/stm32l1/src/bin/spi.rs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 8 | use embassy_stm32::spi::{Config, Spi}; | 7 | use embassy_stm32::spi::{Config, Spi}; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| @@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) { | |||
| 17 | let mut spi_config = Config::default(); | 16 | let mut spi_config = Config::default(); |
| 18 | spi_config.frequency = Hertz(1_000_000); | 17 | spi_config.frequency = Hertz(1_000_000); |
| 19 | 18 | ||
| 20 | let mut spi = Spi::new(p.SPI1, p.PA5, p.PA7, p.PA6, NoDma, NoDma, spi_config); | 19 | let mut spi = Spi::new_blocking(p.SPI1, p.PA5, p.PA7, p.PA6, spi_config); |
| 21 | 20 | ||
| 22 | let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); | 21 | let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); |
| 23 | 22 | ||
diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index 7b1e84cbc..837f7fa57 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs | |||
| @@ -3,12 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | ||
| 6 | use embassy_stm32::usb::{self, Driver, Instance}; | 7 | use embassy_stm32::usb::{self, Driver, Instance}; |
| 7 | use embassy_stm32::{bind_interrupts, peripherals}; | 8 | use embassy_stm32::{bind_interrupts, peripherals}; |
| 8 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 9 | use embassy_usb::driver::EndpointError; | 10 | use embassy_usb::driver::EndpointError; |
| 10 | use embassy_usb::Builder; | 11 | use embassy_usb::Builder; |
| 11 | use futures::future::join; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 13 | ||
| 14 | bind_interrupts!(struct Irqs { | 14 | bind_interrupts!(struct Irqs { |
| @@ -27,7 +27,7 @@ async fn main(_spawner: Spawner) { | |||
| 27 | mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz | 27 | mul: PllMul::MUL6, // PLLVCO = 16*6 = 96Mhz |
| 28 | div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) | 28 | div: PllDiv::DIV3, // 32Mhz clock (16 * 6 / 3) |
| 29 | }); | 29 | }); |
| 30 | config.rcc.mux = ClockSrc::PLL1_R; | 30 | config.rcc.sys = Sysclk::PLL1_R; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | let p = embassy_stm32::init(config); | 33 | let p = embassy_stm32::init(config); |
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | config.device_protocol = 0x01; | 46 | config.device_protocol = 0x01; |
| 47 | config.composite_with_iads = true; | 47 | config.composite_with_iads = true; |
| 48 | 48 | ||
| 49 | let mut device_descriptor = [0; 256]; | ||
| 50 | let mut config_descriptor = [0; 256]; | 49 | let mut config_descriptor = [0; 256]; |
| 51 | let mut bos_descriptor = [0; 256]; | 50 | let mut bos_descriptor = [0; 256]; |
| 52 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| @@ -56,7 +55,6 @@ async fn main(_spawner: Spawner) { | |||
| 56 | let mut builder = Builder::new( | 55 | let mut builder = Builder::new( |
| 57 | driver, | 56 | driver, |
| 58 | config, | 57 | config, |
| 59 | &mut device_descriptor, | ||
| 60 | &mut config_descriptor, | 58 | &mut config_descriptor, |
| 61 | &mut bos_descriptor, | 59 | &mut bos_descriptor, |
| 62 | &mut [], // no msos descriptors | 60 | &mut [], // no msos descriptors |
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index db3a7ceff..83fc6d6f8 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` | 2 | # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` |
| 3 | #runner = "probe-rs run --chip STM32L475VGT6" | 3 | #runner = "probe-rs run --chip STM32L475VGT6" |
| 4 | #runner = "probe-rs run --chip STM32L475VG" | 4 | #runner = "probe-rs run --chip STM32L475VG" |
| 5 | runner = "probe-run --chip STM32L4S5QI" | 5 | runner = "probe-rs run --chip STM32L4S5QI" |
| 6 | 6 | ||
| 7 | [build] | 7 | [build] |
| 8 | target = "thumbv7em-none-eabi" | 8 | target = "thumbv7em-none-eabi" |
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index d42e69578..c5478b17b 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml | |||
| @@ -7,11 +7,11 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32l4s5vi to your chip name, if necessary. | 8 | # Change stm32l4s5vi to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } | 15 | embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } |
| 16 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } | 16 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } |
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| @@ -28,7 +28,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | |||
| 28 | embedded-hal-async = { version = "1.0" } | 28 | embedded-hal-async = { version = "1.0" } |
| 29 | embedded-hal-bus = { version = "0.1", features = ["async"] } | 29 | embedded-hal-bus = { version = "0.1", features = ["async"] } |
| 30 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 30 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 31 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 32 | heapless = { version = "0.8", default-features = false } | 31 | heapless = { version = "0.8", default-features = false } |
| 33 | chrono = { version = "^0.4", default-features = false } | 32 | chrono = { version = "^0.4", default-features = false } |
| 34 | rand = { version = "0.8.5", default-features = false } | 33 | rand = { version = "0.8.5", default-features = false } |
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index d01e9f1b3..c557ac6d7 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs | |||
| @@ -3,28 +3,27 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::adc::{Adc, Resolution}; | 5 | use embassy_stm32::adc::{Adc, Resolution}; |
| 6 | use embassy_stm32::pac; | 6 | use embassy_stm32::Config; |
| 7 | use embassy_time::Delay; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 7 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 8 | ||
| 10 | #[cortex_m_rt::entry] | 9 | #[cortex_m_rt::entry] |
| 11 | fn main() -> ! { | 10 | fn main() -> ! { |
| 12 | info!("Hello World!"); | 11 | info!("Hello World!"); |
| 13 | 12 | ||
| 14 | pac::RCC.ccipr().modify(|w| { | 13 | let mut config = Config::default(); |
| 15 | w.set_adcsel(pac::rcc::vals::Adcsel::SYS); | 14 | { |
| 16 | }); | 15 | use embassy_stm32::rcc::*; |
| 17 | pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); | 16 | config.rcc.mux.adcsel = mux::Adcsel::SYS; |
| 18 | 17 | } | |
| 19 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(config); |
| 20 | 19 | ||
| 21 | let mut adc = Adc::new(p.ADC1, &mut Delay); | 20 | let mut adc = Adc::new(p.ADC1); |
| 22 | //adc.enable_vref(); | 21 | //adc.enable_vref(); |
| 23 | adc.set_resolution(Resolution::EightBit); | 22 | adc.set_resolution(Resolution::BITS8); |
| 24 | let mut channel = p.PC0; | 23 | let mut channel = p.PC0; |
| 25 | 24 | ||
| 26 | loop { | 25 | loop { |
| 27 | let v = adc.read(&mut channel); | 26 | let v = adc.blocking_read(&mut channel); |
| 28 | info!("--> {}", v); | 27 | info!("--> {}", v); |
| 29 | } | 28 | } |
| 30 | } | 29 | } |
diff --git a/examples/stm32l4/src/bin/can.rs b/examples/stm32l4/src/bin/can.rs new file mode 100644 index 000000000..3c4cdac24 --- /dev/null +++ b/examples/stm32l4/src/bin/can.rs | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::can::filter::Mask32; | ||
| 7 | use embassy_stm32::can::{ | ||
| 8 | Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, | ||
| 9 | }; | ||
| 10 | use embassy_stm32::peripherals::CAN1; | ||
| 11 | use embassy_stm32::{bind_interrupts, Config}; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | CAN1_RX0 => Rx0InterruptHandler<CAN1>; | ||
| 17 | CAN1_RX1 => Rx1InterruptHandler<CAN1>; | ||
| 18 | CAN1_SCE => SceInterruptHandler<CAN1>; | ||
| 19 | CAN1_TX => TxInterruptHandler<CAN1>; | ||
| 20 | }); | ||
| 21 | |||
| 22 | #[embassy_executor::main] | ||
| 23 | async fn main(_spawner: Spawner) { | ||
| 24 | let p = embassy_stm32::init(Config::default()); | ||
| 25 | |||
| 26 | let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); | ||
| 27 | |||
| 28 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 29 | |||
| 30 | can.modify_config() | ||
| 31 | .set_loopback(true) // Receive own frames | ||
| 32 | .set_silent(true) | ||
| 33 | .set_bitrate(250_000); | ||
| 34 | |||
| 35 | can.enable().await; | ||
| 36 | println!("CAN enabled"); | ||
| 37 | |||
| 38 | let mut i = 0; | ||
| 39 | let mut last_read_ts = embassy_time::Instant::now(); | ||
| 40 | loop { | ||
| 41 | let frame = Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 42 | info!("Writing frame"); | ||
| 43 | |||
| 44 | _ = can.write(&frame).await; | ||
| 45 | |||
| 46 | match can.read().await { | ||
| 47 | Ok(envelope) => { | ||
| 48 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 49 | let delta = (ts - last_read_ts).as_millis(); | ||
| 50 | last_read_ts = ts; | ||
| 51 | info!( | ||
| 52 | "Rx: {} {:02x} --- {}ms", | ||
| 53 | rx_frame.header().len(), | ||
| 54 | rx_frame.data()[0..rx_frame.header().len() as usize], | ||
| 55 | delta, | ||
| 56 | ) | ||
| 57 | } | ||
| 58 | Err(err) => error!("Error in frame: {}", err), | ||
| 59 | } | ||
| 60 | |||
| 61 | Timer::after_millis(250).await; | ||
| 62 | |||
| 63 | i += 1; | ||
| 64 | if i > 2 { | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index f227812cd..d01b016c0 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs | |||
| @@ -6,9 +6,9 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; | 6 | use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; |
| 7 | use embassy_stm32::pac::timer::vals::Mms; | 7 | use embassy_stm32::pac::timer::vals::Mms; |
| 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; | 8 | use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; |
| 9 | use embassy_stm32::rcc::low_level::RccPeripheral; | 9 | use embassy_stm32::rcc::frequency; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::timer::low_level::BasicInstance; | 11 | use embassy_stm32::timer::low_level::Timer; |
| 12 | use micromath::F32Ext; | 12 | use micromath::F32Ext; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| @@ -22,19 +22,19 @@ async fn main(spawner: Spawner) { | |||
| 22 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) | 22 | // Obtain two independent channels (p.DAC1 can only be consumed once, though!) |
| 23 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); | 23 | let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); |
| 24 | 24 | ||
| 25 | spawner.spawn(dac_task1(dac_ch1)).ok(); | 25 | spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok(); |
| 26 | spawner.spawn(dac_task2(dac_ch2)).ok(); | 26 | spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok(); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | #[embassy_executor::task] | 29 | #[embassy_executor::task] |
| 30 | async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | 30 | async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { |
| 31 | let data: &[u8; 256] = &calculate_array::<256>(); | 31 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 32 | 32 | ||
| 33 | info!("TIM6 frequency is {}", TIM6::frequency()); | 33 | info!("TIM6 frequency is {}", frequency::<TIM6>()); |
| 34 | const FREQUENCY: Hertz = Hertz::hz(200); | 34 | const FREQUENCY: Hertz = Hertz::hz(200); |
| 35 | 35 | ||
| 36 | // Compute the reload value such that we obtain the FREQUENCY for the sine | 36 | // Compute the reload value such that we obtain the FREQUENCY for the sine |
| 37 | let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; | 37 | let reload: u32 = (frequency::<TIM6>().0 / FREQUENCY.0) / data.len() as u32; |
| 38 | 38 | ||
| 39 | // Depends on your clock and on the specific chip used, you may need higher or lower values here | 39 | // Depends on your clock and on the specific chip used, you may need higher or lower values here |
| 40 | if reload < 10 { | 40 | if reload < 10 { |
| @@ -45,17 +45,17 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 45 | dac.set_triggering(true); | 45 | dac.set_triggering(true); |
| 46 | dac.enable(); | 46 | dac.enable(); |
| 47 | 47 | ||
| 48 | TIM6::enable_and_reset(); | 48 | let tim = Timer::new(tim); |
| 49 | TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 49 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 50 | TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 50 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 51 | TIM6::regs_basic().cr1().modify(|w| { | 51 | tim.regs_basic().cr1().modify(|w| { |
| 52 | w.set_opm(false); | 52 | w.set_opm(false); |
| 53 | w.set_cen(true); | 53 | w.set_cen(true); |
| 54 | }); | 54 | }); |
| 55 | 55 | ||
| 56 | debug!( | 56 | debug!( |
| 57 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 57 | "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 58 | TIM6::frequency(), | 58 | frequency::<TIM6>(), |
| 59 | FREQUENCY, | 59 | FREQUENCY, |
| 60 | reload, | 60 | reload, |
| 61 | reload as u16, | 61 | reload as u16, |
| @@ -70,22 +70,22 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | #[embassy_executor::task] | 72 | #[embassy_executor::task] |
| 73 | async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | 73 | async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { |
| 74 | let data: &[u8; 256] = &calculate_array::<256>(); | 74 | let data: &[u8; 256] = &calculate_array::<256>(); |
| 75 | 75 | ||
| 76 | info!("TIM7 frequency is {}", TIM7::frequency()); | 76 | info!("TIM7 frequency is {}", frequency::<TIM7>()); |
| 77 | 77 | ||
| 78 | const FREQUENCY: Hertz = Hertz::hz(600); | 78 | const FREQUENCY: Hertz = Hertz::hz(600); |
| 79 | let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; | 79 | let reload: u32 = (frequency::<TIM7>().0 / FREQUENCY.0) / data.len() as u32; |
| 80 | 80 | ||
| 81 | if reload < 10 { | 81 | if reload < 10 { |
| 82 | error!("Reload value {} below threshold!", reload); | 82 | error!("Reload value {} below threshold!", reload); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | TIM7::enable_and_reset(); | 85 | let tim = Timer::new(tim); |
| 86 | TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); | 86 | tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); |
| 87 | TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); | 87 | tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); |
| 88 | TIM7::regs_basic().cr1().modify(|w| { | 88 | tim.regs_basic().cr1().modify(|w| { |
| 89 | w.set_opm(false); | 89 | w.set_opm(false); |
| 90 | w.set_cen(true); | 90 | w.set_cen(true); |
| 91 | }); | 91 | }); |
| @@ -96,7 +96,7 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { | |||
| 96 | 96 | ||
| 97 | debug!( | 97 | debug!( |
| 98 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", | 98 | "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", |
| 99 | TIM7::frequency(), | 99 | frequency::<TIM7>(), |
| 100 | FREQUENCY, | 100 | FREQUENCY, |
| 101 | reload, | 101 | reload, |
| 102 | reload as u16, | 102 | reload as u16, |
diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs index f553deb82..2861bc091 100644 --- a/examples/stm32l4/src/bin/i2c.rs +++ b/examples/stm32l4/src/bin/i2c.rs | |||
| @@ -3,33 +3,17 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use embassy_stm32::i2c::I2c; | 6 | use embassy_stm32::i2c::I2c; |
| 8 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 9 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 9 | ||
| 12 | const ADDRESS: u8 = 0x5F; | 10 | const ADDRESS: u8 = 0x5F; |
| 13 | const WHOAMI: u8 = 0x0F; | 11 | const WHOAMI: u8 = 0x0F; |
| 14 | 12 | ||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||
| 17 | I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||
| 18 | }); | ||
| 19 | |||
| 20 | #[embassy_executor::main] | 13 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 14 | async fn main(_spawner: Spawner) { |
| 22 | let p = embassy_stm32::init(Default::default()); | 15 | let p = embassy_stm32::init(Default::default()); |
| 23 | let mut i2c = I2c::new( | 16 | let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); |
| 24 | p.I2C2, | ||
| 25 | p.PB10, | ||
| 26 | p.PB11, | ||
| 27 | Irqs, | ||
| 28 | NoDma, | ||
| 29 | NoDma, | ||
| 30 | Hertz(100_000), | ||
| 31 | Default::default(), | ||
| 32 | ); | ||
| 33 | 17 | ||
| 34 | let mut data = [0u8; 1]; | 18 | let mut data = [0u8; 1]; |
| 35 | unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); | 19 | unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); |
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs index 1b8652bcc..a014b23e0 100644 --- a/examples/stm32l4/src/bin/i2c_blocking_async.rs +++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs | |||
| @@ -4,34 +4,18 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_embedded_hal::adapter::BlockingAsync; | 5 | use embassy_embedded_hal::adapter::BlockingAsync; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::i2c::I2c; | 7 | use embassy_stm32::i2c::I2c; |
| 9 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | ||
| 11 | use embedded_hal_async::i2c::I2c as I2cTrait; | 9 | use embedded_hal_async::i2c::I2c as I2cTrait; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 11 | ||
| 14 | const ADDRESS: u8 = 0x5F; | 12 | const ADDRESS: u8 = 0x5F; |
| 15 | const WHOAMI: u8 = 0x0F; | 13 | const WHOAMI: u8 = 0x0F; |
| 16 | 14 | ||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||
| 19 | I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||
| 20 | }); | ||
| 21 | |||
| 22 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 23 | async fn main(_spawner: Spawner) { | 16 | async fn main(_spawner: Spawner) { |
| 24 | let p = embassy_stm32::init(Default::default()); | 17 | let p = embassy_stm32::init(Default::default()); |
| 25 | let i2c = I2c::new( | 18 | let i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); |
| 26 | p.I2C2, | ||
| 27 | p.PB10, | ||
| 28 | p.PB11, | ||
| 29 | Irqs, | ||
| 30 | NoDma, | ||
| 31 | NoDma, | ||
| 32 | Hertz(100_000), | ||
| 33 | Default::default(), | ||
| 34 | ); | ||
| 35 | let mut i2c = BlockingAsync::new(i2c); | 19 | let mut i2c = BlockingAsync::new(i2c); |
| 36 | 20 | ||
| 37 | let mut data = [0u8; 1]; | 21 | let mut data = [0u8; 1]; |
diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index 638b3e9e4..14d0e3c1e 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource}; | 6 | use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk}; |
| 7 | use embassy_stm32::rng::Rng; | 7 | use embassy_stm32::rng::Rng; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs { | |||
| 15 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 16 | async fn main(_spawner: Spawner) { | 16 | async fn main(_spawner: Spawner) { |
| 17 | let mut config = Config::default(); | 17 | let mut config = Config::default(); |
| 18 | config.rcc.mux = ClockSrc::PLL1_R; | 18 | config.rcc.sys = Sysclk::PLL1_R; |
| 19 | config.rcc.hsi = true; | 19 | config.rcc.hsi = true; |
| 20 | config.rcc.pll = Some(Pll { | 20 | config.rcc.pll = Some(Pll { |
| 21 | source: PllSource::HSI, | 21 | source: PllSource::HSI, |
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index 526620bfb..f554f0f78 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs | |||
| @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { | |||
| 15 | let mut config = Config::default(); | 15 | let mut config = Config::default(); |
| 16 | { | 16 | { |
| 17 | use embassy_stm32::rcc::*; | 17 | use embassy_stm32::rcc::*; |
| 18 | config.rcc.mux = ClockSrc::PLL1_R; | 18 | config.rcc.sys = Sysclk::PLL1_R; |
| 19 | config.rcc.hse = Some(Hse { | 19 | config.rcc.hse = Some(Hse { |
| 20 | freq: Hertz::mhz(8), | 20 | freq: Hertz::mhz(8), |
| 21 | mode: HseMode::Oscillator, | 21 | mode: HseMode::Oscillator, |
| @@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) { | |||
| 40 | .unwrap(); | 40 | .unwrap(); |
| 41 | 41 | ||
| 42 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 42 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 43 | info!("Got RTC! {:?}", now.timestamp()); | 43 | info!("Got RTC! {:?}", now.and_utc().timestamp()); |
| 44 | 44 | ||
| 45 | rtc.set_datetime(now.into()).expect("datetime not set"); | 45 | rtc.set_datetime(now.into()).expect("datetime not set"); |
| 46 | 46 | ||
| @@ -48,5 +48,5 @@ async fn main(_spawner: Spawner) { | |||
| 48 | Timer::after_millis(20000).await; | 48 | Timer::after_millis(20000).await; |
| 49 | 49 | ||
| 50 | let then: NaiveDateTime = rtc.now().unwrap().into(); | 50 | let then: NaiveDateTime = rtc.now().unwrap().into(); |
| 51 | info!("Got RTC! {:?}", then.timestamp()); | 51 | info!("Got RTC! {:?}", then.and_utc().timestamp()); |
| 52 | } | 52 | } |
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 026a3a477..be4270ada 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs | |||
| @@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either}; | |||
| 23 | use embassy_futures::yield_now; | 23 | use embassy_futures::yield_now; |
| 24 | use embassy_net::tcp::TcpSocket; | 24 | use embassy_net::tcp::TcpSocket; |
| 25 | use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; | 25 | use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; |
| 26 | use embassy_net_adin1110::{Device, Runner, ADIN1110}; | ||
| 27 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | ||
| 28 | use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; | ||
| 29 | use embassy_stm32::mode::Async; | ||
| 30 | use embassy_stm32::rng::{self, Rng}; | ||
| 31 | use embassy_stm32::spi::{Config as SPI_Config, Spi}; | ||
| 32 | use embassy_stm32::time::Hertz; | ||
| 33 | use embassy_stm32::{bind_interrupts, exti, pac, peripherals}; | ||
| 26 | use embassy_time::{Delay, Duration, Ticker, Timer}; | 34 | use embassy_time::{Delay, Duration, Ticker, Timer}; |
| 27 | use embedded_hal_async::i2c::I2c as I2cBus; | 35 | use embedded_hal_async::i2c::I2c as I2cBus; |
| 36 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 28 | use embedded_io::Write as bWrite; | 37 | use embedded_io::Write as bWrite; |
| 29 | use embedded_io_async::Write; | 38 | use embedded_io_async::Write; |
| 30 | use hal::gpio::{Input, Level, Output, Speed}; | ||
| 31 | use hal::i2c::{self, I2c}; | ||
| 32 | use hal::rng::{self, Rng}; | ||
| 33 | use hal::{bind_interrupts, exti, pac, peripherals}; | ||
| 34 | use heapless::Vec; | 39 | use heapless::Vec; |
| 40 | use panic_probe as _; | ||
| 35 | use rand::RngCore; | 41 | use rand::RngCore; |
| 36 | use static_cell::StaticCell; | 42 | use static_cell::StaticCell; |
| 37 | use {embassy_stm32 as hal, panic_probe as _}; | ||
| 38 | 43 | ||
| 39 | bind_interrupts!(struct Irqs { | 44 | bind_interrupts!(struct Irqs { |
| 40 | I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>; | 45 | I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>; |
| @@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs { | |||
| 42 | RNG => rng::InterruptHandler<peripherals::RNG>; | 47 | RNG => rng::InterruptHandler<peripherals::RNG>; |
| 43 | }); | 48 | }); |
| 44 | 49 | ||
| 45 | use embassy_net_adin1110::{self, Device, Runner, ADIN1110}; | ||
| 46 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 47 | use hal::gpio::Pull; | ||
| 48 | use hal::i2c::Config as I2C_Config; | ||
| 49 | use hal::spi::{Config as SPI_Config, Spi}; | ||
| 50 | use hal::time::Hertz; | ||
| 51 | |||
| 52 | // Basic settings | 50 | // Basic settings |
| 53 | // MAC-address used by the adin1110 | 51 | // MAC-address used by the adin1110 |
| 54 | const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; | 52 | const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; |
| @@ -57,12 +55,12 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); | |||
| 57 | // Listen port for the webserver | 55 | // Listen port for the webserver |
| 58 | const HTTP_LISTEN_PORT: u16 = 80; | 56 | const HTTP_LISTEN_PORT: u16 = 80; |
| 59 | 57 | ||
| 60 | pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; | 58 | pub type SpeSpi = Spi<'static, Async>; |
| 61 | pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; | 59 | pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; |
| 62 | pub type SpeInt = exti::ExtiInput<'static>; | 60 | pub type SpeInt = exti::ExtiInput<'static>; |
| 63 | pub type SpeRst = Output<'static>; | 61 | pub type SpeRst = Output<'static>; |
| 64 | pub type Adin1110T = ADIN1110<SpeSpiCs>; | 62 | pub type Adin1110T = ADIN1110<SpeSpiCs>; |
| 65 | pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; | 63 | pub type TempSensI2c = I2c<'static, Async>; |
| 66 | 64 | ||
| 67 | static TEMP: AtomicI32 = AtomicI32::new(0); | 65 | static TEMP: AtomicI32 = AtomicI32::new(0); |
| 68 | 66 | ||
| @@ -75,7 +73,7 @@ async fn main(spawner: Spawner) { | |||
| 75 | use embassy_stm32::rcc::*; | 73 | use embassy_stm32::rcc::*; |
| 76 | // 80Mhz clock (Source: 8 / SrcDiv: 1 * PllMul 20 / ClkDiv 2) | 74 | // 80Mhz clock (Source: 8 / SrcDiv: 1 * PllMul 20 / ClkDiv 2) |
| 77 | // 80MHz highest frequency for flash 0 wait. | 75 | // 80MHz highest frequency for flash 0 wait. |
| 78 | config.rcc.mux = ClockSrc::PLL1_R; | 76 | config.rcc.sys = Sysclk::PLL1_R; |
| 79 | config.rcc.hse = Some(Hse { | 77 | config.rcc.hse = Some(Hse { |
| 80 | freq: Hertz::mhz(8), | 78 | freq: Hertz::mhz(8), |
| 81 | mode: HseMode::Oscillator, | 79 | mode: HseMode::Oscillator, |
| @@ -93,12 +91,6 @@ async fn main(spawner: Spawner) { | |||
| 93 | 91 | ||
| 94 | let dp = embassy_stm32::init(config); | 92 | let dp = embassy_stm32::init(config); |
| 95 | 93 | ||
| 96 | // RM0432rev9, 5.1.2: Independent I/O supply rail | ||
| 97 | // After reset, the I/Os supplied by VDDIO2 are logically and electrically isolated and | ||
| 98 | // therefore are not available. The isolation must be removed before using any I/O from | ||
| 99 | // PG[15:2], by setting the IOSV bit in the PWR_CR2 register, once the VDDIO2 supply is present | ||
| 100 | pac::PWR.cr2().modify(|w| w.set_iosv(true)); | ||
| 101 | |||
| 102 | let reset_status = pac::RCC.bdcr().read().0; | 94 | let reset_status = pac::RCC.bdcr().read().0; |
| 103 | defmt::println!("bdcr before: 0x{:X}", reset_status); | 95 | defmt::println!("bdcr before: 0x{:X}", reset_status); |
| 104 | 96 | ||
| @@ -214,17 +206,11 @@ async fn main(spawner: Spawner) { | |||
| 214 | }; | 206 | }; |
| 215 | 207 | ||
| 216 | // Init network stack | 208 | // Init network stack |
| 217 | static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); | 209 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 218 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 210 | let (stack, runner) = embassy_net::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed); |
| 219 | let stack = &*STACK.init(Stack::new( | ||
| 220 | device, | ||
| 221 | ip_cfg, | ||
| 222 | RESOURCES.init(StackResources::<2>::new()), | ||
| 223 | seed, | ||
| 224 | )); | ||
| 225 | 211 | ||
| 226 | // Launch network task | 212 | // Launch network task |
| 227 | unwrap!(spawner.spawn(net_task(stack))); | 213 | unwrap!(spawner.spawn(net_task(runner))); |
| 228 | 214 | ||
| 229 | let cfg = wait_for_config(stack).await; | 215 | let cfg = wait_for_config(stack).await; |
| 230 | let local_addr = cfg.address.address(); | 216 | let local_addr = cfg.address.address(); |
| @@ -287,7 +273,7 @@ async fn main(spawner: Spawner) { | |||
| 287 | } | 273 | } |
| 288 | } | 274 | } |
| 289 | 275 | ||
| 290 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { | 276 | async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { |
| 291 | loop { | 277 | loop { |
| 292 | if let Some(config) = stack.config_v4() { | 278 | if let Some(config) = stack.config_v4() { |
| 293 | return config; | 279 | return config; |
| @@ -336,8 +322,8 @@ async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! { | |||
| 336 | } | 322 | } |
| 337 | 323 | ||
| 338 | #[embassy_executor::task] | 324 | #[embassy_executor::task] |
| 339 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | 325 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { |
| 340 | stack.run().await | 326 | runner.run().await |
| 341 | } | 327 | } |
| 342 | 328 | ||
| 343 | // same panicking *behavior* as `panic-probe` but doesn't print a panic message | 329 | // same panicking *behavior* as `panic-probe` but doesn't print a panic message |
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 6653e4516..5693a3765 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::dma::NoDma; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | 5 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 7 | use embassy_stm32::spi::{Config, Spi}; | 6 | use embassy_stm32::spi::{Config, Spi}; |
| 8 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| @@ -17,7 +16,7 @@ fn main() -> ! { | |||
| 17 | let mut spi_config = Config::default(); | 16 | let mut spi_config = Config::default(); |
| 18 | spi_config.frequency = Hertz(1_000_000); | 17 | spi_config.frequency = Hertz(1_000_000); |
| 19 | 18 | ||
| 20 | let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); | 19 | let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); |
| 21 | 20 | ||
| 22 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); | 21 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); |
| 23 | 22 | ||
diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs index 68dbb70ad..1f1089101 100644 --- a/examples/stm32l4/src/bin/spi_blocking_async.rs +++ b/examples/stm32l4/src/bin/spi_blocking_async.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_embedded_hal::adapter::BlockingAsync; | 5 | use embassy_embedded_hal::adapter::BlockingAsync; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | 7 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; |
| 9 | use embassy_stm32::spi::{Config, Spi}; | 8 | use embassy_stm32::spi::{Config, Spi}; |
| 10 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| @@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) { | |||
| 19 | let mut spi_config = Config::default(); | 18 | let mut spi_config = Config::default(); |
| 20 | spi_config.frequency = Hertz(1_000_000); | 19 | spi_config.frequency = Hertz(1_000_000); |
| 21 | 20 | ||
| 22 | let spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); | 21 | let spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); |
| 23 | 22 | ||
| 24 | let mut spi = BlockingAsync::new(spi); | 23 | let mut spi = BlockingAsync::new(spi); |
| 25 | 24 | ||
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 7bab23950..d9b388026 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_stm32::dma::NoDma; | ||
| 6 | use embassy_stm32::usart::{Config, Uart}; | 5 | use embassy_stm32::usart::{Config, Uart}; |
| 7 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 6 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 7 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -18,7 +17,7 @@ fn main() -> ! { | |||
| 18 | let p = embassy_stm32::init(Default::default()); | 17 | let p = embassy_stm32::init(Default::default()); |
| 19 | 18 | ||
| 20 | let config = Config::default(); | 19 | let config = Config::default(); |
| 21 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap(); | 20 | let mut usart = Uart::new_blocking(p.UART4, p.PA1, p.PA0, config).unwrap(); |
| 22 | 21 | ||
| 23 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 22 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 24 | info!("wrote Hello, starting echo"); | 23 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 031888f70..b4f7a1643 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs | |||
| @@ -5,7 +5,6 @@ use core::fmt::Write; | |||
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::dma::NoDma; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; |
| 11 | use heapless::String; | 10 | use heapless::String; |
| @@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) { | |||
| 21 | info!("Hello World!"); | 20 | info!("Hello World!"); |
| 22 | 21 | ||
| 23 | let config = Config::default(); | 22 | let config = Config::default(); |
| 24 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); | 23 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, p.DMA1_CH4, config).unwrap(); |
| 25 | 24 | ||
| 26 | for n in 0u32.. { | 25 | for n in 0u32.. { |
| 27 | let mut s: String<128> = String::new(); | 26 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 8cc9a7aed..c3b1211d8 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs | |||
| @@ -4,42 +4,55 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use defmt_rtt as _; // global logger | 5 | use defmt_rtt as _; // global logger |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rcc::*; | 7 | use embassy_futures::join::join; |
| 8 | use embassy_stm32::usb_otg::{Driver, Instance}; | 8 | use embassy_stm32::usb::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 11 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| 12 | use embassy_usb::Builder; | 12 | use embassy_usb::Builder; |
| 13 | use futures::future::join; | ||
| 14 | use panic_probe as _; | 13 | use panic_probe as _; |
| 15 | 14 | ||
| 16 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 17 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 18 | }); | 17 | }); |
| 19 | 18 | ||
| 19 | // If you are trying this and your USB device doesn't connect, the most | ||
| 20 | // common issues are the RCC config and vbus_detection | ||
| 21 | // | ||
| 22 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 23 | // for more information. | ||
| 20 | #[embassy_executor::main] | 24 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 25 | async fn main(_spawner: Spawner) { |
| 22 | info!("Hello World!"); | 26 | info!("Hello World!"); |
| 23 | 27 | ||
| 24 | let mut config = Config::default(); | 28 | let mut config = Config::default(); |
| 25 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | 29 | { |
| 26 | config.rcc.mux = ClockSrc::PLL1_R; | 30 | use embassy_stm32::rcc::*; |
| 27 | config.rcc.hsi = true; | 31 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB |
| 28 | config.rcc.pll = Some(Pll { | 32 | config.rcc.sys = Sysclk::PLL1_R; |
| 29 | source: PllSource::HSI, | 33 | config.rcc.hsi = true; |
| 30 | prediv: PllPreDiv::DIV1, | 34 | config.rcc.pll = Some(Pll { |
| 31 | mul: PllMul::MUL10, | 35 | source: PllSource::HSI, |
| 32 | divp: None, | 36 | prediv: PllPreDiv::DIV1, |
| 33 | divq: None, | 37 | mul: PllMul::MUL10, |
| 34 | divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) | 38 | divp: None, |
| 35 | }); | 39 | divq: None, |
| 36 | 40 | divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) | |
| 41 | }); | ||
| 42 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 43 | } | ||
| 37 | let p = embassy_stm32::init(config); | 44 | let p = embassy_stm32::init(config); |
| 38 | 45 | ||
| 39 | // Create the driver, from the HAL. | 46 | // Create the driver, from the HAL. |
| 40 | let mut ep_out_buffer = [0u8; 256]; | 47 | let mut ep_out_buffer = [0u8; 256]; |
| 41 | let mut config = embassy_stm32::usb_otg::Config::default(); | 48 | let mut config = embassy_stm32::usb::Config::default(); |
| 42 | config.vbus_detection = true; | 49 | |
| 50 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 51 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 52 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 53 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 54 | config.vbus_detection = false; | ||
| 55 | |||
| 43 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 56 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 44 | 57 | ||
| 45 | // Create embassy-usb Config | 58 | // Create embassy-usb Config |
| @@ -58,7 +71,6 @@ async fn main(_spawner: Spawner) { | |||
| 58 | 71 | ||
| 59 | // Create embassy-usb DeviceBuilder using the driver and config. | 72 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 60 | // It needs some buffers for building the descriptors. | 73 | // It needs some buffers for building the descriptors. |
| 61 | let mut device_descriptor = [0; 256]; | ||
| 62 | let mut config_descriptor = [0; 256]; | 74 | let mut config_descriptor = [0; 256]; |
| 63 | let mut bos_descriptor = [0; 256]; | 75 | let mut bos_descriptor = [0; 256]; |
| 64 | let mut control_buf = [0; 64]; | 76 | let mut control_buf = [0; 64]; |
| @@ -68,7 +80,6 @@ async fn main(_spawner: Spawner) { | |||
| 68 | let mut builder = Builder::new( | 80 | let mut builder = Builder::new( |
| 69 | driver, | 81 | driver, |
| 70 | config, | 82 | config, |
| 71 | &mut device_descriptor, | ||
| 72 | &mut config_descriptor, | 83 | &mut config_descriptor, |
| 73 | &mut bos_descriptor, | 84 | &mut bos_descriptor, |
| 74 | &mut [], // no msos descriptors | 85 | &mut [], // no msos descriptors |
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 0c6beb72c..16c184de2 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml | |||
| @@ -7,13 +7,13 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32l552ze to your chip name, if necessary. | 8 | # Change stm32l552ze to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } |
| 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 16 | usbd-hid = "0.6.0" | 16 | usbd-hid = "0.8.1" |
| 17 | 17 | ||
| 18 | defmt = "0.3" | 18 | defmt = "0.3" |
| 19 | defmt-rtt = "0.4" | 19 | defmt-rtt = "0.4" |
| @@ -22,7 +22,6 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } | |||
| 22 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 22 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 23 | cortex-m-rt = "0.7.0" | 23 | cortex-m-rt = "0.7.0" |
| 24 | embedded-hal = "0.2.6" | 24 | embedded-hal = "0.2.6" |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 26 | heapless = { version = "0.8", default-features = false } | 25 | heapless = { version = "0.8", default-features = false } |
| 27 | rand_core = { version = "0.6.3", default-features = false } | 26 | rand_core = { version = "0.6.3", default-features = false } |
| 28 | embedded-io-async = { version = "0.6.1" } | 27 | embedded-io-async = { version = "0.6.1" } |
diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs index 50da6c946..0a644e73d 100644 --- a/examples/stm32l5/src/bin/rng.rs +++ b/examples/stm32l5/src/bin/rng.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::rcc::{ClockSrc, Pll, PllMul, PllPreDiv, PllRDiv, PllSource}; | 6 | use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, PllSource, Sysclk}; |
| 7 | use embassy_stm32::rng::Rng; | 7 | use embassy_stm32::rng::Rng; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs { | |||
| 16 | async fn main(_spawner: Spawner) { | 16 | async fn main(_spawner: Spawner) { |
| 17 | let mut config = Config::default(); | 17 | let mut config = Config::default(); |
| 18 | config.rcc.hsi = true; | 18 | config.rcc.hsi = true; |
| 19 | config.rcc.mux = ClockSrc::PLL1_R; | 19 | config.rcc.sys = Sysclk::PLL1_R; |
| 20 | config.rcc.pll = Some(Pll { | 20 | config.rcc.pll = Some(Pll { |
| 21 | // 64Mhz clock (16 / 1 * 8 / 2) | 21 | // 64Mhz clock (16 / 1 * 8 / 2) |
| 22 | source: PllSource::HSI, | 22 | source: PllSource::HSI, |
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 88060b6b0..095d50c73 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs | |||
| @@ -4,8 +4,7 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | 7 | use embassy_net::StackResources; |
| 8 | use embassy_stm32::rcc::*; | ||
| 9 | use embassy_stm32::rng::Rng; | 8 | use embassy_stm32::rng::Rng; |
| 10 | use embassy_stm32::usb::Driver; | 9 | use embassy_stm32::usb::Driver; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; | 10 | use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; |
| @@ -37,24 +36,29 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { | |||
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | #[embassy_executor::task] | 38 | #[embassy_executor::task] |
| 40 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 39 | async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { |
| 41 | stack.run().await | 40 | runner.run().await |
| 42 | } | 41 | } |
| 43 | 42 | ||
| 44 | #[embassy_executor::main] | 43 | #[embassy_executor::main] |
| 45 | async fn main(spawner: Spawner) { | 44 | async fn main(spawner: Spawner) { |
| 46 | let mut config = Config::default(); | 45 | let mut config = Config::default(); |
| 47 | config.rcc.hsi = true; | 46 | { |
| 48 | config.rcc.mux = ClockSrc::PLL1_R; | 47 | use embassy_stm32::rcc::*; |
| 49 | config.rcc.pll = Some(Pll { | 48 | config.rcc.hsi = true; |
| 50 | // 80Mhz clock (16 / 1 * 10 / 2) | 49 | config.rcc.sys = Sysclk::PLL1_R; |
| 51 | source: PllSource::HSI, | 50 | config.rcc.pll = Some(Pll { |
| 52 | prediv: PllPreDiv::DIV1, | 51 | // 80Mhz clock (16 / 1 * 10 / 2) |
| 53 | mul: PllMul::MUL10, | 52 | source: PllSource::HSI, |
| 54 | divp: None, | 53 | prediv: PllPreDiv::DIV1, |
| 55 | divq: None, | 54 | mul: PllMul::MUL10, |
| 56 | divr: Some(PllRDiv::DIV2), | 55 | divp: None, |
| 57 | }); | 56 | divq: None, |
| 57 | divr: Some(PllRDiv::DIV2), | ||
| 58 | }); | ||
| 59 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 60 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 61 | } | ||
| 58 | let p = embassy_stm32::init(config); | 62 | let p = embassy_stm32::init(config); |
| 59 | 63 | ||
| 60 | // Create the driver, from the HAL. | 64 | // Create the driver, from the HAL. |
| @@ -75,14 +79,12 @@ async fn main(spawner: Spawner) { | |||
| 75 | config.device_protocol = 0x01; | 79 | config.device_protocol = 0x01; |
| 76 | 80 | ||
| 77 | // Create embassy-usb DeviceBuilder using the driver and config. | 81 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 78 | static DEVICE_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | ||
| 79 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 82 | static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 80 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); | 83 | static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); |
| 81 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); | 84 | static CONTROL_BUF: StaticCell<[u8; 128]> = StaticCell::new(); |
| 82 | let mut builder = Builder::new( | 85 | let mut builder = Builder::new( |
| 83 | driver, | 86 | driver, |
| 84 | config, | 87 | config, |
| 85 | &mut DEVICE_DESC.init([0; 256])[..], | ||
| 86 | &mut CONFIG_DESC.init([0; 256])[..], | 88 | &mut CONFIG_DESC.init([0; 256])[..], |
| 87 | &mut BOS_DESC.init([0; 256])[..], | 89 | &mut BOS_DESC.init([0; 256])[..], |
| 88 | &mut [], // no msos descriptors | 90 | &mut [], // no msos descriptors |
| @@ -119,16 +121,10 @@ async fn main(spawner: Spawner) { | |||
| 119 | let seed = rng.next_u64(); | 121 | let seed = rng.next_u64(); |
| 120 | 122 | ||
| 121 | // Init network stack | 123 | // Init network stack |
| 122 | static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); | 124 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 123 | static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); | 125 | let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); |
| 124 | let stack = &*STACK.init(Stack::new( | ||
| 125 | device, | ||
| 126 | config, | ||
| 127 | RESOURCES.init(StackResources::<2>::new()), | ||
| 128 | seed, | ||
| 129 | )); | ||
| 130 | 126 | ||
| 131 | unwrap!(spawner.spawn(net_task(stack))); | 127 | unwrap!(spawner.spawn(net_task(runner))); |
| 132 | 128 | ||
| 133 | // And now we can use it! | 129 | // And now we can use it! |
| 134 | 130 | ||
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 7c8a8ebfb..3f8c52b82 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::rcc::*; | ||
| 8 | use embassy_stm32::usb::Driver; | 7 | use embassy_stm32::usb::Driver; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 10 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| @@ -21,17 +20,22 @@ bind_interrupts!(struct Irqs { | |||
| 21 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 22 | async fn main(_spawner: Spawner) { | 21 | async fn main(_spawner: Spawner) { |
| 23 | let mut config = Config::default(); | 22 | let mut config = Config::default(); |
| 24 | config.rcc.hsi = true; | 23 | { |
| 25 | config.rcc.mux = ClockSrc::PLL1_R; | 24 | use embassy_stm32::rcc::*; |
| 26 | config.rcc.pll = Some(Pll { | 25 | config.rcc.hsi = true; |
| 27 | // 80Mhz clock (16 / 1 * 10 / 2) | 26 | config.rcc.sys = Sysclk::PLL1_R; |
| 28 | source: PllSource::HSI, | 27 | config.rcc.pll = Some(Pll { |
| 29 | prediv: PllPreDiv::DIV1, | 28 | // 80Mhz clock (16 / 1 * 10 / 2) |
| 30 | mul: PllMul::MUL10, | 29 | source: PllSource::HSI, |
| 31 | divp: None, | 30 | prediv: PllPreDiv::DIV1, |
| 32 | divq: None, | 31 | mul: PllMul::MUL10, |
| 33 | divr: Some(PllRDiv::DIV2), | 32 | divp: None, |
| 34 | }); | 33 | divq: None, |
| 34 | divr: Some(PllRDiv::DIV2), | ||
| 35 | }); | ||
| 36 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 37 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 38 | } | ||
| 35 | let p = embassy_stm32::init(config); | 39 | let p = embassy_stm32::init(config); |
| 36 | 40 | ||
| 37 | // Create the driver, from the HAL. | 41 | // Create the driver, from the HAL. |
| @@ -47,18 +51,16 @@ async fn main(_spawner: Spawner) { | |||
| 47 | 51 | ||
| 48 | // Create embassy-usb DeviceBuilder using the driver and config. | 52 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 49 | // It needs some buffers for building the descriptors. | 53 | // It needs some buffers for building the descriptors. |
| 50 | let mut device_descriptor = [0; 256]; | ||
| 51 | let mut config_descriptor = [0; 256]; | 54 | let mut config_descriptor = [0; 256]; |
| 52 | let mut bos_descriptor = [0; 256]; | 55 | let mut bos_descriptor = [0; 256]; |
| 53 | let mut control_buf = [0; 64]; | 56 | let mut control_buf = [0; 64]; |
| 54 | let request_handler = MyRequestHandler {}; | 57 | let mut request_handler = MyRequestHandler {}; |
| 55 | 58 | ||
| 56 | let mut state = State::new(); | 59 | let mut state = State::new(); |
| 57 | 60 | ||
| 58 | let mut builder = Builder::new( | 61 | let mut builder = Builder::new( |
| 59 | driver, | 62 | driver, |
| 60 | config, | 63 | config, |
| 61 | &mut device_descriptor, | ||
| 62 | &mut config_descriptor, | 64 | &mut config_descriptor, |
| 63 | &mut bos_descriptor, | 65 | &mut bos_descriptor, |
| 64 | &mut [], // no msos descriptors | 66 | &mut [], // no msos descriptors |
| @@ -68,7 +70,7 @@ async fn main(_spawner: Spawner) { | |||
| 68 | // Create classes on the builder. | 70 | // Create classes on the builder. |
| 69 | let config = embassy_usb::class::hid::Config { | 71 | let config = embassy_usb::class::hid::Config { |
| 70 | report_descriptor: MouseReport::desc(), | 72 | report_descriptor: MouseReport::desc(), |
| 71 | request_handler: Some(&request_handler), | 73 | request_handler: Some(&mut request_handler), |
| 72 | poll_ms: 60, | 74 | poll_ms: 60, |
| 73 | max_packet_size: 8, | 75 | max_packet_size: 8, |
| 74 | }; | 76 | }; |
| @@ -110,21 +112,21 @@ async fn main(_spawner: Spawner) { | |||
| 110 | struct MyRequestHandler {} | 112 | struct MyRequestHandler {} |
| 111 | 113 | ||
| 112 | impl RequestHandler for MyRequestHandler { | 114 | impl RequestHandler for MyRequestHandler { |
| 113 | fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { | 115 | fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> { |
| 114 | info!("Get report for {:?}", id); | 116 | info!("Get report for {:?}", id); |
| 115 | None | 117 | None |
| 116 | } | 118 | } |
| 117 | 119 | ||
| 118 | fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { | 120 | fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { |
| 119 | info!("Set report for {:?}: {=[u8]}", id, data); | 121 | info!("Set report for {:?}: {=[u8]}", id, data); |
| 120 | OutResponse::Accepted | 122 | OutResponse::Accepted |
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) { | 125 | fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { |
| 124 | info!("Set idle rate for {:?} to {:?}", id, dur); | 126 | info!("Set idle rate for {:?} to {:?}", id, dur); |
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> { | 129 | fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> { |
| 128 | info!("Get idle rate for {:?}", id); | 130 | info!("Get idle rate for {:?}", id); |
| 129 | None | 131 | None |
| 130 | } | 132 | } |
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 75053ce4b..a64bda31b 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::rcc::*; | ||
| 8 | use embassy_stm32::usb::{Driver, Instance}; | 7 | use embassy_stm32::usb::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| @@ -19,17 +18,22 @@ bind_interrupts!(struct Irqs { | |||
| 19 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) { | 19 | async fn main(_spawner: Spawner) { |
| 21 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 22 | config.rcc.hsi = true; | 21 | { |
| 23 | config.rcc.mux = ClockSrc::PLL1_R; | 22 | use embassy_stm32::rcc::*; |
| 24 | config.rcc.pll = Some(Pll { | 23 | config.rcc.hsi = true; |
| 25 | // 80Mhz clock (16 / 1 * 10 / 2) | 24 | config.rcc.sys = Sysclk::PLL1_R; |
| 26 | source: PllSource::HSI, | 25 | config.rcc.pll = Some(Pll { |
| 27 | prediv: PllPreDiv::DIV1, | 26 | // 80Mhz clock (16 / 1 * 10 / 2) |
| 28 | mul: PllMul::MUL10, | 27 | source: PllSource::HSI, |
| 29 | divp: None, | 28 | prediv: PllPreDiv::DIV1, |
| 30 | divq: None, | 29 | mul: PllMul::MUL10, |
| 31 | divr: Some(PllRDiv::DIV2), | 30 | divp: None, |
| 32 | }); | 31 | divq: None, |
| 32 | divr: Some(PllRDiv::DIV2), | ||
| 33 | }); | ||
| 34 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 35 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; | ||
| 36 | } | ||
| 33 | let p = embassy_stm32::init(config); | 37 | let p = embassy_stm32::init(config); |
| 34 | 38 | ||
| 35 | info!("Hello World!"); | 39 | info!("Hello World!"); |
| @@ -43,7 +47,6 @@ async fn main(_spawner: Spawner) { | |||
| 43 | 47 | ||
| 44 | // Create embassy-usb DeviceBuilder using the driver and config. | 48 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 45 | // It needs some buffers for building the descriptors. | 49 | // It needs some buffers for building the descriptors. |
| 46 | let mut device_descriptor = [0; 256]; | ||
| 47 | let mut config_descriptor = [0; 256]; | 50 | let mut config_descriptor = [0; 256]; |
| 48 | let mut bos_descriptor = [0; 256]; | 51 | let mut bos_descriptor = [0; 256]; |
| 49 | let mut control_buf = [0; 7]; | 52 | let mut control_buf = [0; 7]; |
| @@ -53,7 +56,6 @@ async fn main(_spawner: Spawner) { | |||
| 53 | let mut builder = Builder::new( | 56 | let mut builder = Builder::new( |
| 54 | driver, | 57 | driver, |
| 55 | config, | 58 | config, |
| 56 | &mut device_descriptor, | ||
| 57 | &mut config_descriptor, | 59 | &mut config_descriptor, |
| 58 | &mut bos_descriptor, | 60 | &mut bos_descriptor, |
| 59 | &mut [], // no msos descriptors | 61 | &mut [], // no msos descriptors |
diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml new file mode 100644 index 000000000..688347084 --- /dev/null +++ b/examples/stm32u0/.cargo/config.toml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace stm32u083rctx with your chip as listed in `probe-rs chip list` | ||
| 3 | runner = "probe-rs run --chip stm32u083rctx" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv6m-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml new file mode 100644 index 000000000..2e890cdb5 --- /dev/null +++ b/examples/stm32u0/Cargo.toml | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32u0-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | # Change stm32u083rc to your chip name, if necessary. | ||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } | ||
| 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | ||
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } | ||
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 15 | |||
| 16 | defmt = "0.3" | ||
| 17 | defmt-rtt = "0.4" | ||
| 18 | |||
| 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | ||
| 20 | cortex-m-rt = "0.7.0" | ||
| 21 | embedded-hal = "0.2.6" | ||
| 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 23 | heapless = { version = "0.8", default-features = false } | ||
| 24 | |||
| 25 | micromath = "2.0.0" | ||
| 26 | chrono = { version = "0.4.38", default-features = false } | ||
| 27 | |||
| 28 | [profile.release] | ||
| 29 | debug = 2 | ||
diff --git a/examples/stm32u0/build.rs b/examples/stm32u0/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32u0/build.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | fn main() { | ||
| 2 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 3 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 4 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 5 | } | ||
diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs new file mode 100644 index 000000000..c8252e4e1 --- /dev/null +++ b/examples/stm32u0/src/bin/adc.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_stm32::adc::{Adc, Resolution}; | ||
| 6 | use embassy_stm32::Config; | ||
| 7 | use embassy_time::Duration; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[cortex_m_rt::entry] | ||
| 11 | fn main() -> ! { | ||
| 12 | info!("Hello World!"); | ||
| 13 | |||
| 14 | let mut config = Config::default(); | ||
| 15 | { | ||
| 16 | use embassy_stm32::rcc::*; | ||
| 17 | config.rcc.mux.adcsel = mux::Adcsel::SYS; | ||
| 18 | } | ||
| 19 | let p = embassy_stm32::init(config); | ||
| 20 | |||
| 21 | let mut adc = Adc::new(p.ADC1); | ||
| 22 | adc.set_resolution(Resolution::BITS8); | ||
| 23 | let mut channel = p.PC0; | ||
| 24 | |||
| 25 | loop { | ||
| 26 | let v = adc.blocking_read(&mut channel); | ||
| 27 | info!("--> {}", v); | ||
| 28 | embassy_time::block_for(Duration::from_millis(200)); | ||
| 29 | } | ||
| 30 | } | ||
diff --git a/examples/stm32u0/src/bin/blinky.rs b/examples/stm32u0/src/bin/blinky.rs new file mode 100644 index 000000000..90e479aae --- /dev/null +++ b/examples/stm32u0/src/bin/blinky.rs | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let mut led = Output::new(p.PA5, Level::High, Speed::Low); | ||
| 16 | |||
| 17 | loop { | ||
| 18 | info!("high"); | ||
| 19 | led.set_high(); | ||
| 20 | Timer::after_millis(300).await; | ||
| 21 | |||
| 22 | info!("low"); | ||
| 23 | led.set_low(); | ||
| 24 | Timer::after_millis(300).await; | ||
| 25 | } | ||
| 26 | } | ||
diff --git a/examples/stm32u0/src/bin/button.rs b/examples/stm32u0/src/bin/button.rs new file mode 100644 index 000000000..8017f0274 --- /dev/null +++ b/examples/stm32u0/src/bin/button.rs | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use cortex_m_rt::entry; | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_stm32::gpio::{Input, Pull}; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[entry] | ||
| 10 | fn main() -> ! { | ||
| 11 | info!("Hello World!"); | ||
| 12 | |||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | |||
| 15 | let button = Input::new(p.PC13, Pull::Up); | ||
| 16 | |||
| 17 | loop { | ||
| 18 | if button.is_high() { | ||
| 19 | info!("high"); | ||
| 20 | } else { | ||
| 21 | info!("low"); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | } | ||
diff --git a/examples/stm32u0/src/bin/button_exti.rs b/examples/stm32u0/src/bin/button_exti.rs new file mode 100644 index 000000000..34a08bbc6 --- /dev/null +++ b/examples/stm32u0/src/bin/button_exti.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::exti::ExtiInput; | ||
| 7 | use embassy_stm32::gpio::Pull; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); | ||
| 16 | |||
| 17 | info!("Press the USER button..."); | ||
| 18 | |||
| 19 | loop { | ||
| 20 | button.wait_for_falling_edge().await; | ||
| 21 | info!("Pressed!"); | ||
| 22 | button.wait_for_rising_edge().await; | ||
| 23 | info!("Released!"); | ||
| 24 | } | ||
| 25 | } | ||
diff --git a/examples/stm32u0/src/bin/crc.rs b/examples/stm32u0/src/bin/crc.rs new file mode 100644 index 000000000..d1b545d5b --- /dev/null +++ b/examples/stm32u0/src/bin/crc.rs | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize}; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = embassy_stm32::init(Default::default()); | ||
| 12 | info!("Hello World!"); | ||
| 13 | |||
| 14 | // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0 | ||
| 15 | let mut crc = Crc::new( | ||
| 16 | p.CRC, | ||
| 17 | unwrap!(Config::new( | ||
| 18 | InputReverseConfig::Byte, | ||
| 19 | true, | ||
| 20 | PolySize::Width32, | ||
| 21 | 0xFFFFFFFF, | ||
| 22 | 0x04C11DB7 | ||
| 23 | )), | ||
| 24 | ); | ||
| 25 | |||
| 26 | let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF; | ||
| 27 | |||
| 28 | defmt::assert_eq!(output, 0x33F0E26B); | ||
| 29 | |||
| 30 | cortex_m::asm::bkpt(); | ||
| 31 | } | ||
diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs new file mode 100644 index 000000000..fdbf1d374 --- /dev/null +++ b/examples/stm32u0/src/bin/dac.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_stm32::dac::{DacCh1, Value}; | ||
| 6 | use embassy_stm32::dma::NoDma; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[cortex_m_rt::entry] | ||
| 10 | fn main() -> ! { | ||
| 11 | let p = embassy_stm32::init(Default::default()); | ||
| 12 | info!("Hello World!"); | ||
| 13 | |||
| 14 | let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); | ||
| 15 | |||
| 16 | loop { | ||
| 17 | for v in 0..=255 { | ||
| 18 | dac.set(Value::Bit8(to_sine_wave(v))); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | use micromath::F32Ext; | ||
| 24 | |||
| 25 | fn to_sine_wave(v: u8) -> u8 { | ||
| 26 | if v >= 128 { | ||
| 27 | // top half | ||
| 28 | let r = 3.14 * ((v - 128) as f32 / 128.0); | ||
| 29 | (r.sin() * 128.0 + 127.0) as u8 | ||
| 30 | } else { | ||
| 31 | // bottom half | ||
| 32 | let r = 3.14 + 3.14 * (v as f32 / 128.0); | ||
| 33 | (r.sin() * 128.0 + 127.0) as u8 | ||
| 34 | } | ||
| 35 | } | ||
diff --git a/examples/stm32u0/src/bin/flash.rs b/examples/stm32u0/src/bin/flash.rs new file mode 100644 index 000000000..01b80a76b --- /dev/null +++ b/examples/stm32u0/src/bin/flash.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::flash::Flash; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async fn main(_spawner: Spawner) { | ||
| 11 | let p = embassy_stm32::init(Default::default()); | ||
| 12 | info!("Hello World!"); | ||
| 13 | |||
| 14 | let addr: u32 = 0x40000 - 2 * 1024; | ||
| 15 | |||
| 16 | let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; | ||
| 17 | |||
| 18 | info!("Reading..."); | ||
| 19 | let mut buf = [0u8; 32]; | ||
| 20 | unwrap!(f.blocking_read(addr, &mut buf)); | ||
| 21 | info!("Read: {=[u8]:x}", buf); | ||
| 22 | info!("Erasing..."); | ||
| 23 | unwrap!(f.blocking_erase(addr, addr + 2 * 1024)); | ||
| 24 | |||
| 25 | info!("Reading..."); | ||
| 26 | let mut buf = [0u8; 32]; | ||
| 27 | unwrap!(f.blocking_read(addr, &mut buf)); | ||
| 28 | info!("Read after erase: {=[u8]:x}", buf); | ||
| 29 | |||
| 30 | info!("Writing..."); | ||
| 31 | unwrap!(f.blocking_write( | ||
| 32 | addr, | ||
| 33 | &[ | ||
| 34 | 1, 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, | ||
| 35 | 30, 31, 32 | ||
| 36 | ] | ||
| 37 | )); | ||
| 38 | |||
| 39 | info!("Reading..."); | ||
| 40 | let mut buf = [0u8; 32]; | ||
| 41 | unwrap!(f.blocking_read(addr, &mut buf)); | ||
| 42 | info!("Read: {=[u8]:x}", buf); | ||
| 43 | } | ||
diff --git a/examples/stm32u0/src/bin/i2c.rs b/examples/stm32u0/src/bin/i2c.rs new file mode 100644 index 000000000..2861bc091 --- /dev/null +++ b/examples/stm32u0/src/bin/i2c.rs | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::i2c::I2c; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | const ADDRESS: u8 = 0x5F; | ||
| 11 | const WHOAMI: u8 = 0x0F; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let p = embassy_stm32::init(Default::default()); | ||
| 16 | let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); | ||
| 17 | |||
| 18 | let mut data = [0u8; 1]; | ||
| 19 | unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); | ||
| 20 | info!("Whoami: {}", data[0]); | ||
| 21 | } | ||
diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs new file mode 100644 index 000000000..89445b042 --- /dev/null +++ b/examples/stm32u0/src/bin/rng.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::rcc::mux::Clk48sel; | ||
| 7 | use embassy_stm32::rng::Rng; | ||
| 8 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | RNG_CRYP => rng::InterruptHandler<peripherals::RNG>; | ||
| 13 | }); | ||
| 14 | |||
| 15 | #[embassy_executor::main] | ||
| 16 | async fn main(_spawner: Spawner) { | ||
| 17 | let mut config = Config::default(); | ||
| 18 | { | ||
| 19 | use embassy_stm32::rcc::*; | ||
| 20 | config.rcc.hsi = true; | ||
| 21 | config.rcc.pll = Some(Pll { | ||
| 22 | source: PllSource::HSI, // 16 MHz | ||
| 23 | prediv: PllPreDiv::DIV1, | ||
| 24 | mul: PllMul::MUL7, // 16 * 7 = 112 MHz | ||
| 25 | divp: None, | ||
| 26 | divq: None, | ||
| 27 | divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz | ||
| 28 | }); | ||
| 29 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 30 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: false }); // needed for RNG | ||
| 31 | config.rcc.mux.clk48sel = Clk48sel::HSI48; // needed for RNG (or use MSI or PLLQ if you want) | ||
| 32 | } | ||
| 33 | |||
| 34 | let p = embassy_stm32::init(config); | ||
| 35 | |||
| 36 | info!("Hello World!"); | ||
| 37 | |||
| 38 | let mut rng = Rng::new(p.RNG, Irqs); | ||
| 39 | |||
| 40 | let mut buf = [0u8; 16]; | ||
| 41 | unwrap!(rng.async_fill_bytes(&mut buf).await); | ||
| 42 | info!("random bytes: {:02x}", buf); | ||
| 43 | } | ||
diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs new file mode 100644 index 000000000..72fa0fde4 --- /dev/null +++ b/examples/stm32u0/src/bin/rtc.rs | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use chrono::{NaiveDate, NaiveDateTime}; | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 8 | use embassy_stm32::Config; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let mut config = Config::default(); | ||
| 15 | { | ||
| 16 | use embassy_stm32::rcc::*; | ||
| 17 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 18 | config.rcc.hsi = true; | ||
| 19 | config.rcc.pll = Some(Pll { | ||
| 20 | source: PllSource::HSI, // 16 MHz | ||
| 21 | prediv: PllPreDiv::DIV1, | ||
| 22 | mul: PllMul::MUL7, // 16 * 7 = 112 MHz | ||
| 23 | divp: None, | ||
| 24 | divq: None, | ||
| 25 | divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz | ||
| 26 | }); | ||
| 27 | config.rcc.ls = LsConfig::default(); | ||
| 28 | } | ||
| 29 | |||
| 30 | let p = embassy_stm32::init(config); | ||
| 31 | |||
| 32 | info!("Hello World!"); | ||
| 33 | |||
| 34 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) | ||
| 35 | .unwrap() | ||
| 36 | .and_hms_opt(10, 30, 15) | ||
| 37 | .unwrap(); | ||
| 38 | |||
| 39 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 40 | info!("Got RTC! {:?}", now.and_utc().timestamp()); | ||
| 41 | |||
| 42 | rtc.set_datetime(now.into()).expect("datetime not set"); | ||
| 43 | |||
| 44 | // In reality the delay would be much longer | ||
| 45 | Timer::after_millis(20000).await; | ||
| 46 | |||
| 47 | let then: NaiveDateTime = rtc.now().unwrap().into(); | ||
| 48 | info!("Got RTC! {:?}", then.and_utc().timestamp()); | ||
| 49 | } | ||
diff --git a/examples/stm32u0/src/bin/spi.rs b/examples/stm32u0/src/bin/spi.rs new file mode 100644 index 000000000..5693a3765 --- /dev/null +++ b/examples/stm32u0/src/bin/spi.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 6 | use embassy_stm32::spi::{Config, Spi}; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[cortex_m_rt::entry] | ||
| 11 | fn main() -> ! { | ||
| 12 | info!("Hello World!"); | ||
| 13 | |||
| 14 | let p = embassy_stm32::init(Default::default()); | ||
| 15 | |||
| 16 | let mut spi_config = Config::default(); | ||
| 17 | spi_config.frequency = Hertz(1_000_000); | ||
| 18 | |||
| 19 | let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); | ||
| 20 | |||
| 21 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); | ||
| 22 | |||
| 23 | loop { | ||
| 24 | let mut buf = [0x0Au8; 4]; | ||
| 25 | cs.set_low(); | ||
| 26 | unwrap!(spi.blocking_transfer_in_place(&mut buf)); | ||
| 27 | cs.set_high(); | ||
| 28 | info!("xfer {=[u8]:x}", buf); | ||
| 29 | } | ||
| 30 | } | ||
diff --git a/examples/stm32u0/src/bin/usart.rs b/examples/stm32u0/src/bin/usart.rs new file mode 100644 index 000000000..037a5c833 --- /dev/null +++ b/examples/stm32u0/src/bin/usart.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_stm32::usart::{Config, Uart}; | ||
| 6 | use {defmt_rtt as _, panic_probe as _}; | ||
| 7 | |||
| 8 | #[cortex_m_rt::entry] | ||
| 9 | fn main() -> ! { | ||
| 10 | info!("Hello World!"); | ||
| 11 | |||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | |||
| 14 | let config = Config::default(); | ||
| 15 | let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap(); | ||
| 16 | |||
| 17 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||
| 18 | info!("wrote Hello, starting echo"); | ||
| 19 | |||
| 20 | let mut buf = [0u8; 1]; | ||
| 21 | loop { | ||
| 22 | unwrap!(usart.blocking_read(&mut buf)); | ||
| 23 | unwrap!(usart.blocking_write(&buf)); | ||
| 24 | } | ||
| 25 | } | ||
diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs new file mode 100644 index 000000000..273f40643 --- /dev/null +++ b/examples/stm32u0/src/bin/usb_serial.rs | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{panic, *}; | ||
| 5 | use defmt_rtt as _; // global logger | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_futures::join::join; | ||
| 8 | use embassy_stm32::usb::{Driver, Instance}; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 11 | use embassy_usb::driver::EndpointError; | ||
| 12 | use embassy_usb::Builder; | ||
| 13 | use panic_probe as _; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | USB_DRD_FS => usb::InterruptHandler<peripherals::USB>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) { | ||
| 21 | let mut config = Config::default(); | ||
| 22 | { | ||
| 23 | use embassy_stm32::rcc::*; | ||
| 24 | config.rcc.hsi = true; | ||
| 25 | config.rcc.pll = Some(Pll { | ||
| 26 | source: PllSource::HSI, // 16 MHz | ||
| 27 | prediv: PllPreDiv::DIV1, | ||
| 28 | mul: PllMul::MUL7, | ||
| 29 | divp: None, | ||
| 30 | divq: None, | ||
| 31 | divr: Some(PllRDiv::DIV2), // 56 MHz | ||
| 32 | }); | ||
| 33 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 34 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 35 | config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; // USB uses ICLK | ||
| 36 | } | ||
| 37 | |||
| 38 | let p = embassy_stm32::init(config); | ||
| 39 | |||
| 40 | info!("Hello World!"); | ||
| 41 | |||
| 42 | // Create the driver, from the HAL. | ||
| 43 | let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | ||
| 44 | |||
| 45 | // Create embassy-usb Config | ||
| 46 | let config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 47 | //config.max_packet_size_0 = 64; | ||
| 48 | |||
| 49 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 50 | // It needs some buffers for building the descriptors. | ||
| 51 | let mut config_descriptor = [0; 256]; | ||
| 52 | let mut bos_descriptor = [0; 256]; | ||
| 53 | let mut control_buf = [0; 7]; | ||
| 54 | |||
| 55 | let mut state = State::new(); | ||
| 56 | |||
| 57 | let mut builder = Builder::new( | ||
| 58 | driver, | ||
| 59 | config, | ||
| 60 | &mut config_descriptor, | ||
| 61 | &mut bos_descriptor, | ||
| 62 | &mut [], // no msos descriptors | ||
| 63 | &mut control_buf, | ||
| 64 | ); | ||
| 65 | |||
| 66 | // Create classes on the builder. | ||
| 67 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | ||
| 68 | |||
| 69 | // Build the builder. | ||
| 70 | let mut usb = builder.build(); | ||
| 71 | |||
| 72 | // Run the USB device. | ||
| 73 | let usb_fut = usb.run(); | ||
| 74 | |||
| 75 | // Do stuff with the class! | ||
| 76 | let echo_fut = async { | ||
| 77 | loop { | ||
| 78 | class.wait_connection().await; | ||
| 79 | info!("Connected"); | ||
| 80 | let _ = echo(&mut class).await; | ||
| 81 | info!("Disconnected"); | ||
| 82 | } | ||
| 83 | }; | ||
| 84 | |||
| 85 | // Run everything concurrently. | ||
| 86 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 87 | join(usb_fut, echo_fut).await; | ||
| 88 | } | ||
| 89 | |||
| 90 | struct Disconnected {} | ||
| 91 | |||
| 92 | impl From<EndpointError> for Disconnected { | ||
| 93 | fn from(val: EndpointError) -> Self { | ||
| 94 | match val { | ||
| 95 | EndpointError::BufferOverflow => panic!("Buffer overflow"), | ||
| 96 | EndpointError::Disabled => Disconnected {}, | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { | ||
| 102 | let mut buf = [0; 64]; | ||
| 103 | loop { | ||
| 104 | let n = class.read_packet(&mut buf).await?; | ||
| 105 | let data = &buf[..n]; | ||
| 106 | info!("data: {:x}", data); | ||
| 107 | class.write_packet(data).await?; | ||
| 108 | } | ||
| 109 | } | ||
diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs new file mode 100644 index 000000000..f6276e2e9 --- /dev/null +++ b/examples/stm32u0/src/bin/wdt.rs | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 7 | use embassy_stm32::wdg::IndependentWatchdog; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner) { | ||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | info!("Hello World!"); | ||
| 15 | |||
| 16 | let mut led = Output::new(p.PA5, Level::High, Speed::Low); | ||
| 17 | |||
| 18 | let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); | ||
| 19 | wdt.unleash(); | ||
| 20 | |||
| 21 | let mut i = 0; | ||
| 22 | |||
| 23 | loop { | ||
| 24 | info!("high"); | ||
| 25 | led.set_high(); | ||
| 26 | Timer::after_millis(300).await; | ||
| 27 | |||
| 28 | info!("low"); | ||
| 29 | led.set_low(); | ||
| 30 | Timer::after_millis(300).await; | ||
| 31 | |||
| 32 | // Pet watchdog for 5 iterations and then stop. | ||
| 33 | // MCU should restart in 1 second after the last pet. | ||
| 34 | if i < 5 { | ||
| 35 | info!("Petting watchdog"); | ||
| 36 | wdt.pet(); | ||
| 37 | } | ||
| 38 | |||
| 39 | i += 1; | ||
| 40 | } | ||
| 41 | } | ||
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 03294339d..20d64c6f7 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml | |||
| @@ -7,10 +7,11 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32u585ai to your chip name, if necessary. | 8 | # Change stm32u585ai to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 14 | 15 | ||
| 15 | defmt = "0.3" | 16 | defmt = "0.3" |
| 16 | defmt-rtt = "0.4" | 17 | defmt-rtt = "0.4" |
| @@ -19,10 +20,13 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 19 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 20 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 23 | heapless = { version = "0.8", default-features = false } | 23 | heapless = { version = "0.8", default-features = false } |
| 24 | 24 | ||
| 25 | micromath = "2.0.0" | 25 | micromath = "2.0.0" |
| 26 | 26 | ||
| 27 | [features] | ||
| 28 | ## Use secure registers when TrustZone is enabled | ||
| 29 | trustzone-secure = ["embassy-stm32/trustzone-secure"] | ||
| 30 | |||
| 27 | [profile.release] | 31 | [profile.release] |
| 28 | debug = 2 | 32 | debug = 2 |
diff --git a/examples/stm32u5/src/bin/flash.rs b/examples/stm32u5/src/bin/flash.rs new file mode 100644 index 000000000..e4fd6bb9c --- /dev/null +++ b/examples/stm32u5/src/bin/flash.rs | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::flash::Flash; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | info!("Hello Flash!"); | ||
| 14 | |||
| 15 | const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000. | ||
| 16 | |||
| 17 | // wait a bit before accessing the flash | ||
| 18 | Timer::after_millis(300).await; | ||
| 19 | |||
| 20 | let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; | ||
| 21 | |||
| 22 | info!("Reading..."); | ||
| 23 | let mut buf = [0u8; 32]; | ||
| 24 | unwrap!(f.blocking_read(ADDR, &mut buf)); | ||
| 25 | info!("Read: {=[u8]:x}", buf); | ||
| 26 | |||
| 27 | info!("Erasing..."); | ||
| 28 | unwrap!(f.blocking_erase(ADDR, ADDR + 256 * 1024)); | ||
| 29 | |||
| 30 | info!("Reading..."); | ||
| 31 | let mut buf = [0u8; 32]; | ||
| 32 | unwrap!(f.blocking_read(ADDR, &mut buf)); | ||
| 33 | info!("Read after erase: {=[u8]:x}", buf); | ||
| 34 | |||
| 35 | info!("Writing..."); | ||
| 36 | unwrap!(f.blocking_write( | ||
| 37 | ADDR, | ||
| 38 | &[ | ||
| 39 | 1, 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, | ||
| 40 | 30, 31, 32 | ||
| 41 | ] | ||
| 42 | )); | ||
| 43 | |||
| 44 | info!("Reading..."); | ||
| 45 | let mut buf = [0u8; 32]; | ||
| 46 | unwrap!(f.blocking_read(ADDR, &mut buf)); | ||
| 47 | info!("Read: {=[u8]:x}", buf); | ||
| 48 | assert_eq!( | ||
| 49 | &buf[..], | ||
| 50 | &[ | ||
| 51 | 1, 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, | ||
| 52 | 30, 31, 32 | ||
| 53 | ] | ||
| 54 | ); | ||
| 55 | } | ||
diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs new file mode 100644 index 000000000..19a78eac9 --- /dev/null +++ b/examples/stm32u5/src/bin/i2c.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::i2c::I2c; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | const HTS221_ADDRESS: u8 = 0x5F; | ||
| 11 | const WHOAMI: u8 = 0x0F; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let p = embassy_stm32::init(Default::default()); | ||
| 16 | let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default()); | ||
| 17 | |||
| 18 | let mut data = [0u8; 1]; | ||
| 19 | unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); | ||
| 20 | |||
| 21 | // HTS221 data sheet is here: https://www.st.com/resource/en/datasheet/hts221.pdf | ||
| 22 | // 7.1 WHO_AM_I command is x0F which expected response xBC. | ||
| 23 | info!("Whoami: 0x{:02x}", data[0]); | ||
| 24 | assert_eq!(0xBC, data[0]); | ||
| 25 | } | ||
diff --git a/examples/stm32u5/src/bin/rng.rs b/examples/stm32u5/src/bin/rng.rs new file mode 100644 index 000000000..3a5bce097 --- /dev/null +++ b/examples/stm32u5/src/bin/rng.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::rng::Rng; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, rng}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 12 | }); | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) { | ||
| 16 | let p = embassy_stm32::init(Default::default()); | ||
| 17 | |||
| 18 | info!("Hello World!"); | ||
| 19 | |||
| 20 | let mut rng = Rng::new(p.RNG, Irqs); | ||
| 21 | |||
| 22 | let mut buf = [0u8; 16]; | ||
| 23 | unwrap!(rng.async_fill_bytes(&mut buf).await); | ||
| 24 | info!("random bytes: {:02x}", buf); | ||
| 25 | } | ||
diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs new file mode 100644 index 000000000..eb15d275a --- /dev/null +++ b/examples/stm32u5/src/bin/tsc.rs | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_stm32::bind_interrupts; | ||
| 6 | use embassy_stm32::tsc::{self, *}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | TSC => InterruptHandler<embassy_stm32::peripherals::TSC>; | ||
| 12 | }); | ||
| 13 | |||
| 14 | #[cortex_m_rt::exception] | ||
| 15 | unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! { | ||
| 16 | cortex_m::peripheral::SCB::sys_reset(); | ||
| 17 | } | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: embassy_executor::Spawner) { | ||
| 21 | let device_config = embassy_stm32::Config::default(); | ||
| 22 | let context = embassy_stm32::init(device_config); | ||
| 23 | |||
| 24 | let config = tsc::Config { | ||
| 25 | ct_pulse_high_length: ChargeTransferPulseCycle::_2, | ||
| 26 | ct_pulse_low_length: ChargeTransferPulseCycle::_2, | ||
| 27 | spread_spectrum: false, | ||
| 28 | spread_spectrum_deviation: SSDeviation::new(2).unwrap(), | ||
| 29 | spread_spectrum_prescaler: false, | ||
| 30 | pulse_generator_prescaler: PGPrescalerDivider::_4, | ||
| 31 | max_count_value: MaxCount::_8191, | ||
| 32 | io_default_mode: false, | ||
| 33 | synchro_pin_polarity: false, | ||
| 34 | acquisition_mode: false, | ||
| 35 | max_count_interrupt: false, | ||
| 36 | channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3, | ||
| 37 | shield_ios: TscIOPin::Group1Io3.into(), | ||
| 38 | sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2, | ||
| 39 | }; | ||
| 40 | |||
| 41 | let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new(); | ||
| 42 | g1.set_io2(context.PB13, PinType::Sample); | ||
| 43 | g1.set_io3(context.PB14, PinType::Shield); | ||
| 44 | |||
| 45 | let mut g2: PinGroup<embassy_stm32::peripherals::TSC, G2> = PinGroup::new(); | ||
| 46 | g2.set_io1(context.PB4, PinType::Sample); | ||
| 47 | g2.set_io2(context.PB5, PinType::Channel); | ||
| 48 | |||
| 49 | let mut g7: PinGroup<embassy_stm32::peripherals::TSC, G7> = PinGroup::new(); | ||
| 50 | g7.set_io2(context.PE3, PinType::Sample); | ||
| 51 | g7.set_io3(context.PE4, PinType::Channel); | ||
| 52 | |||
| 53 | let mut touch_controller = tsc::Tsc::new_async( | ||
| 54 | context.TSC, | ||
| 55 | Some(g1), | ||
| 56 | Some(g2), | ||
| 57 | None, | ||
| 58 | None, | ||
| 59 | None, | ||
| 60 | None, | ||
| 61 | Some(g7), | ||
| 62 | None, | ||
| 63 | config, | ||
| 64 | Irqs, | ||
| 65 | ); | ||
| 66 | |||
| 67 | touch_controller.discharge_io(true); | ||
| 68 | Timer::after_millis(1).await; | ||
| 69 | |||
| 70 | touch_controller.start(); | ||
| 71 | |||
| 72 | let mut group_two_val = 0; | ||
| 73 | let mut group_seven_val = 0; | ||
| 74 | info!("Starting touch_controller interface"); | ||
| 75 | loop { | ||
| 76 | touch_controller.pend_for_acquisition().await; | ||
| 77 | touch_controller.discharge_io(true); | ||
| 78 | Timer::after_millis(1).await; | ||
| 79 | |||
| 80 | if touch_controller.group_get_status(Group::Two) == GroupStatus::Complete { | ||
| 81 | group_two_val = touch_controller.group_get_value(Group::Two); | ||
| 82 | } | ||
| 83 | |||
| 84 | if touch_controller.group_get_status(Group::Seven) == GroupStatus::Complete { | ||
| 85 | group_seven_val = touch_controller.group_get_value(Group::Seven); | ||
| 86 | } | ||
| 87 | |||
| 88 | info!( | ||
| 89 | "Group Two value: {}, Group Seven value: {},", | ||
| 90 | group_two_val, group_seven_val | ||
| 91 | ); | ||
| 92 | |||
| 93 | touch_controller.start(); | ||
| 94 | } | ||
| 95 | } | ||
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index dca34fd0e..4d56395da 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs | |||
| @@ -4,17 +4,16 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use defmt_rtt as _; // global logger | 5 | use defmt_rtt as _; // global logger |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rcc::*; | 7 | use embassy_futures::join::join; |
| 8 | use embassy_stm32::usb_otg::{Driver, Instance}; | 8 | use embassy_stm32::usb::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 11 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| 12 | use embassy_usb::Builder; | 12 | use embassy_usb::Builder; |
| 13 | use futures::future::join; | ||
| 14 | use panic_probe as _; | 13 | use panic_probe as _; |
| 15 | 14 | ||
| 16 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 17 | OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>; | 16 | OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; |
| 18 | }); | 17 | }); |
| 19 | 18 | ||
| 20 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| @@ -22,22 +21,33 @@ async fn main(_spawner: Spawner) { | |||
| 22 | info!("Hello World!"); | 21 | info!("Hello World!"); |
| 23 | 22 | ||
| 24 | let mut config = Config::default(); | 23 | let mut config = Config::default(); |
| 25 | config.rcc.mux = ClockSrc::PLL1_R(PllConfig { | 24 | { |
| 26 | source: PllSource::HSI, | 25 | use embassy_stm32::rcc::*; |
| 27 | m: Pllm::DIV2, | 26 | config.rcc.hsi = true; |
| 28 | n: Plln::MUL10, | 27 | config.rcc.pll1 = Some(Pll { |
| 29 | p: Plldiv::DIV1, | 28 | source: PllSource::HSI, // 16 MHz |
| 30 | q: Plldiv::DIV1, | 29 | prediv: PllPreDiv::DIV1, |
| 31 | r: Plldiv::DIV1, | 30 | mul: PllMul::MUL10, |
| 32 | }); | 31 | divp: None, |
| 33 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | 32 | divq: None, |
| 33 | divr: Some(PllDiv::DIV1), // 160 MHz | ||
| 34 | }); | ||
| 35 | config.rcc.sys = Sysclk::PLL1_R; | ||
| 36 | config.rcc.voltage_range = VoltageScale::RANGE1; | ||
| 37 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 38 | config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK | ||
| 39 | } | ||
| 34 | 40 | ||
| 35 | let p = embassy_stm32::init(config); | 41 | let p = embassy_stm32::init(config); |
| 36 | 42 | ||
| 37 | // Create the driver, from the HAL. | 43 | // Create the driver, from the HAL. |
| 38 | let mut ep_out_buffer = [0u8; 256]; | 44 | let mut ep_out_buffer = [0u8; 256]; |
| 39 | let mut config = embassy_stm32::usb_otg::Config::default(); | 45 | let mut config = embassy_stm32::usb::Config::default(); |
| 40 | config.vbus_detection = true; | 46 | // Do not enable vbus_detection. This is a safe default that works in all boards. |
| 47 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 48 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 49 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 50 | config.vbus_detection = false; | ||
| 41 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 51 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 42 | 52 | ||
| 43 | // Create embassy-usb Config | 53 | // Create embassy-usb Config |
| @@ -55,7 +65,6 @@ async fn main(_spawner: Spawner) { | |||
| 55 | 65 | ||
| 56 | // Create embassy-usb DeviceBuilder using the driver and config. | 66 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 57 | // It needs some buffers for building the descriptors. | 67 | // It needs some buffers for building the descriptors. |
| 58 | let mut device_descriptor = [0; 256]; | ||
| 59 | let mut config_descriptor = [0; 256]; | 68 | let mut config_descriptor = [0; 256]; |
| 60 | let mut bos_descriptor = [0; 256]; | 69 | let mut bos_descriptor = [0; 256]; |
| 61 | let mut control_buf = [0; 64]; | 70 | let mut control_buf = [0; 64]; |
| @@ -65,7 +74,6 @@ async fn main(_spawner: Spawner) { | |||
| 65 | let mut builder = Builder::new( | 74 | let mut builder = Builder::new( |
| 66 | driver, | 75 | driver, |
| 67 | config, | 76 | config, |
| 68 | &mut device_descriptor, | ||
| 69 | &mut config_descriptor, | 77 | &mut config_descriptor, |
| 70 | &mut bos_descriptor, | 78 | &mut bos_descriptor, |
| 71 | &mut [], // no msos descriptors | 79 | &mut [], // no msos descriptors |
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml index 51c499ee7..8b6d6d754 100644 --- a/examples/stm32wb/.cargo/config.toml +++ b/examples/stm32wb/.cargo/config.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 2 | # replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` | 2 | # replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` |
| 3 | # runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" | 3 | # runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" |
| 4 | runner = "teleprobe local run --chip STM32WB55RG --elf" | 4 | runner = "teleprobe local run --chip STM32WB55RG --elf" |
| 5 | 5 | ||
| 6 | [build] | 6 | [build] |
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 94a5141f5..1e1a0efe2 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml | |||
| @@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0" | |||
| 8 | # Change stm32wb55rg to your chip name in both dependencies, if necessary. | 8 | # Change stm32wb55rg to your chip name in both dependencies, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } |
| 10 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } | 10 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } |
| 11 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 13 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } | 14 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } |
| 15 | 15 | ||
| 16 | defmt = "0.3" | 16 | defmt = "0.3" |
| @@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 24 | heapless = { version = "0.8", default-features = false } | 23 | heapless = { version = "0.8", default-features = false } |
| 25 | static_cell = "2" | 24 | static_cell = "2" |
| 26 | 25 | ||
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs index d3b3c15ca..3bd8b4a63 100644 --- a/examples/stm32wb/src/bin/eddystone_beacon.rs +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs | |||
| @@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) { | |||
| 46 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 46 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 47 | - Select "Start Wireless Stack". | 47 | - Select "Start Wireless Stack". |
| 48 | - Disconnect from the device. | 48 | - Disconnect from the device. |
| 49 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 50 | - Run this example. | 49 | - Run this example. |
| 51 | 50 | ||
| 52 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 51 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 3b50d6c31..1cc50e134 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs | |||
| @@ -57,7 +57,6 @@ async fn main(_spawner: Spawner) { | |||
| 57 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 57 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 58 | - Select "Start Wireless Stack". | 58 | - Select "Start Wireless Stack". |
| 59 | - Disconnect from the device. | 59 | - Disconnect from the device. |
| 60 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 61 | - Run this example. | 60 | - Run this example. |
| 62 | 61 | ||
| 63 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 62 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index 5cd660543..d139aa61b 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs | |||
| @@ -43,7 +43,6 @@ async fn main(spawner: Spawner) { | |||
| 43 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 43 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 44 | - Select "Start Wireless Stack". | 44 | - Select "Start Wireless Stack". |
| 45 | - Disconnect from the device. | 45 | - Disconnect from the device. |
| 46 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 47 | - Run this example. | 46 | - Run this example. |
| 48 | 47 | ||
| 49 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 48 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index 7a42bf577..6a97daf4d 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs | |||
| @@ -49,7 +49,6 @@ async fn main(spawner: Spawner) { | |||
| 49 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 49 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 50 | - Select "Start Wireless Stack". | 50 | - Select "Start Wireless Stack". |
| 51 | - Disconnect from the device. | 51 | - Disconnect from the device. |
| 52 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 53 | - Run this example. | 52 | - Run this example. |
| 54 | 53 | ||
| 55 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 54 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index 7949211fb..9062bdcd2 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs | |||
| @@ -45,7 +45,6 @@ async fn main(spawner: Spawner) { | |||
| 45 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 45 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 46 | - Select "Start Wireless Stack". | 46 | - Select "Start Wireless Stack". |
| 47 | - Disconnect from the device. | 47 | - Disconnect from the device. |
| 48 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 49 | - Run this example. | 48 | - Run this example. |
| 50 | 49 | ||
| 51 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 50 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index cb92d462d..4e7f2304d 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs | |||
| @@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) { | |||
| 35 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 35 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 36 | - Select "Start Wireless Stack". | 36 | - Select "Start Wireless Stack". |
| 37 | - Disconnect from the device. | 37 | - Disconnect from the device. |
| 38 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 39 | - Run this example. | 38 | - Run this example. |
| 40 | 39 | ||
| 41 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 40 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs index 2599e1151..72a4c18e6 100644 --- a/examples/stm32wb/src/bin/tl_mbox_ble.rs +++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs | |||
| @@ -34,7 +34,6 @@ async fn main(_spawner: Spawner) { | |||
| 34 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 34 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 35 | - Select "Start Wireless Stack". | 35 | - Select "Start Wireless Stack". |
| 36 | - Disconnect from the device. | 36 | - Disconnect from the device. |
| 37 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 38 | - Run this example. | 37 | - Run this example. |
| 39 | 38 | ||
| 40 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 39 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs index 5d868412a..9224e626d 100644 --- a/examples/stm32wb/src/bin/tl_mbox_mac.rs +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs | |||
| @@ -40,7 +40,6 @@ async fn main(spawner: Spawner) { | |||
| 40 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | 40 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". |
| 41 | - Select "Start Wireless Stack". | 41 | - Select "Start Wireless Stack". |
| 42 | - Disconnect from the device. | 42 | - Disconnect from the device. |
| 43 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 44 | - Run this example. | 43 | - Run this example. |
| 45 | 44 | ||
| 46 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | 45 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. |
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 47279a012..401281c0b 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml | |||
| @@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } | 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } |
| 9 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 11 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 12 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } | 12 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "0.3" |
| @@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing | |||
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 21 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 22 | heapless = { version = "0.8", default-features = false } | 21 | heapless = { version = "0.8", default-features = false } |
| 23 | static_cell = "2" | 22 | static_cell = "2" |
| 24 | 23 | ||
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 4cb55930b..46af5218c 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml | |||
| @@ -7,10 +7,10 @@ license = "MIT OR Apache-2.0" | |||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | # Change stm32wl55jc-cm4 to your chip name, if necessary. | 8 | # Change stm32wl55jc-cm4 to your chip name, if necessary. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.4" | 16 | defmt-rtt = "0.4" |
| @@ -20,7 +20,6 @@ cortex-m-rt = "0.7.0" | |||
| 20 | embedded-hal = "0.2.6" | 20 | embedded-hal = "0.2.6" |
| 21 | embedded-storage = "0.3.1" | 21 | embedded-storage = "0.3.1" |
| 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 24 | heapless = { version = "0.8", default-features = false } | 23 | heapless = { version = "0.8", default-features = false } |
| 25 | chrono = { version = "^0.4", default-features = false } | 24 | chrono = { version = "^0.4", default-features = false } |
| 26 | 25 | ||
diff --git a/examples/stm32wl/memory.x b/examples/stm32wl/memory.x new file mode 100644 index 000000000..4590867a8 --- /dev/null +++ b/examples/stm32wl/memory.x | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ | ||
| 4 | FLASH : ORIGIN = 0x08000000, LENGTH = 256K | ||
| 5 | SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128 | ||
| 6 | RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128 | ||
| 7 | } | ||
| 8 | |||
| 9 | SECTIONS | ||
| 10 | { | ||
| 11 | .shared_data : | ||
| 12 | { | ||
| 13 | *(.shared_data) | ||
| 14 | } > SHARED_RAM | ||
| 15 | } | ||
diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs index 347bd093f..ce7d0ec58 100644 --- a/examples/stm32wl/src/bin/blinky.rs +++ b/examples/stm32wl/src/bin/blinky.rs | |||
| @@ -1,15 +1,21 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | 8 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 9 | use embassy_stm32::SharedData; | ||
| 7 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 12 | ||
| 13 | #[link_section = ".shared_data"] | ||
| 14 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 15 | |||
| 10 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 12 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); |
| 13 | info!("Hello World!"); | 19 | info!("Hello World!"); |
| 14 | 20 | ||
| 15 | let mut led = Output::new(p.PB15, Level::High, Speed::Low); | 21 | 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..8b5204479 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs | |||
| @@ -1,16 +1,22 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 4 | use cortex_m_rt::entry; | 6 | use cortex_m_rt::entry; |
| 5 | use defmt::*; | 7 | use defmt::*; |
| 6 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | 8 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; |
| 9 | use embassy_stm32::SharedData; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 8 | 11 | ||
| 12 | #[link_section = ".shared_data"] | ||
| 13 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 14 | |||
| 9 | #[entry] | 15 | #[entry] |
| 10 | fn main() -> ! { | 16 | fn main() -> ! { |
| 11 | info!("Hello World!"); | 17 | info!("Hello World!"); |
| 12 | 18 | ||
| 13 | let p = embassy_stm32::init(Default::default()); | 19 | let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); |
| 14 | 20 | ||
| 15 | let button = Input::new(p.PA0, Pull::Up); | 21 | let button = Input::new(p.PA0, Pull::Up); |
| 16 | let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); | 22 | 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..8dd1a6a5e 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs | |||
| @@ -1,15 +1,21 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::exti::ExtiInput; | 8 | use embassy_stm32::exti::ExtiInput; |
| 7 | use embassy_stm32::gpio::Pull; | 9 | use embassy_stm32::gpio::Pull; |
| 10 | use embassy_stm32::SharedData; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 12 | ||
| 13 | #[link_section = ".shared_data"] | ||
| 14 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 15 | |||
| 10 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 12 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); |
| 13 | info!("Hello World!"); | 19 | info!("Hello World!"); |
| 14 | 20 | ||
| 15 | let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); | 21 | 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..147f5d293 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs | |||
| @@ -1,14 +1,20 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 4 | use defmt::{info, unwrap}; | 6 | use defmt::{info, unwrap}; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::flash::Flash; | 8 | use embassy_stm32::flash::Flash; |
| 9 | use embassy_stm32::SharedData; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 8 | 11 | ||
| 12 | #[link_section = ".shared_data"] | ||
| 13 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 14 | |||
| 9 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 10 | async fn main(_spawner: Spawner) { | 16 | async fn main(_spawner: Spawner) { |
| 11 | let p = embassy_stm32::init(Default::default()); | 17 | let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA); |
| 12 | info!("Hello Flash!"); | 18 | info!("Hello Flash!"); |
| 13 | 19 | ||
| 14 | const ADDR: u32 = 0x36000; | 20 | const ADDR: u32 = 0x36000; |
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 3610392be..df2ed0054 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs | |||
| @@ -1,17 +1,22 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::rng::{self, Rng}; | 8 | use embassy_stm32::rng::{self, Rng}; |
| 7 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals}; | 10 | use embassy_stm32::{bind_interrupts, peripherals, SharedData}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 12 | ||
| 11 | bind_interrupts!(struct Irqs{ | 13 | bind_interrupts!(struct Irqs{ |
| 12 | RNG => rng::InterruptHandler<peripherals::RNG>; | 14 | RNG => rng::InterruptHandler<peripherals::RNG>; |
| 13 | }); | 15 | }); |
| 14 | 16 | ||
| 17 | #[link_section = ".shared_data"] | ||
| 18 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 19 | |||
| 15 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 16 | async fn main(_spawner: Spawner) { | 21 | async fn main(_spawner: Spawner) { |
| 17 | let mut config = embassy_stm32::Config::default(); | 22 | let mut config = embassy_stm32::Config::default(); |
| @@ -22,7 +27,7 @@ async fn main(_spawner: Spawner) { | |||
| 22 | mode: HseMode::Bypass, | 27 | mode: HseMode::Bypass, |
| 23 | prescaler: HsePrescaler::DIV1, | 28 | prescaler: HsePrescaler::DIV1, |
| 24 | }); | 29 | }); |
| 25 | config.rcc.mux = ClockSrc::PLL1_R; | 30 | config.rcc.sys = Sysclk::PLL1_R; |
| 26 | config.rcc.pll = Some(Pll { | 31 | config.rcc.pll = Some(Pll { |
| 27 | source: PllSource::HSE, | 32 | source: PllSource::HSE, |
| 28 | prediv: PllPreDiv::DIV2, | 33 | prediv: PllPreDiv::DIV2, |
| @@ -32,7 +37,7 @@ async fn main(_spawner: Spawner) { | |||
| 32 | divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) | 37 | divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) |
| 33 | }); | 38 | }); |
| 34 | } | 39 | } |
| 35 | let p = embassy_stm32::init(config); | 40 | let p = embassy_stm32::init_primary(config, &SHARED_DATA); |
| 36 | 41 | ||
| 37 | info!("Hello World!"); | 42 | info!("Hello World!"); |
| 38 | 43 | ||
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index 4738d5770..69a9ddc4c 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs | |||
| @@ -1,15 +1,20 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 4 | use chrono::{NaiveDate, NaiveDateTime}; | 6 | use chrono::{NaiveDate, NaiveDateTime}; |
| 5 | use defmt::*; | 7 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | 9 | use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 8 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 9 | use embassy_stm32::Config; | 11 | use embassy_stm32::{Config, SharedData}; |
| 10 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 14 | ||
| 15 | #[link_section = ".shared_data"] | ||
| 16 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 17 | |||
| 13 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 14 | async fn main(_spawner: Spawner) { | 19 | async fn main(_spawner: Spawner) { |
| 15 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| @@ -21,7 +26,7 @@ async fn main(_spawner: Spawner) { | |||
| 21 | mode: HseMode::Bypass, | 26 | mode: HseMode::Bypass, |
| 22 | prescaler: HsePrescaler::DIV1, | 27 | prescaler: HsePrescaler::DIV1, |
| 23 | }); | 28 | }); |
| 24 | config.rcc.mux = ClockSrc::PLL1_R; | 29 | config.rcc.sys = Sysclk::PLL1_R; |
| 25 | config.rcc.pll = Some(Pll { | 30 | config.rcc.pll = Some(Pll { |
| 26 | source: PllSource::HSE, | 31 | source: PllSource::HSE, |
| 27 | prediv: PllPreDiv::DIV2, | 32 | prediv: PllPreDiv::DIV2, |
| @@ -31,7 +36,7 @@ async fn main(_spawner: Spawner) { | |||
| 31 | divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) | 36 | divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) |
| 32 | }); | 37 | }); |
| 33 | } | 38 | } |
| 34 | let p = embassy_stm32::init(config); | 39 | let p = embassy_stm32::init_primary(config, &SHARED_DATA); |
| 35 | info!("Hello World!"); | 40 | info!("Hello World!"); |
| 36 | 41 | ||
| 37 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) | 42 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) |
| @@ -40,7 +45,7 @@ async fn main(_spawner: Spawner) { | |||
| 40 | .unwrap(); | 45 | .unwrap(); |
| 41 | 46 | ||
| 42 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 47 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 43 | info!("Got RTC! {:?}", now.timestamp()); | 48 | info!("Got RTC! {:?}", now.and_utc().timestamp()); |
| 44 | 49 | ||
| 45 | rtc.set_datetime(now.into()).expect("datetime not set"); | 50 | rtc.set_datetime(now.into()).expect("datetime not set"); |
| 46 | 51 | ||
| @@ -48,5 +53,5 @@ async fn main(_spawner: Spawner) { | |||
| 48 | Timer::after_millis(20000).await; | 53 | Timer::after_millis(20000).await; |
| 49 | 54 | ||
| 50 | let then: NaiveDateTime = rtc.now().unwrap().into(); | 55 | let then: NaiveDateTime = rtc.now().unwrap().into(); |
| 51 | info!("Got RTC! {:?}", then.timestamp()); | 56 | info!("Got RTC! {:?}", then.and_utc().timestamp()); |
| 52 | } | 57 | } |
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 8e545834c..ece9b9201 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs | |||
| @@ -1,10 +1,12 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::mem::MaybeUninit; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::usart::{Config, InterruptHandler, Uart}; | 8 | use embassy_stm32::usart::{Config, InterruptHandler, Uart}; |
| 7 | use embassy_stm32::{bind_interrupts, peripherals}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, SharedData}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 11 | ||
| 10 | bind_interrupts!(struct Irqs{ | 12 | bind_interrupts!(struct Irqs{ |
| @@ -12,6 +14,9 @@ bind_interrupts!(struct Irqs{ | |||
| 12 | LPUART1 => InterruptHandler<peripherals::LPUART1>; | 14 | LPUART1 => InterruptHandler<peripherals::LPUART1>; |
| 13 | }); | 15 | }); |
| 14 | 16 | ||
| 17 | #[link_section = ".shared_data"] | ||
| 18 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | ||
| 19 | |||
| 15 | /* | 20 | /* |
| 16 | Pass Incoming data from LPUART1 to USART1 | 21 | Pass Incoming data from LPUART1 to USART1 |
| 17 | Example is written for the LoRa-E5 mini v1.0, | 22 | Example is written for the LoRa-E5 mini v1.0, |
| @@ -20,8 +25,8 @@ but can be surely changed for your needs. | |||
| 20 | #[embassy_executor::main] | 25 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 26 | async fn main(_spawner: Spawner) { |
| 22 | let mut config = embassy_stm32::Config::default(); | 27 | let mut config = embassy_stm32::Config::default(); |
| 23 | config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; | 28 | config.rcc.sys = embassy_stm32::rcc::Sysclk::HSE; |
| 24 | let p = embassy_stm32::init(config); | 29 | let p = embassy_stm32::init_primary(config, &SHARED_DATA); |
| 25 | 30 | ||
| 26 | defmt::info!("Starting system"); | 31 | defmt::info!("Starting system"); |
| 27 | 32 | ||
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 3d2300b59..75de079b7 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml | |||
| @@ -8,15 +8,14 @@ license = "MIT OR Apache-2.0" | |||
| 8 | crate-type = ["cdylib"] | 8 | crate-type = ["cdylib"] |
| 9 | 9 | ||
| 10 | [dependencies] | 10 | [dependencies] |
| 11 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } | 11 | embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } |
| 12 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } |
| 13 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "wasm", ] } | 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } |
| 14 | 14 | ||
| 15 | wasm-logger = "0.2.0" | 15 | wasm-logger = "0.2.0" |
| 16 | wasm-bindgen = "0.2" | 16 | wasm-bindgen = "0.2" |
| 17 | web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] } | 17 | web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] } |
| 18 | log = "0.4.11" | 18 | log = "0.4.11" |
| 19 | critical-section = { version = "1.1", features = ["std"] } | ||
| 20 | 19 | ||
| 21 | [profile.release] | 20 | [profile.release] |
| 22 | debug = 2 | 21 | debug = 2 |
