2020-11-12 01:44:28 +08:00
|
|
|
///! The sampling timer is used for managing ADC sampling and external reference timestamping.
|
2020-11-12 01:28:48 +08:00
|
|
|
use super::hal;
|
|
|
|
|
2020-12-08 00:29:36 +08:00
|
|
|
macro_rules! timer_channels {
|
2020-12-08 20:53:34 +08:00
|
|
|
($name:ident, $TY:ident, u32) => {
|
2020-12-08 00:29:36 +08:00
|
|
|
paste::paste! {
|
2020-12-08 00:58:36 +08:00
|
|
|
|
|
|
|
/// The timer used for managing ADC sampling.
|
|
|
|
pub struct $name {
|
|
|
|
timer: hal::timer::Timer<hal::stm32::[< $TY >]>,
|
|
|
|
channels: Option<[< $TY:lower >]::Channels>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl $name {
|
|
|
|
/// Construct the sampling timer.
|
|
|
|
pub fn new(mut timer: hal::timer::Timer<hal::stm32::[< $TY>]>) -> Self {
|
|
|
|
timer.pause();
|
|
|
|
|
|
|
|
Self {
|
|
|
|
timer,
|
|
|
|
// Note(unsafe): Once these channels are taken, we guarantee that we do not modify any
|
|
|
|
// of the underlying timer channel registers, as ownership of the channels is now
|
|
|
|
// provided through the associated channel structures. We additionally guarantee this
|
|
|
|
// can only be called once because there is only one Timer2 and this resource takes
|
|
|
|
// ownership of it once instantiated.
|
|
|
|
channels: unsafe { Some([< $TY:lower >]::Channels::new()) },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the timer capture/compare channels.
|
|
|
|
pub fn channels(&mut self) -> [< $TY:lower >]::Channels {
|
|
|
|
self.channels.take().unwrap()
|
|
|
|
}
|
|
|
|
|
2020-12-08 20:53:34 +08:00
|
|
|
/// Get the period of the timer.
|
2020-12-08 01:11:46 +08:00
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn get_period(&self) -> u32 {
|
|
|
|
let regs = unsafe { &*hal::stm32::$TY::ptr() };
|
|
|
|
regs.arr.read().arr().bits()
|
|
|
|
}
|
|
|
|
|
2020-12-08 20:53:34 +08:00
|
|
|
/// Manually set the period of the timer.
|
2020-12-08 01:11:46 +08:00
|
|
|
#[allow(dead_code)]
|
2021-01-05 00:12:24 +08:00
|
|
|
pub fn set_period_ticks(&mut self, period: u32) {
|
2020-12-08 01:11:46 +08:00
|
|
|
let regs = unsafe { &*hal::stm32::$TY::ptr() };
|
|
|
|
regs.arr.write(|w| w.arr().bits(period));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Start the timer.
|
|
|
|
pub fn start(mut self) {
|
|
|
|
// Force a refresh of the frequency settings.
|
|
|
|
self.timer.apply_freq();
|
|
|
|
|
2020-12-08 00:58:36 +08:00
|
|
|
self.timer.reset_counter();
|
|
|
|
self.timer.resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-08 00:29:36 +08:00
|
|
|
pub mod [< $TY:lower >] {
|
2020-12-08 00:58:36 +08:00
|
|
|
pub use hal::stm32::tim2::ccmr1_input::{CC1S_A, CC2S_A};
|
|
|
|
pub use hal::stm32::tim2::ccmr2_input::{CC3S_A, CC4S_A};
|
2020-12-08 00:29:36 +08:00
|
|
|
|
|
|
|
use stm32h7xx_hal as hal;
|
|
|
|
use hal::dma::{traits::TargetAddress, PeripheralToMemory, dma::DMAReq};
|
2020-12-08 00:58:36 +08:00
|
|
|
use hal::stm32::$TY;
|
2020-12-08 00:29:36 +08:00
|
|
|
|
|
|
|
/// The channels representing the timer.
|
|
|
|
pub struct Channels {
|
|
|
|
pub ch1: Channel1,
|
|
|
|
pub ch2: Channel2,
|
|
|
|
pub ch3: Channel3,
|
|
|
|
pub ch4: Channel4,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Channels {
|
|
|
|
/// Construct a new set of channels.
|
|
|
|
///
|
|
|
|
/// Note(unsafe): This is only safe to call once.
|
|
|
|
pub unsafe fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
ch1: Channel1::new(),
|
|
|
|
ch2: Channel2::new(),
|
|
|
|
ch3: Channel3::new(),
|
|
|
|
ch4: Channel4::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
timer_channels!(1, $TY, ccmr1);
|
|
|
|
timer_channels!(2, $TY, ccmr1);
|
|
|
|
timer_channels!(3, $TY, ccmr2);
|
|
|
|
timer_channels!(4, $TY, ccmr2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2020-11-23 21:30:29 +08:00
|
|
|
|
2020-12-08 00:29:36 +08:00
|
|
|
($index:expr, $TY:ty, $ccmrx:expr) => {
|
2020-11-23 21:30:29 +08:00
|
|
|
paste::paste! {
|
2020-12-08 20:53:34 +08:00
|
|
|
/// A capture/compare channel of the timer.
|
2020-12-08 00:29:36 +08:00
|
|
|
pub struct [< Channel $index >] {}
|
|
|
|
|
2020-12-08 20:53:34 +08:00
|
|
|
/// A capture channel of the timer.
|
2020-12-08 00:29:36 +08:00
|
|
|
pub struct [< Channel $index InputCapture>] {}
|
|
|
|
|
|
|
|
impl [< Channel $index >] {
|
2020-11-23 21:30:29 +08:00
|
|
|
/// Construct a new timer channel.
|
|
|
|
///
|
|
|
|
/// Note(unsafe): This function must only be called once. Once constructed, the
|
|
|
|
/// constructee guarantees to never modify the timer channel.
|
|
|
|
unsafe fn new() -> Self {
|
|
|
|
Self {}
|
|
|
|
}
|
|
|
|
|
2020-12-08 00:29:36 +08:00
|
|
|
/// Allow the channel to generate DMA requests.
|
2020-12-08 00:58:36 +08:00
|
|
|
#[allow(dead_code)]
|
2020-11-23 21:30:29 +08:00
|
|
|
pub fn listen_dma(&self) {
|
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
2020-12-08 00:29:36 +08:00
|
|
|
regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit());
|
2020-11-23 21:30:29 +08:00
|
|
|
}
|
|
|
|
|
2020-12-08 00:29:36 +08:00
|
|
|
/// Operate the channel as an output-compare.
|
2020-11-23 21:30:29 +08:00
|
|
|
///
|
|
|
|
/// # Args
|
|
|
|
/// * `value` - The value to compare the sampling timer's counter against.
|
2020-12-08 00:58:36 +08:00
|
|
|
#[allow(dead_code)]
|
2020-11-23 21:30:29 +08:00
|
|
|
pub fn to_output_compare(&self, value: u32) {
|
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
|
|
|
assert!(value <= regs.arr.read().bits());
|
2020-12-08 00:29:36 +08:00
|
|
|
regs.[< ccr $index >].write(|w| w.ccr().bits(value));
|
|
|
|
regs.[< $ccmrx _output >]()
|
|
|
|
.modify(|_, w| unsafe { w.[< cc $index s >]().bits(0) });
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Operate the channel in input-capture mode.
|
|
|
|
///
|
|
|
|
/// # Args
|
|
|
|
/// * `input` - The input source for the input capture event.
|
2020-12-08 00:58:36 +08:00
|
|
|
#[allow(dead_code)]
|
2021-01-05 00:12:24 +08:00
|
|
|
pub fn into_input_capture(self, input: hal::stm32::tim2::[< $ccmrx _input >]::[< CC $index S_A >]) -> [< Channel $index InputCapture >]{
|
2020-12-08 00:29:36 +08:00
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
|
|
|
regs.[< $ccmrx _input >]().modify(|_, w| w.[< cc $index s>]().variant(input));
|
|
|
|
|
|
|
|
[< Channel $index InputCapture >] {}
|
2020-11-23 21:30:29 +08:00
|
|
|
}
|
|
|
|
}
|
2020-11-12 01:28:48 +08:00
|
|
|
|
2020-12-08 20:53:34 +08:00
|
|
|
impl [< Channel $index InputCapture >] {
|
|
|
|
/// Get the latest capture from the channel.
|
|
|
|
#[allow(dead_code)]
|
2021-01-05 01:04:01 +08:00
|
|
|
pub fn latest_capture(&mut self) -> Result<Option<u32>, ()> {
|
2020-12-08 20:53:34 +08:00
|
|
|
// Note(unsafe): This channel owns all access to the specific timer channel.
|
|
|
|
// Only atomic operations on completed on the timer registers.
|
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
|
|
|
let sr = regs.sr.read();
|
2021-01-05 01:04:01 +08:00
|
|
|
|
|
|
|
let result = if sr.[< cc $index if >]().bit_is_set() {
|
2021-01-06 19:24:09 +08:00
|
|
|
// Read the capture value. Reading the captured value clears the flag in the
|
|
|
|
// status register automatically.
|
|
|
|
let ccx = regs.[< ccr $index >].read();
|
2020-12-08 20:53:34 +08:00
|
|
|
Some(ccx.ccr().bits())
|
|
|
|
} else {
|
|
|
|
None
|
2021-01-05 01:04:01 +08:00
|
|
|
};
|
|
|
|
|
2021-01-06 19:24:09 +08:00
|
|
|
// Read SR again to check for a potential over-capture. If there is an
|
|
|
|
// overcapture, return an error.
|
|
|
|
if regs.sr.read().[< cc $index of >]().bit_is_clear() {
|
2021-01-05 01:04:01 +08:00
|
|
|
Ok(result)
|
|
|
|
} else {
|
2021-01-06 19:24:09 +08:00
|
|
|
regs.sr.modify(|_, w| w.[< cc $index of >]().clear_bit());
|
2021-01-05 01:04:01 +08:00
|
|
|
Err(())
|
2020-12-08 20:53:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-08 23:14:27 +08:00
|
|
|
/// Allow the channel to generate DMA requests.
|
2020-12-08 20:53:34 +08:00
|
|
|
#[allow(dead_code)]
|
2020-12-08 23:14:27 +08:00
|
|
|
pub fn listen_dma(&self) {
|
2020-12-08 20:53:34 +08:00
|
|
|
// Note(unsafe): This channel owns all access to the specific timer channel.
|
|
|
|
// Only atomic operations on completed on the timer registers.
|
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
2020-12-08 23:14:27 +08:00
|
|
|
regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit());
|
2020-12-08 20:53:34 +08:00
|
|
|
}
|
|
|
|
|
2020-12-08 23:14:27 +08:00
|
|
|
/// Enable the input capture to begin capturing timer values.
|
2020-12-08 20:53:34 +08:00
|
|
|
#[allow(dead_code)]
|
2020-12-08 23:14:27 +08:00
|
|
|
pub fn enable(&mut self) {
|
2020-12-08 20:53:34 +08:00
|
|
|
// Note(unsafe): This channel owns all access to the specific timer channel.
|
|
|
|
// Only atomic operations on completed on the timer registers.
|
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
2020-12-08 23:14:27 +08:00
|
|
|
regs.ccer.modify(|_, w| w.[< cc $index e >]().set_bit());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check if an over-capture event has occurred.
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn check_overcapture(&self) -> bool {
|
|
|
|
// Note(unsafe): This channel owns all access to the specific timer channel.
|
|
|
|
// Only atomic operations on completed on the timer registers.
|
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
|
|
|
regs.sr.read().[< cc $index of >]().bit_is_set()
|
2020-12-08 20:53:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note(unsafe): This manually implements DMA support for input-capture channels. This
|
|
|
|
// is safe as it is only completed once per channel and each DMA request is allocated to
|
|
|
|
// each channel as the owner.
|
2020-12-08 00:29:36 +08:00
|
|
|
unsafe impl TargetAddress<PeripheralToMemory> for [< Channel $index InputCapture >] {
|
2020-12-08 20:53:34 +08:00
|
|
|
type MemSize = u32;
|
2020-11-12 01:28:48 +08:00
|
|
|
|
2020-12-08 00:29:36 +08:00
|
|
|
const REQUEST_LINE: Option<u8> = Some(DMAReq::[< $TY _CH $index >]as u8);
|
2020-11-12 01:28:48 +08:00
|
|
|
|
2020-12-08 00:29:36 +08:00
|
|
|
fn address(&self) -> u32 {
|
|
|
|
let regs = unsafe { &*<$TY>::ptr() };
|
|
|
|
®s.[<ccr $index >] as *const _ as u32
|
|
|
|
}
|
2020-11-23 21:30:29 +08:00
|
|
|
}
|
|
|
|
}
|
2020-12-08 00:29:36 +08:00
|
|
|
};
|
2020-11-12 01:28:48 +08:00
|
|
|
}
|
2020-12-08 00:29:36 +08:00
|
|
|
|
2020-12-08 20:53:34 +08:00
|
|
|
timer_channels!(SamplingTimer, TIM2, u32);
|
|
|
|
timer_channels!(TimestampTimer, TIM5, u32);
|