From f64dd8228b7b8a570546ffa9b522ae85145cfdef Mon Sep 17 00:00:00 2001 From: seth Date: Mon, 24 Jun 2024 17:09:43 -0700 Subject: new PR, taking Dirbao's advice to make the DMA impl in a separate struct that consumes Adc to make RingBufferedAdc. Handling overrun similar to RingBufferedUart --- examples/stm32f4/src/bin/adc_dma.rs | 59 +++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 examples/stm32f4/src/bin/adc_dma.rs (limited to 'examples') diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs new file mode 100644 index 000000000..a2611bb6f --- /dev/null +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] +use cortex_m::singleton; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::RingBufferedAdc; +use embassy_stm32::adc::{Adc, SampleTime, Sequence}; +use embassy_time::{Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + const ADC_BUF_SIZE: usize = 1024; + let mut p = embassy_stm32::init(Default::default()); + + let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); + + let adc = Adc::new(p.ADC1); + + let mut adc: RingBufferedAdc = adc.into_ring_buffered(p.DMA2_CH0, adc_data); + + adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); + adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112); + adc.set_sample_sequence(Sequence::Three, &mut p.PA1, SampleTime::CYCLES112); + adc.set_sample_sequence(Sequence::Four, &mut p.PA3, SampleTime::CYCLES112); + + // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around + // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of + // what channel is at what index is lost. The buffer must be cleared and reset. This *is* handled here, but allowing this to happen will cause + // a reduction of performance as each time the buffer is reset, the adc & dma buffer must be restarted. + + // An interrupt executor with a higher priority than other tasks may be a good approach here, allowing this task to wake and read the buffer most + // frequently. + let mut tic = Instant::now(); + let mut buffer1: [u16; 256] = [0u16; 256]; + let _ = adc.start(); + loop { + match adc.read(&mut buffer1).await { + Ok(_data) => { + let toc = Instant::now(); + info!( + "\n adc1: {} dt = {}, n = {}", + buffer1[0..16], + (toc - tic).as_micros(), + _data + ); + tic = toc; + } + Err(e) => { + warn!("Error: {:?}", e); + buffer1 = [0u16; 256]; + let _ = adc.start(); + continue; + } + } + + Timer::after_micros(300).await; + } +} -- cgit From 27b83fdbcfe7e9e64a8b65fdcb8dc82d6dc3e58c Mon Sep 17 00:00:00 2001 From: seth Date: Mon, 24 Jun 2024 17:15:16 -0700 Subject: fmt --- examples/stm32f4/src/bin/adc_dma.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index a2611bb6f..88822a507 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -3,8 +3,7 @@ use cortex_m::singleton; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::RingBufferedAdc; -use embassy_stm32::adc::{Adc, SampleTime, Sequence}; +use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,7 +13,7 @@ async fn main(_spawner: Spawner) { let mut p = embassy_stm32::init(Default::default()); let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); - + let adc = Adc::new(p.ADC1); let mut adc: RingBufferedAdc = adc.into_ring_buffered(p.DMA2_CH0, adc_data); -- cgit From 7056783fa23eb25629e1e57da0021916a073a432 Mon Sep 17 00:00:00 2001 From: seth Date: Mon, 24 Jun 2024 17:53:59 -0700 Subject: second adc added to example + API todos completed --- examples/stm32f4/src/bin/adc_dma.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index 88822a507..dd19caf1d 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -13,15 +13,18 @@ async fn main(_spawner: Spawner) { let mut p = embassy_stm32::init(Default::default()); let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); + let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); let adc = Adc::new(p.ADC1); + let adc2 = Adc::new(p.ADC2); let mut adc: RingBufferedAdc = adc.into_ring_buffered(p.DMA2_CH0, adc_data); + let mut adc2: RingBufferedAdc = adc2.into_ring_buffered(p.DMA2_CH2, adc_data2); adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112); - adc.set_sample_sequence(Sequence::Three, &mut p.PA1, SampleTime::CYCLES112); - adc.set_sample_sequence(Sequence::Four, &mut p.PA3, SampleTime::CYCLES112); + adc2.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112); + adc2.set_sample_sequence(Sequence::Two, &mut p.PA3, SampleTime::CYCLES112); // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of @@ -31,10 +34,12 @@ async fn main(_spawner: Spawner) { // An interrupt executor with a higher priority than other tasks may be a good approach here, allowing this task to wake and read the buffer most // frequently. let mut tic = Instant::now(); - let mut buffer1: [u16; 256] = [0u16; 256]; + let mut buffer1 = [0u16; 256]; + let mut buffer2 = [0u16; 256]; let _ = adc.start(); + let _ = adc2.start(); loop { - match adc.read(&mut buffer1).await { + match adc.read_exact(&mut buffer1).await { Ok(_data) => { let toc = Instant::now(); info!( @@ -49,10 +54,25 @@ async fn main(_spawner: Spawner) { warn!("Error: {:?}", e); buffer1 = [0u16; 256]; let _ = adc.start(); - continue; } } - Timer::after_micros(300).await; + match adc2.read_exact(&mut buffer2).await { + Ok(_data) => { + let toc = Instant::now(); + info!( + "\n adc2: {} dt = {}, n = {}", + buffer2[0..16], + (toc - tic).as_micros(), + _data + ); + tic = toc; + } + Err(e) => { + warn!("Error: {:?}", e); + buffer2 = [0u16; 256]; + let _ = adc2.start(); + } + } } } -- cgit From 6926e9e07154c72d68ef099d5f28178274f86032 Mon Sep 17 00:00:00 2001 From: seth Date: Mon, 24 Jun 2024 23:15:00 -0700 Subject: CI --- examples/stm32f4/src/bin/adc_dma.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index dd19caf1d..992bed573 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -4,14 +4,19 @@ use cortex_m::singleton; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; -use embassy_time::{Instant, Timer}; +use embassy_stm32::Peripherals; +use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] -async fn main(_spawner: Spawner) { - const ADC_BUF_SIZE: usize = 1024; - let mut p = embassy_stm32::init(Default::default()); +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + spawner.must_spawn(adc_task(p)); +} +#[embassy_executor::task] +async fn adc_task(mut p: Peripherals) { + const ADC_BUF_SIZE: usize = 1024; let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); @@ -34,8 +39,8 @@ async fn main(_spawner: Spawner) { // An interrupt executor with a higher priority than other tasks may be a good approach here, allowing this task to wake and read the buffer most // frequently. let mut tic = Instant::now(); - let mut buffer1 = [0u16; 256]; - let mut buffer2 = [0u16; 256]; + let mut buffer1 = [0u16; 512]; + let mut buffer2 = [0u16; 512]; let _ = adc.start(); let _ = adc2.start(); loop { @@ -52,7 +57,7 @@ async fn main(_spawner: Spawner) { } Err(e) => { warn!("Error: {:?}", e); - buffer1 = [0u16; 256]; + buffer1 = [0u16; 512]; let _ = adc.start(); } } @@ -70,7 +75,7 @@ async fn main(_spawner: Spawner) { } Err(e) => { warn!("Error: {:?}", e); - buffer2 = [0u16; 256]; + buffer2 = [0u16; 512]; let _ = adc2.start(); } } -- cgit