diff --git a/libboard_zynq/src/timer/global.rs b/libboard_zynq/src/timer/global.rs index 616ae03..e671e06 100644 --- a/libboard_zynq/src/timer/global.rs +++ b/libboard_zynq/src/timer/global.rs @@ -1,3 +1,4 @@ +use void::Void; use libregister::{RegisterR, RegisterW}; use crate::{ clocks::Clocks, @@ -5,6 +6,7 @@ use crate::{ time::Milliseconds, }; +/// "uptime" pub struct GlobalTimer { regs: &'static mut mpcore::RegisterBlock, } @@ -14,7 +16,7 @@ impl GlobalTimer { let regs = mpcore::RegisterBlock::new(); GlobalTimer { regs } } - + pub fn reset(&mut self) { // Disable self.regs.global_timer_control.write( @@ -32,28 +34,64 @@ impl GlobalTimer { // Start self.regs.global_timer_control.write( mpcore::GlobalTimerControl::zeroed() + // maximum prescaler is still enough for millisecond + // precision while overflowing after centuries. .prescaler(255) .auto_increment_mode(true) .timer_enable(true) ); } + /// read the raw counter value pub fn get_counter(&self) -> u64 { loop { - let c1 = self.regs.global_timer_counter1.read().value(); + let c1_pre = self.regs.global_timer_counter1.read().value(); let c0 = self.regs.global_timer_counter0.read().value(); let c1_post = self.regs.global_timer_counter1.read().value(); - if c1 == c1_post { - return ((c1 as u64) << 32) | (c0 as u64); + if c1_pre == c1_post { + return ((c1_pre as u64) << 32) | (c0 as u64); } + // retry if c0 has wrapped while reading. } } + /// read and convert to time pub fn get_time(&self) -> Milliseconds { let prescaler = self.regs.global_timer_control.read().prescaler() as u64; let clocks = Clocks::get(); Milliseconds(self.get_counter() * (prescaler + 1) / (clocks.cpu_3x2x() as u64 / 1000)) } + + /// return a handle that has implements + /// `embedded_hal::timer::CountDown` + pub fn countdown(&self) -> CountDown { + CountDown { + timer: &self, + timeout: Milliseconds(0), + } + } +} + +#[derive(Clone)] +pub struct CountDown<'a> { + timer: &'a GlobalTimer, + timeout: Milliseconds, +} + +impl embedded_hal::timer::CountDown for CountDown<'_> { + type Time = Milliseconds; + + fn start>(&mut self, count: T) { + self.timeout = count.into(); + } + + fn wait(&mut self) -> nb::Result<(), Void> { + if self.timer.get_time() < self.timeout { + Err(nb::Error::WouldBlock) + } else { + Ok(()) + } + } } diff --git a/libboard_zynq/src/timer/mod.rs b/libboard_zynq/src/timer/mod.rs index 2bb4e94..88026ff 100644 --- a/libboard_zynq/src/timer/mod.rs +++ b/libboard_zynq/src/timer/mod.rs @@ -1,2 +1,2 @@ -mod global; +pub mod global; pub use global::GlobalTimer;