libboard_zynq: impl embedded_hal CountDown for GlobalTimer

This commit is contained in:
Astro 2020-04-25 00:28:40 +02:00
parent 4ab6fb6271
commit 8012573a8f
2 changed files with 43 additions and 5 deletions

View File

@ -1,3 +1,4 @@
use void::Void;
use libregister::{RegisterR, RegisterW}; use libregister::{RegisterR, RegisterW};
use crate::{ use crate::{
clocks::Clocks, clocks::Clocks,
@ -5,6 +6,7 @@ use crate::{
time::Milliseconds, time::Milliseconds,
}; };
/// "uptime"
pub struct GlobalTimer { pub struct GlobalTimer {
regs: &'static mut mpcore::RegisterBlock, regs: &'static mut mpcore::RegisterBlock,
} }
@ -14,7 +16,7 @@ impl GlobalTimer {
let regs = mpcore::RegisterBlock::new(); let regs = mpcore::RegisterBlock::new();
GlobalTimer { regs } GlobalTimer { regs }
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
// Disable // Disable
self.regs.global_timer_control.write( self.regs.global_timer_control.write(
@ -32,28 +34,64 @@ impl GlobalTimer {
// Start // Start
self.regs.global_timer_control.write( self.regs.global_timer_control.write(
mpcore::GlobalTimerControl::zeroed() mpcore::GlobalTimerControl::zeroed()
// maximum prescaler is still enough for millisecond
// precision while overflowing after centuries.
.prescaler(255) .prescaler(255)
.auto_increment_mode(true) .auto_increment_mode(true)
.timer_enable(true) .timer_enable(true)
); );
} }
/// read the raw counter value
pub fn get_counter(&self) -> u64 { pub fn get_counter(&self) -> u64 {
loop { 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 c0 = self.regs.global_timer_counter0.read().value();
let c1_post = self.regs.global_timer_counter1.read().value(); let c1_post = self.regs.global_timer_counter1.read().value();
if c1 == c1_post { if c1_pre == c1_post {
return ((c1 as u64) << 32) | (c0 as u64); 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 { pub fn get_time(&self) -> Milliseconds {
let prescaler = self.regs.global_timer_control.read().prescaler() as u64; let prescaler = self.regs.global_timer_control.read().prescaler() as u64;
let clocks = Clocks::get(); let clocks = Clocks::get();
Milliseconds(self.get_counter() * (prescaler + 1) / (clocks.cpu_3x2x() as u64 / 1000)) 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<T: Into<Self::Time>>(&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(())
}
}
} }

View File

@ -1,2 +1,2 @@
mod global; pub mod global;
pub use global::GlobalTimer; pub use global::GlobalTimer;