aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/rust.yml2
-rw-r--r--embassy-macros/src/chip/nrf.rs13
-rw-r--r--embassy-macros/src/chip/rp.rs8
-rw-r--r--embassy-macros/src/chip/stm32.rs17
-rw-r--r--embassy-nrf/src/lib.rs8
-rw-r--r--embassy-nrf/src/time_driver.rs (renamed from embassy-nrf/src/rtc.rs)239
-rw-r--r--embassy-rp/Cargo.toml2
-rw-r--r--embassy-rp/src/lib.rs5
-rw-r--r--embassy-rp/src/timer.rs72
-rw-r--r--embassy-std/src/lib.rs38
-rw-r--r--embassy-stm32/src/clock.rs372
-rw-r--r--embassy-stm32/src/lib.rs6
-rw-r--r--embassy-stm32/src/time_driver.rs319
-rw-r--r--embassy/src/executor/mod.rs12
-rw-r--r--embassy/src/executor/raw.rs37
-rw-r--r--embassy/src/time/driver.rs118
-rw-r--r--embassy/src/time/instant.rs7
-rw-r--r--embassy/src/time/mod.rs22
-rw-r--r--embassy/src/time/traits.rs32
-rw-r--r--examples/nrf/src/bin/blinky.rs1
-rw-r--r--examples/nrf/src/bin/executor_fairness_test.rs3
-rw-r--r--examples/nrf/src/bin/gpiote_channel.rs3
-rw-r--r--examples/nrf/src/bin/gpiote_port.rs2
-rw-r--r--examples/nrf/src/bin/mpsc.rs1
-rw-r--r--examples/nrf/src/bin/multiprio.rs18
-rw-r--r--examples/nrf/src/bin/ppi.rs3
-rw-r--r--examples/nrf/src/bin/pwm.rs4
-rw-r--r--examples/nrf/src/bin/raw_spawn.rs15
-rw-r--r--examples/nrf/src/bin/timer.rs1
-rw-r--r--examples/stm32f4/src/bin/blinky.rs1
-rw-r--r--examples/stm32f4/src/bin/button_exti.rs1
-rw-r--r--examples/stm32f4/src/bin/hello.rs2
-rw-r--r--examples/stm32f4/src/bin/spi_dma.rs1
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32h7/src/bin/blinky.rs17
-rw-r--r--examples/stm32h7/src/bin/eth.rs13
-rw-r--r--examples/stm32h7/src/bin/spi.rs10
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs10
-rw-r--r--examples/stm32h7/src/bin/usart.rs11
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs11
-rw-r--r--examples/stm32l0/src/bin/blinky.rs1
-rw-r--r--examples/stm32l0/src/bin/button_exti.rs1
-rw-r--r--examples/stm32l0/src/bin/usart_dma.rs1
-rw-r--r--examples/stm32l4/src/bin/blinky.rs1
-rw-r--r--examples/stm32l4/src/bin/button_exti.rs1
-rw-r--r--examples/stm32l4/src/bin/spi_dma.rs1
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs1
47 files changed, 657 insertions, 808 deletions
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index d11bc8d41..38d9c128f 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -77,7 +77,7 @@ jobs:
77 features: stm32l476vg,defmt 77 features: stm32l476vg,defmt
78 - package: embassy-stm32 78 - package: embassy-stm32
79 target: thumbv6m-none-eabi 79 target: thumbv6m-none-eabi
80 features: stm32l053r8,defmt 80 features: stm32l072cz,defmt
81 - package: examples/stm32f4 81 - package: examples/stm32f4
82 target: thumbv7em-none-eabi 82 target: thumbv7em-none-eabi
83 - package: examples/stm32l4 83 - package: examples/stm32l4
diff --git a/embassy-macros/src/chip/nrf.rs b/embassy-macros/src/chip/nrf.rs
index 503a8ba5a..3ff6a74cf 100644
--- a/embassy-macros/src/chip/nrf.rs
+++ b/embassy-macros/src/chip/nrf.rs
@@ -3,22 +3,9 @@ use proc_macro2::TokenStream;
3use quote::quote; 3use quote::quote;
4 4
5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { 5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
6 let embassy_path = embassy_prefix.append("embassy").path();
7 let embassy_nrf_path = embassy_prefix.append("embassy_nrf").path(); 6 let embassy_nrf_path = embassy_prefix.append("embassy_nrf").path();
8 7
9 quote!( 8 quote!(
10 use #embassy_nrf_path::{interrupt, peripherals, rtc};
11
12 let p = #embassy_nrf_path::init(#config); 9 let p = #embassy_nrf_path::init(#config);
13
14 let mut rtc = rtc::RTC::new(unsafe { <peripherals::RTC1 as #embassy_path::util::Steal>::steal() }, interrupt::take!(RTC1));
15 let rtc = unsafe { make_static(&mut rtc) };
16 rtc.start();
17 let mut alarm = rtc.alarm0();
18
19 unsafe { #embassy_path::time::set_clock(rtc) };
20
21 let alarm = unsafe { make_static(&mut alarm) };
22 executor.set_alarm(alarm);
23 ) 10 )
24} 11}
diff --git a/embassy-macros/src/chip/rp.rs b/embassy-macros/src/chip/rp.rs
index d40a44963..ba0a97ada 100644
--- a/embassy-macros/src/chip/rp.rs
+++ b/embassy-macros/src/chip/rp.rs
@@ -3,16 +3,8 @@ use proc_macro2::TokenStream;
3use quote::quote; 3use quote::quote;
4 4
5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { 5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
6 let embassy_path = embassy_prefix.append("embassy").path();
7 let embassy_rp_path = embassy_prefix.append("embassy_rp").path(); 6 let embassy_rp_path = embassy_prefix.append("embassy_rp").path();
8 quote!( 7 quote!(
9 use #embassy_rp_path::{interrupt, peripherals};
10
11 let p = #embassy_rp_path::init(#config); 8 let p = #embassy_rp_path::init(#config);
12
13 let alarm = unsafe { <#embassy_rp_path::peripherals::TIMER_ALARM0 as #embassy_path::util::Steal>::steal() };
14 let mut alarm = #embassy_rp_path::timer::Alarm::new(alarm);
15 let alarm = unsafe { make_static(&mut alarm) };
16 executor.set_alarm(alarm);
17 ) 9 )
18} 10}
diff --git a/embassy-macros/src/chip/stm32.rs b/embassy-macros/src/chip/stm32.rs
index 32a0a0173..c6938836c 100644
--- a/embassy-macros/src/chip/stm32.rs
+++ b/embassy-macros/src/chip/stm32.rs
@@ -3,26 +3,9 @@ use proc_macro2::TokenStream;
3use quote::quote; 3use quote::quote;
4 4
5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { 5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
6 let embassy_path = embassy_prefix.append("embassy").path();
7 let embassy_stm32_path = embassy_prefix.append("embassy_stm32").path(); 6 let embassy_stm32_path = embassy_prefix.append("embassy_stm32").path();
8 7
9 quote!( 8 quote!(
10 use #embassy_stm32_path::{interrupt, peripherals, clock::Clock, time::Hertz};
11
12 let p = #embassy_stm32_path::init(#config); 9 let p = #embassy_stm32_path::init(#config);
13
14 let mut c = Clock::new(
15 unsafe { <peripherals::TIM3 as embassy::util::Steal>::steal() },
16 interrupt::take!(TIM3),
17 );
18 let clock = unsafe { make_static(&mut c) };
19
20 clock.start();
21
22 let mut alarm = clock.alarm1();
23 unsafe { #embassy_path::time::set_clock(clock) };
24
25 let alarm = unsafe { make_static(&mut alarm) };
26 executor.set_alarm(alarm);
27 ) 10 )
28} 11}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 9054ba891..4cce8028a 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -23,6 +23,8 @@ compile_error!("No chip feature activated. You must activate exactly one of the
23pub(crate) mod fmt; 23pub(crate) mod fmt;
24pub(crate) mod util; 24pub(crate) mod util;
25 25
26mod time_driver;
27
26pub mod buffered_uarte; 28pub mod buffered_uarte;
27pub mod gpio; 29pub mod gpio;
28pub mod gpiote; 30pub mod gpiote;
@@ -32,7 +34,6 @@ pub mod pwm;
32#[cfg(feature = "nrf52840")] 34#[cfg(feature = "nrf52840")]
33pub mod qspi; 35pub mod qspi;
34pub mod rng; 36pub mod rng;
35pub mod rtc;
36#[cfg(not(feature = "nrf52820"))] 37#[cfg(not(feature = "nrf52820"))]
37pub mod saadc; 38pub mod saadc;
38pub mod spim; 39pub mod spim;
@@ -160,7 +161,10 @@ pub fn init(config: config::Config) -> Peripherals {
160 while r.events_lfclkstarted.read().bits() == 0 {} 161 while r.events_lfclkstarted.read().bits() == 0 {}
161 162
162 // Init GPIOTE 163 // Init GPIOTE
163 crate::gpiote::init(config.gpiote_interrupt_priority); 164 gpiote::init(config.gpiote_interrupt_priority);
165
166 // init RTC time driver
167 time_driver::init();
164 168
165 peripherals 169 peripherals
166} 170}
diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/time_driver.rs
index 99b6c099d..7815427ee 100644
--- a/embassy-nrf/src/rtc.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -1,13 +1,17 @@
1use core::cell::Cell; 1use core::cell::Cell;
2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 2use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
3use core::{mem, ptr};
3use critical_section::CriticalSection; 4use critical_section::CriticalSection;
4use embassy::interrupt::InterruptExt; 5use embassy::interrupt::{Interrupt, InterruptExt};
5use embassy::time::Clock; 6use embassy::time::driver::{AlarmHandle, Driver};
6use embassy::util::{CriticalSectionMutex as Mutex, Unborrow}; 7use embassy::util::CriticalSectionMutex as Mutex;
7 8
8use crate::interrupt::Interrupt; 9use crate::interrupt;
9use crate::pac; 10use crate::pac;
10use crate::{interrupt, peripherals}; 11
12fn rtc() -> &'static pac::rtc0::RegisterBlock {
13 unsafe { &*pac::RTC1::ptr() }
14}
11 15
12// RTC timekeeping works with something we call "periods", which are time intervals 16// RTC timekeeping works with something we call "periods", which are time intervals
13// of 2^23 ticks. The RTC counter value is 24 bits, so one "overflow cycle" is 2 periods. 17// of 2^23 ticks. The RTC counter value is 24 bits, so one "overflow cycle" is 2 periods.
@@ -57,46 +61,45 @@ mod test {
57 61
58struct AlarmState { 62struct AlarmState {
59 timestamp: Cell<u64>, 63 timestamp: Cell<u64>,
60 callback: Cell<Option<(fn(*mut ()), *mut ())>>, 64
65 // This is really a Option<(fn(*mut ()), *mut ())>
66 // but fn pointers aren't allowed in const yet
67 callback: Cell<*const ()>,
68 ctx: Cell<*mut ()>,
61} 69}
62 70
71unsafe impl Send for AlarmState {}
72
63impl AlarmState { 73impl AlarmState {
64 fn new() -> Self { 74 const fn new() -> Self {
65 Self { 75 Self {
66 timestamp: Cell::new(u64::MAX), 76 timestamp: Cell::new(u64::MAX),
67 callback: Cell::new(None), 77 callback: Cell::new(ptr::null()),
78 ctx: Cell::new(ptr::null_mut()),
68 } 79 }
69 } 80 }
70} 81}
71 82
72const ALARM_COUNT: usize = 3; 83const ALARM_COUNT: usize = 3;
73 84
74pub struct RTC<T: Instance> { 85struct State {
75 rtc: T,
76 irq: T::Interrupt,
77
78 /// Number of 2^23 periods elapsed since boot. 86 /// Number of 2^23 periods elapsed since boot.
79 period: AtomicU32, 87 period: AtomicU32,
80 88 alarm_count: AtomicU8,
81 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. 89 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
82 alarms: Mutex<[AlarmState; ALARM_COUNT]>, 90 alarms: Mutex<[AlarmState; ALARM_COUNT]>,
83} 91}
84 92
85unsafe impl<T: Instance> Send for RTC<T> {} 93const ALARM_STATE_NEW: AlarmState = AlarmState::new();
86unsafe impl<T: Instance> Sync for RTC<T> {} 94static STATE: State = State {
95 period: AtomicU32::new(0),
96 alarm_count: AtomicU8::new(0),
97 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
98};
87 99
88impl<T: Instance> RTC<T> { 100impl State {
89 pub fn new(rtc: T, irq: T::Interrupt) -> Self { 101 fn init(&'static self) {
90 Self { 102 let r = rtc();
91 rtc,
92 irq,
93 period: AtomicU32::new(0),
94 alarms: Mutex::new([AlarmState::new(), AlarmState::new(), AlarmState::new()]),
95 }
96 }
97
98 pub fn start(&'static self) {
99 let r = self.rtc.regs();
100 r.cc[3].write(|w| unsafe { w.bits(0x800000) }); 103 r.cc[3].write(|w| unsafe { w.bits(0x800000) });
101 104
102 r.intenset.write(|w| { 105 r.intenset.write(|w| {
@@ -111,17 +114,11 @@ impl<T: Instance> RTC<T> {
111 // Wait for clear 114 // Wait for clear
112 while r.counter.read().bits() != 0 {} 115 while r.counter.read().bits() != 0 {}
113 116
114 self.irq.set_handler(|ptr| unsafe { 117 unsafe { interrupt::RTC1::steal() }.enable();
115 let this = &*(ptr as *const () as *const Self);
116 this.on_interrupt();
117 });
118 self.irq.set_handler_context(self as *const _ as *mut _);
119 self.irq.unpend();
120 self.irq.enable();
121 } 118 }
122 119
123 fn on_interrupt(&self) { 120 fn on_interrupt(&self) {
124 let r = self.rtc.regs(); 121 let r = rtc();
125 if r.events_ovrflw.read().bits() == 1 { 122 if r.events_ovrflw.read().bits() == 1 {
126 r.events_ovrflw.write(|w| w); 123 r.events_ovrflw.write(|w| w);
127 self.next_period(); 124 self.next_period();
@@ -144,7 +141,7 @@ impl<T: Instance> RTC<T> {
144 141
145 fn next_period(&self) { 142 fn next_period(&self) {
146 critical_section::with(|cs| { 143 critical_section::with(|cs| {
147 let r = self.rtc.regs(); 144 let r = rtc();
148 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; 145 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
149 let t = (period as u64) << 23; 146 let t = (period as u64) << 23;
150 147
@@ -152,38 +149,77 @@ impl<T: Instance> RTC<T> {
152 let alarm = &self.alarms.borrow(cs)[n]; 149 let alarm = &self.alarms.borrow(cs)[n];
153 let at = alarm.timestamp.get(); 150 let at = alarm.timestamp.get();
154 151
155 let diff = at - t; 152 if at < t + 0xc00000 {
156 if diff < 0xc00000 { 153 // just enable it. `set_alarm` has already set the correct CC val.
157 r.cc[n].write(|w| unsafe { w.bits(at as u32 & 0xFFFFFF) });
158 r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); 154 r.intenset.write(|w| unsafe { w.bits(compare_n(n)) });
159 } 155 }
160 } 156 }
161 }) 157 })
162 } 158 }
163 159
160 fn now(&self) -> u64 {
161 // `period` MUST be read before `counter`, see comment at the top for details.
162 let period = self.period.load(Ordering::Relaxed);
163 compiler_fence(Ordering::Acquire);
164 let counter = rtc().counter.read().bits();
165 calc_now(period, counter)
166 }
167
168 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
169 // safety: we're allowed to assume the AlarmState is created by us, and
170 // we never create one that's out of bounds.
171 unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) }
172 }
173
164 fn trigger_alarm(&self, n: usize, cs: CriticalSection) { 174 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
165 let r = self.rtc.regs(); 175 let r = rtc();
166 r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); 176 r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) });
167 177
168 let alarm = &self.alarms.borrow(cs)[n]; 178 let alarm = &self.alarms.borrow(cs)[n];
169 alarm.timestamp.set(u64::MAX); 179 alarm.timestamp.set(u64::MAX);
170 180
171 // Call after clearing alarm, so the callback can set another alarm. 181 // Call after clearing alarm, so the callback can set another alarm.
172 if let Some((f, ctx)) = alarm.callback.get() { 182
173 f(ctx); 183 // safety:
184 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
185 // - other than that we only store valid function pointers into alarm.callback
186 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
187 f(alarm.ctx.get());
188 }
189
190 fn allocate_alarm(&self) -> Option<AlarmHandle> {
191 let id = self
192 .alarm_count
193 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
194 if x < ALARM_COUNT as u8 {
195 Some(x + 1)
196 } else {
197 None
198 }
199 });
200
201 match id {
202 Ok(id) => Some(unsafe { AlarmHandle::new(id) }),
203 Err(_) => None,
174 } 204 }
175 } 205 }
176 206
177 fn set_alarm_callback(&self, n: usize, callback: fn(*mut ()), ctx: *mut ()) { 207 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
178 critical_section::with(|cs| { 208 critical_section::with(|cs| {
179 let alarm = &self.alarms.borrow(cs)[n]; 209 let alarm = self.get_alarm(cs, alarm);
180 alarm.callback.set(Some((callback, ctx))); 210
211 // safety: it's OK to transmute a fn pointer into a raw pointer
212 let callback_ptr: *const () = unsafe { mem::transmute(callback) };
213
214 alarm.callback.set(callback_ptr);
215 alarm.ctx.set(ctx);
181 }) 216 })
182 } 217 }
183 218
184 fn set_alarm(&self, n: usize, timestamp: u64) { 219 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
185 critical_section::with(|cs| { 220 critical_section::with(|cs| {
186 let alarm = &self.alarms.borrow(cs)[n]; 221 let n = alarm.id() as _;
222 let alarm = self.get_alarm(cs, alarm);
187 alarm.timestamp.set(timestamp); 223 alarm.timestamp.set(timestamp);
188 224
189 let t = self.now(); 225 let t = self.now();
@@ -194,25 +230,30 @@ impl<T: Instance> RTC<T> {
194 return; 230 return;
195 } 231 }
196 232
197 let r = self.rtc.regs(); 233 let r = rtc();
198 234
199 // If it hasn't triggered yet, setup it in the compare channel. 235 // If it hasn't triggered yet, setup it in the compare channel.
236
237 // Write the CC value regardless of whether we're going to enable it now or not.
238 // This way, when we enable it later, the right value is already set.
239
240 // nrf52 docs say:
241 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
242 // To workaround this, we never write a timestamp smaller than N+3.
243 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
244 //
245 // It is impossible for rtc to tick more than once because
246 // - this code takes less time than 1 tick
247 // - it runs with interrupts disabled so nothing else can preempt it.
248 //
249 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
250 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
251 // and we don't do that here.
252 let safe_timestamp = timestamp.max(t + 3);
253 r.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) });
254
200 let diff = timestamp - t; 255 let diff = timestamp - t;
201 if diff < 0xc00000 { 256 if diff < 0xc00000 {
202 // nrf52 docs say:
203 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
204 // To workaround this, we never write a timestamp smaller than N+3.
205 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
206 //
207 // It is impossible for rtc to tick more than once because
208 // - this code takes less time than 1 tick
209 // - it runs with interrupts disabled so nothing else can preempt it.
210 //
211 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
212 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
213 // and we don't do that here.
214 let safe_timestamp = timestamp.max(t + 3);
215 r.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) });
216 r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); 257 r.intenset.write(|w| unsafe { w.bits(compare_n(n)) });
217 } else { 258 } else {
218 // If it's too far in the future, don't setup the compare channel yet. 259 // If it's too far in the future, don't setup the compare channel yet.
@@ -221,74 +262,34 @@ impl<T: Instance> RTC<T> {
221 } 262 }
222 }) 263 })
223 } 264 }
224
225 pub fn alarm0(&'static self) -> Alarm<T> {
226 Alarm { n: 0, rtc: self }
227 }
228 pub fn alarm1(&'static self) -> Alarm<T> {
229 Alarm { n: 1, rtc: self }
230 }
231 pub fn alarm2(&'static self) -> Alarm<T> {
232 Alarm { n: 2, rtc: self }
233 }
234}
235
236impl<T: Instance> embassy::time::Clock for RTC<T> {
237 fn now(&self) -> u64 {
238 // `period` MUST be read before `counter`, see comment at the top for details.
239 let period = self.period.load(Ordering::Relaxed);
240 compiler_fence(Ordering::Acquire);
241 let counter = self.rtc.regs().counter.read().bits();
242 calc_now(period, counter)
243 }
244} 265}
245 266
246pub struct Alarm<T: Instance> { 267struct RtcDriver;
247 n: usize, 268embassy::time_driver_impl!(RtcDriver);
248 rtc: &'static RTC<T>,
249}
250 269
251impl<T: Instance> embassy::time::Alarm for Alarm<T> { 270impl Driver for RtcDriver {
252 fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { 271 fn now() -> u64 {
253 self.rtc.set_alarm_callback(self.n, callback, ctx); 272 STATE.now()
254 } 273 }
255 274
256 fn set(&self, timestamp: u64) { 275 unsafe fn allocate_alarm() -> Option<AlarmHandle> {
257 self.rtc.set_alarm(self.n, timestamp); 276 STATE.allocate_alarm()
258 } 277 }
259 278
260 fn clear(&self) { 279 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
261 self.rtc.set_alarm(self.n, u64::MAX); 280 STATE.set_alarm_callback(alarm, callback, ctx)
262 } 281 }
263}
264 282
265mod sealed { 283 fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
266 use super::*; 284 STATE.set_alarm(alarm, timestamp)
267 pub trait Instance {
268 fn regs(&self) -> &pac::rtc0::RegisterBlock;
269 } 285 }
270} 286}
271 287
272macro_rules! impl_instance { 288#[interrupt]
273 ($type:ident, $irq:ident) => { 289fn RTC1() {
274 impl sealed::Instance for peripherals::$type { 290 STATE.on_interrupt()
275 fn regs(&self) -> &pac::rtc0::RegisterBlock {
276 unsafe { &*pac::$type::ptr() }
277 }
278 }
279 impl Instance for peripherals::$type {
280 type Interrupt = interrupt::$irq;
281 }
282 };
283} 291}
284 292
285/// Implemented by all RTC instances. 293pub(crate) fn init() {
286pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { 294 STATE.init()
287 /// The interrupt associated with this RTC instance.
288 type Interrupt: Interrupt;
289} 295}
290
291impl_instance!(RTC0, RTC0);
292impl_instance!(RTC1, RTC1);
293#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
294impl_instance!(RTC2, RTC2);
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index e2da226dd..5f0784071 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -22,7 +22,7 @@ defmt-error = [ ]
22embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] } 22embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] }
23embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 23embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
24embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} 24embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]}
25 25atomic-polyfill = { version = "0.1.2" }
26defmt = { version = "0.2.0", optional = true } 26defmt = { version = "0.2.0", optional = true }
27log = { version = "0.4.11", optional = true } 27log = { version = "0.4.11", optional = true }
28cortex-m-rt = "0.6.13" 28cortex-m-rt = "0.6.13"
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 10bf7158f..26ebbebfb 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -69,11 +69,6 @@ embassy_hal_common::peripherals! {
69 SPI0, 69 SPI0,
70 SPI1, 70 SPI1,
71 71
72 TIMER_ALARM0,
73 TIMER_ALARM1,
74 TIMER_ALARM2,
75 TIMER_ALARM3,
76
77 DMA_CH0, 72 DMA_CH0,
78 DMA_CH1, 73 DMA_CH1,
79 DMA_CH2, 74 DMA_CH2,
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index 5baa02607..71c59ec8d 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -1,6 +1,8 @@
1use atomic_polyfill::{AtomicU8, Ordering};
1use core::cell::Cell; 2use core::cell::Cell;
2use critical_section::CriticalSection; 3use critical_section::CriticalSection;
3use embassy::interrupt::{Interrupt, InterruptExt}; 4use embassy::interrupt::{Interrupt, InterruptExt};
5use embassy::time::driver::{AlarmHandle, Driver};
4use embassy::util::CriticalSectionMutex as Mutex; 6use embassy::util::CriticalSectionMutex as Mutex;
5 7
6use crate::{interrupt, pac}; 8use crate::{interrupt, pac};
@@ -18,6 +20,7 @@ const DUMMY_ALARM: AlarmState = AlarmState {
18}; 20};
19 21
20static ALARMS: Mutex<[AlarmState; ALARM_COUNT]> = Mutex::new([DUMMY_ALARM; ALARM_COUNT]); 22static ALARMS: Mutex<[AlarmState; ALARM_COUNT]> = Mutex::new([DUMMY_ALARM; ALARM_COUNT]);
23static NEXT_ALARM: AtomicU8 = AtomicU8::new(0);
21 24
22fn now() -> u64 { 25fn now() -> u64 {
23 loop { 26 loop {
@@ -32,60 +35,39 @@ fn now() -> u64 {
32 } 35 }
33} 36}
34 37
35struct Timer; 38struct TimerDriver;
36impl embassy::time::Clock for Timer { 39embassy::time_driver_impl!(TimerDriver);
37 fn now(&self) -> u64 {
38 now()
39 }
40}
41 40
42pub trait AlarmInstance { 41impl Driver for TimerDriver {
43 fn alarm_num(&self) -> usize; 42 fn now() -> u64 {
44} 43 now()
45
46impl AlarmInstance for crate::peripherals::TIMER_ALARM0 {
47 fn alarm_num(&self) -> usize {
48 0
49 }
50}
51impl AlarmInstance for crate::peripherals::TIMER_ALARM1 {
52 fn alarm_num(&self) -> usize {
53 1
54 }
55}
56impl AlarmInstance for crate::peripherals::TIMER_ALARM2 {
57 fn alarm_num(&self) -> usize {
58 2
59 }
60}
61impl AlarmInstance for crate::peripherals::TIMER_ALARM3 {
62 fn alarm_num(&self) -> usize {
63 3
64 } 44 }
65}
66 45
67pub struct Alarm<T: AlarmInstance> { 46 unsafe fn allocate_alarm() -> Option<AlarmHandle> {
68 inner: T, 47 let id = NEXT_ALARM.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
69} 48 if x < ALARM_COUNT as u8 {
49 Some(x + 1)
50 } else {
51 None
52 }
53 });
70 54
71impl<T: AlarmInstance> Alarm<T> { 55 match id {
72 pub fn new(inner: T) -> Self { 56 Ok(id) => Some(AlarmHandle::new(id)),
73 Self { inner } 57 Err(_) => None,
58 }
74 } 59 }
75}
76 60
77impl<T: AlarmInstance> embassy::time::Alarm for Alarm<T> { 61 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
78 fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { 62 let n = alarm.id() as usize;
79 let n = self.inner.alarm_num();
80 critical_section::with(|cs| { 63 critical_section::with(|cs| {
81 let alarm = &ALARMS.borrow(cs)[n]; 64 let alarm = &ALARMS.borrow(cs)[n];
82 alarm.callback.set(Some((callback, ctx))); 65 alarm.callback.set(Some((callback, ctx)));
83 }) 66 })
84 } 67 }
85 68
86 fn set(&self, timestamp: u64) { 69 fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
87 let n = self.inner.alarm_num(); 70 let n = alarm.id() as usize;
88
89 critical_section::with(|cs| { 71 critical_section::with(|cs| {
90 let alarm = &ALARMS.borrow(cs)[n]; 72 let alarm = &ALARMS.borrow(cs)[n];
91 alarm.timestamp.set(timestamp); 73 alarm.timestamp.set(timestamp);
@@ -105,10 +87,6 @@ impl<T: AlarmInstance> embassy::time::Alarm for Alarm<T> {
105 } 87 }
106 }) 88 })
107 } 89 }
108
109 fn clear(&self) {
110 self.set(u64::MAX);
111 }
112} 90}
113 91
114fn check_alarm(n: usize) { 92fn check_alarm(n: usize) {
@@ -162,8 +140,6 @@ pub unsafe fn init() {
162 interrupt::TIMER_IRQ_1::steal().enable(); 140 interrupt::TIMER_IRQ_1::steal().enable();
163 interrupt::TIMER_IRQ_2::steal().enable(); 141 interrupt::TIMER_IRQ_2::steal().enable();
164 interrupt::TIMER_IRQ_3::steal().enable(); 142 interrupt::TIMER_IRQ_3::steal().enable();
165
166 embassy::time::set_clock(&Timer);
167} 143}
168 144
169#[interrupt] 145#[interrupt]
diff --git a/embassy-std/src/lib.rs b/embassy-std/src/lib.rs
index 688054cb9..d85137e9a 100644
--- a/embassy-std/src/lib.rs
+++ b/embassy-std/src/lib.rs
@@ -1,6 +1,6 @@
1use embassy::executor::{raw, Spawner}; 1use embassy::executor::{raw, Spawner};
2use embassy::time::driver::{AlarmHandle, Driver};
2use embassy::time::TICKS_PER_SECOND; 3use embassy::time::TICKS_PER_SECOND;
3use embassy::time::{Alarm, Clock};
4use std::marker::PhantomData; 4use std::marker::PhantomData;
5use std::mem::MaybeUninit; 5use std::mem::MaybeUninit;
6use std::ptr; 6use std::ptr;
@@ -8,28 +8,31 @@ use std::sync::{Condvar, Mutex};
8use std::time::{Duration as StdDuration, Instant as StdInstant}; 8use std::time::{Duration as StdDuration, Instant as StdInstant};
9 9
10static mut CLOCK_ZERO: MaybeUninit<StdInstant> = MaybeUninit::uninit(); 10static mut CLOCK_ZERO: MaybeUninit<StdInstant> = MaybeUninit::uninit();
11struct StdClock; 11
12impl Clock for StdClock { 12static mut ALARM_AT: u64 = u64::MAX;
13 fn now(&self) -> u64 { 13static mut NEXT_ALARM_ID: u8 = 0;
14
15struct TimeDriver;
16embassy::time_driver_impl!(TimeDriver);
17
18impl Driver for TimeDriver {
19 fn now() -> u64 {
14 let zero = unsafe { CLOCK_ZERO.as_ptr().read() }; 20 let zero = unsafe { CLOCK_ZERO.as_ptr().read() };
15 let dur = StdInstant::now().duration_since(zero); 21 let dur = StdInstant::now().duration_since(zero);
16 dur.as_secs() * (TICKS_PER_SECOND as u64) 22 dur.as_secs() * (TICKS_PER_SECOND as u64)
17 + (dur.subsec_nanos() as u64) * (TICKS_PER_SECOND as u64) / 1_000_000_000 23 + (dur.subsec_nanos() as u64) * (TICKS_PER_SECOND as u64) / 1_000_000_000
18 } 24 }
19}
20 25
21static mut ALARM_AT: u64 = u64::MAX; 26 unsafe fn allocate_alarm() -> Option<AlarmHandle> {
22 27 let r = NEXT_ALARM_ID;
23pub struct StdAlarm; 28 NEXT_ALARM_ID += 1;
24impl Alarm for StdAlarm { 29 Some(AlarmHandle::new(r))
25 fn set_callback(&self, _callback: fn(*mut ()), _ctx: *mut ()) {}
26
27 fn set(&self, timestamp: u64) {
28 unsafe { ALARM_AT = timestamp }
29 } 30 }
30 31
31 fn clear(&self) { 32 fn set_alarm_callback(_alarm: AlarmHandle, _callback: fn(*mut ()), _ctx: *mut ()) {}
32 unsafe { ALARM_AT = u64::MAX } 33
34 fn set_alarm(_alarm: AlarmHandle, timestamp: u64) {
35 unsafe { ALARM_AT = ALARM_AT.min(timestamp) }
33 } 36 }
34} 37}
35 38
@@ -53,7 +56,8 @@ impl Signaler {
53 if alarm_at == u64::MAX { 56 if alarm_at == u64::MAX {
54 signaled = self.condvar.wait(signaled).unwrap(); 57 signaled = self.condvar.wait(signaled).unwrap();
55 } else { 58 } else {
56 let now = StdClock.now(); 59 unsafe { ALARM_AT = u64::MAX };
60 let now = TimeDriver::now();
57 if now >= alarm_at { 61 if now >= alarm_at {
58 break; 62 break;
59 } 63 }
@@ -92,7 +96,6 @@ impl Executor {
92 pub fn new() -> Self { 96 pub fn new() -> Self {
93 unsafe { 97 unsafe {
94 CLOCK_ZERO.as_mut_ptr().write(StdInstant::now()); 98 CLOCK_ZERO.as_mut_ptr().write(StdInstant::now());
95 embassy::time::set_clock(&StdClock);
96 } 99 }
97 100
98 Self { 101 Self {
@@ -107,7 +110,6 @@ impl Executor {
107 /// This function never returns. 110 /// This function never returns.
108 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 111 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
109 self.inner.set_signal_ctx(&self.signaler as *const _ as _); 112 self.inner.set_signal_ctx(&self.signaler as *const _ as _);
110 self.inner.set_alarm(&StdAlarm);
111 113
112 init(unsafe { self.inner.spawner() }); 114 init(unsafe { self.inner.spawner() });
113 115
diff --git a/embassy-stm32/src/clock.rs b/embassy-stm32/src/clock.rs
deleted file mode 100644
index 6c3175789..000000000
--- a/embassy-stm32/src/clock.rs
+++ /dev/null
@@ -1,372 +0,0 @@
1#![macro_use]
2
3use core::cell::Cell;
4use core::convert::TryInto;
5use core::sync::atomic::{compiler_fence, Ordering};
6
7use atomic_polyfill::AtomicU32;
8use embassy::interrupt::InterruptExt;
9use embassy::time::{Clock as EmbassyClock, TICKS_PER_SECOND};
10
11use crate::interrupt::{CriticalSection, Interrupt, Mutex};
12use crate::pac::timer::TimGp16;
13use crate::peripherals;
14use crate::rcc::RccPeripheral;
15use crate::time::Hertz;
16
17// Clock timekeeping works with something we call "periods", which are time intervals
18// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods.
19//
20// A `period` count is maintained in parallel to the Timer hardware `counter`, like this:
21// - `period` and `counter` start at 0
22// - `period` is incremented on overflow (at counter value 0)
23// - `period` is incremented "midway" between overflows (at counter value 0x8000)
24//
25// Therefore, when `period` is even, counter is in 0..0x7FFF. When odd, counter is in 0x8000..0xFFFF
26// This allows for now() to return the correct value even if it races an overflow.
27//
28// To get `now()`, `period` is read first, then `counter` is read. If the counter value matches
29// the expected range for the `period` parity, we're done. If it doesn't, this means that
30// a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value
31// corresponds to the next period.
32//
33// `period` is a 32bit integer, so It overflows on 2^32 * 2^15 / 32768 seconds of uptime, which is 136 years.
34fn calc_now(period: u32, counter: u16) -> u64 {
35 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
36}
37
38struct AlarmState {
39 timestamp: Cell<u64>,
40 #[allow(clippy::type_complexity)]
41 callback: Cell<Option<(fn(*mut ()), *mut ())>>,
42}
43
44impl AlarmState {
45 fn new() -> Self {
46 Self {
47 timestamp: Cell::new(u64::MAX),
48 callback: Cell::new(None),
49 }
50 }
51}
52
53const ALARM_COUNT: usize = 3;
54
55/// Clock timer that can be used by the executor and to set alarms.
56///
57/// It can work with Timers 2, 3, 4, 5. This timer works internally with a unit of 2^15 ticks, which
58/// means that if a call to [`embassy::time::Clock::now`] is blocked for that amount of ticks the
59/// returned value will be wrong (an old value). The current default tick rate is 32768 ticks per
60/// second.
61pub struct Clock<T: Instance> {
62 _inner: T,
63 irq: T::Interrupt,
64 /// Number of 2^23 periods elapsed since boot.
65 period: AtomicU32,
66 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
67 alarms: Mutex<[AlarmState; ALARM_COUNT]>,
68}
69
70impl<T: Instance> Clock<T> {
71 pub fn new(peripheral: T, irq: T::Interrupt) -> Self {
72 Self {
73 _inner: peripheral,
74 irq,
75 period: AtomicU32::new(0),
76 alarms: Mutex::new([AlarmState::new(), AlarmState::new(), AlarmState::new()]),
77 }
78 }
79
80 pub fn start(&'static self) {
81 let inner = T::inner();
82
83 T::enable();
84 T::reset();
85
86 let timer_freq = T::frequency();
87
88 // NOTE(unsafe) Critical section to use the unsafe methods
89 critical_section::with(|_| {
90 unsafe {
91 inner.prepare(timer_freq);
92 }
93
94 self.irq.set_handler_context(self as *const _ as *mut _);
95 self.irq.set_handler(|ptr| unsafe {
96 let this = &*(ptr as *const () as *const Self);
97 this.on_interrupt();
98 });
99 self.irq.unpend();
100 self.irq.enable();
101
102 unsafe {
103 inner.start_counter();
104 }
105 })
106 }
107
108 fn on_interrupt(&self) {
109 let inner = T::inner();
110
111 // NOTE(unsafe) Use critical section to access the methods
112 // XXX: reduce the size of this critical section ?
113 critical_section::with(|cs| unsafe {
114 if inner.overflow_interrupt_status() {
115 inner.overflow_clear_flag();
116 self.next_period();
117 }
118
119 // Half overflow
120 if inner.compare_interrupt_status(0) {
121 inner.compare_clear_flag(0);
122 self.next_period();
123 }
124
125 for n in 1..=ALARM_COUNT {
126 if inner.compare_interrupt_status(n) {
127 inner.compare_clear_flag(n);
128 self.trigger_alarm(n, cs);
129 }
130 }
131 })
132 }
133
134 fn next_period(&self) {
135 let inner = T::inner();
136
137 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
138 let t = (period as u64) << 15;
139
140 critical_section::with(move |cs| {
141 for n in 1..=ALARM_COUNT {
142 let alarm = &self.alarms.borrow(cs)[n - 1];
143 let at = alarm.timestamp.get();
144
145 let diff = at - t;
146 if diff < 0xc000 {
147 inner.set_compare(n, at as u16);
148 // NOTE(unsafe) We're in a critical section
149 unsafe {
150 inner.set_compare_interrupt(n, true);
151 }
152 }
153 }
154 })
155 }
156
157 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
158 let inner = T::inner();
159 // NOTE(unsafe) We have a critical section
160 unsafe {
161 inner.set_compare_interrupt(n, false);
162 }
163
164 let alarm = &self.alarms.borrow(cs)[n - 1];
165 alarm.timestamp.set(u64::MAX);
166
167 // Call after clearing alarm, so the callback can set another alarm.
168 if let Some((f, ctx)) = alarm.callback.get() {
169 f(ctx);
170 }
171 }
172
173 fn set_alarm_callback(&self, n: usize, callback: fn(*mut ()), ctx: *mut ()) {
174 critical_section::with(|cs| {
175 let alarm = &self.alarms.borrow(cs)[n - 1];
176 alarm.callback.set(Some((callback, ctx)));
177 })
178 }
179
180 fn set_alarm(&self, n: usize, timestamp: u64) {
181 critical_section::with(|cs| {
182 let inner = T::inner();
183
184 let alarm = &self.alarms.borrow(cs)[n - 1];
185 alarm.timestamp.set(timestamp);
186
187 let t = self.now();
188 if timestamp <= t {
189 self.trigger_alarm(n, cs);
190 return;
191 }
192
193 let diff = timestamp - t;
194 if diff < 0xc000 {
195 let safe_timestamp = timestamp.max(t + 3);
196 inner.set_compare(n, safe_timestamp as u16);
197
198 // NOTE(unsafe) We're in a critical section
199 unsafe {
200 inner.set_compare_interrupt(n, true);
201 }
202 } else {
203 unsafe {
204 inner.set_compare_interrupt(n, false);
205 }
206 }
207 })
208 }
209
210 pub fn alarm1(&'static self) -> Alarm<T> {
211 Alarm { n: 1, rtc: self }
212 }
213 pub fn alarm2(&'static self) -> Alarm<T> {
214 Alarm { n: 2, rtc: self }
215 }
216 pub fn alarm3(&'static self) -> Alarm<T> {
217 Alarm { n: 3, rtc: self }
218 }
219}
220
221impl<T: Instance> EmbassyClock for Clock<T> {
222 fn now(&self) -> u64 {
223 let inner = T::inner();
224
225 let period = self.period.load(Ordering::Relaxed);
226 compiler_fence(Ordering::Acquire);
227 let counter = inner.counter();
228 calc_now(period, counter)
229 }
230}
231
232pub struct Alarm<T: Instance> {
233 n: usize,
234 rtc: &'static Clock<T>,
235}
236
237impl<T: Instance> embassy::time::Alarm for Alarm<T> {
238 fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) {
239 self.rtc.set_alarm_callback(self.n, callback, ctx);
240 }
241
242 fn set(&self, timestamp: u64) {
243 self.rtc.set_alarm(self.n, timestamp);
244 }
245
246 fn clear(&self) {
247 self.rtc.set_alarm(self.n, u64::MAX);
248 }
249}
250
251pub struct TimerInner(pub(crate) TimGp16);
252
253impl TimerInner {
254 unsafe fn prepare(&self, timer_freq: Hertz) {
255 self.stop_and_reset();
256
257 let psc = timer_freq.0 / TICKS_PER_SECOND as u32 - 1;
258 let psc: u16 = psc.try_into().unwrap();
259
260 self.set_psc_arr(psc, u16::MAX);
261 // Mid-way point
262 self.set_compare(0, 0x8000);
263 self.set_compare_interrupt(0, true);
264 }
265
266 unsafe fn start_counter(&self) {
267 self.0.cr1().modify(|w| w.set_cen(true));
268 }
269
270 unsafe fn stop_and_reset(&self) {
271 let regs = self.0;
272
273 regs.cr1().modify(|w| w.set_cen(false));
274 regs.cnt().write(|w| w.set_cnt(0));
275 }
276
277 fn overflow_interrupt_status(&self) -> bool {
278 // NOTE(unsafe) Atomic read with no side-effects
279 unsafe { self.0.sr().read().uif() }
280 }
281
282 unsafe fn overflow_clear_flag(&self) {
283 self.0.sr().modify(|w| w.set_uif(false));
284 }
285
286 unsafe fn set_psc_arr(&self, psc: u16, arr: u16) {
287 use crate::pac::timer::vals::Urs;
288
289 let regs = self.0;
290
291 regs.psc().write(|w| w.set_psc(psc));
292 regs.arr().write(|w| w.set_arr(arr));
293
294 // Set URS, generate update and clear URS
295 regs.cr1().modify(|w| w.set_urs(Urs::COUNTERONLY));
296 regs.egr().write(|w| w.set_ug(true));
297 regs.cr1().modify(|w| w.set_urs(Urs::ANYEVENT));
298 }
299
300 fn compare_interrupt_status(&self, n: usize) -> bool {
301 if n > 3 {
302 false
303 } else {
304 // NOTE(unsafe) Atomic read with no side-effects
305 unsafe { self.0.sr().read().ccif(n) }
306 }
307 }
308
309 unsafe fn compare_clear_flag(&self, n: usize) {
310 if n > 3 {
311 return;
312 }
313 self.0.sr().modify(|w| w.set_ccif(n, false));
314 }
315
316 fn set_compare(&self, n: usize, value: u16) {
317 if n > 3 {
318 return;
319 }
320 // NOTE(unsafe) Atomic write
321 unsafe {
322 self.0.ccr(n).write(|w| w.set_ccr(value));
323 }
324 }
325
326 unsafe fn set_compare_interrupt(&self, n: usize, enable: bool) {
327 if n > 3 {
328 return;
329 }
330 self.0.dier().modify(|w| w.set_ccie(n, enable));
331 }
332
333 fn counter(&self) -> u16 {
334 // NOTE(unsafe) Atomic read with no side-effects
335 unsafe { self.0.cnt().read().cnt() }
336 }
337}
338
339// ------------------------------------------------------
340
341pub(crate) mod sealed {
342 use super::*;
343 pub trait Instance {
344 type Interrupt: Interrupt;
345
346 fn inner() -> TimerInner;
347 }
348}
349
350pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {}
351
352macro_rules! impl_timer {
353 ($inst:ident) => {
354 impl sealed::Instance for peripherals::$inst {
355 type Interrupt = crate::interrupt::$inst;
356
357 fn inner() -> crate::clock::TimerInner {
358 const INNER: TimerInner = TimerInner(crate::pac::$inst);
359 INNER
360 }
361 }
362
363 impl Instance for peripherals::$inst {}
364 };
365}
366
367crate::pac::peripherals!(
368 (timer, TIM2) => { impl_timer!(TIM2); };
369 (timer, TIM3) => { impl_timer!(TIM3); };
370 (timer, TIM4) => { impl_timer!(TIM4); };
371 (timer, TIM5) => { impl_timer!(TIM5); };
372);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index a58bc3697..28bfcbaac 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -20,13 +20,12 @@ pub mod time;
20pub mod dma; 20pub mod dma;
21pub mod gpio; 21pub mod gpio;
22pub mod rcc; 22pub mod rcc;
23mod time_driver;
23 24
24// Sometimes-present hardware 25// Sometimes-present hardware
25 26
26#[cfg(adc)] 27#[cfg(adc)]
27pub mod adc; 28pub mod adc;
28#[cfg(timer)]
29pub mod clock;
30#[cfg(dac)] 29#[cfg(dac)]
31pub mod dac; 30pub mod dac;
32#[cfg(dbgmcu)] 31#[cfg(dbgmcu)]
@@ -87,6 +86,9 @@ pub fn init(config: Config) -> Peripherals {
87 exti::init(); 86 exti::init();
88 87
89 rcc::init(config.rcc); 88 rcc::init(config.rcc);
89
90 // must be after rcc init
91 time_driver::init();
90 } 92 }
91 93
92 p 94 p
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
new file mode 100644
index 000000000..16c871e8d
--- /dev/null
+++ b/embassy-stm32/src/time_driver.rs
@@ -0,0 +1,319 @@
1use atomic_polyfill::{AtomicU32, AtomicU8};
2use core::cell::Cell;
3use core::convert::TryInto;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::{mem, ptr};
6use embassy::interrupt::InterruptExt;
7use embassy::time::driver::{AlarmHandle, Driver};
8use embassy::time::TICKS_PER_SECOND;
9use stm32_metapac::timer::regs;
10
11use crate::interrupt;
12use crate::interrupt::{CriticalSection, Interrupt, Mutex};
13use crate::pac::timer::{vals, TimGp16};
14use crate::peripherals;
15use crate::rcc::sealed::RccPeripheral;
16
17use self::sealed::Instance as _;
18
19const ALARM_COUNT: usize = 3;
20type T = peripherals::TIM3;
21
22// Clock timekeeping works with something we call "periods", which are time intervals
23// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods.
24//
25// A `period` count is maintained in parallel to the Timer hardware `counter`, like this:
26// - `period` and `counter` start at 0
27// - `period` is incremented on overflow (at counter value 0)
28// - `period` is incremented "midway" between overflows (at counter value 0x8000)
29//
30// Therefore, when `period` is even, counter is in 0..0x7FFF. When odd, counter is in 0x8000..0xFFFF
31// This allows for now() to return the correct value even if it races an overflow.
32//
33// To get `now()`, `period` is read first, then `counter` is read. If the counter value matches
34// the expected range for the `period` parity, we're done. If it doesn't, this means that
35// a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value
36// corresponds to the next period.
37//
38// `period` is a 32bit integer, so It overflows on 2^32 * 2^15 / 32768 seconds of uptime, which is 136 years.
39fn calc_now(period: u32, counter: u16) -> u64 {
40 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
41}
42
43struct AlarmState {
44 timestamp: Cell<u64>,
45
46 // This is really a Option<(fn(*mut ()), *mut ())>
47 // but fn pointers aren't allowed in const yet
48 callback: Cell<*const ()>,
49 ctx: Cell<*mut ()>,
50}
51
52unsafe impl Send for AlarmState {}
53
54impl AlarmState {
55 const fn new() -> Self {
56 Self {
57 timestamp: Cell::new(u64::MAX),
58 callback: Cell::new(ptr::null()),
59 ctx: Cell::new(ptr::null_mut()),
60 }
61 }
62}
63
64struct State {
65 /// Number of 2^15 periods elapsed since boot.
66 period: AtomicU32,
67 alarm_count: AtomicU8,
68 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
69 alarms: Mutex<[AlarmState; ALARM_COUNT]>,
70}
71
72const ALARM_STATE_NEW: AlarmState = AlarmState::new();
73static STATE: State = State {
74 period: AtomicU32::new(0),
75 alarm_count: AtomicU8::new(0),
76 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]),
77};
78
79impl State {
80 fn init(&'static self) {
81 let r = T::regs();
82
83 T::enable();
84 T::reset();
85
86 let timer_freq = T::frequency();
87
88 // NOTE(unsafe) Critical section to use the unsafe methods
89 critical_section::with(|_| unsafe {
90 r.cr1().modify(|w| w.set_cen(false));
91 r.cnt().write(|w| w.set_cnt(0));
92
93 let psc = timer_freq.0 / TICKS_PER_SECOND as u32 - 1;
94 let psc: u16 = psc.try_into().unwrap();
95
96 r.psc().write(|w| w.set_psc(psc));
97 r.arr().write(|w| w.set_arr(u16::MAX));
98
99 // Set URS, generate update and clear URS
100 r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTERONLY));
101 r.egr().write(|w| w.set_ug(true));
102 r.cr1().modify(|w| w.set_urs(vals::Urs::ANYEVENT));
103
104 // Mid-way point
105 r.ccr(0).write(|w| w.set_ccr(0x8000));
106
107 // Enable CC0, disable others
108 r.dier().write(|w| w.set_ccie(0, true));
109
110 let irq: <T as sealed::Instance>::Interrupt = core::mem::transmute(());
111 irq.unpend();
112 irq.enable();
113
114 r.cr1().modify(|w| w.set_cen(true));
115 })
116 }
117
118 fn on_interrupt(&self) {
119 let r = T::regs();
120
121 // NOTE(unsafe) Use critical section to access the methods
122 // XXX: reduce the size of this critical section ?
123 critical_section::with(|cs| unsafe {
124 let sr = r.sr().read();
125 let dier = r.dier().read();
126
127 // Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT.
128 // Other approaches such as writing all zeros, or RMWing won't work, they can
129 // miss interrupts.
130 r.sr().write_value(regs::SrGp(!sr.0));
131
132 if sr.uif() {
133 self.next_period();
134 }
135
136 // Half overflow
137 if sr.ccif(0) {
138 self.next_period();
139 }
140
141 for n in 0..ALARM_COUNT {
142 if sr.ccif(n + 1) && dier.ccie(n + 1) {
143 self.trigger_alarm(n, cs);
144 }
145 }
146 })
147 }
148
149 fn next_period(&self) {
150 let r = T::regs();
151
152 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
153 let t = (period as u64) << 15;
154
155 critical_section::with(move |cs| unsafe {
156 r.dier().modify(move |w| {
157 for n in 0..ALARM_COUNT {
158 let alarm = &self.alarms.borrow(cs)[n];
159 let at = alarm.timestamp.get();
160
161 if at < t + 0xc000 {
162 // just enable it. `set_alarm` has already set the correct CCR val.
163 w.set_ccie(n + 1, true);
164 }
165 }
166 })
167 })
168 }
169
170 fn now(&self) -> u64 {
171 let r = T::regs();
172
173 let period = self.period.load(Ordering::Relaxed);
174 compiler_fence(Ordering::Acquire);
175 // NOTE(unsafe) Atomic read with no side-effects
176 let counter = unsafe { r.cnt().read().cnt() };
177 calc_now(period, counter)
178 }
179
180 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
181 // safety: we're allowed to assume the AlarmState is created by us, and
182 // we never create one that's out of bounds.
183 unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) }
184 }
185
186 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
187 let alarm = &self.alarms.borrow(cs)[n];
188 alarm.timestamp.set(u64::MAX);
189
190 // Call after clearing alarm, so the callback can set another alarm.
191
192 // safety:
193 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
194 // - other than that we only store valid function pointers into alarm.callback
195 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
196 f(alarm.ctx.get());
197 }
198
199 fn allocate_alarm(&self) -> Option<AlarmHandle> {
200 let id = self
201 .alarm_count
202 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
203 if x < ALARM_COUNT as u8 {
204 Some(x + 1)
205 } else {
206 None
207 }
208 });
209
210 match id {
211 Ok(id) => Some(unsafe { AlarmHandle::new(id) }),
212 Err(_) => None,
213 }
214 }
215
216 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
217 critical_section::with(|cs| {
218 let alarm = self.get_alarm(cs, alarm);
219
220 // safety: it's OK to transmute a fn pointer into a raw pointer
221 let callback_ptr: *const () = unsafe { mem::transmute(callback) };
222
223 alarm.callback.set(callback_ptr);
224 alarm.ctx.set(ctx);
225 })
226 }
227
228 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
229 critical_section::with(|cs| {
230 let r = T::regs();
231
232 let n = alarm.id() as _;
233 let alarm = self.get_alarm(cs, alarm);
234 alarm.timestamp.set(timestamp);
235
236 let t = self.now();
237 if timestamp <= t {
238 unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) };
239 self.trigger_alarm(n, cs);
240 return;
241 }
242
243 let safe_timestamp = timestamp.max(t + 3);
244
245 // Write the CCR value regardless of whether we're going to enable it now or not.
246 // This way, when we enable it later, the right value is already set.
247 unsafe { r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)) };
248
249 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
250 let diff = timestamp - t;
251 // NOTE(unsafe) We're in a critical section
252 unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) };
253 })
254 }
255}
256
257struct RtcDriver;
258embassy::time_driver_impl!(RtcDriver);
259
260impl Driver for RtcDriver {
261 fn now() -> u64 {
262 STATE.now()
263 }
264
265 unsafe fn allocate_alarm() -> Option<AlarmHandle> {
266 STATE.allocate_alarm()
267 }
268
269 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
270 STATE.set_alarm_callback(alarm, callback, ctx)
271 }
272
273 fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
274 STATE.set_alarm(alarm, timestamp)
275 }
276}
277
278#[interrupt]
279fn TIM3() {
280 STATE.on_interrupt()
281}
282
283pub(crate) fn init() {
284 STATE.init()
285}
286
287// ------------------------------------------------------
288
289pub(crate) mod sealed {
290 use super::*;
291 pub trait Instance {
292 type Interrupt: Interrupt;
293
294 fn regs() -> TimGp16;
295 }
296}
297
298pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {}
299
300macro_rules! impl_timer {
301 ($inst:ident) => {
302 impl sealed::Instance for peripherals::$inst {
303 type Interrupt = crate::interrupt::$inst;
304
305 fn regs() -> TimGp16 {
306 crate::pac::$inst
307 }
308 }
309
310 impl Instance for peripherals::$inst {}
311 };
312}
313
314crate::pac::peripherals!(
315 (timer, TIM2) => { impl_timer!(TIM2); };
316 (timer, TIM3) => { impl_timer!(TIM3); };
317 (timer, TIM4) => { impl_timer!(TIM4); };
318 (timer, TIM5) => { impl_timer!(TIM5); };
319);
diff --git a/embassy/src/executor/mod.rs b/embassy/src/executor/mod.rs
index 771f75ee8..ee05b6760 100644
--- a/embassy/src/executor/mod.rs
+++ b/embassy/src/executor/mod.rs
@@ -109,18 +109,13 @@ pub struct Executor {
109} 109}
110 110
111impl Executor { 111impl Executor {
112 pub const fn new() -> Self { 112 pub fn new() -> Self {
113 Self { 113 Self {
114 inner: raw::Executor::new(|_| cortex_m::asm::sev(), ptr::null_mut()), 114 inner: raw::Executor::new(|_| cortex_m::asm::sev(), ptr::null_mut()),
115 not_send: PhantomData, 115 not_send: PhantomData,
116 } 116 }
117 } 117 }
118 118
119 #[cfg(feature = "time")]
120 pub fn set_alarm(&mut self, alarm: &'static dyn crate::time::Alarm) {
121 self.inner.set_alarm(alarm);
122 }
123
124 /// Runs the executor. 119 /// Runs the executor.
125 /// 120 ///
126 /// This function never returns. 121 /// This function never returns.
@@ -161,11 +156,6 @@ impl<I: Interrupt> InterruptExecutor<I> {
161 } 156 }
162 } 157 }
163 158
164 #[cfg(feature = "time")]
165 pub fn set_alarm(&mut self, alarm: &'static dyn crate::time::Alarm) {
166 self.inner.set_alarm(alarm);
167 }
168
169 /// Start the executor. 159 /// Start the executor.
170 /// 160 ///
171 /// `init` is called in the interrupt context, then the interrupt is 161 /// `init` is called in the interrupt context, then the interrupt is
diff --git a/embassy/src/executor/raw.rs b/embassy/src/executor/raw.rs
index cd2f0446d..fac46d1f4 100644
--- a/embassy/src/executor/raw.rs
+++ b/embassy/src/executor/raw.rs
@@ -15,7 +15,9 @@ use super::SpawnToken;
15#[cfg(feature = "time")] 15#[cfg(feature = "time")]
16use super::timer_queue::{TimerQueue, TimerQueueItem}; 16use super::timer_queue::{TimerQueue, TimerQueueItem};
17#[cfg(feature = "time")] 17#[cfg(feature = "time")]
18use crate::time::{Alarm, Instant}; 18use crate::time::driver::{self, AlarmHandle};
19#[cfg(feature = "time")]
20use crate::time::Instant;
19 21
20/// Task is spawned (has a future) 22/// Task is spawned (has a future)
21pub(crate) const STATE_SPAWNED: u32 = 1 << 0; 23pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
@@ -169,11 +171,16 @@ pub struct Executor {
169 #[cfg(feature = "time")] 171 #[cfg(feature = "time")]
170 timer_queue: TimerQueue, 172 timer_queue: TimerQueue,
171 #[cfg(feature = "time")] 173 #[cfg(feature = "time")]
172 alarm: Option<&'static dyn Alarm>, 174 alarm: AlarmHandle,
173} 175}
174 176
175impl Executor { 177impl Executor {
176 pub const fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { 178 pub fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self {
179 #[cfg(feature = "time")]
180 let alarm = unsafe { unwrap!(driver::allocate_alarm()) };
181 #[cfg(feature = "time")]
182 driver::set_alarm_callback(alarm, signal_fn, signal_ctx);
183
177 Self { 184 Self {
178 run_queue: RunQueue::new(), 185 run_queue: RunQueue::new(),
179 signal_fn, 186 signal_fn,
@@ -182,15 +189,10 @@ impl Executor {
182 #[cfg(feature = "time")] 189 #[cfg(feature = "time")]
183 timer_queue: TimerQueue::new(), 190 timer_queue: TimerQueue::new(),
184 #[cfg(feature = "time")] 191 #[cfg(feature = "time")]
185 alarm: None, 192 alarm,
186 } 193 }
187 } 194 }
188 195
189 #[cfg(feature = "time")]
190 pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) {
191 self.alarm = Some(alarm);
192 }
193
194 pub fn set_signal_ctx(&mut self, signal_ctx: *mut ()) { 196 pub fn set_signal_ctx(&mut self, signal_ctx: *mut ()) {
195 self.signal_ctx = signal_ctx; 197 self.signal_ctx = signal_ctx;
196 } 198 }
@@ -209,11 +211,9 @@ impl Executor {
209 211
210 pub unsafe fn run_queued(&'static self) { 212 pub unsafe fn run_queued(&'static self) {
211 #[cfg(feature = "time")] 213 #[cfg(feature = "time")]
212 if self.alarm.is_some() { 214 self.timer_queue.dequeue_expired(Instant::now(), |p| {
213 self.timer_queue.dequeue_expired(Instant::now(), |p| { 215 p.as_ref().enqueue();
214 p.as_ref().enqueue(); 216 });
215 });
216 }
217 217
218 self.run_queue.dequeue_all(|p| { 218 self.run_queue.dequeue_all(|p| {
219 let task = p.as_ref(); 219 let task = p.as_ref();
@@ -239,13 +239,12 @@ impl Executor {
239 self.timer_queue.update(p); 239 self.timer_queue.update(p);
240 }); 240 });
241 241
242 // If this is in the past, set_alarm will immediately trigger the alarm,
243 // which will make the wfe immediately return so we do another loop iteration.
244 #[cfg(feature = "time")] 242 #[cfg(feature = "time")]
245 if let Some(alarm) = self.alarm { 243 {
244 // If this is in the past, set_alarm will immediately trigger the alarm,
245 // which will make the wfe immediately return so we do another loop iteration.
246 let next_expiration = self.timer_queue.next_expiration(); 246 let next_expiration = self.timer_queue.next_expiration();
247 alarm.set_callback(self.signal_fn, self.signal_ctx); 247 driver::set_alarm(self.alarm, next_expiration.as_ticks());
248 alarm.set(next_expiration.as_ticks());
249 } 248 }
250 } 249 }
251 250
diff --git a/embassy/src/time/driver.rs b/embassy/src/time/driver.rs
new file mode 100644
index 000000000..b09cffd8c
--- /dev/null
+++ b/embassy/src/time/driver.rs
@@ -0,0 +1,118 @@
1/// Alarm handle, assigned by the driver.
2#[derive(Clone, Copy)]
3pub struct AlarmHandle {
4 id: u8,
5}
6
7impl AlarmHandle {
8 /// Create an AlarmHandle
9 ///
10 /// Safety: May only be called by the current global Driver impl.
11 /// The impl is allowed to rely on the fact that all `AlarmHandle` instances
12 /// are created by itself in unsafe code (e.g. indexing operations)
13 pub unsafe fn new(id: u8) -> Self {
14 Self { id }
15 }
16
17 /// Get the ID of the AlarmHandle.
18 pub fn id(&self) -> u8 {
19 self.id
20 }
21}
22
23/// Time driver
24pub trait Driver {
25 /// Return the current timestamp in ticks.
26 /// This is guaranteed to be monotonic, i.e. a call to now() will always return
27 /// a greater or equal value than earler calls.
28 fn now() -> u64;
29
30 /// Try allocating an alarm handle. Returns None if no alarms left.
31 /// Initially the alarm has no callback set, and a null `ctx` pointer.
32 ///
33 /// # Safety
34 /// It is UB to make the alarm fire before setting a callback.
35 unsafe fn allocate_alarm() -> Option<AlarmHandle>;
36
37 /// Sets the callback function to be called when the alarm triggers.
38 /// The callback may be called from any context (interrupt or thread mode).
39 fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
40
41 /// Sets an alarm at the given timestamp. When the current timestamp reaches that
42 /// timestamp, the provided callback funcion will be called.
43 ///
44 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
45 ///
46 /// Only one alarm can be active at a time. This overwrites any previously-set alarm if any.
47 fn set_alarm(alarm: AlarmHandle, timestamp: u64);
48}
49
50extern "Rust" {
51 fn _embassy_time_now() -> u64;
52 fn _embassy_time_allocate_alarm() -> Option<AlarmHandle>;
53 fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
54 fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64);
55}
56
57pub(crate) fn now() -> u64 {
58 unsafe { _embassy_time_now() }
59}
60/// Safety: it is UB to make the alarm fire before setting a callback.
61pub(crate) unsafe fn allocate_alarm() -> Option<AlarmHandle> {
62 _embassy_time_allocate_alarm()
63}
64pub(crate) fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
65 unsafe { _embassy_time_set_alarm_callback(alarm, callback, ctx) }
66}
67pub(crate) fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
68 unsafe { _embassy_time_set_alarm(alarm, timestamp) }
69}
70
71/// Set the time Driver implementation.
72///
73/// # Example
74///
75/// ```
76/// struct MyDriver;
77/// embassy::time_driver_impl!(MyDriver);
78///
79/// unsafe impl embassy::time::driver::Driver for MyDriver {
80/// fn now() -> u64 {
81/// todo!()
82/// }
83/// unsafe fn allocate_alarm() -> Option<AlarmHandle> {
84/// todo!()
85/// }
86/// fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
87/// todo!()
88/// }
89/// fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
90/// todo!()
91/// }
92/// }
93///
94#[macro_export]
95macro_rules! time_driver_impl {
96 ($t: ty) => {
97 #[no_mangle]
98 fn _embassy_time_now() -> u64 {
99 <$t as $crate::time::driver::Driver>::now()
100 }
101 #[no_mangle]
102 unsafe fn _embassy_time_allocate_alarm() -> Option<AlarmHandle> {
103 <$t as $crate::time::driver::Driver>::allocate_alarm()
104 }
105 #[no_mangle]
106 fn _embassy_time_set_alarm_callback(
107 alarm: AlarmHandle,
108 callback: fn(*mut ()),
109 ctx: *mut (),
110 ) {
111 <$t as $crate::time::driver::Driver>::set_alarm_callback(alarm, callback, ctx)
112 }
113 #[no_mangle]
114 fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) {
115 <$t as $crate::time::driver::Driver>::set_alarm(alarm, timestamp)
116 }
117 };
118}
diff --git a/embassy/src/time/instant.rs b/embassy/src/time/instant.rs
index 61a61defe..3d430d886 100644
--- a/embassy/src/time/instant.rs
+++ b/embassy/src/time/instant.rs
@@ -1,8 +1,7 @@
1use core::fmt; 1use core::fmt;
2use core::ops::{Add, AddAssign, Sub, SubAssign}; 2use core::ops::{Add, AddAssign, Sub, SubAssign};
3 3
4use super::TICKS_PER_SECOND; 4use super::{driver, Duration, TICKS_PER_SECOND};
5use super::{now, Duration};
6 5
7#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))] 7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -17,7 +16,9 @@ impl Instant {
17 16
18 /// Returns an Instant representing the current time. 17 /// Returns an Instant representing the current time.
19 pub fn now() -> Instant { 18 pub fn now() -> Instant {
20 Instant { ticks: now() } 19 Instant {
20 ticks: driver::now(),
21 }
21 } 22 }
22 23
23 /// Instant as clock ticks since MCU start. 24 /// Instant as clock ticks since MCU start.
diff --git a/embassy/src/time/mod.rs b/embassy/src/time/mod.rs
index d9777c45b..f5ad1b3ff 100644
--- a/embassy/src/time/mod.rs
+++ b/embassy/src/time/mod.rs
@@ -1,17 +1,15 @@
1//! Time abstractions 1//! Time abstractions
2//! To use these abstractions, first call `set_clock` with an instance of an [Clock](trait.Clock.html). 2
3//!
4mod delay; 3mod delay;
4pub mod driver;
5mod duration; 5mod duration;
6mod instant; 6mod instant;
7mod timer; 7mod timer;
8mod traits;
9 8
10pub use delay::{block_for, Delay}; 9pub use delay::{block_for, Delay};
11pub use duration::Duration; 10pub use duration::Duration;
12pub use instant::Instant; 11pub use instant::Instant;
13pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; 12pub use timer::{with_timeout, Ticker, TimeoutError, Timer};
14pub use traits::*;
15 13
16#[cfg(feature = "time-tick-1000hz")] 14#[cfg(feature = "time-tick-1000hz")]
17pub const TICKS_PER_SECOND: u64 = 1_000; 15pub const TICKS_PER_SECOND: u64 = 1_000;
@@ -21,19 +19,3 @@ pub const TICKS_PER_SECOND: u64 = 32_768;
21 19
22#[cfg(feature = "time-tick-1mhz")] 20#[cfg(feature = "time-tick-1mhz")]
23pub const TICKS_PER_SECOND: u64 = 1_000_000; 21pub const TICKS_PER_SECOND: u64 = 1_000_000;
24
25static mut CLOCK: Option<&'static dyn Clock> = None;
26
27/// Sets the clock used for the timing abstractions
28///
29/// Safety: Sets a mutable global.
30pub unsafe fn set_clock(clock: &'static dyn Clock) {
31 CLOCK = Some(clock);
32}
33
34/// Return the current timestamp in ticks.
35/// This is guaranteed to be monotonic, i.e. a call to now() will always return
36/// a greater or equal value than earler calls.
37pub(crate) fn now() -> u64 {
38 unsafe { unwrap!(CLOCK, "No clock set").now() }
39}
diff --git a/embassy/src/time/traits.rs b/embassy/src/time/traits.rs
deleted file mode 100644
index 4c6134c3c..000000000
--- a/embassy/src/time/traits.rs
+++ /dev/null
@@ -1,32 +0,0 @@
1/// Monotonic clock
2pub trait Clock {
3 /// Return the current timestamp in ticks.
4 /// This is guaranteed to be monotonic, i.e. a call to now() will always return
5 /// a greater or equal value than earler calls.
6 fn now(&self) -> u64;
7}
8
9impl<T: Clock + ?Sized> Clock for &T {
10 fn now(&self) -> u64 {
11 T::now(self)
12 }
13}
14
15/// Trait to register a callback at a given timestamp.
16pub trait Alarm {
17 /// Sets the callback function to be called when the alarm triggers.
18 /// The callback may be called from any context (interrupt or thread mode).
19 fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ());
20
21 /// Sets an alarm at the given timestamp. When the clock reaches that
22 /// timestamp, the provided callback funcion will be called.
23 ///
24 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
25 ///
26 /// Only one alarm can be active at a time. This overwrites any previously-set alarm if any.
27 fn set(&self, timestamp: u64);
28
29 /// Clears the previously-set alarm.
30 /// If no alarm was set, this is a noop.
31 fn clear(&self);
32}
diff --git a/examples/nrf/src/bin/blinky.rs b/examples/nrf/src/bin/blinky.rs
index 77b08b09b..6d4561beb 100644
--- a/examples/nrf/src/bin/blinky.rs
+++ b/examples/nrf/src/bin/blinky.rs
@@ -6,7 +6,6 @@
6#[path = "../example_common.rs"] 6#[path = "../example_common.rs"]
7mod example_common; 7mod example_common;
8 8
9use defmt::panic;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy::time::{Duration, Timer}; 10use embassy::time::{Duration, Timer};
12use embassy_nrf::gpio::{Level, Output, OutputDrive}; 11use embassy_nrf::gpio::{Level, Output, OutputDrive};
diff --git a/examples/nrf/src/bin/executor_fairness_test.rs b/examples/nrf/src/bin/executor_fairness_test.rs
index d874013f6..2d81a7551 100644
--- a/examples/nrf/src/bin/executor_fairness_test.rs
+++ b/examples/nrf/src/bin/executor_fairness_test.rs
@@ -8,10 +8,9 @@ mod example_common;
8use example_common::*; 8use example_common::*;
9 9
10use core::task::Poll; 10use core::task::Poll;
11use defmt::panic;
12use embassy::executor::Spawner; 11use embassy::executor::Spawner;
13use embassy::time::{Duration, Instant, Timer}; 12use embassy::time::{Duration, Instant, Timer};
14use embassy_nrf::{interrupt, Peripherals}; 13use embassy_nrf::Peripherals;
15 14
16#[embassy::task] 15#[embassy::task]
17async fn run1() { 16async fn run1() {
diff --git a/examples/nrf/src/bin/gpiote_channel.rs b/examples/nrf/src/bin/gpiote_channel.rs
index a132f846e..a96523e65 100644
--- a/examples/nrf/src/bin/gpiote_channel.rs
+++ b/examples/nrf/src/bin/gpiote_channel.rs
@@ -7,11 +7,10 @@
7mod example_common; 7mod example_common;
8use example_common::*; 8use example_common::*;
9 9
10use defmt::panic;
11use embassy::executor::Spawner; 10use embassy::executor::Spawner;
12use embassy_nrf::gpio::{Input, Pull}; 11use embassy_nrf::gpio::{Input, Pull};
13use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; 12use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
14use embassy_nrf::{interrupt, Peripherals}; 13use embassy_nrf::Peripherals;
15 14
16#[embassy::main] 15#[embassy::main]
17async fn main(_spawner: Spawner, p: Peripherals) { 16async fn main(_spawner: Spawner, p: Peripherals) {
diff --git a/examples/nrf/src/bin/gpiote_port.rs b/examples/nrf/src/bin/gpiote_port.rs
index a782d8935..700247d37 100644
--- a/examples/nrf/src/bin/gpiote_port.rs
+++ b/examples/nrf/src/bin/gpiote_port.rs
@@ -6,12 +6,10 @@
6#[path = "../example_common.rs"] 6#[path = "../example_common.rs"]
7mod example_common; 7mod example_common;
8 8
9use defmt::panic;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy::traits::gpio::{WaitForHigh, WaitForLow}; 10use embassy::traits::gpio::{WaitForHigh, WaitForLow};
12use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; 11use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull};
13use embassy_nrf::gpiote::PortInput; 12use embassy_nrf::gpiote::PortInput;
14use embassy_nrf::interrupt;
15use embassy_nrf::Peripherals; 13use embassy_nrf::Peripherals;
16use example_common::*; 14use example_common::*;
17 15
diff --git a/examples/nrf/src/bin/mpsc.rs b/examples/nrf/src/bin/mpsc.rs
index c4c0572bd..e31754eb8 100644
--- a/examples/nrf/src/bin/mpsc.rs
+++ b/examples/nrf/src/bin/mpsc.rs
@@ -6,7 +6,6 @@
6#[path = "../example_common.rs"] 6#[path = "../example_common.rs"]
7mod example_common; 7mod example_common;
8 8
9use defmt::panic;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy::time::{Duration, Timer}; 10use embassy::time::{Duration, Timer};
12use embassy::util::mpsc::TryRecvError; 11use embassy::util::mpsc::TryRecvError;
diff --git a/examples/nrf/src/bin/multiprio.rs b/examples/nrf/src/bin/multiprio.rs
index 7ce79168b..b91bbb740 100644
--- a/examples/nrf/src/bin/multiprio.rs
+++ b/examples/nrf/src/bin/multiprio.rs
@@ -68,7 +68,7 @@ use embassy::executor::{Executor, InterruptExecutor};
68use embassy::interrupt::InterruptExt; 68use embassy::interrupt::InterruptExt;
69use embassy::time::{Duration, Instant, Timer}; 69use embassy::time::{Duration, Instant, Timer};
70use embassy::util::Forever; 70use embassy::util::Forever;
71use embassy_nrf::{interrupt, peripherals, rtc}; 71use embassy_nrf::interrupt;
72 72
73#[embassy::task] 73#[embassy::task]
74async fn run_high() { 74async fn run_high() {
@@ -112,30 +112,20 @@ async fn run_low() {
112 } 112 }
113} 113}
114 114
115static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
116static ALARM_HIGH: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
117static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new(); 115static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new();
118static ALARM_MED: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
119static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new(); 116static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new();
120static ALARM_LOW: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
121static EXECUTOR_LOW: Forever<Executor> = Forever::new(); 117static EXECUTOR_LOW: Forever<Executor> = Forever::new();
122 118
123#[entry] 119#[entry]
124fn main() -> ! { 120fn main() -> ! {
125 info!("Hello World!"); 121 info!("Hello World!");
126 122
127 let p = embassy_nrf::init(Default::default()); 123 let _p = embassy_nrf::init(Default::default());
128
129 let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
130 rtc.start();
131 unsafe { embassy::time::set_clock(rtc) };
132 124
133 // High-priority executor: SWI1_EGU1, priority level 6 125 // High-priority executor: SWI1_EGU1, priority level 6
134 let irq = interrupt::take!(SWI1_EGU1); 126 let irq = interrupt::take!(SWI1_EGU1);
135 irq.set_priority(interrupt::Priority::P6); 127 irq.set_priority(interrupt::Priority::P6);
136 let alarm = ALARM_HIGH.put(rtc.alarm2());
137 let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq)); 128 let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
138 executor.set_alarm(alarm);
139 executor.start(|spawner| { 129 executor.start(|spawner| {
140 unwrap!(spawner.spawn(run_high())); 130 unwrap!(spawner.spawn(run_high()));
141 }); 131 });
@@ -143,17 +133,13 @@ fn main() -> ! {
143 // Medium-priority executor: SWI0_EGU0, priority level 7 133 // Medium-priority executor: SWI0_EGU0, priority level 7
144 let irq = interrupt::take!(SWI0_EGU0); 134 let irq = interrupt::take!(SWI0_EGU0);
145 irq.set_priority(interrupt::Priority::P7); 135 irq.set_priority(interrupt::Priority::P7);
146 let alarm = ALARM_MED.put(rtc.alarm1());
147 let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq)); 136 let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
148 executor.set_alarm(alarm);
149 executor.start(|spawner| { 137 executor.start(|spawner| {
150 unwrap!(spawner.spawn(run_med())); 138 unwrap!(spawner.spawn(run_med()));
151 }); 139 });
152 140
153 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
154 let alarm = ALARM_LOW.put(rtc.alarm0());
155 let executor = EXECUTOR_LOW.put(Executor::new()); 142 let executor = EXECUTOR_LOW.put(Executor::new());
156 executor.set_alarm(alarm);
157 executor.run(|spawner| { 143 executor.run(|spawner| {
158 unwrap!(spawner.spawn(run_low())); 144 unwrap!(spawner.spawn(run_low()));
159 }); 145 });
diff --git a/examples/nrf/src/bin/ppi.rs b/examples/nrf/src/bin/ppi.rs
index 0bac875bd..2dc3fe1b7 100644
--- a/examples/nrf/src/bin/ppi.rs
+++ b/examples/nrf/src/bin/ppi.rs
@@ -8,12 +8,11 @@ mod example_common;
8use example_common::*; 8use example_common::*;
9 9
10use core::future::pending; 10use core::future::pending;
11use defmt::panic;
12use embassy::executor::Spawner; 11use embassy::executor::Spawner;
13use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 12use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
14use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; 13use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity};
15use embassy_nrf::ppi::Ppi; 14use embassy_nrf::ppi::Ppi;
16use embassy_nrf::{interrupt, Peripherals}; 15use embassy_nrf::Peripherals;
17use gpiote::{OutputChannel, OutputChannelPolarity}; 16use gpiote::{OutputChannel, OutputChannelPolarity};
18 17
19#[embassy::main] 18#[embassy::main]
diff --git a/examples/nrf/src/bin/pwm.rs b/examples/nrf/src/bin/pwm.rs
index d2bc81cea..f30ad8f52 100644
--- a/examples/nrf/src/bin/pwm.rs
+++ b/examples/nrf/src/bin/pwm.rs
@@ -5,11 +5,11 @@
5 5
6#[path = "../example_common.rs"] 6#[path = "../example_common.rs"]
7mod example_common; 7mod example_common;
8use defmt::{panic, *}; 8use defmt::*;
9use embassy::executor::Spawner; 9use embassy::executor::Spawner;
10use embassy::time::{Duration, Timer}; 10use embassy::time::{Duration, Timer};
11use embassy_nrf::pwm::{Prescaler, Pwm}; 11use embassy_nrf::pwm::{Prescaler, Pwm};
12use embassy_nrf::{interrupt, Peripherals}; 12use embassy_nrf::Peripherals;
13 13
14// for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='') 14// for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='')
15static DUTY: [u16; 1024] = [ 15static DUTY: [u16; 1024] = [
diff --git a/examples/nrf/src/bin/raw_spawn.rs b/examples/nrf/src/bin/raw_spawn.rs
index 78de7b100..326dd9aac 100644
--- a/examples/nrf/src/bin/raw_spawn.rs
+++ b/examples/nrf/src/bin/raw_spawn.rs
@@ -7,13 +7,11 @@ use example_common::*;
7 7
8use core::mem; 8use core::mem;
9use cortex_m_rt::entry; 9use cortex_m_rt::entry;
10use defmt::panic; 10
11use embassy::executor::raw::Task; 11use embassy::executor::raw::Task;
12use embassy::executor::Executor; 12use embassy::executor::Executor;
13use embassy::time::{Duration, Timer}; 13use embassy::time::{Duration, Timer};
14use embassy::util::Forever; 14use embassy::util::Forever;
15use embassy_nrf::peripherals;
16use embassy_nrf::{interrupt, rtc};
17 15
18async fn run1() { 16async fn run1() {
19 loop { 17 loop {
@@ -29,23 +27,14 @@ async fn run2() {
29 } 27 }
30} 28}
31 29
32static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
33static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
34static EXECUTOR: Forever<Executor> = Forever::new(); 30static EXECUTOR: Forever<Executor> = Forever::new();
35 31
36#[entry] 32#[entry]
37fn main() -> ! { 33fn main() -> ! {
38 info!("Hello World!"); 34 info!("Hello World!");
39 35
40 let p = embassy_nrf::init(Default::default()); 36 let _p = embassy_nrf::init(Default::default());
41
42 let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
43 rtc.start();
44 unsafe { embassy::time::set_clock(rtc) };
45
46 let alarm = ALARM.put(rtc.alarm0());
47 let executor = EXECUTOR.put(Executor::new()); 37 let executor = EXECUTOR.put(Executor::new());
48 executor.set_alarm(alarm);
49 38
50 let run1_task = Task::new(); 39 let run1_task = Task::new();
51 let run2_task = Task::new(); 40 let run2_task = Task::new();
diff --git a/examples/nrf/src/bin/timer.rs b/examples/nrf/src/bin/timer.rs
index 630ea87a5..60cbe5a0f 100644
--- a/examples/nrf/src/bin/timer.rs
+++ b/examples/nrf/src/bin/timer.rs
@@ -8,7 +8,6 @@ mod example_common;
8use embassy_nrf::Peripherals; 8use embassy_nrf::Peripherals;
9use example_common::*; 9use example_common::*;
10 10
11use defmt::panic;
12use embassy::executor::Spawner; 11use embassy::executor::Spawner;
13use embassy::time::{Duration, Timer}; 12use embassy::time::{Duration, Timer};
14 13
diff --git a/examples/stm32f4/src/bin/blinky.rs b/examples/stm32f4/src/bin/blinky.rs
index 9c695a809..00eab761e 100644
--- a/examples/stm32f4/src/bin/blinky.rs
+++ b/examples/stm32f4/src/bin/blinky.rs
@@ -6,7 +6,6 @@
6 6
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9use defmt::panic;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy::time::{Duration, Timer}; 10use embassy::time::{Duration, Timer};
12use embassy_stm32::dbgmcu::Dbgmcu; 11use embassy_stm32::dbgmcu::Dbgmcu;
diff --git a/examples/stm32f4/src/bin/button_exti.rs b/examples/stm32f4/src/bin/button_exti.rs
index caebdac1f..ee43fa7d9 100644
--- a/examples/stm32f4/src/bin/button_exti.rs
+++ b/examples/stm32f4/src/bin/button_exti.rs
@@ -6,7 +6,6 @@
6 6
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9use defmt::panic;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy_stm32::dbgmcu::Dbgmcu; 10use embassy_stm32::dbgmcu::Dbgmcu;
12use embassy_stm32::exti::ExtiInput; 11use embassy_stm32::exti::ExtiInput;
diff --git a/examples/stm32f4/src/bin/hello.rs b/examples/stm32f4/src/bin/hello.rs
index 41d808406..1b8730aea 100644
--- a/examples/stm32f4/src/bin/hello.rs
+++ b/examples/stm32f4/src/bin/hello.rs
@@ -4,7 +4,7 @@
4#![feature(type_alias_impl_trait)] 4#![feature(type_alias_impl_trait)]
5#![allow(incomplete_features)] 5#![allow(incomplete_features)]
6 6
7use defmt::{info, panic}; 7use defmt::info;
8use embassy::executor::Spawner; 8use embassy::executor::Spawner;
9use embassy::time::{Duration, Timer}; 9use embassy::time::{Duration, Timer};
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
diff --git a/examples/stm32f4/src/bin/spi_dma.rs b/examples/stm32f4/src/bin/spi_dma.rs
index 9f7101122..a965bef70 100644
--- a/examples/stm32f4/src/bin/spi_dma.rs
+++ b/examples/stm32f4/src/bin/spi_dma.rs
@@ -8,7 +8,6 @@
8mod example_common; 8mod example_common;
9use core::fmt::Write; 9use core::fmt::Write;
10use core::str::from_utf8; 10use core::str::from_utf8;
11use defmt::panic;
12use embassy::executor::Spawner; 11use embassy::executor::Spawner;
13use embassy_stm32::dbgmcu::Dbgmcu; 12use embassy_stm32::dbgmcu::Dbgmcu;
14use embassy_stm32::spi::{Config, Spi}; 13use embassy_stm32::spi::{Config, Spi};
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index 5023075ff..05a550e95 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -7,7 +7,6 @@
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9use core::fmt::Write; 9use core::fmt::Write;
10use defmt::panic;
11use embassy::executor::Spawner; 10use embassy::executor::Spawner;
12use embassy_stm32::dbgmcu::Dbgmcu; 11use embassy_stm32::dbgmcu::Dbgmcu;
13use embassy_stm32::dma::NoDma; 12use embassy_stm32::dma::NoDma;
diff --git a/examples/stm32h7/src/bin/blinky.rs b/examples/stm32h7/src/bin/blinky.rs
index 3291f5e81..b5e0c18a5 100644
--- a/examples/stm32h7/src/bin/blinky.rs
+++ b/examples/stm32h7/src/bin/blinky.rs
@@ -6,30 +6,29 @@
6 6
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9use embassy::executor::Spawner;
10use embassy::time::{Duration, Timer};
11use embassy_stm32::dbgmcu::Dbgmcu;
9use embassy_stm32::gpio::{Level, Output, Speed}; 12use embassy_stm32::gpio::{Level, Output, Speed};
13use embassy_stm32::Peripherals;
10use embedded_hal::digital::v2::OutputPin; 14use embedded_hal::digital::v2::OutputPin;
11use example_common::*; 15use example_common::*;
12 16
13use cortex_m_rt::entry; 17#[embassy::main]
14use embassy_stm32::dbgmcu::Dbgmcu; 18async fn main(_spawner: Spawner, p: Peripherals) {
15
16#[entry]
17fn main() -> ! {
18 info!("Hello World!"); 19 info!("Hello World!");
19 20
20 unsafe { Dbgmcu::enable_all() }; 21 unsafe { Dbgmcu::enable_all() };
21 22
22 let p = embassy_stm32::init(Default::default());
23
24 let mut led = Output::new(p.PB14, Level::High, Speed::Low); 23 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
25 24
26 loop { 25 loop {
27 info!("high"); 26 info!("high");
28 led.set_high().unwrap(); 27 led.set_high().unwrap();
29 cortex_m::asm::delay(10_000_000); 28 Timer::after(Duration::from_millis(500)).await;
30 29
31 info!("low"); 30 info!("low");
32 led.set_low().unwrap(); 31 led.set_low().unwrap();
33 cortex_m::asm::delay(10_000_000); 32 Timer::after(Duration::from_millis(500)).await;
34 } 33 }
35} 34}
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 6c4ba6eb9..e8d13876a 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -19,7 +19,6 @@ use embassy_macros::interrupt_take;
19use embassy_net::{ 19use embassy_net::{
20 Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket, 20 Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket,
21}; 21};
22use embassy_stm32::clock::{Alarm, Clock};
23use embassy_stm32::dbgmcu::Dbgmcu; 22use embassy_stm32::dbgmcu::Dbgmcu;
24use embassy_stm32::eth::lan8742a::LAN8742A; 23use embassy_stm32::eth::lan8742a::LAN8742A;
25use embassy_stm32::eth::{Ethernet, State}; 24use embassy_stm32::eth::{Ethernet, State};
@@ -27,7 +26,7 @@ use embassy_stm32::rng::Random;
27use embassy_stm32::{interrupt, peripherals}; 26use embassy_stm32::{interrupt, peripherals};
28use heapless::Vec; 27use heapless::Vec;
29use panic_probe as _; 28use panic_probe as _;
30use peripherals::{RNG, TIM2}; 29use peripherals::RNG;
31 30
32#[embassy::task] 31#[embassy::task]
33async fn main_task( 32async fn main_task(
@@ -86,8 +85,6 @@ fn _embassy_rand(buf: &mut [u8]) {
86static mut RNG_INST: Option<Random<RNG>> = None; 85static mut RNG_INST: Option<Random<RNG>> = None;
87 86
88static EXECUTOR: Forever<Executor> = Forever::new(); 87static EXECUTOR: Forever<Executor> = Forever::new();
89static TIMER_RTC: Forever<Clock<TIM2>> = Forever::new();
90static ALARM: Forever<Alarm<TIM2>> = Forever::new();
91static STATE: Forever<State<'static, 4, 4>> = Forever::new(); 88static STATE: Forever<State<'static, 4, 4>> = Forever::new();
92static ETH: Forever<Ethernet<'static, LAN8742A, 4, 4>> = Forever::new(); 89static ETH: Forever<Ethernet<'static, LAN8742A, 4, 4>> = Forever::new();
93static CONFIG: Forever<StaticConfigurator> = Forever::new(); 90static CONFIG: Forever<StaticConfigurator> = Forever::new();
@@ -105,13 +102,6 @@ fn main() -> ! {
105 102
106 let p = embassy_stm32::init(config()); 103 let p = embassy_stm32::init(config());
107 104
108 let rtc_int = interrupt_take!(TIM2);
109 let rtc = TIMER_RTC.put(Clock::new(p.TIM2, rtc_int));
110 rtc.start();
111 let alarm = ALARM.put(rtc.alarm1());
112
113 unsafe { embassy::time::set_clock(rtc) };
114
115 let rng = Random::new(p.RNG); 105 let rng = Random::new(p.RNG);
116 unsafe { 106 unsafe {
117 RNG_INST.replace(rng); 107 RNG_INST.replace(rng);
@@ -136,7 +126,6 @@ fn main() -> ! {
136 let config = CONFIG.put(config); 126 let config = CONFIG.put(config);
137 127
138 let executor = EXECUTOR.put(Executor::new()); 128 let executor = EXECUTOR.put(Executor::new());
139 executor.set_alarm(alarm);
140 129
141 executor.run(move |spawner| { 130 executor.run(move |spawner| {
142 unwrap!(spawner.spawn(main_task(eth, config, spawner))); 131 unwrap!(spawner.spawn(main_task(eth, config, spawner)));
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index 5175538df..047b65849 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -9,7 +9,6 @@ mod example_common;
9 9
10use core::fmt::Write; 10use core::fmt::Write;
11use embassy::executor::Executor; 11use embassy::executor::Executor;
12use embassy::time::Clock;
13use embassy::util::Forever; 12use embassy::util::Forever;
14use embassy_stm32::dma::NoDma; 13use embassy_stm32::dma::NoDma;
15use embassy_stm32::spi; 14use embassy_stm32::spi;
@@ -38,14 +37,6 @@ async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) {
38 } 37 }
39} 38}
40 39
41struct ZeroClock;
42
43impl Clock for ZeroClock {
44 fn now(&self) -> u64 {
45 0
46 }
47}
48
49static EXECUTOR: Forever<Executor> = Forever::new(); 40static EXECUTOR: Forever<Executor> = Forever::new();
50 41
51#[entry] 42#[entry]
@@ -69,7 +60,6 @@ fn main() -> ! {
69 spi::Config::default(), 60 spi::Config::default(),
70 ); 61 );
71 62
72 unsafe { embassy::time::set_clock(&ZeroClock) };
73 let executor = EXECUTOR.put(Executor::new()); 63 let executor = EXECUTOR.put(Executor::new());
74 64
75 executor.run(|spawner| { 65 executor.run(|spawner| {
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 3b9043bc2..f11b7eb45 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -9,7 +9,6 @@ mod example_common;
9 9
10use core::fmt::Write; 10use core::fmt::Write;
11use embassy::executor::Executor; 11use embassy::executor::Executor;
12use embassy::time::Clock;
13use embassy::util::Forever; 12use embassy::util::Forever;
14use embassy_stm32::time::U32Ext; 13use embassy_stm32::time::U32Ext;
15use embassy_traits::spi::FullDuplex; 14use embassy_traits::spi::FullDuplex;
@@ -34,14 +33,6 @@ async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) {
34 } 33 }
35} 34}
36 35
37struct ZeroClock;
38
39impl Clock for ZeroClock {
40 fn now(&self) -> u64 {
41 0
42 }
43}
44
45static EXECUTOR: Forever<Executor> = Forever::new(); 36static EXECUTOR: Forever<Executor> = Forever::new();
46 37
47#[entry] 38#[entry]
@@ -65,7 +56,6 @@ fn main() -> ! {
65 spi::Config::default(), 56 spi::Config::default(),
66 ); 57 );
67 58
68 unsafe { embassy::time::set_clock(&ZeroClock) };
69 let executor = EXECUTOR.put(Executor::new()); 59 let executor = EXECUTOR.put(Executor::new());
70 60
71 executor.run(|spawner| { 61 executor.run(|spawner| {
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index 5fa21b6a2..9c93d3f22 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -8,7 +8,6 @@
8mod example_common; 8mod example_common;
9use cortex_m::prelude::_embedded_hal_blocking_serial_Write; 9use cortex_m::prelude::_embedded_hal_blocking_serial_Write;
10use embassy::executor::Executor; 10use embassy::executor::Executor;
11use embassy::time::Clock;
12use embassy::util::Forever; 11use embassy::util::Forever;
13use embassy_stm32::dma::NoDma; 12use embassy_stm32::dma::NoDma;
14use embassy_stm32::usart::{Config, Uart}; 13use embassy_stm32::usart::{Config, Uart};
@@ -34,14 +33,6 @@ async fn main_task() {
34 } 33 }
35} 34}
36 35
37struct ZeroClock;
38
39impl Clock for ZeroClock {
40 fn now(&self) -> u64 {
41 0
42 }
43}
44
45static EXECUTOR: Forever<Executor> = Forever::new(); 36static EXECUTOR: Forever<Executor> = Forever::new();
46 37
47#[entry] 38#[entry]
@@ -52,8 +43,6 @@ fn main() -> ! {
52 Dbgmcu::enable_all(); 43 Dbgmcu::enable_all();
53 } 44 }
54 45
55 unsafe { embassy::time::set_clock(&ZeroClock) };
56
57 let executor = EXECUTOR.put(Executor::new()); 46 let executor = EXECUTOR.put(Executor::new());
58 47
59 executor.run(|spawner| { 48 executor.run(|spawner| {
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index 26cc3c5da..3f70a82b0 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -8,7 +8,6 @@
8mod example_common; 8mod example_common;
9use core::fmt::Write; 9use core::fmt::Write;
10use embassy::executor::Executor; 10use embassy::executor::Executor;
11use embassy::time::Clock;
12use embassy::util::Forever; 11use embassy::util::Forever;
13use embassy_stm32::dbgmcu::Dbgmcu; 12use embassy_stm32::dbgmcu::Dbgmcu;
14use embassy_stm32::dma::NoDma; 13use embassy_stm32::dma::NoDma;
@@ -36,14 +35,6 @@ async fn main_task() {
36 } 35 }
37} 36}
38 37
39struct ZeroClock;
40
41impl Clock for ZeroClock {
42 fn now(&self) -> u64 {
43 0
44 }
45}
46
47static EXECUTOR: Forever<Executor> = Forever::new(); 38static EXECUTOR: Forever<Executor> = Forever::new();
48 39
49#[entry] 40#[entry]
@@ -54,8 +45,6 @@ fn main() -> ! {
54 Dbgmcu::enable_all(); 45 Dbgmcu::enable_all();
55 } 46 }
56 47
57 unsafe { embassy::time::set_clock(&ZeroClock) };
58
59 let executor = EXECUTOR.put(Executor::new()); 48 let executor = EXECUTOR.put(Executor::new());
60 49
61 executor.run(|spawner| { 50 executor.run(|spawner| {
diff --git a/examples/stm32l0/src/bin/blinky.rs b/examples/stm32l0/src/bin/blinky.rs
index 27060edca..faa42896b 100644
--- a/examples/stm32l0/src/bin/blinky.rs
+++ b/examples/stm32l0/src/bin/blinky.rs
@@ -7,7 +7,6 @@
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9 9
10use defmt::panic;
11use embassy::executor::Spawner; 10use embassy::executor::Spawner;
12use embassy::time::{Duration, Timer}; 11use embassy::time::{Duration, Timer};
13use embassy_stm32::gpio::{Level, Output, Speed}; 12use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs
index 9f0b0bde6..40e25b088 100644
--- a/examples/stm32l0/src/bin/button_exti.rs
+++ b/examples/stm32l0/src/bin/button_exti.rs
@@ -7,7 +7,6 @@
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9 9
10use defmt::panic;
11use embassy::executor::Spawner; 10use embassy::executor::Spawner;
12use embassy_stm32::exti::ExtiInput; 11use embassy_stm32::exti::ExtiInput;
13use embassy_stm32::gpio::{Input, Pull}; 12use embassy_stm32::gpio::{Input, Pull};
diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs
index 2c0690d0e..39a605174 100644
--- a/examples/stm32l0/src/bin/usart_dma.rs
+++ b/examples/stm32l0/src/bin/usart_dma.rs
@@ -9,7 +9,6 @@ mod example_common;
9 9
10use example_common::*; 10use example_common::*;
11 11
12use defmt::panic;
13use embassy::executor::Spawner; 12use embassy::executor::Spawner;
14use embassy_stm32::usart::{Config, Uart}; 13use embassy_stm32::usart::{Config, Uart};
15use embassy_stm32::{rcc, Peripherals}; 14use embassy_stm32::{rcc, Peripherals};
diff --git a/examples/stm32l4/src/bin/blinky.rs b/examples/stm32l4/src/bin/blinky.rs
index c929335dc..fc86b11eb 100644
--- a/examples/stm32l4/src/bin/blinky.rs
+++ b/examples/stm32l4/src/bin/blinky.rs
@@ -6,7 +6,6 @@
6 6
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9use defmt::panic;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy::time::{Duration, Timer}; 10use embassy::time::{Duration, Timer};
12use embassy_stm32::dbgmcu::Dbgmcu; 11use embassy_stm32::dbgmcu::Dbgmcu;
diff --git a/examples/stm32l4/src/bin/button_exti.rs b/examples/stm32l4/src/bin/button_exti.rs
index a702b5ba1..8a78b2589 100644
--- a/examples/stm32l4/src/bin/button_exti.rs
+++ b/examples/stm32l4/src/bin/button_exti.rs
@@ -6,7 +6,6 @@
6 6
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9use defmt::panic;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy_stm32::dbgmcu::Dbgmcu; 10use embassy_stm32::dbgmcu::Dbgmcu;
12use embassy_stm32::exti::ExtiInput; 11use embassy_stm32::exti::ExtiInput;
diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs
index aa0762589..ba77331be 100644
--- a/examples/stm32l4/src/bin/spi_dma.rs
+++ b/examples/stm32l4/src/bin/spi_dma.rs
@@ -7,7 +7,6 @@
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9 9
10use defmt::panic;
11use embassy::executor::Spawner; 10use embassy::executor::Spawner;
12use embassy_stm32::dbgmcu::Dbgmcu; 11use embassy_stm32::dbgmcu::Dbgmcu;
13use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index b15bba76e..f74a0e06b 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -7,7 +7,6 @@
7#[path = "../example_common.rs"] 7#[path = "../example_common.rs"]
8mod example_common; 8mod example_common;
9use core::fmt::Write; 9use core::fmt::Write;
10use defmt::panic;
11use embassy::executor::Spawner; 10use embassy::executor::Spawner;
12use embassy_stm32::dbgmcu::Dbgmcu; 11use embassy_stm32::dbgmcu::Dbgmcu;
13use embassy_stm32::dma::NoDma; 12use embassy_stm32::dma::NoDma;