Combining ADC + DAC ISRs

This commit is contained in:
Ryan Summers 2020-11-03 16:09:00 +01:00
parent e95cad5bde
commit 5cc21cfde8
4 changed files with 180 additions and 185 deletions

View File

@ -1,8 +1,9 @@
use super::{
hal, DMAReq, DmaConfig, MemoryToPeripheral, PeripheralToMemory, TargetAddress, Transfer,
hal, DMAReq, DmaConfig, MemoryToPeripheral, PeripheralToMemory, Priority,
Stream, TargetAddress, Transfer,
};
const INPUT_BUFFER_SIZE: usize = 25;
const INPUT_BUFFER_SIZE: usize = 1;
#[link_section = ".axisram.buffers"]
static mut SPI_START: [u16; 1] = [0x00];
@ -57,6 +58,25 @@ unsafe impl TargetAddress<MemoryToPeripheral> for SPI3 {
}
}
pub struct AdcInputs {
adc0: Adc0Input,
adc1: Adc1Input,
}
impl AdcInputs {
pub fn new(adc0: Adc0Input, adc1: Adc1Input) -> Self {
Self { adc0, adc1 }
}
pub fn transfer_complete_handler(
&mut self,
) -> (&[u16; INPUT_BUFFER_SIZE], &[u16; INPUT_BUFFER_SIZE]) {
let adc0_buffer = self.adc0.transfer_complete_handler();
let adc1_buffer = self.adc1.transfer_complete_handler();
(adc0_buffer, adc1_buffer)
}
}
pub struct Adc0Input {
next_buffer: Option<&'static mut [u16; INPUT_BUFFER_SIZE]>,
transfer: Transfer<
@ -76,6 +96,7 @@ impl Adc0Input {
let trigger_config = DmaConfig::default()
.memory_increment(false)
.peripheral_increment(false)
.priority(Priority::High)
.circular_buffer(true);
let mut trigger_transfer: Transfer<_, _, MemoryToPeripheral, _> =
@ -89,7 +110,7 @@ impl Adc0Input {
let data_config = DmaConfig::default()
.memory_increment(true)
.transfer_complete_interrupt(true)
.priority(Priority::VeryHigh)
.peripheral_increment(false);
let mut spi = spi.disable();
@ -121,6 +142,8 @@ impl Adc0Input {
pub fn transfer_complete_handler(&mut self) -> &[u16; INPUT_BUFFER_SIZE] {
let next_buffer = self.next_buffer.take().unwrap();
while hal::dma::dma::Stream1::<hal::stm32::DMA1>::is_enabled() {}
self.transfer.clear_interrupts();
let (prev_buffer, _) =
self.transfer.next_transfer(next_buffer).unwrap();
self.next_buffer.replace(prev_buffer);
@ -147,6 +170,7 @@ impl Adc1Input {
let trigger_config = DmaConfig::default()
.memory_increment(false)
.peripheral_increment(false)
.priority(Priority::High)
.circular_buffer(true);
let mut trigger_transfer: Transfer<_, _, MemoryToPeripheral, _> =
@ -161,6 +185,7 @@ impl Adc1Input {
let data_config = DmaConfig::default()
.memory_increment(true)
.transfer_complete_interrupt(true)
.priority(Priority::VeryHigh)
.peripheral_increment(false);
let mut spi = spi.disable();
@ -192,6 +217,8 @@ impl Adc1Input {
pub fn transfer_complete_handler(&mut self) -> &[u16; INPUT_BUFFER_SIZE] {
let next_buffer = self.next_buffer.take().unwrap();
while hal::dma::dma::Stream3::<hal::stm32::DMA1>::is_enabled() {}
self.transfer.clear_interrupts();
let (prev_buffer, _) =
self.transfer.next_transfer(next_buffer).unwrap();
self.next_buffer.replace(prev_buffer);

View File

@ -1,95 +1,61 @@
use super::hal;
use heapless::consts;
pub struct Dac0Output {
outputs: heapless::spsc::Queue<u16, consts::U32>,
spi: hal::spi::Spi<hal::stm32::SPI4, hal::spi::Enabled, u16>,
pub struct DacOutputs {
dac0_spi: hal::spi::Spi<hal::stm32::SPI4, hal::spi::Enabled, u16>,
dac1_spi: hal::spi::Spi<hal::stm32::SPI5, hal::spi::Enabled, u16>,
outputs: heapless::spsc::Queue<(u16, u16), consts::U32>,
timer: hal::timer::Timer<hal::stm32::TIM3>,
}
impl Dac0Output {
impl DacOutputs {
pub fn new(
spi: hal::spi::Spi<hal::stm32::SPI4, hal::spi::Enabled, u16>,
dac0_spi: hal::spi::Spi<hal::stm32::SPI4, hal::spi::Enabled, u16>,
dac1_spi: hal::spi::Spi<hal::stm32::SPI5, hal::spi::Enabled, u16>,
mut timer: hal::timer::Timer<hal::stm32::TIM3>,
) -> Self {
spi.inner().cr1.modify(|_, w| w.cstart().started());
dac0_spi.inner().cr1.modify(|_, w| w.cstart().started());
dac1_spi.inner().cr1.modify(|_, w| w.cstart().started());
timer.pause();
timer.reset_counter();
timer.clear_irq();
timer.listen(hal::timer::Event::TimeOut);
Self {
spi,
dac0_spi,
dac1_spi,
outputs: heapless::spsc::Queue::new(),
timer,
}
}
pub fn push(&mut self, value: u16) {
self.outputs.enqueue(value).unwrap();
pub fn push(&mut self, dac0_value: u16, dac1_value: u16) {
self.outputs.enqueue((dac0_value, dac1_value)).unwrap();
self.timer.resume();
}
pub fn update(&mut self) {
self.timer.clear_irq();
match self.outputs.dequeue() {
Some(value) => self.write(value),
None => self.timer.pause(),
}
}
pub fn write(&mut self, value: u16) {
unsafe {
core::ptr::write_volatile(
&self.spi.inner().txdr as *const _ as *mut u16,
value,
);
}
}
}
pub struct Dac1Output {
outputs: heapless::spsc::Queue<u16, consts::U32>,
spi: hal::spi::Spi<hal::stm32::SPI5, hal::spi::Enabled, u16>,
timer: hal::timer::Timer<hal::stm32::TIM4>,
}
impl Dac1Output {
pub fn new(
spi: hal::spi::Spi<hal::stm32::SPI5, hal::spi::Enabled, u16>,
mut timer: hal::timer::Timer<hal::stm32::TIM4>,
) -> Self {
spi.inner().cr1.modify(|_, w| w.cstart().started());
timer.pause();
timer.reset_counter();
timer.clear_irq();
timer.listen(hal::timer::Event::TimeOut);
Self {
spi,
outputs: heapless::spsc::Queue::new(),
timer,
}
}
pub fn push(&mut self, value: u16) {
self.outputs.enqueue(value).unwrap();
self.timer.resume();
}
pub fn update(&mut self) {
Some((dac0, dac1)) => self.write(dac0, dac1),
None => {
self.timer.pause();
self.timer.reset_counter();
self.timer.clear_irq();
match self.outputs.dequeue() {
Some(value) => self.write(value),
None => self.timer.pause(),
}
};
}
pub fn write(&mut self, value: u16) {
pub fn write(&mut self, dac0_value: u16, dac1_value: u16) {
unsafe {
core::ptr::write_volatile(
&self.spi.inner().txdr as *const _ as *mut u16,
value,
&self.dac0_spi.inner().txdr as *const _ as *mut u16,
dac0_value,
);
core::ptr::write_volatile(
&self.dac1_spi.inner().txdr as *const _ as *mut u16,
dac1_value,
);
}
}

View File

@ -105,4 +105,14 @@ impl IIR {
xy[xy.len() / 2] = y0;
y0
}
pub fn update_from_adc_sample(
&mut self,
sample: u16,
state: &mut IIRState,
) -> u16 {
let x0 = f32::from(sample as i16);
let y0 = self.update(state, x0);
y0 as i16 as u16 ^ 0x8000
}
}

View File

@ -36,8 +36,9 @@ use embedded_hal::digital::v2::{InputPin, OutputPin};
use hal::{
dma::{
config::Priority,
dma::{DMAReq, DmaConfig},
traits::TargetAddress,
traits::{Stream, TargetAddress},
MemoryToPeripheral, PeripheralToMemory, Transfer,
},
ethernet::{self, PHY},
@ -46,7 +47,7 @@ use smoltcp as net;
use heapless::{consts::*, String};
const SAMPLE_FREQUENCY_KHZ: u32 = 800;
const SAMPLE_FREQUENCY_KHZ: u32 = 500;
#[link_section = ".sram3.eth"]
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
@ -59,8 +60,8 @@ mod iir;
mod pounder;
mod server;
use adc::{Adc0Input, Adc1Input};
use dac::{Dac0Output, Dac1Output};
use adc::{Adc0Input, Adc1Input, AdcInputs};
use dac::DacOutputs;
#[cfg(not(feature = "semihosting"))]
fn init_log() {}
@ -171,14 +172,12 @@ macro_rules! route_request {
#[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
const APP: () = {
struct Resources {
adc0: Adc0Input,
dac0: Dac0Output,
afe0: AFE0,
adc1: Adc1Input,
dac1: Dac1Output,
afe1: AFE1,
adcs: AdcInputs,
dacs: DacOutputs,
eeprom_i2c: hal::i2c::I2c<hal::stm32::I2C2>,
timer: hal::timer::Timer<hal::stm32::TIM2>,
@ -259,6 +258,7 @@ const APP: () = {
hal::dma::dma::StreamsTuple::new(dp.DMA1, ccdr.peripheral.DMA1);
// Configure the SPI interfaces to the ADCs and DACs.
let adcs = {
let adc0 = {
let spi_miso = gpiob
.pb14
@ -325,13 +325,17 @@ const APP: () = {
Adc1Input::new(spi, dma_streams.2, dma_streams.3)
};
let _dac_clr_n = gpioe.pe12.into_push_pull_output().set_high().unwrap();
AdcInputs::new(adc0, adc1)
};
let dacs = {
let _dac_clr_n =
gpioe.pe12.into_push_pull_output().set_high().unwrap();
let _dac0_ldac_n =
gpioe.pe11.into_push_pull_output().set_low().unwrap();
let _dac1_ldac_n =
gpioe.pe15.into_push_pull_output().set_low().unwrap();
let dac0 = {
let dac0_spi = {
let spi_miso = gpioe
.pe5
@ -364,11 +368,6 @@ const APP: () = {
)
};
let timer = dp.TIM3.timer(SAMPLE_FREQUENCY_KHZ.khz(), ccdr.peripheral.TIM3, &ccdr.clocks);
Dac0Output::new(dac0_spi, timer)
};
let dac1 = {
let dac1_spi = {
let spi_miso = gpiof
.pf8
@ -401,8 +400,13 @@ const APP: () = {
)
};
let timer = dp.TIM4.timer(SAMPLE_FREQUENCY_KHZ.khz(), ccdr.peripheral.TIM4, &ccdr.clocks);
Dac1Output::new(dac1_spi, timer)
let timer = dp.TIM3.timer(
SAMPLE_FREQUENCY_KHZ.khz(),
ccdr.peripheral.TIM3,
&ccdr.clocks,
);
DacOutputs::new(dac0_spi, dac1_spi, timer)
};
let mut fp_led_0 = gpiod.pd5.into_push_pull_output();
@ -682,8 +686,11 @@ const APP: () = {
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);
let timer2 = dp.TIM2.timer(
SAMPLE_FREQUENCY_KHZ.khz(),
ccdr.peripheral.TIM2,
&ccdr.clocks,
);
{
let t2_regs = unsafe { &*hal::stm32::TIM2::ptr() };
t2_regs.dier.modify(|_, w| w.ude().set_bit());
@ -691,12 +698,10 @@ const APP: () = {
init::LateResources {
afe0: afe0,
adc0: adc0,
dac0: dac0,
afe1: afe1,
adc1: adc1,
dac1: dac1,
adcs,
dacs,
timer: timer2,
pounder: pounder_devices,
@ -708,29 +713,26 @@ const APP: () = {
}
}
#[task(binds=DMA1_STR1, resources=[adc0, dac0, iir_state, iir_ch], priority=2)]
fn adc0(mut c: adc0::Context) {
let samples = c.resources.adc0.transfer_complete_handler();
for sample in samples {
let x0 = f32::from(*sample as i16);
let y0 =
c.resources.iir_ch[0].update(&mut c.resources.iir_state[0], x0);
let result = y0 as i16 as u16 ^ 0x8000;
c.resources.dac0.lock(|dac| dac.push(result));
}
#[task(binds = TIM3, resources=[dacs], priority = 3)]
fn dac_update(c: dac_update::Context) {
c.resources.dacs.update();
}
#[task(binds=DMA1_STR3, resources=[adc1, dac1, iir_state, iir_ch], priority=2)]
fn adc1(mut c: adc1::Context) {
let samples = c.resources.adc1.transfer_complete_handler();
#[task(binds=DMA1_STR3, resources=[adcs, dacs, iir_state, iir_ch], priority=2)]
fn adc_update(mut c: adc_update::Context) {
let (adc0_samples, adc1_samples) =
c.resources.adcs.transfer_complete_handler();
for sample in samples {
let x0 = f32::from(*sample as i16);
let y0 =
c.resources.iir_ch[1].update(&mut c.resources.iir_state[1], x0);
let result = y0 as i16 as u16 ^ 0x8000;
c.resources.dac1.lock(|dac| dac.push(result));
for (adc0, adc1) in adc0_samples.iter().zip(adc1_samples.iter()) {
let result_adc0 = c.resources.iir_ch[0]
.update_from_adc_sample(*adc0, &mut c.resources.iir_state[0]);
let result_adc1 = c.resources.iir_ch[1]
.update_from_adc_sample(*adc1, &mut c.resources.iir_state[1]);
c.resources
.dacs
.lock(|dacs| dacs.push(result_adc0, result_adc1));
}
}
@ -934,16 +936,6 @@ const APP: () = {
panic!("ADC0 input overrun");
}
#[task(binds = TIM3, resources=[dac0], priority = 3)]
fn dac0(c: dac0::Context) {
c.resources.dac0.update();
}
#[task(binds = TIM4, resources=[dac1], priority = 3)]
fn dac1(c: dac1::Context) {
c.resources.dac1.update();
}
extern "C" {
// hw interrupt handlers for RTIC to use for scheduling tasks
// one per priority