Add embedded_hal::timer support (#110)

* Add embedded_hal::timer support

* fixup: add pico countdown based blinky example & rework get_counter(&self) -> u16
This commit is contained in:
Wilfried Chauveau 2021-09-16 09:47:34 +01:00 committed by GitHub
parent 833b69819e
commit c509b9d22f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 134 additions and 4 deletions

View file

@ -23,6 +23,7 @@ panic-halt= "0.2.0"
embedded-hal ="0.2.5"
cortex-m-rtic = "0.6.0-alpha.5"
rp2040-boot2 = "0.1.2"
nb = "1.0"
[features]
default = ["rt"]

View file

@ -0,0 +1,61 @@
//! Blinks the LED on a Pico board
//!
//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED.
#![no_std]
#![no_main]
use cortex_m::prelude::_embedded_hal_timer_CountDown;
use cortex_m_rt::entry;
use embedded_hal::digital::v2::OutputPin;
use embedded_time::duration::Extensions;
use panic_halt as _;
use pico::{
hal::{self as hal, clocks::init_clocks_and_plls, pac, sio::Sio, watchdog::Watchdog},
XOSC_CRYSTAL_FREQ,
};
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
#[entry]
fn main() -> ! {
let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let _clocks = init_clocks_and_plls(
XOSC_CRYSTAL_FREQ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let timer = hal::timer::Timer::new(pac.TIMER);
let mut count_down = timer.count_down();
let sio = Sio::new(pac.SIO);
let pins = hal::gpio::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
let mut led_pin = pins.gpio25.into_push_pull_output();
loop {
led_pin.set_high().unwrap();
// wait for 500ms
count_down.start(500.milliseconds());
let _ = nb::block!(count_down.wait());
led_pin.set_low().unwrap();
// wait for 500ms
count_down.start(500.milliseconds());
let _ = nb::block!(count_down.wait());
}
}

View file

@ -1,6 +1,8 @@
//! Timer Peripheral
// See [Chapter 4 Section 6](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details
use embedded_time::duration::Microseconds;
use crate::pac::TIMER;
/// Timer peripheral
@ -16,9 +18,75 @@ impl Timer {
/// Get the current counter value.
pub fn get_counter(&self) -> u64 {
// latched read, low before high
let lo = self.timer.timelr.read().bits();
let hi = self.timer.timehr.read().bits();
(hi as u64) << 32 | lo as u64
let mut hi0 = self.timer.timerawh.read().bits();
loop {
let low = self.timer.timerawl.read().bits();
let hi1 = self.timer.timerawh.read().bits();
if hi0 == hi1 {
break (u64::from(hi0) << 32) | u64::from(low);
}
hi0 = hi1;
}
}
/// Get the value of the least significant word of the counter.
pub fn get_counter_low(&self) -> u32 {
self.timer.timerawl.read().bits()
}
/// Initialized a Count Down instance without starting it.
pub fn count_down(&self) -> CountDown<'_> {
CountDown {
timer: self,
period: Microseconds::new(0),
next_end: None,
}
}
}
/// Delay implementation
pub struct CountDown<'timer> {
timer: &'timer Timer,
period: embedded_time::duration::Microseconds<u64>,
next_end: Option<u64>,
}
impl embedded_hal::timer::CountDown for CountDown<'_> {
type Time = embedded_time::duration::Microseconds<u64>;
fn start<T>(&mut self, count: T)
where
T: Into<Self::Time>,
{
self.period = count.into();
self.next_end = Some(self.timer.get_counter().wrapping_add(self.period.0));
}
fn wait(&mut self) -> nb::Result<(), void::Void> {
if let Some(end) = self.next_end {
let ts = self.timer.get_counter();
if ts >= end {
self.next_end = Some(end.wrapping_add(self.period.0));
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
} else {
panic!("CountDown is not running!");
}
}
}
impl embedded_hal::timer::Periodic for CountDown<'_> {}
impl embedded_hal::timer::Cancel for CountDown<'_> {
type Error = &'static str;
fn cancel(&mut self) -> Result<(), Self::Error> {
if self.next_end.is_none() {
Err("CountDown is not running.")
} else {
self.next_end = None;
Ok(())
}
}
}