Fixing timing synchronization
This commit is contained in:
parent
91975993cf
commit
6b170c25ed
27
src/adc.rs
27
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<u8> = 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<hal::stm32::$spi, hal::spi::Enabled, u16>,
|
||||
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(|_| {});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue