Skip to content

Commit

Permalink
Merge pull request #289 from braun-embedded/mrt
Browse files Browse the repository at this point in the history
Add embedded-hal alpha and embedded-time support to MRT
  • Loading branch information
hannobraun authored Oct 19, 2020
2 parents 39c548a + e84836e commit 6e787f8
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 27 deletions.
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ travis-ci = { repository = "lpc-rs/lpc8xx-hal" }


[dependencies]
cortex-m = "0.6.3"
nb = "1.0.0"
cortex-m = "0.6.3"
embedded-time = "0.10.0"
nb = "1.0.0"

# This should be in [dev-dependencies], but those can't be optional.
# Issue: https://github.com/rust-lang/cargo/issues/1596
Expand Down Expand Up @@ -158,6 +159,10 @@ required-features = ["rt-selected", "82x"]
name = "i2c_eeprom"
required-features = ["rt-selected"]

[[example]]
name = "mrt_clock"
required-features = ["rt-selected", "845"]

[[example]]
name = "pinint"
required-features = ["rt-selected", "845"]
Expand Down
32 changes: 32 additions & 0 deletions examples/mrt_clock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#![no_main]
#![no_std]

extern crate panic_rtt_target;

use embedded_time::{duration::Extensions as _, Clock as _};
use lpc8xx_hal::{cortex_m_rt::entry, gpio::Level, mrt, Peripherals};

#[entry]
fn main() -> ! {
rtt_target::rtt_init_print!();

let p = Peripherals::take().unwrap();

let mut syscon = p.SYSCON.split();
let gpio = p.GPIO.enable(&mut syscon.handle);
let mut mrt = p.MRT0.split(&mut syscon.handle).mrt0;

let mut led = p
.pins
.pio1_1
.into_output_pin(gpio.tokens.pio1_1, Level::Low);

loop {
mrt.start(mrt::MAX_VALUE);

let timer = mrt.new_timer(1u32.seconds());
timer.start().unwrap().wait().unwrap();

led.toggle();
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub extern crate cortex_m;
pub extern crate cortex_m_rt;
pub extern crate embedded_hal;
pub extern crate embedded_hal_alpha;
pub extern crate embedded_time;
pub extern crate nb;
pub extern crate void;

Expand Down
116 changes: 91 additions & 25 deletions src/mrt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use crate::{
};

use embedded_hal::timer::{CountDown, Periodic};
use nb::{Error, Result};
use embedded_hal_alpha::timer::{
CountDown as CountDownAlpha, Periodic as PeriodicAlpha,
};
use embedded_time::{clock, fraction::Fraction, Instant};
use void::Void;

/// Represents the MRT instance
Expand Down Expand Up @@ -74,32 +77,13 @@ where
Self(RegProxy::new())
}

/// Returns the current timer value
pub fn value(&self) -> u32 {
self.0.timer.read().value().bits()
}
}

impl<T> CountDown for Channel<T>
where
T: Trait,
{
/// The timer operates in clock ticks from the system clock, that means it
/// runs at 12_000_000 ticks per second if you haven't changed it.
///
/// It can also only use values smaller than 0x7FFFFFFF.
type Time = u32;

/// Start counting down from the given count
/// Start the timer
///
/// The `reload` argument must be smaller than or equal to [`MAX_VALUE`].
///
/// [`MAX_VALUE`]: constant.MAX_VALUE.html
fn start<Time>(&mut self, count: Time)
where
Time: Into<Self::Time>,
{
let reload: Self::Time = count.into();
pub fn start(&mut self, reload: impl Into<u32>) {
let reload = reload.into();
debug_assert!(reload <= MAX_VALUE);

// This stops the timer, to prevent race conditions when resetting the
Expand All @@ -114,20 +98,102 @@ where
.write(|w| unsafe { w.ivalue().bits(reload + 1) });
}

/// Indicates whether the timer is running
pub fn is_running(&self) -> bool {
self.0.stat.read().run().is_running()
}

/// Returns the current timer value
pub fn value(&self) -> u32 {
self.0.timer.read().value().bits()
}

/// Returns the reload value of the timer
pub fn reload_value(&self) -> u32 {
self.0.intval.read().ivalue().bits()
}

/// Non-blockingly "waits" until the count down finishes
fn wait(&mut self) -> Result<(), Void> {
fn wait(&mut self) -> nb::Result<(), Void> {
if self.0.stat.read().intflag().is_pending_interrupt() {
// Reset the interrupt flag
self.0.stat.write(|w| w.intflag().set_bit());
Ok(())
} else {
Err(Error::WouldBlock)
Err(nb::Error::WouldBlock)
}
}
}

impl<T> CountDown for Channel<T>
where
T: Trait,
{
/// The timer operates in clock ticks from the system clock, that means it
/// runs at 12_000_000 ticks per second if you haven't changed it.
///
/// It can also only use values smaller than 0x7FFFFFFF.
type Time = u32;

fn start<Time>(&mut self, count: Time)
where
Time: Into<Self::Time>,
{
self.start(count);
}

fn wait(&mut self) -> nb::Result<(), Void> {
self.wait()
}
}

impl<T> CountDownAlpha for Channel<T>
where
T: Trait,
{
type Error = Void;

/// The timer operates in clock ticks from the system clock, that means it
/// runs at 12_000_000 ticks per second if you haven't changed it.
///
/// It can also only use values smaller than 0x7FFFFFFF.
type Time = u32;

fn try_start<Time>(&mut self, count: Time) -> Result<(), Self::Error>
where
Time: Into<Self::Time>,
{
Ok(self.start(count))
}

fn try_wait(&mut self) -> nb::Result<(), Self::Error> {
self.wait()
}
}

impl<T> Periodic for Channel<T> where T: Trait {}

impl<T> PeriodicAlpha for Channel<T> where T: Trait {}

impl<T> embedded_time::Clock for Channel<T>
where
T: Trait,
{
type T = u32;

const SCALING_FACTOR: Fraction = Fraction::new(1, 12_000_000);

fn try_now(&self) -> Result<Instant<Self>, clock::Error> {
if self.is_running() {
// embedded-time assumes that clocks are counting up, but we are
// counting down here. Thus, the need for some translation.
Ok(Instant::new(self.reload_value() - self.value()))
} else {
Err(clock::Error::NotRunning)
}
}
}

/// Implemented for types that identify MRT channels
pub trait Trait: Reg<Target = CHANNEL> + sealed::Sealed {}

Expand Down

0 comments on commit 6e787f8

Please sign in to comment.