From 6b170c25edc27da458c7f4639e8f69d28edd4792 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 12 Jan 2021 13:29:15 +0100 Subject: [PATCH] Fixing timing synchronization --- src/adc.rs | 27 ++++++++++++--------------- src/main.rs | 8 +++----- src/timers.rs | 3 +++ 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index 3e60a0d..b4d4359 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -1,12 +1,12 @@ ///! Stabilizer ADC management interface ///! ///! The Stabilizer ADCs utilize three DMA channels: one to trigger sampling, one to collect -///! samples, and one to clear the TXTF flag betwen samples. The SPI interfaces are configured +///! samples, and one to clear the EOT flag betwen samples. The SPI interfaces are configured ///! for receiver-only operation. A timer channel is ///! configured to generate a DMA write into the SPI CR1 register, which initiates a SPI transfer and ///! results in a single ADC sample read for both channels. A separate timer channel is configured to ///! occur immediately before the trigger channel, which initiates a write to the IFCR (flag-clear) -///! register to clear the TXTF flag, which allows for a new transmission to be generated by the +///! register to clear the EOT flag, which allows for a new transmission to be generated by the ///! trigger channel. ///! ///! In order to read multiple samples without interrupting the CPU, a separate DMA transfer is @@ -26,13 +26,13 @@ use super::{ // transfer. Data in AXI SRAM is not initialized on boot, so the contents are random. This value is // initialized during setup. #[link_section = ".axisram.buffers"] -static mut SPI_START: [u32; 1] = [0x00]; +static mut SPI_START: [u32; 1] = [0x00; 1]; // The following data is written by the timer flag clear trigger into the SPI IFCR register to clear -// the TXTF flag. Data in AXI SRAM is not initialized on boot, so the contents are random. This +// the EOT flag. Data in AXI SRAM is not initialized on boot, so the contents are random. This // value is initialized during setup. #[link_section = ".axisram.buffers"] -static mut SPI_TXTF_CLEAR: [u32; 1] = [0x00]; +static mut SPI_EOT_CLEAR: [u32; 1] = [0x00]; // The following global buffers are used for the ADC sample DMA transfers. Two buffers are used for // each transfer in a ping-pong buffer configuration (one is being acquired while the other is being @@ -101,7 +101,7 @@ macro_rules! adc_input { const REQUEST_LINE: Option = Some(DMAReq::$dma_clear_req as u8); /// Whenever the DMA request occurs, it should write into SPI's IFCR to clear the - /// TXTF flag to allow the next transmission. + /// EOT flag to allow the next transmission. fn address(&self) -> usize { // Note(unsafe): It is assumed that SPI is owned by another DMA transfer and // this DMA is only used for writing to the configuration registers. @@ -141,10 +141,10 @@ macro_rules! adc_input { /// * `trigger_stream` - The DMA stream used to trigger each ADC transfer by /// writing a word into the SPI TX FIFO. /// * `data_stream` - The DMA stream used to read samples received over SPI into a data buffer. - /// * `clear_stream` - The DMA stream used to clear the TXTF flag in the SPI peripheral. + /// * `clear_stream` - The DMA stream used to clear the EOT flag in the SPI peripheral. /// * `trigger_channel` - The ADC sampling timer output compare channel for read triggers. /// * `clear_channel` - The shadow sampling timer output compare channel used for - /// clearing the SPI TXTF flag. + /// clearing the SPI EOT flag. pub fn new( spi: hal::spi::Spi, trigger_stream: hal::dma::dma::$trigger_stream< @@ -155,7 +155,7 @@ macro_rules! adc_input { trigger_channel: timers::tim2::$trigger_channel, clear_channel: timers::tim3::$clear_channel, ) -> Self { - // The flag clear DMA transfer always clears the TXTF flag in the SPI + // The flag clear DMA transfer always clears the EOT flag in the SPI // peripheral. It has the highest priority to ensure it is completed before the // transfer trigger. let clear_config = DmaConfig::default() @@ -163,7 +163,7 @@ macro_rules! adc_input { .circular_buffer(true); unsafe { - SPI_TXTF_CLEAR[0] = 1 << 4; + SPI_EOT_CLEAR[0] = 1 << 3; } // Generate DMA events when the timer hits zero (roll-over). This must be before @@ -183,7 +183,7 @@ macro_rules! adc_input { // Note(unsafe): Because this is a Memory->Peripheral transfer, this data is // never actually modified. It technically only needs to be immutably // borrowed, but the current HAL API only supports mutable borrows. - unsafe { &mut SPI_TXTF_CLEAR }, + unsafe { &mut SPI_EOT_CLEAR }, None, clear_config, ); @@ -191,7 +191,7 @@ macro_rules! adc_input { // Generate DMA events when an output compare of the timer hits the specified // value. trigger_channel.listen_dma(); - trigger_channel.to_output_compare(1); + trigger_channel.to_output_compare(2); // The trigger stream constantly writes to the SPI CR1 using a static word // (which is a static value to enable the SPI transfer). Thus, neither the @@ -262,10 +262,7 @@ macro_rules! adc_input { // Each transaction is 1 word (16 bytes). spi.inner().cr2.modify(|_, w| w.tsize().bits(1)); - - // Enable SPI and start it in infinite transaction mode. spi.inner().cr1.modify(|_, w| w.spe().set_bit()); - spi.inner().cr1.modify(|_, w| w.cstart().started()); }); clear_transfer.start(|_| {}); diff --git a/src/main.rs b/src/main.rs index f2b7c7a..e2de7d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -298,6 +298,7 @@ const APP: () = { // Configure the timer to count at the designed tick rate. We will manually set the // period below. timer2.pause(); + timer2.reset_counter(); timer2.set_tick_freq(design_parameters::TIMER_FREQUENCY); let mut sampling_timer = timers::SamplingTimer::new(timer2); @@ -318,6 +319,7 @@ const APP: () = { // Configure the timer to count at the designed tick rate. We will manually set the // period below. timer3.pause(); + timer3.reset_counter(); timer3.set_tick_freq(design_parameters::TIMER_FREQUENCY); let mut shadow_sampling_timer = @@ -925,10 +927,6 @@ const APP: () = { #[cfg(not(feature = "pounder_v1_1"))] let pounder_stamper = None; - // Force an update of the shadow sampling timer configuration and enable it. It will not - // start counting until the sampling timer starts due to the slave mode configuration. - shadow_sampling_timer.start(); - // Start sampling ADCs. sampling_timer.start(); timestamp_timer.start(); @@ -951,7 +949,7 @@ const APP: () = { } } - #[task(binds=DMA1_STR3, resources=[pounder_stamper, adcs, dacs, iir_state, iir_ch, dds_output, input_stamper], priority=2)] + #[task(binds=DMA1_STR4, resources=[pounder_stamper, adcs, dacs, iir_state, iir_ch, dds_output, input_stamper], priority=2)] fn process(c: process::Context) { if let Some(stamper) = c.resources.pounder_stamper { let pounder_timestamps = stamper.acquire_buffer(); diff --git a/src/timers.rs b/src/timers.rs index fa6ae15..062eb4b 100644 --- a/src/timers.rs +++ b/src/timers.rs @@ -98,6 +98,9 @@ macro_rules! timer_channels { pub fn set_period_ticks(&mut self, period: $size) { let regs = unsafe { &*hal::stm32::$TY::ptr() }; regs.arr.write(|w| w.arr().bits(period)); + + // Force the new period to take effect immediately. + self.timer.apply_freq(); } /// Clock the timer from an external source.