systick_timer/
embassy_driver.rs1use core::cell::RefCell;
4use cortex_m::{
5 interrupt::{self, Mutex},
6 peripheral::SYST,
7};
8
9struct Wakeup {
10 wakeup_at: u64,
11 waker: core::task::Waker,
12}
13
14pub struct SystickDriver<const N: usize> {
26 wakeup_at: Mutex<RefCell<[Option<Wakeup>; N]>>,
27 timer: crate::Timer,
28}
29
30impl<const N: usize> SystickDriver<N> {
31 pub const fn new(systick_freq: u64, reload_value: u32) -> Self {
41 let timer = crate::Timer::new(embassy_time_driver::TICK_HZ, reload_value, systick_freq);
42 Self {
43 wakeup_at: Mutex::new(RefCell::new([const { None }; N])),
44 timer: timer,
45 }
46 }
47
48 pub const fn new_default(systick_freq: u64) -> Self {
58 let reload = (systick_freq / embassy_time_driver::TICK_HZ) - 1;
59 Self::new(systick_freq, reload as u32)
60 }
61
62 fn maybe_wake(&self) {
63 interrupt::free(|cs| {
64 let mutex_borrow = &self.wakeup_at.borrow(cs);
65 for slot in mutex_borrow.borrow_mut().iter_mut() {
66 let mut cleared = false;
67 if let Some(wakeup) = slot {
68 if self.timer.now() >= wakeup.wakeup_at {
69 wakeup.waker.wake_by_ref();
70 cleared = true;
71 }
72 }
73 if cleared {
74 *slot = None;
75 }
76 }
77 })
78 }
79
80 pub fn start(&self, syst: &mut SYST) {
81 self.timer.start(syst);
82 }
83
84 pub fn systick_interrupt(&self) {
86 self.timer.systick_handler();
87 self.maybe_wake();
88 }
89}
90
91impl<const N: usize> embassy_time_driver::Driver for SystickDriver<N> {
92 fn now(&self) -> u64 {
93 self.timer.now()
94 }
95
96 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
97 interrupt::free(|cs| {
98 let mutex_borrow = self.wakeup_at.borrow(cs);
99 let mut found = false;
100 for slot in mutex_borrow.borrow_mut().iter_mut() {
101 if slot.is_none() {
102 *slot = Some(Wakeup {
103 wakeup_at: at,
104 waker: waker.clone(),
105 });
106 found = true;
107 break;
108 }
109 }
110 if !found {
111 panic!("No free wakeup slots");
112 }
113 })
114 }
115}
116
117#[cfg(feature = "embassy-defaults")]
118embassy_time_driver::time_driver_impl!(static DRIVER: SystickDriver<4> = SystickDriver::new(8_000_000, 7_999));
119
120#[cfg(feature = "embassy-defaults")]
121#[cortex_m_rt::exception]
122fn SysTick() {
123 DRIVER.systick_interrupt();
124}