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

Fix input capture. Auto-format.

parent 98c8c8d8
No related branches found
No related tags found
No related merge requests found
Showing
with 586 additions and 149 deletions
target remote :3333
monitor arm semihosting enable
monitor reset halt
# monitor arm semihosting enable
# # send captured ITM to the file itm.fifo
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
# # 8000000 must match the core clock frequency
# monitor tpiu config internal itm.fifo uart off 8000000
monitor tpiu config internal itm.fifo uart off 16000000
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
# # 2000000 is the frequency of the SWO pin
# monitor tpiu config external uart off 8000000 2000000
# # enable ITM port 0
# monitor itm port 0 on
monitor itm port 0 on
load
# step
......@@ -4,9 +4,9 @@
#![feature(proc_macro)]
#![no_std]
extern crate f4;
extern crate cortex_m;
extern crate cortex_m_rtfm as rtfm;
extern crate f4;
use cortex_m::peripheral::SystClkSource;
use f4::led::{self, LED};
......
//! Input capture using TIM4
#![deny(unsafe_code)]
#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]
#[macro_use]
extern crate cortex_m;
extern crate cortex_m_rtfm as rtfm;
extern crate f4;
extern crate nb;
use f4::time::Milliseconds;
use f4::{Capture, Channel};
use f4::prelude::*;
use rtfm::{app, Threshold};
const RESOLUTION: Milliseconds = Milliseconds(1);
app! {
device: f4::stm32f40x,
idle: {
resources: [ITM, TIM4],
},
}
fn init(p: init::Peripherals) {
let capture = Capture(p.TIM4);
capture.init(RESOLUTION, p.GPIOA, p.GPIOB, p.GPIOC, p.RCC);
}
fn idle(_t: &mut Threshold, r: idle::Resources) -> ! {
const CHANNELS: [Channel; 4] = [Channel::_1, Channel::_2, Channel::_3, Channel::_4];
let capture = Capture(&*r.TIM4);
for c in &CHANNELS {
capture.enable(*c);
}
loop {
for c in &CHANNELS {
match capture.capture(*c) {
Ok(snapshot) => {
iprintln!(&r.ITM.stim[0], "{:?}: {:?} ms", c, snapshot);
}
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => {
iprintln!(&r.ITM.stim[0], "{:?}: {:?}", c, e);
panic!("{:?}", e);
}
}
}
}
}
......@@ -21,7 +21,7 @@ extern crate heapless;
use cast::{usize, u8};
use cortex_m::peripheral::SystClkSource;
use f4::Serial;
use f4::leds::{LEDS};
use f4::leds::LEDS;
use f4::prelude::*;
use f4::serial::Event;
use heapless::Vec;
......@@ -96,14 +96,14 @@ fn receive(t: &mut Threshold, mut r: USART2::Resources) {
match &***r.BUFFER {
b"bounce" => {
r.SHARED
.claim_mut(t, |shared, _| { shared.mode = Mode::Bounce; });
r.SHARED.claim_mut(t, |shared, _| {
shared.mode = Mode::Bounce;
});
}
b"continuous" => {
r.SHARED.claim_mut(
t,
|shared, _| { shared.mode = Mode::Continuous; },
);
r.SHARED.claim_mut(t, |shared, _| {
shared.mode = Mode::Continuous;
});
}
b"reverse" => {
r.SHARED.claim_mut(t, |shared, _| {
......
......@@ -9,8 +9,8 @@
#![feature(proc_macro)]
#![no_std]
extern crate f4;
extern crate cortex_m_rtfm as rtfm;
extern crate f4;
use core::u32;
......
......@@ -6,8 +6,8 @@
#![feature(proc_macro)]
#![no_std]
extern crate f4;
extern crate cortex_m_rtfm as rtfm;
extern crate f4;
use f4::prelude::*;
use f4::time::Hertz;
......
......@@ -24,7 +24,7 @@ extern crate heapless;
use cast::{usize, u8};
use cortex_m::peripheral::SystClkSource;
use f4::Serial;
use f4::leds::{LEDS};
use f4::leds::LEDS;
use f4::prelude::*;
use f4::serial::Event;
use f4::time::Hertz;
......
......@@ -5,13 +5,13 @@
#![no_std]
extern crate cast;
extern crate f4;
extern crate cortex_m;
extern crate cortex_m_rtfm as rtfm;
extern crate f4;
use cast::{usize, u8};
use cortex_m::peripheral::SystClkSource;
use f4::leds::{LEDS};
use f4::leds::LEDS;
use rtfm::{app, Threshold};
// CONFIGURATION
......
//! Input capture interface
//!
//! You can use the `Capture` interface with these TIM instances:
//!
//! # TIM1
//!
//! - CH1 = PA8 (5V tolerant)
//! - CH2 = PA9 (5V tolerant)
//! - CH3 = PA10 (5V tolerant)
//! - CH4 = PA11 (5V tolerant)
//!
//! # TIM2
//!
//! - CH1 = PA0
//! - CH2 = PA1
//! - CH3 = PB10
//! - CH4 = PA3 (Unimplemented: conflicts with USB USART2_RX)
//!
//! # TIM3
//!
//! - CH1 = PA6
//! - CH2 = PA7
//! - CH3 = PB0
//! - CH4 = PB1
//!
//! **WARNING** Do not use channels 3 and 4 with the `Capture.capture` API or
//! you'll get junk values.
//!
//! # TIM4
//!
//! - CH1 = PB6 (5V tolerant)
//! - CH2 = PB7 (5V tolerant)
//! - CH3 = PB8 (5V tolerant)
//! - CH4 = PB9 (5V tolerant)
use core::any::{Any, TypeId};
use core::u32;
use cast::{u16, u32};
use hal;
use nb;
use stm32f40x::{TIM1, TIM2, TIM3, TIM4, GPIOA, GPIOB, GPIOC, RCC};
use timer::Channel;
/// Input / capture error
#[derive(Debug)]
pub enum Error {
/// Previous capture value was overwritten
Overcapture,
#[doc(hidden)] _Extensible,
}
/// Interrupt event
pub enum Event {
/// Capture on channel 1
Capture1,
/// Capture on channel 2
Capture2,
/// Capture on channel 3
Capture3,
/// Capture on channel 4
Capture4,
}
/// Input capture interface
pub struct Capture<'a, T>(pub &'a T)
where
T: 'a;
impl<'a, T> Clone for Capture<'a, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, T> Copy for Capture<'a, T> {}
// TODO: TIM1 is a 16 bit timer, must have its own implementation
macro_rules! impl_Capture {
($TIM:ident, $APB:ident) => {
impl<'a> Capture<'a, $TIM>
{
/// Initializes the input capture interface
///
/// `resolution` is the resolution of the capture timer
pub fn init<R>(
&self,
resolution: R,
gpioa: &GPIOA, // TODO: Make these optional/implement custom init for each TIM
gpiob: &GPIOB,
gpioc: &GPIOC,
rcc: &RCC)
where
R: Into<::$APB::Ticks>,
{
self._init(resolution.into(), gpioa, gpiob, gpioc, rcc)
}
fn _init(
&self,
resolution: ::$APB::Ticks,
gpioa: &GPIOA,
gpiob: &GPIOB,
gpioc: &GPIOC,
rcc: &RCC) {
let tim = self.0;
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());
}
// enable AFIO, GPIOx and TIMx
rcc.ahb1enr.modify(|_, w| {
if tim.get_type_id() == TypeId::of::<TIM2>() {
w.gpioaen().set_bit().gpioben().set_bit()
} else if tim.get_type_id() == TypeId::of::<TIM3>() {
w.gpioaen().set_bit().gpioben().set_bit().gpiocen().set_bit()
} else if tim.get_type_id() == TypeId::of::<TIM4>() {
w.gpioben().set_bit()
} else {
unreachable!()
}
});
// don't remap TIM pins
if tim.get_type_id() == TypeId::of::<TIM2>() {
// CH1 = PA0 = floating input
// CH2 = PA1 = floating input
// CH3 = PB10 = floating input
// CH4 = PA3 = floating input (Unimplemented: conflicts with USB USART2_RX)
// See datasheet DM00115249 Table 9. Alternate function mapping
gpioa.afrl.modify(|_, w| {
w.afrl0().bits(1)
.afrl1().bits(1)
});
gpioa.moder.modify(|_, w| {
w.moder0().bits(2)
.moder1().bits(2)
});
gpiob.afrh.modify(|_, w| { unsafe {
w.afrh10().bits(1)
}});
gpiob.moder.modify(|_, w| { unsafe {
w.moder10().bits(2)
}});
} else if tim.get_type_id() == TypeId::of::<TIM3>() {
// CH1 = PA6 = floating input
// CH2 = PC7 = floating input
// CH3 = PB0 = floating input
// CH4 = PB1 = floating input
gpioa.afrl.modify(|_, w| {
w.afrl6().bits(2)
});
gpioa.moder.modify(|_, w| {
w.moder6().bits(2)
});
gpiob.afrl.modify(|_, w| { unsafe {
w.afrl0().bits(2)
.afrl1().bits(2)
}});
gpiob.moder.modify(|_, w| { unsafe {
w.moder0().bits(2)
.moder1().bits(2)
}});
gpioc.afrl.modify(|_, w| { unsafe {
w.afrl7().bits(2)
}});
gpioc.moder.modify(|_, w| { unsafe {
w.moder7().bits(2)
}});
} else if tim.get_type_id() == TypeId::of::<TIM4>() {
// CH1 = PB6 = alternate push-pull
// CH2 = PB7 = alternate push-pull
// CH3 = PB8 = alternate push-pull
// CH4 = PB9 = alternate push-pull
gpiob.afrl.modify(|_, w| { unsafe {
w.afrl6().bits(2)
.afrl7().bits(2)
}
});
gpiob.moder.modify(|_, w| { unsafe {
w.moder6().bits(2)
.moder7().bits(2)
}
});
gpiob.afrh.modify(|_, w| { unsafe {
w.afrh8().bits(2)
.afrh9().bits(2)
}
});
gpiob.moder.modify(|_, w| { unsafe {
w.moder8().bits(2)
.moder9().bits(2)
}
});
gpiob.pupdr.modify(|_, w| { unsafe {
w.pupdr6().bits(2)
.pupdr7().bits(2)
.pupdr8().bits(2)
.pupdr9().bits(2)
}
});
}
tim.smcr.write(|w| unsafe {
w.bits(3)
});
// configure CC{1,2,3,4} as input and wire it to TI{1,2,3,4}
// apply the heaviest filter
tim.ccmr1_output.write(|w| unsafe {
w.bits((0b1111 << 12) | (0b01 << 8) | (0b1111 << 4) | (0b01 << 0))
});
// if tim.get_type_id() != TypeId::of::<TIM3>() {
// tim.ccmr2_output.write(|w| unsafe {
// w.bits(0)
// });
// }
// enable capture on rising edge
// capture pins disabled by default
if tim.get_type_id() == TypeId::of::<TIM2>() {
tim.ccer.modify(|_, w| {
w.cc1p()
.clear_bit()
.cc1e()
.clear_bit()
.cc2p()
.clear_bit()
.cc2e()
.clear_bit()
.cc3p()
.clear_bit()
.cc3e()
.clear_bit()
});
} else {
tim.ccer.modify(|_, w| {
w.cc1p()
.clear_bit()
.cc1e()
.clear_bit()
.cc2p()
.clear_bit()
.cc2e()
.clear_bit()
.cc3p()
.clear_bit()
.cc3e()
.clear_bit()
.cc4p()
.clear_bit()
.cc4e()
.clear_bit()
});
}
self._set_resolution(resolution);
tim.arr.write(|w| unsafe{ w.bits(u32::MAX) });
// configure timer as a continuous upcounter and start
tim.cr1.write(|w| w.dir().bit(false).opm().bit(false).cen().set_bit());
}
/// Starts listening for an interrupt `event`
pub fn listen(&self, event: Event) {
let tim = self.0;
match event {
Event::Capture1 => tim.dier.modify(|_, w| w.cc1ie().set_bit()),
Event::Capture2 => tim.dier.modify(|_, w| w.cc2ie().set_bit()),
Event::Capture3 => tim.dier.modify(|_, w| w.cc3ie().set_bit()),
Event::Capture4 => tim.dier.modify(|_, w| w.cc4ie().set_bit()),
}
}
/// Stops listening for an interrupt `event`
pub fn unlisten(&self, event: Event) {
let tim = self.0;
match event {
Event::Capture1 => tim.dier.modify(|_, w| w.cc1ie().clear_bit()),
Event::Capture2 => tim.dier.modify(|_, w| w.cc2ie().clear_bit()),
Event::Capture3 => tim.dier.modify(|_, w| w.cc3ie().clear_bit()),
Event::Capture4 => tim.dier.modify(|_, w| w.cc4ie().clear_bit()),
}
}
fn _set_resolution(&self, resolution: ::$APB::Ticks) {
let psc = resolution.0.checked_sub(1).expect("impossible resolution");
self.0.psc.write(|w| unsafe{ w.bits(psc)});
}
}
impl<'a> hal::Capture for Capture<'a, $TIM>
{
type Capture = u32;
type Channel = Channel;
type Error = Error;
type Time = ::$APB::Ticks;
fn capture(&self, channel: Channel) -> nb::Result<u32, Error> {
let tim = self.0;
let sr = tim.sr.read();
match channel {
Channel::_1 => if sr.cc1of().bit_is_set() {
Err(nb::Error::Other(Error::Overcapture))
} else if sr.cc1if().bit_is_set() {
Ok(tim.ccr1.read().bits())
} else {
Err(nb::Error::WouldBlock)
},
Channel::_2 => if sr.cc2of().bit_is_set() {
Err(nb::Error::Other(Error::Overcapture))
} else if sr.cc2if().bit_is_set() {
Ok(tim.ccr2.read().bits())
} else {
Err(nb::Error::WouldBlock)
},
Channel::_3 => if sr.cc3of().bit_is_set() {
Err(nb::Error::Other(Error::Overcapture))
} else if sr.cc3if().bit_is_set() {
Ok(tim.ccr3.read().bits())
} else {
Err(nb::Error::WouldBlock)
},
Channel::_4 => if sr.cc4of().bit_is_set() {
Err(nb::Error::Other(Error::Overcapture))
} else if sr.cc4if().bit_is_set() {
Ok(tim.ccr4.read().bits())
} else {
Err(nb::Error::WouldBlock)
},
}
}
fn disable(&self, channel: Channel) {
match channel {
Channel::_1 => self.0.ccer.modify(|_, w| w.cc1e().clear_bit()),
Channel::_2 => self.0.ccer.modify(|_, w| w.cc2e().clear_bit()),
Channel::_3 => self.0.ccer.modify(|_, w| w.cc3e().clear_bit()),
Channel::_4 => self.0.ccer.modify(|_, w| w.cc4e().clear_bit()),
}
}
fn enable(&self, channel: Channel) {
match channel {
Channel::_1 => self.0.ccer.modify(|_, w| w.cc1e().set_bit()),
Channel::_2 => self.0.ccer.modify(|_, w| w.cc2e().set_bit()),
Channel::_3 => self.0.ccer.modify(|_, w| w.cc3e().set_bit()),
Channel::_4 => self.0.ccer.modify(|_, w| w.cc4e().set_bit()),
}
}
fn get_resolution(&self) -> ::$APB::Ticks {
::$APB::Ticks(u32(self.0.psc.read().psc().bits()))
}
fn set_resolution<R>(&self, resolution: R)
where
R: Into<::$APB::Ticks>,
{
self._set_resolution(resolution.into())
}
}
}
}
impl_Capture!(TIM2, apb1);
impl_Capture!(TIM3, apb1);
impl_Capture!(TIM4, apb1);
......@@ -17,7 +17,6 @@ pub fn init(gpioa: &GPIOA, rcc: &RCC) {
// configure PC13 as output
gpioa.moder.write(|w| w.moder5().bits(1));
}
impl PA5 {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment