Combining ADC + DAC ISRs
This commit is contained in:
parent
e95cad5bde
commit
5cc21cfde8
33
src/adc.rs
33
src/adc.rs
|
@ -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);
|
||||
|
|
86
src/dac.rs
86
src/dac.rs
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
10
src/iir.rs
10
src/iir.rs
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
102
src/main.rs
102
src/main.rs
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue