diff --git a/src/adc.rs b/src/adc.rs index 4017f7f..8d2b61a 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -14,8 +14,8 @@ ///! 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. use super::{ - hal, sampling_timer, DMAReq, DmaConfig, MemoryToPeripheral, - PeripheralToMemory, Priority, TargetAddress, Transfer, SAMPLE_BUFFER_SIZE, + hal, timers, DMAReq, DmaConfig, MemoryToPeripheral, PeripheralToMemory, + Priority, TargetAddress, Transfer, SAMPLE_BUFFER_SIZE, }; // 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 /// whenever the tim2 update dma request occurs. struct $spi { - _channel: sampling_timer::tim2::$trigger_channel, + _channel: timers::tim2::$trigger_channel, } impl $spi { - pub fn new( - _channel: sampling_timer::tim2::$trigger_channel, - ) -> Self { + pub fn new(_channel: timers::tim2::$trigger_channel) -> Self { Self { _channel } } } @@ -100,7 +98,7 @@ macro_rules! adc_input { hal::stm32::DMA1, >, data_stream: hal::dma::dma::$data_stream, - trigger_channel: sampling_timer::tim2::$trigger_channel, + trigger_channel: timers::tim2::$trigger_channel, ) -> Self { // Generate DMA events when an output compare of the timer hitting zero (timer roll over) // occurs. diff --git a/src/dac.rs b/src/dac.rs index 00c24d4..06a6362 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -4,7 +4,7 @@ ///! configured to generate a DMA write into the SPI TXFIFO, which initiates a SPI transfer and ///! results in DAC update for both channels. use super::{ - hal, sampling_timer, DMAReq, DmaConfig, MemoryToPeripheral, TargetAddress, + hal, timers, DMAReq, DmaConfig, MemoryToPeripheral, TargetAddress, 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 struct $spi { spi: hal::spi::Spi, - _channel: sampling_timer::tim2::$trigger_channel, + _channel: timers::tim2::$trigger_channel, } impl $spi { pub fn new( - _channel: sampling_timer::tim2::$trigger_channel, + _channel: timers::tim2::$trigger_channel, spi: hal::spi::Spi, ) -> Self { Self { _channel, spi } @@ -73,7 +73,7 @@ macro_rules! dac_output { pub fn new( spi: hal::spi::Spi, stream: hal::dma::dma::$data_stream, - trigger_channel: sampling_timer::tim2::$trigger_channel, + trigger_channel: timers::tim2::$trigger_channel, ) -> Self { // Generate DMA events when an output compare of the timer hitting zero (timer roll over) // occurs. diff --git a/src/digital_input_stamper.rs b/src/digital_input_stamper.rs index 71cd5b1..8b8f3af 100644 --- a/src/digital_input_stamper.rs +++ b/src/digital_input_stamper.rs @@ -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; #[link_section = ".axisram.buffers"] -static mut BUF0: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE]; - -#[link_section = ".axisram.buffers"] -static mut BUF1: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE]; +static mut BUF: [[u16; INPUT_BUFFER_SIZE]; 2] = [[0; INPUT_BUFFER_SIZE]; 2]; pub struct InputStamper { - _di0_trigger: hal::gpio::gpioa::PA3>, + _di0_trigger: hal::gpio::gpioa::PA3>, timestamp_buffer: heapless::Vec, next_buffer: Option<&'static mut [u16; INPUT_BUFFER_SIZE]>, transfer: Transfer< hal::dma::dma::Stream6, - sampling_timer::tim2::Channel4InputCapture, + timers::tim5::Channel4InputCapture, PeripheralToMemory, &'static mut [u16; INPUT_BUFFER_SIZE], >, @@ -22,17 +19,19 @@ pub struct InputStamper { impl InputStamper { pub fn new( - trigger: hal::gpio::gpioa::PA3>, + trigger: hal::gpio::gpioa::PA3>, stream: hal::dma::dma::Stream6, - timer_channel: sampling_timer::tim2::Channel4, + timer_channel: timers::tim5::Channel4, ) -> 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. 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. let dma_config = DmaConfig::default() + .transfer_complete_interrupt(true) .memory_increment(true) .peripheral_increment(false); @@ -40,7 +39,7 @@ impl InputStamper { Transfer::init( stream, input_capture, - unsafe { &mut BUF0 }, + unsafe { &mut BUF[0] }, None, dma_config, ); @@ -49,7 +48,7 @@ impl InputStamper { Self { timestamp_buffer: heapless::Vec::new(), - next_buffer: unsafe { Some(&mut BUF1) }, + next_buffer: unsafe { Some(&mut BUF[1]) }, transfer: timestamp_transfer, _di0_trigger: trigger, } diff --git a/src/main.rs b/src/main.rs index f168c95..425b401 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,13 +69,13 @@ static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new(); mod adc; mod afe; mod dac; -mod digital_input_stamper; -mod hrtimer; mod design_parameters; +mod digital_input_stamper; mod eeprom; +mod hrtimer; mod pounder; -mod sampling_timer; mod server; +mod timers; use adc::{Adc0Input, Adc1Input}; use dac::{Dac0Output, Dac1Output}; @@ -285,9 +285,22 @@ const APP: () = { &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 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. let adcs = { let adc0 = { @@ -770,16 +783,17 @@ const APP: () = { cp.DWT.enable_cycle_counter(); let input_stamper = { - let trigger = gpioa.pa3.into_alternate_af1(); + let trigger = gpioa.pa3.into_alternate_af2(); digital_input_stamper::InputStamper::new( trigger, dma_streams.6, - sampling_timer_channels.ch4, + timestamp_timer_channels.ch4, ) }; // Start sampling ADCs. sampling_timer.start(); + timestamp_timer.start(); init::LateResources { 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)] fn process(c: process::Context) { let adc_samples = [ @@ -833,6 +842,11 @@ const APP: () = { 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])] fn idle(mut c: idle::Context) -> ! { let mut socket_set_entries: [_; 8] = Default::default(); diff --git a/src/sampling_timer.rs b/src/timers.rs similarity index 64% rename from src/sampling_timer.rs rename to src/timers.rs index 3218996..36f8c01 100644 --- a/src/sampling_timer.rs +++ b/src/timers.rs @@ -1,50 +1,51 @@ ///! The sampling timer is used for managing ADC sampling and external reference timestamping. use super::hal; -/// The timer used for managing ADC sampling. -pub struct SamplingTimer { - timer: hal::timer::Timer, - channels: Option, -} - -impl SamplingTimer { - /// Construct the sampling timer. - pub fn new(mut timer: hal::timer::Timer) -> 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 { - ($TY:ty) => { + ($name:ident, $TY:ident) => { paste::paste! { + + /// The timer used for managing ADC sampling. + pub struct $name { + timer: hal::timer::Timer]>, + channels: Option<[< $TY:lower >]::Channels>, + } + + impl $name { + /// Construct the sampling timer. + pub fn new(mut timer: hal::timer::Timer]>) -> 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 use hal::stm32::[< $TY:lower >]::ccmr1_input::{CC1S_A, CC2S_A}; - pub use hal::stm32::[< $TY:lower >]::ccmr2_input::{CC3S_A, CC4S_A}; + pub use hal::stm32::tim2::ccmr1_input::{CC1S_A, CC2S_A}; + pub use hal::stm32::tim2::ccmr2_input::{CC3S_A, CC4S_A}; use stm32h7xx_hal as hal; use hal::dma::{traits::TargetAddress, PeripheralToMemory, dma::DMAReq}; - use hal::stm32::TIM2; + use hal::stm32::$TY; /// The channels representing the timer. pub struct Channels { @@ -92,6 +93,7 @@ macro_rules! timer_channels { } /// Allow the channel to generate DMA requests. + #[allow(dead_code)] pub fn listen_dma(&self) { let regs = unsafe { &*<$TY>::ptr() }; regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit()); @@ -101,6 +103,7 @@ macro_rules! timer_channels { /// /// # Args /// * `value` - The value to compare the sampling timer's counter against. + #[allow(dead_code)] pub fn to_output_compare(&self, value: u32) { let regs = unsafe { &*<$TY>::ptr() }; assert!(value <= regs.arr.read().bits()); @@ -113,7 +116,8 @@ macro_rules! timer_channels { /// /// # Args /// * `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() }; 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);