diff options
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; | |||
| 3 | use quote::quote; | 3 | use quote::quote; |
| 4 | 4 | ||
| 5 | pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { | 5 | pub 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; | |||
| 3 | use quote::quote; | 3 | use quote::quote; |
| 4 | 4 | ||
| 5 | pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { | 5 | pub 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; | |||
| 3 | use quote::quote; | 3 | use quote::quote; |
| 4 | 4 | ||
| 5 | pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { | 5 | pub 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 | |||
| 23 | pub(crate) mod fmt; | 23 | pub(crate) mod fmt; |
| 24 | pub(crate) mod util; | 24 | pub(crate) mod util; |
| 25 | 25 | ||
| 26 | mod time_driver; | ||
| 27 | |||
| 26 | pub mod buffered_uarte; | 28 | pub mod buffered_uarte; |
| 27 | pub mod gpio; | 29 | pub mod gpio; |
| 28 | pub mod gpiote; | 30 | pub mod gpiote; |
| @@ -32,7 +34,6 @@ pub mod pwm; | |||
| 32 | #[cfg(feature = "nrf52840")] | 34 | #[cfg(feature = "nrf52840")] |
| 33 | pub mod qspi; | 35 | pub mod qspi; |
| 34 | pub mod rng; | 36 | pub mod rng; |
| 35 | pub mod rtc; | ||
| 36 | #[cfg(not(feature = "nrf52820"))] | 37 | #[cfg(not(feature = "nrf52820"))] |
| 37 | pub mod saadc; | 38 | pub mod saadc; |
| 38 | pub mod spim; | 39 | pub 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 @@ | |||
| 1 | use core::cell::Cell; | 1 | use core::cell::Cell; |
| 2 | use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; | 2 | use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; |
| 3 | use core::{mem, ptr}; | ||
| 3 | use critical_section::CriticalSection; | 4 | use critical_section::CriticalSection; |
| 4 | use embassy::interrupt::InterruptExt; | 5 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 5 | use embassy::time::Clock; | 6 | use embassy::time::driver::{AlarmHandle, Driver}; |
| 6 | use embassy::util::{CriticalSectionMutex as Mutex, Unborrow}; | 7 | use embassy::util::CriticalSectionMutex as Mutex; |
| 7 | 8 | ||
| 8 | use crate::interrupt::Interrupt; | 9 | use crate::interrupt; |
| 9 | use crate::pac; | 10 | use crate::pac; |
| 10 | use crate::{interrupt, peripherals}; | 11 | |
| 12 | fn 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 | ||
| 58 | struct AlarmState { | 62 | struct 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 | ||
| 71 | unsafe impl Send for AlarmState {} | ||
| 72 | |||
| 63 | impl AlarmState { | 73 | impl 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 | ||
| 72 | const ALARM_COUNT: usize = 3; | 83 | const ALARM_COUNT: usize = 3; |
| 73 | 84 | ||
| 74 | pub struct RTC<T: Instance> { | 85 | struct 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 | ||
| 85 | unsafe impl<T: Instance> Send for RTC<T> {} | 93 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); |
| 86 | unsafe impl<T: Instance> Sync for RTC<T> {} | 94 | static 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 | ||
| 88 | impl<T: Instance> RTC<T> { | 100 | impl 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 | |||
| 236 | impl<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 | ||
| 246 | pub struct Alarm<T: Instance> { | 267 | struct RtcDriver; |
| 247 | n: usize, | 268 | embassy::time_driver_impl!(RtcDriver); |
| 248 | rtc: &'static RTC<T>, | ||
| 249 | } | ||
| 250 | 269 | ||
| 251 | impl<T: Instance> embassy::time::Alarm for Alarm<T> { | 270 | impl 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 | ||
| 265 | mod 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 | ||
| 272 | macro_rules! impl_instance { | 288 | #[interrupt] |
| 273 | ($type:ident, $irq:ident) => { | 289 | fn 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. | 293 | pub(crate) fn init() { |
| 286 | pub 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 | |||
| 291 | impl_instance!(RTC0, RTC0); | ||
| 292 | impl_instance!(RTC1, RTC1); | ||
| 293 | #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] | ||
| 294 | impl_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 = [ ] | |||
| 22 | embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] } | 22 | embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] } |
| 23 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } | 23 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } |
| 24 | embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} | 24 | embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} |
| 25 | 25 | atomic-polyfill = { version = "0.1.2" } | |
| 26 | defmt = { version = "0.2.0", optional = true } | 26 | defmt = { version = "0.2.0", optional = true } |
| 27 | log = { version = "0.4.11", optional = true } | 27 | log = { version = "0.4.11", optional = true } |
| 28 | cortex-m-rt = "0.6.13" | 28 | cortex-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 @@ | |||
| 1 | use atomic_polyfill::{AtomicU8, Ordering}; | ||
| 1 | use core::cell::Cell; | 2 | use core::cell::Cell; |
| 2 | use critical_section::CriticalSection; | 3 | use critical_section::CriticalSection; |
| 3 | use embassy::interrupt::{Interrupt, InterruptExt}; | 4 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 5 | use embassy::time::driver::{AlarmHandle, Driver}; | ||
| 4 | use embassy::util::CriticalSectionMutex as Mutex; | 6 | use embassy::util::CriticalSectionMutex as Mutex; |
| 5 | 7 | ||
| 6 | use crate::{interrupt, pac}; | 8 | use crate::{interrupt, pac}; |
| @@ -18,6 +20,7 @@ const DUMMY_ALARM: AlarmState = AlarmState { | |||
| 18 | }; | 20 | }; |
| 19 | 21 | ||
| 20 | static ALARMS: Mutex<[AlarmState; ALARM_COUNT]> = Mutex::new([DUMMY_ALARM; ALARM_COUNT]); | 22 | static ALARMS: Mutex<[AlarmState; ALARM_COUNT]> = Mutex::new([DUMMY_ALARM; ALARM_COUNT]); |
| 23 | static NEXT_ALARM: AtomicU8 = AtomicU8::new(0); | ||
| 21 | 24 | ||
| 22 | fn now() -> u64 { | 25 | fn now() -> u64 { |
| 23 | loop { | 26 | loop { |
| @@ -32,60 +35,39 @@ fn now() -> u64 { | |||
| 32 | } | 35 | } |
| 33 | } | 36 | } |
| 34 | 37 | ||
| 35 | struct Timer; | 38 | struct TimerDriver; |
| 36 | impl embassy::time::Clock for Timer { | 39 | embassy::time_driver_impl!(TimerDriver); |
| 37 | fn now(&self) -> u64 { | ||
| 38 | now() | ||
| 39 | } | ||
| 40 | } | ||
| 41 | 40 | ||
| 42 | pub trait AlarmInstance { | 41 | impl Driver for TimerDriver { |
| 43 | fn alarm_num(&self) -> usize; | 42 | fn now() -> u64 { |
| 44 | } | 43 | now() |
| 45 | |||
| 46 | impl AlarmInstance for crate::peripherals::TIMER_ALARM0 { | ||
| 47 | fn alarm_num(&self) -> usize { | ||
| 48 | 0 | ||
| 49 | } | ||
| 50 | } | ||
| 51 | impl AlarmInstance for crate::peripherals::TIMER_ALARM1 { | ||
| 52 | fn alarm_num(&self) -> usize { | ||
| 53 | 1 | ||
| 54 | } | ||
| 55 | } | ||
| 56 | impl AlarmInstance for crate::peripherals::TIMER_ALARM2 { | ||
| 57 | fn alarm_num(&self) -> usize { | ||
| 58 | 2 | ||
| 59 | } | ||
| 60 | } | ||
| 61 | impl AlarmInstance for crate::peripherals::TIMER_ALARM3 { | ||
| 62 | fn alarm_num(&self) -> usize { | ||
| 63 | 3 | ||
| 64 | } | 44 | } |
| 65 | } | ||
| 66 | 45 | ||
| 67 | pub 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 | ||
| 71 | impl<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 | ||
| 77 | impl<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 | ||
| 114 | fn check_alarm(n: usize) { | 92 | fn 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 @@ | |||
| 1 | use embassy::executor::{raw, Spawner}; | 1 | use embassy::executor::{raw, Spawner}; |
| 2 | use embassy::time::driver::{AlarmHandle, Driver}; | ||
| 2 | use embassy::time::TICKS_PER_SECOND; | 3 | use embassy::time::TICKS_PER_SECOND; |
| 3 | use embassy::time::{Alarm, Clock}; | ||
| 4 | use std::marker::PhantomData; | 4 | use std::marker::PhantomData; |
| 5 | use std::mem::MaybeUninit; | 5 | use std::mem::MaybeUninit; |
| 6 | use std::ptr; | 6 | use std::ptr; |
| @@ -8,28 +8,31 @@ use std::sync::{Condvar, Mutex}; | |||
| 8 | use std::time::{Duration as StdDuration, Instant as StdInstant}; | 8 | use std::time::{Duration as StdDuration, Instant as StdInstant}; |
| 9 | 9 | ||
| 10 | static mut CLOCK_ZERO: MaybeUninit<StdInstant> = MaybeUninit::uninit(); | 10 | static mut CLOCK_ZERO: MaybeUninit<StdInstant> = MaybeUninit::uninit(); |
| 11 | struct StdClock; | 11 | |
| 12 | impl Clock for StdClock { | 12 | static mut ALARM_AT: u64 = u64::MAX; |
| 13 | fn now(&self) -> u64 { | 13 | static mut NEXT_ALARM_ID: u8 = 0; |
| 14 | |||
| 15 | struct TimeDriver; | ||
| 16 | embassy::time_driver_impl!(TimeDriver); | ||
| 17 | |||
| 18 | impl 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 | ||
| 21 | static mut ALARM_AT: u64 = u64::MAX; | 26 | unsafe fn allocate_alarm() -> Option<AlarmHandle> { |
| 22 | 27 | let r = NEXT_ALARM_ID; | |
| 23 | pub struct StdAlarm; | 28 | NEXT_ALARM_ID += 1; |
| 24 | impl 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 | |||
| 3 | use core::cell::Cell; | ||
| 4 | use core::convert::TryInto; | ||
| 5 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 6 | |||
| 7 | use atomic_polyfill::AtomicU32; | ||
| 8 | use embassy::interrupt::InterruptExt; | ||
| 9 | use embassy::time::{Clock as EmbassyClock, TICKS_PER_SECOND}; | ||
| 10 | |||
| 11 | use crate::interrupt::{CriticalSection, Interrupt, Mutex}; | ||
| 12 | use crate::pac::timer::TimGp16; | ||
| 13 | use crate::peripherals; | ||
| 14 | use crate::rcc::RccPeripheral; | ||
| 15 | use 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. | ||
| 34 | fn calc_now(period: u32, counter: u16) -> u64 { | ||
| 35 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | ||
| 36 | } | ||
| 37 | |||
| 38 | struct AlarmState { | ||
| 39 | timestamp: Cell<u64>, | ||
| 40 | #[allow(clippy::type_complexity)] | ||
| 41 | callback: Cell<Option<(fn(*mut ()), *mut ())>>, | ||
| 42 | } | ||
| 43 | |||
| 44 | impl AlarmState { | ||
| 45 | fn new() -> Self { | ||
| 46 | Self { | ||
| 47 | timestamp: Cell::new(u64::MAX), | ||
| 48 | callback: Cell::new(None), | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | const 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. | ||
| 61 | pub 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 | |||
| 70 | impl<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 | |||
| 221 | impl<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 | |||
| 232 | pub struct Alarm<T: Instance> { | ||
| 233 | n: usize, | ||
| 234 | rtc: &'static Clock<T>, | ||
| 235 | } | ||
| 236 | |||
| 237 | impl<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 | |||
| 251 | pub struct TimerInner(pub(crate) TimGp16); | ||
| 252 | |||
| 253 | impl 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 | |||
| 341 | pub(crate) mod sealed { | ||
| 342 | use super::*; | ||
| 343 | pub trait Instance { | ||
| 344 | type Interrupt: Interrupt; | ||
| 345 | |||
| 346 | fn inner() -> TimerInner; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {} | ||
| 351 | |||
| 352 | macro_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 | |||
| 367 | crate::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; | |||
| 20 | pub mod dma; | 20 | pub mod dma; |
| 21 | pub mod gpio; | 21 | pub mod gpio; |
| 22 | pub mod rcc; | 22 | pub mod rcc; |
| 23 | mod time_driver; | ||
| 23 | 24 | ||
| 24 | // Sometimes-present hardware | 25 | // Sometimes-present hardware |
| 25 | 26 | ||
| 26 | #[cfg(adc)] | 27 | #[cfg(adc)] |
| 27 | pub mod adc; | 28 | pub mod adc; |
| 28 | #[cfg(timer)] | ||
| 29 | pub mod clock; | ||
| 30 | #[cfg(dac)] | 29 | #[cfg(dac)] |
| 31 | pub mod dac; | 30 | pub 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 @@ | |||
| 1 | use atomic_polyfill::{AtomicU32, AtomicU8}; | ||
| 2 | use core::cell::Cell; | ||
| 3 | use core::convert::TryInto; | ||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 5 | use core::{mem, ptr}; | ||
| 6 | use embassy::interrupt::InterruptExt; | ||
| 7 | use embassy::time::driver::{AlarmHandle, Driver}; | ||
| 8 | use embassy::time::TICKS_PER_SECOND; | ||
| 9 | use stm32_metapac::timer::regs; | ||
| 10 | |||
| 11 | use crate::interrupt; | ||
| 12 | use crate::interrupt::{CriticalSection, Interrupt, Mutex}; | ||
| 13 | use crate::pac::timer::{vals, TimGp16}; | ||
| 14 | use crate::peripherals; | ||
| 15 | use crate::rcc::sealed::RccPeripheral; | ||
| 16 | |||
| 17 | use self::sealed::Instance as _; | ||
| 18 | |||
| 19 | const ALARM_COUNT: usize = 3; | ||
| 20 | type 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. | ||
| 39 | fn calc_now(period: u32, counter: u16) -> u64 { | ||
| 40 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | ||
| 41 | } | ||
| 42 | |||
| 43 | struct 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 | |||
| 52 | unsafe impl Send for AlarmState {} | ||
| 53 | |||
| 54 | impl 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 | |||
| 64 | struct 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 | |||
| 72 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); | ||
| 73 | static 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 | |||
| 79 | impl 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 | |||
| 257 | struct RtcDriver; | ||
| 258 | embassy::time_driver_impl!(RtcDriver); | ||
| 259 | |||
| 260 | impl 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] | ||
| 279 | fn TIM3() { | ||
| 280 | STATE.on_interrupt() | ||
| 281 | } | ||
| 282 | |||
| 283 | pub(crate) fn init() { | ||
| 284 | STATE.init() | ||
| 285 | } | ||
| 286 | |||
| 287 | // ------------------------------------------------------ | ||
| 288 | |||
| 289 | pub(crate) mod sealed { | ||
| 290 | use super::*; | ||
| 291 | pub trait Instance { | ||
| 292 | type Interrupt: Interrupt; | ||
| 293 | |||
| 294 | fn regs() -> TimGp16; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {} | ||
| 299 | |||
| 300 | macro_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 | |||
| 314 | crate::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 | ||
| 111 | impl Executor { | 111 | impl 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")] |
| 16 | use super::timer_queue::{TimerQueue, TimerQueueItem}; | 16 | use super::timer_queue::{TimerQueue, TimerQueueItem}; |
| 17 | #[cfg(feature = "time")] | 17 | #[cfg(feature = "time")] |
| 18 | use crate::time::{Alarm, Instant}; | 18 | use crate::time::driver::{self, AlarmHandle}; |
| 19 | #[cfg(feature = "time")] | ||
| 20 | use crate::time::Instant; | ||
| 19 | 21 | ||
| 20 | /// Task is spawned (has a future) | 22 | /// Task is spawned (has a future) |
| 21 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; | 23 | pub(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 | ||
| 175 | impl Executor { | 177 | impl 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)] | ||
| 3 | pub struct AlarmHandle { | ||
| 4 | id: u8, | ||
| 5 | } | ||
| 6 | |||
| 7 | impl 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 | ||
| 24 | pub 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 | |||
| 50 | extern "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 | |||
| 57 | pub(crate) fn now() -> u64 { | ||
| 58 | unsafe { _embassy_time_now() } | ||
| 59 | } | ||
| 60 | /// Safety: it is UB to make the alarm fire before setting a callback. | ||
| 61 | pub(crate) unsafe fn allocate_alarm() -> Option<AlarmHandle> { | ||
| 62 | _embassy_time_allocate_alarm() | ||
| 63 | } | ||
| 64 | pub(crate) fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { | ||
| 65 | unsafe { _embassy_time_set_alarm_callback(alarm, callback, ctx) } | ||
| 66 | } | ||
| 67 | pub(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] | ||
| 95 | macro_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 @@ | |||
| 1 | use core::fmt; | 1 | use core::fmt; |
| 2 | use core::ops::{Add, AddAssign, Sub, SubAssign}; | 2 | use core::ops::{Add, AddAssign, Sub, SubAssign}; |
| 3 | 3 | ||
| 4 | use super::TICKS_PER_SECOND; | 4 | use super::{driver, Duration, TICKS_PER_SECOND}; |
| 5 | use 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 | //! | ||
| 4 | mod delay; | 3 | mod delay; |
| 4 | pub mod driver; | ||
| 5 | mod duration; | 5 | mod duration; |
| 6 | mod instant; | 6 | mod instant; |
| 7 | mod timer; | 7 | mod timer; |
| 8 | mod traits; | ||
| 9 | 8 | ||
| 10 | pub use delay::{block_for, Delay}; | 9 | pub use delay::{block_for, Delay}; |
| 11 | pub use duration::Duration; | 10 | pub use duration::Duration; |
| 12 | pub use instant::Instant; | 11 | pub use instant::Instant; |
| 13 | pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; | 12 | pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; |
| 14 | pub use traits::*; | ||
| 15 | 13 | ||
| 16 | #[cfg(feature = "time-tick-1000hz")] | 14 | #[cfg(feature = "time-tick-1000hz")] |
| 17 | pub const TICKS_PER_SECOND: u64 = 1_000; | 15 | pub 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")] |
| 23 | pub const TICKS_PER_SECOND: u64 = 1_000_000; | 21 | pub const TICKS_PER_SECOND: u64 = 1_000_000; |
| 24 | |||
| 25 | static mut CLOCK: Option<&'static dyn Clock> = None; | ||
| 26 | |||
| 27 | /// Sets the clock used for the timing abstractions | ||
| 28 | /// | ||
| 29 | /// Safety: Sets a mutable global. | ||
| 30 | pub 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. | ||
| 37 | pub(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 | ||
| 2 | pub 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 | |||
| 9 | impl<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. | ||
| 16 | pub 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"] |
| 7 | mod example_common; | 7 | mod example_common; |
| 8 | 8 | ||
| 9 | use defmt::panic; | ||
| 10 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 11 | use embassy::time::{Duration, Timer}; | 10 | use embassy::time::{Duration, Timer}; |
| 12 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | 11 | use 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; | |||
| 8 | use example_common::*; | 8 | use example_common::*; |
| 9 | 9 | ||
| 10 | use core::task::Poll; | 10 | use core::task::Poll; |
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | 11 | use embassy::executor::Spawner; |
| 13 | use embassy::time::{Duration, Instant, Timer}; | 12 | use embassy::time::{Duration, Instant, Timer}; |
| 14 | use embassy_nrf::{interrupt, Peripherals}; | 13 | use embassy_nrf::Peripherals; |
| 15 | 14 | ||
| 16 | #[embassy::task] | 15 | #[embassy::task] |
| 17 | async fn run1() { | 16 | async 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 @@ | |||
| 7 | mod example_common; | 7 | mod example_common; |
| 8 | use example_common::*; | 8 | use example_common::*; |
| 9 | 9 | ||
| 10 | use defmt::panic; | ||
| 11 | use embassy::executor::Spawner; | 10 | use embassy::executor::Spawner; |
| 12 | use embassy_nrf::gpio::{Input, Pull}; | 11 | use embassy_nrf::gpio::{Input, Pull}; |
| 13 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; | 12 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; |
| 14 | use embassy_nrf::{interrupt, Peripherals}; | 13 | use embassy_nrf::Peripherals; |
| 15 | 14 | ||
| 16 | #[embassy::main] | 15 | #[embassy::main] |
| 17 | async fn main(_spawner: Spawner, p: Peripherals) { | 16 | async 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"] |
| 7 | mod example_common; | 7 | mod example_common; |
| 8 | 8 | ||
| 9 | use defmt::panic; | ||
| 10 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 11 | use embassy::traits::gpio::{WaitForHigh, WaitForLow}; | 10 | use embassy::traits::gpio::{WaitForHigh, WaitForLow}; |
| 12 | use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; | 11 | use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; |
| 13 | use embassy_nrf::gpiote::PortInput; | 12 | use embassy_nrf::gpiote::PortInput; |
| 14 | use embassy_nrf::interrupt; | ||
| 15 | use embassy_nrf::Peripherals; | 13 | use embassy_nrf::Peripherals; |
| 16 | use example_common::*; | 14 | use 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"] |
| 7 | mod example_common; | 7 | mod example_common; |
| 8 | 8 | ||
| 9 | use defmt::panic; | ||
| 10 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 11 | use embassy::time::{Duration, Timer}; | 10 | use embassy::time::{Duration, Timer}; |
| 12 | use embassy::util::mpsc::TryRecvError; | 11 | use 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}; | |||
| 68 | use embassy::interrupt::InterruptExt; | 68 | use embassy::interrupt::InterruptExt; |
| 69 | use embassy::time::{Duration, Instant, Timer}; | 69 | use embassy::time::{Duration, Instant, Timer}; |
| 70 | use embassy::util::Forever; | 70 | use embassy::util::Forever; |
| 71 | use embassy_nrf::{interrupt, peripherals, rtc}; | 71 | use embassy_nrf::interrupt; |
| 72 | 72 | ||
| 73 | #[embassy::task] | 73 | #[embassy::task] |
| 74 | async fn run_high() { | 74 | async fn run_high() { |
| @@ -112,30 +112,20 @@ async fn run_low() { | |||
| 112 | } | 112 | } |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new(); | ||
| 116 | static ALARM_HIGH: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 117 | static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new(); | 115 | static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new(); |
| 118 | static ALARM_MED: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 119 | static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new(); | 116 | static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new(); |
| 120 | static ALARM_LOW: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 121 | static EXECUTOR_LOW: Forever<Executor> = Forever::new(); | 117 | static EXECUTOR_LOW: Forever<Executor> = Forever::new(); |
| 122 | 118 | ||
| 123 | #[entry] | 119 | #[entry] |
| 124 | fn main() -> ! { | 120 | fn 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; | |||
| 8 | use example_common::*; | 8 | use example_common::*; |
| 9 | 9 | ||
| 10 | use core::future::pending; | 10 | use core::future::pending; |
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | 11 | use embassy::executor::Spawner; |
| 13 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | 12 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; |
| 14 | use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; | 13 | use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; |
| 15 | use embassy_nrf::ppi::Ppi; | 14 | use embassy_nrf::ppi::Ppi; |
| 16 | use embassy_nrf::{interrupt, Peripherals}; | 15 | use embassy_nrf::Peripherals; |
| 17 | use gpiote::{OutputChannel, OutputChannelPolarity}; | 16 | use 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"] |
| 7 | mod example_common; | 7 | mod example_common; |
| 8 | use defmt::{panic, *}; | 8 | use defmt::*; |
| 9 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 10 | use embassy::time::{Duration, Timer}; | 10 | use embassy::time::{Duration, Timer}; |
| 11 | use embassy_nrf::pwm::{Prescaler, Pwm}; | 11 | use embassy_nrf::pwm::{Prescaler, Pwm}; |
| 12 | use embassy_nrf::{interrupt, Peripherals}; | 12 | use 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='') |
| 15 | static DUTY: [u16; 1024] = [ | 15 | static 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 | ||
| 8 | use core::mem; | 8 | use core::mem; |
| 9 | use cortex_m_rt::entry; | 9 | use cortex_m_rt::entry; |
| 10 | use defmt::panic; | 10 | |
| 11 | use embassy::executor::raw::Task; | 11 | use embassy::executor::raw::Task; |
| 12 | use embassy::executor::Executor; | 12 | use embassy::executor::Executor; |
| 13 | use embassy::time::{Duration, Timer}; | 13 | use embassy::time::{Duration, Timer}; |
| 14 | use embassy::util::Forever; | 14 | use embassy::util::Forever; |
| 15 | use embassy_nrf::peripherals; | ||
| 16 | use embassy_nrf::{interrupt, rtc}; | ||
| 17 | 15 | ||
| 18 | async fn run1() { | 16 | async fn run1() { |
| 19 | loop { | 17 | loop { |
| @@ -29,23 +27,14 @@ async fn run2() { | |||
| 29 | } | 27 | } |
| 30 | } | 28 | } |
| 31 | 29 | ||
| 32 | static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new(); | ||
| 33 | static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 34 | static EXECUTOR: Forever<Executor> = Forever::new(); | 30 | static EXECUTOR: Forever<Executor> = Forever::new(); |
| 35 | 31 | ||
| 36 | #[entry] | 32 | #[entry] |
| 37 | fn main() -> ! { | 33 | fn 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; | |||
| 8 | use embassy_nrf::Peripherals; | 8 | use embassy_nrf::Peripherals; |
| 9 | use example_common::*; | 9 | use example_common::*; |
| 10 | 10 | ||
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | 11 | use embassy::executor::Spawner; |
| 13 | use embassy::time::{Duration, Timer}; | 12 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use defmt::panic; | ||
| 10 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 11 | use embassy::time::{Duration, Timer}; | 10 | use embassy::time::{Duration, Timer}; |
| 12 | use embassy_stm32::dbgmcu::Dbgmcu; | 11 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use defmt::panic; | ||
| 10 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 11 | use embassy_stm32::dbgmcu::Dbgmcu; | 10 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 12 | use embassy_stm32::exti::ExtiInput; | 11 | use 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 | ||
| 7 | use defmt::{info, panic}; | 7 | use defmt::info; |
| 8 | use embassy::executor::Spawner; | 8 | use embassy::executor::Spawner; |
| 9 | use embassy::time::{Duration, Timer}; | 9 | use embassy::time::{Duration, Timer}; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use 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 @@ | |||
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use core::fmt::Write; | 9 | use core::fmt::Write; |
| 10 | use core::str::from_utf8; | 10 | use core::str::from_utf8; |
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | 11 | use embassy::executor::Spawner; |
| 13 | use embassy_stm32::dbgmcu::Dbgmcu; | 12 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 14 | use embassy_stm32::spi::{Config, Spi}; | 13 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use core::fmt::Write; | 9 | use core::fmt::Write; |
| 10 | use defmt::panic; | ||
| 11 | use embassy::executor::Spawner; | 10 | use embassy::executor::Spawner; |
| 12 | use embassy_stm32::dbgmcu::Dbgmcu; | 11 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 13 | use embassy_stm32::dma::NoDma; | 12 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use embassy::executor::Spawner; | ||
| 10 | use embassy::time::{Duration, Timer}; | ||
| 11 | use embassy_stm32::dbgmcu::Dbgmcu; | ||
| 9 | use embassy_stm32::gpio::{Level, Output, Speed}; | 12 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 13 | use embassy_stm32::Peripherals; | ||
| 10 | use embedded_hal::digital::v2::OutputPin; | 14 | use embedded_hal::digital::v2::OutputPin; |
| 11 | use example_common::*; | 15 | use example_common::*; |
| 12 | 16 | ||
| 13 | use cortex_m_rt::entry; | 17 | #[embassy::main] |
| 14 | use embassy_stm32::dbgmcu::Dbgmcu; | 18 | async fn main(_spawner: Spawner, p: Peripherals) { |
| 15 | |||
| 16 | #[entry] | ||
| 17 | fn 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; | |||
| 19 | use embassy_net::{ | 19 | use embassy_net::{ |
| 20 | Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket, | 20 | Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket, |
| 21 | }; | 21 | }; |
| 22 | use embassy_stm32::clock::{Alarm, Clock}; | ||
| 23 | use embassy_stm32::dbgmcu::Dbgmcu; | 22 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 24 | use embassy_stm32::eth::lan8742a::LAN8742A; | 23 | use embassy_stm32::eth::lan8742a::LAN8742A; |
| 25 | use embassy_stm32::eth::{Ethernet, State}; | 24 | use embassy_stm32::eth::{Ethernet, State}; |
| @@ -27,7 +26,7 @@ use embassy_stm32::rng::Random; | |||
| 27 | use embassy_stm32::{interrupt, peripherals}; | 26 | use embassy_stm32::{interrupt, peripherals}; |
| 28 | use heapless::Vec; | 27 | use heapless::Vec; |
| 29 | use panic_probe as _; | 28 | use panic_probe as _; |
| 30 | use peripherals::{RNG, TIM2}; | 29 | use peripherals::RNG; |
| 31 | 30 | ||
| 32 | #[embassy::task] | 31 | #[embassy::task] |
| 33 | async fn main_task( | 32 | async fn main_task( |
| @@ -86,8 +85,6 @@ fn _embassy_rand(buf: &mut [u8]) { | |||
| 86 | static mut RNG_INST: Option<Random<RNG>> = None; | 85 | static mut RNG_INST: Option<Random<RNG>> = None; |
| 87 | 86 | ||
| 88 | static EXECUTOR: Forever<Executor> = Forever::new(); | 87 | static EXECUTOR: Forever<Executor> = Forever::new(); |
| 89 | static TIMER_RTC: Forever<Clock<TIM2>> = Forever::new(); | ||
| 90 | static ALARM: Forever<Alarm<TIM2>> = Forever::new(); | ||
| 91 | static STATE: Forever<State<'static, 4, 4>> = Forever::new(); | 88 | static STATE: Forever<State<'static, 4, 4>> = Forever::new(); |
| 92 | static ETH: Forever<Ethernet<'static, LAN8742A, 4, 4>> = Forever::new(); | 89 | static ETH: Forever<Ethernet<'static, LAN8742A, 4, 4>> = Forever::new(); |
| 93 | static CONFIG: Forever<StaticConfigurator> = Forever::new(); | 90 | static 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 | ||
| 10 | use core::fmt::Write; | 10 | use core::fmt::Write; |
| 11 | use embassy::executor::Executor; | 11 | use embassy::executor::Executor; |
| 12 | use embassy::time::Clock; | ||
| 13 | use embassy::util::Forever; | 12 | use embassy::util::Forever; |
| 14 | use embassy_stm32::dma::NoDma; | 13 | use embassy_stm32::dma::NoDma; |
| 15 | use embassy_stm32::spi; | 14 | use 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 | ||
| 41 | struct ZeroClock; | ||
| 42 | |||
| 43 | impl Clock for ZeroClock { | ||
| 44 | fn now(&self) -> u64 { | ||
| 45 | 0 | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | static EXECUTOR: Forever<Executor> = Forever::new(); | 40 | static 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 | ||
| 10 | use core::fmt::Write; | 10 | use core::fmt::Write; |
| 11 | use embassy::executor::Executor; | 11 | use embassy::executor::Executor; |
| 12 | use embassy::time::Clock; | ||
| 13 | use embassy::util::Forever; | 12 | use embassy::util::Forever; |
| 14 | use embassy_stm32::time::U32Ext; | 13 | use embassy_stm32::time::U32Ext; |
| 15 | use embassy_traits::spi::FullDuplex; | 14 | use 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 | ||
| 37 | struct ZeroClock; | ||
| 38 | |||
| 39 | impl Clock for ZeroClock { | ||
| 40 | fn now(&self) -> u64 { | ||
| 41 | 0 | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | static EXECUTOR: Forever<Executor> = Forever::new(); | 36 | static 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 @@ | |||
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use cortex_m::prelude::_embedded_hal_blocking_serial_Write; | 9 | use cortex_m::prelude::_embedded_hal_blocking_serial_Write; |
| 10 | use embassy::executor::Executor; | 10 | use embassy::executor::Executor; |
| 11 | use embassy::time::Clock; | ||
| 12 | use embassy::util::Forever; | 11 | use embassy::util::Forever; |
| 13 | use embassy_stm32::dma::NoDma; | 12 | use embassy_stm32::dma::NoDma; |
| 14 | use embassy_stm32::usart::{Config, Uart}; | 13 | use embassy_stm32::usart::{Config, Uart}; |
| @@ -34,14 +33,6 @@ async fn main_task() { | |||
| 34 | } | 33 | } |
| 35 | } | 34 | } |
| 36 | 35 | ||
| 37 | struct ZeroClock; | ||
| 38 | |||
| 39 | impl Clock for ZeroClock { | ||
| 40 | fn now(&self) -> u64 { | ||
| 41 | 0 | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | static EXECUTOR: Forever<Executor> = Forever::new(); | 36 | static 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 @@ | |||
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use core::fmt::Write; | 9 | use core::fmt::Write; |
| 10 | use embassy::executor::Executor; | 10 | use embassy::executor::Executor; |
| 11 | use embassy::time::Clock; | ||
| 12 | use embassy::util::Forever; | 11 | use embassy::util::Forever; |
| 13 | use embassy_stm32::dbgmcu::Dbgmcu; | 12 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 14 | use embassy_stm32::dma::NoDma; | 13 | use embassy_stm32::dma::NoDma; |
| @@ -36,14 +35,6 @@ async fn main_task() { | |||
| 36 | } | 35 | } |
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | struct ZeroClock; | ||
| 40 | |||
| 41 | impl Clock for ZeroClock { | ||
| 42 | fn now(&self) -> u64 { | ||
| 43 | 0 | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | static EXECUTOR: Forever<Executor> = Forever::new(); | 38 | static 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | 9 | ||
| 10 | use defmt::panic; | ||
| 11 | use embassy::executor::Spawner; | 10 | use embassy::executor::Spawner; |
| 12 | use embassy::time::{Duration, Timer}; | 11 | use embassy::time::{Duration, Timer}; |
| 13 | use embassy_stm32::gpio::{Level, Output, Speed}; | 12 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | 9 | ||
| 10 | use defmt::panic; | ||
| 11 | use embassy::executor::Spawner; | 10 | use embassy::executor::Spawner; |
| 12 | use embassy_stm32::exti::ExtiInput; | 11 | use embassy_stm32::exti::ExtiInput; |
| 13 | use embassy_stm32::gpio::{Input, Pull}; | 12 | use 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 | ||
| 10 | use example_common::*; | 10 | use example_common::*; |
| 11 | 11 | ||
| 12 | use defmt::panic; | ||
| 13 | use embassy::executor::Spawner; | 12 | use embassy::executor::Spawner; |
| 14 | use embassy_stm32::usart::{Config, Uart}; | 13 | use embassy_stm32::usart::{Config, Uart}; |
| 15 | use embassy_stm32::{rcc, Peripherals}; | 14 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use defmt::panic; | ||
| 10 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 11 | use embassy::time::{Duration, Timer}; | 10 | use embassy::time::{Duration, Timer}; |
| 12 | use embassy_stm32::dbgmcu::Dbgmcu; | 11 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use defmt::panic; | ||
| 10 | use embassy::executor::Spawner; | 9 | use embassy::executor::Spawner; |
| 11 | use embassy_stm32::dbgmcu::Dbgmcu; | 10 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 12 | use embassy_stm32::exti::ExtiInput; | 11 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | 9 | ||
| 10 | use defmt::panic; | ||
| 11 | use embassy::executor::Spawner; | 10 | use embassy::executor::Spawner; |
| 12 | use embassy_stm32::dbgmcu::Dbgmcu; | 11 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 13 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | 12 | use 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"] |
| 8 | mod example_common; | 8 | mod example_common; |
| 9 | use core::fmt::Write; | 9 | use core::fmt::Write; |
| 10 | use defmt::panic; | ||
| 11 | use embassy::executor::Spawner; | 10 | use embassy::executor::Spawner; |
| 12 | use embassy_stm32::dbgmcu::Dbgmcu; | 11 | use embassy_stm32::dbgmcu::Dbgmcu; |
| 13 | use embassy_stm32::dma::NoDma; | 12 | use embassy_stm32::dma::NoDma; |
