diff --git a/examples/blinky-blocking.rs b/examples/blinky-blocking.rs new file mode 100644 index 0000000000000000000000000000000000000000..9a09898504625a53a9901723f72c67a30caba5d1 --- /dev/null +++ b/examples/blinky-blocking.rs @@ -0,0 +1,56 @@ +//! Blocking version of blinky + +#![allow(unreachable_code)] // for the `block!` macro +#![deny(unsafe_code)] +#![deny(warnings)] +#![feature(proc_macro)] +#![no_std] + +extern crate f4; + +extern crate cortex_m_rtfm as rtfm; + +#[macro_use(block)] +extern crate nb; + +use f4::Timer; +use f4::led::{self, LED}; +use f4::prelude::*; +use f4::time::Hertz; +use rtfm::{app, Threshold}; + +const FREQUENCY: Hertz = Hertz(1); + +app! { + device: f4::stm32f40x, + + idle: { + resources: [TIM11], + } +} + +fn init(p: init::Peripherals) { + led::init(p.GPIOA, p.RCC); + + let timer = Timer(&*p.TIM11); + + timer.init(FREQUENCY.invert(), p.RCC); +} + +fn idle(_t: &mut Threshold, r: idle::Resources) -> ! { + let timer = Timer(&*r.TIM11); + + timer.resume(); + let mut state = false; + loop { + block!(timer.wait()).unwrap(); // NOTE(unwrap) E = ! + + state = !state; + + if state { + LED.on(); + } else { + LED.off(); + } + } +} diff --git a/examples/blinky.rs b/examples/blinky.rs index f048a4e867d74dec04d19d9a88058d5d056f4476..63b927ea1854767a0e651c860555b0fa2c99ea6c 100644 --- a/examples/blinky.rs +++ b/examples/blinky.rs @@ -13,7 +13,7 @@ use f4::led::{self, LEDS}; use rtfm::{app, Threshold}; // CONFIGURATION -const FREQUENCY: u32 = 4; // Hz +const FREQUENCY: u32 = 1; // Hz // TASKS & RESOURCES app! { diff --git a/src/led.rs b/src/led.rs index e8582ae2db472e378e888baf3bc783f5ad191500..eb3e7119614d9ce93d52f87b70ca344953204929 100644 --- a/src/led.rs +++ b/src/led.rs @@ -1,57 +1,37 @@ //! User LEDs +//! +//! - PA5 -use stm32f40x::{GPIOB, RCC}; - -/// All the user LEDs -pub static LEDS: [Led; 8] = [ - Led { i: 2 }, - Led { i: 1 }, - Led { i: 15 }, - Led { i: 14 }, - Led { i: 13 }, - Led { i: 5 }, - Led { i: 4 }, - Led { i: 10 }, -]; - -/// An LED -pub struct Led { - i: u8, -} +use stm32f40x::{GPIOA, RCC}; -impl Led { - /// Turns off the LED - pub fn off(&self) { - // NOTE(safe) atomic write - unsafe { (*GPIOB.get()).bsrr.write(|w| w.bits(1 << (self.i + 16))) } - } +/// LED connected to pin PC13 +pub const LED: PA5 = PA5; + +/// Pin PA5. There's an LED connected to this pin +pub struct PA5; + +/// Initializes the user LED +pub fn init(gpioa: &GPIOA, rcc: &RCC) { + // power on GPIOC + rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + + // configure PC13 as output + gpioa.moder.write(|w| w.moder5().bits(1)); - /// Turns on the LED +} + +impl PA5 { + /// Turns the LED on pub fn on(&self) { - // NOTE(safe) atomic write - unsafe { (*GPIOB.get()).bsrr.write(|w| w.bits(1 << self.i)) } + unsafe { + (*GPIOA.get()).odr.write(|w| w.odr5().bit(false)); + } } -} -/// Initializes all the user LEDs -pub fn init(gpioa: &GPIOB, rcc: &RCC) { - // Power up peripherals - rcc.ahb1enr.modify(|_, w| w.gpioben().set_bit()); - - // Configure pins 8-15 as outputs - gpioa - .moder - .modify( - |_, w| {unsafe { - w.moder2().bits(1) - .moder1().bits(1) - .moder15().bits(1) - .moder14().bits(1) - .moder13().bits(1) - .moder5().bits(1) - .moder4().bits(1) - .moder10().bits(1) - } - }, - ); -} + /// Turns the LED off + pub fn off(&self) { + unsafe { + (*GPIOA.get()).odr.write(|w| w.odr5().bit(true)); + } + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 765f9642a562476bc63c22ab42c28c8eba7858b8..34744a15a1776828e6c1d87a3d27d40bc1159420 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,4 +46,5 @@ use frequency::*; pub use hal::prelude; pub use serial::Serial; +pub use timer::{Channel, Timer}; diff --git a/src/timer.rs b/src/timer.rs index 8b0db4196d2c8902560d06d0918f7458087c00fc..9dab206d5c2115cf57b608f7277c2ddfce63efb3 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,66 +1,145 @@ -//! Periodic timer +//! Timer -use core::u16; +use core::any::{Any, TypeId}; use cast::{u16, u32}; -use stm32f40x::{RCC, TIM11}; +use hal; +use nb::{self, Error}; +use stm32f40x::{TIM1, TIM2, TIM3, TIM4, TIM5, TIM9, TIM10, TIM11, RCC}; -/// Specialized `Result` type -pub type Result<T> = ::core::result::Result<T, Error>; - -/// An error -pub struct Error { - _0: (), +/// Channel associated to a timer +#[derive(Clone, Copy, Debug)] +pub enum Channel { + /// TxC1 + _1, + /// TxC2 + _2, + /// TxC3 + _3, + /// TxC4 + _4, } -/// Periodic timer -/// -/// # Interrupts -/// -/// - `Tim11` - update event -pub struct Timer<'a>(pub &'a TIM11); - -impl<'a> Timer<'a> { - /// Initializes the timer with a periodic timeout of `frequency` Hz - /// - /// NOTE After initialization, the timer will be in the paused state. - pub fn init(&self, rcc: &RCC, frequency: u32) { - let tim11 = self.0; - - // Power up peripherals - rcc.apb2enr.modify(|_, w| w.tim11en().set_bit()); - - let ratio = ::apb1::FREQUENCY / frequency; - let psc = u16((ratio - 1) / u32(u16::MAX)).unwrap(); - tim11.psc.write(|w| unsafe{w.psc().bits(psc)}); - let arr = u16(ratio / u32(psc + 1)).unwrap(); - tim11.arr.write(|w| unsafe{ w.arr().bits(arr)}); - - tim11.dier.write(|w| w.uie().set_bit()); - // tim7.cr1.write(|w| w.opm().continuous()); + +/// `hal::Timer` implementation +pub struct Timer<'a, T>(pub &'a T) +where + T: 'a; + +impl<'a, T> Clone for Timer<'a, T> { + fn clone(&self) -> Self { + *self } +} + +impl<'a, T> Copy for Timer<'a, T> {} + +macro_rules! impl_Timer { + ($TIM:ident, $APB:ident) => { + impl<'a> Timer<'a, $TIM> + { + /// Initializes the timer with a periodic timeout of `frequency` Hz + /// + /// NOTE After initialization, the timer will be in the paused state. + pub fn init<P>(&self, period: P, rcc: &RCC) + where + P: Into<::$APB::Ticks>, + { + self.init_(period.into(), rcc) + } + + fn init_(&self, timeout: ::$APB::Ticks, rcc: &RCC) { + let tim = self.0; + + // Enable TIMx + // Reference manual does not mention TIM6-8, TIM 12-14 + // although they are implemented in device crate... + if tim.get_type_id() == TypeId::of::<TIM1>() { + rcc.apb2enr.modify(|_, w| w.tim1en().set_bit()); + } else if tim.get_type_id() == TypeId::of::<TIM2>() { + rcc.apb1enr.modify(|_, w| w.tim2en().set_bit()); + } else if tim.get_type_id() == TypeId::of::<TIM3>() { + rcc.apb1enr.modify(|_, w| w.tim3en().set_bit()); + } else if tim.get_type_id() == TypeId::of::<TIM4>() { + rcc.apb1enr.modify(|_, w| w.tim4en().set_bit()); + } else if tim.get_type_id() == TypeId::of::<TIM5>() { + rcc.apb1enr.modify(|_, w| w.tim5en().set_bit()); + } else if tim.get_type_id() == TypeId::of::<TIM9>() { + rcc.apb2enr.modify(|_, w| w.tim9en().set_bit()); + } else if tim.get_type_id() == TypeId::of::<TIM10>() { + rcc.apb2enr.modify(|_, w| w.tim10en().set_bit()); + } else if tim.get_type_id() == TypeId::of::<TIM11>() { + rcc.apb2enr.modify(|_, w| w.tim11en().set_bit()); + } + + // Configure periodic update event + self._set_timeout(timeout); + + // Continuous mode + // tim2.cr1.write(|w| w.opm().continuous()); + + // Enable the update event interrupt + tim.dier.modify(|_, w| w.uie().set_bit()); + } - /// Clears the update event flag - /// - /// Returns `Err` if no update event has occurred - pub fn clear_update_flag(&self) -> Result<()> { - let tim11 = self.0; - - if tim11.sr.read().uif().bit_is_clear() { - Err(Error { _0: () }) - } else { - self.0.sr.modify(|_, w| w.uif().clear_bit()); - Ok(()) + fn _set_timeout(&self, timeout: ::$APB::Ticks) { + let period = timeout.0; + + let psc = u16((period - 1) / (1 << 16)).unwrap(); + self.0.psc.write(|w| unsafe{w.psc().bits(psc)}); + + let arr = u32(period / u32(psc + 1)); + self.0.arr.write(|w| unsafe{w.bits(arr)}); + } } - } - /// Resumes the timer count - pub fn resume(&self) { - self.0.cr1.modify(|_, w| w.cen().set_bit()); - } + impl<'a> hal::Timer for Timer<'a, $TIM> + { + type Time = ::$APB::Ticks; + + fn get_timeout(&self) -> ::$APB::Ticks { + ::$APB::Ticks( + u32(self.0.psc.read().psc().bits() + 1) * + u32(self.0.arr.read().bits()), + ) + } - /// Pauses the timer - pub fn pause(&self) { - self.0.cr1.modify(|_, w| w.cen().clear_bit()); + fn pause(&self) { + self.0.cr1.modify(|_, w| w.cen().clear_bit()); + } + + fn restart(&self) { + self.0.cnt.write(|w| unsafe{w.bits(0)}); + } + + fn resume(&self) { + self.0.cr1.modify(|_, w| w.cen().set_bit()); + } + + fn set_timeout<TO>(&self, timeout: TO) + where + TO: Into<::$APB::Ticks>, + { + self._set_timeout(timeout.into()) + } + + fn wait(&self) -> nb::Result<(), !> { + if self.0.sr.read().uif().bit_is_clear() { + Err(Error::WouldBlock) + } else { + self.0.sr.modify(|_, w| w.uif().clear_bit()); + Ok(()) + } + } + } } } + +impl_Timer!(TIM1, apb2); +impl_Timer!(TIM2, apb1); +impl_Timer!(TIM3, apb1); +impl_Timer!(TIM4, apb1); +impl_Timer!(TIM5, apb1); +impl_Timer!(TIM9, apb2); +impl_Timer!(TIM10, apb2); +impl_Timer!(TIM11, apb2);