forked from M-Labs/zynq-rs
libboard_zynq: impl embedded_hal CountDown for GlobalTimer
This commit is contained in:
parent
4ab6fb6271
commit
8012573a8f
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
mod global;
|
pub mod global;
|
||||||
pub use global::GlobalTimer;
|
pub use global::GlobalTimer;
|
||||||
|
|
Loading…
Reference in New Issue