diff options
| -rw-r--r-- | embassy-stm32/build.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/ringbuffered_v2.rs | 368 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 3 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/adc_dma.rs | 83 |
5 files changed, 461 insertions, 1 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 6aedcc228..24e2226a2 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -764,7 +764,7 @@ fn main() { | |||
| 764 | 764 | ||
| 765 | #[rustfmt::skip] | 765 | #[rustfmt::skip] |
| 766 | let signals: HashMap<_, _> = [ | 766 | let signals: HashMap<_, _> = [ |
| 767 | // (kind, signal) => trait | 767 | // (kind, signal) => trait |
| 768 | (("ucpd", "CC1"), quote!(crate::ucpd::Cc1Pin)), | 768 | (("ucpd", "CC1"), quote!(crate::ucpd::Cc1Pin)), |
| 769 | (("ucpd", "CC2"), quote!(crate::ucpd::Cc2Pin)), | 769 | (("ucpd", "CC2"), quote!(crate::ucpd::Cc2Pin)), |
| 770 | (("usart", "TX"), quote!(crate::usart::TxPin)), | 770 | (("usart", "TX"), quote!(crate::usart::TxPin)), |
| @@ -1178,6 +1178,10 @@ fn main() { | |||
| 1178 | 1178 | ||
| 1179 | let signals: HashMap<_, _> = [ | 1179 | let signals: HashMap<_, _> = [ |
| 1180 | // (kind, signal) => trait | 1180 | // (kind, signal) => trait |
| 1181 | (("adc", "ADC"), quote!(crate::adc::RxDma)), | ||
| 1182 | (("adc", "ADC1"), quote!(crate::adc::RxDma)), | ||
| 1183 | (("adc", "ADC2"), quote!(crate::adc::RxDma)), | ||
| 1184 | (("adc", "ADC3"), quote!(crate::adc::RxDma)), | ||
| 1181 | (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), | 1185 | (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), |
| 1182 | (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), | 1186 | (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), |
| 1183 | (("usart", "RX"), quote!(crate::usart::RxDma)), | 1187 | (("usart", "RX"), quote!(crate::usart::RxDma)), |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 0c22a7dae..7a7d7cd8e 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -28,6 +28,8 @@ pub use crate::pac::adc::vals::Res as Resolution; | |||
| 28 | pub use crate::pac::adc::vals::SampleTime; | 28 | pub use crate::pac::adc::vals::SampleTime; |
| 29 | use crate::peripherals; | 29 | use crate::peripherals; |
| 30 | 30 | ||
| 31 | dma_trait!(RxDma, Instance); | ||
| 32 | |||
| 31 | /// Analog to Digital driver. | 33 | /// Analog to Digital driver. |
| 32 | pub struct Adc<'d, T: Instance> { | 34 | pub struct Adc<'d, T: Instance> { |
| 33 | #[allow(unused)] | 35 | #[allow(unused)] |
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs new file mode 100644 index 000000000..fb29d9a8c --- /dev/null +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | use core::mem; | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 4 | |||
| 5 | use embassy_hal_internal::{into_ref, Peripheral}; | ||
| 6 | use stm32_metapac::adc::vals::SampleTime; | ||
| 7 | |||
| 8 | use crate::adc::{Adc, AdcChannel, Instance, RxDma}; | ||
| 9 | use crate::dma::ringbuffer::OverrunError; | ||
| 10 | use crate::dma::{Priority, ReadableRingBuffer, TransferOptions}; | ||
| 11 | use crate::pac::adc::vals; | ||
| 12 | use crate::rcc; | ||
| 13 | |||
| 14 | fn clear_interrupt_flags(r: crate::pac::adc::Adc) { | ||
| 15 | r.sr().modify(|regs| { | ||
| 16 | regs.set_eoc(false); | ||
| 17 | regs.set_ovr(false); | ||
| 18 | }); | ||
| 19 | } | ||
| 20 | |||
| 21 | #[derive(PartialOrd, PartialEq, Debug, Clone, Copy)] | ||
| 22 | pub enum Sequence { | ||
| 23 | One, | ||
| 24 | Two, | ||
| 25 | Three, | ||
| 26 | Four, | ||
| 27 | Five, | ||
| 28 | Six, | ||
| 29 | Seven, | ||
| 30 | Eight, | ||
| 31 | Nine, | ||
| 32 | Ten, | ||
| 33 | Eleven, | ||
| 34 | Twelve, | ||
| 35 | Thirteen, | ||
| 36 | Fourteen, | ||
| 37 | Fifteen, | ||
| 38 | Sixteen, | ||
| 39 | } | ||
| 40 | |||
| 41 | impl From<Sequence> for u8 { | ||
| 42 | fn from(s: Sequence) -> u8 { | ||
| 43 | match s { | ||
| 44 | Sequence::One => 0, | ||
| 45 | Sequence::Two => 1, | ||
| 46 | Sequence::Three => 2, | ||
| 47 | Sequence::Four => 3, | ||
| 48 | Sequence::Five => 4, | ||
| 49 | Sequence::Six => 5, | ||
| 50 | Sequence::Seven => 6, | ||
| 51 | Sequence::Eight => 7, | ||
| 52 | Sequence::Nine => 8, | ||
| 53 | Sequence::Ten => 9, | ||
| 54 | Sequence::Eleven => 10, | ||
| 55 | Sequence::Twelve => 11, | ||
| 56 | Sequence::Thirteen => 12, | ||
| 57 | Sequence::Fourteen => 13, | ||
| 58 | Sequence::Fifteen => 14, | ||
| 59 | Sequence::Sixteen => 15, | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | impl From<u8> for Sequence { | ||
| 65 | fn from(val: u8) -> Self { | ||
| 66 | match val { | ||
| 67 | 0 => Sequence::One, | ||
| 68 | 1 => Sequence::Two, | ||
| 69 | 2 => Sequence::Three, | ||
| 70 | 3 => Sequence::Four, | ||
| 71 | 4 => Sequence::Five, | ||
| 72 | 5 => Sequence::Six, | ||
| 73 | 6 => Sequence::Seven, | ||
| 74 | 7 => Sequence::Eight, | ||
| 75 | 8 => Sequence::Nine, | ||
| 76 | 9 => Sequence::Ten, | ||
| 77 | 10 => Sequence::Eleven, | ||
| 78 | 11 => Sequence::Twelve, | ||
| 79 | 12 => Sequence::Thirteen, | ||
| 80 | 13 => Sequence::Fourteen, | ||
| 81 | 14 => Sequence::Fifteen, | ||
| 82 | 15 => Sequence::Sixteen, | ||
| 83 | _ => panic!("Invalid sequence number"), | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | pub struct RingBufferedAdc<'d, T: Instance> { | ||
| 89 | _phantom: PhantomData<T>, | ||
| 90 | ring_buf: ReadableRingBuffer<'d, u16>, | ||
| 91 | } | ||
| 92 | |||
| 93 | impl<'d, T: Instance> Adc<'d, T> { | ||
| 94 | pub fn into_ring_buffered( | ||
| 95 | self, | ||
| 96 | dma: impl Peripheral<P = impl RxDma<T>> + 'd, | ||
| 97 | dma_buf: &'d mut [u16], | ||
| 98 | ) -> RingBufferedAdc<'d, T> { | ||
| 99 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | ||
| 100 | into_ref!(dma); | ||
| 101 | |||
| 102 | let opts: crate::dma::TransferOptions = TransferOptions { | ||
| 103 | half_transfer_ir: true, | ||
| 104 | priority: Priority::VeryHigh, | ||
| 105 | ..Default::default() | ||
| 106 | }; | ||
| 107 | |||
| 108 | // Safety: we forget the struct before this function returns. | ||
| 109 | let rx_src = T::regs().dr().as_ptr() as *mut u16; | ||
| 110 | let request = dma.request(); | ||
| 111 | |||
| 112 | let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) }; | ||
| 113 | |||
| 114 | // Don't disable the clock | ||
| 115 | mem::forget(self); | ||
| 116 | |||
| 117 | RingBufferedAdc { | ||
| 118 | _phantom: PhantomData, | ||
| 119 | ring_buf, | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | impl<'d, T: Instance> RingBufferedAdc<'d, T> { | ||
| 125 | fn is_on() -> bool { | ||
| 126 | T::regs().cr2().read().adon() | ||
| 127 | } | ||
| 128 | |||
| 129 | fn stop_adc() { | ||
| 130 | T::regs().cr2().modify(|reg| { | ||
| 131 | reg.set_adon(false); | ||
| 132 | }); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn start_adc() { | ||
| 136 | T::regs().cr2().modify(|reg| { | ||
| 137 | reg.set_adon(true); | ||
| 138 | }); | ||
| 139 | } | ||
| 140 | |||
| 141 | /// Sets the channel sample time | ||
| 142 | /// | ||
| 143 | /// ## SAFETY: | ||
| 144 | /// - ADON == 0 i.e ADC must not be enabled when this is called. | ||
| 145 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||
| 146 | if ch <= 9 { | ||
| 147 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||
| 148 | } else { | ||
| 149 | T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) { | ||
| 154 | let ch_iter = ch.iter(); | ||
| 155 | for idx in ch_iter { | ||
| 156 | unsafe { | ||
| 157 | Self::set_channel_sample_time(*idx, sample_time); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | pub fn set_sample_sequence( | ||
| 163 | &mut self, | ||
| 164 | sequence: Sequence, | ||
| 165 | channel: &mut impl AdcChannel<T>, | ||
| 166 | sample_time: SampleTime, | ||
| 167 | ) { | ||
| 168 | let was_on = Self::is_on(); | ||
| 169 | if !was_on { | ||
| 170 | Self::start_adc(); | ||
| 171 | } | ||
| 172 | |||
| 173 | // Check the sequence is long enough | ||
| 174 | T::regs().sqr1().modify(|r| { | ||
| 175 | let prev: Sequence = r.l().into(); | ||
| 176 | if prev < sequence { | ||
| 177 | let new_l: Sequence = sequence; | ||
| 178 | trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8); | ||
| 179 | r.set_l(sequence.into()) | ||
| 180 | } else { | ||
| 181 | r.set_l(prev.into()) | ||
| 182 | } | ||
| 183 | }); | ||
| 184 | |||
| 185 | // Set this GPIO as an analog input. | ||
| 186 | channel.setup(); | ||
| 187 | |||
| 188 | // Set the channel in the right sequence field. | ||
| 189 | match sequence { | ||
| 190 | Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())), | ||
| 191 | Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())), | ||
| 192 | Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())), | ||
| 193 | Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())), | ||
| 194 | Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())), | ||
| 195 | Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())), | ||
| 196 | Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(6, channel.channel())), | ||
| 197 | Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(7, channel.channel())), | ||
| 198 | Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(8, channel.channel())), | ||
| 199 | Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(9, channel.channel())), | ||
| 200 | Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(10, channel.channel())), | ||
| 201 | Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(11, channel.channel())), | ||
| 202 | Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(12, channel.channel())), | ||
| 203 | Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(13, channel.channel())), | ||
| 204 | Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(14, channel.channel())), | ||
| 205 | Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(15, channel.channel())), | ||
| 206 | }; | ||
| 207 | |||
| 208 | if !was_on { | ||
| 209 | Self::stop_adc(); | ||
| 210 | } | ||
| 211 | |||
| 212 | self.set_channels_sample_time(&[channel.channel()], sample_time); | ||
| 213 | |||
| 214 | Self::start_adc(); | ||
| 215 | } | ||
| 216 | |||
| 217 | pub fn start(&mut self) -> Result<(), OverrunError> { | ||
| 218 | self.ring_buf.clear(); | ||
| 219 | |||
| 220 | self.setup_adc(); | ||
| 221 | |||
| 222 | Ok(()) | ||
| 223 | } | ||
| 224 | |||
| 225 | fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> { | ||
| 226 | self.teardown_adc(); | ||
| 227 | Err(err) | ||
| 228 | } | ||
| 229 | |||
| 230 | pub fn teardown_adc(&mut self) { | ||
| 231 | // Stop the DMA transfer | ||
| 232 | self.ring_buf.request_stop(); | ||
| 233 | |||
| 234 | let r = T::regs(); | ||
| 235 | |||
| 236 | // Stop ADC | ||
| 237 | r.cr2().modify(|reg| { | ||
| 238 | // Stop ADC | ||
| 239 | reg.set_swstart(false); | ||
| 240 | // Stop DMA | ||
| 241 | reg.set_dma(false); | ||
| 242 | }); | ||
| 243 | |||
| 244 | r.cr1().modify(|w| { | ||
| 245 | // Disable interrupt for end of conversion | ||
| 246 | w.set_eocie(false); | ||
| 247 | // Disable interrupt for overrun | ||
| 248 | w.set_ovrie(false); | ||
| 249 | }); | ||
| 250 | |||
| 251 | clear_interrupt_flags(r); | ||
| 252 | |||
| 253 | compiler_fence(Ordering::SeqCst); | ||
| 254 | } | ||
| 255 | |||
| 256 | fn setup_adc(&mut self) { | ||
| 257 | compiler_fence(Ordering::SeqCst); | ||
| 258 | |||
| 259 | self.ring_buf.start(); | ||
| 260 | |||
| 261 | let r = T::regs(); | ||
| 262 | |||
| 263 | // Enable ADC | ||
| 264 | let was_on = Self::is_on(); | ||
| 265 | if !was_on { | ||
| 266 | r.cr2().modify(|reg| { | ||
| 267 | reg.set_adon(false); | ||
| 268 | reg.set_swstart(false); | ||
| 269 | }); | ||
| 270 | } | ||
| 271 | |||
| 272 | // Clear all interrupts | ||
| 273 | r.sr().modify(|regs| { | ||
| 274 | regs.set_eoc(false); | ||
| 275 | regs.set_ovr(false); | ||
| 276 | regs.set_strt(false); | ||
| 277 | }); | ||
| 278 | |||
| 279 | r.cr1().modify(|w| { | ||
| 280 | // Enable interrupt for end of conversion | ||
| 281 | w.set_eocie(true); | ||
| 282 | // Enable interrupt for overrun | ||
| 283 | w.set_ovrie(true); | ||
| 284 | // Scanning converisons of multiple channels | ||
| 285 | w.set_scan(true); | ||
| 286 | // Continuous conversion mode | ||
| 287 | w.set_discen(false); | ||
| 288 | }); | ||
| 289 | |||
| 290 | r.cr2().modify(|w| { | ||
| 291 | // Enable DMA mode | ||
| 292 | w.set_dma(true); | ||
| 293 | // Enable continuous conversions | ||
| 294 | w.set_cont(vals::Cont::CONTINUOUS); | ||
| 295 | // DMA requests are issues as long as DMA=1 and data are converted. | ||
| 296 | w.set_dds(vals::Dds::CONTINUOUS); | ||
| 297 | // EOC flag is set at the end of each conversion. | ||
| 298 | w.set_eocs(vals::Eocs::EACHCONVERSION); | ||
| 299 | }); | ||
| 300 | |||
| 301 | // Begin ADC conversions | ||
| 302 | T::regs().cr2().modify(|reg| { | ||
| 303 | reg.set_adon(true); | ||
| 304 | reg.set_swstart(true); | ||
| 305 | }); | ||
| 306 | |||
| 307 | super::blocking_delay_us(3); | ||
| 308 | } | ||
| 309 | |||
| 310 | /// Read bytes that are readily available in the ring buffer. | ||
| 311 | /// If no bytes are currently available in the buffer the call waits until the some | ||
| 312 | /// bytes are available (at least one byte and at most half the buffer size) | ||
| 313 | /// | ||
| 314 | /// Background receive is started if `start()` has not been previously called. | ||
| 315 | /// | ||
| 316 | /// Receive in the background is terminated if an error is returned. | ||
| 317 | /// It must then manually be started again by calling `start()` or by re-calling `read()`. | ||
| 318 | pub fn read<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> { | ||
| 319 | let r = T::regs(); | ||
| 320 | |||
| 321 | // Start background receive if it was not already started | ||
| 322 | if !r.cr2().read().dma() { | ||
| 323 | self.start()?; | ||
| 324 | } | ||
| 325 | |||
| 326 | // Clear overrun flag if set. | ||
| 327 | if r.sr().read().ovr() { | ||
| 328 | return self.stop(OverrunError); | ||
| 329 | } | ||
| 330 | |||
| 331 | loop { | ||
| 332 | match self.ring_buf.read(buf) { | ||
| 333 | Ok((0, _)) => {} | ||
| 334 | Ok((len, _)) => { | ||
| 335 | return Ok(len); | ||
| 336 | } | ||
| 337 | Err(_) => { | ||
| 338 | return self.stop(OverrunError); | ||
| 339 | } | ||
| 340 | } | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | pub async fn read_exact<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> { | ||
| 345 | let r = T::regs(); | ||
| 346 | |||
| 347 | // Start background receive if it was not already started | ||
| 348 | if !r.cr2().read().dma() { | ||
| 349 | self.start()?; | ||
| 350 | } | ||
| 351 | |||
| 352 | // Clear overrun flag if set. | ||
| 353 | if r.sr().read().ovr() { | ||
| 354 | return self.stop(OverrunError); | ||
| 355 | } | ||
| 356 | match self.ring_buf.read_exact(buf).await { | ||
| 357 | Ok(len) => Ok(len), | ||
| 358 | Err(_) => self.stop(OverrunError), | ||
| 359 | } | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | impl<T: Instance> Drop for RingBufferedAdc<'_, T> { | ||
| 364 | fn drop(&mut self) { | ||
| 365 | self.teardown_adc(); | ||
| 366 | rcc::disable::<T>(); | ||
| 367 | } | ||
| 368 | } | ||
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index e3175dff5..ddeb7ea79 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -6,6 +6,9 @@ use crate::peripherals::ADC1; | |||
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 7 | use crate::{rcc, Peripheral}; | 7 | use crate::{rcc, Peripheral}; |
| 8 | 8 | ||
| 9 | mod ringbuffered_v2; | ||
| 10 | pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; | ||
| 11 | |||
| 9 | /// Default VREF voltage used for sample conversion to millivolts. | 12 | /// Default VREF voltage used for sample conversion to millivolts. |
| 10 | pub const VREF_DEFAULT_MV: u32 = 3300; | 13 | pub const VREF_DEFAULT_MV: u32 = 3300; |
| 11 | /// VREF voltage used for factory calibration of VREFINTCAL register. | 14 | /// VREF voltage used for factory calibration of VREFINTCAL register. |
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs new file mode 100644 index 000000000..992bed573 --- /dev/null +++ b/examples/stm32f4/src/bin/adc_dma.rs | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | use cortex_m::singleton; | ||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; | ||
| 7 | use embassy_stm32::Peripherals; | ||
| 8 | use embassy_time::Instant; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(spawner: Spawner) { | ||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | spawner.must_spawn(adc_task(p)); | ||
| 15 | } | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async fn adc_task(mut p: Peripherals) { | ||
| 19 | const ADC_BUF_SIZE: usize = 1024; | ||
| 20 | let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); | ||
| 21 | let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); | ||
| 22 | |||
| 23 | let adc = Adc::new(p.ADC1); | ||
| 24 | let adc2 = Adc::new(p.ADC2); | ||
| 25 | |||
| 26 | let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_data); | ||
| 27 | let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(p.DMA2_CH2, adc_data2); | ||
| 28 | |||
| 29 | adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); | ||
| 30 | adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112); | ||
| 31 | adc2.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112); | ||
| 32 | adc2.set_sample_sequence(Sequence::Two, &mut p.PA3, SampleTime::CYCLES112); | ||
| 33 | |||
| 34 | // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around | ||
| 35 | // 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 | ||
| 36 | // 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 | ||
| 37 | // a reduction of performance as each time the buffer is reset, the adc & dma buffer must be restarted. | ||
| 38 | |||
| 39 | // 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 | ||
| 40 | // frequently. | ||
| 41 | let mut tic = Instant::now(); | ||
| 42 | let mut buffer1 = [0u16; 512]; | ||
| 43 | let mut buffer2 = [0u16; 512]; | ||
| 44 | let _ = adc.start(); | ||
| 45 | let _ = adc2.start(); | ||
| 46 | loop { | ||
| 47 | match adc.read_exact(&mut buffer1).await { | ||
| 48 | Ok(_data) => { | ||
| 49 | let toc = Instant::now(); | ||
| 50 | info!( | ||
| 51 | "\n adc1: {} dt = {}, n = {}", | ||
| 52 | buffer1[0..16], | ||
| 53 | (toc - tic).as_micros(), | ||
| 54 | _data | ||
| 55 | ); | ||
| 56 | tic = toc; | ||
| 57 | } | ||
| 58 | Err(e) => { | ||
| 59 | warn!("Error: {:?}", e); | ||
| 60 | buffer1 = [0u16; 512]; | ||
| 61 | let _ = adc.start(); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | match adc2.read_exact(&mut buffer2).await { | ||
| 66 | Ok(_data) => { | ||
| 67 | let toc = Instant::now(); | ||
| 68 | info!( | ||
| 69 | "\n adc2: {} dt = {}, n = {}", | ||
| 70 | buffer2[0..16], | ||
| 71 | (toc - tic).as_micros(), | ||
| 72 | _data | ||
| 73 | ); | ||
| 74 | tic = toc; | ||
| 75 | } | ||
| 76 | Err(e) => { | ||
| 77 | warn!("Error: {:?}", e); | ||
| 78 | buffer2 = [0u16; 512]; | ||
| 79 | let _ = adc2.start(); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
