diff options
| -rw-r--r-- | embassy-macros/src/chip/nrf.rs | 55 | ||||
| -rw-r--r-- | embassy-macros/src/chip/rp.rs | 14 | ||||
| -rw-r--r-- | embassy-macros/src/chip/stm32.rs | 54 | ||||
| -rw-r--r-- | embassy-macros/src/lib.rs | 38 | ||||
| -rw-r--r-- | embassy-stm32-examples/src/bin/rtc_async.rs | 3 | ||||
| -rw-r--r-- | embassy-stm32-examples/src/bin/serial.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32-examples/src/bin/usb_serial.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/f4/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/f4/rtc.rs (renamed from embassy-stm32/src/rtc.rs) | 0 | ||||
| -rw-r--r-- | embassy-stm32/src/f4/system.rs | 61 | ||||
| -rw-r--r-- | embassy-stm32/src/l0/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/l0/rtc.rs | 371 | ||||
| -rw-r--r-- | embassy-stm32/src/l0/system.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 64 |
15 files changed, 546 insertions, 142 deletions
diff --git a/embassy-macros/src/chip/nrf.rs b/embassy-macros/src/chip/nrf.rs index b7ea8d389..aba4c004f 100644 --- a/embassy-macros/src/chip/nrf.rs +++ b/embassy-macros/src/chip/nrf.rs | |||
| @@ -1,60 +1,15 @@ | |||
| 1 | use crate::path::ModulePrefix; | 1 | use crate::path::ModulePrefix; |
| 2 | use darling::FromMeta; | ||
| 3 | use proc_macro2::TokenStream; | 2 | use proc_macro2::TokenStream; |
| 4 | use quote::{format_ident, quote}; | 3 | use quote::quote; |
| 5 | use syn::spanned::Spanned; | ||
| 6 | 4 | ||
| 7 | #[derive(Debug, FromMeta)] | 5 | pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { |
| 8 | pub enum HfclkSource { | 6 | let embassy_path = embassy_prefix.append("embassy").path(); |
| 9 | Internal, | 7 | let embassy_nrf_path = embassy_prefix.append("embassy_nrf").path(); |
| 10 | ExternalXtal, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl Default for HfclkSource { | ||
| 14 | fn default() -> Self { | ||
| 15 | Self::Internal | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | #[derive(Debug, FromMeta)] | ||
| 20 | pub enum LfclkSource { | ||
| 21 | InternalRC, | ||
| 22 | Synthesized, | ||
| 23 | ExternalXtal, | ||
| 24 | ExternalLowSwing, | ||
| 25 | ExternalFullSwing, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl Default for LfclkSource { | ||
| 29 | fn default() -> Self { | ||
| 30 | Self::InternalRC | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | #[derive(Debug, FromMeta, Default)] | ||
| 35 | pub struct Args { | ||
| 36 | #[darling(default)] | ||
| 37 | pub embassy_prefix: ModulePrefix, | ||
| 38 | #[darling(default)] | ||
| 39 | pub hfclk_source: HfclkSource, | ||
| 40 | #[darling(default)] | ||
| 41 | pub lfclk_source: LfclkSource, | ||
| 42 | } | ||
| 43 | |||
| 44 | pub fn generate(args: &Args) -> TokenStream { | ||
| 45 | let hfclk_source = format_ident!("{}", format!("{:?}", args.hfclk_source)); | ||
| 46 | let lfclk_source = format_ident!("{}", format!("{:?}", args.lfclk_source)); | ||
| 47 | |||
| 48 | let embassy_path = args.embassy_prefix.append("embassy").path(); | ||
| 49 | let embassy_nrf_path = args.embassy_prefix.append("embassy_nrf").path(); | ||
| 50 | 8 | ||
| 51 | quote!( | 9 | quote!( |
| 52 | use #embassy_nrf_path::{interrupt, peripherals, rtc}; | 10 | use #embassy_nrf_path::{interrupt, peripherals, rtc}; |
| 53 | 11 | ||
| 54 | let mut config = #embassy_nrf_path::system::Config::default(); | 12 | unsafe { #embassy_nrf_path::system::configure(#config) }; |
| 55 | config.hfclk_source = #embassy_nrf_path::system::HfclkSource::#hfclk_source; | ||
| 56 | config.lfclk_source = #embassy_nrf_path::system::LfclkSource::#lfclk_source; | ||
| 57 | unsafe { #embassy_nrf_path::system::configure(config) }; | ||
| 58 | 13 | ||
| 59 | let mut rtc = rtc::RTC::new(unsafe { <peripherals::RTC1 as #embassy_path::util::Steal>::steal() }, interrupt::take!(RTC1)); | 14 | let mut rtc = rtc::RTC::new(unsafe { <peripherals::RTC1 as #embassy_path::util::Steal>::steal() }, interrupt::take!(RTC1)); |
| 60 | let rtc = unsafe { make_static(&mut rtc) }; | 15 | let rtc = unsafe { make_static(&mut rtc) }; |
diff --git a/embassy-macros/src/chip/rp.rs b/embassy-macros/src/chip/rp.rs index 6093dc9d3..33863de86 100644 --- a/embassy-macros/src/chip/rp.rs +++ b/embassy-macros/src/chip/rp.rs | |||
| @@ -1,20 +1,12 @@ | |||
| 1 | use crate::path::ModulePrefix; | 1 | use crate::path::ModulePrefix; |
| 2 | use darling::FromMeta; | ||
| 3 | use proc_macro2::TokenStream; | 2 | use proc_macro2::TokenStream; |
| 4 | use quote::quote; | 3 | use quote::quote; |
| 5 | 4 | ||
| 6 | #[derive(Debug, FromMeta, Default)] | 5 | pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { |
| 7 | pub struct Args { | 6 | let embassy_rp_path = embassy_prefix.append("embassy_rp").path(); |
| 8 | #[darling(default)] | ||
| 9 | pub embassy_prefix: ModulePrefix, | ||
| 10 | } | ||
| 11 | |||
| 12 | pub fn generate(args: &Args) -> TokenStream { | ||
| 13 | let embassy_rp_path = args.embassy_prefix.append("embassy_rp").path(); | ||
| 14 | quote!( | 7 | quote!( |
| 15 | use #embassy_rp_path::{interrupt, peripherals}; | 8 | use #embassy_rp_path::{interrupt, peripherals}; |
| 16 | 9 | ||
| 17 | let mut config = #embassy_rp_path::system::Config::default(); | 10 | unsafe { #embassy_rp_path::system::configure(#config) }; |
| 18 | unsafe { #embassy_rp_path::system::configure(config) }; | ||
| 19 | ) | 11 | ) |
| 20 | } | 12 | } |
diff --git a/embassy-macros/src/chip/stm32.rs b/embassy-macros/src/chip/stm32.rs index 486a9aa65..3f299650c 100644 --- a/embassy-macros/src/chip/stm32.rs +++ b/embassy-macros/src/chip/stm32.rs | |||
| @@ -1,57 +1,19 @@ | |||
| 1 | use crate::path::ModulePrefix; | 1 | use crate::path::ModulePrefix; |
| 2 | use darling::FromMeta; | ||
| 3 | use proc_macro2::TokenStream; | 2 | use proc_macro2::TokenStream; |
| 4 | use quote::{format_ident, quote}; | 3 | use quote::quote; |
| 5 | use syn::spanned::Spanned; | ||
| 6 | 4 | ||
| 7 | #[derive(Debug, FromMeta, Default)] | 5 | pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { |
| 8 | pub struct Args { | 6 | let embassy_path = embassy_prefix.append("embassy").path(); |
| 9 | #[darling(default)] | 7 | let embassy_stm32_path = embassy_prefix.append("embassy_stm32").path(); |
| 10 | pub embassy_prefix: ModulePrefix, | ||
| 11 | #[darling(default)] | ||
| 12 | pub use_hse: Option<u32>, | ||
| 13 | #[darling(default)] | ||
| 14 | pub sysclk: Option<u32>, | ||
| 15 | #[darling(default)] | ||
| 16 | pub pclk1: Option<u32>, | ||
| 17 | #[darling(default)] | ||
| 18 | pub require_pll48clk: bool, | ||
| 19 | } | ||
| 20 | |||
| 21 | pub fn generate(args: &Args) -> TokenStream { | ||
| 22 | let embassy_path = args.embassy_prefix.append("embassy").path(); | ||
| 23 | let embassy_stm32_path = args.embassy_prefix.append("embassy_stm32").path(); | ||
| 24 | |||
| 25 | let mut clock_cfg_args = quote! {}; | ||
| 26 | if args.use_hse.is_some() { | ||
| 27 | let mhz = args.use_hse.unwrap(); | ||
| 28 | clock_cfg_args = quote! { #clock_cfg_args.use_hse(#mhz.mhz()) }; | ||
| 29 | } | ||
| 30 | |||
| 31 | if args.sysclk.is_some() { | ||
| 32 | let mhz = args.sysclk.unwrap(); | ||
| 33 | clock_cfg_args = quote! { #clock_cfg_args.sysclk(#mhz.mhz()) }; | ||
| 34 | } | ||
| 35 | |||
| 36 | if args.pclk1.is_some() { | ||
| 37 | let mhz = args.pclk1.unwrap(); | ||
| 38 | clock_cfg_args = quote! { #clock_cfg_args.pclk1(#mhz.mhz()) }; | ||
| 39 | } | ||
| 40 | |||
| 41 | if args.require_pll48clk { | ||
| 42 | clock_cfg_args = quote! { #clock_cfg_args.require_pll48clk() }; | ||
| 43 | } | ||
| 44 | 8 | ||
| 45 | quote!( | 9 | quote!( |
| 46 | use #embassy_stm32_path::{rtc, interrupt, Peripherals, pac, hal::rcc::RccExt, hal::time::U32Ext}; | 10 | use #embassy_stm32_path::{rtc, interrupt, Peripherals, pac, hal::rcc::RccExt, hal::time::U32Ext}; |
| 47 | 11 | ||
| 48 | let dp = pac::Peripherals::take().unwrap(); | 12 | unsafe { #embassy_stm32_path::system::configure(#config) }; |
| 49 | let rcc = dp.RCC.constrain(); | ||
| 50 | let clocks = rcc.cfgr#clock_cfg_args.freeze(); | ||
| 51 | 13 | ||
| 52 | unsafe { Peripherals::set_peripherals(clocks) }; | 14 | let (dp, clocks) = Peripherals::take().unwrap(); |
| 53 | 15 | ||
| 54 | let mut rtc = rtc::RTC::new(dp.TIM3, interrupt::take!(TIM3), clocks); | 16 | let mut rtc = rtc::RTC::new(dp.TIM2, interrupt::take!(TIM2), clocks); |
| 55 | let rtc = unsafe { make_static(&mut rtc) }; | 17 | let rtc = unsafe { make_static(&mut rtc) }; |
| 56 | rtc.start(); | 18 | rtc.start(); |
| 57 | let mut alarm = rtc.alarm1(); | 19 | let mut alarm = rtc.alarm1(); |
| @@ -60,5 +22,7 @@ pub fn generate(args: &Args) -> TokenStream { | |||
| 60 | 22 | ||
| 61 | let alarm = unsafe { make_static(&mut alarm) }; | 23 | let alarm = unsafe { make_static(&mut alarm) }; |
| 62 | executor.set_alarm(alarm); | 24 | executor.set_alarm(alarm); |
| 25 | |||
| 26 | unsafe { Peripherals::set_peripherals(clocks) }; | ||
| 63 | ) | 27 | ) |
| 64 | } | 28 | } |
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs index cca6c8a56..64411f5b4 100644 --- a/embassy-macros/src/lib.rs +++ b/embassy-macros/src/lib.rs | |||
| @@ -212,13 +212,13 @@ mod chip; | |||
| 212 | #[path = "chip/rp.rs"] | 212 | #[path = "chip/rp.rs"] |
| 213 | mod chip; | 213 | mod chip; |
| 214 | 214 | ||
| 215 | #[cfg(feature = "std")] | 215 | #[derive(Debug, FromMeta)] |
| 216 | mod chip { | 216 | struct MainArgs { |
| 217 | #[derive(Debug, darling::FromMeta, Default)] | 217 | #[darling(default)] |
| 218 | pub struct Args { | 218 | embassy_prefix: ModulePrefix, |
| 219 | #[darling(default)] | 219 | |
| 220 | pub embassy_prefix: crate::path::ModulePrefix, | 220 | #[darling(default)] |
| 221 | } | 221 | config: Option<syn::LitStr>, |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | #[cfg(any(feature = "nrf", feature = "stm32", feature = "rp"))] | 224 | #[cfg(any(feature = "nrf", feature = "stm32", feature = "rp"))] |
| @@ -227,7 +227,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 227 | let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs); | 227 | let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs); |
| 228 | let task_fn = syn::parse_macro_input!(item as syn::ItemFn); | 228 | let task_fn = syn::parse_macro_input!(item as syn::ItemFn); |
| 229 | 229 | ||
| 230 | let macro_args = match chip::Args::from_list(¯o_args) { | 230 | let macro_args = match MainArgs::from_list(¯o_args) { |
| 231 | Ok(v) => v, | 231 | Ok(v) => v, |
| 232 | Err(e) => { | 232 | Err(e) => { |
| 233 | return TokenStream::from(e.write_errors()); | 233 | return TokenStream::from(e.write_errors()); |
| @@ -270,10 +270,21 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 270 | return TokenStream::new(); | 270 | return TokenStream::new(); |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | let embassy_prefix_lit = macro_args.embassy_prefix.literal(); | 273 | let embassy_prefix = macro_args.embassy_prefix; |
| 274 | let embassy_path = macro_args.embassy_prefix.append("embassy").path(); | 274 | let embassy_prefix_lit = embassy_prefix.literal(); |
| 275 | let task_fn_body = task_fn.block.clone(); | 275 | let embassy_path = embassy_prefix.append("embassy").path(); |
| 276 | let chip_setup = chip::generate(¯o_args); | 276 | let task_fn_body = task_fn.block; |
| 277 | |||
| 278 | let config = macro_args | ||
| 279 | .config | ||
| 280 | .map(|s| s.parse::<syn::Expr>().unwrap()) | ||
| 281 | .unwrap_or_else(|| { | ||
| 282 | syn::Expr::Verbatim(quote! { | ||
| 283 | Default::default() | ||
| 284 | }) | ||
| 285 | }); | ||
| 286 | |||
| 287 | let chip_setup = chip::generate(&embassy_prefix, config); | ||
| 277 | 288 | ||
| 278 | let result = quote! { | 289 | let result = quote! { |
| 279 | #[#embassy_path::task(embassy_prefix = #embassy_prefix_lit)] | 290 | #[#embassy_path::task(embassy_prefix = #embassy_prefix_lit)] |
| @@ -288,6 +299,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 288 | } | 299 | } |
| 289 | 300 | ||
| 290 | let mut executor = #embassy_path::executor::Executor::new(); | 301 | let mut executor = #embassy_path::executor::Executor::new(); |
| 302 | |||
| 291 | let executor = unsafe { make_static(&mut executor) }; | 303 | let executor = unsafe { make_static(&mut executor) }; |
| 292 | 304 | ||
| 293 | #chip_setup | 305 | #chip_setup |
| @@ -307,7 +319,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 307 | let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs); | 319 | let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs); |
| 308 | let task_fn = syn::parse_macro_input!(item as syn::ItemFn); | 320 | let task_fn = syn::parse_macro_input!(item as syn::ItemFn); |
| 309 | 321 | ||
| 310 | let macro_args = match chip::Args::from_list(¯o_args) { | 322 | let macro_args = match MainArgs::from_list(¯o_args) { |
| 311 | Ok(v) => v, | 323 | Ok(v) => v, |
| 312 | Err(e) => { | 324 | Err(e) => { |
| 313 | return TokenStream::from(e.write_errors()); | 325 | return TokenStream::from(e.write_errors()); |
diff --git a/embassy-stm32-examples/src/bin/rtc_async.rs b/embassy-stm32-examples/src/bin/rtc_async.rs index ea54a2a94..b780c3c10 100644 --- a/embassy-stm32-examples/src/bin/rtc_async.rs +++ b/embassy-stm32-examples/src/bin/rtc_async.rs | |||
| @@ -10,6 +10,7 @@ use example_common::*; | |||
| 10 | 10 | ||
| 11 | use defmt::panic; | 11 | use defmt::panic; |
| 12 | use embassy; | 12 | use embassy; |
| 13 | |||
| 13 | use embassy::executor::Spawner; | 14 | use embassy::executor::Spawner; |
| 14 | use embassy::time::{Duration, Timer}; | 15 | use embassy::time::{Duration, Timer}; |
| 15 | use embassy_stm32; | 16 | use embassy_stm32; |
| @@ -31,7 +32,7 @@ async fn run2() { | |||
| 31 | } | 32 | } |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | #[embassy::main(use_hse = 16)] | 35 | #[embassy::main(config = "embassy_stm32::system::Config::new().use_hse(16)")] |
| 35 | async fn main(spawner: Spawner) { | 36 | async fn main(spawner: Spawner) { |
| 36 | let (dp, clocks) = embassy_stm32::Peripherals::take().unwrap(); | 37 | let (dp, clocks) = embassy_stm32::Peripherals::take().unwrap(); |
| 37 | 38 | ||
diff --git a/embassy-stm32-examples/src/bin/serial.rs b/embassy-stm32-examples/src/bin/serial.rs index 9aeca5375..c48ba746b 100644 --- a/embassy-stm32-examples/src/bin/serial.rs +++ b/embassy-stm32-examples/src/bin/serial.rs | |||
| @@ -22,7 +22,7 @@ use embassy_stm32::pac as stm32; | |||
| 22 | use embassy_stm32::serial; | 22 | use embassy_stm32::serial; |
| 23 | use futures::pin_mut; | 23 | use futures::pin_mut; |
| 24 | 24 | ||
| 25 | #[embassy::main(use_hse = 16, sysclk = 48, pclk1 = 24)] | 25 | #[embassy::main(config = "embassy_stm32::system::Config::new().use_hse(16).sysclk(48).pclk1(24)")] |
| 26 | async fn main(spawner: Spawner) { | 26 | async fn main(spawner: Spawner) { |
| 27 | let (dp, clocks) = embassy_stm32::Peripherals::take().unwrap(); | 27 | let (dp, clocks) = embassy_stm32::Peripherals::take().unwrap(); |
| 28 | let cp = cortex_m::peripheral::Peripherals::take().unwrap(); | 28 | let cp = cortex_m::peripheral::Peripherals::take().unwrap(); |
diff --git a/embassy-stm32-examples/src/bin/usb_serial.rs b/embassy-stm32-examples/src/bin/usb_serial.rs index 6a1d27d54..e13275dd3 100644 --- a/embassy-stm32-examples/src/bin/usb_serial.rs +++ b/embassy-stm32-examples/src/bin/usb_serial.rs | |||
| @@ -92,7 +92,9 @@ async fn run1(bus: &'static mut UsbBusAllocator<UsbBus<USB>>) { | |||
| 92 | 92 | ||
| 93 | static USB_BUS: Forever<UsbBusAllocator<UsbBus<USB>>> = Forever::new(); | 93 | static USB_BUS: Forever<UsbBusAllocator<UsbBus<USB>>> = Forever::new(); |
| 94 | 94 | ||
| 95 | #[embassy::main(use_hse = 25, sysclk = 48, require_pll48clk)] | 95 | #[embassy::main( |
| 96 | config = "embassy_stm32::system::Config::new().use_hse(25).sysclk(48).require_pll48clk()" | ||
| 97 | )] | ||
| 96 | async fn main(spawner: Spawner) -> ! { | 98 | async fn main(spawner: Spawner) -> ! { |
| 97 | static mut EP_MEMORY: [u32; 1024] = [0; 1024]; | 99 | static mut EP_MEMORY: [u32; 1024] = [0; 1024]; |
| 98 | 100 | ||
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 523359417..af30f1aae 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -38,6 +38,7 @@ embassy = { version = "0.1.0", path = "../embassy" } | |||
| 38 | embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"]} | 38 | embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"]} |
| 39 | embassy-extras = {version = "0.1.0", path = "../embassy-extras" } | 39 | embassy-extras = {version = "0.1.0", path = "../embassy-extras" } |
| 40 | 40 | ||
| 41 | atomic-polyfill = "0.1.1" | ||
| 41 | defmt = { version = "0.2.0", optional = true } | 42 | defmt = { version = "0.2.0", optional = true } |
| 42 | log = { version = "0.4.11", optional = true } | 43 | log = { version = "0.4.11", optional = true } |
| 43 | cortex-m-rt = "0.6.13" | 44 | cortex-m-rt = "0.6.13" |
diff --git a/embassy-stm32/src/f4/mod.rs b/embassy-stm32/src/f4/mod.rs index 9edde82ca..9549b3ed6 100644 --- a/embassy-stm32/src/f4/mod.rs +++ b/embassy-stm32/src/f4/mod.rs | |||
| @@ -1,2 +1,4 @@ | |||
| 1 | pub mod rtc; | ||
| 1 | pub mod serial; | 2 | pub mod serial; |
| 2 | pub mod spi; | 3 | pub mod spi; |
| 4 | pub mod system; | ||
diff --git a/embassy-stm32/src/rtc.rs b/embassy-stm32/src/f4/rtc.rs index b1abba325..b1abba325 100644 --- a/embassy-stm32/src/rtc.rs +++ b/embassy-stm32/src/f4/rtc.rs | |||
diff --git a/embassy-stm32/src/f4/system.rs b/embassy-stm32/src/f4/system.rs new file mode 100644 index 000000000..fb739272a --- /dev/null +++ b/embassy-stm32/src/f4/system.rs | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | use crate::{hal::prelude::*, pac, Peripherals}; | ||
| 2 | |||
| 3 | #[derive(Default)] | ||
| 4 | pub struct Config { | ||
| 5 | pub use_hse: Option<u32>, | ||
| 6 | pub sysclk: Option<u32>, | ||
| 7 | pub pclk1: Option<u32>, | ||
| 8 | pub require_pll48clk: bool, | ||
| 9 | } | ||
| 10 | |||
| 11 | impl Config { | ||
| 12 | pub fn new() -> Self { | ||
| 13 | Default::default() | ||
| 14 | } | ||
| 15 | |||
| 16 | pub fn use_hse(mut self, freq: u32) -> Self { | ||
| 17 | self.use_hse = Some(freq); | ||
| 18 | self | ||
| 19 | } | ||
| 20 | |||
| 21 | pub fn sysclk(mut self, freq: u32) -> Self { | ||
| 22 | self.sysclk = Some(freq); | ||
| 23 | self | ||
| 24 | } | ||
| 25 | |||
| 26 | pub fn pclk1(mut self, freq: u32) -> Self { | ||
| 27 | self.pclk1 = Some(freq); | ||
| 28 | self | ||
| 29 | } | ||
| 30 | |||
| 31 | pub fn require_pll48clk(mut self) -> Self { | ||
| 32 | self.require_pll48clk = true; | ||
| 33 | self | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | /// safety: must only call once. | ||
| 38 | pub unsafe fn configure(config: Config) { | ||
| 39 | let dp = pac::Peripherals::take().unwrap(); | ||
| 40 | let mut cfgr = dp.RCC.constrain().cfgr; | ||
| 41 | |||
| 42 | if let Some(hz) = config.use_hse { | ||
| 43 | cfgr = cfgr.use_hse(hz.mhz()); | ||
| 44 | }; | ||
| 45 | |||
| 46 | if let Some(hz) = config.sysclk { | ||
| 47 | cfgr = cfgr.sysclk(hz.mhz()); | ||
| 48 | }; | ||
| 49 | |||
| 50 | if let Some(hz) = config.pclk1 { | ||
| 51 | cfgr = cfgr.pclk1(hz.mhz()); | ||
| 52 | }; | ||
| 53 | |||
| 54 | if config.require_pll48clk { | ||
| 55 | cfgr = cfgr.require_pll48clk(); | ||
| 56 | }; | ||
| 57 | |||
| 58 | let clocks = cfgr.freeze(); | ||
| 59 | |||
| 60 | unsafe { Peripherals::set_peripherals(clocks) }; | ||
| 61 | } | ||
diff --git a/embassy-stm32/src/l0/mod.rs b/embassy-stm32/src/l0/mod.rs new file mode 100644 index 000000000..53b44fe2d --- /dev/null +++ b/embassy-stm32/src/l0/mod.rs | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | pub mod rtc; | ||
| 2 | pub mod system; | ||
diff --git a/embassy-stm32/src/l0/rtc.rs b/embassy-stm32/src/l0/rtc.rs new file mode 100644 index 000000000..9a1342044 --- /dev/null +++ b/embassy-stm32/src/l0/rtc.rs | |||
| @@ -0,0 +1,371 @@ | |||
| 1 | use crate::hal::rcc::Clocks; | ||
| 2 | use atomic_polyfill::{compiler_fence, AtomicU32, Ordering}; | ||
| 3 | use core::cell::Cell; | ||
| 4 | use core::convert::TryInto; | ||
| 5 | |||
| 6 | use embassy::interrupt::InterruptExt; | ||
| 7 | use embassy::time::{Clock, TICKS_PER_SECOND}; | ||
| 8 | |||
| 9 | use crate::interrupt; | ||
| 10 | use crate::interrupt::{CriticalSection, Interrupt, Mutex}; | ||
| 11 | |||
| 12 | // RTC timekeeping works with something we call "periods", which are time intervals | ||
| 13 | // of 2^15 ticks. The RTC counter value is 16 bits, so one "overflow cycle" is 2 periods. | ||
| 14 | // | ||
| 15 | // A `period` count is maintained in parallel to the RTC hardware `counter`, like this: | ||
| 16 | // - `period` and `counter` start at 0 | ||
| 17 | // - `period` is incremented on overflow (at counter value 0) | ||
| 18 | // - `period` is incremented "midway" between overflows (at counter value 0x8000) | ||
| 19 | // | ||
| 20 | // Therefore, when `period` is even, counter is in 0..0x7FFF. When odd, counter is in 0x8000..0xFFFF | ||
| 21 | // This allows for now() to return the correct value even if it races an overflow. | ||
| 22 | // | ||
| 23 | // To get `now()`, `period` is read first, then `counter` is read. If the counter value matches | ||
| 24 | // the expected range for the `period` parity, we're done. If it doesn't, this means that | ||
| 25 | // a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value | ||
| 26 | // corresponds to the next period. | ||
| 27 | // | ||
| 28 | // `period` is a 32bit integer, so It overflows on 2^32 * 2^15 / 32768 seconds of uptime, which is 136 years. | ||
| 29 | fn calc_now(period: u32, counter: u16) -> u64 { | ||
| 30 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | ||
| 31 | } | ||
| 32 | |||
| 33 | struct AlarmState { | ||
| 34 | timestamp: Cell<u64>, | ||
| 35 | callback: Cell<Option<(fn(*mut ()), *mut ())>>, | ||
| 36 | } | ||
| 37 | |||
| 38 | impl AlarmState { | ||
| 39 | fn new() -> Self { | ||
| 40 | Self { | ||
| 41 | timestamp: Cell::new(u64::MAX), | ||
| 42 | callback: Cell::new(None), | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | // TODO: This is sometimes wasteful, try to find a better way | ||
| 48 | const ALARM_COUNT: usize = 3; | ||
| 49 | |||
| 50 | /// RTC timer that can be used by the executor and to set alarms. | ||
| 51 | /// | ||
| 52 | /// It can work with Timers 2 and 3. | ||
| 53 | |||
| 54 | /// This timer works internally with a unit of 2^15 ticks, which means that if a call to | ||
| 55 | /// [`embassy::time::Clock::now`] is blocked for that amount of ticks the returned value will be | ||
| 56 | /// wrong (an old value). The current default tick rate is 32768 ticks per second. | ||
| 57 | pub struct RTC<T: Instance> { | ||
| 58 | rtc: T, | ||
| 59 | irq: T::Interrupt, | ||
| 60 | |||
| 61 | /// Number of 2^23 periods elapsed since boot. | ||
| 62 | period: AtomicU32, | ||
| 63 | |||
| 64 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | ||
| 65 | alarms: Mutex<[AlarmState; ALARM_COUNT]>, | ||
| 66 | |||
| 67 | clocks: Clocks, | ||
| 68 | } | ||
| 69 | |||
| 70 | impl<T: Instance> RTC<T> { | ||
| 71 | pub fn new(rtc: T, irq: T::Interrupt, clocks: Clocks) -> Self { | ||
| 72 | Self { | ||
| 73 | rtc, | ||
| 74 | irq, | ||
| 75 | period: AtomicU32::new(0), | ||
| 76 | alarms: Mutex::new([AlarmState::new(), AlarmState::new(), AlarmState::new()]), | ||
| 77 | clocks, | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | pub fn start(&'static self) { | ||
| 82 | self.rtc.enable_clock(); | ||
| 83 | self.rtc.stop_and_reset(); | ||
| 84 | |||
| 85 | let freq = T::pclk(&self.clocks); | ||
| 86 | let psc = freq / TICKS_PER_SECOND as u32 - 1; | ||
| 87 | let psc: u16 = psc.try_into().unwrap(); | ||
| 88 | |||
| 89 | self.rtc.set_psc_arr(psc, u16::MAX); | ||
| 90 | // Mid-way point | ||
| 91 | self.rtc.set_compare(0, 0x8000); | ||
| 92 | self.rtc.set_compare_interrupt(0, true); | ||
| 93 | |||
| 94 | self.irq.set_handler(|ptr| unsafe { | ||
| 95 | let this = &*(ptr as *const () as *const Self); | ||
| 96 | this.on_interrupt(); | ||
| 97 | }); | ||
| 98 | self.irq.set_handler_context(self as *const _ as *mut _); | ||
| 99 | self.irq.unpend(); | ||
| 100 | self.irq.enable(); | ||
| 101 | |||
| 102 | self.rtc.start(); | ||
| 103 | } | ||
| 104 | |||
| 105 | fn on_interrupt(&self) { | ||
| 106 | if self.rtc.overflow_interrupt_status() { | ||
| 107 | self.rtc.overflow_clear_flag(); | ||
| 108 | self.next_period(); | ||
| 109 | } | ||
| 110 | |||
| 111 | // Half overflow | ||
| 112 | if self.rtc.compare_interrupt_status(0) { | ||
| 113 | self.rtc.compare_clear_flag(0); | ||
| 114 | self.next_period(); | ||
| 115 | } | ||
| 116 | |||
| 117 | for n in 1..=ALARM_COUNT { | ||
| 118 | if self.rtc.compare_interrupt_status(n) { | ||
| 119 | self.rtc.compare_clear_flag(n); | ||
| 120 | interrupt::free(|cs| self.trigger_alarm(n, cs)); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | fn next_period(&self) { | ||
| 126 | interrupt::free(|cs| { | ||
| 127 | let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; | ||
| 128 | let t = (period as u64) << 15; | ||
| 129 | |||
| 130 | for n in 1..=ALARM_COUNT { | ||
| 131 | let alarm = &self.alarms.borrow(cs)[n - 1]; | ||
| 132 | let at = alarm.timestamp.get(); | ||
| 133 | |||
| 134 | let diff = at - t; | ||
| 135 | if diff < 0xc000 { | ||
| 136 | self.rtc.set_compare(n, at as u16); | ||
| 137 | self.rtc.set_compare_interrupt(n, true); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | }) | ||
| 141 | } | ||
| 142 | |||
| 143 | fn trigger_alarm(&self, n: usize, cs: &CriticalSection) { | ||
| 144 | self.rtc.set_compare_interrupt(n, false); | ||
| 145 | |||
| 146 | let alarm = &self.alarms.borrow(cs)[n - 1]; | ||
| 147 | alarm.timestamp.set(u64::MAX); | ||
| 148 | |||
| 149 | // Call after clearing alarm, so the callback can set another alarm. | ||
| 150 | if let Some((f, ctx)) = alarm.callback.get() { | ||
| 151 | f(ctx); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | fn set_alarm_callback(&self, n: usize, callback: fn(*mut ()), ctx: *mut ()) { | ||
| 156 | interrupt::free(|cs| { | ||
| 157 | let alarm = &self.alarms.borrow(cs)[n - 1]; | ||
| 158 | alarm.callback.set(Some((callback, ctx))); | ||
| 159 | }) | ||
| 160 | } | ||
| 161 | |||
| 162 | fn set_alarm(&self, n: usize, timestamp: u64) { | ||
| 163 | interrupt::free(|cs| { | ||
| 164 | let alarm = &self.alarms.borrow(cs)[n - 1]; | ||
| 165 | alarm.timestamp.set(timestamp); | ||
| 166 | |||
| 167 | let t = self.now(); | ||
| 168 | if timestamp <= t { | ||
| 169 | self.trigger_alarm(n, cs); | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 173 | let diff = timestamp - t; | ||
| 174 | if diff < 0xc000 { | ||
| 175 | let safe_timestamp = timestamp.max(t + 3); | ||
| 176 | self.rtc.set_compare(n, safe_timestamp as u16); | ||
| 177 | self.rtc.set_compare_interrupt(n, true); | ||
| 178 | } else { | ||
| 179 | self.rtc.set_compare_interrupt(n, false); | ||
| 180 | } | ||
| 181 | }); | ||
| 182 | } | ||
| 183 | |||
| 184 | pub fn alarm1(&'static self) -> Alarm<T> { | ||
| 185 | Alarm { n: 1, rtc: self } | ||
| 186 | } | ||
| 187 | pub fn alarm2(&'static self) -> Option<Alarm<T>> { | ||
| 188 | if T::REAL_ALARM_COUNT >= 2 { | ||
| 189 | Some(Alarm { n: 2, rtc: self }) | ||
| 190 | } else { | ||
| 191 | None | ||
| 192 | } | ||
| 193 | } | ||
| 194 | pub fn alarm3(&'static self) -> Option<Alarm<T>> { | ||
| 195 | if T::REAL_ALARM_COUNT >= 3 { | ||
| 196 | Some(Alarm { n: 3, rtc: self }) | ||
| 197 | } else { | ||
| 198 | None | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | impl<T: Instance> embassy::time::Clock for RTC<T> { | ||
| 204 | fn now(&self) -> u64 { | ||
| 205 | let period = self.period.load(Ordering::Relaxed); | ||
| 206 | compiler_fence(Ordering::Acquire); | ||
| 207 | let counter = self.rtc.counter(); | ||
| 208 | calc_now(period, counter) | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | pub struct Alarm<T: Instance> { | ||
| 213 | n: usize, | ||
| 214 | rtc: &'static RTC<T>, | ||
| 215 | } | ||
| 216 | |||
| 217 | impl<T: Instance> embassy::time::Alarm for Alarm<T> { | ||
| 218 | fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { | ||
| 219 | self.rtc.set_alarm_callback(self.n, callback, ctx); | ||
| 220 | } | ||
| 221 | |||
| 222 | fn set(&self, timestamp: u64) { | ||
| 223 | self.rtc.set_alarm(self.n, timestamp); | ||
| 224 | } | ||
| 225 | |||
| 226 | fn clear(&self) { | ||
| 227 | self.rtc.set_alarm(self.n, u64::MAX); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | mod sealed { | ||
| 232 | pub trait Sealed {} | ||
| 233 | } | ||
| 234 | |||
| 235 | pub trait Instance: sealed::Sealed + Sized + 'static { | ||
| 236 | type Interrupt: Interrupt; | ||
| 237 | const REAL_ALARM_COUNT: usize; | ||
| 238 | |||
| 239 | fn enable_clock(&self); | ||
| 240 | fn set_compare(&self, n: usize, value: u16); | ||
| 241 | fn set_compare_interrupt(&self, n: usize, enable: bool); | ||
| 242 | fn compare_interrupt_status(&self, n: usize) -> bool; | ||
| 243 | fn compare_clear_flag(&self, n: usize); | ||
| 244 | fn overflow_interrupt_status(&self) -> bool; | ||
| 245 | fn overflow_clear_flag(&self); | ||
| 246 | // This method should ensure that the values are really updated before returning | ||
| 247 | fn set_psc_arr(&self, psc: u16, arr: u16); | ||
| 248 | fn stop_and_reset(&self); | ||
| 249 | fn start(&self); | ||
| 250 | fn counter(&self) -> u16; | ||
| 251 | fn pclk(clocks: &Clocks) -> u32; | ||
| 252 | } | ||
| 253 | |||
| 254 | #[allow(unused_macros)] | ||
| 255 | macro_rules! impl_timer { | ||
| 256 | ($module:ident: ($TYPE:ident, $INT:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident, $pclk: ident)) => { | ||
| 257 | mod $module { | ||
| 258 | use super::*; | ||
| 259 | use crate::hal::pac::{$TYPE, RCC}; | ||
| 260 | |||
| 261 | impl sealed::Sealed for $TYPE {} | ||
| 262 | |||
| 263 | impl Instance for $TYPE { | ||
| 264 | type Interrupt = interrupt::$INT; | ||
| 265 | const REAL_ALARM_COUNT: usize = 3; | ||
| 266 | |||
| 267 | fn enable_clock(&self) { | ||
| 268 | // NOTE(unsafe) It will only be used for atomic operations | ||
| 269 | unsafe { | ||
| 270 | let rcc = &*RCC::ptr(); | ||
| 271 | |||
| 272 | rcc.$apbenr.modify(|_, w| w.$timXen().set_bit()); | ||
| 273 | rcc.$apbrstr.modify(|_, w| w.$timXrst().set_bit()); | ||
| 274 | rcc.$apbrstr.modify(|_, w| w.$timXrst().clear_bit()); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | fn set_compare(&self, n: usize, value: u16) { | ||
| 279 | // NOTE(unsafe) these registers accept all the range of u16 values | ||
| 280 | match n { | ||
| 281 | 0 => self.ccr1.write(|w| unsafe { w.bits(value.into()) }), | ||
| 282 | 1 => self.ccr2.write(|w| unsafe { w.bits(value.into()) }), | ||
| 283 | 2 => self.ccr3.write(|w| unsafe { w.bits(value.into()) }), | ||
| 284 | 3 => self.ccr4.write(|w| unsafe { w.bits(value.into()) }), | ||
| 285 | _ => {} | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | fn set_compare_interrupt(&self, n: usize, enable: bool) { | ||
| 290 | if n > 3 { | ||
| 291 | return; | ||
| 292 | } | ||
| 293 | let bit = n as u8 + 1; | ||
| 294 | unsafe { | ||
| 295 | if enable { | ||
| 296 | self.dier.modify(|r, w| w.bits(r.bits() | (1 << bit))); | ||
| 297 | } else { | ||
| 298 | self.dier.modify(|r, w| w.bits(r.bits() & !(1 << bit))); | ||
| 299 | } | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | fn compare_interrupt_status(&self, n: usize) -> bool { | ||
| 304 | let status = self.sr.read(); | ||
| 305 | match n { | ||
| 306 | 0 => status.cc1if().bit_is_set(), | ||
| 307 | 1 => status.cc2if().bit_is_set(), | ||
| 308 | 2 => status.cc3if().bit_is_set(), | ||
| 309 | 3 => status.cc4if().bit_is_set(), | ||
| 310 | _ => false, | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | fn compare_clear_flag(&self, n: usize) { | ||
| 315 | if n > 3 { | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | let bit = n as u8 + 1; | ||
| 319 | unsafe { | ||
| 320 | self.sr.modify(|r, w| w.bits(r.bits() & !(1 << bit))); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | fn overflow_interrupt_status(&self) -> bool { | ||
| 325 | self.sr.read().uif().bit_is_set() | ||
| 326 | } | ||
| 327 | |||
| 328 | fn overflow_clear_flag(&self) { | ||
| 329 | unsafe { | ||
| 330 | self.sr.modify(|_, w| w.uif().clear_bit()); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | fn set_psc_arr(&self, psc: u16, arr: u16) { | ||
| 335 | // NOTE(unsafe) All u16 values are valid | ||
| 336 | self.psc.write(|w| unsafe { w.bits(psc.into()) }); | ||
| 337 | self.arr.write(|w| unsafe { w.bits(arr.into()) }); | ||
| 338 | |||
| 339 | unsafe { | ||
| 340 | // Set URS, generate update, clear URS | ||
| 341 | self.cr1.modify(|_, w| w.urs().set_bit()); | ||
| 342 | self.egr.write(|w| w.ug().set_bit()); | ||
| 343 | self.cr1.modify(|_, w| w.urs().clear_bit()); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | fn stop_and_reset(&self) { | ||
| 348 | unsafe { | ||
| 349 | self.cr1.modify(|_, w| w.cen().clear_bit()); | ||
| 350 | } | ||
| 351 | self.cnt.reset(); | ||
| 352 | } | ||
| 353 | |||
| 354 | fn start(&self) { | ||
| 355 | self.cr1.modify(|_, w| w.cen().set_bit()); | ||
| 356 | } | ||
| 357 | |||
| 358 | fn counter(&self) -> u16 { | ||
| 359 | self.cnt.read().bits() as u16 | ||
| 360 | } | ||
| 361 | |||
| 362 | fn pclk(clocks: &Clocks) -> u32 { | ||
| 363 | clocks.$pclk().0 | ||
| 364 | } | ||
| 365 | } | ||
| 366 | } | ||
| 367 | }; | ||
| 368 | } | ||
| 369 | |||
| 370 | impl_timer!(tim2: (TIM2, TIM2, tim2en, tim2rst, apb1enr, apb1rstr, apb1_tim_clk)); | ||
| 371 | impl_timer!(tim3: (TIM3, TIM3, tim3en, tim3rst, apb1enr, apb1rstr, apb1_tim_clk)); | ||
diff --git a/embassy-stm32/src/l0/system.rs b/embassy-stm32/src/l0/system.rs new file mode 100644 index 000000000..00e417d4b --- /dev/null +++ b/embassy-stm32/src/l0/system.rs | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | use crate::{hal, pac, Peripherals}; | ||
| 2 | |||
| 3 | pub use hal::{ | ||
| 4 | prelude::*, | ||
| 5 | rcc::{Clocks, Config}, | ||
| 6 | }; | ||
| 7 | |||
| 8 | /// safety: must only call once. | ||
| 9 | pub unsafe fn configure(config: Config) { | ||
| 10 | let dp = pac::Peripherals::take().unwrap(); | ||
| 11 | |||
| 12 | let rcc = dp.RCC.freeze(config); | ||
| 13 | |||
| 14 | let clocks = rcc.clocks; | ||
| 15 | |||
| 16 | unsafe { Peripherals::set_peripherals(clocks) }; | ||
| 17 | } | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 27f865ecb..2fd9f1d3d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -49,6 +49,12 @@ pub use {stm32f4xx_hal as hal, stm32f4xx_hal::stm32 as pac}; | |||
| 49 | #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | 49 | #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] |
| 50 | pub use {stm32l0xx_hal as hal, stm32l0xx_hal::pac}; | 50 | pub use {stm32l0xx_hal as hal, stm32l0xx_hal::pac}; |
| 51 | 51 | ||
| 52 | #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||
| 53 | mod l0; | ||
| 54 | |||
| 55 | #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||
| 56 | pub use l0::{rtc, system}; | ||
| 57 | |||
| 52 | pub mod fmt; | 58 | pub mod fmt; |
| 53 | 59 | ||
| 54 | pub mod exti; | 60 | pub mod exti; |
| @@ -89,26 +95,7 @@ pub mod can; | |||
| 89 | feature = "stm32f469", | 95 | feature = "stm32f469", |
| 90 | feature = "stm32f479", | 96 | feature = "stm32f479", |
| 91 | ))] | 97 | ))] |
| 92 | pub mod rtc; | 98 | pub use f4::{rtc, serial, spi, system}; |
| 93 | |||
| 94 | #[cfg(any( | ||
| 95 | feature = "stm32f401", | ||
| 96 | feature = "stm32f405", | ||
| 97 | feature = "stm32f407", | ||
| 98 | feature = "stm32f412", | ||
| 99 | feature = "stm32f413", | ||
| 100 | feature = "stm32f415", | ||
| 101 | feature = "stm32f417", | ||
| 102 | feature = "stm32f423", | ||
| 103 | feature = "stm32f427", | ||
| 104 | feature = "stm32f429", | ||
| 105 | feature = "stm32f437", | ||
| 106 | feature = "stm32f439", | ||
| 107 | feature = "stm32f446", | ||
| 108 | feature = "stm32f469", | ||
| 109 | feature = "stm32f479", | ||
| 110 | ))] | ||
| 111 | pub use f4::{serial, spi}; | ||
| 112 | 99 | ||
| 113 | #[cfg(any( | 100 | #[cfg(any( |
| 114 | feature = "stm32f401", | 101 | feature = "stm32f401", |
| @@ -452,3 +439,40 @@ embassy_extras::std_peripherals! { | |||
| 452 | FPU_CPACR, | 439 | FPU_CPACR, |
| 453 | SCB_ACTRL, | 440 | SCB_ACTRL, |
| 454 | } | 441 | } |
| 442 | |||
| 443 | #[cfg(feature = "stm32l0x2")] | ||
| 444 | embassy_extras::std_peripherals! { | ||
| 445 | SPI1, | ||
| 446 | SPI2, | ||
| 447 | USART1, | ||
| 448 | USART2, | ||
| 449 | USART4, | ||
| 450 | USART5, | ||
| 451 | I2C1, | ||
| 452 | I2C2, | ||
| 453 | I2C3, | ||
| 454 | RNG, | ||
| 455 | TIM2, | ||
| 456 | TIM3, | ||
| 457 | TIM6, | ||
| 458 | TIM7, | ||
| 459 | TIM21, | ||
| 460 | TIM22, | ||
| 461 | DAC, | ||
| 462 | RTC, | ||
| 463 | PWR, | ||
| 464 | CRC, | ||
| 465 | GPIOA, | ||
| 466 | GPIOB, | ||
| 467 | GPIOC, | ||
| 468 | GPIOD, | ||
| 469 | GPIOE, | ||
| 470 | GPIOH, | ||
| 471 | SYSCFG, | ||
| 472 | DMA1, | ||
| 473 | EXTI, | ||
| 474 | ADC, | ||
| 475 | IWDG, | ||
| 476 | WWDG, | ||
| 477 | DBG, | ||
| 478 | } | ||
