diff --git a/boards/pico/Cargo.toml b/boards/pico/Cargo.toml index 2dfb934..561503f 100644 --- a/boards/pico/Cargo.toml +++ b/boards/pico/Cargo.toml @@ -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"] diff --git a/boards/pico/examples/pico_countdown_blinky.rs b/boards/pico/examples/pico_countdown_blinky.rs new file mode 100644 index 0000000..5957a1c --- /dev/null +++ b/boards/pico/examples/pico_countdown_blinky.rs @@ -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()); + } +} diff --git a/rp2040-hal/src/timer.rs b/rp2040-hal/src/timer.rs index 6d60991..8e0dd51 100644 --- a/rp2040-hal/src/timer.rs +++ b/rp2040-hal/src/timer.rs @@ -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, + next_end: Option, +} + +impl embedded_hal::timer::CountDown for CountDown<'_> { + type Time = embedded_time::duration::Microseconds; + + fn start(&mut self, count: T) + where + T: Into, + { + 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(()) + } } }