From 3b953e36aa3ec77ee00de4c70830f196301971b5 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Wed, 11 Nov 2020 18:42:34 +0100 Subject: [PATCH] Adding compile-time management of TIM2 channels --- src/adc.rs | 18 ++++++++++++++++-- src/main.rs | 46 +++++++++++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index e3310f4..d63ebe9 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, DMAReq, DmaConfig, MemoryToPeripheral, PeripheralToMemory, Priority, - TargetAddress, Transfer, + hal, sampling_timer, DMAReq, DmaConfig, MemoryToPeripheral, + PeripheralToMemory, Priority, TargetAddress, Transfer, }; // The desired ADC input buffer size. This is use configurable. @@ -142,11 +142,18 @@ impl Adc0Input { /// * `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. + /// * `_trigger_channel` - The ADC sampling timer output compare channel for read triggers. pub fn new( spi: hal::spi::Spi, trigger_stream: hal::dma::dma::Stream0, data_stream: hal::dma::dma::Stream1, + trigger_channel: sampling_timer::Timer2Channel1, ) -> Self { + // Generate DMA events when an output compare of the timer hitting zero (timer roll over) + // occurs. + trigger_channel.listen_dma(); + trigger_channel.to_output_compare(0); + // The trigger stream constantly writes to the TX FIFO using a static word (dont-care // contents). Thus, neither the memory or peripheral address ever change. This is run in // circular mode to be completed at every DMA request. @@ -256,11 +263,18 @@ impl Adc1Input { /// * `spi` - The SPI interface connected to ADC1. /// * `trigger_stream` - The DMA stream used to trigger ADC conversions on the SPI interface. /// * `data_stream` - The DMA stream used to read ADC samples from the SPI RX FIFO. + /// * `trigger_channel` - The ADC sampling timer output compare channel for read triggers. pub fn new( spi: hal::spi::Spi, trigger_stream: hal::dma::dma::Stream2, data_stream: hal::dma::dma::Stream3, + trigger_channel: sampling_timer::Timer2Channel2, ) -> Self { + // Generate DMA events when an output compare of the timer hitting zero (timer roll over) + // occurs. + trigger_channel.listen_dma(); + trigger_channel.to_output_compare(0); + // The trigger stream constantly writes to the TX FIFO using a static word (dont-care // contents). Thus, neither the memory or peripheral address ever change. This is run in // circular mode to be completed at every DMA request. diff --git a/src/main.rs b/src/main.rs index 1805370..59b19fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,6 +62,7 @@ mod dac; mod eeprom; mod iir; mod pounder; +mod sampling_timer; mod server; use adc::{Adc0Input, Adc1Input, AdcInputs}; @@ -187,8 +188,6 @@ const APP: () = { eeprom_i2c: hal::i2c::I2c, - timer: hal::timer::Timer, - // Note: It appears that rustfmt generates a format that GDB cannot recognize, which // results in GDB breakpoints being set improperly. #[rustfmt::skip] @@ -264,6 +263,16 @@ const APP: () = { let dma_streams = hal::dma::dma::StreamsTuple::new(dp.DMA1, ccdr.peripheral.DMA1); + // Configure timer 2 to trigger conversions for the ADC + let timer2 = dp.TIM2.timer( + SAMPLE_FREQUENCY_KHZ.khz(), + ccdr.peripheral.TIM2, + &ccdr.clocks, + ); + + let mut sampling_timer = sampling_timer::SamplingTimer::new(timer2); + let sampling_timer_channels = sampling_timer.channels(); + // Configure the SPI interfaces to the ADCs and DACs. let adcs = { let adc0 = { @@ -296,7 +305,12 @@ const APP: () = { &ccdr.clocks, ); - Adc0Input::new(spi, dma_streams.0, dma_streams.1) + Adc0Input::new( + spi, + dma_streams.0, + dma_streams.1, + sampling_timer_channels.ch1, + ) }; let adc1 = { @@ -329,7 +343,12 @@ const APP: () = { &ccdr.clocks, ); - Adc1Input::new(spi, dma_streams.2, dma_streams.3) + Adc1Input::new( + spi, + dma_streams.2, + dma_streams.3, + sampling_timer_channels.ch2, + ) }; AdcInputs::new(adc0, adc1) @@ -697,22 +716,8 @@ const APP: () = { // Utilize the cycle counter for RTIC scheduling. cp.DWT.enable_cycle_counter(); - // Configure timer 2 to trigger conversions for the ADC - let timer2 = dp.TIM2.timer( - SAMPLE_FREQUENCY_KHZ.khz(), - ccdr.peripheral.TIM2, - &ccdr.clocks, - ); - { - // Listen to the CH1 and CH2 comparison events. These channels should have a value of - // zero loaded into them, so the event should occur whenever the timer overflows. Note - // that we use channels instead of timer updates because each SPI DMA transfer needs a - // unique request line. - let t2_regs = unsafe { &*hal::stm32::TIM2::ptr() }; - t2_regs - .dier - .modify(|_, w| w.cc1de().set_bit().cc2de().set_bit()); - } + // Start sampling ADCs. + sampling_timer.start(); init::LateResources { afe0: afe0, @@ -721,7 +726,6 @@ const APP: () = { adcs, dacs, - timer: timer2, pounder: pounder_devices, eeprom_i2c,