Adding compile-time management of TIM2 channels

master
Ryan Summers 2020-11-11 18:42:34 +01:00
parent da9ca81856
commit 3b953e36aa
2 changed files with 41 additions and 23 deletions

View File

@ -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<hal::stm32::SPI2, hal::spi::Enabled, u16>,
trigger_stream: hal::dma::dma::Stream0<hal::stm32::DMA1>,
data_stream: hal::dma::dma::Stream1<hal::stm32::DMA1>,
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<hal::stm32::SPI3, hal::spi::Enabled, u16>,
trigger_stream: hal::dma::dma::Stream2<hal::stm32::DMA1>,
data_stream: hal::dma::dma::Stream3<hal::stm32::DMA1>,
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.

View File

@ -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<hal::stm32::I2C2>,
timer: hal::timer::Timer<hal::stm32::TIM2>,
// 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,