Skip to content
Snippets Groups Projects
Commit 5f1da7ce authored by Johannes Sjölund's avatar Johannes Sjölund
Browse files

Improve timer.rs

parent 04c1304e
No related branches found
No related tags found
No related merge requests found
//! 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();
}
}
}
...@@ -13,7 +13,7 @@ use f4::led::{self, LEDS}; ...@@ -13,7 +13,7 @@ use f4::led::{self, LEDS};
use rtfm::{app, Threshold}; use rtfm::{app, Threshold};
// CONFIGURATION // CONFIGURATION
const FREQUENCY: u32 = 4; // Hz const FREQUENCY: u32 = 1; // Hz
// TASKS & RESOURCES // TASKS & RESOURCES
app! { app! {
......
//! User LEDs //! User LEDs
//!
//! - PA5
use stm32f40x::{GPIOB, RCC}; use stm32f40x::{GPIOA, RCC};
/// All the user LEDs /// LED connected to pin PC13
pub static LEDS: [Led; 8] = [ pub const LED: PA5 = PA5;
Led { i: 2 },
Led { i: 1 }, /// Pin PA5. There's an LED connected to this pin
Led { i: 15 }, pub struct PA5;
Led { i: 14 },
Led { i: 13 }, /// Initializes the user LED
Led { i: 5 }, pub fn init(gpioa: &GPIOA, rcc: &RCC) {
Led { i: 4 }, // power on GPIOC
Led { i: 10 }, rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
];
// configure PC13 as output
/// An LED gpioa.moder.write(|w| w.moder5().bits(1));
pub struct Led {
i: u8,
}
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))) }
} }
/// Turns on the LED impl PA5 {
/// Turns the LED on
pub fn on(&self) { pub fn on(&self) {
// NOTE(safe) atomic write unsafe {
unsafe { (*GPIOB.get()).bsrr.write(|w| w.bits(1 << self.i)) } (*GPIOA.get()).odr.write(|w| w.odr5().bit(false));
} }
} }
/// Initializes all the user LEDs /// Turns the LED off
pub fn init(gpioa: &GPIOB, rcc: &RCC) { pub fn off(&self) {
// Power up peripherals unsafe {
rcc.ahb1enr.modify(|_, w| w.gpioben().set_bit()); (*GPIOA.get()).odr.write(|w| w.odr5().bit(true));
}
// 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)
} }
},
);
} }
\ No newline at end of file
...@@ -46,4 +46,5 @@ use frequency::*; ...@@ -46,4 +46,5 @@ use frequency::*;
pub use hal::prelude; pub use hal::prelude;
pub use serial::Serial; pub use serial::Serial;
pub use timer::{Channel, Timer};
//! Periodic timer //! Timer
use core::u16; use core::any::{Any, TypeId};
use cast::{u16, u32}; 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 /// Channel associated to a timer
pub type Result<T> = ::core::result::Result<T, Error>; #[derive(Clone, Copy, Debug)]
pub enum Channel {
/// TxC1
_1,
/// TxC2
_2,
/// TxC3
_3,
/// TxC4
_4,
}
/// `hal::Timer` implementation
pub struct Timer<'a, T>(pub &'a T)
where
T: 'a;
/// An error impl<'a, T> Clone for Timer<'a, T> {
pub struct Error { fn clone(&self) -> Self {
_0: (), *self
}
} }
/// Periodic timer impl<'a, T> Copy for Timer<'a, T> {}
///
/// # Interrupts
///
/// - `Tim11` - update event
pub struct Timer<'a>(pub &'a TIM11);
impl<'a> Timer<'a> { macro_rules! impl_Timer {
($TIM:ident, $APB:ident) => {
impl<'a> Timer<'a, $TIM>
{
/// Initializes the timer with a periodic timeout of `frequency` Hz /// Initializes the timer with a periodic timeout of `frequency` Hz
/// ///
/// NOTE After initialization, the timer will be in the paused state. /// NOTE After initialization, the timer will be in the paused state.
pub fn init(&self, rcc: &RCC, frequency: u32) { pub fn init<P>(&self, period: P, rcc: &RCC)
let tim11 = self.0; where
P: Into<::$APB::Ticks>,
{
self.init_(period.into(), rcc)
}
// Power up peripherals 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()); rcc.apb2enr.modify(|_, w| w.tim11en().set_bit());
}
let ratio = ::apb1::FREQUENCY / frequency; // Configure periodic update event
let psc = u16((ratio - 1) / u32(u16::MAX)).unwrap(); self._set_timeout(timeout);
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()); // Continuous mode
// tim7.cr1.write(|w| w.opm().continuous()); // 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 fn _set_timeout(&self, timeout: ::$APB::Ticks) {
/// let period = timeout.0;
/// 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() { let psc = u16((period - 1) / (1 << 16)).unwrap();
Err(Error { _0: () }) self.0.psc.write(|w| unsafe{w.psc().bits(psc)});
} else {
self.0.sr.modify(|_, w| w.uif().clear_bit()); let arr = u32(period / u32(psc + 1));
Ok(()) self.0.arr.write(|w| unsafe{w.bits(arr)});
} }
} }
/// Resumes the timer count impl<'a> hal::Timer for Timer<'a, $TIM>
pub fn resume(&self) { {
self.0.cr1.modify(|_, w| w.cen().set_bit()); 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 fn pause(&self) {
pub fn pause(&self) {
self.0.cr1.modify(|_, w| w.cen().clear_bit()); 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);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment