diff options
69 files changed, 1979 insertions, 1901 deletions
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 72ecb116a..f6fe1e14f 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md | |||
| @@ -23,6 +23,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 23 | - bugfix: Do not write to UICR from non-secure code on nrf53 | 23 | - bugfix: Do not write to UICR from non-secure code on nrf53 |
| 24 | - bugfix: Add delay to uart init anomaly fix | 24 | - bugfix: Add delay to uart init anomaly fix |
| 25 | - changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned | 25 | - changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned |
| 26 | - added: add `gpiote::InputChannel::wait_for_high()` and `wait_for_low()` to wait for specific signal level | ||
| 27 | - changed: `gpiote::InputChannel::wait()` now takes a mutable reference to `self` to avoid interference from concurrent calls | ||
| 28 | - changed: `gpiote::InputChannel::wait()` now ensures events are seen as soon as the function is called, even if the future is not polled | ||
| 29 | - bugfix: use correct flash size for nRF54l | ||
| 26 | 30 | ||
| 27 | ## 0.8.0 - 2025-09-30 | 31 | ## 0.8.0 - 2025-09-30 |
| 28 | 32 | ||
diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index 0724f2ff6..8846717db 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs | |||
| @@ -204,7 +204,7 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; | |||
| 204 | 204 | ||
| 205 | // 1.5 MB NVM | 205 | // 1.5 MB NVM |
| 206 | #[allow(unused)] | 206 | #[allow(unused)] |
| 207 | pub const FLASH_SIZE: usize = 1536 * 1024; | 207 | pub const FLASH_SIZE: usize = 1524 * 1024; |
| 208 | 208 | ||
| 209 | embassy_hal_internal::peripherals! { | 209 | embassy_hal_internal::peripherals! { |
| 210 | // PPI | 210 | // PPI |
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 91944d8cd..d4f6668f3 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -349,16 +349,73 @@ impl<'d> InputChannel<'d> { | |||
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | /// Asynchronously wait for an event in this channel. | 351 | /// Asynchronously wait for an event in this channel. |
| 352 | pub async fn wait(&self) { | 352 | /// |
| 353 | let g = self.ch.regs(); | 353 | /// It is possible to call this function and await the returned future later. |
| 354 | let num = self.ch.number(); | 354 | /// If an even occurs in the mean time, the future will immediately report ready. |
| 355 | let waker = self.ch.waker(); | 355 | pub fn wait(&mut self) -> impl Future<Output = ()> { |
| 356 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 357 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 358 | Self::wait_internal(&mut self.ch) | ||
| 359 | } | ||
| 360 | |||
| 361 | /// Asynchronously wait for the pin to become high. | ||
| 362 | /// | ||
| 363 | /// The channel must be configured with [`InputChannelPolarity::LoToHi`] or [`InputChannelPolarity::Toggle`]. | ||
| 364 | /// If the channel is not configured to detect rising edges, it is unspecified when the returned future completes. | ||
| 365 | /// | ||
| 366 | /// It is possible to call this function and await the returned future later. | ||
| 367 | /// If an even occurs in the mean time, the future will immediately report ready. | ||
| 368 | pub fn wait_for_high(&mut self) -> impl Future<Output = ()> { | ||
| 369 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 370 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 371 | |||
| 372 | // Subscribe to the event before checking the pin level. | ||
| 373 | let wait = Self::wait_internal(&mut self.ch); | ||
| 374 | let pin = &self.pin; | ||
| 375 | async move { | ||
| 376 | if pin.is_high() { | ||
| 377 | return; | ||
| 378 | } | ||
| 379 | wait.await; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | /// Asynchronously wait for the pin to become low. | ||
| 384 | /// | ||
| 385 | /// The channel must be configured with [`InputChannelPolarity::HiToLo`] or [`InputChannelPolarity::Toggle`]. | ||
| 386 | /// If the channel is not configured to detect falling edges, it is unspecified when the returned future completes. | ||
| 387 | /// | ||
| 388 | /// It is possible to call this function and await the returned future later. | ||
| 389 | /// If an even occurs in the mean time, the future will immediately report ready. | ||
| 390 | pub fn wait_for_low(&mut self) -> impl Future<Output = ()> { | ||
| 391 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 392 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 393 | |||
| 394 | // Subscribe to the event before checking the pin level. | ||
| 395 | let wait = Self::wait_internal(&mut self.ch); | ||
| 396 | let pin = &self.pin; | ||
| 397 | async move { | ||
| 398 | if pin.is_low() { | ||
| 399 | return; | ||
| 400 | } | ||
| 401 | wait.await; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | /// Internal implementation for `wait()` and friends. | ||
| 406 | fn wait_internal(channel: &mut Peri<'_, AnyChannel>) -> impl Future<Output = ()> { | ||
| 407 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 408 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 409 | |||
| 410 | let g = channel.regs(); | ||
| 411 | let num = channel.number(); | ||
| 412 | let waker = channel.waker(); | ||
| 356 | 413 | ||
| 357 | // Enable interrupt | 414 | // Enable interrupt |
| 358 | g.events_in(num).write_value(0); | 415 | g.events_in(num).write_value(0); |
| 359 | g.intenset(INTNUM).write(|w| w.0 = 1 << num); | 416 | g.intenset(INTNUM).write(|w| w.0 = 1 << num); |
| 360 | 417 | ||
| 361 | poll_fn(|cx| { | 418 | poll_fn(move |cx| { |
| 362 | CHANNEL_WAKERS[waker].register(cx.waker()); | 419 | CHANNEL_WAKERS[waker].register(cx.waker()); |
| 363 | 420 | ||
| 364 | if g.events_in(num).read() != 0 { | 421 | if g.events_in(num).read() != 0 { |
| @@ -367,7 +424,6 @@ impl<'d> InputChannel<'d> { | |||
| 367 | Poll::Pending | 424 | Poll::Pending |
| 368 | } | 425 | } |
| 369 | }) | 426 | }) |
| 370 | .await; | ||
| 371 | } | 427 | } |
| 372 | 428 | ||
| 373 | /// Get the associated input pin. | 429 | /// Get the associated input pin. |
diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md index 39f5c75bd..e6f117da4 100644 --- a/embassy-nxp/CHANGELOG.md +++ b/embassy-nxp/CHANGELOG.md | |||
| @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | - Codegen using `nxp-pac` metadata | ||
| 10 | - LPC55: PWM simple | 11 | - LPC55: PWM simple |
| 11 | - LPC55: Move ALT definitions for USART to TX/RX pin impls. | 12 | - LPC55: Move ALT definitions for USART to TX/RX pin impls. |
| 12 | - LPC55: Remove internal match_iocon macro | 13 | - LPC55: Remove internal match_iocon macro |
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index f8c63ba29..b78c26c77 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml | |||
| @@ -38,13 +38,13 @@ embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-ut | |||
| 38 | embedded-io = "0.6.1" | 38 | embedded-io = "0.6.1" |
| 39 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 39 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 40 | ## Chip dependencies | 40 | ## Chip dependencies |
| 41 | nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263"} | 41 | nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "af5122e1cbe1483833c5d2e5af96b26a34ed5d62"} |
| 42 | 42 | ||
| 43 | imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } | 43 | imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } |
| 44 | 44 | ||
| 45 | [build-dependencies] | 45 | [build-dependencies] |
| 46 | cfg_aliases = "0.2.1" | 46 | cfg_aliases = "0.2.1" |
| 47 | nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263", features = ["metadata"], optional = true } | 47 | nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "af5122e1cbe1483833c5d2e5af96b26a34ed5d62", features = ["metadata"], optional = true } |
| 48 | proc-macro2 = "1.0.95" | 48 | proc-macro2 = "1.0.95" |
| 49 | quote = "1.0.15" | 49 | quote = "1.0.15" |
| 50 | 50 | ||
diff --git a/embassy-nxp/build.rs b/embassy-nxp/build.rs index f3c062c87..f53c29161 100644 --- a/embassy-nxp/build.rs +++ b/embassy-nxp/build.rs | |||
| @@ -4,10 +4,12 @@ use std::process::Command; | |||
| 4 | use std::{env, fs}; | 4 | use std::{env, fs}; |
| 5 | 5 | ||
| 6 | use cfg_aliases::cfg_aliases; | 6 | use cfg_aliases::cfg_aliases; |
| 7 | #[cfg(feature = "_rt1xxx")] | ||
| 8 | use nxp_pac::metadata; | 7 | use nxp_pac::metadata; |
| 8 | use nxp_pac::metadata::{METADATA, Peripheral}; | ||
| 9 | #[allow(unused)] | 9 | #[allow(unused)] |
| 10 | use proc_macro2::TokenStream; | 10 | use proc_macro2::TokenStream; |
| 11 | use proc_macro2::{Ident, Literal, Span}; | ||
| 12 | use quote::format_ident; | ||
| 11 | #[allow(unused)] | 13 | #[allow(unused)] |
| 12 | use quote::quote; | 14 | use quote::quote; |
| 13 | 15 | ||
| @@ -31,56 +33,188 @@ fn main() { | |||
| 31 | .unwrap() | 33 | .unwrap() |
| 32 | .to_ascii_lowercase(); | 34 | .to_ascii_lowercase(); |
| 33 | 35 | ||
| 36 | let singletons = singletons(&mut cfgs); | ||
| 37 | |||
| 34 | cfg_aliases! { | 38 | cfg_aliases! { |
| 35 | rt1xxx: { any(feature = "mimxrt1011", feature = "mimxrt1062") }, | 39 | rt1xxx: { any(feature = "mimxrt1011", feature = "mimxrt1062") }, |
| 36 | gpio1: { any(feature = "mimxrt1011", feature = "mimxrt1062") }, | ||
| 37 | gpio2: { any(feature = "mimxrt1011", feature = "mimxrt1062") }, | ||
| 38 | gpio3: { feature = "mimxrt1062" }, | ||
| 39 | gpio4: { feature = "mimxrt1062" }, | ||
| 40 | gpio5: { any(feature = "mimxrt1011", feature = "mimxrt1062") }, | ||
| 41 | } | 40 | } |
| 42 | 41 | ||
| 43 | eprintln!("chip: {chip_name}"); | 42 | eprintln!("chip: {chip_name}"); |
| 44 | 43 | ||
| 45 | generate_code(); | 44 | generate_code(&mut cfgs, &singletons); |
| 46 | } | 45 | } |
| 47 | 46 | ||
| 48 | #[cfg(feature = "_rt1xxx")] | 47 | /// A peripheral singleton returned by `embassy_nxp::init`. |
| 49 | fn generate_iomuxc() -> TokenStream { | 48 | struct Singleton { |
| 50 | use proc_macro2::{Ident, Span}; | 49 | name: String, |
| 51 | 50 | ||
| 52 | let pads = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| { | 51 | /// A cfg guard which indicates whether the `Peripherals` struct will give the user this singleton. |
| 53 | let name = Ident::new(®isters.name, Span::call_site()); | 52 | cfg: Option<TokenStream>, |
| 54 | let address = registers.pad_ctl; | 53 | } |
| 55 | 54 | ||
| 56 | quote! { | 55 | fn singletons(cfgs: &mut common::CfgSet) -> Vec<Singleton> { |
| 57 | pub const #name: u32 = #address; | 56 | let mut singletons = Vec::new(); |
| 57 | |||
| 58 | for peripheral in METADATA.peripherals { | ||
| 59 | // GPIO and DMA are generated in a 2nd pass. | ||
| 60 | let skip_singleton = if peripheral.name.starts_with("GPIO") || peripheral.name.starts_with("DMA") { | ||
| 61 | true | ||
| 62 | } else { | ||
| 63 | false | ||
| 64 | }; | ||
| 65 | |||
| 66 | if !skip_singleton { | ||
| 67 | singletons.push(Singleton { | ||
| 68 | name: peripheral.name.into(), | ||
| 69 | cfg: None, | ||
| 70 | }); | ||
| 58 | } | 71 | } |
| 59 | }); | 72 | } |
| 60 | 73 | ||
| 61 | let muxes = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| { | 74 | cfgs.declare_all(&[ |
| 62 | let name = Ident::new(®isters.name, Span::call_site()); | 75 | "gpio1", |
| 63 | let address = registers.mux_ctl; | 76 | "gpio1_hi", |
| 77 | "gpio2", | ||
| 78 | "gpio2_hi", | ||
| 79 | "gpio3", | ||
| 80 | "gpio3_hi", | ||
| 81 | "gpio4", | ||
| 82 | "gpio4_hi", | ||
| 83 | "gpio5", | ||
| 84 | "gpio5_hi", | ||
| 85 | "gpio10", | ||
| 86 | "gpio10_hi", | ||
| 87 | ]); | ||
| 64 | 88 | ||
| 65 | quote! { | 89 | for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("GPIO")) { |
| 66 | pub const #name: u32 = #address; | 90 | let number = peripheral.name.strip_prefix("GPIO").unwrap(); |
| 91 | assert!(number.parse::<u8>().is_ok()); | ||
| 92 | cfgs.enable(format!("gpio{}", number)); | ||
| 93 | |||
| 94 | for signal in peripheral.signals.iter() { | ||
| 95 | let pin_number = signal.name.parse::<u8>().unwrap(); | ||
| 96 | |||
| 97 | if pin_number > 15 { | ||
| 98 | cfgs.enable(format!("gpio{}_hi", number)); | ||
| 99 | } | ||
| 100 | |||
| 101 | // GPIO signals only defined a single signal, on a single pin. | ||
| 102 | assert_eq!(signal.pins.len(), 1); | ||
| 103 | |||
| 104 | singletons.push(Singleton { | ||
| 105 | name: signal.pins[0].pin.into(), | ||
| 106 | cfg: None, | ||
| 107 | }); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("DMA")) { | ||
| 112 | let instance = peripheral.name.strip_prefix("DMA").unwrap(); | ||
| 113 | assert!(instance.parse::<u8>().is_ok()); | ||
| 114 | |||
| 115 | for signal in peripheral.signals.iter() { | ||
| 116 | let channel_number = signal.name.parse::<u8>().unwrap(); | ||
| 117 | let name = format!("DMA{instance}_CH{channel_number}"); | ||
| 118 | |||
| 119 | // DMA has no pins. | ||
| 120 | assert!(signal.pins.is_empty()); | ||
| 121 | |||
| 122 | singletons.push(Singleton { name, cfg: None }); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("SCT")) { | ||
| 127 | let instance = peripheral.name.strip_prefix("SCT").unwrap(); | ||
| 128 | assert!(instance.parse::<u8>().is_ok()); | ||
| 129 | |||
| 130 | for signal in peripheral.signals.iter() { | ||
| 131 | if !signal.name.starts_with("OUT") { | ||
| 132 | continue; | ||
| 133 | } | ||
| 134 | |||
| 135 | let channel_number = signal.name.strip_prefix("OUT").unwrap().parse::<u8>().unwrap(); | ||
| 136 | let name = format!("SCT{instance}_OUT{channel_number}"); | ||
| 137 | |||
| 138 | singletons.push(Singleton { name, cfg: None }); | ||
| 67 | } | 139 | } |
| 140 | } | ||
| 141 | |||
| 142 | singletons | ||
| 143 | } | ||
| 144 | |||
| 145 | #[cfg(feature = "_rt1xxx")] | ||
| 146 | fn generate_iomuxc() -> TokenStream { | ||
| 147 | let iomuxc_pad_impls = metadata::METADATA | ||
| 148 | .pins | ||
| 149 | .iter() | ||
| 150 | .filter(|p| p.iomuxc.as_ref().filter(|i| i.mux.is_some()).is_some()) | ||
| 151 | .map(|pin| { | ||
| 152 | let Some(ref iomuxc) = pin.iomuxc else { | ||
| 153 | panic!("Pin {} has no IOMUXC definitions", pin.name); | ||
| 154 | }; | ||
| 155 | |||
| 156 | let name = Ident::new(pin.name, Span::call_site()); | ||
| 157 | let mux = iomuxc.mux.unwrap(); | ||
| 158 | let pad = iomuxc.pad; | ||
| 159 | |||
| 160 | quote! { | ||
| 161 | impl_iomuxc_pad!(#name, #pad, #mux); | ||
| 162 | } | ||
| 163 | }); | ||
| 164 | |||
| 165 | let base_match_arms = metadata::METADATA | ||
| 166 | .peripherals | ||
| 167 | .iter() | ||
| 168 | .filter(|p| p.name.starts_with("GPIO")) | ||
| 169 | .map(|peripheral| { | ||
| 170 | peripheral.signals.iter().map(|signal| { | ||
| 171 | // All GPIO signals have a single pin. | ||
| 172 | let pin = &signal.pins[0]; | ||
| 173 | let instance = peripheral.name.strip_prefix("GPIO").unwrap(); | ||
| 174 | let bank_match = format_ident!("Gpio{}", instance); | ||
| 175 | let pin_number = signal.name.parse::<u8>().unwrap(); | ||
| 176 | let pin_ident = Ident::new(pin.pin, Span::call_site()); | ||
| 177 | |||
| 178 | quote! { | ||
| 179 | (Bank::#bank_match, #pin_number) => <crate::peripherals::#pin_ident as crate::iomuxc::SealedPad> | ||
| 180 | } | ||
| 181 | }) | ||
| 182 | }) | ||
| 183 | .flatten() | ||
| 184 | .collect::<Vec<_>>(); | ||
| 185 | |||
| 186 | let pad_match_arms = base_match_arms.iter().map(|arm| { | ||
| 187 | quote! { #arm::PAD } | ||
| 188 | }); | ||
| 189 | |||
| 190 | let mux_match_arms = base_match_arms.iter().map(|arm| { | ||
| 191 | quote! { #arm::MUX } | ||
| 68 | }); | 192 | }); |
| 69 | 193 | ||
| 70 | quote! { | 194 | quote! { |
| 71 | pub mod iomuxc { | 195 | #(#iomuxc_pad_impls)* |
| 72 | pub mod pads { | 196 | |
| 73 | #(#pads)* | 197 | pub(crate) fn iomuxc_pad(bank: crate::gpio::Bank, pin: u8) -> *mut () { |
| 198 | use crate::gpio::Bank; | ||
| 199 | |||
| 200 | match (bank, pin) { | ||
| 201 | #(#pad_match_arms),*, | ||
| 202 | _ => unreachable!() | ||
| 74 | } | 203 | } |
| 204 | } | ||
| 205 | |||
| 206 | pub(crate) fn iomuxc_mux(bank: crate::gpio::Bank, pin: u8) -> Option<*mut ()> { | ||
| 207 | use crate::gpio::Bank; | ||
| 75 | 208 | ||
| 76 | pub mod muxes { | 209 | match (bank, pin) { |
| 77 | #(#muxes)* | 210 | #(#mux_match_arms),*, |
| 211 | _ => unreachable!() | ||
| 78 | } | 212 | } |
| 79 | } | 213 | } |
| 80 | } | 214 | } |
| 81 | } | 215 | } |
| 82 | 216 | ||
| 83 | fn generate_code() { | 217 | fn generate_code(cfgs: &mut common::CfgSet, singletons: &[Singleton]) { |
| 84 | #[allow(unused)] | 218 | #[allow(unused)] |
| 85 | use std::fmt::Write; | 219 | use std::fmt::Write; |
| 86 | 220 | ||
| @@ -88,14 +222,179 @@ fn generate_code() { | |||
| 88 | #[allow(unused_mut)] | 222 | #[allow(unused_mut)] |
| 89 | let mut output = String::new(); | 223 | let mut output = String::new(); |
| 90 | 224 | ||
| 225 | writeln!(&mut output, "{}", peripherals(singletons)).unwrap(); | ||
| 226 | |||
| 91 | #[cfg(feature = "_rt1xxx")] | 227 | #[cfg(feature = "_rt1xxx")] |
| 92 | writeln!(&mut output, "{}", generate_iomuxc()).unwrap(); | 228 | writeln!(&mut output, "{}", generate_iomuxc()).unwrap(); |
| 93 | 229 | ||
| 230 | writeln!(&mut output, "{}", interrupts()).unwrap(); | ||
| 231 | writeln!(&mut output, "{}", impl_peripherals(cfgs, singletons)).unwrap(); | ||
| 232 | |||
| 94 | let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); | 233 | let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); |
| 95 | fs::write(&out_file, output).unwrap(); | 234 | fs::write(&out_file, output).unwrap(); |
| 96 | rustfmt(&out_file); | 235 | rustfmt(&out_file); |
| 97 | } | 236 | } |
| 98 | 237 | ||
| 238 | fn interrupts() -> TokenStream { | ||
| 239 | let interrupts = METADATA.interrupts.iter().map(|interrupt| format_ident!("{interrupt}")); | ||
| 240 | |||
| 241 | quote! { | ||
| 242 | embassy_hal_internal::interrupt_mod!(#(#interrupts),*); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | fn peripherals(singletons: &[Singleton]) -> TokenStream { | ||
| 247 | let defs = singletons.iter().map(|s| { | ||
| 248 | let ident = Ident::new(&s.name, Span::call_site()); | ||
| 249 | quote! { #ident } | ||
| 250 | }); | ||
| 251 | |||
| 252 | let peripherals = singletons.iter().map(|s| { | ||
| 253 | let ident = Ident::new(&s.name, Span::call_site()); | ||
| 254 | let cfg = s.cfg.clone().unwrap_or_else(|| quote! {}); | ||
| 255 | quote! { | ||
| 256 | #cfg | ||
| 257 | #ident | ||
| 258 | } | ||
| 259 | }); | ||
| 260 | |||
| 261 | quote! { | ||
| 262 | embassy_hal_internal::peripherals_definition!(#(#defs),*); | ||
| 263 | embassy_hal_internal::peripherals_struct!(#(#peripherals),*); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | fn impl_gpio_pin(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) { | ||
| 268 | let instance = peripheral.name.strip_prefix("GPIO").unwrap(); | ||
| 269 | let bank = format_ident!("Gpio{}", instance); | ||
| 270 | // let pin = | ||
| 271 | |||
| 272 | for signal in peripheral.signals.iter() { | ||
| 273 | let pin_number = signal.name.parse::<u8>().unwrap(); | ||
| 274 | let pin = Ident::new(signal.pins[0].pin, Span::call_site()); | ||
| 275 | |||
| 276 | impls.push(quote! { | ||
| 277 | impl_pin!(#pin, #bank, #pin_number); | ||
| 278 | }); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | fn impl_dma_channel(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) { | ||
| 283 | let instance = Ident::new(peripheral.name, Span::call_site()); | ||
| 284 | |||
| 285 | for signal in peripheral.signals.iter() { | ||
| 286 | let channel_number = signal.name.parse::<u8>().unwrap(); | ||
| 287 | let channel_name = format_ident!("{instance}_CH{channel_number}"); | ||
| 288 | |||
| 289 | impls.push(quote! { | ||
| 290 | impl_dma_channel!(#instance, #channel_name, #channel_number); | ||
| 291 | }); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | fn impl_usart(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) { | ||
| 296 | let instance = Ident::new(peripheral.name, Span::call_site()); | ||
| 297 | let flexcomm = Ident::new( | ||
| 298 | peripheral.flexcomm.expect("LPC55 must specify FLEXCOMM instance"), | ||
| 299 | Span::call_site(), | ||
| 300 | ); | ||
| 301 | let number = Literal::u8_unsuffixed(peripheral.name.strip_prefix("USART").unwrap().parse::<u8>().unwrap()); | ||
| 302 | |||
| 303 | impls.push(quote! { | ||
| 304 | impl_usart_instance!(#instance, #flexcomm, #number); | ||
| 305 | }); | ||
| 306 | |||
| 307 | for signal in peripheral.signals { | ||
| 308 | let r#macro = match signal.name { | ||
| 309 | "TXD" => format_ident!("impl_usart_txd_pin"), | ||
| 310 | "RXD" => format_ident!("impl_usart_rxd_pin"), | ||
| 311 | _ => unreachable!(), | ||
| 312 | }; | ||
| 313 | |||
| 314 | for pin in signal.pins { | ||
| 315 | let alt = format_ident!("ALT{}", pin.alt); | ||
| 316 | let pin = format_ident!("{}", pin.pin); | ||
| 317 | |||
| 318 | impls.push(quote! { | ||
| 319 | #r#macro!(#pin, #instance, #alt); | ||
| 320 | }); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | for dma_mux in peripheral.dma_muxing { | ||
| 325 | assert_eq!(dma_mux.mux, "DMA0", "TODO: USART for more than LPC55"); | ||
| 326 | |||
| 327 | let r#macro = match dma_mux.signal { | ||
| 328 | "TX" => format_ident!("impl_usart_tx_channel"), | ||
| 329 | "RX" => format_ident!("impl_usart_rx_channel"), | ||
| 330 | _ => unreachable!(), | ||
| 331 | }; | ||
| 332 | |||
| 333 | let channel = format_ident!("DMA0_CH{}", dma_mux.request); | ||
| 334 | |||
| 335 | impls.push(quote! { | ||
| 336 | #r#macro!(#instance, #channel); | ||
| 337 | }); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | fn impl_sct(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) { | ||
| 342 | let instance = Ident::new(peripheral.name, Span::call_site()); | ||
| 343 | |||
| 344 | impls.push(quote! { | ||
| 345 | impl_sct_instance!(#instance); | ||
| 346 | }); | ||
| 347 | |||
| 348 | for signal in peripheral.signals.iter() { | ||
| 349 | if signal.name.starts_with("OUT") { | ||
| 350 | let channel_number = signal.name.strip_prefix("OUT").unwrap().parse::<u8>().unwrap(); | ||
| 351 | |||
| 352 | let channel_name = format_ident!("{instance}_OUT{channel_number}"); | ||
| 353 | |||
| 354 | impls.push(quote! { | ||
| 355 | impl_sct_output_instance!(#instance, #channel_name, #channel_number); | ||
| 356 | }); | ||
| 357 | |||
| 358 | if signal.name.starts_with("OUT") { | ||
| 359 | for pin in signal.pins { | ||
| 360 | let pin_name = format_ident!("{}", pin.pin); | ||
| 361 | let alt = format_ident!("ALT{}", pin.alt); | ||
| 362 | |||
| 363 | impls.push(quote! { | ||
| 364 | impl_sct_output_pin!(#instance, #channel_name, #pin_name, #alt); | ||
| 365 | }); | ||
| 366 | } | ||
| 367 | } | ||
| 368 | } | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | fn impl_peripherals(_cfgs: &mut common::CfgSet, _singletons: &[Singleton]) -> TokenStream { | ||
| 373 | let mut impls = Vec::new(); | ||
| 374 | |||
| 375 | for peripheral in metadata::METADATA.peripherals.iter() { | ||
| 376 | if peripheral.name.starts_with("GPIO") { | ||
| 377 | impl_gpio_pin(&mut impls, peripheral); | ||
| 378 | } | ||
| 379 | |||
| 380 | if peripheral.name.starts_with("DMA") { | ||
| 381 | impl_dma_channel(&mut impls, peripheral); | ||
| 382 | } | ||
| 383 | |||
| 384 | if peripheral.name.starts_with("USART") { | ||
| 385 | impl_usart(&mut impls, peripheral); | ||
| 386 | } | ||
| 387 | |||
| 388 | if peripheral.name.starts_with("SCT") { | ||
| 389 | impl_sct(&mut impls, peripheral); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | quote! { | ||
| 394 | #(#impls)* | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 99 | /// rustfmt a given path. | 398 | /// rustfmt a given path. |
| 100 | /// Failures are logged to stderr and ignored. | 399 | /// Failures are logged to stderr and ignored. |
| 101 | fn rustfmt(path: impl AsRef<Path>) { | 400 | fn rustfmt(path: impl AsRef<Path>) { |
diff --git a/embassy-nxp/src/chips/lpc55.rs b/embassy-nxp/src/chips/lpc55.rs index e9addddb6..7967e07d1 100644 --- a/embassy-nxp/src/chips/lpc55.rs +++ b/embassy-nxp/src/chips/lpc55.rs | |||
| @@ -1,121 +1,10 @@ | |||
| 1 | pub use nxp_pac as pac; | 1 | pub(crate) mod _generated { |
| 2 | #![allow(dead_code)] | ||
| 3 | #![allow(unused_imports)] | ||
| 4 | #![allow(non_snake_case)] | ||
| 5 | #![allow(missing_docs)] | ||
| 2 | 6 | ||
| 3 | embassy_hal_internal::interrupt_mod!( | 7 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); |
| 4 | FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7 | ||
| 5 | ); | ||
| 6 | |||
| 7 | embassy_hal_internal::peripherals! { | ||
| 8 | // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other | ||
| 9 | // peripheral types (e.g. I2C). | ||
| 10 | PIO0_0, | ||
| 11 | PIO0_1, | ||
| 12 | PIO0_2, | ||
| 13 | PIO0_3, | ||
| 14 | PIO0_4, | ||
| 15 | PIO0_5, | ||
| 16 | PIO0_6, | ||
| 17 | PIO0_7, | ||
| 18 | PIO0_8, | ||
| 19 | PIO0_9, | ||
| 20 | PIO0_10, | ||
| 21 | PIO0_11, | ||
| 22 | PIO0_12, | ||
| 23 | PIO0_13, | ||
| 24 | PIO0_14, | ||
| 25 | PIO0_15, | ||
| 26 | PIO0_16, | ||
| 27 | PIO0_17, | ||
| 28 | PIO0_18, | ||
| 29 | PIO0_19, | ||
| 30 | PIO0_20, | ||
| 31 | PIO0_21, | ||
| 32 | PIO0_22, | ||
| 33 | PIO0_23, | ||
| 34 | PIO0_24, | ||
| 35 | PIO0_25, | ||
| 36 | PIO0_26, | ||
| 37 | PIO0_27, | ||
| 38 | PIO0_28, | ||
| 39 | PIO0_29, | ||
| 40 | PIO0_30, | ||
| 41 | PIO0_31, | ||
| 42 | PIO1_0, | ||
| 43 | PIO1_1, | ||
| 44 | PIO1_2, | ||
| 45 | PIO1_3, | ||
| 46 | PIO1_4, | ||
| 47 | PIO1_5, | ||
| 48 | PIO1_6, | ||
| 49 | PIO1_7, | ||
| 50 | PIO1_8, | ||
| 51 | PIO1_9, | ||
| 52 | PIO1_10, | ||
| 53 | PIO1_11, | ||
| 54 | PIO1_12, | ||
| 55 | PIO1_13, | ||
| 56 | PIO1_14, | ||
| 57 | PIO1_15, | ||
| 58 | PIO1_16, | ||
| 59 | PIO1_17, | ||
| 60 | PIO1_18, | ||
| 61 | PIO1_19, | ||
| 62 | PIO1_20, | ||
| 63 | PIO1_21, | ||
| 64 | PIO1_22, | ||
| 65 | PIO1_23, | ||
| 66 | PIO1_24, | ||
| 67 | PIO1_25, | ||
| 68 | PIO1_26, | ||
| 69 | PIO1_27, | ||
| 70 | PIO1_28, | ||
| 71 | PIO1_29, | ||
| 72 | PIO1_30, | ||
| 73 | PIO1_31, | ||
| 74 | |||
| 75 | // Direct Memory Access (DMA) channels. They are used for asynchronous modes of peripherals. | ||
| 76 | DMA_CH0, | ||
| 77 | DMA_CH1, | ||
| 78 | DMA_CH2, | ||
| 79 | DMA_CH3, | ||
| 80 | DMA_CH4, | ||
| 81 | DMA_CH5, | ||
| 82 | DMA_CH6, | ||
| 83 | DMA_CH7, | ||
| 84 | DMA_CH8, | ||
| 85 | DMA_CH9, | ||
| 86 | DMA_CH10, | ||
| 87 | DMA_CH11, | ||
| 88 | DMA_CH12, | ||
| 89 | DMA_CH13, | ||
| 90 | DMA_CH14, | ||
| 91 | DMA_CH15, | ||
| 92 | DMA_CH16, | ||
| 93 | DMA_CH17, | ||
| 94 | DMA_CH18, | ||
| 95 | DMA_CH19, | ||
| 96 | DMA_CH20, | ||
| 97 | DMA_CH21, | ||
| 98 | DMA_CH22, | ||
| 99 | |||
| 100 | // Pulse-Width Modulation Outputs. | ||
| 101 | PWM_OUTPUT0, | ||
| 102 | PWM_OUTPUT1, | ||
| 103 | PWM_OUTPUT2, | ||
| 104 | PWM_OUTPUT3, | ||
| 105 | PWM_OUTPUT4, | ||
| 106 | PWM_OUTPUT5, | ||
| 107 | PWM_OUTPUT6, | ||
| 108 | PWM_OUTPUT7, | ||
| 109 | PWM_OUTPUT8, | ||
| 110 | PWM_OUTPUT9, | ||
| 111 | |||
| 112 | // Universal Synchronous/Asynchronous Receiver/Transmitter (USART) instances. | ||
| 113 | USART0, | ||
| 114 | USART1, | ||
| 115 | USART2, | ||
| 116 | USART3, | ||
| 117 | USART4, | ||
| 118 | USART5, | ||
| 119 | USART6, | ||
| 120 | USART7 | ||
| 121 | } | 8 | } |
| 9 | |||
| 10 | pub use _generated::*; | ||
diff --git a/embassy-nxp/src/chips/mimxrt1011.rs b/embassy-nxp/src/chips/mimxrt1011.rs index a74d953fc..d5969a24b 100644 --- a/embassy-nxp/src/chips/mimxrt1011.rs +++ b/embassy-nxp/src/chips/mimxrt1011.rs | |||
| @@ -1,107 +1,5 @@ | |||
| 1 | // This must be imported so that __preinit is defined. | 1 | // This must be imported so that __preinit is defined. |
| 2 | use imxrt_rt as _; | 2 | use imxrt_rt as _; |
| 3 | pub use nxp_pac as pac; | ||
| 4 | |||
| 5 | embassy_hal_internal::peripherals! { | ||
| 6 | // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other | ||
| 7 | // peripheral types (e.g. I2C). | ||
| 8 | GPIO_00, | ||
| 9 | GPIO_01, | ||
| 10 | GPIO_02, | ||
| 11 | GPIO_03, | ||
| 12 | GPIO_04, | ||
| 13 | GPIO_05, | ||
| 14 | GPIO_06, | ||
| 15 | GPIO_07, | ||
| 16 | GPIO_08, | ||
| 17 | GPIO_09, | ||
| 18 | GPIO_10, | ||
| 19 | GPIO_11, | ||
| 20 | GPIO_12, | ||
| 21 | GPIO_13, | ||
| 22 | GPIO_AD_00, | ||
| 23 | GPIO_AD_01, | ||
| 24 | GPIO_AD_02, | ||
| 25 | GPIO_AD_03, | ||
| 26 | GPIO_AD_04, | ||
| 27 | GPIO_AD_05, | ||
| 28 | GPIO_AD_06, | ||
| 29 | GPIO_AD_07, | ||
| 30 | GPIO_AD_08, | ||
| 31 | GPIO_AD_09, | ||
| 32 | GPIO_AD_10, | ||
| 33 | GPIO_AD_11, | ||
| 34 | GPIO_AD_12, | ||
| 35 | GPIO_AD_13, | ||
| 36 | GPIO_AD_14, | ||
| 37 | GPIO_SD_00, | ||
| 38 | GPIO_SD_01, | ||
| 39 | GPIO_SD_02, | ||
| 40 | GPIO_SD_03, | ||
| 41 | GPIO_SD_04, | ||
| 42 | GPIO_SD_05, | ||
| 43 | GPIO_SD_06, | ||
| 44 | GPIO_SD_07, | ||
| 45 | GPIO_SD_08, | ||
| 46 | GPIO_SD_09, | ||
| 47 | GPIO_SD_10, | ||
| 48 | GPIO_SD_11, | ||
| 49 | GPIO_SD_12, | ||
| 50 | GPIO_SD_13, | ||
| 51 | PMIC_ON_REQ, | ||
| 52 | } | ||
| 53 | |||
| 54 | impl_gpio! { | ||
| 55 | // GPIO Bank 1 | ||
| 56 | GPIO_00(Gpio1, 0); | ||
| 57 | GPIO_01(Gpio1, 1); | ||
| 58 | GPIO_02(Gpio1, 2); | ||
| 59 | GPIO_03(Gpio1, 3); | ||
| 60 | GPIO_04(Gpio1, 4); | ||
| 61 | GPIO_05(Gpio1, 5); | ||
| 62 | GPIO_06(Gpio1, 6); | ||
| 63 | GPIO_07(Gpio1, 7); | ||
| 64 | GPIO_08(Gpio1, 8); | ||
| 65 | GPIO_09(Gpio1, 9); | ||
| 66 | GPIO_10(Gpio1, 10); | ||
| 67 | GPIO_11(Gpio1, 11); | ||
| 68 | GPIO_12(Gpio1, 12); | ||
| 69 | GPIO_13(Gpio1, 13); | ||
| 70 | GPIO_AD_00(Gpio1, 14); | ||
| 71 | GPIO_AD_01(Gpio1, 15); | ||
| 72 | GPIO_AD_02(Gpio1, 16); | ||
| 73 | GPIO_AD_03(Gpio1, 17); | ||
| 74 | GPIO_AD_04(Gpio1, 18); | ||
| 75 | GPIO_AD_05(Gpio1, 19); | ||
| 76 | GPIO_AD_06(Gpio1, 20); | ||
| 77 | GPIO_AD_07(Gpio1, 21); | ||
| 78 | GPIO_AD_08(Gpio1, 22); | ||
| 79 | GPIO_AD_09(Gpio1, 23); | ||
| 80 | GPIO_AD_10(Gpio1, 24); | ||
| 81 | GPIO_AD_11(Gpio1, 25); | ||
| 82 | GPIO_AD_12(Gpio1, 26); | ||
| 83 | GPIO_AD_13(Gpio1, 27); | ||
| 84 | GPIO_AD_14(Gpio1, 28); | ||
| 85 | |||
| 86 | // GPIO Bank 2 | ||
| 87 | GPIO_SD_00(Gpio2, 0); | ||
| 88 | GPIO_SD_01(Gpio2, 1); | ||
| 89 | GPIO_SD_02(Gpio2, 2); | ||
| 90 | GPIO_SD_03(Gpio2, 3); | ||
| 91 | GPIO_SD_04(Gpio2, 4); | ||
| 92 | GPIO_SD_05(Gpio2, 5); | ||
| 93 | GPIO_SD_06(Gpio2, 6); | ||
| 94 | GPIO_SD_07(Gpio2, 7); | ||
| 95 | GPIO_SD_08(Gpio2, 8); | ||
| 96 | GPIO_SD_09(Gpio2, 9); | ||
| 97 | GPIO_SD_10(Gpio2, 10); | ||
| 98 | GPIO_SD_11(Gpio2, 11); | ||
| 99 | GPIO_SD_12(Gpio2, 12); | ||
| 100 | GPIO_SD_13(Gpio2, 13); | ||
| 101 | |||
| 102 | // GPIO Bank 5 | ||
| 103 | PMIC_ON_REQ(Gpio5, 0); | ||
| 104 | } | ||
| 105 | 3 | ||
| 106 | pub(crate) mod _generated { | 4 | pub(crate) mod _generated { |
| 107 | #![allow(dead_code)] | 5 | #![allow(dead_code)] |
| @@ -111,3 +9,5 @@ pub(crate) mod _generated { | |||
| 111 | 9 | ||
| 112 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); | 10 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); |
| 113 | } | 11 | } |
| 12 | |||
| 13 | pub use _generated::*; | ||
diff --git a/embassy-nxp/src/chips/mimxrt1062.rs b/embassy-nxp/src/chips/mimxrt1062.rs index ef153bd66..d5969a24b 100644 --- a/embassy-nxp/src/chips/mimxrt1062.rs +++ b/embassy-nxp/src/chips/mimxrt1062.rs | |||
| @@ -1,276 +1,5 @@ | |||
| 1 | // This must be imported so that __preinit is defined. | 1 | // This must be imported so that __preinit is defined. |
| 2 | use imxrt_rt as _; | 2 | use imxrt_rt as _; |
| 3 | pub use nxp_pac as pac; | ||
| 4 | |||
| 5 | embassy_hal_internal::peripherals! { | ||
| 6 | // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other | ||
| 7 | // peripheral types (e.g. I2C). | ||
| 8 | GPIO_AD_B0_00, | ||
| 9 | GPIO_AD_B0_01, | ||
| 10 | GPIO_AD_B0_02, | ||
| 11 | GPIO_AD_B0_03, | ||
| 12 | GPIO_AD_B0_04, | ||
| 13 | GPIO_AD_B0_05, | ||
| 14 | GPIO_AD_B0_06, | ||
| 15 | GPIO_AD_B0_07, | ||
| 16 | GPIO_AD_B0_08, | ||
| 17 | GPIO_AD_B0_09, | ||
| 18 | GPIO_AD_B0_10, | ||
| 19 | GPIO_AD_B0_11, | ||
| 20 | GPIO_AD_B0_12, | ||
| 21 | GPIO_AD_B0_13, | ||
| 22 | GPIO_AD_B0_14, | ||
| 23 | GPIO_AD_B0_15, | ||
| 24 | GPIO_AD_B1_00, | ||
| 25 | GPIO_AD_B1_01, | ||
| 26 | GPIO_AD_B1_02, | ||
| 27 | GPIO_AD_B1_03, | ||
| 28 | GPIO_AD_B1_04, | ||
| 29 | GPIO_AD_B1_05, | ||
| 30 | GPIO_AD_B1_06, | ||
| 31 | GPIO_AD_B1_07, | ||
| 32 | GPIO_AD_B1_08, | ||
| 33 | GPIO_AD_B1_09, | ||
| 34 | GPIO_AD_B1_10, | ||
| 35 | GPIO_AD_B1_11, | ||
| 36 | GPIO_AD_B1_12, | ||
| 37 | GPIO_AD_B1_13, | ||
| 38 | GPIO_AD_B1_14, | ||
| 39 | GPIO_AD_B1_15, | ||
| 40 | GPIO_B0_00, | ||
| 41 | GPIO_B0_01, | ||
| 42 | GPIO_B0_02, | ||
| 43 | GPIO_B0_03, | ||
| 44 | GPIO_B0_04, | ||
| 45 | GPIO_B0_05, | ||
| 46 | GPIO_B0_06, | ||
| 47 | GPIO_B0_07, | ||
| 48 | GPIO_B0_08, | ||
| 49 | GPIO_B0_09, | ||
| 50 | GPIO_B0_10, | ||
| 51 | GPIO_B0_11, | ||
| 52 | GPIO_B0_12, | ||
| 53 | GPIO_B0_13, | ||
| 54 | GPIO_B0_14, | ||
| 55 | GPIO_B0_15, | ||
| 56 | GPIO_B1_00, | ||
| 57 | GPIO_B1_01, | ||
| 58 | GPIO_B1_02, | ||
| 59 | GPIO_B1_03, | ||
| 60 | GPIO_B1_04, | ||
| 61 | GPIO_B1_05, | ||
| 62 | GPIO_B1_06, | ||
| 63 | GPIO_B1_07, | ||
| 64 | GPIO_B1_08, | ||
| 65 | GPIO_B1_09, | ||
| 66 | GPIO_B1_10, | ||
| 67 | GPIO_B1_11, | ||
| 68 | GPIO_B1_12, | ||
| 69 | GPIO_B1_13, | ||
| 70 | GPIO_B1_14, | ||
| 71 | GPIO_B1_15, | ||
| 72 | GPIO_EMC_00, | ||
| 73 | GPIO_EMC_01, | ||
| 74 | GPIO_EMC_02, | ||
| 75 | GPIO_EMC_03, | ||
| 76 | GPIO_EMC_04, | ||
| 77 | GPIO_EMC_05, | ||
| 78 | GPIO_EMC_06, | ||
| 79 | GPIO_EMC_07, | ||
| 80 | GPIO_EMC_08, | ||
| 81 | GPIO_EMC_09, | ||
| 82 | GPIO_EMC_10, | ||
| 83 | GPIO_EMC_11, | ||
| 84 | GPIO_EMC_12, | ||
| 85 | GPIO_EMC_13, | ||
| 86 | GPIO_EMC_14, | ||
| 87 | GPIO_EMC_15, | ||
| 88 | GPIO_EMC_16, | ||
| 89 | GPIO_EMC_17, | ||
| 90 | GPIO_EMC_18, | ||
| 91 | GPIO_EMC_19, | ||
| 92 | GPIO_EMC_20, | ||
| 93 | GPIO_EMC_21, | ||
| 94 | GPIO_EMC_22, | ||
| 95 | GPIO_EMC_23, | ||
| 96 | GPIO_EMC_24, | ||
| 97 | GPIO_EMC_25, | ||
| 98 | GPIO_EMC_26, | ||
| 99 | GPIO_EMC_27, | ||
| 100 | GPIO_EMC_28, | ||
| 101 | GPIO_EMC_29, | ||
| 102 | GPIO_EMC_30, | ||
| 103 | GPIO_EMC_31, | ||
| 104 | GPIO_EMC_32, | ||
| 105 | GPIO_EMC_33, | ||
| 106 | GPIO_EMC_34, | ||
| 107 | GPIO_EMC_35, | ||
| 108 | GPIO_EMC_36, | ||
| 109 | GPIO_EMC_37, | ||
| 110 | GPIO_EMC_38, | ||
| 111 | GPIO_EMC_39, | ||
| 112 | GPIO_EMC_40, | ||
| 113 | GPIO_EMC_41, | ||
| 114 | GPIO_SD_B0_00, | ||
| 115 | GPIO_SD_B0_01, | ||
| 116 | GPIO_SD_B0_02, | ||
| 117 | GPIO_SD_B0_03, | ||
| 118 | GPIO_SD_B0_04, | ||
| 119 | GPIO_SD_B0_05, | ||
| 120 | GPIO_SD_B1_00, | ||
| 121 | GPIO_SD_B1_01, | ||
| 122 | GPIO_SD_B1_02, | ||
| 123 | GPIO_SD_B1_03, | ||
| 124 | GPIO_SD_B1_04, | ||
| 125 | GPIO_SD_B1_05, | ||
| 126 | GPIO_SD_B1_06, | ||
| 127 | GPIO_SD_B1_07, | ||
| 128 | GPIO_SD_B1_08, | ||
| 129 | GPIO_SD_B1_09, | ||
| 130 | GPIO_SD_B1_10, | ||
| 131 | GPIO_SD_B1_11, | ||
| 132 | WAKEUP, | ||
| 133 | PMIC_ON_REQ, | ||
| 134 | PMIC_STBY_REQ, | ||
| 135 | } | ||
| 136 | |||
| 137 | impl_gpio! { | ||
| 138 | // GPIO Bank 1 | ||
| 139 | GPIO_AD_B0_00(Gpio1, 0); | ||
| 140 | GPIO_AD_B0_01(Gpio1, 1); | ||
| 141 | GPIO_AD_B0_02(Gpio1, 2); | ||
| 142 | GPIO_AD_B0_03(Gpio1, 3); | ||
| 143 | GPIO_AD_B0_04(Gpio1, 4); | ||
| 144 | GPIO_AD_B0_05(Gpio1, 5); | ||
| 145 | GPIO_AD_B0_06(Gpio1, 6); | ||
| 146 | GPIO_AD_B0_07(Gpio1, 7); | ||
| 147 | GPIO_AD_B0_08(Gpio1, 8); | ||
| 148 | GPIO_AD_B0_09(Gpio1, 9); | ||
| 149 | GPIO_AD_B0_10(Gpio1, 10); | ||
| 150 | GPIO_AD_B0_11(Gpio1, 11); | ||
| 151 | GPIO_AD_B0_12(Gpio1, 12); | ||
| 152 | GPIO_AD_B0_13(Gpio1, 13); | ||
| 153 | GPIO_AD_B0_14(Gpio1, 14); | ||
| 154 | GPIO_AD_B0_15(Gpio1, 15); | ||
| 155 | GPIO_AD_B1_00(Gpio1, 16); | ||
| 156 | GPIO_AD_B1_01(Gpio1, 17); | ||
| 157 | GPIO_AD_B1_02(Gpio1, 18); | ||
| 158 | GPIO_AD_B1_03(Gpio1, 19); | ||
| 159 | GPIO_AD_B1_04(Gpio1, 20); | ||
| 160 | GPIO_AD_B1_05(Gpio1, 21); | ||
| 161 | GPIO_AD_B1_06(Gpio1, 22); | ||
| 162 | GPIO_AD_B1_07(Gpio1, 23); | ||
| 163 | GPIO_AD_B1_08(Gpio1, 24); | ||
| 164 | GPIO_AD_B1_09(Gpio1, 25); | ||
| 165 | GPIO_AD_B1_10(Gpio1, 26); | ||
| 166 | GPIO_AD_B1_11(Gpio1, 27); | ||
| 167 | GPIO_AD_B1_12(Gpio1, 28); | ||
| 168 | GPIO_AD_B1_13(Gpio1, 29); | ||
| 169 | GPIO_AD_B1_14(Gpio1, 30); | ||
| 170 | GPIO_AD_B1_15(Gpio1, 31); | ||
| 171 | |||
| 172 | // GPIO Bank 2 | ||
| 173 | GPIO_B0_00(Gpio2, 0); | ||
| 174 | GPIO_B0_01(Gpio2, 1); | ||
| 175 | GPIO_B0_02(Gpio2, 2); | ||
| 176 | GPIO_B0_03(Gpio2, 3); | ||
| 177 | GPIO_B0_04(Gpio2, 4); | ||
| 178 | GPIO_B0_05(Gpio2, 5); | ||
| 179 | GPIO_B0_06(Gpio2, 6); | ||
| 180 | GPIO_B0_07(Gpio2, 7); | ||
| 181 | GPIO_B0_08(Gpio2, 8); | ||
| 182 | GPIO_B0_09(Gpio2, 9); | ||
| 183 | GPIO_B0_10(Gpio2, 10); | ||
| 184 | GPIO_B0_11(Gpio2, 11); | ||
| 185 | GPIO_B0_12(Gpio2, 12); | ||
| 186 | GPIO_B0_13(Gpio2, 13); | ||
| 187 | GPIO_B0_14(Gpio2, 14); | ||
| 188 | GPIO_B0_15(Gpio2, 15); | ||
| 189 | GPIO_B1_00(Gpio2, 16); | ||
| 190 | GPIO_B1_01(Gpio2, 17); | ||
| 191 | GPIO_B1_02(Gpio2, 18); | ||
| 192 | GPIO_B1_03(Gpio2, 19); | ||
| 193 | GPIO_B1_04(Gpio2, 20); | ||
| 194 | GPIO_B1_05(Gpio2, 21); | ||
| 195 | GPIO_B1_06(Gpio2, 22); | ||
| 196 | GPIO_B1_07(Gpio2, 23); | ||
| 197 | GPIO_B1_08(Gpio2, 24); | ||
| 198 | GPIO_B1_09(Gpio2, 25); | ||
| 199 | GPIO_B1_10(Gpio2, 26); | ||
| 200 | GPIO_B1_11(Gpio2, 27); | ||
| 201 | GPIO_B1_12(Gpio2, 28); | ||
| 202 | GPIO_B1_13(Gpio2, 29); | ||
| 203 | GPIO_B1_14(Gpio2, 30); | ||
| 204 | GPIO_B1_15(Gpio2, 31); | ||
| 205 | |||
| 206 | // GPIO Bank 4 (EMC is 4, then 3) | ||
| 207 | GPIO_EMC_00(Gpio4, 0); | ||
| 208 | GPIO_EMC_01(Gpio4, 1); | ||
| 209 | GPIO_EMC_02(Gpio4, 2); | ||
| 210 | GPIO_EMC_03(Gpio4, 3); | ||
| 211 | GPIO_EMC_04(Gpio4, 4); | ||
| 212 | GPIO_EMC_05(Gpio4, 5); | ||
| 213 | GPIO_EMC_06(Gpio4, 6); | ||
| 214 | GPIO_EMC_07(Gpio4, 7); | ||
| 215 | GPIO_EMC_08(Gpio4, 8); | ||
| 216 | GPIO_EMC_09(Gpio4, 9); | ||
| 217 | GPIO_EMC_10(Gpio4, 10); | ||
| 218 | GPIO_EMC_11(Gpio4, 11); | ||
| 219 | GPIO_EMC_12(Gpio4, 12); | ||
| 220 | GPIO_EMC_13(Gpio4, 13); | ||
| 221 | GPIO_EMC_14(Gpio4, 14); | ||
| 222 | GPIO_EMC_15(Gpio4, 15); | ||
| 223 | GPIO_EMC_16(Gpio4, 16); | ||
| 224 | GPIO_EMC_17(Gpio4, 17); | ||
| 225 | GPIO_EMC_18(Gpio4, 18); | ||
| 226 | GPIO_EMC_19(Gpio4, 19); | ||
| 227 | GPIO_EMC_20(Gpio4, 20); | ||
| 228 | GPIO_EMC_21(Gpio4, 21); | ||
| 229 | GPIO_EMC_22(Gpio4, 22); | ||
| 230 | GPIO_EMC_23(Gpio4, 23); | ||
| 231 | GPIO_EMC_24(Gpio4, 24); | ||
| 232 | GPIO_EMC_25(Gpio4, 25); | ||
| 233 | GPIO_EMC_26(Gpio4, 26); | ||
| 234 | GPIO_EMC_27(Gpio4, 27); | ||
| 235 | GPIO_EMC_28(Gpio4, 28); | ||
| 236 | GPIO_EMC_29(Gpio4, 29); | ||
| 237 | GPIO_EMC_30(Gpio4, 30); | ||
| 238 | GPIO_EMC_31(Gpio4, 31); | ||
| 239 | |||
| 240 | // GPIO Bank 3 | ||
| 241 | GPIO_EMC_32(Gpio3, 18); | ||
| 242 | GPIO_EMC_33(Gpio3, 19); | ||
| 243 | GPIO_EMC_34(Gpio3, 20); | ||
| 244 | GPIO_EMC_35(Gpio3, 21); | ||
| 245 | GPIO_EMC_36(Gpio3, 22); | ||
| 246 | GPIO_EMC_37(Gpio3, 23); | ||
| 247 | GPIO_EMC_38(Gpio3, 24); | ||
| 248 | GPIO_EMC_39(Gpio3, 25); | ||
| 249 | GPIO_EMC_40(Gpio3, 26); | ||
| 250 | GPIO_EMC_41(Gpio3, 27); | ||
| 251 | GPIO_SD_B0_00(Gpio3, 12); | ||
| 252 | GPIO_SD_B0_01(Gpio3, 13); | ||
| 253 | GPIO_SD_B0_02(Gpio3, 14); | ||
| 254 | GPIO_SD_B0_03(Gpio3, 15); | ||
| 255 | GPIO_SD_B0_04(Gpio3, 16); | ||
| 256 | GPIO_SD_B0_05(Gpio3, 17); | ||
| 257 | GPIO_SD_B1_00(Gpio3, 0); | ||
| 258 | GPIO_SD_B1_01(Gpio3, 1); | ||
| 259 | GPIO_SD_B1_02(Gpio3, 2); | ||
| 260 | GPIO_SD_B1_03(Gpio3, 3); | ||
| 261 | GPIO_SD_B1_04(Gpio3, 4); | ||
| 262 | GPIO_SD_B1_05(Gpio3, 5); | ||
| 263 | GPIO_SD_B1_06(Gpio3, 6); | ||
| 264 | GPIO_SD_B1_07(Gpio3, 7); | ||
| 265 | GPIO_SD_B1_08(Gpio3, 8); | ||
| 266 | GPIO_SD_B1_09(Gpio3, 9); | ||
| 267 | GPIO_SD_B1_10(Gpio3, 10); | ||
| 268 | GPIO_SD_B1_11(Gpio3, 11); | ||
| 269 | |||
| 270 | WAKEUP(Gpio5, 0); | ||
| 271 | PMIC_ON_REQ(Gpio5, 1); | ||
| 272 | PMIC_STBY_REQ(Gpio5, 2); | ||
| 273 | } | ||
| 274 | 3 | ||
| 275 | pub(crate) mod _generated { | 4 | pub(crate) mod _generated { |
| 276 | #![allow(dead_code)] | 5 | #![allow(dead_code)] |
| @@ -280,3 +9,5 @@ pub(crate) mod _generated { | |||
| 280 | 9 | ||
| 281 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); | 10 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); |
| 282 | } | 11 | } |
| 12 | |||
| 13 | pub use _generated::*; | ||
diff --git a/embassy-nxp/src/dma.rs b/embassy-nxp/src/dma.rs index e2df65fc9..1f479122d 100644 --- a/embassy-nxp/src/dma.rs +++ b/embassy-nxp/src/dma.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | #![macro_use] | ||
| 1 | //! Direct Memory Access (DMA) driver. | 2 | //! Direct Memory Access (DMA) driver. |
| 2 | 3 | ||
| 3 | #[cfg_attr(feature = "lpc55-core0", path = "./dma/lpc55.rs")] | 4 | #[cfg_attr(feature = "lpc55-core0", path = "./dma/lpc55.rs")] |
diff --git a/embassy-nxp/src/dma/lpc55.rs b/embassy-nxp/src/dma/lpc55.rs index 5bd763f03..623644bf1 100644 --- a/embassy-nxp/src/dma/lpc55.rs +++ b/embassy-nxp/src/dma/lpc55.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 1 | use core::cell::RefCell; | 3 | use core::cell::RefCell; |
| 2 | use core::future::Future; | 4 | use core::future::Future; |
| 3 | use core::pin::Pin; | 5 | use core::pin::Pin; |
| @@ -9,9 +11,12 @@ use embassy_hal_internal::interrupt::InterruptExt; | |||
| 9 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; | 11 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 12 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | 13 | ||
| 12 | use crate::pac::{DMA0, SYSCON, *}; | 14 | use crate::Peri; |
| 13 | use crate::{Peri, peripherals}; | 15 | #[cfg(feature = "rt")] |
| 16 | use crate::pac::interrupt; | ||
| 17 | use crate::pac::{SYSCON, *}; | ||
| 14 | 18 | ||
| 19 | #[cfg(feature = "rt")] | ||
| 15 | #[interrupt] | 20 | #[interrupt] |
| 16 | fn DMA0() { | 21 | fn DMA0() { |
| 17 | let inta = DMA0.inta0().read().ia(); | 22 | let inta = DMA0.inta0().read().ia(); |
| @@ -278,7 +283,7 @@ static DMA_DESCRIPTORS: Mutex<RefCell<DmaDescriptorTable>> = Mutex::new(RefCell: | |||
| 278 | }; CHANNEL_COUNT], | 283 | }; CHANNEL_COUNT], |
| 279 | })); | 284 | })); |
| 280 | 285 | ||
| 281 | trait SealedChannel {} | 286 | pub(crate) trait SealedChannel {} |
| 282 | trait SealedWord {} | 287 | trait SealedWord {} |
| 283 | 288 | ||
| 284 | /// DMA channel interface. | 289 | /// DMA channel interface. |
| @@ -323,7 +328,7 @@ impl Word for u32 { | |||
| 323 | 328 | ||
| 324 | /// Type erased DMA channel. | 329 | /// Type erased DMA channel. |
| 325 | pub struct AnyChannel { | 330 | pub struct AnyChannel { |
| 326 | number: u8, | 331 | pub(crate) number: u8, |
| 327 | } | 332 | } |
| 328 | 333 | ||
| 329 | impl_peripheral!(AnyChannel); | 334 | impl_peripheral!(AnyChannel); |
| @@ -335,10 +340,10 @@ impl Channel for AnyChannel { | |||
| 335 | } | 340 | } |
| 336 | } | 341 | } |
| 337 | 342 | ||
| 338 | macro_rules! channel { | 343 | macro_rules! impl_dma_channel { |
| 339 | ($name:ident, $num:expr) => { | 344 | ($instance:ident, $name:ident, $num:expr) => { |
| 340 | impl SealedChannel for peripherals::$name {} | 345 | impl crate::dma::SealedChannel for crate::peripherals::$name {} |
| 341 | impl Channel for peripherals::$name { | 346 | impl crate::dma::Channel for crate::peripherals::$name { |
| 342 | fn number(&self) -> u8 { | 347 | fn number(&self) -> u8 { |
| 343 | $num | 348 | $num |
| 344 | } | 349 | } |
| @@ -346,32 +351,10 @@ macro_rules! channel { | |||
| 346 | 351 | ||
| 347 | impl From<peripherals::$name> for crate::dma::AnyChannel { | 352 | impl From<peripherals::$name> for crate::dma::AnyChannel { |
| 348 | fn from(val: peripherals::$name) -> Self { | 353 | fn from(val: peripherals::$name) -> Self { |
| 354 | use crate::dma::Channel; | ||
| 355 | |||
| 349 | Self { number: val.number() } | 356 | Self { number: val.number() } |
| 350 | } | 357 | } |
| 351 | } | 358 | } |
| 352 | }; | 359 | }; |
| 353 | } | 360 | } |
| 354 | |||
| 355 | channel!(DMA_CH0, 0); | ||
| 356 | channel!(DMA_CH1, 1); | ||
| 357 | channel!(DMA_CH2, 2); | ||
| 358 | channel!(DMA_CH3, 3); | ||
| 359 | channel!(DMA_CH4, 4); | ||
| 360 | channel!(DMA_CH5, 5); | ||
| 361 | channel!(DMA_CH6, 6); | ||
| 362 | channel!(DMA_CH7, 7); | ||
| 363 | channel!(DMA_CH8, 8); | ||
| 364 | channel!(DMA_CH9, 9); | ||
| 365 | channel!(DMA_CH10, 10); | ||
| 366 | channel!(DMA_CH11, 11); | ||
| 367 | channel!(DMA_CH12, 12); | ||
| 368 | channel!(DMA_CH13, 13); | ||
| 369 | channel!(DMA_CH14, 14); | ||
| 370 | channel!(DMA_CH15, 15); | ||
| 371 | channel!(DMA_CH16, 16); | ||
| 372 | channel!(DMA_CH17, 17); | ||
| 373 | channel!(DMA_CH18, 18); | ||
| 374 | channel!(DMA_CH19, 19); | ||
| 375 | channel!(DMA_CH20, 20); | ||
| 376 | channel!(DMA_CH21, 21); | ||
| 377 | channel!(DMA_CH22, 22); | ||
diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs index 6039d8ca8..6be405463 100644 --- a/embassy-nxp/src/gpio/lpc55.rs +++ b/embassy-nxp/src/gpio/lpc55.rs | |||
| @@ -1,9 +1,11 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 1 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; | 3 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; |
| 2 | 4 | ||
| 5 | use crate::Peri; | ||
| 3 | use crate::pac::common::{RW, Reg}; | 6 | use crate::pac::common::{RW, Reg}; |
| 4 | use crate::pac::iocon::vals::{PioDigimode, PioMode}; | 7 | use crate::pac::iocon::vals::{PioDigimode, PioMode}; |
| 5 | use crate::pac::{GPIO, IOCON, SYSCON, iocon}; | 8 | use crate::pac::{GPIO, IOCON, SYSCON, iocon}; |
| 6 | use crate::{Peri, peripherals}; | ||
| 7 | 9 | ||
| 8 | pub(crate) fn init() { | 10 | pub(crate) fn init() { |
| 9 | // Enable clocks for GPIO, PINT, and IOCON | 11 | // Enable clocks for GPIO, PINT, and IOCON |
| @@ -39,8 +41,8 @@ pub enum Pull { | |||
| 39 | /// The LPC55 boards have two GPIO banks, each with 32 pins. This enum represents the two banks. | 41 | /// The LPC55 boards have two GPIO banks, each with 32 pins. This enum represents the two banks. |
| 40 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 42 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 41 | pub enum Bank { | 43 | pub enum Bank { |
| 42 | Bank0 = 0, | 44 | Gpio0 = 0, |
| 43 | Bank1 = 1, | 45 | Gpio1 = 1, |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | /// GPIO output driver. Internally, this is a specialized [Flex] pin. | 48 | /// GPIO output driver. Internally, this is a specialized [Flex] pin. |
| @@ -228,8 +230,8 @@ pub(crate) trait SealedPin: Sized { | |||
| 228 | #[inline] | 230 | #[inline] |
| 229 | fn pio(&self) -> Reg<iocon::regs::Pio, RW> { | 231 | fn pio(&self) -> Reg<iocon::regs::Pio, RW> { |
| 230 | match self.pin_bank() { | 232 | match self.pin_bank() { |
| 231 | Bank::Bank0 => IOCON.pio0(self.pin_number() as usize), | 233 | Bank::Gpio0 => IOCON.pio0(self.pin_number() as usize), |
| 232 | Bank::Bank1 => IOCON.pio1(self.pin_number() as usize), | 234 | Bank::Gpio1 => IOCON.pio1(self.pin_number() as usize), |
| 233 | } | 235 | } |
| 234 | } | 236 | } |
| 235 | } | 237 | } |
| @@ -254,8 +256,8 @@ pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { | |||
| 254 | 256 | ||
| 255 | /// Type-erased GPIO pin. | 257 | /// Type-erased GPIO pin. |
| 256 | pub struct AnyPin { | 258 | pub struct AnyPin { |
| 257 | pin_bank: Bank, | 259 | pub(crate) pin_bank: Bank, |
| 258 | pin_number: u8, | 260 | pub(crate) pin_number: u8, |
| 259 | } | 261 | } |
| 260 | 262 | ||
| 261 | impl AnyPin { | 263 | impl AnyPin { |
| @@ -285,12 +287,12 @@ impl SealedPin for AnyPin { | |||
| 285 | } | 287 | } |
| 286 | 288 | ||
| 287 | macro_rules! impl_pin { | 289 | macro_rules! impl_pin { |
| 288 | ($name:ident, $bank:expr, $pin_num:expr) => { | 290 | ($name:ident, $bank:ident, $pin_num:expr) => { |
| 289 | impl Pin for peripherals::$name {} | 291 | impl crate::gpio::Pin for peripherals::$name {} |
| 290 | impl SealedPin for peripherals::$name { | 292 | impl crate::gpio::SealedPin for peripherals::$name { |
| 291 | #[inline] | 293 | #[inline] |
| 292 | fn pin_bank(&self) -> Bank { | 294 | fn pin_bank(&self) -> crate::gpio::Bank { |
| 293 | $bank | 295 | crate::gpio::Bank::$bank |
| 294 | } | 296 | } |
| 295 | 297 | ||
| 296 | #[inline] | 298 | #[inline] |
| @@ -301,6 +303,8 @@ macro_rules! impl_pin { | |||
| 301 | 303 | ||
| 302 | impl From<peripherals::$name> for crate::gpio::AnyPin { | 304 | impl From<peripherals::$name> for crate::gpio::AnyPin { |
| 303 | fn from(val: peripherals::$name) -> Self { | 305 | fn from(val: peripherals::$name) -> Self { |
| 306 | use crate::gpio::SealedPin; | ||
| 307 | |||
| 304 | Self { | 308 | Self { |
| 305 | pin_bank: val.pin_bank(), | 309 | pin_bank: val.pin_bank(), |
| 306 | pin_number: val.pin_number(), | 310 | pin_number: val.pin_number(), |
| @@ -309,68 +313,3 @@ macro_rules! impl_pin { | |||
| 309 | } | 313 | } |
| 310 | }; | 314 | }; |
| 311 | } | 315 | } |
| 312 | |||
| 313 | impl_pin!(PIO0_0, Bank::Bank0, 0); | ||
| 314 | impl_pin!(PIO0_1, Bank::Bank0, 1); | ||
| 315 | impl_pin!(PIO0_2, Bank::Bank0, 2); | ||
| 316 | impl_pin!(PIO0_3, Bank::Bank0, 3); | ||
| 317 | impl_pin!(PIO0_4, Bank::Bank0, 4); | ||
| 318 | impl_pin!(PIO0_5, Bank::Bank0, 5); | ||
| 319 | impl_pin!(PIO0_6, Bank::Bank0, 6); | ||
| 320 | impl_pin!(PIO0_7, Bank::Bank0, 7); | ||
| 321 | impl_pin!(PIO0_8, Bank::Bank0, 8); | ||
| 322 | impl_pin!(PIO0_9, Bank::Bank0, 9); | ||
| 323 | impl_pin!(PIO0_10, Bank::Bank0, 10); | ||
| 324 | impl_pin!(PIO0_11, Bank::Bank0, 11); | ||
| 325 | impl_pin!(PIO0_12, Bank::Bank0, 12); | ||
| 326 | impl_pin!(PIO0_13, Bank::Bank0, 13); | ||
| 327 | impl_pin!(PIO0_14, Bank::Bank0, 14); | ||
| 328 | impl_pin!(PIO0_15, Bank::Bank0, 15); | ||
| 329 | impl_pin!(PIO0_16, Bank::Bank0, 16); | ||
| 330 | impl_pin!(PIO0_17, Bank::Bank0, 17); | ||
| 331 | impl_pin!(PIO0_18, Bank::Bank0, 18); | ||
| 332 | impl_pin!(PIO0_19, Bank::Bank0, 19); | ||
| 333 | impl_pin!(PIO0_20, Bank::Bank0, 20); | ||
| 334 | impl_pin!(PIO0_21, Bank::Bank0, 21); | ||
| 335 | impl_pin!(PIO0_22, Bank::Bank0, 22); | ||
| 336 | impl_pin!(PIO0_23, Bank::Bank0, 23); | ||
| 337 | impl_pin!(PIO0_24, Bank::Bank0, 24); | ||
| 338 | impl_pin!(PIO0_25, Bank::Bank0, 25); | ||
| 339 | impl_pin!(PIO0_26, Bank::Bank0, 26); | ||
| 340 | impl_pin!(PIO0_27, Bank::Bank0, 27); | ||
| 341 | impl_pin!(PIO0_28, Bank::Bank0, 28); | ||
| 342 | impl_pin!(PIO0_29, Bank::Bank0, 29); | ||
| 343 | impl_pin!(PIO0_30, Bank::Bank0, 30); | ||
| 344 | impl_pin!(PIO0_31, Bank::Bank0, 31); | ||
| 345 | impl_pin!(PIO1_0, Bank::Bank1, 0); | ||
| 346 | impl_pin!(PIO1_1, Bank::Bank1, 1); | ||
| 347 | impl_pin!(PIO1_2, Bank::Bank1, 2); | ||
| 348 | impl_pin!(PIO1_3, Bank::Bank1, 3); | ||
| 349 | impl_pin!(PIO1_4, Bank::Bank1, 4); | ||
| 350 | impl_pin!(PIO1_5, Bank::Bank1, 5); | ||
| 351 | impl_pin!(PIO1_6, Bank::Bank1, 6); | ||
| 352 | impl_pin!(PIO1_7, Bank::Bank1, 7); | ||
| 353 | impl_pin!(PIO1_8, Bank::Bank1, 8); | ||
| 354 | impl_pin!(PIO1_9, Bank::Bank1, 9); | ||
| 355 | impl_pin!(PIO1_10, Bank::Bank1, 10); | ||
| 356 | impl_pin!(PIO1_11, Bank::Bank1, 11); | ||
| 357 | impl_pin!(PIO1_12, Bank::Bank1, 12); | ||
| 358 | impl_pin!(PIO1_13, Bank::Bank1, 13); | ||
| 359 | impl_pin!(PIO1_14, Bank::Bank1, 14); | ||
| 360 | impl_pin!(PIO1_15, Bank::Bank1, 15); | ||
| 361 | impl_pin!(PIO1_16, Bank::Bank1, 16); | ||
| 362 | impl_pin!(PIO1_17, Bank::Bank1, 17); | ||
| 363 | impl_pin!(PIO1_18, Bank::Bank1, 18); | ||
| 364 | impl_pin!(PIO1_19, Bank::Bank1, 19); | ||
| 365 | impl_pin!(PIO1_20, Bank::Bank1, 20); | ||
| 366 | impl_pin!(PIO1_21, Bank::Bank1, 21); | ||
| 367 | impl_pin!(PIO1_22, Bank::Bank1, 22); | ||
| 368 | impl_pin!(PIO1_23, Bank::Bank1, 23); | ||
| 369 | impl_pin!(PIO1_24, Bank::Bank1, 24); | ||
| 370 | impl_pin!(PIO1_25, Bank::Bank1, 25); | ||
| 371 | impl_pin!(PIO1_26, Bank::Bank1, 26); | ||
| 372 | impl_pin!(PIO1_27, Bank::Bank1, 27); | ||
| 373 | impl_pin!(PIO1_28, Bank::Bank1, 28); | ||
| 374 | impl_pin!(PIO1_29, Bank::Bank1, 29); | ||
| 375 | impl_pin!(PIO1_30, Bank::Bank1, 30); | ||
| 376 | impl_pin!(PIO1_31, Bank::Bank1, 31); | ||
diff --git a/embassy-nxp/src/gpio/rt1xxx.rs b/embassy-nxp/src/gpio/rt1xxx.rs index c4dc110ff..8a560310c 100644 --- a/embassy-nxp/src/gpio/rt1xxx.rs +++ b/embassy-nxp/src/gpio/rt1xxx.rs | |||
| @@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 10 | use nxp_pac::gpio::vals::Icr; | 10 | use nxp_pac::gpio::vals::Icr; |
| 11 | use nxp_pac::iomuxc::vals::Pus; | 11 | use nxp_pac::iomuxc::vals::Pus; |
| 12 | 12 | ||
| 13 | use crate::chip::{mux_address, pad_address}; | 13 | use crate::chip::{iomuxc_mux, iomuxc_pad}; |
| 14 | use crate::pac::common::{RW, Reg}; | 14 | use crate::pac::common::{RW, Reg}; |
| 15 | use crate::pac::gpio::Gpio; | 15 | use crate::pac::gpio::Gpio; |
| 16 | #[cfg(feature = "rt")] | 16 | #[cfg(feature = "rt")] |
| @@ -121,6 +121,10 @@ pub enum Bank { | |||
| 121 | /// Bank 5 | 121 | /// Bank 5 |
| 122 | #[cfg(gpio5)] | 122 | #[cfg(gpio5)] |
| 123 | Gpio5, | 123 | Gpio5, |
| 124 | |||
| 125 | #[cfg(gpio10)] | ||
| 126 | /// Bank 10 | ||
| 127 | Gpio10, | ||
| 124 | } | 128 | } |
| 125 | 129 | ||
| 126 | /// GPIO flexible pin. | 130 | /// GPIO flexible pin. |
| @@ -656,6 +660,8 @@ static GPIO3_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; | |||
| 656 | static GPIO4_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; | 660 | static GPIO4_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; |
| 657 | #[cfg(gpio5)] | 661 | #[cfg(gpio5)] |
| 658 | static GPIO5_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; | 662 | static GPIO5_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; |
| 663 | #[cfg(gpio10)] | ||
| 664 | static GPIO10_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; | ||
| 659 | 665 | ||
| 660 | /// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate. | 666 | /// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate. |
| 661 | pub(crate) trait SealedPin: Sized { | 667 | pub(crate) trait SealedPin: Sized { |
| @@ -676,13 +682,15 @@ pub(crate) trait SealedPin: Sized { | |||
| 676 | Bank::Gpio4 => pac::GPIO4, | 682 | Bank::Gpio4 => pac::GPIO4, |
| 677 | #[cfg(gpio5)] | 683 | #[cfg(gpio5)] |
| 678 | Bank::Gpio5 => pac::GPIO5, | 684 | Bank::Gpio5 => pac::GPIO5, |
| 685 | #[cfg(gpio10)] | ||
| 686 | Bank::Gpio10 => pac::GPIO10, | ||
| 679 | } | 687 | } |
| 680 | } | 688 | } |
| 681 | 689 | ||
| 682 | #[inline] | 690 | #[inline] |
| 683 | fn mux(&self) -> Reg<MuxCtl, RW> { | 691 | fn mux(&self) -> Reg<MuxCtl, RW> { |
| 684 | // SAFETY: The generated mux address table is valid since it is generated from the SVD files. | 692 | // SAFETY: The generated mux address table is valid since it is generated from the SVD files. |
| 685 | let address = unsafe { mux_address(self._bank(), self.pin_number()).unwrap_unchecked() }; | 693 | let address = unsafe { iomuxc_mux(self._bank(), self.pin_number()).unwrap_unchecked() }; |
| 686 | 694 | ||
| 687 | // SAFETY: The register at the address is an instance of MuxCtl. | 695 | // SAFETY: The register at the address is an instance of MuxCtl. |
| 688 | unsafe { Reg::from_ptr(address as *mut _) } | 696 | unsafe { Reg::from_ptr(address as *mut _) } |
| @@ -690,8 +698,7 @@ pub(crate) trait SealedPin: Sized { | |||
| 690 | 698 | ||
| 691 | #[inline] | 699 | #[inline] |
| 692 | fn pad(&self) -> Reg<Ctl, RW> { | 700 | fn pad(&self) -> Reg<Ctl, RW> { |
| 693 | // SAFETY: The generated pad address table is valid since it is generated from the SVD files. | 701 | let address = iomuxc_pad(self._bank(), self.pin_number()); |
| 694 | let address = unsafe { pad_address(self._bank(), self.pin_number()).unwrap_unchecked() }; | ||
| 695 | 702 | ||
| 696 | // SAFETY: The register at the address is an instance of Ctl. | 703 | // SAFETY: The register at the address is an instance of Ctl. |
| 697 | unsafe { Reg::from_ptr(address as *mut _) } | 704 | unsafe { Reg::from_ptr(address as *mut _) } |
| @@ -709,6 +716,8 @@ pub(crate) trait SealedPin: Sized { | |||
| 709 | Bank::Gpio4 => &GPIO4_WAKERS[self.pin_number() as usize], | 716 | Bank::Gpio4 => &GPIO4_WAKERS[self.pin_number() as usize], |
| 710 | #[cfg(gpio5)] | 717 | #[cfg(gpio5)] |
| 711 | Bank::Gpio5 => &GPIO5_WAKERS[self.pin_number() as usize], | 718 | Bank::Gpio5 => &GPIO5_WAKERS[self.pin_number() as usize], |
| 719 | #[cfg(gpio10)] | ||
| 720 | Bank::Gpio10 => &GPIO10_WAKERS[self.pin_number() as usize], | ||
| 712 | } | 721 | } |
| 713 | } | 722 | } |
| 714 | } | 723 | } |
| @@ -793,39 +802,6 @@ impl<'d> Future for InputFuture<'d> { | |||
| 793 | } | 802 | } |
| 794 | } | 803 | } |
| 795 | 804 | ||
| 796 | /// A macro to generate all GPIO pins. | ||
| 797 | /// | ||
| 798 | /// This generates a lookup table for IOMUX register addresses. | ||
| 799 | macro_rules! impl_gpio { | ||
| 800 | ( | ||
| 801 | $($name: ident($bank: ident, $pin_number: expr);)* | ||
| 802 | ) => { | ||
| 803 | #[inline] | ||
| 804 | pub(crate) const fn pad_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> { | ||
| 805 | match (bank, pin) { | ||
| 806 | $( | ||
| 807 | (crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::pads::$name), | ||
| 808 | )* | ||
| 809 | _ => None | ||
| 810 | } | ||
| 811 | } | ||
| 812 | |||
| 813 | #[inline] | ||
| 814 | pub(crate) const fn mux_address(bank: crate::gpio::Bank, pin: u8) -> Option<u32> { | ||
| 815 | match (bank, pin) { | ||
| 816 | $( | ||
| 817 | (crate::gpio::Bank::$bank, $pin_number) => Some(crate::chip::_generated::iomuxc::muxes::$name), | ||
| 818 | )* | ||
| 819 | _ => None | ||
| 820 | } | ||
| 821 | } | ||
| 822 | |||
| 823 | $( | ||
| 824 | impl_pin!($name, $bank, $pin_number); | ||
| 825 | )* | ||
| 826 | }; | ||
| 827 | } | ||
| 828 | |||
| 829 | macro_rules! impl_pin { | 805 | macro_rules! impl_pin { |
| 830 | ($name: ident, $bank: ident, $pin_num: expr) => { | 806 | ($name: ident, $bank: ident, $pin_num: expr) => { |
| 831 | impl crate::gpio::Pin for crate::peripherals::$name {} | 807 | impl crate::gpio::Pin for crate::peripherals::$name {} |
diff --git a/embassy-nxp/src/iomuxc.rs b/embassy-nxp/src/iomuxc.rs new file mode 100644 index 000000000..c015ecbc2 --- /dev/null +++ b/embassy-nxp/src/iomuxc.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | /// An IOMUXC pad. | ||
| 4 | /// | ||
| 5 | /// This trait does not imply that GPIO can be used with this pad. [`Pin`](crate::gpio::Pin) must | ||
| 6 | /// also be implemented for GPIO. | ||
| 7 | #[allow(private_bounds)] | ||
| 8 | pub trait Pad: SealedPad {} | ||
| 9 | |||
| 10 | pub(crate) trait SealedPad { | ||
| 11 | /// Address of the pad register for this pad. | ||
| 12 | const PAD: *mut (); | ||
| 13 | |||
| 14 | /// Address of the mux register for this pad. | ||
| 15 | /// | ||
| 16 | /// Some pads do not allow muxing (e.g. ONOFF). | ||
| 17 | const MUX: Option<*mut ()>; | ||
| 18 | } | ||
| 19 | |||
| 20 | macro_rules! impl_iomuxc_pad { | ||
| 21 | ($name: ident, $pad: expr, $mux: expr) => { | ||
| 22 | impl crate::iomuxc::SealedPad for crate::peripherals::$name { | ||
| 23 | const PAD: *mut () = $pad as *mut (); | ||
| 24 | const MUX: Option<*mut ()> = Some($mux as *mut ()); | ||
| 25 | } | ||
| 26 | |||
| 27 | impl crate::iomuxc::Pad for crate::peripherals::$name {} | ||
| 28 | }; | ||
| 29 | } | ||
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index 4058881a5..4c3dbebb9 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs | |||
| @@ -12,8 +12,13 @@ pub mod pint; | |||
| 12 | #[cfg(feature = "lpc55-core0")] | 12 | #[cfg(feature = "lpc55-core0")] |
| 13 | pub mod pwm; | 13 | pub mod pwm; |
| 14 | #[cfg(feature = "lpc55-core0")] | 14 | #[cfg(feature = "lpc55-core0")] |
| 15 | pub mod sct; | ||
| 16 | #[cfg(feature = "lpc55-core0")] | ||
| 15 | pub mod usart; | 17 | pub mod usart; |
| 16 | 18 | ||
| 19 | #[cfg(rt1xxx)] | ||
| 20 | mod iomuxc; | ||
| 21 | |||
| 17 | #[cfg(feature = "_time_driver")] | 22 | #[cfg(feature = "_time_driver")] |
| 18 | #[cfg_attr(feature = "time-driver-pit", path = "time_driver/pit.rs")] | 23 | #[cfg_attr(feature = "time-driver-pit", path = "time_driver/pit.rs")] |
| 19 | #[cfg_attr(feature = "time-driver-rtc", path = "time_driver/rtc.rs")] | 24 | #[cfg_attr(feature = "time-driver-rtc", path = "time_driver/rtc.rs")] |
| @@ -25,15 +30,12 @@ mod time_driver; | |||
| 25 | #[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")] | 30 | #[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")] |
| 26 | mod chip; | 31 | mod chip; |
| 27 | 32 | ||
| 28 | // TODO: Remove when this module is implemented for other chips | 33 | pub use chip::{Peripherals, interrupt, peripherals}; |
| 29 | #[cfg(feature = "lpc55-core0")] | 34 | pub use embassy_hal_internal::{Peri, PeripheralType}; |
| 30 | pub use chip::interrupt; | ||
| 31 | #[cfg(feature = "unstable-pac")] | 35 | #[cfg(feature = "unstable-pac")] |
| 32 | pub use chip::pac; | 36 | pub use nxp_pac as pac; |
| 33 | #[cfg(not(feature = "unstable-pac"))] | 37 | #[cfg(not(feature = "unstable-pac"))] |
| 34 | pub(crate) use chip::pac; | 38 | pub(crate) use nxp_pac as pac; |
| 35 | pub use chip::{Peripherals, peripherals}; | ||
| 36 | pub use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 37 | 39 | ||
| 38 | /// Macro to bind interrupts to handlers. | 40 | /// Macro to bind interrupts to handlers. |
| 39 | /// (Copied from `embassy-rp`) | 41 | /// (Copied from `embassy-rp`) |
diff --git a/embassy-nxp/src/pwm.rs b/embassy-nxp/src/pwm.rs index 68980924a..c87a39c34 100644 --- a/embassy-nxp/src/pwm.rs +++ b/embassy-nxp/src/pwm.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 1 | //! Pulse-Width Modulation (PWM) driver. | 3 | //! Pulse-Width Modulation (PWM) driver. |
| 2 | 4 | ||
| 3 | #[cfg_attr(feature = "lpc55-core0", path = "./pwm/lpc55.rs")] | 5 | #[cfg_attr(feature = "lpc55-core0", path = "./pwm/lpc55.rs")] |
diff --git a/embassy-nxp/src/pwm/lpc55.rs b/embassy-nxp/src/pwm/lpc55.rs index 197184ad6..4cdbd8526 100644 --- a/embassy-nxp/src/pwm/lpc55.rs +++ b/embassy-nxp/src/pwm/lpc55.rs | |||
| @@ -1,12 +1,15 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 1 | use core::sync::atomic::{AtomicU8, AtomicU32, Ordering}; | 3 | use core::sync::atomic::{AtomicU8, AtomicU32, Ordering}; |
| 2 | 4 | ||
| 3 | use embassy_hal_internal::{Peri, PeripheralType}; | 5 | use embassy_hal_internal::Peri; |
| 4 | 6 | ||
| 5 | use crate::gpio::AnyPin; | 7 | use crate::gpio::AnyPin; |
| 6 | use crate::pac::iocon::vals::{PioDigimode, PioFunc, PioMode, PioOd, PioSlew}; | 8 | use crate::pac::iocon::vals::{PioDigimode, PioMode, PioOd, PioSlew}; |
| 7 | use crate::pac::sct0::vals; | 9 | use crate::pac::sct0::vals; |
| 8 | use crate::pac::syscon::vals::{SctRst, SctclkselSel}; | 10 | use crate::pac::syscon::vals::{SctRst, SctclkselSel}; |
| 9 | use crate::pac::{SCT0, SYSCON}; | 11 | use crate::pac::{SCT0, SYSCON}; |
| 12 | use crate::sct; | ||
| 10 | 13 | ||
| 11 | // Since for now the counter is shared, the TOP value has to be kept. | 14 | // Since for now the counter is shared, the TOP value has to be kept. |
| 12 | static TOP_VALUE: AtomicU32 = AtomicU32::new(0); | 15 | static TOP_VALUE: AtomicU32 = AtomicU32::new(0); |
| @@ -75,7 +78,11 @@ impl<'d> Pwm<'d> { | |||
| 75 | SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::ASSERTED)); | 78 | SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::ASSERTED)); |
| 76 | SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::RELEASED)); | 79 | SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::RELEASED)); |
| 77 | } | 80 | } |
| 78 | fn new_inner<T: Output>(output: usize, channel: Peri<'d, impl OutputChannelPin<T>>, config: Config) -> Self { | 81 | fn new_inner<T: sct::Instance, O: sct::Output<T>>( |
| 82 | output: usize, | ||
| 83 | channel: Peri<'d, impl sct::OutputPin<T, O>>, | ||
| 84 | config: Config, | ||
| 85 | ) -> Self { | ||
| 79 | // Enable clocks (Syscon is enabled by default) | 86 | // Enable clocks (Syscon is enabled by default) |
| 80 | critical_section::with(|_cs| { | 87 | critical_section::with(|_cs| { |
| 81 | if !SYSCON.ahbclkctrl0().read().iocon() { | 88 | if !SYSCON.ahbclkctrl0().read().iocon() { |
| @@ -109,12 +116,12 @@ impl<'d> Pwm<'d> { | |||
| 109 | 116 | ||
| 110 | /// Create PWM driver with a single 'a' pin as output. | 117 | /// Create PWM driver with a single 'a' pin as output. |
| 111 | #[inline] | 118 | #[inline] |
| 112 | pub fn new_output<T: Output>( | 119 | pub fn new_output<T: sct::Instance, O: sct::Output<T>>( |
| 113 | output: Peri<'d, T>, | 120 | output: Peri<'d, O>, |
| 114 | channel: Peri<'d, impl OutputChannelPin<T>>, | 121 | channel: Peri<'d, impl sct::OutputPin<T, O>>, |
| 115 | config: Config, | 122 | config: Config, |
| 116 | ) -> Self { | 123 | ) -> Self { |
| 117 | Self::new_inner(output.number(), channel, config) | 124 | Self::new_inner::<T, O>(output.number(), channel, config) |
| 118 | } | 125 | } |
| 119 | 126 | ||
| 120 | /// Set the PWM config. | 127 | /// Set the PWM config. |
| @@ -196,18 +203,18 @@ impl<'d> Pwm<'d> { | |||
| 196 | // TODO(frihetselsker): optimize nxp-pac so that `set_clr` and `set_set` are turned into a bit array. | 203 | // TODO(frihetselsker): optimize nxp-pac so that `set_clr` and `set_set` are turned into a bit array. |
| 197 | if config.invert { | 204 | if config.invert { |
| 198 | // Low when event 0 is active | 205 | // Low when event 0 is active |
| 199 | SCT0.out(output_number).out_clr().modify(|w| w.set_clr(1 << 0)); | 206 | SCT0.out(output_number).out_clr().modify(|w| w.set_clr(0, true)); |
| 200 | // High when event `output_number + 1` is active | 207 | // High when event `output_number + 1` is active |
| 201 | SCT0.out(output_number) | 208 | SCT0.out(output_number) |
| 202 | .out_set() | 209 | .out_set() |
| 203 | .modify(|w| w.set_set(1 << (output_number + 1))); | 210 | .modify(|w| w.set_set(output_number, true)); |
| 204 | } else { | 211 | } else { |
| 205 | // High when event 0 is active | 212 | // High when event 0 is active |
| 206 | SCT0.out(output_number).out_set().modify(|w| w.set_set(1 << 0)); | 213 | SCT0.out(output_number).out_set().modify(|w| w.set_set(0, true)); |
| 207 | // Low when event `output_number + 1` is active | 214 | // Low when event `output_number + 1` is active |
| 208 | SCT0.out(output_number) | 215 | SCT0.out(output_number) |
| 209 | .out_clr() | 216 | .out_clr() |
| 210 | .modify(|w| w.set_clr(1 << (output_number + 1))); | 217 | .modify(|w| w.set_clr(output_number, true)); |
| 211 | } | 218 | } |
| 212 | 219 | ||
| 213 | if config.phase_correct { | 220 | if config.phase_correct { |
| @@ -239,87 +246,3 @@ impl<'d> Drop for Pwm<'d> { | |||
| 239 | } | 246 | } |
| 240 | } | 247 | } |
| 241 | } | 248 | } |
| 242 | |||
| 243 | trait SealedOutput { | ||
| 244 | /// Output number. | ||
| 245 | fn number(&self) -> usize; | ||
| 246 | } | ||
| 247 | |||
| 248 | /// PWM Output. | ||
| 249 | #[allow(private_bounds)] | ||
| 250 | pub trait Output: PeripheralType + SealedOutput {} | ||
| 251 | |||
| 252 | macro_rules! output { | ||
| 253 | ($name:ident, $num:expr) => { | ||
| 254 | impl SealedOutput for crate::peripherals::$name { | ||
| 255 | fn number(&self) -> usize { | ||
| 256 | $num | ||
| 257 | } | ||
| 258 | } | ||
| 259 | impl Output for crate::peripherals::$name {} | ||
| 260 | }; | ||
| 261 | } | ||
| 262 | |||
| 263 | output!(PWM_OUTPUT0, 0); | ||
| 264 | output!(PWM_OUTPUT1, 1); | ||
| 265 | output!(PWM_OUTPUT2, 2); | ||
| 266 | output!(PWM_OUTPUT3, 3); | ||
| 267 | output!(PWM_OUTPUT4, 4); | ||
| 268 | output!(PWM_OUTPUT5, 5); | ||
| 269 | output!(PWM_OUTPUT6, 6); | ||
| 270 | output!(PWM_OUTPUT7, 7); | ||
| 271 | output!(PWM_OUTPUT8, 8); | ||
| 272 | output!(PWM_OUTPUT9, 9); | ||
| 273 | |||
| 274 | /// PWM Output Channel. | ||
| 275 | pub trait OutputChannelPin<T: Output>: crate::gpio::Pin { | ||
| 276 | fn pin_func(&self) -> PioFunc; | ||
| 277 | } | ||
| 278 | |||
| 279 | macro_rules! impl_pin { | ||
| 280 | ($pin:ident, $output:ident, $func:ident) => { | ||
| 281 | impl crate::pwm::inner::OutputChannelPin<crate::peripherals::$output> for crate::peripherals::$pin { | ||
| 282 | fn pin_func(&self) -> PioFunc { | ||
| 283 | PioFunc::$func | ||
| 284 | } | ||
| 285 | } | ||
| 286 | }; | ||
| 287 | } | ||
| 288 | |||
| 289 | impl_pin!(PIO0_2, PWM_OUTPUT0, ALT3); | ||
| 290 | impl_pin!(PIO0_17, PWM_OUTPUT0, ALT4); | ||
| 291 | impl_pin!(PIO1_4, PWM_OUTPUT0, ALT4); | ||
| 292 | impl_pin!(PIO1_23, PWM_OUTPUT0, ALT2); | ||
| 293 | |||
| 294 | impl_pin!(PIO0_3, PWM_OUTPUT1, ALT3); | ||
| 295 | impl_pin!(PIO0_18, PWM_OUTPUT1, ALT4); | ||
| 296 | impl_pin!(PIO1_8, PWM_OUTPUT1, ALT4); | ||
| 297 | impl_pin!(PIO1_24, PWM_OUTPUT1, ALT2); | ||
| 298 | |||
| 299 | impl_pin!(PIO0_10, PWM_OUTPUT2, ALT5); | ||
| 300 | impl_pin!(PIO0_15, PWM_OUTPUT2, ALT4); | ||
| 301 | impl_pin!(PIO0_19, PWM_OUTPUT2, ALT4); | ||
| 302 | impl_pin!(PIO1_9, PWM_OUTPUT2, ALT4); | ||
| 303 | impl_pin!(PIO1_25, PWM_OUTPUT2, ALT2); | ||
| 304 | |||
| 305 | impl_pin!(PIO0_22, PWM_OUTPUT3, ALT4); | ||
| 306 | impl_pin!(PIO0_31, PWM_OUTPUT3, ALT4); | ||
| 307 | impl_pin!(PIO1_10, PWM_OUTPUT3, ALT4); | ||
| 308 | impl_pin!(PIO1_26, PWM_OUTPUT3, ALT2); | ||
| 309 | |||
| 310 | impl_pin!(PIO0_23, PWM_OUTPUT4, ALT4); | ||
| 311 | impl_pin!(PIO1_3, PWM_OUTPUT4, ALT4); | ||
| 312 | impl_pin!(PIO1_17, PWM_OUTPUT4, ALT4); | ||
| 313 | |||
| 314 | impl_pin!(PIO0_26, PWM_OUTPUT5, ALT4); | ||
| 315 | impl_pin!(PIO1_18, PWM_OUTPUT5, ALT4); | ||
| 316 | |||
| 317 | impl_pin!(PIO0_27, PWM_OUTPUT6, ALT4); | ||
| 318 | impl_pin!(PIO1_31, PWM_OUTPUT6, ALT4); | ||
| 319 | |||
| 320 | impl_pin!(PIO0_28, PWM_OUTPUT7, ALT4); | ||
| 321 | impl_pin!(PIO1_19, PWM_OUTPUT7, ALT2); | ||
| 322 | |||
| 323 | impl_pin!(PIO0_29, PWM_OUTPUT8, ALT4); | ||
| 324 | |||
| 325 | impl_pin!(PIO0_30, PWM_OUTPUT9, ALT4); | ||
diff --git a/embassy-nxp/src/sct.rs b/embassy-nxp/src/sct.rs new file mode 100644 index 000000000..b6b0e35a9 --- /dev/null +++ b/embassy-nxp/src/sct.rs | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use embassy_hal_internal::PeripheralType; | ||
| 4 | use nxp_pac::iocon::vals::PioFunc; | ||
| 5 | |||
| 6 | use crate::gpio; | ||
| 7 | |||
| 8 | /// SCT instance. | ||
| 9 | #[allow(private_bounds)] | ||
| 10 | pub trait Instance: SealedInstance + PeripheralType {} | ||
| 11 | |||
| 12 | pub(crate) trait SealedInstance {} | ||
| 13 | |||
| 14 | /// An SCT output. | ||
| 15 | #[allow(private_bounds)] | ||
| 16 | pub trait Output<T: Instance>: SealedOutput + PeripheralType {} | ||
| 17 | |||
| 18 | pub(crate) trait SealedOutput { | ||
| 19 | /// Output number. | ||
| 20 | fn number(&self) -> usize; | ||
| 21 | } | ||
| 22 | |||
| 23 | /// An SCT output capable pin. | ||
| 24 | pub trait OutputPin<T: Instance, O: Output<T>>: gpio::Pin { | ||
| 25 | fn pin_func(&self) -> PioFunc; | ||
| 26 | } | ||
| 27 | |||
| 28 | macro_rules! impl_sct_instance { | ||
| 29 | ($instance: ident) => { | ||
| 30 | impl crate::sct::SealedInstance for crate::peripherals::$instance {} | ||
| 31 | impl crate::sct::Instance for crate::peripherals::$instance {} | ||
| 32 | }; | ||
| 33 | } | ||
| 34 | |||
| 35 | macro_rules! impl_sct_output_instance { | ||
| 36 | ($instance: ident, $name: ident, $num: expr) => { | ||
| 37 | impl crate::sct::SealedOutput for crate::peripherals::$name { | ||
| 38 | fn number(&self) -> usize { | ||
| 39 | $num as usize | ||
| 40 | } | ||
| 41 | } | ||
| 42 | impl crate::sct::Output<crate::peripherals::$instance> for crate::peripherals::$name {} | ||
| 43 | }; | ||
| 44 | } | ||
| 45 | |||
| 46 | macro_rules! impl_sct_output_pin { | ||
| 47 | ($instance: ident, $output_instance: ident, $pin: ident, $alt: ident) => { | ||
| 48 | impl crate::sct::OutputPin<crate::peripherals::$instance, crate::peripherals::$output_instance> | ||
| 49 | for crate::peripherals::$pin | ||
| 50 | { | ||
| 51 | fn pin_func(&self) -> crate::pac::iocon::vals::PioFunc { | ||
| 52 | crate::pac::iocon::vals::PioFunc::$alt | ||
| 53 | } | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | } | ||
diff --git a/embassy-nxp/src/usart.rs b/embassy-nxp/src/usart.rs index 1d8886f24..af039dee4 100644 --- a/embassy-nxp/src/usart.rs +++ b/embassy-nxp/src/usart.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 1 | //! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver. | 3 | //! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver. |
| 2 | 4 | ||
| 3 | #[cfg_attr(feature = "lpc55-core0", path = "./usart/lpc55.rs")] | 5 | #[cfg_attr(feature = "lpc55-core0", path = "./usart/lpc55.rs")] |
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index d54927b25..d77f08fd8 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 1 | use core::fmt::Debug; | 3 | use core::fmt::Debug; |
| 2 | use core::future::poll_fn; | 4 | use core::future::poll_fn; |
| 3 | use core::marker::PhantomData; | 5 | use core::marker::PhantomData; |
| @@ -13,7 +15,7 @@ use embedded_io::{self, ErrorKind}; | |||
| 13 | use crate::dma::{AnyChannel, Channel}; | 15 | use crate::dma::{AnyChannel, Channel}; |
| 14 | use crate::gpio::{AnyPin, SealedPin}; | 16 | use crate::gpio::{AnyPin, SealedPin}; |
| 15 | use crate::interrupt::Interrupt; | 17 | use crate::interrupt::Interrupt; |
| 16 | use crate::interrupt::typelevel::{Binding, Interrupt as _}; | 18 | use crate::interrupt::typelevel::Binding; |
| 17 | use crate::pac::flexcomm::Flexcomm as FlexcommReg; | 19 | use crate::pac::flexcomm::Flexcomm as FlexcommReg; |
| 18 | use crate::pac::iocon::vals::PioFunc; | 20 | use crate::pac::iocon::vals::PioFunc; |
| 19 | use crate::pac::usart::Usart as UsartReg; | 21 | use crate::pac::usart::Usart as UsartReg; |
| @@ -113,8 +115,8 @@ impl Default for Config { | |||
| 113 | 115 | ||
| 114 | /// Internal DMA state of UART RX. | 116 | /// Internal DMA state of UART RX. |
| 115 | pub struct DmaState { | 117 | pub struct DmaState { |
| 116 | rx_err_waker: AtomicWaker, | 118 | pub(crate) rx_err_waker: AtomicWaker, |
| 117 | rx_err: AtomicBool, | 119 | pub(crate) rx_err: AtomicBool, |
| 118 | } | 120 | } |
| 119 | 121 | ||
| 120 | /// # Type parameters | 122 | /// # Type parameters |
| @@ -818,13 +820,13 @@ impl<'d> embedded_io::Read for Usart<'d, Blocking> { | |||
| 818 | } | 820 | } |
| 819 | } | 821 | } |
| 820 | 822 | ||
| 821 | struct Info { | 823 | pub(crate) struct Info { |
| 822 | usart_reg: UsartReg, | 824 | pub(crate) usart_reg: UsartReg, |
| 823 | fc_reg: FlexcommReg, | 825 | pub(crate) fc_reg: FlexcommReg, |
| 824 | interrupt: Interrupt, | 826 | pub(crate) interrupt: Interrupt, |
| 825 | } | 827 | } |
| 826 | 828 | ||
| 827 | trait SealedInstance { | 829 | pub(crate) trait SealedInstance { |
| 828 | fn info() -> &'static Info; | 830 | fn info() -> &'static Info; |
| 829 | fn dma_state() -> &'static DmaState; | 831 | fn dma_state() -> &'static DmaState; |
| 830 | fn instance_number() -> usize; | 832 | fn instance_number() -> usize; |
| @@ -837,10 +839,13 @@ pub trait Instance: SealedInstance + PeripheralType { | |||
| 837 | type Interrupt: crate::interrupt::typelevel::Interrupt; | 839 | type Interrupt: crate::interrupt::typelevel::Interrupt; |
| 838 | } | 840 | } |
| 839 | 841 | ||
| 840 | macro_rules! impl_instance { | 842 | macro_rules! impl_usart_instance { |
| 841 | ($inst:ident, $fc:ident, $fc_num:expr) => { | 843 | ($inst:ident, $fc:ident, $fc_num:expr) => { |
| 842 | impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst { | 844 | impl crate::usart::SealedInstance for $crate::peripherals::$inst { |
| 843 | fn info() -> &'static Info { | 845 | fn info() -> &'static crate::usart::Info { |
| 846 | use crate::interrupt::typelevel::Interrupt; | ||
| 847 | use crate::usart::Info; | ||
| 848 | |||
| 844 | static INFO: Info = Info { | 849 | static INFO: Info = Info { |
| 845 | usart_reg: crate::pac::$inst, | 850 | usart_reg: crate::pac::$inst, |
| 846 | fc_reg: crate::pac::$fc, | 851 | fc_reg: crate::pac::$fc, |
| @@ -849,7 +854,13 @@ macro_rules! impl_instance { | |||
| 849 | &INFO | 854 | &INFO |
| 850 | } | 855 | } |
| 851 | 856 | ||
| 852 | fn dma_state() -> &'static DmaState { | 857 | fn dma_state() -> &'static crate::usart::DmaState { |
| 858 | use core::sync::atomic::AtomicBool; | ||
| 859 | |||
| 860 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 861 | |||
| 862 | use crate::usart::DmaState; | ||
| 863 | |||
| 853 | static STATE: DmaState = DmaState { | 864 | static STATE: DmaState = DmaState { |
| 854 | rx_err_waker: AtomicWaker::new(), | 865 | rx_err_waker: AtomicWaker::new(), |
| 855 | rx_err: AtomicBool::new(false), | 866 | rx_err: AtomicBool::new(false), |
| @@ -867,15 +878,6 @@ macro_rules! impl_instance { | |||
| 867 | }; | 878 | }; |
| 868 | } | 879 | } |
| 869 | 880 | ||
| 870 | impl_instance!(USART0, FLEXCOMM0, 0); | ||
| 871 | impl_instance!(USART1, FLEXCOMM1, 1); | ||
| 872 | impl_instance!(USART2, FLEXCOMM2, 2); | ||
| 873 | impl_instance!(USART3, FLEXCOMM3, 3); | ||
| 874 | impl_instance!(USART4, FLEXCOMM4, 4); | ||
| 875 | impl_instance!(USART5, FLEXCOMM5, 5); | ||
| 876 | impl_instance!(USART6, FLEXCOMM6, 6); | ||
| 877 | impl_instance!(USART7, FLEXCOMM7, 7); | ||
| 878 | |||
| 879 | pub(crate) trait SealedTxPin<T: Instance>: crate::gpio::Pin { | 881 | pub(crate) trait SealedTxPin<T: Instance>: crate::gpio::Pin { |
| 880 | fn pin_func(&self) -> PioFunc; | 882 | fn pin_func(&self) -> PioFunc; |
| 881 | } | 883 | } |
| @@ -892,75 +894,46 @@ pub trait TxPin<T: Instance>: SealedTxPin<T> + crate::gpio::Pin {} | |||
| 892 | #[allow(private_bounds)] | 894 | #[allow(private_bounds)] |
| 893 | pub trait RxPin<T: Instance>: SealedRxPin<T> + crate::gpio::Pin {} | 895 | pub trait RxPin<T: Instance>: SealedRxPin<T> + crate::gpio::Pin {} |
| 894 | 896 | ||
| 895 | macro_rules! impl_tx_pin { | 897 | macro_rules! impl_usart_txd_pin { |
| 896 | ($pin:ident, $instance:ident, $func: ident) => { | 898 | ($pin:ident, $instance:ident, $func: ident) => { |
| 897 | impl SealedTxPin<crate::peripherals::$instance> for crate::peripherals::$pin { | 899 | impl crate::usart::SealedTxPin<crate::peripherals::$instance> for crate::peripherals::$pin { |
| 898 | fn pin_func(&self) -> PioFunc { | 900 | fn pin_func(&self) -> crate::pac::iocon::vals::PioFunc { |
| 901 | use crate::pac::iocon::vals::PioFunc; | ||
| 899 | PioFunc::$func | 902 | PioFunc::$func |
| 900 | } | 903 | } |
| 901 | } | 904 | } |
| 902 | 905 | ||
| 903 | impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} | 906 | impl crate::usart::TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} |
| 904 | }; | 907 | }; |
| 905 | } | 908 | } |
| 906 | 909 | ||
| 907 | macro_rules! impl_rx_pin { | 910 | macro_rules! impl_usart_rxd_pin { |
| 908 | ($pin:ident, $instance:ident, $func: ident) => { | 911 | ($pin:ident, $instance:ident, $func: ident) => { |
| 909 | impl SealedRxPin<crate::peripherals::$instance> for crate::peripherals::$pin { | 912 | impl crate::usart::SealedRxPin<crate::peripherals::$instance> for crate::peripherals::$pin { |
| 910 | fn pin_func(&self) -> PioFunc { | 913 | fn pin_func(&self) -> crate::pac::iocon::vals::PioFunc { |
| 914 | use crate::pac::iocon::vals::PioFunc; | ||
| 911 | PioFunc::$func | 915 | PioFunc::$func |
| 912 | } | 916 | } |
| 913 | } | 917 | } |
| 914 | 918 | ||
| 915 | impl RxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} | 919 | impl crate::usart::RxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} |
| 916 | }; | 920 | }; |
| 917 | } | 921 | } |
| 918 | 922 | ||
| 919 | impl_tx_pin!(PIO1_6, USART0, ALT1); | 923 | /// Marker trait indicating a DMA channel may be used for USART transmit. |
| 920 | impl_tx_pin!(PIO1_11, USART1, ALT2); | ||
| 921 | impl_tx_pin!(PIO0_27, USART2, ALT1); | ||
| 922 | impl_tx_pin!(PIO0_2, USART3, ALT1); | ||
| 923 | impl_tx_pin!(PIO0_16, USART4, ALT1); | ||
| 924 | impl_tx_pin!(PIO0_9, USART5, ALT3); | ||
| 925 | impl_tx_pin!(PIO1_16, USART6, ALT2); | ||
| 926 | impl_tx_pin!(PIO0_19, USART7, ALT7); | ||
| 927 | |||
| 928 | impl_rx_pin!(PIO1_5, USART0, ALT1); | ||
| 929 | impl_rx_pin!(PIO1_10, USART1, ALT2); | ||
| 930 | impl_rx_pin!(PIO1_24, USART2, ALT1); | ||
| 931 | impl_rx_pin!(PIO0_3, USART3, ALT1); | ||
| 932 | impl_rx_pin!(PIO0_5, USART4, ALT2); | ||
| 933 | impl_rx_pin!(PIO0_8, USART5, ALT3); | ||
| 934 | impl_rx_pin!(PIO1_13, USART6, ALT2); | ||
| 935 | impl_rx_pin!(PIO0_20, USART7, ALT7); | ||
| 936 | |||
| 937 | /// Trait for TX DMA channels. | ||
| 938 | pub trait TxChannel<T: Instance>: crate::dma::Channel {} | 924 | pub trait TxChannel<T: Instance>: crate::dma::Channel {} |
| 939 | /// Trait for RX DMA channels. | 925 | |
| 926 | /// Marker trait indicating a DMA channel may be used for USART recieve. | ||
| 940 | pub trait RxChannel<T: Instance>: crate::dma::Channel {} | 927 | pub trait RxChannel<T: Instance>: crate::dma::Channel {} |
| 941 | 928 | ||
| 942 | macro_rules! impl_channel { | 929 | macro_rules! impl_usart_tx_channel { |
| 943 | ($dma:ident, $instance:ident, Tx) => { | 930 | ($instance: ident, $channel: ident) => { |
| 944 | impl TxChannel<crate::peripherals::$instance> for crate::peripherals::$dma {} | 931 | impl crate::usart::TxChannel<crate::peripherals::$instance> for crate::peripherals::$channel {} |
| 945 | }; | ||
| 946 | ($dma:ident, $instance:ident, Rx) => { | ||
| 947 | impl RxChannel<crate::peripherals::$instance> for crate::peripherals::$dma {} | ||
| 948 | }; | 932 | }; |
| 949 | } | 933 | } |
| 950 | 934 | ||
| 951 | impl_channel!(DMA_CH4, USART0, Rx); | 935 | macro_rules! impl_usart_rx_channel { |
| 952 | impl_channel!(DMA_CH5, USART0, Tx); | 936 | ($instance: ident, $channel: ident) => { |
| 953 | impl_channel!(DMA_CH6, USART1, Rx); | 937 | impl crate::usart::RxChannel<crate::peripherals::$instance> for crate::peripherals::$channel {} |
| 954 | impl_channel!(DMA_CH7, USART1, Tx); | 938 | }; |
| 955 | impl_channel!(DMA_CH10, USART2, Rx); | 939 | } |
| 956 | impl_channel!(DMA_CH11, USART2, Tx); | ||
| 957 | impl_channel!(DMA_CH8, USART3, Rx); | ||
| 958 | impl_channel!(DMA_CH9, USART3, Tx); | ||
| 959 | impl_channel!(DMA_CH12, USART4, Rx); | ||
| 960 | impl_channel!(DMA_CH13, USART4, Tx); | ||
| 961 | impl_channel!(DMA_CH14, USART5, Rx); | ||
| 962 | impl_channel!(DMA_CH15, USART5, Tx); | ||
| 963 | impl_channel!(DMA_CH16, USART6, Rx); | ||
| 964 | impl_channel!(DMA_CH17, USART6, Tx); | ||
| 965 | impl_channel!(DMA_CH18, USART7, Rx); | ||
| 966 | impl_channel!(DMA_CH19, USART7, Tx); | ||
diff --git a/embassy-stm32-wpan/CHANGELOG.md b/embassy-stm32-wpan/CHANGELOG.md index 7042ad14c..c567fe1de 100644 --- a/embassy-stm32-wpan/CHANGELOG.md +++ b/embassy-stm32-wpan/CHANGELOG.md | |||
| @@ -8,4 +8,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | - restructure to allow embassy net driver to work. | ||
| 11 | - First release with changelog. | 12 | - First release with changelog. |
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 0802b7328..05d76f4a6 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml | |||
| @@ -33,6 +33,7 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" } | |||
| 33 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" } | 33 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" } |
| 34 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } | 34 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } |
| 35 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } | 35 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } |
| 36 | smoltcp = { version = "0.12.0", optional=true, default-features = false } | ||
| 36 | 37 | ||
| 37 | defmt = { version = "1.0.1", optional = true } | 38 | defmt = { version = "1.0.1", optional = true } |
| 38 | log = { version = "0.4.17", optional = true } | 39 | log = { version = "0.4.17", optional = true } |
| @@ -40,6 +41,7 @@ log = { version = "0.4.17", optional = true } | |||
| 40 | cortex-m = "0.7.6" | 41 | cortex-m = "0.7.6" |
| 41 | heapless = "0.8" | 42 | heapless = "0.8" |
| 42 | aligned = "0.4.1" | 43 | aligned = "0.4.1" |
| 44 | critical-section = "1.1" | ||
| 43 | 45 | ||
| 44 | bit_field = "0.10.2" | 46 | bit_field = "0.10.2" |
| 45 | stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } | 47 | stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } |
| @@ -51,7 +53,7 @@ bitflags = { version = "2.3.3", optional = true } | |||
| 51 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "stm32wb-hci?/defmt"] | 53 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "stm32wb-hci?/defmt"] |
| 52 | 54 | ||
| 53 | ble = ["dep:stm32wb-hci"] | 55 | ble = ["dep:stm32wb-hci"] |
| 54 | mac = ["dep:bitflags", "dep:embassy-net-driver" ] | 56 | mac = ["dep:bitflags", "dep:embassy-net-driver", "dep:smoltcp", "smoltcp/medium-ieee802154"] |
| 55 | 57 | ||
| 56 | extended = [] | 58 | extended = [] |
| 57 | 59 | ||
diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs index 82b9d2772..a3a40f377 100644 --- a/embassy-stm32-wpan/src/mac/commands.rs +++ b/embassy-stm32-wpan/src/mac/commands.rs | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | use core::{mem, slice}; | 3 | use core::{mem, slice}; |
| 4 | 4 | ||
| 5 | use smoltcp::wire::ieee802154::Frame; | ||
| 6 | |||
| 5 | use super::opcodes::OpcodeM4ToM0; | 7 | use super::opcodes::OpcodeM4ToM0; |
| 6 | use super::typedefs::{ | 8 | use super::typedefs::{ |
| 7 | AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus, | 9 | AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus, |
| @@ -379,6 +381,30 @@ impl DataRequest { | |||
| 379 | } | 381 | } |
| 380 | } | 382 | } |
| 381 | 383 | ||
| 384 | impl<'a, T: AsRef<[u8]>> TryFrom<Frame<&'a T>> for DataRequest { | ||
| 385 | type Error = (); | ||
| 386 | |||
| 387 | fn try_from(frame: Frame<&'a T>) -> Result<Self, Self::Error> { | ||
| 388 | // TODO: map the rest of these | ||
| 389 | |||
| 390 | let mut request = DataRequest { | ||
| 391 | src_addr_mode: frame.src_addressing_mode().try_into()?, | ||
| 392 | dst_addr_mode: frame.dst_addressing_mode().try_into()?, | ||
| 393 | dst_pan_id: frame.dst_pan_id().ok_or(())?.into(), | ||
| 394 | dst_address: frame.dst_addr().ok_or(())?.into(), | ||
| 395 | msdu_handle: frame.sequence_number().ok_or(())?, | ||
| 396 | ack_tx: 0x00, | ||
| 397 | gts_tx: false, | ||
| 398 | security_level: SecurityLevel::Unsecure, | ||
| 399 | ..Default::default() | ||
| 400 | }; | ||
| 401 | |||
| 402 | request.set_buffer(frame.payload().ok_or(())?); | ||
| 403 | |||
| 404 | Ok(request) | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 382 | impl Default for DataRequest { | 408 | impl Default for DataRequest { |
| 383 | fn default() -> Self { | 409 | fn default() -> Self { |
| 384 | Self { | 410 | Self { |
diff --git a/embassy-stm32-wpan/src/mac/control.rs b/embassy-stm32-wpan/src/mac/control.rs index e8d2f9f7b..d2a7b65ee 100644 --- a/embassy-stm32-wpan/src/mac/control.rs +++ b/embassy-stm32-wpan/src/mac/control.rs | |||
| @@ -1,65 +1,186 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 1 | use core::future::Future; | 2 | use core::future::Future; |
| 3 | use core::sync::atomic::{Ordering, compiler_fence}; | ||
| 2 | use core::task; | 4 | use core::task; |
| 3 | use core::task::Poll; | 5 | use core::task::Poll; |
| 4 | 6 | ||
| 7 | use embassy_net_driver::LinkState; | ||
| 8 | use embassy_sync::blocking_mutex; | ||
| 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 9 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 6 | use embassy_sync::mutex::MutexGuard; | 10 | use embassy_sync::mutex::Mutex; |
| 7 | use embassy_sync::signal::Signal; | 11 | use embassy_sync::signal::Signal; |
| 8 | use futures_util::FutureExt; | 12 | use futures_util::FutureExt; |
| 9 | 13 | ||
| 10 | use super::commands::MacCommand; | 14 | use crate::mac::commands::*; |
| 11 | use super::event::MacEvent; | 15 | use crate::mac::driver::NetworkState; |
| 12 | use super::typedefs::MacError; | 16 | use crate::mac::event::MacEvent; |
| 13 | use crate::mac::runner::Runner; | 17 | use crate::mac::runner::ZeroCopyPubSub; |
| 18 | use crate::mac::typedefs::*; | ||
| 19 | use crate::sub::mac::MacTx; | ||
| 14 | 20 | ||
| 15 | pub struct Control<'a> { | 21 | pub struct Control<'a> { |
| 16 | runner: &'a Runner<'a>, | 22 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, |
| 23 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx>, | ||
| 24 | #[allow(unused)] | ||
| 25 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 17 | } | 26 | } |
| 18 | 27 | ||
| 19 | impl<'a> Control<'a> { | 28 | impl<'a> Control<'a> { |
| 20 | pub(crate) fn new(runner: &'a Runner<'a>) -> Self { | 29 | pub(crate) fn new( |
| 21 | Self { runner: runner } | 30 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, |
| 31 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx>, | ||
| 32 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 33 | ) -> Self { | ||
| 34 | Self { | ||
| 35 | rx_event_channel, | ||
| 36 | mac_tx, | ||
| 37 | network_state, | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | pub async fn init_link(&mut self, pan_id: [u8; 2]) { | ||
| 42 | debug!("resetting"); | ||
| 43 | |||
| 44 | debug!( | ||
| 45 | "{:#x}", | ||
| 46 | self.send_command_and_get_response(&ResetRequest { | ||
| 47 | set_default_pib: true, | ||
| 48 | ..Default::default() | ||
| 49 | }) | ||
| 50 | .await | ||
| 51 | .unwrap() | ||
| 52 | .await | ||
| 53 | ); | ||
| 54 | |||
| 55 | let (short_address, mac_address) = critical_section::with(|cs| { | ||
| 56 | let mut network_state = self.network_state.borrow(cs).borrow_mut(); | ||
| 57 | |||
| 58 | network_state.pan_id = pan_id; | ||
| 59 | |||
| 60 | (network_state.short_addr, network_state.mac_addr) | ||
| 61 | }); | ||
| 62 | |||
| 63 | debug!("setting extended address"); | ||
| 64 | debug!( | ||
| 65 | "{:#x}", | ||
| 66 | self.send_command_and_get_response(&SetRequest { | ||
| 67 | pib_attribute_ptr: &u64::from_be_bytes(mac_address) as *const _ as *const u8, | ||
| 68 | pib_attribute: PibId::ExtendedAddress, | ||
| 69 | }) | ||
| 70 | .await | ||
| 71 | .unwrap() | ||
| 72 | .await | ||
| 73 | ); | ||
| 74 | |||
| 75 | debug!("setting short address"); | ||
| 76 | debug!( | ||
| 77 | "{:#x}", | ||
| 78 | self.send_command_and_get_response(&SetRequest { | ||
| 79 | pib_attribute_ptr: &u16::from_be_bytes(short_address) as *const _ as *const u8, | ||
| 80 | pib_attribute: PibId::ShortAddress, | ||
| 81 | }) | ||
| 82 | .await | ||
| 83 | .unwrap() | ||
| 84 | .await | ||
| 85 | ); | ||
| 86 | |||
| 87 | debug!("setting association permit"); | ||
| 88 | let association_permit: bool = true; | ||
| 89 | debug!( | ||
| 90 | "{:#x}", | ||
| 91 | self.send_command_and_get_response(&SetRequest { | ||
| 92 | pib_attribute_ptr: &association_permit as *const _ as *const u8, | ||
| 93 | pib_attribute: PibId::AssociationPermit, | ||
| 94 | }) | ||
| 95 | .await | ||
| 96 | .unwrap() | ||
| 97 | .await | ||
| 98 | ); | ||
| 99 | |||
| 100 | debug!("setting TX power"); | ||
| 101 | let transmit_power: i8 = 2; | ||
| 102 | debug!( | ||
| 103 | "{:#x}", | ||
| 104 | self.send_command_and_get_response(&SetRequest { | ||
| 105 | pib_attribute_ptr: &transmit_power as *const _ as *const u8, | ||
| 106 | pib_attribute: PibId::TransmitPower, | ||
| 107 | }) | ||
| 108 | .await | ||
| 109 | .unwrap() | ||
| 110 | .await | ||
| 111 | ); | ||
| 112 | |||
| 113 | debug!("starting FFD device"); | ||
| 114 | debug!( | ||
| 115 | "{:#x}", | ||
| 116 | self.send_command_and_get_response(&StartRequest { | ||
| 117 | pan_id: PanId(pan_id), | ||
| 118 | channel_number: MacChannel::Channel16, | ||
| 119 | beacon_order: 0x0F, | ||
| 120 | superframe_order: 0x0F, | ||
| 121 | pan_coordinator: true, | ||
| 122 | battery_life_extension: false, | ||
| 123 | ..Default::default() | ||
| 124 | }) | ||
| 125 | .await | ||
| 126 | .unwrap() | ||
| 127 | .await | ||
| 128 | ); | ||
| 129 | |||
| 130 | debug!("setting RX on when idle"); | ||
| 131 | let rx_on_while_idle: bool = true; | ||
| 132 | debug!( | ||
| 133 | "{:#x}", | ||
| 134 | self.send_command_and_get_response(&SetRequest { | ||
| 135 | pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8, | ||
| 136 | pib_attribute: PibId::RxOnWhenIdle, | ||
| 137 | }) | ||
| 138 | .await | ||
| 139 | .unwrap() | ||
| 140 | .await | ||
| 141 | ); | ||
| 142 | |||
| 143 | critical_section::with(|cs| { | ||
| 144 | let mut network_state = self.network_state.borrow(cs).borrow_mut(); | ||
| 145 | |||
| 146 | network_state.link_state = LinkState::Up; | ||
| 147 | network_state.link_waker.wake(); | ||
| 148 | }); | ||
| 22 | } | 149 | } |
| 23 | 150 | ||
| 24 | pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError> | 151 | pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError> |
| 25 | where | 152 | where |
| 26 | T: MacCommand, | 153 | T: MacCommand, |
| 27 | { | 154 | { |
| 28 | let _wm = self.runner.write_mutex.lock().await; | 155 | self.mac_tx.lock().await.send_command(cmd).await |
| 29 | |||
| 30 | self.runner.mac_subsystem.send_command(cmd).await | ||
| 31 | } | 156 | } |
| 32 | 157 | ||
| 33 | pub async fn send_command_and_get_response<T>(&self, cmd: &T) -> Result<EventToken<'a>, MacError> | 158 | pub async fn send_command_and_get_response<T>(&self, cmd: &T) -> Result<EventToken<'a>, MacError> |
| 34 | where | 159 | where |
| 35 | T: MacCommand, | 160 | T: MacCommand, |
| 36 | { | 161 | { |
| 37 | let rm = self.runner.read_mutex.lock().await; | 162 | let token = EventToken::new(self.rx_event_channel); |
| 38 | let _wm = self.runner.write_mutex.lock().await; | ||
| 39 | let token = EventToken::new(self.runner, rm); | ||
| 40 | 163 | ||
| 41 | self.runner.mac_subsystem.send_command(cmd).await?; | 164 | compiler_fence(Ordering::Release); |
| 165 | |||
| 166 | self.mac_tx.lock().await.send_command(cmd).await?; | ||
| 42 | 167 | ||
| 43 | Ok(token) | 168 | Ok(token) |
| 44 | } | 169 | } |
| 45 | } | 170 | } |
| 46 | 171 | ||
| 47 | pub struct EventToken<'a> { | 172 | pub struct EventToken<'a> { |
| 48 | runner: &'a Runner<'a>, | 173 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, |
| 49 | _mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>, | ||
| 50 | } | 174 | } |
| 51 | 175 | ||
| 52 | impl<'a> EventToken<'a> { | 176 | impl<'a> EventToken<'a> { |
| 53 | pub(crate) fn new(runner: &'a Runner<'a>, mutex_guard: MutexGuard<'a, CriticalSectionRawMutex, ()>) -> Self { | 177 | pub(crate) fn new(rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>) -> Self { |
| 54 | // Enable event receiving | 178 | // Enable event receiving |
| 55 | runner.rx_event_channel.lock(|s| { | 179 | rx_event_channel.lock(|s| { |
| 56 | *s.borrow_mut() = Some(Signal::new()); | 180 | *s.borrow_mut() = Some(Signal::new()); |
| 57 | }); | 181 | }); |
| 58 | 182 | ||
| 59 | Self { | 183 | Self { rx_event_channel } |
| 60 | runner: runner, | ||
| 61 | _mutex_guard: mutex_guard, | ||
| 62 | } | ||
| 63 | } | 184 | } |
| 64 | } | 185 | } |
| 65 | 186 | ||
| @@ -67,20 +188,8 @@ impl<'a> Future for EventToken<'a> { | |||
| 67 | type Output = MacEvent<'a>; | 188 | type Output = MacEvent<'a>; |
| 68 | 189 | ||
| 69 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | 190 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { |
| 70 | self.get_mut().runner.rx_event_channel.lock(|s| { | 191 | self.rx_event_channel |
| 71 | let signal = s.borrow_mut(); | 192 | .lock(|s| s.borrow_mut().as_mut().unwrap().wait().poll_unpin(cx)) |
| 72 | let signal = match &*signal { | ||
| 73 | Some(s) => s, | ||
| 74 | _ => unreachable!(), | ||
| 75 | }; | ||
| 76 | |||
| 77 | let result = match signal.wait().poll_unpin(cx) { | ||
| 78 | Poll::Ready(mac_event) => Poll::Ready(mac_event), | ||
| 79 | Poll::Pending => Poll::Pending, | ||
| 80 | }; | ||
| 81 | |||
| 82 | result | ||
| 83 | }) | ||
| 84 | } | 193 | } |
| 85 | } | 194 | } |
| 86 | 195 | ||
| @@ -88,7 +197,7 @@ impl<'a> Drop for EventToken<'a> { | |||
| 88 | fn drop(&mut self) { | 197 | fn drop(&mut self) { |
| 89 | // Disable event receiving | 198 | // Disable event receiving |
| 90 | // This will also drop the contained event, if it exists, and will free up receiving the next event | 199 | // This will also drop the contained event, if it exists, and will free up receiving the next event |
| 91 | self.runner.rx_event_channel.lock(|s| { | 200 | self.rx_event_channel.lock(|s| { |
| 92 | *s.borrow_mut() = None; | 201 | *s.borrow_mut() = None; |
| 93 | }); | 202 | }); |
| 94 | } | 203 | } |
diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 480ac3790..c43d595b7 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs | |||
| @@ -1,22 +1,108 @@ | |||
| 1 | #![deny(unused_must_use)] | 1 | #![deny(unused_must_use)] |
| 2 | 2 | ||
| 3 | use core::cell::RefCell; | ||
| 3 | use core::task::Context; | 4 | use core::task::Context; |
| 4 | 5 | ||
| 5 | use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; | 6 | use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; |
| 7 | use embassy_sync::blocking_mutex; | ||
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 7 | use embassy_sync::channel::Channel; | 9 | use embassy_sync::channel::Channel; |
| 10 | use embassy_sync::mutex::Mutex; | ||
| 11 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 8 | 12 | ||
| 9 | use crate::mac::MTU; | ||
| 10 | use crate::mac::event::MacEvent; | 13 | use crate::mac::event::MacEvent; |
| 11 | use crate::mac::runner::Runner; | 14 | use crate::mac::indications::{write_frame_from_beacon_indication, write_frame_from_data_indication}; |
| 15 | use crate::mac::runner::{BUF_SIZE, ZeroCopyPubSub}; | ||
| 16 | use crate::mac::{Control, MTU, Runner}; | ||
| 17 | use crate::sub::mac::{Mac, MacRx, MacTx}; | ||
| 18 | |||
| 19 | pub struct NetworkState { | ||
| 20 | pub mac_addr: [u8; 8], | ||
| 21 | pub short_addr: [u8; 2], | ||
| 22 | pub pan_id: [u8; 2], | ||
| 23 | pub link_state: LinkState, | ||
| 24 | pub link_waker: AtomicWaker, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl NetworkState { | ||
| 28 | pub const fn new() -> Self { | ||
| 29 | Self { | ||
| 30 | mac_addr: [0u8; 8], | ||
| 31 | short_addr: [0u8; 2], | ||
| 32 | pan_id: [0u8; 2], | ||
| 33 | link_state: LinkState::Down, | ||
| 34 | link_waker: AtomicWaker::new(), | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | pub struct DriverState<'d> { | ||
| 40 | pub mac_tx: Mutex<CriticalSectionRawMutex, MacTx>, | ||
| 41 | pub mac_rx: MacRx, | ||
| 42 | pub rx_event_channel: ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'d>>, | ||
| 43 | pub rx_data_channel: Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>, | ||
| 44 | pub tx_data_channel: Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), BUF_SIZE>, | ||
| 45 | pub tx_buf_channel: Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], BUF_SIZE>, | ||
| 46 | pub tx_buf_queue: [[u8; MTU]; BUF_SIZE], | ||
| 47 | pub network_state: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<'d> DriverState<'d> { | ||
| 51 | pub const fn new(mac: Mac) -> Self { | ||
| 52 | let (mac_rx, mac_tx) = mac.split(); | ||
| 53 | let mac_tx = Mutex::new(mac_tx); | ||
| 54 | |||
| 55 | Self { | ||
| 56 | mac_tx, | ||
| 57 | mac_rx, | ||
| 58 | rx_event_channel: ZeroCopyPubSub::new(RefCell::new(None)), | ||
| 59 | rx_data_channel: Channel::new(), | ||
| 60 | tx_data_channel: Channel::new(), | ||
| 61 | tx_buf_channel: Channel::new(), | ||
| 62 | tx_buf_queue: [[0u8; MTU]; BUF_SIZE], | ||
| 63 | network_state: blocking_mutex::Mutex::new(RefCell::new(NetworkState::new())), | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 12 | 67 | ||
| 13 | pub struct Driver<'d> { | 68 | pub struct Driver<'d> { |
| 14 | runner: &'d Runner<'d>, | 69 | tx_data_channel: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), BUF_SIZE>, |
| 70 | tx_buf_channel: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], BUF_SIZE>, | ||
| 71 | rx_data_channel: &'d Channel<CriticalSectionRawMutex, MacEvent<'d>, 1>, | ||
| 72 | network_state: &'d blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 15 | } | 73 | } |
| 16 | 74 | ||
| 17 | impl<'d> Driver<'d> { | 75 | impl<'d> Driver<'d> { |
| 18 | pub(crate) fn new(runner: &'d Runner<'d>) -> Self { | 76 | pub fn new( |
| 19 | Self { runner: runner } | 77 | driver_state: &'d mut DriverState<'d>, |
| 78 | short_address: [u8; 2], | ||
| 79 | mac_address: [u8; 8], | ||
| 80 | ) -> (Self, Runner<'d>, Control<'d>) { | ||
| 81 | ( | ||
| 82 | Self { | ||
| 83 | tx_data_channel: &driver_state.tx_data_channel, | ||
| 84 | tx_buf_channel: &driver_state.tx_buf_channel, | ||
| 85 | rx_data_channel: &driver_state.rx_data_channel, | ||
| 86 | network_state: &driver_state.network_state, | ||
| 87 | }, | ||
| 88 | Runner::new( | ||
| 89 | &driver_state.rx_event_channel, | ||
| 90 | &driver_state.rx_data_channel, | ||
| 91 | &mut driver_state.mac_rx, | ||
| 92 | &driver_state.tx_data_channel, | ||
| 93 | &driver_state.tx_buf_channel, | ||
| 94 | &driver_state.mac_tx, | ||
| 95 | &mut driver_state.tx_buf_queue, | ||
| 96 | &driver_state.network_state, | ||
| 97 | short_address, | ||
| 98 | mac_address, | ||
| 99 | ), | ||
| 100 | Control::new( | ||
| 101 | &driver_state.rx_event_channel, | ||
| 102 | &driver_state.mac_tx, | ||
| 103 | &driver_state.network_state, | ||
| 104 | ), | ||
| 105 | ) | ||
| 20 | } | 106 | } |
| 21 | } | 107 | } |
| 22 | 108 | ||
| @@ -33,16 +119,16 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { | |||
| 33 | Self: 'a; | 119 | Self: 'a; |
| 34 | 120 | ||
| 35 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { | 121 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { |
| 36 | if self.runner.rx_channel.poll_ready_to_receive(cx).is_ready() | 122 | if self.rx_data_channel.poll_ready_to_receive(cx).is_ready() |
| 37 | && self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready() | 123 | && self.tx_buf_channel.poll_ready_to_receive(cx).is_ready() |
| 38 | { | 124 | { |
| 39 | Some(( | 125 | Some(( |
| 40 | RxToken { | 126 | RxToken { |
| 41 | rx: &self.runner.rx_channel, | 127 | rx: self.rx_data_channel, |
| 42 | }, | 128 | }, |
| 43 | TxToken { | 129 | TxToken { |
| 44 | tx: &self.runner.tx_channel, | 130 | tx: self.tx_data_channel, |
| 45 | tx_buf: &self.runner.tx_buf_channel, | 131 | tx_buf: self.tx_buf_channel, |
| 46 | }, | 132 | }, |
| 47 | )) | 133 | )) |
| 48 | } else { | 134 | } else { |
| @@ -51,10 +137,10 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { | |||
| 51 | } | 137 | } |
| 52 | 138 | ||
| 53 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { | 139 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { |
| 54 | if self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready() { | 140 | if self.tx_buf_channel.poll_ready_to_receive(cx).is_ready() { |
| 55 | Some(TxToken { | 141 | Some(TxToken { |
| 56 | tx: &self.runner.tx_channel, | 142 | tx: self.tx_data_channel, |
| 57 | tx_buf: &self.runner.tx_buf_channel, | 143 | tx_buf: self.tx_buf_channel, |
| 58 | }) | 144 | }) |
| 59 | } else { | 145 | } else { |
| 60 | None | 146 | None |
| @@ -68,13 +154,20 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { | |||
| 68 | caps | 154 | caps |
| 69 | } | 155 | } |
| 70 | 156 | ||
| 71 | fn link_state(&mut self, _cx: &mut Context) -> LinkState { | 157 | fn link_state(&mut self, cx: &mut Context) -> LinkState { |
| 72 | LinkState::Down | 158 | critical_section::with(|cs| { |
| 159 | let network_state = self.network_state.borrow(cs).borrow_mut(); | ||
| 160 | |||
| 161 | // Unconditionally register the waker to avoid a race | ||
| 162 | network_state.link_waker.register(cx.waker()); | ||
| 163 | network_state.link_state | ||
| 164 | }) | ||
| 73 | } | 165 | } |
| 74 | 166 | ||
| 75 | fn hardware_address(&self) -> HardwareAddress { | 167 | fn hardware_address(&self) -> HardwareAddress { |
| 76 | // self.mac_addr | 168 | HardwareAddress::Ieee802154(critical_section::with(|cs| { |
| 77 | HardwareAddress::Ieee802154([0; 8]) | 169 | self.network_state.borrow(cs).borrow().mac_addr |
| 170 | })) | ||
| 78 | } | 171 | } |
| 79 | } | 172 | } |
| 80 | 173 | ||
| @@ -87,20 +180,20 @@ impl<'d> embassy_net_driver::RxToken for RxToken<'d> { | |||
| 87 | where | 180 | where |
| 88 | F: FnOnce(&mut [u8]) -> R, | 181 | F: FnOnce(&mut [u8]) -> R, |
| 89 | { | 182 | { |
| 90 | // Only valid data events should be put into the queue | 183 | let mut buffer = [0u8; MTU]; |
| 91 | 184 | match self.rx.try_receive().unwrap() { | |
| 92 | let data_event = match self.rx.try_receive().unwrap() { | 185 | MacEvent::McpsDataInd(data_event) => write_frame_from_data_indication(data_event, &mut buffer), |
| 93 | MacEvent::McpsDataInd(data_event) => data_event, | 186 | MacEvent::MlmeBeaconNotifyInd(data_event) => write_frame_from_beacon_indication(data_event, &mut buffer), |
| 94 | _ => unreachable!(), | 187 | _ => {} |
| 95 | }; | 188 | }; |
| 96 | 189 | ||
| 97 | f(&mut data_event.payload()) | 190 | f(&mut buffer[..]) |
| 98 | } | 191 | } |
| 99 | } | 192 | } |
| 100 | 193 | ||
| 101 | pub struct TxToken<'d> { | 194 | pub struct TxToken<'d> { |
| 102 | tx: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), 5>, | 195 | tx: &'d Channel<CriticalSectionRawMutex, (&'d mut [u8; MTU], usize), BUF_SIZE>, |
| 103 | tx_buf: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], 5>, | 196 | tx_buf: &'d Channel<CriticalSectionRawMutex, &'d mut [u8; MTU], BUF_SIZE>, |
| 104 | } | 197 | } |
| 105 | 198 | ||
| 106 | impl<'d> embassy_net_driver::TxToken for TxToken<'d> { | 199 | impl<'d> embassy_net_driver::TxToken for TxToken<'d> { |
diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/mac/indications.rs index c0b86d745..5673514c9 100644 --- a/embassy-stm32-wpan/src/mac/indications.rs +++ b/embassy-stm32-wpan/src/mac/indications.rs | |||
| @@ -1,11 +1,15 @@ | |||
| 1 | use core::slice; | 1 | use core::slice; |
| 2 | 2 | ||
| 3 | use smoltcp::wire::Ieee802154FrameType; | ||
| 4 | use smoltcp::wire::ieee802154::Frame; | ||
| 5 | |||
| 3 | use super::consts::MAX_PENDING_ADDRESS; | 6 | use super::consts::MAX_PENDING_ADDRESS; |
| 4 | use super::event::ParseableMacEvent; | 7 | use super::event::ParseableMacEvent; |
| 5 | use super::typedefs::{ | 8 | use super::typedefs::{ |
| 6 | AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor, | 9 | AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor, |
| 7 | PanId, SecurityLevel, | 10 | PanId, SecurityLevel, |
| 8 | }; | 11 | }; |
| 12 | use crate::mac::typedefs::MacAddressAndMode; | ||
| 9 | 13 | ||
| 10 | /// MLME ASSOCIATE Indication which will be used by the MAC | 14 | /// MLME ASSOCIATE Indication which will be used by the MAC |
| 11 | /// to indicate the reception of an association request command | 15 | /// to indicate the reception of an association request command |
| @@ -74,6 +78,22 @@ pub struct BeaconNotifyIndication { | |||
| 74 | 78 | ||
| 75 | impl ParseableMacEvent for BeaconNotifyIndication {} | 79 | impl ParseableMacEvent for BeaconNotifyIndication {} |
| 76 | 80 | ||
| 81 | impl BeaconNotifyIndication { | ||
| 82 | pub fn payload<'a>(&'a self) -> &'a mut [u8] { | ||
| 83 | unsafe { slice::from_raw_parts_mut(self.sdu_ptr as *mut _, self.sdu_length as usize) } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | pub fn write_frame_from_beacon_indication<'a, T: AsRef<[u8]> + AsMut<[u8]>>( | ||
| 88 | data: &'a BeaconNotifyIndication, | ||
| 89 | buffer: &'a mut T, | ||
| 90 | ) { | ||
| 91 | let mut frame = Frame::new_unchecked(buffer); | ||
| 92 | |||
| 93 | frame.set_frame_type(Ieee802154FrameType::Beacon); | ||
| 94 | frame.set_sequence_number(data.bsn); | ||
| 95 | } | ||
| 96 | |||
| 77 | /// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status | 97 | /// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status |
| 78 | #[repr(C)] | 98 | #[repr(C)] |
| 79 | #[derive(Debug)] | 99 | #[derive(Debug)] |
| @@ -250,6 +270,21 @@ impl DataIndication { | |||
| 250 | } | 270 | } |
| 251 | } | 271 | } |
| 252 | 272 | ||
| 273 | pub fn write_frame_from_data_indication<'a, T: AsRef<[u8]> + AsMut<[u8]>>(data: &'a DataIndication, buffer: &'a mut T) { | ||
| 274 | let mut frame = Frame::new_unchecked(buffer); | ||
| 275 | |||
| 276 | frame.set_frame_type(Ieee802154FrameType::Data); | ||
| 277 | frame.set_src_addr(MacAddressAndMode(data.src_address, data.src_addr_mode).into()); | ||
| 278 | frame.set_dst_addr(MacAddressAndMode(data.dst_address, data.dst_addr_mode).into()); | ||
| 279 | frame.set_dst_pan_id(data.dst_pan_id.into()); | ||
| 280 | frame.set_src_pan_id(data.src_pan_id.into()); | ||
| 281 | frame.set_sequence_number(data.dsn); | ||
| 282 | frame.set_security_enabled(data.security_level == SecurityLevel::Secured); | ||
| 283 | |||
| 284 | // No way around the copy with the current API | ||
| 285 | frame.payload_mut().unwrap().copy_from_slice(data.payload()); | ||
| 286 | } | ||
| 287 | |||
| 253 | /// MLME POLL Indication which will be used for indicating the Data Request | 288 | /// MLME POLL Indication which will be used for indicating the Data Request |
| 254 | /// reception to upper layer as defined in Zigbee r22 - D.8.2 | 289 | /// reception to upper layer as defined in Zigbee r22 - D.8.2 |
| 255 | #[repr(C)] | 290 | #[repr(C)] |
diff --git a/embassy-stm32-wpan/src/mac/mod.rs b/embassy-stm32-wpan/src/mac/mod.rs index c847a5cca..ac50a6b29 100644 --- a/embassy-stm32-wpan/src/mac/mod.rs +++ b/embassy-stm32-wpan/src/mac/mod.rs | |||
| @@ -11,11 +11,7 @@ pub mod runner; | |||
| 11 | pub mod typedefs; | 11 | pub mod typedefs; |
| 12 | 12 | ||
| 13 | pub use crate::mac::control::Control; | 13 | pub use crate::mac::control::Control; |
| 14 | use crate::mac::driver::Driver; | 14 | pub use crate::mac::driver::{Driver, DriverState}; |
| 15 | pub use crate::mac::runner::Runner; | 15 | pub use crate::mac::runner::Runner; |
| 16 | 16 | ||
| 17 | const MTU: usize = 127; | 17 | const MTU: usize = 127; |
| 18 | |||
| 19 | pub async fn new<'a>(runner: &'a Runner<'a>) -> (Control<'a>, Driver<'a>) { | ||
| 20 | (Control::new(runner), Driver::new(runner)) | ||
| 21 | } | ||
diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 2409f994d..acca70019 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs | |||
| @@ -6,96 +6,138 @@ use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; | |||
| 6 | use embassy_sync::channel::Channel; | 6 | use embassy_sync::channel::Channel; |
| 7 | use embassy_sync::mutex::Mutex; | 7 | use embassy_sync::mutex::Mutex; |
| 8 | use embassy_sync::signal::Signal; | 8 | use embassy_sync::signal::Signal; |
| 9 | use smoltcp::wire::Ieee802154FrameType; | ||
| 10 | use smoltcp::wire::ieee802154::Frame; | ||
| 9 | 11 | ||
| 10 | use crate::mac::MTU; | 12 | use crate::mac::MTU; |
| 11 | use crate::mac::commands::DataRequest; | 13 | use crate::mac::commands::*; |
| 14 | use crate::mac::driver::NetworkState; | ||
| 12 | use crate::mac::event::MacEvent; | 15 | use crate::mac::event::MacEvent; |
| 13 | use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel}; | 16 | use crate::sub::mac::{MacRx, MacTx}; |
| 14 | use crate::sub::mac::Mac; | ||
| 15 | 17 | ||
| 16 | type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>; | 18 | pub type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>; |
| 19 | |||
| 20 | pub const BUF_SIZE: usize = 3; | ||
| 17 | 21 | ||
| 18 | pub struct Runner<'a> { | 22 | pub struct Runner<'a> { |
| 19 | pub(crate) mac_subsystem: Mac, | ||
| 20 | // rx event backpressure is already provided through the MacEvent drop mechanism | 23 | // rx event backpressure is already provided through the MacEvent drop mechanism |
| 21 | // therefore, we don't need to worry about overwriting events | 24 | // therefore, we don't need to worry about overwriting events |
| 22 | pub(crate) rx_event_channel: ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, | 25 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, |
| 23 | pub(crate) read_mutex: Mutex<CriticalSectionRawMutex, ()>, | 26 | rx_data_channel: &'a Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>, |
| 24 | pub(crate) write_mutex: Mutex<CriticalSectionRawMutex, ()>, | 27 | mac_rx: &'a mut MacRx, |
| 25 | pub(crate) rx_channel: Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>, | 28 | |
| 26 | pub(crate) tx_channel: Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), 5>, | 29 | tx_data_channel: &'a Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), BUF_SIZE>, |
| 27 | pub(crate) tx_buf_channel: Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], 5>, | 30 | tx_buf_channel: &'a Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], BUF_SIZE>, |
| 31 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx>, | ||
| 32 | |||
| 33 | #[allow(unused)] | ||
| 34 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, | ||
| 28 | } | 35 | } |
| 29 | 36 | ||
| 30 | impl<'a> Runner<'a> { | 37 | impl<'a> Runner<'a> { |
| 31 | pub fn new(mac: Mac, tx_buf_queue: [&'a mut [u8; MTU]; 5]) -> Self { | 38 | pub(crate) fn new( |
| 32 | let this = Self { | 39 | rx_event_channel: &'a ZeroCopyPubSub<CriticalSectionRawMutex, MacEvent<'a>>, |
| 33 | mac_subsystem: mac, | 40 | rx_data_channel: &'a Channel<CriticalSectionRawMutex, MacEvent<'a>, 1>, |
| 34 | rx_event_channel: blocking_mutex::Mutex::new(RefCell::new(None)), | 41 | mac_rx: &'a mut MacRx, |
| 35 | read_mutex: Mutex::new(()), | 42 | tx_data_channel: &'a Channel<CriticalSectionRawMutex, (&'a mut [u8; MTU], usize), BUF_SIZE>, |
| 36 | write_mutex: Mutex::new(()), | 43 | tx_buf_channel: &'a Channel<CriticalSectionRawMutex, &'a mut [u8; MTU], BUF_SIZE>, |
| 37 | rx_channel: Channel::new(), | 44 | mac_tx: &'a Mutex<CriticalSectionRawMutex, MacTx>, |
| 38 | tx_channel: Channel::new(), | 45 | tx_buf_queue: &'a mut [[u8; MTU]; BUF_SIZE], |
| 39 | tx_buf_channel: Channel::new(), | 46 | network_state: &'a blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<NetworkState>>, |
| 40 | }; | 47 | short_address: [u8; 2], |
| 41 | 48 | mac_address: [u8; 8], | |
| 49 | ) -> Self { | ||
| 42 | for buf in tx_buf_queue { | 50 | for buf in tx_buf_queue { |
| 43 | this.tx_buf_channel.try_send(buf).unwrap(); | 51 | tx_buf_channel.try_send(buf).unwrap(); |
| 52 | } | ||
| 53 | |||
| 54 | critical_section::with(|cs| { | ||
| 55 | let mut network_state = network_state.borrow(cs).borrow_mut(); | ||
| 56 | |||
| 57 | network_state.mac_addr = mac_address; | ||
| 58 | network_state.short_addr = short_address; | ||
| 59 | }); | ||
| 60 | |||
| 61 | Self { | ||
| 62 | rx_event_channel, | ||
| 63 | rx_data_channel, | ||
| 64 | mac_rx, | ||
| 65 | tx_data_channel, | ||
| 66 | tx_buf_channel, | ||
| 67 | mac_tx, | ||
| 68 | network_state, | ||
| 44 | } | 69 | } |
| 70 | } | ||
| 71 | |||
| 72 | async fn send_request<T: MacCommand, U: TryInto<T>>(&self, frame: U) -> Result<(), ()> | ||
| 73 | where | ||
| 74 | (): From<<U as TryInto<T>>::Error>, | ||
| 75 | { | ||
| 76 | let request: T = frame.try_into()?; | ||
| 77 | self.mac_tx.lock().await.send_command(&request).await.map_err(|_| ())?; | ||
| 45 | 78 | ||
| 46 | this | 79 | Ok(()) |
| 47 | } | 80 | } |
| 48 | 81 | ||
| 49 | pub async fn run(&'a self) -> ! { | 82 | pub async fn run(&'a self) -> ! { |
| 50 | join::join( | 83 | join::join( |
| 51 | async { | 84 | async { |
| 52 | loop { | 85 | loop { |
| 53 | if let Ok(mac_event) = self.mac_subsystem.read().await { | 86 | if let Ok(mac_event) = self.mac_rx.read().await { |
| 54 | match mac_event { | 87 | match mac_event { |
| 88 | MacEvent::MlmeAssociateCnf(_) | ||
| 89 | | MacEvent::MlmeDisassociateCnf(_) | ||
| 90 | | MacEvent::MlmeGetCnf(_) | ||
| 91 | | MacEvent::MlmeGtsCnf(_) | ||
| 92 | | MacEvent::MlmeResetCnf(_) | ||
| 93 | | MacEvent::MlmeRxEnableCnf(_) | ||
| 94 | | MacEvent::MlmeScanCnf(_) | ||
| 95 | | MacEvent::MlmeSetCnf(_) | ||
| 96 | | MacEvent::MlmeStartCnf(_) | ||
| 97 | | MacEvent::MlmePollCnf(_) | ||
| 98 | | MacEvent::MlmeDpsCnf(_) | ||
| 99 | | MacEvent::MlmeSoundingCnf(_) | ||
| 100 | | MacEvent::MlmeCalibrateCnf(_) | ||
| 101 | | MacEvent::McpsDataCnf(_) | ||
| 102 | | MacEvent::McpsPurgeCnf(_) => { | ||
| 103 | self.rx_event_channel.lock(|s| { | ||
| 104 | s.borrow().as_ref().map(|signal| signal.signal(mac_event)); | ||
| 105 | }); | ||
| 106 | } | ||
| 55 | MacEvent::McpsDataInd(_) => { | 107 | MacEvent::McpsDataInd(_) => { |
| 56 | self.rx_channel.send(mac_event).await; | 108 | // Pattern should match driver |
| 109 | self.rx_data_channel.send(mac_event).await; | ||
| 57 | } | 110 | } |
| 58 | _ => { | 111 | _ => { |
| 59 | self.rx_event_channel.lock(|s| { | 112 | debug!("unhandled mac event: {:#x}", mac_event); |
| 60 | match &*s.borrow() { | ||
| 61 | Some(signal) => { | ||
| 62 | signal.signal(mac_event); | ||
| 63 | } | ||
| 64 | None => {} | ||
| 65 | }; | ||
| 66 | }); | ||
| 67 | } | 113 | } |
| 68 | } | 114 | } |
| 69 | } | 115 | } |
| 70 | } | 116 | } |
| 71 | }, | 117 | }, |
| 72 | async { | 118 | async { |
| 73 | let mut msdu_handle = 0x02; | ||
| 74 | |||
| 75 | loop { | 119 | loop { |
| 76 | let (buf, len) = self.tx_channel.receive().await; | 120 | let (buf, _) = self.tx_data_channel.receive().await; |
| 77 | let _wm = self.write_mutex.lock().await; | 121 | |
| 78 | 122 | // Smoltcp has created this frame, so there's no need to reparse it. | |
| 79 | // The mutex should be dropped on the next loop iteration | 123 | let frame = Frame::new_unchecked(&buf); |
| 80 | self.mac_subsystem | ||
| 81 | .send_command( | ||
| 82 | DataRequest { | ||
| 83 | src_addr_mode: AddressMode::Short, | ||
| 84 | dst_addr_mode: AddressMode::Short, | ||
| 85 | dst_pan_id: PanId([0x1A, 0xAA]), | ||
| 86 | dst_address: MacAddress::BROADCAST, | ||
| 87 | msdu_handle: msdu_handle, | ||
| 88 | ack_tx: 0x00, | ||
| 89 | gts_tx: false, | ||
| 90 | security_level: SecurityLevel::Unsecure, | ||
| 91 | ..Default::default() | ||
| 92 | } | ||
| 93 | .set_buffer(&buf[..len]), | ||
| 94 | ) | ||
| 95 | .await | ||
| 96 | .unwrap(); | ||
| 97 | 124 | ||
| 98 | msdu_handle = msdu_handle.wrapping_add(1); | 125 | let result: Result<(), ()> = match frame.frame_type() { |
| 126 | Ieee802154FrameType::Beacon => Err(()), | ||
| 127 | Ieee802154FrameType::Data => self.send_request::<DataRequest, _>(frame).await, | ||
| 128 | Ieee802154FrameType::Acknowledgement => Err(()), | ||
| 129 | Ieee802154FrameType::MacCommand => Err(()), | ||
| 130 | Ieee802154FrameType::Multipurpose => Err(()), | ||
| 131 | Ieee802154FrameType::FragmentOrFrak => Err(()), | ||
| 132 | Ieee802154FrameType::Extended => Err(()), | ||
| 133 | _ => Err(()), | ||
| 134 | }; | ||
| 135 | |||
| 136 | if result.is_err() { | ||
| 137 | debug!("failed to parse mac frame"); | ||
| 138 | } else { | ||
| 139 | trace!("data frame sent!"); | ||
| 140 | } | ||
| 99 | 141 | ||
| 100 | // The tx channel should always be of equal capacity to the tx_buf channel | 142 | // The tx channel should always be of equal capacity to the tx_buf channel |
| 101 | self.tx_buf_channel.try_send(buf).unwrap(); | 143 | self.tx_buf_channel.try_send(buf).unwrap(); |
diff --git a/embassy-stm32-wpan/src/mac/typedefs.rs b/embassy-stm32-wpan/src/mac/typedefs.rs index 0552b8ea1..175d4a37d 100644 --- a/embassy-stm32-wpan/src/mac/typedefs.rs +++ b/embassy-stm32-wpan/src/mac/typedefs.rs | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | use core::fmt::Debug; | 1 | use core::fmt::Debug; |
| 2 | 2 | ||
| 3 | use smoltcp::wire::ieee802154::{Address, AddressingMode, Pan}; | ||
| 4 | |||
| 3 | use crate::numeric_enum; | 5 | use crate::numeric_enum; |
| 4 | 6 | ||
| 5 | #[derive(Debug)] | 7 | #[derive(Debug)] |
| @@ -109,12 +111,51 @@ numeric_enum! { | |||
| 109 | } | 111 | } |
| 110 | } | 112 | } |
| 111 | 113 | ||
| 114 | impl TryFrom<AddressingMode> for AddressMode { | ||
| 115 | type Error = (); | ||
| 116 | |||
| 117 | fn try_from(value: AddressingMode) -> Result<Self, Self::Error> { | ||
| 118 | match value { | ||
| 119 | AddressingMode::Absent => Ok(Self::NoAddress), | ||
| 120 | AddressingMode::Extended => Ok(Self::Extended), | ||
| 121 | AddressingMode::Short => Ok(Self::Short), | ||
| 122 | AddressingMode::Unknown(_) => Err(()), | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 112 | #[derive(Clone, Copy)] | 127 | #[derive(Clone, Copy)] |
| 113 | pub union MacAddress { | 128 | pub union MacAddress { |
| 114 | pub short: [u8; 2], | 129 | pub short: [u8; 2], |
| 115 | pub extended: [u8; 8], | 130 | pub extended: [u8; 8], |
| 116 | } | 131 | } |
| 117 | 132 | ||
| 133 | impl From<Address> for MacAddress { | ||
| 134 | fn from(value: Address) -> Self { | ||
| 135 | match value { | ||
| 136 | Address::Short(addr) => Self { short: addr }, | ||
| 137 | Address::Extended(addr) => Self { extended: addr }, | ||
| 138 | Address::Absent => Self { short: [0u8; 2] }, | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | pub struct MacAddressAndMode(pub MacAddress, pub AddressMode); | ||
| 144 | |||
| 145 | impl From<MacAddressAndMode> for Address { | ||
| 146 | fn from(mac_address_and_mode: MacAddressAndMode) -> Self { | ||
| 147 | let address = mac_address_and_mode.0; | ||
| 148 | let mode = mac_address_and_mode.1; | ||
| 149 | |||
| 150 | match mode { | ||
| 151 | AddressMode::Short => Address::Short(unsafe { address.short }), | ||
| 152 | AddressMode::Extended => Address::Extended(unsafe { address.extended }), | ||
| 153 | AddressMode::NoAddress => Address::Absent, | ||
| 154 | AddressMode::Reserved => Address::Absent, | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 118 | impl Debug for MacAddress { | 159 | impl Debug for MacAddress { |
| 119 | fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | 160 | fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
| 120 | unsafe { | 161 | unsafe { |
| @@ -346,7 +387,7 @@ numeric_enum! { | |||
| 346 | 387 | ||
| 347 | numeric_enum! { | 388 | numeric_enum! { |
| 348 | #[repr(u8)] | 389 | #[repr(u8)] |
| 349 | #[derive(Default, Clone, Copy, Debug)] | 390 | #[derive(Default, Clone, Copy, Debug, PartialEq)] |
| 350 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 391 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 351 | pub enum SecurityLevel { | 392 | pub enum SecurityLevel { |
| 352 | /// MAC Unsecured Mode Security | 393 | /// MAC Unsecured Mode Security |
| @@ -379,3 +420,15 @@ pub struct PanId(pub [u8; 2]); | |||
| 379 | impl PanId { | 420 | impl PanId { |
| 380 | pub const BROADCAST: Self = Self([0xFF, 0xFF]); | 421 | pub const BROADCAST: Self = Self([0xFF, 0xFF]); |
| 381 | } | 422 | } |
| 423 | |||
| 424 | impl From<Pan> for PanId { | ||
| 425 | fn from(value: Pan) -> Self { | ||
| 426 | Self(value.0.to_be_bytes()) | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | impl From<PanId> for Pan { | ||
| 431 | fn from(value: PanId) -> Self { | ||
| 432 | Self(u16::from_be_bytes(value.0)) | ||
| 433 | } | ||
| 434 | } | ||
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs index baf4da979..93cafbc72 100644 --- a/embassy-stm32-wpan/src/sub/mac.rs +++ b/embassy-stm32-wpan/src/sub/mac.rs | |||
| @@ -28,32 +28,39 @@ impl Mac { | |||
| 28 | Self { _private: () } | 28 | Self { _private: () } |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | /// `HW_IPCC_MAC_802_15_4_EvtNot` | 31 | pub const fn split(self) -> (MacRx, MacTx) { |
| 32 | /// | 32 | (MacRx { _private: () }, MacTx { _private: () }) |
| 33 | /// This function will stall if the previous `EvtBox` has not been dropped | 33 | } |
| 34 | pub async fn tl_read(&self) -> EvtBox<Self> { | ||
| 35 | // Wait for the last event box to be dropped | ||
| 36 | poll_fn(|cx| { | ||
| 37 | MAC_WAKER.register(cx.waker()); | ||
| 38 | if MAC_EVT_OUT.load(Ordering::SeqCst) { | ||
| 39 | Poll::Pending | ||
| 40 | } else { | ||
| 41 | Poll::Ready(()) | ||
| 42 | } | ||
| 43 | }) | ||
| 44 | .await; | ||
| 45 | 34 | ||
| 46 | // Return a new event box | 35 | pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { |
| 47 | Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe { | 36 | MacTx { _private: () }.tl_write_and_get_response(opcode, payload).await |
| 48 | // The closure is not async, therefore the closure must execute to completion (cannot be dropped) | 37 | } |
| 49 | // Therefore, the event box is guaranteed to be cleaned up if it's not leaked | ||
| 50 | MAC_EVT_OUT.store(true, Ordering::SeqCst); | ||
| 51 | 38 | ||
| 52 | Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) | 39 | pub async fn tl_write(&self, opcode: u16, payload: &[u8]) { |
| 53 | }) | 40 | MacTx { _private: () }.tl_write(opcode, payload).await |
| 54 | .await | ||
| 55 | } | 41 | } |
| 56 | 42 | ||
| 43 | pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError> | ||
| 44 | where | ||
| 45 | T: MacCommand, | ||
| 46 | { | ||
| 47 | MacTx { _private: () }.send_command(cmd).await | ||
| 48 | } | ||
| 49 | |||
| 50 | pub async fn tl_read(&self) -> EvtBox<Mac> { | ||
| 51 | MacRx { _private: () }.tl_read().await | ||
| 52 | } | ||
| 53 | |||
| 54 | pub async fn read(&self) -> Result<MacEvent<'_>, ()> { | ||
| 55 | MacRx { _private: () }.read().await | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | pub struct MacTx { | ||
| 60 | _private: (), | ||
| 61 | } | ||
| 62 | |||
| 63 | impl MacTx { | ||
| 57 | /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` | 64 | /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` |
| 58 | pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { | 65 | pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 { |
| 59 | self.tl_write(opcode, payload).await; | 66 | self.tl_write(opcode, payload).await; |
| @@ -92,6 +99,38 @@ impl Mac { | |||
| 92 | Err(MacError::from(response)) | 99 | Err(MacError::from(response)) |
| 93 | } | 100 | } |
| 94 | } | 101 | } |
| 102 | } | ||
| 103 | |||
| 104 | pub struct MacRx { | ||
| 105 | _private: (), | ||
| 106 | } | ||
| 107 | |||
| 108 | impl MacRx { | ||
| 109 | /// `HW_IPCC_MAC_802_15_4_EvtNot` | ||
| 110 | /// | ||
| 111 | /// This function will stall if the previous `EvtBox` has not been dropped | ||
| 112 | pub async fn tl_read(&self) -> EvtBox<Mac> { | ||
| 113 | // Wait for the last event box to be dropped | ||
| 114 | poll_fn(|cx| { | ||
| 115 | MAC_WAKER.register(cx.waker()); | ||
| 116 | if MAC_EVT_OUT.load(Ordering::SeqCst) { | ||
| 117 | Poll::Pending | ||
| 118 | } else { | ||
| 119 | Poll::Ready(()) | ||
| 120 | } | ||
| 121 | }) | ||
| 122 | .await; | ||
| 123 | |||
| 124 | // Return a new event box | ||
| 125 | Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe { | ||
| 126 | // The closure is not async, therefore the closure must execute to completion (cannot be dropped) | ||
| 127 | // Therefore, the event box is guaranteed to be cleaned up if it's not leaked | ||
| 128 | MAC_EVT_OUT.store(true, Ordering::SeqCst); | ||
| 129 | |||
| 130 | Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) | ||
| 131 | }) | ||
| 132 | .await | ||
| 133 | } | ||
| 95 | 134 | ||
| 96 | pub async fn read(&self) -> Result<MacEvent<'_>, ()> { | 135 | pub async fn read(&self) -> Result<MacEvent<'_>, ()> { |
| 97 | MacEvent::new(self.tl_read().await) | 136 | MacEvent::new(self.tl_read().await) |
diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs index 62d0de8bd..a90c6ee55 100644 --- a/embassy-stm32-wpan/src/sub/mm.rs +++ b/embassy-stm32-wpan/src/sub/mm.rs | |||
| @@ -46,7 +46,7 @@ impl MemoryManager { | |||
| 46 | Self { _private: () } | 46 | Self { _private: () } |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | pub async fn run_queue(&self) { | 49 | pub async fn run_queue(&self) -> ! { |
| 50 | loop { | 50 | loop { |
| 51 | poll_fn(|cx| unsafe { | 51 | poll_fn(|cx| unsafe { |
| 52 | MM_WAKER.register(cx.waker()); | 52 | MM_WAKER.register(cx.waker()); |
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index d17663a61..b6caf8f65 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | ## Unreleased - ReleaseDate | 8 | ## Unreleased - ReleaseDate |
| 9 | 9 | ||
| 10 | - change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871)) | 10 | - change: stm32/eth: ethernet no longer has a hard dependency on station management, and station management can be used independently ([#4871](https://github.com/embassy-rs/embassy/pull/4871)) |
| 11 | - feat: allow embassy_executor::main for low power | ||
| 12 | - feat: Add waveform methods to ComplementaryPwm | ||
| 13 | - fix: Avoid generating timer update events when updating the frequency ([#4890](https://github.com/embassy-rs/embassy/pull/4890)) | ||
| 14 | - chore: cleanup low-power add time | ||
| 15 | - fix: Allow setting SAI peripheral `frame_length` to `256` | ||
| 11 | - fix: flash erase on dual-bank STM32Gxxx | 16 | - fix: flash erase on dual-bank STM32Gxxx |
| 12 | - feat: Add support for STM32N657X0 | 17 | - feat: Add support for STM32N657X0 |
| 13 | - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) | 18 | - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) |
| @@ -39,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 39 | - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) | 44 | - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) |
| 40 | - feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options | 45 | - feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options |
| 41 | - change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer | 46 | - change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer |
| 47 | - fix: stm32/adc: Calculate the ADC prescaler in a way that it allows for the max frequency to be reached | ||
| 42 | - fix: Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) | 48 | - fix: Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) |
| 43 | - change: timer: added output compare values | 49 | - change: timer: added output compare values |
| 44 | - feat: timer: add ability to set master mode | 50 | - feat: timer: add ability to set master mode |
| @@ -59,6 +65,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 59 | - adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion | 65 | - adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion |
| 60 | - fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written | 66 | - fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written |
| 61 | - feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874)) | 67 | - feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874)) |
| 68 | - fix: fixing channel numbers on vbat and vddcore for adc on adc | ||
| 69 | - adc: adding disable to vbat | ||
| 62 | 70 | ||
| 63 | ## 0.4.0 - 2025-08-26 | 71 | ## 0.4.0 - 2025-08-26 |
| 64 | 72 | ||
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index babdebfdb..499fc2093 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs | |||
| @@ -77,7 +77,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | fn from_ker_ck(frequency: Hertz) -> Presc { | 79 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 80 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | 80 | let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0); |
| 81 | match raw_prescaler { | 81 | match raw_prescaler { |
| 82 | 0 => Presc::DIV1, | 82 | 0 => Presc::DIV1, |
| 83 | 1 => Presc::DIV2, | 83 | 1 => Presc::DIV2, |
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 3bdca7edb..3e109e429 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #[allow(unused)] | 1 | #[allow(unused)] |
| 2 | use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; | 2 | use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; |
| 3 | use pac::adccommon::vals::Presc; | 3 | use pac::adccommon::vals::Presc; |
| 4 | use stm32_metapac::adc::vals::Scandir; | 4 | use stm32_metapac::adc::vals::{SampleTime, Scandir}; |
| 5 | 5 | ||
| 6 | use super::{Adc, Instance, Resolution, blocking_delay_us}; | 6 | use super::{Adc, Instance, Resolution, blocking_delay_us}; |
| 7 | use crate::adc::{AnyInstance, ConversionMode}; | 7 | use crate::adc::{AnyInstance, ConversionMode}; |
| @@ -17,7 +17,6 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25); | |||
| 17 | 17 | ||
| 18 | const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; | 18 | const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; |
| 19 | 19 | ||
| 20 | const NUM_HW_CHANNELS: u8 = 22; | ||
| 21 | const CHSELR_SQ_SIZE: usize = 8; | 20 | const CHSELR_SQ_SIZE: usize = 8; |
| 22 | const CHSELR_SQ_MAX_CHANNEL: u8 = 14; | 21 | const CHSELR_SQ_MAX_CHANNEL: u8 = 14; |
| 23 | const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; | 22 | const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; |
| @@ -31,7 +30,7 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { | |||
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | fn from_ker_ck(frequency: Hertz) -> Presc { | 32 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 34 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | 33 | let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0); |
| 35 | match raw_prescaler { | 34 | match raw_prescaler { |
| 36 | 0 => Presc::DIV1, | 35 | 0 => Presc::DIV1, |
| 37 | 1 => Presc::DIV2, | 36 | 1 => Presc::DIV2, |
| @@ -100,82 +99,67 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 100 | } | 99 | } |
| 101 | } | 100 | } |
| 102 | 101 | ||
| 103 | fn configure_sequence(mut sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool) { | 102 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>) { |
| 104 | T::regs().cfgr1().modify(|reg| { | 103 | let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE; |
| 105 | reg.set_chselrmod(!blocking); | 104 | let mut is_ordered_up = true; |
| 106 | reg.set_align(Align::RIGHT); | 105 | let mut is_ordered_down = true; |
| 107 | }); | ||
| 108 | 106 | ||
| 109 | assert!(!blocking || sequence.len() == 1, "Sequence len must be 1 for blocking."); | 107 | let sequence_len = sequence.len(); |
| 110 | if blocking { | 108 | let mut hw_channel_selection: u32 = 0; |
| 111 | let ((ch, _), sample_time) = sequence.next().unwrap(); | 109 | let mut last_channel: u8 = 0; |
| 112 | // Set all channels to use SMP1 field as source. | 110 | let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5; |
| 113 | T::regs().smpr().modify(|w| { | 111 | |
| 114 | w.smpsel(0); | 112 | T::regs().chselr_sq().write(|w| { |
| 115 | w.set_smp1(sample_time); | 113 | for (i, ((channel, _), _sample_time)) in sequence.enumerate() { |
| 116 | }); | 114 | assert!( |
| 115 | sample_time == _sample_time || i == 0, | ||
| 116 | "C0 only supports one sample time for the sequence." | ||
| 117 | ); | ||
| 117 | 118 | ||
| 118 | // write() because we want all other bits to be set to 0. | 119 | sample_time = _sample_time; |
| 119 | T::regs().chselr().write(|w| w.set_chsel(ch.into(), true)); | 120 | needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL; |
| 120 | } else { | 121 | is_ordered_up = is_ordered_up && (channel > last_channel || i == 0); |
| 121 | let mut hw_channel_selection: u32 = 0; | 122 | is_ordered_down = is_ordered_down && (channel < last_channel || i == 0); |
| 122 | let mut is_ordered_up = true; | 123 | hw_channel_selection += 1 << channel; |
| 123 | let mut is_ordered_down = true; | 124 | last_channel = channel; |
| 124 | let mut needs_hw = false; | ||
| 125 | 125 | ||
| 126 | if !needs_hw { | ||
| 127 | w.set_sq(i, channel); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | for i in sequence_len..CHSELR_SQ_SIZE { | ||
| 132 | w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); | ||
| 133 | } | ||
| 134 | }); | ||
| 135 | |||
| 136 | if needs_hw { | ||
| 126 | assert!( | 137 | assert!( |
| 127 | sequence.len() <= CHSELR_SQ_SIZE, | 138 | sequence_len <= CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down, |
| 128 | "Sequence read set cannot be more than {} in size.", | 139 | "Sequencer is required because of unordered channels, but read set cannot be more than {} in size.", |
| 129 | CHSELR_SQ_SIZE | 140 | CHSELR_SQ_SIZE |
| 130 | ); | 141 | ); |
| 131 | let mut last_sq_set: usize = 0; | 142 | assert!( |
| 132 | let mut last_channel: u8 = 0; | 143 | sequence_len > CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down, |
| 133 | T::regs().chselr_sq().write(|w| { | 144 | "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.", |
| 134 | for (i, ((channel, _), _sample_time)) in sequence.enumerate() { | 145 | CHSELR_SQ_MAX_CHANNEL |
| 135 | needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL; | 146 | ); |
| 136 | last_sq_set = i; | ||
| 137 | is_ordered_up = is_ordered_up && channel > last_channel; | ||
| 138 | is_ordered_down = is_ordered_down && channel < last_channel; | ||
| 139 | hw_channel_selection += 1 << channel; | ||
| 140 | last_channel = channel; | ||
| 141 | |||
| 142 | if !needs_hw { | ||
| 143 | w.set_sq(i, channel); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | assert!( | ||
| 148 | !needs_hw || is_ordered_up || is_ordered_down, | ||
| 149 | "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.", | ||
| 150 | CHSELR_SQ_MAX_CHANNEL | ||
| 151 | ); | ||
| 152 | 147 | ||
| 153 | if needs_hw { | 148 | // Set required channels for multi-convert. |
| 154 | assert!( | 149 | unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } |
| 155 | hw_channel_selection != 0, | ||
| 156 | "Some bits in `hw_channel_selection` shall be set." | ||
| 157 | ); | ||
| 158 | assert!( | ||
| 159 | (hw_channel_selection >> NUM_HW_CHANNELS) == 0, | ||
| 160 | "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", | ||
| 161 | NUM_HW_CHANNELS | ||
| 162 | ); | ||
| 163 | |||
| 164 | T::regs().cfgr1().modify(|reg| { | ||
| 165 | reg.set_chselrmod(false); | ||
| 166 | reg.set_scandir(if is_ordered_up { Scandir::UP} else { Scandir::BACK }); | ||
| 167 | }); | ||
| 168 | |||
| 169 | // Set required channels for multi-convert. | ||
| 170 | unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } | ||
| 171 | } else { | ||
| 172 | for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { | ||
| 173 | w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | }); | ||
| 177 | } | 150 | } |
| 178 | 151 | ||
| 152 | T::regs().smpr().modify(|w| { | ||
| 153 | w.smpsel(0); | ||
| 154 | w.set_smp1(sample_time); | ||
| 155 | }); | ||
| 156 | |||
| 157 | T::regs().cfgr1().modify(|reg| { | ||
| 158 | reg.set_chselrmod(!needs_hw); | ||
| 159 | reg.set_align(Align::RIGHT); | ||
| 160 | reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK }); | ||
| 161 | }); | ||
| 162 | |||
| 179 | // Trigger and wait for the channel selection procedure to complete. | 163 | // Trigger and wait for the channel selection procedure to complete. |
| 180 | T::regs().isr().modify(|w| w.set_ccrdy(false)); | 164 | T::regs().isr().modify(|w| w.set_ccrdy(false)); |
| 181 | while !T::regs().isr().read().ccrdy() {} | 165 | while !T::regs().isr().read().ccrdy() {} |
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 514734017..1767a3bb3 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | #[cfg(stm32g4)] | ||
| 2 | use pac::adc::regs::Difsel as DifselReg; | ||
| 3 | #[allow(unused)] | ||
| 4 | #[cfg(stm32g4)] | ||
| 5 | pub use pac::adc::vals::{Adcaldif, Adstp, Difsel, Dmacfg, Dmaen, Exten, Rovsm, Trovs}; | ||
| 1 | #[allow(unused)] | 6 | #[allow(unused)] |
| 2 | #[cfg(stm32h7)] | 7 | #[cfg(stm32h7)] |
| 3 | use pac::adc::vals::{Adcaldif, Difsel, Exten}; | 8 | use pac::adc::vals::{Adcaldif, Difsel, Exten}; |
| 4 | #[allow(unused)] | 9 | pub use pac::adccommon::vals::{Dual, Presc}; |
| 5 | #[cfg(stm32g4)] | ||
| 6 | pub use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; | ||
| 7 | pub use pac::adccommon::vals::Presc; | ||
| 8 | pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; | ||
| 9 | pub use stm32_metapac::adccommon::vals::Dual; | ||
| 10 | 10 | ||
| 11 | use super::{ | 11 | use super::{ |
| 12 | Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, | 12 | Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, |
| @@ -33,7 +33,7 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); | |||
| 33 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); | 33 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); |
| 34 | 34 | ||
| 35 | fn from_ker_ck(frequency: Hertz) -> Presc { | 35 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 36 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | 36 | let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0); |
| 37 | match raw_prescaler { | 37 | match raw_prescaler { |
| 38 | 0 => Presc::DIV1, | 38 | 0 => Presc::DIV1, |
| 39 | 1 => Presc::DIV2, | 39 | 1 => Presc::DIV2, |
| @@ -174,50 +174,51 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 176 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 177 | T::regs().cr().modify(|w| w.set_aden(false)); | ||
| 178 | |||
| 177 | // Set sequence length | 179 | // Set sequence length |
| 178 | T::regs().sqr1().modify(|w| { | 180 | T::regs().sqr1().modify(|w| { |
| 179 | w.set_l(sequence.len() as u8 - 1); | 181 | w.set_l(sequence.len() as u8 - 1); |
| 180 | }); | 182 | }); |
| 181 | 183 | ||
| 184 | #[cfg(stm32g4)] | ||
| 185 | let mut difsel = DifselReg::default(); | ||
| 186 | let mut smpr = T::regs().smpr().read(); | ||
| 187 | let mut smpr2 = T::regs().smpr2().read(); | ||
| 188 | let mut sqr1 = T::regs().sqr1().read(); | ||
| 189 | let mut sqr2 = T::regs().sqr2().read(); | ||
| 190 | let mut sqr3 = T::regs().sqr3().read(); | ||
| 191 | let mut sqr4 = T::regs().sqr4().read(); | ||
| 192 | |||
| 182 | // Configure channels and ranks | 193 | // Configure channels and ranks |
| 183 | for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { | 194 | for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { |
| 184 | let sample_time = sample_time.into(); | 195 | let sample_time = sample_time.into(); |
| 185 | if ch <= 9 { | 196 | if ch <= 9 { |
| 186 | T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); | 197 | smpr.set_smp(ch as _, sample_time); |
| 187 | } else { | 198 | } else { |
| 188 | T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | 199 | smpr2.set_smp((ch - 10) as _, sample_time); |
| 189 | } | 200 | } |
| 190 | 201 | ||
| 191 | match _i { | 202 | match _i { |
| 192 | 0..=3 => { | 203 | 0..=3 => { |
| 193 | T::regs().sqr1().modify(|w| { | 204 | sqr1.set_sq(_i, ch); |
| 194 | w.set_sq(_i, ch); | ||
| 195 | }); | ||
| 196 | } | 205 | } |
| 197 | 4..=8 => { | 206 | 4..=8 => { |
| 198 | T::regs().sqr2().modify(|w| { | 207 | sqr2.set_sq(_i - 4, ch); |
| 199 | w.set_sq(_i - 4, ch); | ||
| 200 | }); | ||
| 201 | } | 208 | } |
| 202 | 9..=13 => { | 209 | 9..=13 => { |
| 203 | T::regs().sqr3().modify(|w| { | 210 | sqr3.set_sq(_i - 9, ch); |
| 204 | w.set_sq(_i - 9, ch); | ||
| 205 | }); | ||
| 206 | } | 211 | } |
| 207 | 14..=15 => { | 212 | 14..=15 => { |
| 208 | T::regs().sqr4().modify(|w| { | 213 | sqr4.set_sq(_i - 14, ch); |
| 209 | w.set_sq(_i - 14, ch); | ||
| 210 | }); | ||
| 211 | } | 214 | } |
| 212 | _ => unreachable!(), | 215 | _ => unreachable!(), |
| 213 | } | 216 | } |
| 214 | 217 | ||
| 215 | #[cfg(stm32g4)] | 218 | #[cfg(stm32g4)] |
| 216 | { | 219 | { |
| 217 | T::regs().cr().modify(|w| w.set_aden(false)); // disable adc | 220 | if ch < 18 { |
| 218 | 221 | difsel.set_difsel( | |
| 219 | T::regs().difsel().modify(|w| { | ||
| 220 | w.set_difsel( | ||
| 221 | ch.into(), | 222 | ch.into(), |
| 222 | if is_differential { | 223 | if is_differential { |
| 223 | Difsel::DIFFERENTIAL | 224 | Difsel::DIFFERENTIAL |
| @@ -225,11 +226,18 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 225 | Difsel::SINGLE_ENDED | 226 | Difsel::SINGLE_ENDED |
| 226 | }, | 227 | }, |
| 227 | ); | 228 | ); |
| 228 | }); | 229 | } |
| 229 | |||
| 230 | T::regs().cr().modify(|w| w.set_aden(true)); // enable adc | ||
| 231 | } | 230 | } |
| 232 | } | 231 | } |
| 232 | |||
| 233 | T::regs().smpr().write_value(smpr); | ||
| 234 | T::regs().smpr2().write_value(smpr2); | ||
| 235 | T::regs().sqr1().write_value(sqr1); | ||
| 236 | T::regs().sqr2().write_value(sqr2); | ||
| 237 | T::regs().sqr3().write_value(sqr3); | ||
| 238 | T::regs().sqr4().write_value(sqr4); | ||
| 239 | #[cfg(stm32g4)] | ||
| 240 | T::regs().difsel().write_value(difsel); | ||
| 233 | } | 241 | } |
| 234 | } | 242 | } |
| 235 | 243 | ||
| @@ -412,7 +420,6 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 412 | NR_INJECTED_RANKS | 420 | NR_INJECTED_RANKS |
| 413 | ); | 421 | ); |
| 414 | 422 | ||
| 415 | T::stop(); | ||
| 416 | T::enable(); | 423 | T::enable(); |
| 417 | 424 | ||
| 418 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); | 425 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 5ec08a22d..74648cc21 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -111,10 +111,7 @@ pub(self) trait SealedAnyInstance: BasicAnyInstance { | |||
| 111 | fn stop(); | 111 | fn stop(); |
| 112 | fn convert() -> u16; | 112 | fn convert() -> u16; |
| 113 | fn configure_dma(conversion_mode: ConversionMode); | 113 | fn configure_dma(conversion_mode: ConversionMode); |
| 114 | #[cfg(not(adc_c0))] | ||
| 115 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); | 114 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); |
| 116 | #[cfg(adc_c0)] | ||
| 117 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool); | ||
| 118 | #[allow(dead_code)] | 115 | #[allow(dead_code)] |
| 119 | fn dr() -> *mut u16; | 116 | fn dr() -> *mut u16; |
| 120 | } | 117 | } |
| @@ -195,15 +192,15 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 195 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 192 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] |
| 196 | channel.setup(); | 193 | channel.setup(); |
| 197 | 194 | ||
| 198 | #[cfg(not(adc_v4))] | 195 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))] |
| 199 | T::enable(); | 196 | T::enable(); |
| 200 | #[cfg(not(adc_c0))] | ||
| 201 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); | 197 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); |
| 202 | #[cfg(adc_c0)] | 198 | |
| 203 | T::configure_sequence( | 199 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels |
| 204 | [((channel.channel(), channel.is_differential()), sample_time)].into_iter(), | 200 | // |
| 205 | true, | 201 | // TODO: If hardware allows, enable after configure_sequence on all chips |
| 206 | ); | 202 | #[cfg(any(adc_g4, adc_h5))] |
| 203 | T::enable(); | ||
| 207 | 204 | ||
| 208 | T::convert() | 205 | T::convert() |
| 209 | } | 206 | } |
| @@ -238,10 +235,10 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 238 | /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use | 235 | /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use |
| 239 | /// `into_ring_buffered`, `into_ring_buffered_and_injected` | 236 | /// `into_ring_buffered`, `into_ring_buffered_and_injected` |
| 240 | /// | 237 | /// |
| 241 | /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use | 238 | /// Note: Depending on hardware limitations, this method may require channels to be passed |
| 242 | /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). | 239 | /// in order or require the sequence to have the same sample time for all channnels, depending |
| 243 | /// | 240 | /// on the number and properties of the channels in the sequence. This method will panic if |
| 244 | /// In addtion, on STM320, this method will panic if the channels are not passed in order | 241 | /// the hardware cannot deliver the requested configuration. |
| 245 | pub async fn read( | 242 | pub async fn read( |
| 246 | &mut self, | 243 | &mut self, |
| 247 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, | 244 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, |
| @@ -258,21 +255,20 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 258 | "Asynchronous read sequence cannot be more than 16 in length" | 255 | "Asynchronous read sequence cannot be more than 16 in length" |
| 259 | ); | 256 | ); |
| 260 | 257 | ||
| 261 | // Ensure no conversions are ongoing and ADC is enabled. | 258 | // Ensure no conversions are ongoing |
| 262 | T::stop(); | 259 | T::stop(); |
| 260 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 263 | T::enable(); | 261 | T::enable(); |
| 264 | 262 | ||
| 265 | #[cfg(not(adc_c0))] | ||
| 266 | T::configure_sequence( | ||
| 267 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | ||
| 268 | ); | ||
| 269 | |||
| 270 | #[cfg(adc_c0)] | ||
| 271 | T::configure_sequence( | 263 | T::configure_sequence( |
| 272 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 264 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 273 | false, | ||
| 274 | ); | 265 | ); |
| 275 | 266 | ||
| 267 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels | ||
| 268 | // | ||
| 269 | // TODO: If hardware allows, enable after configure_sequence on all chips | ||
| 270 | #[cfg(any(adc_g4, adc_h5))] | ||
| 271 | T::enable(); | ||
| 276 | T::configure_dma(ConversionMode::Singular); | 272 | T::configure_dma(ConversionMode::Singular); |
| 277 | 273 | ||
| 278 | let request = rx_dma.request(); | 274 | let request = rx_dma.request(); |
| @@ -310,6 +306,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 310 | /// | 306 | /// |
| 311 | /// # Returns | 307 | /// # Returns |
| 312 | /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling. | 308 | /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling. |
| 309 | /// | ||
| 310 | /// Note: Depending on hardware limitations, this method may require channels to be passed | ||
| 311 | /// in order or require the sequence to have the same sample time for all channnels, depending | ||
| 312 | /// on the number and properties of the channels in the sequence. This method will panic if | ||
| 313 | /// the hardware cannot deliver the requested configuration. | ||
| 313 | pub fn into_ring_buffered<'a>( | 314 | pub fn into_ring_buffered<'a>( |
| 314 | self, | 315 | self, |
| 315 | dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, | 316 | dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, |
| @@ -323,15 +324,20 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 323 | sequence.len() <= 16, | 324 | sequence.len() <= 16, |
| 324 | "Asynchronous read sequence cannot be more than 16 in length" | 325 | "Asynchronous read sequence cannot be more than 16 in length" |
| 325 | ); | 326 | ); |
| 326 | // reset conversions and enable the adc | 327 | // Ensure no conversions are ongoing |
| 327 | T::stop(); | 328 | T::stop(); |
| 329 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 328 | T::enable(); | 330 | T::enable(); |
| 329 | 331 | ||
| 330 | //adc side setup | ||
| 331 | T::configure_sequence( | 332 | T::configure_sequence( |
| 332 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 333 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 333 | ); | 334 | ); |
| 334 | 335 | ||
| 336 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels | ||
| 337 | // | ||
| 338 | // TODO: If hardware allows, enable after configure_sequence on all chips | ||
| 339 | #[cfg(any(adc_g4, adc_h5))] | ||
| 340 | T::enable(); | ||
| 335 | T::configure_dma(ConversionMode::Repeated(mode)); | 341 | T::configure_dma(ConversionMode::Repeated(mode)); |
| 336 | 342 | ||
| 337 | core::mem::forget(self); | 343 | core::mem::forget(self); |
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 07eaebf7c..341b15674 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -58,7 +58,7 @@ fn from_pclk2(freq: Hertz) -> Adcpre { | |||
| 58 | // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. | 58 | // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. |
| 59 | #[cfg(not(stm32f2))] | 59 | #[cfg(not(stm32f2))] |
| 60 | const MAX_FREQUENCY: Hertz = Hertz(36_000_000); | 60 | const MAX_FREQUENCY: Hertz = Hertz(36_000_000); |
| 61 | let raw_div = freq.0 / MAX_FREQUENCY.0; | 61 | let raw_div = rcc::raw_prescaler(freq.0, MAX_FREQUENCY.0); |
| 62 | match raw_div { | 62 | match raw_div { |
| 63 | 0..=1 => Adcpre::DIV2, | 63 | 0..=1 => Adcpre::DIV2, |
| 64 | 2..=3 => Adcpre::DIV4, | 64 | 2..=3 => Adcpre::DIV4, |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 78b497727..b270588c4 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -65,7 +65,7 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { | |||
| 65 | } | 65 | } |
| 66 | #[cfg(any(adc_h5, adc_h7rs))] | 66 | #[cfg(any(adc_h5, adc_h7rs))] |
| 67 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { | 67 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { |
| 68 | const CHANNEL: u8 = 2; | 68 | const CHANNEL: u8 = 16; |
| 69 | } | 69 | } |
| 70 | #[cfg(adc_u0)] | 70 | #[cfg(adc_u0)] |
| 71 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { | 71 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { |
| @@ -82,7 +82,7 @@ cfg_if! { | |||
| 82 | impl<T: Instance> super::AdcChannel<T> for VddCore {} | 82 | impl<T: Instance> super::AdcChannel<T> for VddCore {} |
| 83 | impl<T: Instance> super::SealedAdcChannel<T> for VddCore { | 83 | impl<T: Instance> super::SealedAdcChannel<T> for VddCore { |
| 84 | fn channel(&self) -> u8 { | 84 | fn channel(&self) -> u8 { |
| 85 | 6 | 85 | 17 |
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| 88 | } | 88 | } |
| @@ -174,38 +174,31 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | fn start() { | 176 | fn start() { |
| 177 | #[cfg(any(adc_v3, adc_g0, adc_u0))] | 177 | T::regs().cr().modify(|reg| { |
| 178 | { | 178 | reg.set_adstart(true); |
| 179 | // Start adc conversion | 179 | }); |
| 180 | T::regs().cr().modify(|reg| { | ||
| 181 | reg.set_adstart(true); | ||
| 182 | }); | ||
| 183 | } | ||
| 184 | } | 180 | } |
| 185 | 181 | ||
| 186 | fn stop() { | 182 | fn stop() { |
| 187 | #[cfg(any(adc_v3, adc_g0, adc_u0))] | 183 | // Ensure conversions are finished. |
| 188 | { | 184 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
| 189 | // Ensure conversions are finished. | 185 | T::regs().cr().modify(|reg| { |
| 190 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 186 | reg.set_adstp(true); |
| 191 | T::regs().cr().modify(|reg| { | ||
| 192 | reg.set_adstp(true); | ||
| 193 | }); | ||
| 194 | while T::regs().cr().read().adstart() {} | ||
| 195 | } | ||
| 196 | |||
| 197 | // Reset configuration. | ||
| 198 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 199 | T::regs().cfgr().modify(|reg| { | ||
| 200 | reg.set_cont(false); | ||
| 201 | reg.set_dmaen(false); | ||
| 202 | }); | ||
| 203 | #[cfg(any(adc_g0, adc_u0))] | ||
| 204 | T::regs().cfgr1().modify(|reg| { | ||
| 205 | reg.set_cont(false); | ||
| 206 | reg.set_dmaen(false); | ||
| 207 | }); | 187 | }); |
| 188 | while T::regs().cr().read().adstart() {} | ||
| 208 | } | 189 | } |
| 190 | |||
| 191 | // Reset configuration. | ||
| 192 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 193 | T::regs().cfgr().modify(|reg| { | ||
| 194 | reg.set_cont(false); | ||
| 195 | reg.set_dmaen(false); | ||
| 196 | }); | ||
| 197 | #[cfg(any(adc_g0, adc_u0))] | ||
| 198 | T::regs().cfgr1().modify(|reg| { | ||
| 199 | reg.set_cont(false); | ||
| 200 | reg.set_dmaen(false); | ||
| 201 | }); | ||
| 209 | } | 202 | } |
| 210 | 203 | ||
| 211 | /// Perform a single conversion. | 204 | /// Perform a single conversion. |
| @@ -267,6 +260,9 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 267 | } | 260 | } |
| 268 | 261 | ||
| 269 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { | 262 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 263 | #[cfg(adc_h5)] | ||
| 264 | T::regs().cr().modify(|w| w.set_aden(false)); | ||
| 265 | |||
| 270 | // Set sequence length | 266 | // Set sequence length |
| 271 | #[cfg(not(any(adc_g0, adc_u0)))] | 267 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 272 | T::regs().sqr1().modify(|w| { | 268 | T::regs().sqr1().modify(|w| { |
| @@ -301,8 +297,11 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 301 | #[cfg(adc_u0)] | 297 | #[cfg(adc_u0)] |
| 302 | let mut channel_mask = 0; | 298 | let mut channel_mask = 0; |
| 303 | 299 | ||
| 300 | #[cfg(adc_h5)] | ||
| 301 | let mut difsel = 0u32; | ||
| 302 | |||
| 304 | // Configure channels and ranks | 303 | // Configure channels and ranks |
| 305 | for (_i, ((channel, _), sample_time)) in sequence.enumerate() { | 304 | for (_i, ((channel, _is_differential), sample_time)) in sequence.enumerate() { |
| 306 | // RM0492, RM0481, etc. | 305 | // RM0492, RM0481, etc. |
| 307 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." | 306 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." |
| 308 | #[cfg(any(adc_h5, adc_h7rs))] | 307 | #[cfg(any(adc_h5, adc_h7rs))] |
| @@ -364,12 +363,20 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 364 | _ => unreachable!(), | 363 | _ => unreachable!(), |
| 365 | } | 364 | } |
| 366 | 365 | ||
| 366 | #[cfg(adc_h5)] | ||
| 367 | { | ||
| 368 | difsel |= (_is_differential as u32) << channel; | ||
| 369 | } | ||
| 370 | |||
| 367 | #[cfg(adc_u0)] | 371 | #[cfg(adc_u0)] |
| 368 | { | 372 | { |
| 369 | channel_mask |= 1 << channel; | 373 | channel_mask |= 1 << channel; |
| 370 | } | 374 | } |
| 371 | } | 375 | } |
| 372 | 376 | ||
| 377 | #[cfg(adc_h5)] | ||
| 378 | T::regs().difsel().write(|w| w.set_difsel(difsel)); | ||
| 379 | |||
| 373 | // On G0 and U0 enabled channels are sampled from 0 to last channel. | 380 | // On G0 and U0 enabled channels are sampled from 0 to last channel. |
| 374 | // It is possible to add up to 8 sequences if CHSELRMOD = 1. | 381 | // It is possible to add up to 8 sequences if CHSELRMOD = 1. |
| 375 | // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. | 382 | // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. |
| @@ -582,6 +589,24 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 582 | Vbat {} | 589 | Vbat {} |
| 583 | } | 590 | } |
| 584 | 591 | ||
| 592 | pub fn disable_vbat(&self) { | ||
| 593 | cfg_if! { | ||
| 594 | if #[cfg(any(adc_g0, adc_u0))] { | ||
| 595 | T::regs().ccr().modify(|reg| { | ||
| 596 | reg.set_vbaten(false); | ||
| 597 | }); | ||
| 598 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | ||
| 599 | T::common_regs().ccr().modify(|reg| { | ||
| 600 | reg.set_vbaten(false); | ||
| 601 | }); | ||
| 602 | } else { | ||
| 603 | T::common_regs().ccr().modify(|reg| { | ||
| 604 | reg.set_ch18sel(false); | ||
| 605 | }); | ||
| 606 | } | ||
| 607 | } | ||
| 608 | } | ||
| 609 | |||
| 585 | /* | 610 | /* |
| 586 | /// Convert a raw sample from the `Temperature` to deg C | 611 | /// Convert a raw sample from the `Temperature` to deg C |
| 587 | pub fn to_degrees_centigrade(sample: u16) -> f32 { | 612 | pub fn to_degrees_centigrade(sample: u16) -> f32 { |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 804e63db6..a3d9e6176 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -60,7 +60,7 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { | |||
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | fn from_ker_ck(frequency: Hertz) -> Presc { | 62 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 63 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | 63 | let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0); |
| 64 | match raw_prescaler { | 64 | match raw_prescaler { |
| 65 | 0 => Presc::DIV1, | 65 | 0 => Presc::DIV1, |
| 66 | 1 => Presc::DIV2, | 66 | 1 => Presc::DIV2, |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 6e492946a..7c3770643 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -649,10 +649,7 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 649 | rcc::init_rcc(cs, config.rcc); | 649 | rcc::init_rcc(cs, config.rcc); |
| 650 | 650 | ||
| 651 | #[cfg(feature = "low-power")] | 651 | #[cfg(feature = "low-power")] |
| 652 | crate::rtc::init_rtc(cs, config.rtc); | 652 | rtc::init_rtc(cs, config.rtc, config.min_stop_pause); |
| 653 | |||
| 654 | #[cfg(feature = "low-power")] | ||
| 655 | crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause); | ||
| 656 | } | 653 | } |
| 657 | 654 | ||
| 658 | p | 655 | p |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 696dfe83f..cf8f2b393 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | //! | 14 | //! |
| 15 | //! Since entering and leaving low-power modes typically incurs a significant latency, the | 15 | //! Since entering and leaving low-power modes typically incurs a significant latency, the |
| 16 | //! low-power executor will only attempt to enter when the next timer event is at least | 16 | //! low-power executor will only attempt to enter when the next timer event is at least |
| 17 | //! [`time_driver::MIN_STOP_PAUSE`] in the future. | 17 | //! [`time_driver::min_stop_pause`] in the future. |
| 18 | //! | 18 | //! |
| 19 | //! Currently there is no macro analogous to `embassy_executor::main` for this executor; | 19 | //! Currently there is no macro analogous to `embassy_executor::main` for this executor; |
| 20 | //! consequently one must define their entrypoint manually. Moreover, you must relinquish control | 20 | //! consequently one must define their entrypoint manually. Moreover, you must relinquish control |
| @@ -22,21 +22,16 @@ | |||
| 22 | //! | 22 | //! |
| 23 | //! ```rust,no_run | 23 | //! ```rust,no_run |
| 24 | //! use embassy_executor::Spawner; | 24 | //! use embassy_executor::Spawner; |
| 25 | //! use embassy_stm32::low_power::Executor; | 25 | //! use embassy_stm32::low_power; |
| 26 | //! use embassy_stm32::rtc::{Rtc, RtcConfig}; | 26 | //! use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 27 | //! use static_cell::StaticCell; | 27 | //! use embassy_time::Duration; |
| 28 | //! | 28 | //! |
| 29 | //! #[cortex_m_rt::entry] | 29 | //! #[embassy_executor::main(executor = "low_power::Executor")] |
| 30 | //! fn main() -> ! { | ||
| 31 | //! Executor::take().run(|spawner| { | ||
| 32 | //! spawner.spawn(unwrap!(async_main(spawner))); | ||
| 33 | //! }); | ||
| 34 | //! } | ||
| 35 | //! | ||
| 36 | //! #[embassy_executor::task] | ||
| 37 | //! async fn async_main(spawner: Spawner) { | 30 | //! async fn async_main(spawner: Spawner) { |
| 38 | //! // initialize the platform... | 31 | //! // initialize the platform... |
| 39 | //! let mut config = embassy_stm32::Config::default(); | 32 | //! let mut config = embassy_stm32::Config::default(); |
| 33 | //! // the default value, but can be adjusted | ||
| 34 | //! config.min_stop_pause = Duration::from_millis(250); | ||
| 40 | //! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working | 35 | //! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working |
| 41 | //! config.enable_debug_during_sleep = false; | 36 | //! config.enable_debug_during_sleep = false; |
| 42 | //! let p = embassy_stm32::init(config); | 37 | //! let p = embassy_stm32::init(config); |
| @@ -45,11 +40,9 @@ | |||
| 45 | //! } | 40 | //! } |
| 46 | //! ``` | 41 | //! ``` |
| 47 | 42 | ||
| 48 | // TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.` | ||
| 49 | #![allow(static_mut_refs)] | ||
| 50 | |||
| 51 | use core::arch::asm; | 43 | use core::arch::asm; |
| 52 | use core::marker::PhantomData; | 44 | use core::marker::PhantomData; |
| 45 | use core::mem; | ||
| 53 | use core::sync::atomic::{Ordering, compiler_fence}; | 46 | use core::sync::atomic::{Ordering, compiler_fence}; |
| 54 | 47 | ||
| 55 | use cortex_m::peripheral::SCB; | 48 | use cortex_m::peripheral::SCB; |
| @@ -57,11 +50,12 @@ use critical_section::CriticalSection; | |||
| 57 | use embassy_executor::*; | 50 | use embassy_executor::*; |
| 58 | 51 | ||
| 59 | use crate::interrupt; | 52 | use crate::interrupt; |
| 53 | use crate::rcc::{REFCOUNT_STOP1, REFCOUNT_STOP2}; | ||
| 60 | use crate::time_driver::get_driver; | 54 | use crate::time_driver::get_driver; |
| 61 | 55 | ||
| 62 | const THREAD_PENDER: usize = usize::MAX; | 56 | const THREAD_PENDER: usize = usize::MAX; |
| 63 | 57 | ||
| 64 | static mut EXECUTOR: Option<Executor> = None; | 58 | static mut EXECUTOR_TAKEN: bool = false; |
| 65 | 59 | ||
| 66 | /// Prevent the device from going into the stop mode if held | 60 | /// Prevent the device from going into the stop mode if held |
| 67 | pub struct DeviceBusy(StopMode); | 61 | pub struct DeviceBusy(StopMode); |
| @@ -182,42 +176,47 @@ impl Into<Lpms> for StopMode { | |||
| 182 | pub struct Executor { | 176 | pub struct Executor { |
| 183 | inner: raw::Executor, | 177 | inner: raw::Executor, |
| 184 | not_send: PhantomData<*mut ()>, | 178 | not_send: PhantomData<*mut ()>, |
| 185 | scb: SCB, | ||
| 186 | } | 179 | } |
| 187 | 180 | ||
| 188 | impl Executor { | 181 | impl Executor { |
| 189 | /// Create a new Executor. | 182 | /// Create a new Executor. |
| 190 | pub fn take() -> &'static mut Self { | 183 | pub fn new() -> Self { |
| 191 | critical_section::with(|_| unsafe { | 184 | unsafe { |
| 192 | assert!(EXECUTOR.is_none()); | 185 | if EXECUTOR_TAKEN { |
| 193 | 186 | panic!("Low power executor can only be taken once."); | |
| 194 | EXECUTOR = Some(Self { | 187 | } else { |
| 195 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), | 188 | EXECUTOR_TAKEN = true; |
| 196 | not_send: PhantomData, | 189 | } |
| 197 | scb: cortex_m::Peripherals::steal().SCB, | 190 | } |
| 198 | }); | ||
| 199 | |||
| 200 | let executor = EXECUTOR.as_mut().unwrap(); | ||
| 201 | 191 | ||
| 202 | executor | 192 | Self { |
| 203 | }) | 193 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), |
| 194 | not_send: PhantomData, | ||
| 195 | } | ||
| 204 | } | 196 | } |
| 205 | 197 | ||
| 206 | pub(crate) unsafe fn on_wakeup_irq() { | 198 | pub(crate) unsafe fn on_wakeup_irq() { |
| 207 | critical_section::with(|cs| { | 199 | critical_section::with(|cs| { |
| 208 | #[cfg(stm32wlex)] | 200 | #[cfg(stm32wlex)] |
| 209 | { | 201 | { |
| 210 | let extscr = crate::pac::PWR.extscr().read(); | 202 | use crate::pac::rcc::vals::Sw; |
| 203 | use crate::pac::{PWR, RCC}; | ||
| 204 | use crate::rcc::{RCC_CONFIG, init as init_rcc}; | ||
| 205 | |||
| 206 | let extscr = PWR.extscr().read(); | ||
| 211 | if extscr.c1stop2f() || extscr.c1stopf() { | 207 | if extscr.c1stop2f() || extscr.c1stopf() { |
| 212 | // when we wake from any stop mode we need to re-initialize the rcc | 208 | // when we wake from any stop mode we need to re-initialize the rcc |
| 213 | crate::rcc::apply_resume_config(); | 209 | while RCC.cfgr().read().sws() != Sw::MSI {} |
| 210 | |||
| 211 | init_rcc(RCC_CONFIG.unwrap()); | ||
| 212 | |||
| 214 | if extscr.c1stop2f() { | 213 | if extscr.c1stop2f() { |
| 215 | // when we wake from STOP2, we need to re-initialize the time driver | 214 | // when we wake from STOP2, we need to re-initialize the time driver |
| 216 | crate::time_driver::init_timer(cs); | 215 | get_driver().init_timer(cs); |
| 217 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) | 216 | // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) |
| 218 | // and given that we just woke from STOP2, we can reset them | 217 | // and given that we just woke from STOP2, we can reset them |
| 219 | crate::rcc::REFCOUNT_STOP2 = 0; | 218 | REFCOUNT_STOP2 = 0; |
| 220 | crate::rcc::REFCOUNT_STOP1 = 0; | 219 | REFCOUNT_STOP1 = 0; |
| 221 | } | 220 | } |
| 222 | } | 221 | } |
| 223 | } | 222 | } |
| @@ -226,18 +225,25 @@ impl Executor { | |||
| 226 | }); | 225 | }); |
| 227 | } | 226 | } |
| 228 | 227 | ||
| 228 | const fn get_scb() -> SCB { | ||
| 229 | unsafe { mem::transmute(()) } | ||
| 230 | } | ||
| 231 | |||
| 229 | fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { | 232 | fn stop_mode(_cs: CriticalSection) -> Option<StopMode> { |
| 230 | if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 && crate::rcc::REFCOUNT_STOP1 == 0 } { | 233 | if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } { |
| 234 | trace!("low power: stop 2"); | ||
| 231 | Some(StopMode::Stop2) | 235 | Some(StopMode::Stop2) |
| 232 | } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { | 236 | } else if unsafe { REFCOUNT_STOP1 == 0 } { |
| 237 | trace!("low power: stop 1"); | ||
| 233 | Some(StopMode::Stop1) | 238 | Some(StopMode::Stop1) |
| 234 | } else { | 239 | } else { |
| 240 | trace!("low power: not ready to stop"); | ||
| 235 | None | 241 | None |
| 236 | } | 242 | } |
| 237 | } | 243 | } |
| 238 | 244 | ||
| 239 | #[allow(unused_variables)] | 245 | #[allow(unused_variables)] |
| 240 | fn configure_stop(&mut self, stop_mode: StopMode) { | 246 | fn configure_stop(&self, stop_mode: StopMode) { |
| 241 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))] | 247 | #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))] |
| 242 | crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); | 248 | crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); |
| 243 | #[cfg(stm32h5)] | 249 | #[cfg(stm32h5)] |
| @@ -248,8 +254,8 @@ impl Executor { | |||
| 248 | }); | 254 | }); |
| 249 | } | 255 | } |
| 250 | 256 | ||
| 251 | fn configure_pwr(&mut self) { | 257 | fn configure_pwr(&self) { |
| 252 | self.scb.clear_sleepdeep(); | 258 | Self::get_scb().clear_sleepdeep(); |
| 253 | // Clear any previous stop flags | 259 | // Clear any previous stop flags |
| 254 | #[cfg(stm32wlex)] | 260 | #[cfg(stm32wlex)] |
| 255 | crate::pac::PWR.extscr().modify(|w| { | 261 | crate::pac::PWR.extscr().modify(|w| { |
| @@ -258,27 +264,18 @@ impl Executor { | |||
| 258 | 264 | ||
| 259 | compiler_fence(Ordering::SeqCst); | 265 | compiler_fence(Ordering::SeqCst); |
| 260 | 266 | ||
| 261 | let stop_mode = critical_section::with(|cs| Self::stop_mode(cs)); | 267 | critical_section::with(|cs| { |
| 262 | 268 | let stop_mode = Self::stop_mode(cs)?; | |
| 263 | if stop_mode.is_none() { | 269 | let _ = get_driver().pause_time(cs).ok()?; |
| 264 | trace!("low power: not ready to stop"); | ||
| 265 | return; | ||
| 266 | } | ||
| 267 | |||
| 268 | if get_driver().pause_time().is_err() { | ||
| 269 | trace!("low power: failed to pause time"); | ||
| 270 | return; | ||
| 271 | } | ||
| 272 | 270 | ||
| 273 | let stop_mode = stop_mode.unwrap(); | 271 | Some(stop_mode) |
| 274 | match stop_mode { | 272 | }) |
| 275 | StopMode::Stop1 => trace!("low power: stop 1"), | 273 | .map(|stop_mode| { |
| 276 | StopMode::Stop2 => trace!("low power: stop 2"), | 274 | self.configure_stop(stop_mode); |
| 277 | } | ||
| 278 | self.configure_stop(stop_mode); | ||
| 279 | 275 | ||
| 280 | #[cfg(not(feature = "low-power-debug-with-sleep"))] | 276 | #[cfg(not(feature = "low-power-debug-with-sleep"))] |
| 281 | self.scb.set_sleepdeep(); | 277 | Self::get_scb().set_sleepdeep(); |
| 278 | }); | ||
| 282 | } | 279 | } |
| 283 | 280 | ||
| 284 | /// Run the executor. | 281 | /// Run the executor. |
| @@ -300,12 +297,11 @@ impl Executor { | |||
| 300 | /// | 297 | /// |
| 301 | /// This function never returns. | 298 | /// This function never returns. |
| 302 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | 299 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { |
| 303 | let executor = unsafe { EXECUTOR.as_mut().unwrap() }; | 300 | init(self.inner.spawner()); |
| 304 | init(executor.inner.spawner()); | ||
| 305 | 301 | ||
| 306 | loop { | 302 | loop { |
| 307 | unsafe { | 303 | unsafe { |
| 308 | executor.inner.poll(); | 304 | self.inner.poll(); |
| 309 | self.configure_pwr(); | 305 | self.configure_pwr(); |
| 310 | asm!("wfe"); | 306 | asm!("wfe"); |
| 311 | #[cfg(stm32wlex)] | 307 | #[cfg(stm32wlex)] |
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 584957c6d..2e1cbd702 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs | |||
| @@ -1,6 +1,3 @@ | |||
| 1 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 2 | use core::mem::MaybeUninit; | ||
| 3 | |||
| 4 | #[cfg(any(stm32l0, stm32l1))] | 1 | #[cfg(any(stm32l0, stm32l1))] |
| 5 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | 2 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 6 | use crate::pac::rcc::regs::Cfgr; | 3 | use crate::pac::rcc::regs::Cfgr; |
| @@ -14,42 +11,6 @@ use crate::time::Hertz; | |||
| 14 | /// HSI speed | 11 | /// HSI speed |
| 15 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 12 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| 16 | 13 | ||
| 17 | /// Saved RCC Config | ||
| 18 | /// | ||
| 19 | /// Used when exiting STOP2 to re-enable clocks to their last configured state | ||
| 20 | /// for chips that need it. | ||
| 21 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 22 | static mut RESUME_RCC_CONFIG: MaybeUninit<Config> = MaybeUninit::uninit(); | ||
| 23 | |||
| 24 | /// Set the rcc config to be restored when exiting STOP2 | ||
| 25 | /// | ||
| 26 | /// Safety: Sets a mutable global. | ||
| 27 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 28 | pub(crate) unsafe fn set_resume_config(config: Config) { | ||
| 29 | trace!("rcc set_resume_config()"); | ||
| 30 | RESUME_RCC_CONFIG = MaybeUninit::new(config); | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Get the rcc config to be restored when exiting STOP2 | ||
| 34 | /// | ||
| 35 | /// Safety: Reads a mutable global. | ||
| 36 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 37 | pub(crate) unsafe fn get_resume_config() -> Config { | ||
| 38 | *(*core::ptr::addr_of_mut!(RESUME_RCC_CONFIG)).assume_init_ref() | ||
| 39 | } | ||
| 40 | |||
| 41 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 42 | /// Safety: should only be called from low power executable just after resuming from STOP2 | ||
| 43 | pub(crate) unsafe fn apply_resume_config() { | ||
| 44 | trace!("rcc apply_resume_config()"); | ||
| 45 | |||
| 46 | while RCC.cfgr().read().sws() != Sysclk::MSI {} | ||
| 47 | |||
| 48 | let config = get_resume_config(); | ||
| 49 | |||
| 50 | init(config); | ||
| 51 | } | ||
| 52 | |||
| 53 | #[derive(Clone, Copy, Eq, PartialEq)] | 14 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 54 | pub enum HseMode { | 15 | pub enum HseMode { |
| 55 | /// crystal/ceramic oscillator (HSEBYP=0) | 16 | /// crystal/ceramic oscillator (HSEBYP=0) |
| @@ -193,10 +154,6 @@ fn msi_enable(range: MSIRange) { | |||
| 193 | } | 154 | } |
| 194 | 155 | ||
| 195 | pub(crate) unsafe fn init(config: Config) { | 156 | pub(crate) unsafe fn init(config: Config) { |
| 196 | // save the rcc config because if we enter stop 2 we need to re-apply it on wakeup | ||
| 197 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 198 | set_resume_config(config); | ||
| 199 | |||
| 200 | // Switch to MSI to prevent problems with PLL configuration. | 157 | // Switch to MSI to prevent problems with PLL configuration. |
| 201 | if !RCC.cr().read().msion() { | 158 | if !RCC.cr().read().msion() { |
| 202 | // Turn on MSI and configure it to 4MHz. | 159 | // Turn on MSI and configure it to 4MHz. |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 592890777..66ee06e17 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -49,6 +49,9 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0; | |||
| 49 | /// May be read without a critical section | 49 | /// May be read without a critical section |
| 50 | pub(crate) static mut REFCOUNT_STOP2: u32 = 0; | 50 | pub(crate) static mut REFCOUNT_STOP2: u32 = 0; |
| 51 | 51 | ||
| 52 | #[cfg(feature = "low-power")] | ||
| 53 | pub(crate) static mut RCC_CONFIG: Option<Config> = None; | ||
| 54 | |||
| 52 | #[cfg(backup_sram)] | 55 | #[cfg(backup_sram)] |
| 53 | pub(crate) static mut BKSRAM_RETAINED: bool = false; | 56 | pub(crate) static mut BKSRAM_RETAINED: bool = false; |
| 54 | 57 | ||
| @@ -408,8 +411,39 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) { | |||
| 408 | 411 | ||
| 409 | #[cfg(feature = "low-power")] | 412 | #[cfg(feature = "low-power")] |
| 410 | { | 413 | { |
| 414 | RCC_CONFIG = Some(config); | ||
| 411 | REFCOUNT_STOP2 = 0; | 415 | REFCOUNT_STOP2 = 0; |
| 412 | REFCOUNT_STOP1 = 0; | 416 | REFCOUNT_STOP1 = 0; |
| 413 | } | 417 | } |
| 414 | } | 418 | } |
| 415 | } | 419 | } |
| 420 | |||
| 421 | /// Calculate intermediate prescaler number used to calculate peripheral prescalers | ||
| 422 | /// | ||
| 423 | /// This function is intended to calculate a number indicating a minimum division | ||
| 424 | /// necessary to result in a frequency lower than the provided `freq_max`. | ||
| 425 | /// | ||
| 426 | /// The returned value indicates the `val + 1` divider is necessary to result in | ||
| 427 | /// the output frequency that is below the maximum provided. | ||
| 428 | /// | ||
| 429 | /// For example: | ||
| 430 | /// 0 = divider of 1 => no division necessary as the input frequency is below max | ||
| 431 | /// 1 = divider of 2 => division by 2 necessary | ||
| 432 | /// ... | ||
| 433 | /// | ||
| 434 | /// The provided max frequency is inclusive. So if `freq_in == freq_max` the result | ||
| 435 | /// will be 0, indicating that no division is necessary. To accomplish that we subtract | ||
| 436 | /// 1 from the input frequency so that the integer rounding plays in our favor. | ||
| 437 | /// | ||
| 438 | /// For example: | ||
| 439 | /// Let the input frequency be 110 and the max frequency be 55. | ||
| 440 | /// If we naiively do `110/55 = 2` the renult will indicate that we need a divider by 3 | ||
| 441 | /// which in reality will be rounded up to 4 as usually a 3 division is not available. | ||
| 442 | /// In either case the resulting frequency will be either 36 or 27 which is lower than | ||
| 443 | /// what we would want. The result should be 1. | ||
| 444 | /// If we do the following instead `109/55 = 1` indicating that we need a divide by 2 | ||
| 445 | /// which will result in the correct 55. | ||
| 446 | #[allow(unused)] | ||
| 447 | pub(crate) fn raw_prescaler(freq_in: u32, freq_max: u32) -> u32 { | ||
| 448 | freq_in.saturating_sub(1) / freq_max | ||
| 449 | } | ||
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index e5bf30927..f049d6b12 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs | |||
| @@ -3,6 +3,7 @@ use embassy_time::{Duration, TICK_HZ}; | |||
| 3 | 3 | ||
| 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; | 4 | use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; |
| 5 | use crate::interrupt::typelevel::Interrupt; | 5 | use crate::interrupt::typelevel::Interrupt; |
| 6 | use crate::pac::rtc::vals::Wucksel; | ||
| 6 | use crate::peripherals::RTC; | 7 | use crate::peripherals::RTC; |
| 7 | use crate::rtc::{RtcTimeProvider, SealedInstance}; | 8 | use crate::rtc::{RtcTimeProvider, SealedInstance}; |
| 8 | 9 | ||
| @@ -58,60 +59,16 @@ impl core::ops::Sub for RtcInstant { | |||
| 58 | } | 59 | } |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | #[repr(u8)] | 62 | fn wucksel_compute_min(val: u32) -> (Wucksel, u32) { |
| 62 | #[derive(Clone, Copy, Debug)] | 63 | *[ |
| 63 | pub(crate) enum WakeupPrescaler { | 64 | (Wucksel::DIV2, 2), |
| 64 | Div2 = 2, | 65 | (Wucksel::DIV4, 4), |
| 65 | Div4 = 4, | 66 | (Wucksel::DIV8, 8), |
| 66 | Div8 = 8, | 67 | (Wucksel::DIV16, 16), |
| 67 | Div16 = 16, | 68 | ] |
| 68 | } | 69 | .iter() |
| 69 | 70 | .find(|(_, psc)| *psc as u32 > val) | |
| 70 | #[cfg(any( | 71 | .unwrap_or(&(Wucksel::DIV16, 16)) |
| 71 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex | ||
| 72 | ))] | ||
| 73 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | ||
| 74 | fn from(val: WakeupPrescaler) -> Self { | ||
| 75 | use crate::pac::rtc::vals::Wucksel; | ||
| 76 | |||
| 77 | match val { | ||
| 78 | WakeupPrescaler::Div2 => Wucksel::DIV2, | ||
| 79 | WakeupPrescaler::Div4 => Wucksel::DIV4, | ||
| 80 | WakeupPrescaler::Div8 => Wucksel::DIV8, | ||
| 81 | WakeupPrescaler::Div16 => Wucksel::DIV16, | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | #[cfg(any( | ||
| 87 | stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex | ||
| 88 | ))] | ||
| 89 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | ||
| 90 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | ||
| 91 | use crate::pac::rtc::vals::Wucksel; | ||
| 92 | |||
| 93 | match val { | ||
| 94 | Wucksel::DIV2 => WakeupPrescaler::Div2, | ||
| 95 | Wucksel::DIV4 => WakeupPrescaler::Div4, | ||
| 96 | Wucksel::DIV8 => WakeupPrescaler::Div8, | ||
| 97 | Wucksel::DIV16 => WakeupPrescaler::Div16, | ||
| 98 | _ => unreachable!(), | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | impl WakeupPrescaler { | ||
| 104 | pub fn compute_min(val: u32) -> Self { | ||
| 105 | *[ | ||
| 106 | WakeupPrescaler::Div2, | ||
| 107 | WakeupPrescaler::Div4, | ||
| 108 | WakeupPrescaler::Div8, | ||
| 109 | WakeupPrescaler::Div16, | ||
| 110 | ] | ||
| 111 | .iter() | ||
| 112 | .find(|psc| **psc as u32 > val) | ||
| 113 | .unwrap_or(&WakeupPrescaler::Div16) | ||
| 114 | } | ||
| 115 | } | 72 | } |
| 116 | 73 | ||
| 117 | impl Rtc { | 74 | impl Rtc { |
| @@ -138,7 +95,7 @@ impl Rtc { | |||
| 138 | let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); | 95 | let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); |
| 139 | let rtc_hz = Self::frequency().0 as u64; | 96 | let rtc_hz = Self::frequency().0 as u64; |
| 140 | let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; | 97 | let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; |
| 141 | let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); | 98 | let (wucksel, prescaler) = wucksel_compute_min((rtc_ticks / u16::MAX as u64) as u32); |
| 142 | 99 | ||
| 143 | // adjust the rtc ticks to the prescaler and subtract one rtc tick | 100 | // adjust the rtc ticks to the prescaler and subtract one rtc tick |
| 144 | let rtc_ticks = rtc_ticks / prescaler as u64; | 101 | let rtc_ticks = rtc_ticks / prescaler as u64; |
| @@ -159,7 +116,7 @@ impl Rtc { | |||
| 159 | while !regs.icsr().read().wutwf() {} | 116 | while !regs.icsr().read().wutwf() {} |
| 160 | } | 117 | } |
| 161 | 118 | ||
| 162 | regs.cr().modify(|w| w.set_wucksel(prescaler.into())); | 119 | regs.cr().modify(|w| w.set_wucksel(wucksel)); |
| 163 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); | 120 | regs.wutr().write(|w| w.set_wut(rtc_ticks)); |
| 164 | regs.cr().modify(|w| w.set_wute(true)); | 121 | regs.cr().modify(|w| w.set_wute(true)); |
| 165 | regs.cr().modify(|w| w.set_wutie(true)); | 122 | regs.cr().modify(|w| w.set_wutie(true)); |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 116b3c7ed..e88bd7ab2 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -379,13 +379,16 @@ trait SealedInstance { | |||
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | #[cfg(feature = "low-power")] | 381 | #[cfg(feature = "low-power")] |
| 382 | pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig) { | 382 | pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig, min_stop_pause: embassy_time::Duration) { |
| 383 | use crate::time_driver::get_driver; | ||
| 384 | |||
| 383 | #[cfg(feature = "_allow-disable-rtc")] | 385 | #[cfg(feature = "_allow-disable-rtc")] |
| 384 | if config._disable_rtc { | 386 | if config._disable_rtc { |
| 385 | return; | 387 | return; |
| 386 | } | 388 | } |
| 387 | 389 | ||
| 388 | crate::time_driver::get_driver().set_rtc(cs, Rtc::new_inner(config)); | 390 | get_driver().set_rtc(cs, Rtc::new_inner(config)); |
| 391 | get_driver().set_min_stop_pause(cs, min_stop_pause); | ||
| 389 | 392 | ||
| 390 | trace!("low power: stop with rtc configured"); | 393 | trace!("low power: stop with rtc configured"); |
| 391 | } | 394 | } |
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 726d1729a..ce4bc43c3 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs | |||
| @@ -391,7 +391,7 @@ pub struct Config { | |||
| 391 | pub frame_sync_polarity: FrameSyncPolarity, | 391 | pub frame_sync_polarity: FrameSyncPolarity, |
| 392 | pub frame_sync_active_level_length: word::U7, | 392 | pub frame_sync_active_level_length: word::U7, |
| 393 | pub frame_sync_definition: FrameSyncDefinition, | 393 | pub frame_sync_definition: FrameSyncDefinition, |
| 394 | pub frame_length: u8, | 394 | pub frame_length: u16, |
| 395 | pub clock_strobe: ClockStrobe, | 395 | pub clock_strobe: ClockStrobe, |
| 396 | pub output_drive: OutputDrive, | 396 | pub output_drive: OutputDrive, |
| 397 | pub master_clock_divider: Option<MasterClockDivider>, | 397 | pub master_clock_divider: Option<MasterClockDivider>, |
| @@ -696,7 +696,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { | |||
| 696 | w.set_fspol(config.frame_sync_polarity.fspol()); | 696 | w.set_fspol(config.frame_sync_polarity.fspol()); |
| 697 | w.set_fsdef(config.frame_sync_definition.fsdef()); | 697 | w.set_fsdef(config.frame_sync_definition.fsdef()); |
| 698 | w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); | 698 | w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); |
| 699 | w.set_frl(config.frame_length - 1); | 699 | w.set_frl((config.frame_length - 1).try_into().unwrap()); |
| 700 | }); | 700 | }); |
| 701 | 701 | ||
| 702 | ch.slotr().modify(|w| { | 702 | ch.slotr().modify(|w| { |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 7db51d72e..0b75aef92 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -196,6 +196,11 @@ fn calc_now(period: u32, counter: u16) -> u64 { | |||
| 196 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | 196 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | #[cfg(feature = "low-power")] | ||
| 200 | fn calc_period_counter(ticks: u64) -> (u32, u16) { | ||
| 201 | (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16) | ||
| 202 | } | ||
| 203 | |||
| 199 | struct AlarmState { | 204 | struct AlarmState { |
| 200 | timestamp: Cell<u64>, | 205 | timestamp: Cell<u64>, |
| 201 | } | 206 | } |
| @@ -240,7 +245,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | |||
| 240 | impl RtcDriver { | 245 | impl RtcDriver { |
| 241 | /// initialize the timer, but don't start it. Used for chips like stm32wle5 | 246 | /// initialize the timer, but don't start it. Used for chips like stm32wle5 |
| 242 | /// for low power where the timer config is lost in STOP2. | 247 | /// for low power where the timer config is lost in STOP2. |
| 243 | fn init_timer(&'static self, cs: critical_section::CriticalSection) { | 248 | pub(crate) fn init_timer(&'static self, cs: critical_section::CriticalSection) { |
| 244 | let r = regs_gp16(); | 249 | let r = regs_gp16(); |
| 245 | 250 | ||
| 246 | rcc::enable_and_reset_with_cs::<T>(cs); | 251 | rcc::enable_and_reset_with_cs::<T>(cs); |
| @@ -358,34 +363,10 @@ impl RtcDriver { | |||
| 358 | #[cfg(feature = "low-power")] | 363 | #[cfg(feature = "low-power")] |
| 359 | /// Add the given offset to the current time | 364 | /// Add the given offset to the current time |
| 360 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { | 365 | fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { |
| 361 | let offset = offset.as_ticks(); | 366 | let (period, counter) = calc_period_counter(self.now() + offset.as_ticks()); |
| 362 | let cnt = regs_gp16().cnt().read().cnt() as u32; | ||
| 363 | let period = self.period.load(Ordering::SeqCst); | ||
| 364 | |||
| 365 | // Correct the race, if it exists | ||
| 366 | let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 { | ||
| 367 | period + 1 | ||
| 368 | } else { | ||
| 369 | period | ||
| 370 | }; | ||
| 371 | |||
| 372 | // Normalize to the full overflow | ||
| 373 | let period = (period / 2) * 2; | ||
| 374 | |||
| 375 | // Add the offset | ||
| 376 | let period = period + 2 * (offset / u16::MAX as u64) as u32; | ||
| 377 | let cnt = cnt + (offset % u16::MAX as u64) as u32; | ||
| 378 | |||
| 379 | let (cnt, period) = if cnt > u16::MAX as u32 { | ||
| 380 | (cnt - u16::MAX as u32, period + 2) | ||
| 381 | } else { | ||
| 382 | (cnt, period) | ||
| 383 | }; | ||
| 384 | |||
| 385 | let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; | ||
| 386 | 367 | ||
| 387 | self.period.store(period, Ordering::SeqCst); | 368 | self.period.store(period, Ordering::SeqCst); |
| 388 | regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); | 369 | regs_gp16().cnt().write(|w| w.set_cnt(counter)); |
| 389 | 370 | ||
| 390 | // Now, recompute alarm | 371 | // Now, recompute alarm |
| 391 | let alarm = self.alarm.borrow(cs); | 372 | let alarm = self.alarm.borrow(cs); |
| @@ -399,13 +380,15 @@ impl RtcDriver { | |||
| 399 | #[cfg(feature = "low-power")] | 380 | #[cfg(feature = "low-power")] |
| 400 | /// Stop the wakeup alarm, if enabled, and add the appropriate offset | 381 | /// Stop the wakeup alarm, if enabled, and add the appropriate offset |
| 401 | fn stop_wakeup_alarm(&self, cs: CriticalSection) { | 382 | fn stop_wakeup_alarm(&self, cs: CriticalSection) { |
| 402 | if let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs) { | 383 | if !regs_gp16().cr1().read().cen() |
| 384 | && let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs) | ||
| 385 | { | ||
| 403 | self.add_time(offset, cs); | 386 | self.add_time(offset, cs); |
| 404 | } | 387 | } |
| 405 | } | 388 | } |
| 406 | 389 | ||
| 407 | /* | 390 | /* |
| 408 | Low-power public functions: all create or require a critical section | 391 | Low-power public functions: all require a critical section |
| 409 | */ | 392 | */ |
| 410 | #[cfg(feature = "low-power")] | 393 | #[cfg(feature = "low-power")] |
| 411 | pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) { | 394 | pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) { |
| @@ -422,49 +405,36 @@ impl RtcDriver { | |||
| 422 | 405 | ||
| 423 | #[cfg(feature = "low-power")] | 406 | #[cfg(feature = "low-power")] |
| 424 | /// Pause the timer if ready; return err if not | 407 | /// Pause the timer if ready; return err if not |
| 425 | pub(crate) fn pause_time(&self) -> Result<(), ()> { | 408 | pub(crate) fn pause_time(&self, cs: CriticalSection) -> Result<(), ()> { |
| 426 | critical_section::with(|cs| { | 409 | self.stop_wakeup_alarm(cs); |
| 427 | /* | 410 | |
| 428 | If the wakeup timer is currently running, then we need to stop it and | 411 | let time_until_next_alarm = self.time_until_next_alarm(cs); |
| 429 | add the elapsed time to the current time, as this will impact the result | 412 | if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() { |
| 430 | of `time_until_next_alarm`. | 413 | trace!( |
| 431 | */ | 414 | "time_until_next_alarm < self.min_stop_pause ({})", |
| 432 | self.stop_wakeup_alarm(cs); | 415 | time_until_next_alarm |
| 433 | 416 | ); | |
| 434 | let time_until_next_alarm = self.time_until_next_alarm(cs); | 417 | Err(()) |
| 435 | if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() { | 418 | } else { |
| 436 | trace!( | 419 | self.rtc |
| 437 | "time_until_next_alarm < self.min_stop_pause ({})", | 420 | .borrow(cs) |
| 438 | time_until_next_alarm | 421 | .borrow_mut() |
| 439 | ); | 422 | .as_mut() |
| 440 | Err(()) | 423 | .unwrap() |
| 441 | } else { | 424 | .start_wakeup_alarm(time_until_next_alarm, cs); |
| 442 | self.rtc | 425 | |
| 443 | .borrow(cs) | 426 | regs_gp16().cr1().modify(|w| w.set_cen(false)); |
| 444 | .borrow_mut() | 427 | // save the count for the timer as its lost in STOP2 for stm32wlex |
| 445 | .as_mut() | 428 | #[cfg(stm32wlex)] |
| 446 | .unwrap() | 429 | self.saved_count |
| 447 | .start_wakeup_alarm(time_until_next_alarm, cs); | 430 | .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst); |
| 448 | 431 | Ok(()) | |
| 449 | regs_gp16().cr1().modify(|w| w.set_cen(false)); | 432 | } |
| 450 | // save the count for the timer as its lost in STOP2 for stm32wlex | ||
| 451 | #[cfg(stm32wlex)] | ||
| 452 | self.saved_count | ||
| 453 | .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst); | ||
| 454 | Ok(()) | ||
| 455 | } | ||
| 456 | }) | ||
| 457 | } | 433 | } |
| 458 | 434 | ||
| 459 | #[cfg(feature = "low-power")] | 435 | #[cfg(feature = "low-power")] |
| 460 | /// Resume the timer with the given offset | 436 | /// Resume the timer with the given offset |
| 461 | pub(crate) fn resume_time(&self, cs: CriticalSection) { | 437 | pub(crate) fn resume_time(&self, cs: CriticalSection) { |
| 462 | if regs_gp16().cr1().read().cen() { | ||
| 463 | // Time isn't currently stopped | ||
| 464 | |||
| 465 | return; | ||
| 466 | } | ||
| 467 | |||
| 468 | self.stop_wakeup_alarm(cs); | 438 | self.stop_wakeup_alarm(cs); |
| 469 | 439 | ||
| 470 | regs_gp16().cr1().modify(|w| w.set_cen(true)); | 440 | regs_gp16().cr1().modify(|w| w.set_cen(true)); |
| @@ -546,8 +516,3 @@ pub(crate) const fn get_driver() -> &'static RtcDriver { | |||
| 546 | pub(crate) fn init(cs: CriticalSection) { | 516 | pub(crate) fn init(cs: CriticalSection) { |
| 547 | DRIVER.init(cs) | 517 | DRIVER.init(cs) |
| 548 | } | 518 | } |
| 549 | |||
| 550 | #[cfg(all(feature = "low-power", stm32wlex))] | ||
| 551 | pub(crate) fn init_timer(cs: CriticalSection) { | ||
| 552 | DRIVER.init_timer(cs) | ||
| 553 | } | ||
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 9a56a41fb..6d4c70dff 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -77,8 +77,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 77 | 77 | ||
| 78 | this.inner.set_counting_mode(counting_mode); | 78 | this.inner.set_counting_mode(counting_mode); |
| 79 | this.set_frequency(freq); | 79 | this.set_frequency(freq); |
| 80 | this.inner.start(); | ||
| 81 | |||
| 82 | this.inner.enable_outputs(); | 80 | this.inner.enable_outputs(); |
| 83 | 81 | ||
| 84 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 82 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| @@ -89,6 +87,10 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 89 | }); | 87 | }); |
| 90 | this.inner.set_autoreload_preload(true); | 88 | this.inner.set_autoreload_preload(true); |
| 91 | 89 | ||
| 90 | // Generate update event so pre-load registers are written to the shadow registers | ||
| 91 | this.inner.generate_update_event(); | ||
| 92 | this.inner.start(); | ||
| 93 | |||
| 92 | this | 94 | this |
| 93 | } | 95 | } |
| 94 | 96 | ||
| @@ -160,8 +162,8 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 160 | 162 | ||
| 161 | /// Set PWM frequency. | 163 | /// Set PWM frequency. |
| 162 | /// | 164 | /// |
| 163 | /// Note: when you call this, the max duty value changes, so you will have to | 165 | /// Note: that the frequency will not be applied in the timer until an update event |
| 164 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | 166 | /// occurs. |
| 165 | pub fn set_frequency(&mut self, freq: Hertz) { | 167 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 166 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 168 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 167 | 2u8 | 169 | 2u8 |
| @@ -218,60 +220,57 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { | |||
| 218 | /// | 220 | /// |
| 219 | /// Note: | 221 | /// Note: |
| 220 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 222 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. |
| 223 | #[inline(always)] | ||
| 221 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | 224 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { |
| 222 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 225 | self.inner.waveform_up(dma, channel, duty).await |
| 223 | let req = dma.request(); | 226 | } |
| 224 | |||
| 225 | let original_duty_state = self.inner.get_compare_value(channel); | ||
| 226 | let original_enable_state = self.inner.get_channel_enable_state(channel); | ||
| 227 | let original_update_dma_state = self.inner.get_update_dma_state(); | ||
| 228 | |||
| 229 | if !original_update_dma_state { | ||
| 230 | self.inner.enable_update_dma(true); | ||
| 231 | } | ||
| 232 | |||
| 233 | if !original_enable_state { | ||
| 234 | self.inner.enable_channel(channel, true); | ||
| 235 | } | ||
| 236 | |||
| 237 | unsafe { | ||
| 238 | #[cfg(not(any(bdma, gpdma)))] | ||
| 239 | use crate::dma::{Burst, FifoThreshold}; | ||
| 240 | use crate::dma::{Transfer, TransferOptions}; | ||
| 241 | |||
| 242 | let dma_transfer_option = TransferOptions { | ||
| 243 | #[cfg(not(any(bdma, gpdma)))] | ||
| 244 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 245 | #[cfg(not(any(bdma, gpdma)))] | ||
| 246 | mburst: Burst::Incr8, | ||
| 247 | ..Default::default() | ||
| 248 | }; | ||
| 249 | |||
| 250 | Transfer::new_write( | ||
| 251 | dma, | ||
| 252 | req, | ||
| 253 | duty, | ||
| 254 | self.inner.regs_gp16().ccr(channel.index()).as_ptr() as *mut u16, | ||
| 255 | dma_transfer_option, | ||
| 256 | ) | ||
| 257 | .await | ||
| 258 | }; | ||
| 259 | |||
| 260 | // restore output compare state | ||
| 261 | if !original_enable_state { | ||
| 262 | self.inner.enable_channel(channel, false); | ||
| 263 | } | ||
| 264 | 227 | ||
| 265 | self.inner.set_compare_value(channel, original_duty_state); | 228 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. |
| 229 | /// | ||
| 230 | /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers | ||
| 231 | /// in sequence on each update event (UEV). The data is written via the DMAR register using the | ||
| 232 | /// DMA base address (DBA) and burst length (DBL) configured in the DCR register. | ||
| 233 | /// | ||
| 234 | /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row | ||
| 235 | /// represents a single update event and each column corresponds to a specific timer channel (starting | ||
| 236 | /// from `starting_channel` up to and including `ending_channel`). | ||
| 237 | /// | ||
| 238 | /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: | ||
| 239 | /// | ||
| 240 | /// ```rust,ignore | ||
| 241 | /// let dma_buf: [u16; 16] = [ | ||
| 242 | /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 | ||
| 243 | /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 | ||
| 244 | /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 | ||
| 245 | /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 | ||
| 246 | /// ]; | ||
| 247 | /// ``` | ||
| 248 | /// | ||
| 249 | /// Each group of `N` values (where `N` is number of channels) is transferred on one update event, | ||
| 250 | /// updating the duty cycles of all selected channels simultaneously. | ||
| 251 | /// | ||
| 252 | /// Note: | ||
| 253 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. | ||
| 254 | /// Also be aware that embassy timers use one of timers internally. It is possible to | ||
| 255 | /// switch this timer by using `time-driver-timX` feature. | ||
| 256 | /// | ||
| 257 | #[inline(always)] | ||
| 258 | pub async fn waveform_up_multi_channel( | ||
| 259 | &mut self, | ||
| 260 | dma: Peri<'_, impl super::UpDma<T>>, | ||
| 261 | starting_channel: Channel, | ||
| 262 | ending_channel: Channel, | ||
| 263 | duty: &[u16], | ||
| 264 | ) { | ||
| 265 | self.inner | ||
| 266 | .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) | ||
| 267 | .await; | ||
| 268 | } | ||
| 266 | 269 | ||
| 267 | // Since DMA is closed before timer update event trigger DMA is turn off, | 270 | /// Generate a sequence of PWM waveform |
| 268 | // this can almost always trigger a DMA FIFO error. | 271 | #[inline(always)] |
| 269 | // | 272 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { |
| 270 | // optional TODO: | 273 | self.inner.waveform(dma, duty).await; |
| 271 | // clean FEIF after disable UDE | ||
| 272 | if !original_update_dma_state { | ||
| 273 | self.inner.enable_update_dma(false); | ||
| 274 | } | ||
| 275 | } | 274 | } |
| 276 | } | 275 | } |
| 277 | 276 | ||
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 2a4ec2db0..9cf0f8c34 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs | |||
| @@ -60,6 +60,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { | |||
| 60 | this.inner.set_counting_mode(counting_mode); | 60 | this.inner.set_counting_mode(counting_mode); |
| 61 | this.inner.set_tick_freq(freq); | 61 | this.inner.set_tick_freq(freq); |
| 62 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | 62 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 63 | this.inner.generate_update_event(); | ||
| 63 | this.inner.start(); | 64 | this.inner.start(); |
| 64 | 65 | ||
| 65 | // enable NVIC interrupt | 66 | // enable NVIC interrupt |
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 0122fe4f7..f0105ece8 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -14,8 +14,8 @@ pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as Slav | |||
| 14 | 14 | ||
| 15 | use super::*; | 15 | use super::*; |
| 16 | use crate::pac::timer::vals; | 16 | use crate::pac::timer::vals; |
| 17 | use crate::rcc; | ||
| 18 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 18 | use crate::{dma, rcc}; | ||
| 19 | 19 | ||
| 20 | /// Input capture mode. | 20 | /// Input capture mode. |
| 21 | #[derive(Clone, Copy)] | 21 | #[derive(Clone, Copy)] |
| @@ -272,6 +272,17 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 272 | self.regs_core().cr1().modify(|r| r.set_cen(true)); | 272 | self.regs_core().cr1().modify(|r| r.set_cen(true)); |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | /// Generate timer update event from software. | ||
| 276 | /// | ||
| 277 | /// Set URS to avoid generating interrupt or DMA request. This update event is only | ||
| 278 | /// used to load value from pre-load registers. If called when the timer is running, | ||
| 279 | /// it may disrupt the output waveform. | ||
| 280 | pub fn generate_update_event(&self) { | ||
| 281 | self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 282 | self.regs_core().egr().write(|r| r.set_ug(true)); | ||
| 283 | self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 284 | } | ||
| 285 | |||
| 275 | /// Stop the timer. | 286 | /// Stop the timer. |
| 276 | pub fn stop(&self) { | 287 | pub fn stop(&self) { |
| 277 | self.regs_core().cr1().modify(|r| r.set_cen(false)); | 288 | self.regs_core().cr1().modify(|r| r.set_cen(false)); |
| @@ -322,10 +333,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 322 | let regs = self.regs_core(); | 333 | let regs = self.regs_core(); |
| 323 | regs.psc().write_value(psc); | 334 | regs.psc().write_value(psc); |
| 324 | regs.arr().write(|r| r.set_arr(arr)); | 335 | regs.arr().write(|r| r.set_arr(arr)); |
| 325 | |||
| 326 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 327 | regs.egr().write(|r| r.set_ug(true)); | ||
| 328 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 329 | } | 336 | } |
| 330 | #[cfg(not(stm32l0))] | 337 | #[cfg(not(stm32l0))] |
| 331 | TimerBits::Bits32 => { | 338 | TimerBits::Bits32 => { |
| @@ -335,10 +342,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> { | |||
| 335 | let regs = self.regs_gp32_unchecked(); | 342 | let regs = self.regs_gp32_unchecked(); |
| 336 | regs.psc().write_value(psc); | 343 | regs.psc().write_value(psc); |
| 337 | regs.arr().write_value(arr); | 344 | regs.arr().write_value(arr); |
| 338 | |||
| 339 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); | ||
| 340 | regs.egr().write(|r| r.set_ug(true)); | ||
| 341 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); | ||
| 342 | } | 345 | } |
| 343 | } | 346 | } |
| 344 | } | 347 | } |
| @@ -656,6 +659,219 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { | |||
| 656 | } | 659 | } |
| 657 | } | 660 | } |
| 658 | 661 | ||
| 662 | /// Generate a sequence of PWM waveform | ||
| 663 | /// | ||
| 664 | /// Note: | ||
| 665 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | ||
| 666 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | ||
| 667 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | ||
| 668 | let req = dma.request(); | ||
| 669 | |||
| 670 | let original_update_dma_state = self.get_update_dma_state(); | ||
| 671 | |||
| 672 | if !original_update_dma_state { | ||
| 673 | self.enable_update_dma(true); | ||
| 674 | } | ||
| 675 | |||
| 676 | self.waveform_helper(dma, req, channel, duty).await; | ||
| 677 | |||
| 678 | // Since DMA is closed before timer update event trigger DMA is turn off, | ||
| 679 | // this can almost always trigger a DMA FIFO error. | ||
| 680 | // | ||
| 681 | // optional TODO: | ||
| 682 | // clean FEIF after disable UDE | ||
| 683 | if !original_update_dma_state { | ||
| 684 | self.enable_update_dma(false); | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. | ||
| 689 | /// | ||
| 690 | /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers | ||
| 691 | /// in sequence on each update event (UEV). The data is written via the DMAR register using the | ||
| 692 | /// DMA base address (DBA) and burst length (DBL) configured in the DCR register. | ||
| 693 | /// | ||
| 694 | /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row | ||
| 695 | /// represents a single update event and each column corresponds to a specific timer channel (starting | ||
| 696 | /// from `starting_channel` up to and including `ending_channel`). | ||
| 697 | /// | ||
| 698 | /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: | ||
| 699 | /// | ||
| 700 | /// ```rust,ignore | ||
| 701 | /// let dma_buf: [u16; 16] = [ | ||
| 702 | /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 | ||
| 703 | /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 | ||
| 704 | /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 | ||
| 705 | /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 | ||
| 706 | /// ]; | ||
| 707 | /// ``` | ||
| 708 | /// | ||
| 709 | /// Each group of `N` values (where `N` is number of channels) is transferred on one update event, | ||
| 710 | /// updating the duty cycles of all selected channels simultaneously. | ||
| 711 | /// | ||
| 712 | /// Note: | ||
| 713 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. | ||
| 714 | /// Also be aware that embassy timers use one of timers internally. It is possible to | ||
| 715 | /// switch this timer by using `time-driver-timX` feature. | ||
| 716 | /// | ||
| 717 | pub async fn waveform_up_multi_channel( | ||
| 718 | &mut self, | ||
| 719 | dma: Peri<'_, impl super::UpDma<T>>, | ||
| 720 | starting_channel: Channel, | ||
| 721 | ending_channel: Channel, | ||
| 722 | duty: &[u16], | ||
| 723 | ) { | ||
| 724 | let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; | ||
| 725 | let start_ch_index = starting_channel.index(); | ||
| 726 | let end_ch_index = ending_channel.index(); | ||
| 727 | |||
| 728 | assert!(start_ch_index <= end_ch_index); | ||
| 729 | |||
| 730 | let ccrx_addr = self.regs_gp16().ccr(start_ch_index).as_ptr() as u32; | ||
| 731 | self.regs_gp16() | ||
| 732 | .dcr() | ||
| 733 | .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8)); | ||
| 734 | self.regs_gp16() | ||
| 735 | .dcr() | ||
| 736 | .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8)); | ||
| 737 | |||
| 738 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | ||
| 739 | let req = dma.request(); | ||
| 740 | |||
| 741 | let original_update_dma_state = self.get_update_dma_state(); | ||
| 742 | if !original_update_dma_state { | ||
| 743 | self.enable_update_dma(true); | ||
| 744 | } | ||
| 745 | |||
| 746 | unsafe { | ||
| 747 | #[cfg(not(any(bdma, gpdma)))] | ||
| 748 | use crate::dma::{Burst, FifoThreshold}; | ||
| 749 | use crate::dma::{Transfer, TransferOptions}; | ||
| 750 | |||
| 751 | let dma_transfer_option = TransferOptions { | ||
| 752 | #[cfg(not(any(bdma, gpdma)))] | ||
| 753 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 754 | #[cfg(not(any(bdma, gpdma)))] | ||
| 755 | mburst: Burst::Incr4, | ||
| 756 | ..Default::default() | ||
| 757 | }; | ||
| 758 | |||
| 759 | Transfer::new_write( | ||
| 760 | dma, | ||
| 761 | req, | ||
| 762 | duty, | ||
| 763 | self.regs_gp16().dmar().as_ptr() as *mut u16, | ||
| 764 | dma_transfer_option, | ||
| 765 | ) | ||
| 766 | .await | ||
| 767 | }; | ||
| 768 | |||
| 769 | if !original_update_dma_state { | ||
| 770 | self.enable_update_dma(false); | ||
| 771 | } | ||
| 772 | } | ||
| 773 | |||
| 774 | /// Generate a sequence of PWM waveform | ||
| 775 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { | ||
| 776 | use crate::pac::timer::vals::Ccds; | ||
| 777 | |||
| 778 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | ||
| 779 | let req = dma.request(); | ||
| 780 | |||
| 781 | let cc_channel = C::CHANNEL; | ||
| 782 | |||
| 783 | let original_cc_dma_on_update = self.get_cc_dma_selection() == Ccds::ON_UPDATE; | ||
| 784 | let original_cc_dma_enabled = self.get_cc_dma_enable_state(cc_channel); | ||
| 785 | |||
| 786 | // redirect CC DMA request onto Update Event | ||
| 787 | if !original_cc_dma_on_update { | ||
| 788 | self.set_cc_dma_selection(Ccds::ON_UPDATE) | ||
| 789 | } | ||
| 790 | |||
| 791 | if !original_cc_dma_enabled { | ||
| 792 | self.set_cc_dma_enable_state(cc_channel, true); | ||
| 793 | } | ||
| 794 | |||
| 795 | self.waveform_helper(dma, req, cc_channel, duty).await; | ||
| 796 | |||
| 797 | // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, | ||
| 798 | // this can almost always trigger a DMA FIFO error. | ||
| 799 | // | ||
| 800 | // optional TODO: | ||
| 801 | // clean FEIF after disable UDE | ||
| 802 | if !original_cc_dma_enabled { | ||
| 803 | self.set_cc_dma_enable_state(cc_channel, false); | ||
| 804 | } | ||
| 805 | |||
| 806 | if !original_cc_dma_on_update { | ||
| 807 | self.set_cc_dma_selection(Ccds::ON_COMPARE) | ||
| 808 | } | ||
| 809 | } | ||
| 810 | |||
| 811 | async fn waveform_helper( | ||
| 812 | &mut self, | ||
| 813 | dma: Peri<'_, impl dma::Channel>, | ||
| 814 | req: dma::Request, | ||
| 815 | channel: Channel, | ||
| 816 | duty: &[u16], | ||
| 817 | ) { | ||
| 818 | let original_duty_state = self.get_compare_value(channel); | ||
| 819 | let original_enable_state = self.get_channel_enable_state(channel); | ||
| 820 | |||
| 821 | if !original_enable_state { | ||
| 822 | self.enable_channel(channel, true); | ||
| 823 | } | ||
| 824 | |||
| 825 | unsafe { | ||
| 826 | #[cfg(not(any(bdma, gpdma)))] | ||
| 827 | use crate::dma::{Burst, FifoThreshold}; | ||
| 828 | use crate::dma::{Transfer, TransferOptions}; | ||
| 829 | |||
| 830 | let dma_transfer_option = TransferOptions { | ||
| 831 | #[cfg(not(any(bdma, gpdma)))] | ||
| 832 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 833 | #[cfg(not(any(bdma, gpdma)))] | ||
| 834 | mburst: Burst::Incr8, | ||
| 835 | ..Default::default() | ||
| 836 | }; | ||
| 837 | |||
| 838 | match self.bits() { | ||
| 839 | TimerBits::Bits16 => { | ||
| 840 | Transfer::new_write( | ||
| 841 | dma, | ||
| 842 | req, | ||
| 843 | duty, | ||
| 844 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, | ||
| 845 | dma_transfer_option, | ||
| 846 | ) | ||
| 847 | .await | ||
| 848 | } | ||
| 849 | #[cfg(not(any(stm32l0)))] | ||
| 850 | TimerBits::Bits32 => { | ||
| 851 | #[cfg(not(any(bdma, gpdma)))] | ||
| 852 | panic!("unsupported timer bits"); | ||
| 853 | |||
| 854 | #[cfg(any(bdma, gpdma))] | ||
| 855 | Transfer::new_write( | ||
| 856 | dma, | ||
| 857 | req, | ||
| 858 | duty, | ||
| 859 | self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, | ||
| 860 | dma_transfer_option, | ||
| 861 | ) | ||
| 862 | .await | ||
| 863 | } | ||
| 864 | }; | ||
| 865 | }; | ||
| 866 | |||
| 867 | // restore output compare state | ||
| 868 | if !original_enable_state { | ||
| 869 | self.enable_channel(channel, false); | ||
| 870 | } | ||
| 871 | |||
| 872 | self.set_compare_value(channel, original_duty_state); | ||
| 873 | } | ||
| 874 | |||
| 659 | /// Get capture value for a channel. | 875 | /// Get capture value for a channel. |
| 660 | pub fn get_capture_value(&self, channel: Channel) -> u32 { | 876 | pub fn get_capture_value(&self, channel: Channel) -> u32 { |
| 661 | self.get_compare_value(channel) | 877 | self.get_compare_value(channel) |
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index da8a79b09..057ab011a 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs | |||
| @@ -47,6 +47,7 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { | |||
| 47 | inner.set_counting_mode(CountingMode::EdgeAlignedUp); | 47 | inner.set_counting_mode(CountingMode::EdgeAlignedUp); |
| 48 | inner.set_tick_freq(freq); | 48 | inner.set_tick_freq(freq); |
| 49 | inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | 49 | inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 50 | inner.generate_update_event(); | ||
| 50 | inner.start(); | 51 | inner.start(); |
| 51 | 52 | ||
| 52 | // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 | 53 | // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 36303aeb4..6c9ef17e0 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -4,7 +4,7 @@ use core::marker::PhantomData; | |||
| 4 | use core::mem::ManuallyDrop; | 4 | use core::mem::ManuallyDrop; |
| 5 | 5 | ||
| 6 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; | 6 | use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; |
| 7 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; | 7 | use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; |
| 8 | use crate::Peri; | 8 | use crate::Peri; |
| 9 | #[cfg(gpio_v2)] | 9 | #[cfg(gpio_v2)] |
| 10 | use crate::gpio::Pull; | 10 | use crate::gpio::Pull; |
| @@ -198,7 +198,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 198 | this.inner.set_counting_mode(counting_mode); | 198 | this.inner.set_counting_mode(counting_mode); |
| 199 | this.set_frequency(freq); | 199 | this.set_frequency(freq); |
| 200 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details | 200 | this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details |
| 201 | this.inner.start(); | ||
| 202 | 201 | ||
| 203 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] | 202 | [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] |
| 204 | .iter() | 203 | .iter() |
| @@ -207,6 +206,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 207 | 206 | ||
| 208 | this.inner.set_output_compare_preload(channel, true); | 207 | this.inner.set_output_compare_preload(channel, true); |
| 209 | }); | 208 | }); |
| 209 | this.inner.set_autoreload_preload(true); | ||
| 210 | |||
| 211 | // Generate update event so pre-load registers are written to the shadow registers | ||
| 212 | this.inner.generate_update_event(); | ||
| 213 | this.inner.start(); | ||
| 210 | 214 | ||
| 211 | this | 215 | this |
| 212 | } | 216 | } |
| @@ -285,8 +289,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 285 | 289 | ||
| 286 | /// Set PWM frequency. | 290 | /// Set PWM frequency. |
| 287 | /// | 291 | /// |
| 288 | /// Note: when you call this, the max duty value changes, so you will have to | 292 | /// Note: that the frequency will not be applied in the timer until an update event |
| 289 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | 293 | /// occurs. |
| 290 | pub fn set_frequency(&mut self, freq: Hertz) { | 294 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 291 | // TODO: prevent ARR = u16::MAX? | 295 | // TODO: prevent ARR = u16::MAX? |
| 292 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 296 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| @@ -309,80 +313,12 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 309 | /// Generate a sequence of PWM waveform | 313 | /// Generate a sequence of PWM waveform |
| 310 | /// | 314 | /// |
| 311 | /// Note: | 315 | /// Note: |
| 312 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 316 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. |
| 317 | /// Also be aware that embassy timers use one of timers internally. It is possible to | ||
| 318 | /// switch this timer by using `time-driver-timX` feature. | ||
| 319 | #[inline(always)] | ||
| 313 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { | 320 | pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { |
| 314 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | 321 | self.inner.waveform_up(dma, channel, duty).await; |
| 315 | let req = dma.request(); | ||
| 316 | |||
| 317 | let original_duty_state = self.channel(channel).current_duty_cycle(); | ||
| 318 | let original_enable_state = self.channel(channel).is_enabled(); | ||
| 319 | let original_update_dma_state = self.inner.get_update_dma_state(); | ||
| 320 | |||
| 321 | if !original_update_dma_state { | ||
| 322 | self.inner.enable_update_dma(true); | ||
| 323 | } | ||
| 324 | |||
| 325 | if !original_enable_state { | ||
| 326 | self.channel(channel).enable(); | ||
| 327 | } | ||
| 328 | |||
| 329 | unsafe { | ||
| 330 | #[cfg(not(any(bdma, gpdma)))] | ||
| 331 | use crate::dma::{Burst, FifoThreshold}; | ||
| 332 | use crate::dma::{Transfer, TransferOptions}; | ||
| 333 | |||
| 334 | let dma_transfer_option = TransferOptions { | ||
| 335 | #[cfg(not(any(bdma, gpdma)))] | ||
| 336 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 337 | #[cfg(not(any(bdma, gpdma)))] | ||
| 338 | mburst: Burst::Incr8, | ||
| 339 | ..Default::default() | ||
| 340 | }; | ||
| 341 | |||
| 342 | match self.inner.bits() { | ||
| 343 | TimerBits::Bits16 => { | ||
| 344 | Transfer::new_write( | ||
| 345 | dma, | ||
| 346 | req, | ||
| 347 | duty, | ||
| 348 | self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, | ||
| 349 | dma_transfer_option, | ||
| 350 | ) | ||
| 351 | .await | ||
| 352 | } | ||
| 353 | #[cfg(not(any(stm32l0)))] | ||
| 354 | TimerBits::Bits32 => { | ||
| 355 | #[cfg(not(any(bdma, gpdma)))] | ||
| 356 | panic!("unsupported timer bits"); | ||
| 357 | |||
| 358 | #[cfg(any(bdma, gpdma))] | ||
| 359 | Transfer::new_write( | ||
| 360 | dma, | ||
| 361 | req, | ||
| 362 | duty, | ||
| 363 | self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, | ||
| 364 | dma_transfer_option, | ||
| 365 | ) | ||
| 366 | .await | ||
| 367 | } | ||
| 368 | }; | ||
| 369 | }; | ||
| 370 | |||
| 371 | // restore output compare state | ||
| 372 | if !original_enable_state { | ||
| 373 | self.channel(channel).disable(); | ||
| 374 | } | ||
| 375 | |||
| 376 | self.channel(channel).set_duty_cycle(original_duty_state); | ||
| 377 | |||
| 378 | // Since DMA is closed before timer update event trigger DMA is turn off, | ||
| 379 | // this can almost always trigger a DMA FIFO error. | ||
| 380 | // | ||
| 381 | // optional TODO: | ||
| 382 | // clean FEIF after disable UDE | ||
| 383 | if !original_update_dma_state { | ||
| 384 | self.inner.enable_update_dma(false); | ||
| 385 | } | ||
| 386 | } | 322 | } |
| 387 | 323 | ||
| 388 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. | 324 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. |
| @@ -397,18 +333,24 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 397 | /// | 333 | /// |
| 398 | /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: | 334 | /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: |
| 399 | /// | 335 | /// |
| 336 | /// ```rust,ignore | ||
| 400 | /// let dma_buf: [u16; 16] = [ | 337 | /// let dma_buf: [u16; 16] = [ |
| 401 | /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 | 338 | /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 |
| 402 | /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 | 339 | /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 |
| 403 | /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 | 340 | /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 |
| 404 | /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 | 341 | /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 |
| 405 | /// ]; | 342 | /// ]; |
| 343 | /// ``` | ||
| 406 | /// | 344 | /// |
| 407 | /// Each group of N values (where N = number of channels) is transferred on one update event, | 345 | /// Each group of `N` values (where `N` is number of channels) is transferred on one update event, |
| 408 | /// updating the duty cycles of all selected channels simultaneously. | 346 | /// updating the duty cycles of all selected channels simultaneously. |
| 409 | /// | 347 | /// |
| 410 | /// Note: | 348 | /// Note: |
| 411 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | 349 | /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. |
| 350 | /// Also be aware that embassy timers use one of timers internally. It is possible to | ||
| 351 | /// switch this timer by using `time-driver-timX` feature. | ||
| 352 | /// | ||
| 353 | #[inline(always)] | ||
| 412 | pub async fn waveform_up_multi_channel( | 354 | pub async fn waveform_up_multi_channel( |
| 413 | &mut self, | 355 | &mut self, |
| 414 | dma: Peri<'_, impl super::UpDma<T>>, | 356 | dma: Peri<'_, impl super::UpDma<T>>, |
| @@ -416,148 +358,15 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 416 | ending_channel: Channel, | 358 | ending_channel: Channel, |
| 417 | duty: &[u16], | 359 | duty: &[u16], |
| 418 | ) { | 360 | ) { |
| 419 | let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32; | ||
| 420 | let start_ch_index = starting_channel.index(); | ||
| 421 | let end_ch_index = ending_channel.index(); | ||
| 422 | |||
| 423 | assert!(start_ch_index <= end_ch_index); | ||
| 424 | |||
| 425 | let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32; | ||
| 426 | self.inner | 361 | self.inner |
| 427 | .regs_gp16() | 362 | .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) |
| 428 | .dcr() | 363 | .await; |
| 429 | .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8)); | ||
| 430 | self.inner | ||
| 431 | .regs_gp16() | ||
| 432 | .dcr() | ||
| 433 | .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8)); | ||
| 434 | |||
| 435 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | ||
| 436 | let req = dma.request(); | ||
| 437 | |||
| 438 | let original_update_dma_state = self.inner.get_update_dma_state(); | ||
| 439 | if !original_update_dma_state { | ||
| 440 | self.inner.enable_update_dma(true); | ||
| 441 | } | ||
| 442 | |||
| 443 | unsafe { | ||
| 444 | #[cfg(not(any(bdma, gpdma)))] | ||
| 445 | use crate::dma::{Burst, FifoThreshold}; | ||
| 446 | use crate::dma::{Transfer, TransferOptions}; | ||
| 447 | |||
| 448 | let dma_transfer_option = TransferOptions { | ||
| 449 | #[cfg(not(any(bdma, gpdma)))] | ||
| 450 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 451 | #[cfg(not(any(bdma, gpdma)))] | ||
| 452 | mburst: Burst::Incr4, | ||
| 453 | ..Default::default() | ||
| 454 | }; | ||
| 455 | |||
| 456 | Transfer::new_write( | ||
| 457 | dma, | ||
| 458 | req, | ||
| 459 | duty, | ||
| 460 | self.inner.regs_gp16().dmar().as_ptr() as *mut u16, | ||
| 461 | dma_transfer_option, | ||
| 462 | ) | ||
| 463 | .await | ||
| 464 | }; | ||
| 465 | |||
| 466 | if !original_update_dma_state { | ||
| 467 | self.inner.enable_update_dma(false); | ||
| 468 | } | ||
| 469 | } | 364 | } |
| 470 | } | ||
| 471 | 365 | ||
| 472 | impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | ||
| 473 | /// Generate a sequence of PWM waveform | 366 | /// Generate a sequence of PWM waveform |
| 367 | #[inline(always)] | ||
| 474 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { | 368 | pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { |
| 475 | use crate::pac::timer::vals::Ccds; | 369 | self.inner.waveform(dma, duty).await; |
| 476 | |||
| 477 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | ||
| 478 | let req = dma.request(); | ||
| 479 | |||
| 480 | let cc_channel = C::CHANNEL; | ||
| 481 | |||
| 482 | let original_duty_state = self.channel(cc_channel).current_duty_cycle(); | ||
| 483 | let original_enable_state = self.channel(cc_channel).is_enabled(); | ||
| 484 | let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE; | ||
| 485 | let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); | ||
| 486 | |||
| 487 | // redirect CC DMA request onto Update Event | ||
| 488 | if !original_cc_dma_on_update { | ||
| 489 | self.inner.set_cc_dma_selection(Ccds::ON_UPDATE) | ||
| 490 | } | ||
| 491 | |||
| 492 | if !original_cc_dma_enabled { | ||
| 493 | self.inner.set_cc_dma_enable_state(cc_channel, true); | ||
| 494 | } | ||
| 495 | |||
| 496 | if !original_enable_state { | ||
| 497 | self.channel(cc_channel).enable(); | ||
| 498 | } | ||
| 499 | |||
| 500 | unsafe { | ||
| 501 | #[cfg(not(any(bdma, gpdma)))] | ||
| 502 | use crate::dma::{Burst, FifoThreshold}; | ||
| 503 | use crate::dma::{Transfer, TransferOptions}; | ||
| 504 | |||
| 505 | let dma_transfer_option = TransferOptions { | ||
| 506 | #[cfg(not(any(bdma, gpdma)))] | ||
| 507 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 508 | #[cfg(not(any(bdma, gpdma)))] | ||
| 509 | mburst: Burst::Incr8, | ||
| 510 | ..Default::default() | ||
| 511 | }; | ||
| 512 | |||
| 513 | match self.inner.bits() { | ||
| 514 | TimerBits::Bits16 => { | ||
| 515 | Transfer::new_write( | ||
| 516 | dma, | ||
| 517 | req, | ||
| 518 | duty, | ||
| 519 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, | ||
| 520 | dma_transfer_option, | ||
| 521 | ) | ||
| 522 | .await | ||
| 523 | } | ||
| 524 | #[cfg(not(any(stm32l0)))] | ||
| 525 | TimerBits::Bits32 => { | ||
| 526 | #[cfg(not(any(bdma, gpdma)))] | ||
| 527 | panic!("unsupported timer bits"); | ||
| 528 | |||
| 529 | #[cfg(any(bdma, gpdma))] | ||
| 530 | Transfer::new_write( | ||
| 531 | dma, | ||
| 532 | req, | ||
| 533 | duty, | ||
| 534 | self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, | ||
| 535 | dma_transfer_option, | ||
| 536 | ) | ||
| 537 | .await | ||
| 538 | } | ||
| 539 | }; | ||
| 540 | }; | ||
| 541 | |||
| 542 | // restore output compare state | ||
| 543 | if !original_enable_state { | ||
| 544 | self.channel(cc_channel).disable(); | ||
| 545 | } | ||
| 546 | |||
| 547 | self.channel(cc_channel).set_duty_cycle(original_duty_state); | ||
| 548 | |||
| 549 | // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, | ||
| 550 | // this can almost always trigger a DMA FIFO error. | ||
| 551 | // | ||
| 552 | // optional TODO: | ||
| 553 | // clean FEIF after disable UDE | ||
| 554 | if !original_cc_dma_enabled { | ||
| 555 | self.inner.set_cc_dma_enable_state(cc_channel, false); | ||
| 556 | } | ||
| 557 | |||
| 558 | if !original_cc_dma_on_update { | ||
| 559 | self.inner.set_cc_dma_selection(Ccds::ON_COMPARE) | ||
| 560 | } | ||
| 561 | } | 370 | } |
| 562 | } | 371 | } |
| 563 | 372 | ||
diff --git a/examples/lpc55s69/src/bin/pwm.rs b/examples/lpc55s69/src/bin/pwm.rs index 93b898b9d..8a9894b94 100644 --- a/examples/lpc55s69/src/bin/pwm.rs +++ b/examples/lpc55s69/src/bin/pwm.rs | |||
| @@ -10,7 +10,7 @@ use {defmt_rtt as _, panic_halt as _}; | |||
| 10 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 11 | async fn main(_spawner: Spawner) { |
| 12 | let p = embassy_nxp::init(Default::default()); | 12 | let p = embassy_nxp::init(Default::default()); |
| 13 | let pwm = Pwm::new_output(p.PWM_OUTPUT1, p.PIO0_18, Config::new(1_000_000_000, 2_000_000_000)); | 13 | let pwm = Pwm::new_output(p.SCT0_OUT1, p.PIO0_18, Config::new(1_000_000_000, 2_000_000_000)); |
| 14 | loop { | 14 | loop { |
| 15 | info!("Counter: {}", pwm.counter()); | 15 | info!("Counter: {}", pwm.counter()); |
| 16 | Timer::after_millis(50).await; | 16 | Timer::after_millis(50).await; |
diff --git a/examples/lpc55s69/src/bin/usart_async.rs b/examples/lpc55s69/src/bin/usart_async.rs index b06abd477..a9815b920 100644 --- a/examples/lpc55s69/src/bin/usart_async.rs +++ b/examples/lpc55s69/src/bin/usart_async.rs | |||
| @@ -38,8 +38,8 @@ async fn main(spawner: Spawner) { | |||
| 38 | p.PIO0_27, | 38 | p.PIO0_27, |
| 39 | p.PIO1_24, | 39 | p.PIO1_24, |
| 40 | Irqs, | 40 | Irqs, |
| 41 | p.DMA_CH11, | 41 | p.DMA0_CH11, |
| 42 | p.DMA_CH10, | 42 | p.DMA0_CH10, |
| 43 | Config::default(), | 43 | Config::default(), |
| 44 | ); | 44 | ); |
| 45 | let led = Output::new(p.PIO1_6, Level::Low); | 45 | let led = Output::new(p.PIO1_6, Level::Low); |
diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs index c7ddc1d8d..e358779b2 100644 --- a/examples/nrf52840/src/bin/gpiote_channel.rs +++ b/examples/nrf52840/src/bin/gpiote_channel.rs | |||
| @@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) { | |||
| 12 | let p = embassy_nrf::init(Default::default()); | 12 | let p = embassy_nrf::init(Default::default()); |
| 13 | info!("Starting!"); | 13 | info!("Starting!"); |
| 14 | 14 | ||
| 15 | let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); | 15 | let mut ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); |
| 16 | let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi); | 16 | let mut ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi); |
| 17 | let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle); | 17 | let mut ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle); |
| 18 | let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle); | 18 | let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle); |
| 19 | 19 | ||
| 20 | let button1 = async { | 20 | let button1 = async { |
| 21 | loop { | 21 | loop { |
diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs index a085310ce..41ee732c3 100644 --- a/examples/nrf5340/src/bin/gpiote_channel.rs +++ b/examples/nrf5340/src/bin/gpiote_channel.rs | |||
| @@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) { | |||
| 12 | let p = embassy_nrf::init(Default::default()); | 12 | let p = embassy_nrf::init(Default::default()); |
| 13 | info!("Starting!"); | 13 | info!("Starting!"); |
| 14 | 14 | ||
| 15 | let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo); | 15 | let mut ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo); |
| 16 | let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_24, Pull::Up, InputChannelPolarity::LoToHi); | 16 | let mut ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_24, Pull::Up, InputChannelPolarity::LoToHi); |
| 17 | let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_08, Pull::Up, InputChannelPolarity::Toggle); | 17 | let mut ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_08, Pull::Up, InputChannelPolarity::Toggle); |
| 18 | let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle); | 18 | let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle); |
| 19 | 19 | ||
| 20 | let button1 = async { | 20 | let button1 = async { |
| 21 | loop { | 21 | loop { |
diff --git a/examples/nrf54l15/memory.x b/examples/nrf54l15/memory.x index 1064c8a5c..332200828 100644 --- a/examples/nrf54l15/memory.x +++ b/examples/nrf54l15/memory.x | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | MEMORY | 1 | MEMORY |
| 2 | { | 2 | { |
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1536K | 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 1524K |
| 4 | RAM : ORIGIN = 0x20000000, LENGTH = 256K | 4 | RAM : ORIGIN = 0x20000000, LENGTH = 256K |
| 5 | } | 5 | } |
diff --git a/examples/nrf54l15/src/bin/gpiote_channel.rs b/examples/nrf54l15/src/bin/gpiote_channel.rs index 6333250ba..cac8823f8 100644 --- a/examples/nrf54l15/src/bin/gpiote_channel.rs +++ b/examples/nrf54l15/src/bin/gpiote_channel.rs | |||
| @@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) { | |||
| 12 | let p = embassy_nrf::init(Default::default()); | 12 | let p = embassy_nrf::init(Default::default()); |
| 13 | info!("Starting!"); | 13 | info!("Starting!"); |
| 14 | 14 | ||
| 15 | let ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); | 15 | let mut ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); |
| 16 | let ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); | 16 | let mut ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); |
| 17 | let ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); | 17 | let mut ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); |
| 18 | let ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle); | 18 | let mut ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle); |
| 19 | 19 | ||
| 20 | let button1 = async { | 20 | let button1 = async { |
| 21 | loop { | 21 | loop { |
diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index b618d2b38..ce85f4b9a 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs | |||
| @@ -1,9 +1,8 @@ | |||
| 1 | //! This example uses the RP Pico W board Wifi chip (cyw43). | 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. | 2 | //! Connects to Wifi network and makes a web request to httpbin.org. |
| 3 | 3 | ||
| 4 | #![no_std] | 4 | #![no_std] |
| 5 | #![no_main] | 5 | #![no_main] |
| 6 | #![allow(async_fn_in_trait)] | ||
| 7 | 6 | ||
| 8 | use core::str::from_utf8; | 7 | use core::str::from_utf8; |
| 9 | 8 | ||
| @@ -20,11 +19,14 @@ use embassy_rp::gpio::{Level, Output}; | |||
| 20 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | 19 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; |
| 21 | use embassy_rp::pio::{InterruptHandler, Pio}; | 20 | use embassy_rp::pio::{InterruptHandler, Pio}; |
| 22 | use embassy_time::{Duration, Timer}; | 21 | use embassy_time::{Duration, Timer}; |
| 23 | use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; | 22 | use reqwless::client::HttpClient; |
| 23 | // Uncomment these for TLS requests: | ||
| 24 | // use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; | ||
| 24 | use reqwless::request::Method; | 25 | use reqwless::request::Method; |
| 25 | use serde::Deserialize; | 26 | use serde::Deserialize; |
| 27 | use serde_json_core::from_slice; | ||
| 26 | use static_cell::StaticCell; | 28 | use static_cell::StaticCell; |
| 27 | use {defmt_rtt as _, panic_probe as _, serde_json_core}; | 29 | use {defmt_rtt as _, panic_probe as _}; |
| 28 | 30 | ||
| 29 | bind_interrupts!(struct Irqs { | 31 | bind_interrupts!(struct Irqs { |
| 30 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | 32 | PIO0_IRQ_0 => InterruptHandler<PIO0>; |
| @@ -119,64 +121,90 @@ async fn main(spawner: Spawner) { | |||
| 119 | // And now we can use it! | 121 | // And now we can use it! |
| 120 | 122 | ||
| 121 | loop { | 123 | loop { |
| 122 | let mut rx_buffer = [0; 8192]; | 124 | let mut rx_buffer = [0; 4096]; |
| 123 | let mut tls_read_buffer = [0; 16640]; | 125 | // Uncomment these for TLS requests: |
| 124 | let mut tls_write_buffer = [0; 16640]; | 126 | // let mut tls_read_buffer = [0; 16640]; |
| 127 | // let mut tls_write_buffer = [0; 16640]; | ||
| 125 | 128 | ||
| 126 | let client_state = TcpClientState::<1, 1024, 1024>::new(); | 129 | let client_state = TcpClientState::<1, 4096, 4096>::new(); |
| 127 | let tcp_client = TcpClient::new(stack, &client_state); | 130 | let tcp_client = TcpClient::new(stack, &client_state); |
| 128 | let dns_client = DnsSocket::new(stack); | 131 | let dns_client = DnsSocket::new(stack); |
| 129 | let tls_config = TlsConfig::new(seed, &mut tls_read_buffer, &mut tls_write_buffer, TlsVerify::None); | 132 | // Uncomment these for TLS requests: |
| 133 | // let tls_config = TlsConfig::new(seed, &mut tls_read_buffer, &mut tls_write_buffer, TlsVerify::None); | ||
| 130 | 134 | ||
| 131 | let mut http_client = HttpClient::new_with_tls(&tcp_client, &dns_client, tls_config); | 135 | // Using non-TLS HTTP for this example |
| 132 | let url = "https://worldtimeapi.org/api/timezone/Europe/Berlin"; | 136 | let mut http_client = HttpClient::new(&tcp_client, &dns_client); |
| 133 | // for non-TLS requests, use this instead: | 137 | let url = "http://httpbin.org/json"; |
| 134 | // let mut http_client = HttpClient::new(&tcp_client, &dns_client); | 138 | // For TLS requests, use this instead: |
| 135 | // let url = "http://worldtimeapi.org/api/timezone/Europe/Berlin"; | 139 | // let mut http_client = HttpClient::new_with_tls(&tcp_client, &dns_client, tls_config); |
| 140 | // let url = "https://httpbin.org/json"; | ||
| 136 | 141 | ||
| 137 | info!("connecting to {}", &url); | 142 | info!("connecting to {}", &url); |
| 138 | 143 | ||
| 139 | let mut request = match http_client.request(Method::GET, &url).await { | 144 | let mut request = match http_client.request(Method::GET, url).await { |
| 140 | Ok(req) => req, | 145 | Ok(req) => req, |
| 141 | Err(e) => { | 146 | Err(e) => { |
| 142 | error!("Failed to make HTTP request: {:?}", e); | 147 | error!("Failed to make HTTP request: {:?}", e); |
| 143 | return; // handle the error | 148 | Timer::after(Duration::from_secs(5)).await; |
| 149 | continue; | ||
| 144 | } | 150 | } |
| 145 | }; | 151 | }; |
| 146 | 152 | ||
| 147 | let response = match request.send(&mut rx_buffer).await { | 153 | let response = match request.send(&mut rx_buffer).await { |
| 148 | Ok(resp) => resp, | 154 | Ok(resp) => resp, |
| 149 | Err(_e) => { | 155 | Err(e) => { |
| 150 | error!("Failed to send HTTP request"); | 156 | error!("Failed to send HTTP request: {:?}", e); |
| 151 | return; // handle the error; | 157 | Timer::after(Duration::from_secs(5)).await; |
| 158 | continue; | ||
| 152 | } | 159 | } |
| 153 | }; | 160 | }; |
| 154 | 161 | ||
| 155 | let body = match from_utf8(response.body().read_to_end().await.unwrap()) { | 162 | info!("Response status: {}", response.status.0); |
| 163 | |||
| 164 | let body_bytes = match response.body().read_to_end().await { | ||
| 156 | Ok(b) => b, | 165 | Ok(b) => b, |
| 157 | Err(_e) => { | 166 | Err(_e) => { |
| 158 | error!("Failed to read response body"); | 167 | error!("Failed to read response body"); |
| 159 | return; // handle the error | 168 | Timer::after(Duration::from_secs(5)).await; |
| 169 | continue; | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | |||
| 173 | let body = match from_utf8(body_bytes) { | ||
| 174 | Ok(b) => b, | ||
| 175 | Err(_e) => { | ||
| 176 | error!("Failed to parse response body as UTF-8"); | ||
| 177 | Timer::after(Duration::from_secs(5)).await; | ||
| 178 | continue; | ||
| 160 | } | 179 | } |
| 161 | }; | 180 | }; |
| 162 | info!("Response body: {:?}", &body); | 181 | info!("Response body length: {} bytes", body.len()); |
| 163 | 182 | ||
| 164 | // parse the response body and update the RTC | 183 | // Parse the JSON response from httpbin.org/json |
| 184 | #[derive(Deserialize)] | ||
| 185 | struct SlideShow<'a> { | ||
| 186 | author: &'a str, | ||
| 187 | title: &'a str, | ||
| 188 | } | ||
| 165 | 189 | ||
| 166 | #[derive(Deserialize)] | 190 | #[derive(Deserialize)] |
| 167 | struct ApiResponse<'a> { | 191 | struct HttpBinResponse<'a> { |
| 168 | datetime: &'a str, | 192 | #[serde(borrow)] |
| 169 | // other fields as needed | 193 | slideshow: SlideShow<'a>, |
| 170 | } | 194 | } |
| 171 | 195 | ||
| 172 | let bytes = body.as_bytes(); | 196 | let bytes = body.as_bytes(); |
| 173 | match serde_json_core::de::from_slice::<ApiResponse>(bytes) { | 197 | match from_slice::<HttpBinResponse>(bytes) { |
| 174 | Ok((output, _used)) => { | 198 | Ok((output, _used)) => { |
| 175 | info!("Datetime: {:?}", output.datetime); | 199 | info!("Successfully parsed JSON response!"); |
| 200 | info!("Slideshow title: {:?}", output.slideshow.title); | ||
| 201 | info!("Slideshow author: {:?}", output.slideshow.author); | ||
| 176 | } | 202 | } |
| 177 | Err(_e) => { | 203 | Err(e) => { |
| 178 | error!("Failed to parse response body"); | 204 | error!("Failed to parse JSON response: {}", Debug2Format(&e)); |
| 179 | return; // handle the error | 205 | // Log preview of response for debugging |
| 206 | let preview = if body.len() > 200 { &body[..200] } else { body }; | ||
| 207 | info!("Response preview: {:?}", preview); | ||
| 180 | } | 208 | } |
| 181 | } | 209 | } |
| 182 | 210 | ||
diff --git a/examples/stm32h5/src/bin/adc_dma.rs b/examples/stm32h5/src/bin/adc_dma.rs index fb9fcbc5c..2138257f7 100644 --- a/examples/stm32h5/src/bin/adc_dma.rs +++ b/examples/stm32h5/src/bin/adc_dma.rs | |||
| @@ -6,7 +6,7 @@ use embassy_executor::Spawner; | |||
| 6 | use embassy_stm32::adc::{self, Adc, AdcChannel, RxDma, SampleTime}; | 6 | use embassy_stm32::adc::{self, Adc, AdcChannel, RxDma, SampleTime}; |
| 7 | use embassy_stm32::peripherals::{ADC1, ADC2, GPDMA1_CH0, GPDMA1_CH1, PA0, PA1, PA2, PA3}; | 7 | use embassy_stm32::peripherals::{ADC1, ADC2, GPDMA1_CH0, GPDMA1_CH1, PA0, PA1, PA2, PA3}; |
| 8 | use embassy_stm32::{Config, Peri}; | 8 | use embassy_stm32::{Config, Peri}; |
| 9 | use embassy_time::Instant; | 9 | use embassy_time::{Duration, Instant, Ticker}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | #[embassy_executor::main] | 12 | #[embassy_executor::main] |
| @@ -76,6 +76,9 @@ async fn adc_task<'a, T: adc::Instance>( | |||
| 76 | let mut pin1 = pin1.degrade_adc(); | 76 | let mut pin1 = pin1.degrade_adc(); |
| 77 | let mut pin2 = pin2.degrade_adc(); | 77 | let mut pin2 = pin2.degrade_adc(); |
| 78 | 78 | ||
| 79 | info!("adc init"); | ||
| 80 | |||
| 81 | let mut ticker = Ticker::every(Duration::from_millis(500)); | ||
| 79 | let mut tic = Instant::now(); | 82 | let mut tic = Instant::now(); |
| 80 | let mut buffer = [0u16; 512]; | 83 | let mut buffer = [0u16; 512]; |
| 81 | loop { | 84 | loop { |
| @@ -84,11 +87,13 @@ async fn adc_task<'a, T: adc::Instance>( | |||
| 84 | adc.read( | 87 | adc.read( |
| 85 | dma.reborrow(), | 88 | dma.reborrow(), |
| 86 | [(&mut pin1, SampleTime::CYCLES2_5), (&mut pin2, SampleTime::CYCLES2_5)].into_iter(), | 89 | [(&mut pin1, SampleTime::CYCLES2_5), (&mut pin2, SampleTime::CYCLES2_5)].into_iter(), |
| 87 | &mut buffer, | 90 | &mut buffer[0..2], |
| 88 | ) | 91 | ) |
| 89 | .await; | 92 | .await; |
| 90 | let toc = Instant::now(); | 93 | let toc = Instant::now(); |
| 91 | info!("\n adc1: {} dt = {}", buffer[0..16], (toc - tic).as_micros()); | 94 | info!("\n adc1: {} dt = {}", buffer[0..16], (toc - tic).as_micros()); |
| 92 | tic = toc; | 95 | tic = toc; |
| 96 | |||
| 97 | ticker.next().await; | ||
| 93 | } | 98 | } |
| 94 | } | 99 | } |
diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs index caebc9daf..8d5456b80 100644 --- a/examples/stm32h5/src/bin/stop.rs +++ b/examples/stm32h5/src/bin/stop.rs | |||
| @@ -7,20 +7,12 @@ | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | 9 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; |
| 10 | use embassy_stm32::low_power::Executor; | ||
| 11 | use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; | 10 | use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; |
| 12 | use embassy_stm32::{Config, Peri}; | 11 | use embassy_stm32::{Config, Peri, low_power}; |
| 13 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 14 | ||
| 16 | #[cortex_m_rt::entry] | 15 | #[embassy_executor::main(executor = "low_power::Executor")] |
| 17 | fn main() -> ! { | ||
| 18 | Executor::take().run(|spawner| { | ||
| 19 | spawner.spawn(unwrap!(async_main(spawner))); | ||
| 20 | }) | ||
| 21 | } | ||
| 22 | |||
| 23 | #[embassy_executor::task] | ||
| 24 | async fn async_main(spawner: Spawner) { | 16 | async fn async_main(spawner: Spawner) { |
| 25 | defmt::info!("Program Start"); | 17 | defmt::info!("Program Start"); |
| 26 | 18 | ||
diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index cdbd69b89..5c29602c6 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs | |||
| @@ -167,7 +167,7 @@ fn new_sai_transmitter<'d>( | |||
| 167 | sai_config.slot_count = hal::sai::word::U4(CHANNEL_COUNT as u8); | 167 | sai_config.slot_count = hal::sai::word::U4(CHANNEL_COUNT as u8); |
| 168 | sai_config.slot_enable = 0xFFFF; // All slots | 168 | sai_config.slot_enable = 0xFFFF; // All slots |
| 169 | sai_config.data_size = sai::DataSize::Data32; | 169 | sai_config.data_size = sai::DataSize::Data32; |
| 170 | sai_config.frame_length = (CHANNEL_COUNT * 32) as u8; | 170 | sai_config.frame_length = (CHANNEL_COUNT * 32) as u16; |
| 171 | sai_config.master_clock_divider = None; | 171 | sai_config.master_clock_divider = None; |
| 172 | 172 | ||
| 173 | let (sub_block_tx, _) = hal::sai::split_subblocks(sai); | 173 | let (sub_block_tx, _) = hal::sai::split_subblocks(sai); |
diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index 3d119f90f..fde804fb7 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs | |||
| @@ -4,20 +4,12 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; |
| 7 | use embassy_stm32::low_power::Executor; | ||
| 8 | use embassy_stm32::rcc::LsConfig; | 7 | use embassy_stm32::rcc::LsConfig; |
| 9 | use embassy_stm32::{Config, Peri}; | 8 | use embassy_stm32::{Config, Peri, low_power}; |
| 10 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 11 | ||
| 13 | #[cortex_m_rt::entry] | 12 | #[embassy_executor::main(executor = "low_power::Executor")] |
| 14 | fn main() -> ! { | ||
| 15 | Executor::take().run(|spawner| { | ||
| 16 | spawner.spawn(unwrap!(async_main(spawner))); | ||
| 17 | }) | ||
| 18 | } | ||
| 19 | |||
| 20 | #[embassy_executor::task] | ||
| 21 | async fn async_main(spawner: Spawner) { | 13 | async fn async_main(spawner: Spawner) { |
| 22 | let mut config = Config::default(); | 14 | let mut config = Config::default(); |
| 23 | config.rcc.ls = LsConfig::default_lsi(); | 15 | config.rcc.ls = LsConfig::default_lsi(); |
diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index 5296943a1..5d946b35b 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs | |||
| @@ -1,32 +1,44 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use core::net::Ipv6Addr; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_net::udp::{PacketMetadata, UdpSocket}; | ||
| 9 | use embassy_net::{Ipv6Cidr, StackResources, StaticConfigV6}; | ||
| 6 | use embassy_stm32::bind_interrupts; | 10 | use embassy_stm32::bind_interrupts; |
| 7 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; | 11 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; |
| 12 | use embassy_stm32::peripherals::RNG; | ||
| 8 | use embassy_stm32::rcc::WPAN_DEFAULT; | 13 | use embassy_stm32::rcc::WPAN_DEFAULT; |
| 14 | use embassy_stm32::rng::InterruptHandler as RngInterruptHandler; | ||
| 9 | use embassy_stm32_wpan::TlMbox; | 15 | use embassy_stm32_wpan::TlMbox; |
| 10 | use embassy_stm32_wpan::mac::commands::{ResetRequest, SetRequest, StartRequest}; | 16 | use embassy_stm32_wpan::mac::{Driver, DriverState, Runner}; |
| 11 | use embassy_stm32_wpan::mac::typedefs::{MacChannel, PanId, PibId}; | ||
| 12 | use embassy_stm32_wpan::mac::{self, Runner}; | ||
| 13 | use embassy_stm32_wpan::sub::mm; | 17 | use embassy_stm32_wpan::sub::mm; |
| 18 | use embassy_time::{Duration, Timer}; | ||
| 19 | use heapless::Vec; | ||
| 14 | use static_cell::StaticCell; | 20 | use static_cell::StaticCell; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 21 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 22 | ||
| 17 | bind_interrupts!(struct Irqs{ | 23 | bind_interrupts!(struct Irqs{ |
| 18 | IPCC_C1_RX => ReceiveInterruptHandler; | 24 | IPCC_C1_RX => ReceiveInterruptHandler; |
| 19 | IPCC_C1_TX => TransmitInterruptHandler; | 25 | IPCC_C1_TX => TransmitInterruptHandler; |
| 26 | RNG => RngInterruptHandler<RNG>; | ||
| 20 | }); | 27 | }); |
| 21 | 28 | ||
| 22 | #[embassy_executor::task] | 29 | #[embassy_executor::task] |
| 23 | async fn run_mm_queue(memory_manager: mm::MemoryManager) { | 30 | async fn run_mm_queue(memory_manager: mm::MemoryManager) -> ! { |
| 24 | memory_manager.run_queue().await; | 31 | memory_manager.run_queue().await |
| 32 | } | ||
| 33 | |||
| 34 | #[embassy_executor::task] | ||
| 35 | async fn run_mac(runner: &'static Runner<'static>) -> ! { | ||
| 36 | runner.run().await | ||
| 25 | } | 37 | } |
| 26 | 38 | ||
| 27 | #[embassy_executor::task] | 39 | #[embassy_executor::task] |
| 28 | async fn run_mac(runner: &'static Runner<'static>) { | 40 | async fn run_net(mut runner: embassy_net::Runner<'static, Driver<'static>>) -> ! { |
| 29 | runner.run().await; | 41 | runner.run().await |
| 30 | } | 42 | } |
| 31 | 43 | ||
| 32 | #[embassy_executor::main] | 44 | #[embassy_executor::main] |
| @@ -72,106 +84,69 @@ async fn main(spawner: Spawner) { | |||
| 72 | let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; | 84 | let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; |
| 73 | info!("initialized mac: {}", result); | 85 | info!("initialized mac: {}", result); |
| 74 | 86 | ||
| 75 | info!("resetting"); | 87 | static DRIVER_STATE: StaticCell<DriverState> = StaticCell::new(); |
| 76 | mbox.mac_subsystem | ||
| 77 | .send_command(&ResetRequest { | ||
| 78 | set_default_pib: true, | ||
| 79 | ..Default::default() | ||
| 80 | }) | ||
| 81 | .await | ||
| 82 | .unwrap(); | ||
| 83 | defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); | ||
| 84 | |||
| 85 | info!("setting extended address"); | ||
| 86 | let extended_address: u64 = 0xACDE480000000001; | ||
| 87 | mbox.mac_subsystem | ||
| 88 | .send_command(&SetRequest { | ||
| 89 | pib_attribute_ptr: &extended_address as *const _ as *const u8, | ||
| 90 | pib_attribute: PibId::ExtendedAddress, | ||
| 91 | }) | ||
| 92 | .await | ||
| 93 | .unwrap(); | ||
| 94 | defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); | ||
| 95 | |||
| 96 | info!("setting short address"); | ||
| 97 | let short_address: u16 = 0x1122; | ||
| 98 | mbox.mac_subsystem | ||
| 99 | .send_command(&SetRequest { | ||
| 100 | pib_attribute_ptr: &short_address as *const _ as *const u8, | ||
| 101 | pib_attribute: PibId::ShortAddress, | ||
| 102 | }) | ||
| 103 | .await | ||
| 104 | .unwrap(); | ||
| 105 | defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); | ||
| 106 | |||
| 107 | info!("setting association permit"); | ||
| 108 | let association_permit: bool = true; | ||
| 109 | mbox.mac_subsystem | ||
| 110 | .send_command(&SetRequest { | ||
| 111 | pib_attribute_ptr: &association_permit as *const _ as *const u8, | ||
| 112 | pib_attribute: PibId::AssociationPermit, | ||
| 113 | }) | ||
| 114 | .await | ||
| 115 | .unwrap(); | ||
| 116 | defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); | ||
| 117 | |||
| 118 | info!("setting TX power"); | ||
| 119 | let transmit_power: i8 = 2; | ||
| 120 | mbox.mac_subsystem | ||
| 121 | .send_command(&SetRequest { | ||
| 122 | pib_attribute_ptr: &transmit_power as *const _ as *const u8, | ||
| 123 | pib_attribute: PibId::TransmitPower, | ||
| 124 | }) | ||
| 125 | .await | ||
| 126 | .unwrap(); | ||
| 127 | defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); | ||
| 128 | |||
| 129 | info!("starting FFD device"); | ||
| 130 | mbox.mac_subsystem | ||
| 131 | .send_command(&StartRequest { | ||
| 132 | pan_id: PanId([0x1A, 0xAA]), | ||
| 133 | channel_number: MacChannel::Channel16, | ||
| 134 | beacon_order: 0x0F, | ||
| 135 | superframe_order: 0x0F, | ||
| 136 | pan_coordinator: true, | ||
| 137 | battery_life_extension: false, | ||
| 138 | ..Default::default() | ||
| 139 | }) | ||
| 140 | .await | ||
| 141 | .unwrap(); | ||
| 142 | defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); | ||
| 143 | |||
| 144 | info!("setting RX on when idle"); | ||
| 145 | let rx_on_while_idle: bool = true; | ||
| 146 | mbox.mac_subsystem | ||
| 147 | .send_command(&SetRequest { | ||
| 148 | pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8, | ||
| 149 | pib_attribute: PibId::RxOnWhenIdle, | ||
| 150 | }) | ||
| 151 | .await | ||
| 152 | .unwrap(); | ||
| 153 | defmt::info!("{:#x}", mbox.mac_subsystem.read().await.unwrap()); | ||
| 154 | |||
| 155 | static TX1: StaticCell<[u8; 127]> = StaticCell::new(); | ||
| 156 | static TX2: StaticCell<[u8; 127]> = StaticCell::new(); | ||
| 157 | static TX3: StaticCell<[u8; 127]> = StaticCell::new(); | ||
| 158 | static TX4: StaticCell<[u8; 127]> = StaticCell::new(); | ||
| 159 | static TX5: StaticCell<[u8; 127]> = StaticCell::new(); | ||
| 160 | let tx_queue = [ | ||
| 161 | TX1.init([0u8; 127]), | ||
| 162 | TX2.init([0u8; 127]), | ||
| 163 | TX3.init([0u8; 127]), | ||
| 164 | TX4.init([0u8; 127]), | ||
| 165 | TX5.init([0u8; 127]), | ||
| 166 | ]; | ||
| 167 | |||
| 168 | static RUNNER: StaticCell<Runner> = StaticCell::new(); | 88 | static RUNNER: StaticCell<Runner> = StaticCell::new(); |
| 169 | let runner = RUNNER.init(Runner::new(mbox.mac_subsystem, tx_queue)); | 89 | static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); |
| 90 | |||
| 91 | let driver_state = DRIVER_STATE.init(DriverState::new(mbox.mac_subsystem)); | ||
| 92 | |||
| 93 | let (driver, mac_runner, mut control) = Driver::new( | ||
| 94 | driver_state, | ||
| 95 | 0x1122u16.to_be_bytes().try_into().unwrap(), | ||
| 96 | 0xACDE480000000001u64.to_be_bytes().try_into().unwrap(), | ||
| 97 | ); | ||
| 98 | |||
| 99 | // TODO: rng does not work for some reason | ||
| 100 | // Generate random seed. | ||
| 101 | // let mut rng = Rng::new(p.RNG, Irqs); | ||
| 102 | let seed = [0; 8]; | ||
| 103 | // let _ = rng.async_fill_bytes(&mut seed).await; | ||
| 104 | let seed = u64::from_le_bytes(seed); | ||
| 105 | |||
| 106 | info!("seed generated"); | ||
| 107 | |||
| 108 | // Init network stack | ||
| 109 | let ipv6_addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); | ||
| 110 | |||
| 111 | let config = embassy_net::Config::ipv6_static(StaticConfigV6 { | ||
| 112 | address: Ipv6Cidr::new(ipv6_addr, 104), | ||
| 113 | gateway: None, | ||
| 114 | dns_servers: Vec::new(), | ||
| 115 | }); | ||
| 116 | |||
| 117 | let (stack, eth_runner) = embassy_net::new(driver, config, RESOURCES.init(StackResources::new()), seed); | ||
| 118 | |||
| 119 | // wpan runner | ||
| 120 | spawner.spawn(run_mac(RUNNER.init(mac_runner)).unwrap()); | ||
| 121 | |||
| 122 | // Launch network task | ||
| 123 | spawner.spawn(unwrap!(run_net(eth_runner))); | ||
| 124 | |||
| 125 | info!("Network task initialized"); | ||
| 126 | |||
| 127 | control.init_link([0x1A, 0xAA]).await; | ||
| 128 | |||
| 129 | // Ensure DHCP configuration is up before trying connect | ||
| 130 | stack.wait_config_up().await; | ||
| 131 | |||
| 132 | info!("Network up"); | ||
| 133 | |||
| 134 | // Then we can use it! | ||
| 135 | let mut rx_meta = [PacketMetadata::EMPTY]; | ||
| 136 | let mut rx_buffer = [0; 4096]; | ||
| 137 | let mut tx_meta = [PacketMetadata::EMPTY]; | ||
| 138 | let mut tx_buffer = [0; 4096]; | ||
| 139 | |||
| 140 | let mut socket = UdpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); | ||
| 141 | |||
| 142 | let remote_endpoint = (Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2fb), 8000); | ||
| 143 | |||
| 144 | let send_buf = [0u8; 20]; | ||
| 170 | 145 | ||
| 171 | spawner.spawn(run_mac(runner).unwrap()); | 146 | socket.bind((ipv6_addr, 8000)).unwrap(); |
| 147 | socket.send_to(&send_buf, remote_endpoint).await.unwrap(); | ||
| 172 | 148 | ||
| 173 | let (driver, control) = mac::new(runner).await; | 149 | Timer::after(Duration::from_secs(2)).await; |
| 174 | 150 | ||
| 175 | let _ = driver; | 151 | cortex_m::asm::bkpt(); |
| 176 | let _ = control; | ||
| 177 | } | 152 | } |
diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs index 4e0574d97..ea91fb063 100644 --- a/examples/stm32wle5/src/bin/adc.rs +++ b/examples/stm32wle5/src/bin/adc.rs | |||
| @@ -6,20 +6,12 @@ use defmt::*; | |||
| 6 | use defmt_rtt as _; | 6 | use defmt_rtt as _; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::adc::{Adc, SampleTime}; | 8 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power; |
| 10 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 11 | use panic_probe as _; | 11 | use panic_probe as _; |
| 12 | use static_cell::StaticCell; | 12 | use static_cell::StaticCell; |
| 13 | 13 | ||
| 14 | #[cortex_m_rt::entry] | 14 | #[embassy_executor::main(executor = "low_power::Executor")] |
| 15 | fn main() -> ! { | ||
| 16 | info!("main: Starting!"); | ||
| 17 | Executor::take().run(|spawner| { | ||
| 18 | spawner.spawn(unwrap!(async_main(spawner))); | ||
| 19 | }); | ||
| 20 | } | ||
| 21 | |||
| 22 | #[embassy_executor::task] | ||
| 23 | async fn async_main(_spawner: Spawner) { | 15 | async fn async_main(_spawner: Spawner) { |
| 24 | let mut config = embassy_stm32::Config::default(); | 16 | let mut config = embassy_stm32::Config::default(); |
| 25 | // enable HSI clock | 17 | // enable HSI clock |
diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs index b2745fdaf..9f0c04672 100644 --- a/examples/stm32wle5/src/bin/blinky.rs +++ b/examples/stm32wle5/src/bin/blinky.rs | |||
| @@ -6,20 +6,12 @@ use defmt::*; | |||
| 6 | use defmt_rtt as _; | 6 | use defmt_rtt as _; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::gpio::{Level, Output, Speed}; | 8 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 9 | use embassy_stm32::low_power::Executor; | 9 | use embassy_stm32::low_power; |
| 10 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 11 | use panic_probe as _; | 11 | use panic_probe as _; |
| 12 | use static_cell::StaticCell; | 12 | use static_cell::StaticCell; |
| 13 | 13 | ||
| 14 | #[cortex_m_rt::entry] | 14 | #[embassy_executor::main(executor = "low_power::Executor")] |
| 15 | fn main() -> ! { | ||
| 16 | info!("main: Starting!"); | ||
| 17 | Executor::take().run(|spawner| { | ||
| 18 | spawner.spawn(unwrap!(async_main(spawner))); | ||
| 19 | }); | ||
| 20 | } | ||
| 21 | |||
| 22 | #[embassy_executor::task] | ||
| 23 | async fn async_main(_spawner: Spawner) { | 15 | async fn async_main(_spawner: Spawner) { |
| 24 | let mut config = embassy_stm32::Config::default(); | 16 | let mut config = embassy_stm32::Config::default(); |
| 25 | // enable HSI clock | 17 | // enable HSI clock |
diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs index db1bff0be..878eca7d0 100644 --- a/examples/stm32wle5/src/bin/button_exti.rs +++ b/examples/stm32wle5/src/bin/button_exti.rs | |||
| @@ -7,19 +7,11 @@ use defmt_rtt as _; | |||
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::exti::ExtiInput; | 8 | use embassy_stm32::exti::ExtiInput; |
| 9 | use embassy_stm32::gpio::Pull; | 9 | use embassy_stm32::gpio::Pull; |
| 10 | use embassy_stm32::low_power::Executor; | 10 | use embassy_stm32::low_power; |
| 11 | use panic_probe as _; | 11 | use panic_probe as _; |
| 12 | use static_cell::StaticCell; | 12 | use static_cell::StaticCell; |
| 13 | 13 | ||
| 14 | #[cortex_m_rt::entry] | 14 | #[embassy_executor::main(executor = "low_power::Executor")] |
| 15 | fn main() -> ! { | ||
| 16 | info!("main: Starting!"); | ||
| 17 | Executor::take().run(|spawner| { | ||
| 18 | spawner.spawn(unwrap!(async_main(spawner))); | ||
| 19 | }); | ||
| 20 | } | ||
| 21 | |||
| 22 | #[embassy_executor::task] | ||
| 23 | async fn async_main(_spawner: Spawner) { | 15 | async fn async_main(_spawner: Spawner) { |
| 24 | let mut config = embassy_stm32::Config::default(); | 16 | let mut config = embassy_stm32::Config::default(); |
| 25 | // enable HSI clock | 17 | // enable HSI clock |
diff --git a/examples/stm32wle5/src/bin/i2c.rs b/examples/stm32wle5/src/bin/i2c.rs index c31c673c9..68c17a672 100644 --- a/examples/stm32wle5/src/bin/i2c.rs +++ b/examples/stm32wle5/src/bin/i2c.rs | |||
| @@ -6,9 +6,8 @@ use defmt::*; | |||
| 6 | use defmt_rtt as _; | 6 | use defmt_rtt as _; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::i2c::I2c; | 8 | use embassy_stm32::i2c::I2c; |
| 9 | use embassy_stm32::low_power::Executor; | ||
| 10 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::{bind_interrupts, i2c, peripherals}; | 10 | use embassy_stm32::{bind_interrupts, i2c, low_power, peripherals}; |
| 12 | use embassy_time::{Duration, Timer}; | 11 | use embassy_time::{Duration, Timer}; |
| 13 | use panic_probe as _; | 12 | use panic_probe as _; |
| 14 | use static_cell::StaticCell; | 13 | use static_cell::StaticCell; |
| @@ -18,15 +17,7 @@ bind_interrupts!(struct IrqsI2C{ | |||
| 18 | I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | 17 | I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; |
| 19 | }); | 18 | }); |
| 20 | 19 | ||
| 21 | #[cortex_m_rt::entry] | 20 | #[embassy_executor::main(executor = "low_power::Executor")] |
| 22 | fn main() -> ! { | ||
| 23 | info!("main: Starting!"); | ||
| 24 | Executor::take().run(|spawner| { | ||
| 25 | spawner.spawn(unwrap!(async_main(spawner))); | ||
| 26 | }); | ||
| 27 | } | ||
| 28 | |||
| 29 | #[embassy_executor::task] | ||
| 30 | async fn async_main(_spawner: Spawner) { | 21 | async fn async_main(_spawner: Spawner) { |
| 31 | let mut config = embassy_stm32::Config::default(); | 22 | let mut config = embassy_stm32::Config::default(); |
| 32 | // enable HSI clock | 23 | // enable HSI clock |
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 1fe65d867..83c375bc5 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs | |||
| @@ -7,21 +7,13 @@ mod common; | |||
| 7 | 7 | ||
| 8 | use chrono::NaiveDate; | 8 | use chrono::NaiveDate; |
| 9 | use common::*; | 9 | use common::*; |
| 10 | use cortex_m_rt::entry; | ||
| 11 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| 12 | use embassy_stm32::Config; | 11 | use embassy_stm32::low_power::{StopMode, stop_ready}; |
| 13 | use embassy_stm32::low_power::{Executor, StopMode, stop_ready}; | ||
| 14 | use embassy_stm32::rcc::LsConfig; | 12 | use embassy_stm32::rcc::LsConfig; |
| 15 | use embassy_stm32::rtc::Rtc; | 13 | use embassy_stm32::rtc::Rtc; |
| 14 | use embassy_stm32::{Config, low_power}; | ||
| 16 | use embassy_time::Timer; | 15 | use embassy_time::Timer; |
| 17 | 16 | ||
| 18 | #[entry] | ||
| 19 | fn main() -> ! { | ||
| 20 | Executor::take().run(|spawner| { | ||
| 21 | spawner.spawn(unwrap!(async_main(spawner))); | ||
| 22 | }); | ||
| 23 | } | ||
| 24 | |||
| 25 | #[embassy_executor::task] | 17 | #[embassy_executor::task] |
| 26 | async fn task_1() { | 18 | async fn task_1() { |
| 27 | for _ in 0..9 { | 19 | for _ in 0..9 { |
| @@ -43,7 +35,7 @@ async fn task_2() { | |||
| 43 | cortex_m::asm::bkpt(); | 35 | cortex_m::asm::bkpt(); |
| 44 | } | 36 | } |
| 45 | 37 | ||
| 46 | #[embassy_executor::task] | 38 | #[embassy_executor::main(executor = "low_power::Executor")] |
| 47 | async fn async_main(spawner: Spawner) { | 39 | async fn async_main(spawner: Spawner) { |
| 48 | let _ = config(); | 40 | let _ = config(); |
| 49 | 41 | ||
