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};
use rtfm::{app, Threshold};
// CONFIGURATION
const FREQUENCY: u32 = 4; // Hz
const FREQUENCY: u32 = 1; // Hz
// TASKS & RESOURCES
app! {
......
//! 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};
/// 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));
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) {
// 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
......@@ -46,4 +46,5 @@ use frequency::*;
pub use hal::prelude;
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 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>;
/// Channel associated to a timer
#[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
pub struct Error {
_0: (),
impl<'a, T> Clone for Timer<'a, T> {
fn clone(&self) -> Self {
*self
}
}
/// Periodic timer
///
/// # Interrupts
///
/// - `Tim11` - update event
pub struct Timer<'a>(pub &'a TIM11);
impl<'a, T> Copy for Timer<'a, T> {}
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
///
/// NOTE After initialization, the timer will be in the paused state.
pub fn init(&self, rcc: &RCC, frequency: u32) {
let tim11 = self.0;
pub fn init<P>(&self, period: P, rcc: &RCC)
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());
}
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)});
// Configure periodic update event
self._set_timeout(timeout);
tim11.dier.write(|w| w.uie().set_bit());
// tim7.cr1.write(|w| w.opm().continuous());
// 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;
fn _set_timeout(&self, timeout: ::$APB::Ticks) {
let period = timeout.0;
if tim11.sr.read().uif().bit_is_clear() {
Err(Error { _0: () })
} else {
self.0.sr.modify(|_, w| w.uif().clear_bit());
Ok(())
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) {
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);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment