Refactoring timer timestamping
This commit is contained in:
parent
fc81c8b5d8
commit
ec046bc42d
12
src/adc.rs
12
src/adc.rs
|
@ -14,8 +14,8 @@
|
||||||
///! both transfers are completed before reading the data. This is usually not significant for
|
///! both transfers are completed before reading the data. This is usually not significant for
|
||||||
///! busy-waiting because the transfers should complete at approximately the same time.
|
///! busy-waiting because the transfers should complete at approximately the same time.
|
||||||
use super::{
|
use super::{
|
||||||
hal, sampling_timer, DMAReq, DmaConfig, MemoryToPeripheral,
|
hal, timers, DMAReq, DmaConfig, MemoryToPeripheral, PeripheralToMemory,
|
||||||
PeripheralToMemory, Priority, TargetAddress, Transfer, SAMPLE_BUFFER_SIZE,
|
Priority, TargetAddress, Transfer, SAMPLE_BUFFER_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following data is written by the timer ADC sample trigger into each of the SPI TXFIFOs. Note
|
// The following data is written by the timer ADC sample trigger into each of the SPI TXFIFOs. Note
|
||||||
|
@ -38,12 +38,10 @@ macro_rules! adc_input {
|
||||||
/// $spi is used as a type for indicating a DMA transfer into the SPI TX FIFO
|
/// $spi is used as a type for indicating a DMA transfer into the SPI TX FIFO
|
||||||
/// whenever the tim2 update dma request occurs.
|
/// whenever the tim2 update dma request occurs.
|
||||||
struct $spi {
|
struct $spi {
|
||||||
_channel: sampling_timer::tim2::$trigger_channel,
|
_channel: timers::tim2::$trigger_channel,
|
||||||
}
|
}
|
||||||
impl $spi {
|
impl $spi {
|
||||||
pub fn new(
|
pub fn new(_channel: timers::tim2::$trigger_channel) -> Self {
|
||||||
_channel: sampling_timer::tim2::$trigger_channel,
|
|
||||||
) -> Self {
|
|
||||||
Self { _channel }
|
Self { _channel }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +98,7 @@ macro_rules! adc_input {
|
||||||
hal::stm32::DMA1,
|
hal::stm32::DMA1,
|
||||||
>,
|
>,
|
||||||
data_stream: hal::dma::dma::$data_stream<hal::stm32::DMA1>,
|
data_stream: hal::dma::dma::$data_stream<hal::stm32::DMA1>,
|
||||||
trigger_channel: sampling_timer::tim2::$trigger_channel,
|
trigger_channel: timers::tim2::$trigger_channel,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Generate DMA events when an output compare of the timer hitting zero (timer roll over)
|
// Generate DMA events when an output compare of the timer hitting zero (timer roll over)
|
||||||
// occurs.
|
// occurs.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
///! configured to generate a DMA write into the SPI TXFIFO, which initiates a SPI transfer and
|
///! configured to generate a DMA write into the SPI TXFIFO, which initiates a SPI transfer and
|
||||||
///! results in DAC update for both channels.
|
///! results in DAC update for both channels.
|
||||||
use super::{
|
use super::{
|
||||||
hal, sampling_timer, DMAReq, DmaConfig, MemoryToPeripheral, TargetAddress,
|
hal, timers, DMAReq, DmaConfig, MemoryToPeripheral, TargetAddress,
|
||||||
Transfer, SAMPLE_BUFFER_SIZE,
|
Transfer, SAMPLE_BUFFER_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,12 +22,12 @@ macro_rules! dac_output {
|
||||||
/// $spi is used as a type for indicating a DMA transfer into the SPI TX FIFO
|
/// $spi is used as a type for indicating a DMA transfer into the SPI TX FIFO
|
||||||
struct $spi {
|
struct $spi {
|
||||||
spi: hal::spi::Spi<hal::stm32::$spi, hal::spi::Disabled, u16>,
|
spi: hal::spi::Spi<hal::stm32::$spi, hal::spi::Disabled, u16>,
|
||||||
_channel: sampling_timer::tim2::$trigger_channel,
|
_channel: timers::tim2::$trigger_channel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $spi {
|
impl $spi {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_channel: sampling_timer::tim2::$trigger_channel,
|
_channel: timers::tim2::$trigger_channel,
|
||||||
spi: hal::spi::Spi<hal::stm32::$spi, hal::spi::Disabled, u16>,
|
spi: hal::spi::Spi<hal::stm32::$spi, hal::spi::Disabled, u16>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self { _channel, spi }
|
Self { _channel, spi }
|
||||||
|
@ -73,7 +73,7 @@ macro_rules! dac_output {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spi: hal::spi::Spi<hal::stm32::$spi, hal::spi::Enabled, u16>,
|
spi: hal::spi::Spi<hal::stm32::$spi, hal::spi::Enabled, u16>,
|
||||||
stream: hal::dma::dma::$data_stream<hal::stm32::DMA1>,
|
stream: hal::dma::dma::$data_stream<hal::stm32::DMA1>,
|
||||||
trigger_channel: sampling_timer::tim2::$trigger_channel,
|
trigger_channel: timers::tim2::$trigger_channel,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Generate DMA events when an output compare of the timer hitting zero (timer roll over)
|
// Generate DMA events when an output compare of the timer hitting zero (timer roll over)
|
||||||
// occurs.
|
// occurs.
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
use super::{hal, sampling_timer, DmaConfig, PeripheralToMemory, Transfer};
|
use super::{hal, timers, DmaConfig, PeripheralToMemory, Transfer};
|
||||||
|
|
||||||
const INPUT_BUFFER_SIZE: usize = 1;
|
const INPUT_BUFFER_SIZE: usize = 1;
|
||||||
|
|
||||||
#[link_section = ".axisram.buffers"]
|
#[link_section = ".axisram.buffers"]
|
||||||
static mut BUF0: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE];
|
static mut BUF: [[u16; INPUT_BUFFER_SIZE]; 2] = [[0; INPUT_BUFFER_SIZE]; 2];
|
||||||
|
|
||||||
#[link_section = ".axisram.buffers"]
|
|
||||||
static mut BUF1: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE];
|
|
||||||
|
|
||||||
pub struct InputStamper {
|
pub struct InputStamper {
|
||||||
_di0_trigger: hal::gpio::gpioa::PA3<hal::gpio::Alternate<hal::gpio::AF1>>,
|
_di0_trigger: hal::gpio::gpioa::PA3<hal::gpio::Alternate<hal::gpio::AF2>>,
|
||||||
timestamp_buffer: heapless::Vec<u16, heapless::consts::U128>,
|
timestamp_buffer: heapless::Vec<u16, heapless::consts::U128>,
|
||||||
next_buffer: Option<&'static mut [u16; INPUT_BUFFER_SIZE]>,
|
next_buffer: Option<&'static mut [u16; INPUT_BUFFER_SIZE]>,
|
||||||
transfer: Transfer<
|
transfer: Transfer<
|
||||||
hal::dma::dma::Stream6<hal::stm32::DMA1>,
|
hal::dma::dma::Stream6<hal::stm32::DMA1>,
|
||||||
sampling_timer::tim2::Channel4InputCapture,
|
timers::tim5::Channel4InputCapture,
|
||||||
PeripheralToMemory,
|
PeripheralToMemory,
|
||||||
&'static mut [u16; INPUT_BUFFER_SIZE],
|
&'static mut [u16; INPUT_BUFFER_SIZE],
|
||||||
>,
|
>,
|
||||||
|
@ -22,17 +19,19 @@ pub struct InputStamper {
|
||||||
|
|
||||||
impl InputStamper {
|
impl InputStamper {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
trigger: hal::gpio::gpioa::PA3<hal::gpio::Alternate<hal::gpio::AF1>>,
|
trigger: hal::gpio::gpioa::PA3<hal::gpio::Alternate<hal::gpio::AF2>>,
|
||||||
stream: hal::dma::dma::Stream6<hal::stm32::DMA1>,
|
stream: hal::dma::dma::Stream6<hal::stm32::DMA1>,
|
||||||
timer_channel: sampling_timer::tim2::Channel4,
|
timer_channel: timers::tim5::Channel4,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Utilize the TIM2 CH4 as an input capture channel - use TI4 (the DI0 input trigger) as the
|
// Utilize the TIM5 CH4 as an input capture channel - use TI4 (the DI0 input trigger) as the
|
||||||
// capture source.
|
// capture source.
|
||||||
timer_channel.listen_dma();
|
timer_channel.listen_dma();
|
||||||
let input_capture = timer_channel.to_input_capture(sampling_timer::tim2::CC4S_A::TI4);
|
let input_capture =
|
||||||
|
timer_channel.to_input_capture(timers::tim5::CC4S_A::TI4);
|
||||||
|
|
||||||
// Set up the DMA transfer.
|
// Set up the DMA transfer.
|
||||||
let dma_config = DmaConfig::default()
|
let dma_config = DmaConfig::default()
|
||||||
|
.transfer_complete_interrupt(true)
|
||||||
.memory_increment(true)
|
.memory_increment(true)
|
||||||
.peripheral_increment(false);
|
.peripheral_increment(false);
|
||||||
|
|
||||||
|
@ -40,7 +39,7 @@ impl InputStamper {
|
||||||
Transfer::init(
|
Transfer::init(
|
||||||
stream,
|
stream,
|
||||||
input_capture,
|
input_capture,
|
||||||
unsafe { &mut BUF0 },
|
unsafe { &mut BUF[0] },
|
||||||
None,
|
None,
|
||||||
dma_config,
|
dma_config,
|
||||||
);
|
);
|
||||||
|
@ -49,7 +48,7 @@ impl InputStamper {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
timestamp_buffer: heapless::Vec::new(),
|
timestamp_buffer: heapless::Vec::new(),
|
||||||
next_buffer: unsafe { Some(&mut BUF1) },
|
next_buffer: unsafe { Some(&mut BUF[1]) },
|
||||||
transfer: timestamp_transfer,
|
transfer: timestamp_transfer,
|
||||||
_di0_trigger: trigger,
|
_di0_trigger: trigger,
|
||||||
}
|
}
|
||||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -69,13 +69,13 @@ static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
|
||||||
mod adc;
|
mod adc;
|
||||||
mod afe;
|
mod afe;
|
||||||
mod dac;
|
mod dac;
|
||||||
mod digital_input_stamper;
|
|
||||||
mod hrtimer;
|
|
||||||
mod design_parameters;
|
mod design_parameters;
|
||||||
|
mod digital_input_stamper;
|
||||||
mod eeprom;
|
mod eeprom;
|
||||||
|
mod hrtimer;
|
||||||
mod pounder;
|
mod pounder;
|
||||||
mod sampling_timer;
|
|
||||||
mod server;
|
mod server;
|
||||||
|
mod timers;
|
||||||
|
|
||||||
use adc::{Adc0Input, Adc1Input};
|
use adc::{Adc0Input, Adc1Input};
|
||||||
use dac::{Dac0Output, Dac1Output};
|
use dac::{Dac0Output, Dac1Output};
|
||||||
|
@ -285,9 +285,22 @@ const APP: () = {
|
||||||
&ccdr.clocks,
|
&ccdr.clocks,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut sampling_timer = sampling_timer::SamplingTimer::new(timer2);
|
let mut sampling_timer = timers::SamplingTimer::new(timer2);
|
||||||
let sampling_timer_channels = sampling_timer.channels();
|
let sampling_timer_channels = sampling_timer.channels();
|
||||||
|
|
||||||
|
let mut timestamp_timer = {
|
||||||
|
// TODO: This needs to be precisely controlled via the prescaler of the timer.
|
||||||
|
let timer5 = dp.TIM5.timer(
|
||||||
|
(SAMPLE_FREQUENCY_KHZ / SAMPLE_BUFFER_SIZE as u32).khz(),
|
||||||
|
ccdr.peripheral.TIM5,
|
||||||
|
&ccdr.clocks,
|
||||||
|
);
|
||||||
|
|
||||||
|
timers::TimestampTimer::new(timer5)
|
||||||
|
};
|
||||||
|
|
||||||
|
let timestamp_timer_channels = timestamp_timer.channels();
|
||||||
|
|
||||||
// Configure the SPI interfaces to the ADCs and DACs.
|
// Configure the SPI interfaces to the ADCs and DACs.
|
||||||
let adcs = {
|
let adcs = {
|
||||||
let adc0 = {
|
let adc0 = {
|
||||||
|
@ -770,16 +783,17 @@ const APP: () = {
|
||||||
cp.DWT.enable_cycle_counter();
|
cp.DWT.enable_cycle_counter();
|
||||||
|
|
||||||
let input_stamper = {
|
let input_stamper = {
|
||||||
let trigger = gpioa.pa3.into_alternate_af1();
|
let trigger = gpioa.pa3.into_alternate_af2();
|
||||||
digital_input_stamper::InputStamper::new(
|
digital_input_stamper::InputStamper::new(
|
||||||
trigger,
|
trigger,
|
||||||
dma_streams.6,
|
dma_streams.6,
|
||||||
sampling_timer_channels.ch4,
|
timestamp_timer_channels.ch4,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start sampling ADCs.
|
// Start sampling ADCs.
|
||||||
sampling_timer.start();
|
sampling_timer.start();
|
||||||
|
timestamp_timer.start();
|
||||||
|
|
||||||
init::LateResources {
|
init::LateResources {
|
||||||
afes: (afe0, afe1),
|
afes: (afe0, afe1),
|
||||||
|
@ -797,11 +811,6 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(binds=DMA1_STR6, resources=[input_stamper], priority = 2)]
|
|
||||||
fn digital_stamper(c: digital_stamper::Context) {
|
|
||||||
panic!("Timestamp overflow")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task(binds=DMA1_STR3, resources=[adcs, dacs, iir_state, iir_ch], priority=2)]
|
#[task(binds=DMA1_STR3, resources=[adcs, dacs, iir_state, iir_ch], priority=2)]
|
||||||
fn process(c: process::Context) {
|
fn process(c: process::Context) {
|
||||||
let adc_samples = [
|
let adc_samples = [
|
||||||
|
@ -833,6 +842,11 @@ const APP: () = {
|
||||||
c.resources.dacs.1.release_buffer(dac1);
|
c.resources.dacs.1.release_buffer(dac1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[task(binds=DMA1_STR6, priority = 2)]
|
||||||
|
fn digital_stamper(_: digital_stamper::Context) {
|
||||||
|
panic!("Timestamp overflow")
|
||||||
|
}
|
||||||
|
|
||||||
#[idle(resources=[net_interface, pounder, mac_addr, eth_mac, iir_state, iir_ch, afes])]
|
#[idle(resources=[net_interface, pounder, mac_addr, eth_mac, iir_state, iir_ch, afes])]
|
||||||
fn idle(mut c: idle::Context) -> ! {
|
fn idle(mut c: idle::Context) -> ! {
|
||||||
let mut socket_set_entries: [_; 8] = Default::default();
|
let mut socket_set_entries: [_; 8] = Default::default();
|
||||||
|
|
|
@ -1,50 +1,51 @@
|
||||||
///! The sampling timer is used for managing ADC sampling and external reference timestamping.
|
///! The sampling timer is used for managing ADC sampling and external reference timestamping.
|
||||||
use super::hal;
|
use super::hal;
|
||||||
|
|
||||||
/// The timer used for managing ADC sampling.
|
|
||||||
pub struct SamplingTimer {
|
|
||||||
timer: hal::timer::Timer<hal::stm32::TIM2>,
|
|
||||||
channels: Option<tim2::Channels>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SamplingTimer {
|
|
||||||
/// Construct the sampling timer.
|
|
||||||
pub fn new(mut timer: hal::timer::Timer<hal::stm32::TIM2>) -> 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(tim2::Channels::new()) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the timer capture/compare channels.
|
|
||||||
pub fn channels(&mut self) -> tim2::Channels {
|
|
||||||
self.channels.take().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Start the sampling timer.
|
|
||||||
pub fn start(&mut self) {
|
|
||||||
self.timer.reset_counter();
|
|
||||||
self.timer.resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! timer_channels {
|
macro_rules! timer_channels {
|
||||||
($TY:ty) => {
|
($name:ident, $TY:ident) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
|
|
||||||
|
/// 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start the sampling timer.
|
||||||
|
pub fn start(&mut self) {
|
||||||
|
self.timer.reset_counter();
|
||||||
|
self.timer.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod [< $TY:lower >] {
|
pub mod [< $TY:lower >] {
|
||||||
pub use hal::stm32::[< $TY:lower >]::ccmr1_input::{CC1S_A, CC2S_A};
|
pub use hal::stm32::tim2::ccmr1_input::{CC1S_A, CC2S_A};
|
||||||
pub use hal::stm32::[< $TY:lower >]::ccmr2_input::{CC3S_A, CC4S_A};
|
pub use hal::stm32::tim2::ccmr2_input::{CC3S_A, CC4S_A};
|
||||||
|
|
||||||
use stm32h7xx_hal as hal;
|
use stm32h7xx_hal as hal;
|
||||||
use hal::dma::{traits::TargetAddress, PeripheralToMemory, dma::DMAReq};
|
use hal::dma::{traits::TargetAddress, PeripheralToMemory, dma::DMAReq};
|
||||||
use hal::stm32::TIM2;
|
use hal::stm32::$TY;
|
||||||
|
|
||||||
/// The channels representing the timer.
|
/// The channels representing the timer.
|
||||||
pub struct Channels {
|
pub struct Channels {
|
||||||
|
@ -92,6 +93,7 @@ macro_rules! timer_channels {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allow the channel to generate DMA requests.
|
/// Allow the channel to generate DMA requests.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn listen_dma(&self) {
|
pub fn listen_dma(&self) {
|
||||||
let regs = unsafe { &*<$TY>::ptr() };
|
let regs = unsafe { &*<$TY>::ptr() };
|
||||||
regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit());
|
regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit());
|
||||||
|
@ -101,6 +103,7 @@ macro_rules! timer_channels {
|
||||||
///
|
///
|
||||||
/// # Args
|
/// # Args
|
||||||
/// * `value` - The value to compare the sampling timer's counter against.
|
/// * `value` - The value to compare the sampling timer's counter against.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn to_output_compare(&self, value: u32) {
|
pub fn to_output_compare(&self, value: u32) {
|
||||||
let regs = unsafe { &*<$TY>::ptr() };
|
let regs = unsafe { &*<$TY>::ptr() };
|
||||||
assert!(value <= regs.arr.read().bits());
|
assert!(value <= regs.arr.read().bits());
|
||||||
|
@ -113,7 +116,8 @@ macro_rules! timer_channels {
|
||||||
///
|
///
|
||||||
/// # Args
|
/// # Args
|
||||||
/// * `input` - The input source for the input capture event.
|
/// * `input` - The input source for the input capture event.
|
||||||
pub fn to_input_capture(self, input: hal::stm32::[<$TY:lower>]::[< $ccmrx _input >]::[< CC $index S_A >]) -> [< Channel $index InputCapture >]{
|
#[allow(dead_code)]
|
||||||
|
pub fn to_input_capture(self, input: hal::stm32::tim2::[< $ccmrx _input >]::[< CC $index S_A >]) -> [< Channel $index InputCapture >]{
|
||||||
let regs = unsafe { &*<$TY>::ptr() };
|
let regs = unsafe { &*<$TY>::ptr() };
|
||||||
regs.[< $ccmrx _input >]().modify(|_, w| w.[< cc $index s>]().variant(input));
|
regs.[< $ccmrx _input >]().modify(|_, w| w.[< cc $index s>]().variant(input));
|
||||||
|
|
||||||
|
@ -135,4 +139,5 @@ macro_rules! timer_channels {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
timer_channels!(TIM2);
|
timer_channels!(SamplingTimer, TIM2);
|
||||||
|
timer_channels!(TimestampTimer, TIM5);
|
Loading…
Reference in New Issue