aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-macros/src/chip/nrf.rs55
-rw-r--r--embassy-macros/src/chip/rp.rs14
-rw-r--r--embassy-macros/src/chip/stm32.rs54
-rw-r--r--embassy-macros/src/lib.rs38
-rw-r--r--embassy-stm32-examples/src/bin/rtc_async.rs3
-rw-r--r--embassy-stm32-examples/src/bin/serial.rs2
-rw-r--r--embassy-stm32-examples/src/bin/usb_serial.rs4
-rw-r--r--embassy-stm32/Cargo.toml1
-rw-r--r--embassy-stm32/src/f4/mod.rs2
-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.rs61
-rw-r--r--embassy-stm32/src/l0/mod.rs2
-rw-r--r--embassy-stm32/src/l0/rtc.rs371
-rw-r--r--embassy-stm32/src/l0/system.rs17
-rw-r--r--embassy-stm32/src/lib.rs64
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 @@
1use crate::path::ModulePrefix; 1use crate::path::ModulePrefix;
2use darling::FromMeta;
3use proc_macro2::TokenStream; 2use proc_macro2::TokenStream;
4use quote::{format_ident, quote}; 3use quote::quote;
5use syn::spanned::Spanned;
6 4
7#[derive(Debug, FromMeta)] 5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
8pub 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
13impl Default for HfclkSource {
14 fn default() -> Self {
15 Self::Internal
16 }
17}
18
19#[derive(Debug, FromMeta)]
20pub enum LfclkSource {
21 InternalRC,
22 Synthesized,
23 ExternalXtal,
24 ExternalLowSwing,
25 ExternalFullSwing,
26}
27
28impl Default for LfclkSource {
29 fn default() -> Self {
30 Self::InternalRC
31 }
32}
33
34#[derive(Debug, FromMeta, Default)]
35pub 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
44pub 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 @@
1use crate::path::ModulePrefix; 1use crate::path::ModulePrefix;
2use darling::FromMeta;
3use proc_macro2::TokenStream; 2use proc_macro2::TokenStream;
4use quote::quote; 3use quote::quote;
5 4
6#[derive(Debug, FromMeta, Default)] 5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
7pub struct Args { 6 let embassy_rp_path = embassy_prefix.append("embassy_rp").path();
8 #[darling(default)]
9 pub embassy_prefix: ModulePrefix,
10}
11
12pub 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 @@
1use crate::path::ModulePrefix; 1use crate::path::ModulePrefix;
2use darling::FromMeta;
3use proc_macro2::TokenStream; 2use proc_macro2::TokenStream;
4use quote::{format_ident, quote}; 3use quote::quote;
5use syn::spanned::Spanned;
6 4
7#[derive(Debug, FromMeta, Default)] 5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
8pub 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
21pub 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"]
213mod chip; 213mod chip;
214 214
215#[cfg(feature = "std")] 215#[derive(Debug, FromMeta)]
216mod chip { 216struct 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(&macro_args) { 230 let macro_args = match MainArgs::from_list(&macro_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(&macro_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(&macro_args) { 322 let macro_args = match MainArgs::from_list(&macro_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
11use defmt::panic; 11use defmt::panic;
12use embassy; 12use embassy;
13
13use embassy::executor::Spawner; 14use embassy::executor::Spawner;
14use embassy::time::{Duration, Timer}; 15use embassy::time::{Duration, Timer};
15use embassy_stm32; 16use 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)")]
35async fn main(spawner: Spawner) { 36async 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;
22use embassy_stm32::serial; 22use embassy_stm32::serial;
23use futures::pin_mut; 23use 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)")]
26async fn main(spawner: Spawner) { 26async 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
93static USB_BUS: Forever<UsbBusAllocator<UsbBus<USB>>> = Forever::new(); 93static 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)]
96async fn main(spawner: Spawner) -> ! { 98async 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" }
38embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"]} 38embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"]}
39embassy-extras = {version = "0.1.0", path = "../embassy-extras" } 39embassy-extras = {version = "0.1.0", path = "../embassy-extras" }
40 40
41atomic-polyfill = "0.1.1"
41defmt = { version = "0.2.0", optional = true } 42defmt = { version = "0.2.0", optional = true }
42log = { version = "0.4.11", optional = true } 43log = { version = "0.4.11", optional = true }
43cortex-m-rt = "0.6.13" 44cortex-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 @@
1pub mod rtc;
1pub mod serial; 2pub mod serial;
2pub mod spi; 3pub mod spi;
4pub 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 @@
1use crate::{hal::prelude::*, pac, Peripherals};
2
3#[derive(Default)]
4pub 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
11impl 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.
38pub 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 @@
1pub mod rtc;
2pub 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 @@
1use crate::hal::rcc::Clocks;
2use atomic_polyfill::{compiler_fence, AtomicU32, Ordering};
3use core::cell::Cell;
4use core::convert::TryInto;
5
6use embassy::interrupt::InterruptExt;
7use embassy::time::{Clock, TICKS_PER_SECOND};
8
9use crate::interrupt;
10use 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.
29fn calc_now(period: u32, counter: u16) -> u64 {
30 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
31}
32
33struct AlarmState {
34 timestamp: Cell<u64>,
35 callback: Cell<Option<(fn(*mut ()), *mut ())>>,
36}
37
38impl 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
48const 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.
57pub 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
70impl<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
203impl<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
212pub struct Alarm<T: Instance> {
213 n: usize,
214 rtc: &'static RTC<T>,
215}
216
217impl<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
231mod sealed {
232 pub trait Sealed {}
233}
234
235pub 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)]
255macro_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
370impl_timer!(tim2: (TIM2, TIM2, tim2en, tim2rst, apb1enr, apb1rstr, apb1_tim_clk));
371impl_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 @@
1use crate::{hal, pac, Peripherals};
2
3pub use hal::{
4 prelude::*,
5 rcc::{Clocks, Config},
6};
7
8/// safety: must only call once.
9pub 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",))]
50pub use {stm32l0xx_hal as hal, stm32l0xx_hal::pac}; 50pub use {stm32l0xx_hal as hal, stm32l0xx_hal::pac};
51 51
52#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
53mod l0;
54
55#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
56pub use l0::{rtc, system};
57
52pub mod fmt; 58pub mod fmt;
53 59
54pub mod exti; 60pub mod exti;
@@ -89,26 +95,7 @@ pub mod can;
89 feature = "stm32f469", 95 feature = "stm32f469",
90 feature = "stm32f479", 96 feature = "stm32f479",
91))] 97))]
92pub mod rtc; 98pub 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))]
111pub 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")]
444embassy_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}