diff options
| -rw-r--r-- | embassy-nrf/src/saadc.rs | 115 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 51 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 40 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 36 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 5 | ||||
| -rw-r--r-- | examples/nrf/src/bin/saadc_continuous.rs | 59 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spi_dma.rs | 2 | ||||
| m--------- | stm32-data | 0 | ||||
| -rw-r--r-- | tests/stm32/src/bin/spi_dma.rs | 6 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart_dma.rs | 6 |
10 files changed, 208 insertions, 112 deletions
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 617c9e041..c4de7315f 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs | |||
| @@ -10,7 +10,8 @@ use embassy_hal_common::unborrow; | |||
| 10 | use futures::future::poll_fn; | 10 | use futures::future::poll_fn; |
| 11 | 11 | ||
| 12 | use crate::interrupt; | 12 | use crate::interrupt; |
| 13 | use crate::ppi::Task; | 13 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; |
| 14 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | ||
| 14 | use crate::{pac, peripherals}; | 15 | use crate::{pac, peripherals}; |
| 15 | 16 | ||
| 16 | use pac::{saadc, SAADC}; | 17 | use pac::{saadc, SAADC}; |
| @@ -207,6 +208,11 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 207 | fn on_interrupt(_ctx: *mut ()) { | 208 | fn on_interrupt(_ctx: *mut ()) { |
| 208 | let r = Self::regs(); | 209 | let r = Self::regs(); |
| 209 | 210 | ||
| 211 | if r.events_calibratedone.read().bits() != 0 { | ||
| 212 | r.intenclr.write(|w| w.calibratedone().clear()); | ||
| 213 | WAKER.wake(); | ||
| 214 | } | ||
| 215 | |||
| 210 | if r.events_end.read().bits() != 0 { | 216 | if r.events_end.read().bits() != 0 { |
| 211 | r.intenclr.write(|w| w.end().clear()); | 217 | r.intenclr.write(|w| w.end().clear()); |
| 212 | WAKER.wake(); | 218 | WAKER.wake(); |
| @@ -222,6 +228,35 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 222 | unsafe { &*SAADC::ptr() } | 228 | unsafe { &*SAADC::ptr() } |
| 223 | } | 229 | } |
| 224 | 230 | ||
| 231 | /// Perform SAADC calibration. Completes when done. | ||
| 232 | pub async fn calibrate(&self) { | ||
| 233 | let r = Self::regs(); | ||
| 234 | |||
| 235 | // Reset and enable the end event | ||
| 236 | r.events_calibratedone.reset(); | ||
| 237 | r.intenset.write(|w| w.calibratedone().set()); | ||
| 238 | |||
| 239 | // Order is important | ||
| 240 | compiler_fence(Ordering::SeqCst); | ||
| 241 | |||
| 242 | r.tasks_calibrateoffset.write(|w| unsafe { w.bits(1) }); | ||
| 243 | |||
| 244 | // Wait for 'calibratedone' event. | ||
| 245 | poll_fn(|cx| { | ||
| 246 | let r = Self::regs(); | ||
| 247 | |||
| 248 | WAKER.register(cx.waker()); | ||
| 249 | |||
| 250 | if r.events_calibratedone.read().bits() != 0 { | ||
| 251 | r.events_calibratedone.reset(); | ||
| 252 | return Poll::Ready(()); | ||
| 253 | } | ||
| 254 | |||
| 255 | Poll::Pending | ||
| 256 | }) | ||
| 257 | .await; | ||
| 258 | } | ||
| 259 | |||
| 225 | /// One shot sampling. The buffer must be the same size as the number of channels configured. | 260 | /// One shot sampling. The buffer must be the same size as the number of channels configured. |
| 226 | pub async fn sample(&mut self, buf: &mut [i16; N]) { | 261 | pub async fn sample(&mut self, buf: &mut [i16; N]) { |
| 227 | let r = Self::regs(); | 262 | let r = Self::regs(); |
| @@ -263,29 +298,77 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 263 | 298 | ||
| 264 | /// Continuous sampling with double buffers. | 299 | /// Continuous sampling with double buffers. |
| 265 | /// | 300 | /// |
| 266 | /// A task-driven approach to driving TASK_SAMPLE is expected. With a task | 301 | /// A TIMER and two PPI peripherals are passed in so that precise sampling |
| 267 | /// driven approach, multiple channels can be used. | 302 | /// can be attained. The sampling interval is expressed by selecting a |
| 303 | /// timer clock frequency to use along with a counter threshold to be reached. | ||
| 304 | /// For example, 1KHz can be achieved using a frequency of 1MHz and a counter | ||
| 305 | /// threshold of 1000. | ||
| 268 | /// | 306 | /// |
| 269 | /// A sampler closure is provided that receives the buffer of samples, noting | 307 | /// A sampler closure is provided that receives the buffer of samples, noting |
| 270 | /// that the size of this buffer can be less than the original buffer's size. | 308 | /// that the size of this buffer can be less than the original buffer's size. |
| 271 | /// A command is return from the closure that indicates whether the sampling | 309 | /// A command is return from the closure that indicates whether the sampling |
| 272 | /// should continue or stop. | 310 | /// should continue or stop. |
| 273 | pub async fn run_task_sampler<S, const N0: usize>( | 311 | /// |
| 312 | /// NOTE: The time spent within the callback supplied should not exceed the time | ||
| 313 | /// taken to acquire the samples into a single buffer. You should measure the | ||
| 314 | /// time taken by the callback and set the sample buffer size accordingly. | ||
| 315 | /// Exceeding this time can lead to samples becoming dropped. | ||
| 316 | pub async fn run_task_sampler<S, T: TimerInstance, const N0: usize>( | ||
| 274 | &mut self, | 317 | &mut self, |
| 318 | timer: &mut T, | ||
| 319 | ppi_ch1: &mut impl ConfigurableChannel, | ||
| 320 | ppi_ch2: &mut impl ConfigurableChannel, | ||
| 321 | frequency: Frequency, | ||
| 322 | sample_counter: u32, | ||
| 275 | bufs: &mut [[[i16; N]; N0]; 2], | 323 | bufs: &mut [[[i16; N]; N0]; 2], |
| 276 | sampler: S, | 324 | sampler: S, |
| 277 | ) where | 325 | ) where |
| 278 | S: FnMut(&[[i16; N]]) -> SamplerState, | 326 | S: FnMut(&[[i16; N]]) -> SamplerState, |
| 279 | { | 327 | { |
| 280 | self.run_sampler(bufs, None, sampler).await; | 328 | let r = Self::regs(); |
| 329 | |||
| 330 | // We want the task start to effectively short with the last one ending so | ||
| 331 | // we don't miss any samples. It'd be great for the SAADC to offer a SHORTS | ||
| 332 | // register instead, but it doesn't, so we must use PPI. | ||
| 333 | let mut start_ppi = Ppi::new_one_to_one( | ||
| 334 | ppi_ch1, | ||
| 335 | Event::from_reg(&r.events_end), | ||
| 336 | Task::from_reg(&r.tasks_start), | ||
| 337 | ); | ||
| 338 | start_ppi.enable(); | ||
| 339 | |||
| 340 | let mut timer = Timer::new(timer); | ||
| 341 | timer.set_frequency(frequency); | ||
| 342 | timer.cc(0).write(sample_counter); | ||
| 343 | timer.cc(0).short_compare_clear(); | ||
| 344 | |||
| 345 | let mut sample_ppi = Ppi::new_one_to_one( | ||
| 346 | ppi_ch2, | ||
| 347 | timer.cc(0).event_compare(), | ||
| 348 | Task::from_reg(&r.tasks_sample), | ||
| 349 | ); | ||
| 350 | |||
| 351 | timer.start(); | ||
| 352 | |||
| 353 | self.run_sampler( | ||
| 354 | bufs, | ||
| 355 | None, | ||
| 356 | || { | ||
| 357 | sample_ppi.enable(); | ||
| 358 | }, | ||
| 359 | sampler, | ||
| 360 | ) | ||
| 361 | .await; | ||
| 281 | } | 362 | } |
| 282 | 363 | ||
| 283 | async fn run_sampler<S, const N0: usize>( | 364 | async fn run_sampler<I, S, const N0: usize>( |
| 284 | &mut self, | 365 | &mut self, |
| 285 | bufs: &mut [[[i16; N]; N0]; 2], | 366 | bufs: &mut [[[i16; N]; N0]; 2], |
| 286 | sample_rate_divisor: Option<u16>, | 367 | sample_rate_divisor: Option<u16>, |
| 368 | mut init: I, | ||
| 287 | mut sampler: S, | 369 | mut sampler: S, |
| 288 | ) where | 370 | ) where |
| 371 | I: FnMut(), | ||
| 289 | S: FnMut(&[[i16; N]]) -> SamplerState, | 372 | S: FnMut(&[[i16; N]]) -> SamplerState, |
| 290 | { | 373 | { |
| 291 | let r = Self::regs(); | 374 | let r = Self::regs(); |
| @@ -330,6 +413,8 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 330 | 413 | ||
| 331 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | 414 | r.tasks_start.write(|w| unsafe { w.bits(1) }); |
| 332 | 415 | ||
| 416 | let mut inited = false; | ||
| 417 | |||
| 333 | let mut current_buffer = 0; | 418 | let mut current_buffer = 0; |
| 334 | 419 | ||
| 335 | // Wait for events and complete when the sampler indicates it has had enough. | 420 | // Wait for events and complete when the sampler indicates it has had enough. |
| @@ -347,7 +432,6 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 347 | if sampler(&bufs[current_buffer]) == SamplerState::Sampled { | 432 | if sampler(&bufs[current_buffer]) == SamplerState::Sampled { |
| 348 | let next_buffer = 1 - current_buffer; | 433 | let next_buffer = 1 - current_buffer; |
| 349 | current_buffer = next_buffer; | 434 | current_buffer = next_buffer; |
| 350 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||
| 351 | } else { | 435 | } else { |
| 352 | return Poll::Ready(()); | 436 | return Poll::Ready(()); |
| 353 | }; | 437 | }; |
| @@ -357,6 +441,11 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 357 | r.events_started.reset(); | 441 | r.events_started.reset(); |
| 358 | r.intenset.write(|w| w.started().set()); | 442 | r.intenset.write(|w| w.started().set()); |
| 359 | 443 | ||
| 444 | if !inited { | ||
| 445 | init(); | ||
| 446 | inited = true; | ||
| 447 | } | ||
| 448 | |||
| 360 | let next_buffer = 1 - current_buffer; | 449 | let next_buffer = 1 - current_buffer; |
| 361 | r.result | 450 | r.result |
| 362 | .ptr | 451 | .ptr |
| @@ -367,26 +456,20 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 367 | }) | 456 | }) |
| 368 | .await; | 457 | .await; |
| 369 | } | 458 | } |
| 370 | |||
| 371 | /// Return the sample task for use with PPI | ||
| 372 | pub fn task_sample(&self) -> Task { | ||
| 373 | let r = Self::regs(); | ||
| 374 | Task::from_reg(&r.tasks_sample) | ||
| 375 | } | ||
| 376 | } | 459 | } |
| 377 | 460 | ||
| 378 | impl<'d> Saadc<'d, 1> { | 461 | impl<'d> Saadc<'d, 1> { |
| 379 | /// Continuous sampling on a single channel with double buffers. | 462 | /// Continuous sampling on a single channel with double buffers. |
| 380 | /// | 463 | /// |
| 381 | /// The internal clock is to be used with a sample rate expressed as a divisor of | 464 | /// The internal clock is to be used with a sample rate expressed as a divisor of |
| 382 | /// 16MHz, ranging from 80..2047. For example, 1600 represnts a sample rate of 10KHz | 465 | /// 16MHz, ranging from 80..2047. For example, 1600 represents a sample rate of 10KHz |
| 383 | /// given 16_000_000 / 10_000_000 = 1600. | 466 | /// given 16_000_000 / 10_000_000 = 1600. |
| 384 | /// | 467 | /// |
| 385 | /// A sampler closure is provided that receives the buffer of samples, noting | 468 | /// A sampler closure is provided that receives the buffer of samples, noting |
| 386 | /// that the size of this buffer can be less than the original buffer's size. | 469 | /// that the size of this buffer can be less than the original buffer's size. |
| 387 | /// A command is return from the closure that indicates whether the sampling | 470 | /// A command is return from the closure that indicates whether the sampling |
| 388 | /// should continue or stop. | 471 | /// should continue or stop. |
| 389 | pub async fn run_timer_sampler<S, const N0: usize>( | 472 | pub async fn run_timer_sampler<I, S, const N0: usize>( |
| 390 | &mut self, | 473 | &mut self, |
| 391 | bufs: &mut [[[i16; 1]; N0]; 2], | 474 | bufs: &mut [[[i16; 1]; N0]; 2], |
| 392 | sample_rate_divisor: u16, | 475 | sample_rate_divisor: u16, |
| @@ -394,7 +477,7 @@ impl<'d> Saadc<'d, 1> { | |||
| 394 | ) where | 477 | ) where |
| 395 | S: FnMut(&[[i16; 1]]) -> SamplerState, | 478 | S: FnMut(&[[i16; 1]]) -> SamplerState, |
| 396 | { | 479 | { |
| 397 | self.run_sampler(bufs, Some(sample_rate_divisor), sampler) | 480 | self.run_sampler(bufs, Some(sample_rate_divisor), || {}, sampler) |
| 398 | .await; | 481 | .await; |
| 399 | } | 482 | } |
| 400 | } | 483 | } |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 02d47da81..8b64aaaac 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -105,46 +105,41 @@ fn main() { | |||
| 105 | // ======== | 105 | // ======== |
| 106 | // Generate DMA IRQs. | 106 | // Generate DMA IRQs. |
| 107 | 107 | ||
| 108 | let mut dma_irqs: HashSet<&str> = HashSet::new(); | 108 | let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new(); |
| 109 | let mut bdma_irqs: HashSet<&str> = HashSet::new(); | ||
| 110 | 109 | ||
| 111 | for p in METADATA.peripherals { | 110 | for p in METADATA.peripherals { |
| 112 | if let Some(r) = &p.registers { | 111 | if let Some(r) = &p.registers { |
| 113 | match r.kind { | 112 | if r.kind == "dma" || r.kind == "bdma" { |
| 114 | "dma" => { | 113 | if p.name == "BDMA1" { |
| 115 | for irq in p.interrupts { | 114 | // BDMA1 in H7 doesn't use DMAMUX, which breaks |
| 116 | dma_irqs.insert(irq.interrupt); | 115 | continue; |
| 117 | } | ||
| 118 | } | 116 | } |
| 119 | "bdma" => { | 117 | for irq in p.interrupts { |
| 120 | for irq in p.interrupts { | 118 | dma_irqs |
| 121 | bdma_irqs.insert(irq.interrupt); | 119 | .entry(irq.interrupt) |
| 122 | } | 120 | .or_default() |
| 121 | .push((p.name, irq.signal)); | ||
| 123 | } | 122 | } |
| 124 | _ => {} | ||
| 125 | } | 123 | } |
| 126 | } | 124 | } |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | let tokens: Vec<_> = dma_irqs.iter().map(|s| format_ident!("{}", s)).collect(); | 127 | for (irq, channels) in dma_irqs { |
| 130 | g.extend(quote! { | 128 | let irq = format_ident!("{}", irq); |
| 131 | #( | ||
| 132 | #[crate::interrupt] | ||
| 133 | unsafe fn #tokens () { | ||
| 134 | crate::dma::dma::on_irq(); | ||
| 135 | } | ||
| 136 | )* | ||
| 137 | }); | ||
| 138 | 129 | ||
| 139 | let tokens: Vec<_> = bdma_irqs.iter().map(|s| format_ident!("{}", s)).collect(); | 130 | let channels = channels |
| 140 | g.extend(quote! { | 131 | .iter() |
| 141 | #( | 132 | .map(|(dma, ch)| format_ident!("{}_{}", dma, ch)); |
| 133 | |||
| 134 | g.extend(quote! { | ||
| 142 | #[crate::interrupt] | 135 | #[crate::interrupt] |
| 143 | unsafe fn #tokens () { | 136 | unsafe fn #irq () { |
| 144 | crate::dma::bdma::on_irq(); | 137 | #( |
| 138 | <crate::peripherals::#channels as crate::dma::sealed::Channel>::on_irq(); | ||
| 139 | )* | ||
| 145 | } | 140 | } |
| 146 | )* | 141 | }); |
| 147 | }); | 142 | } |
| 148 | 143 | ||
| 149 | // ======== | 144 | // ======== |
| 150 | // Generate RccPeripheral impls | 145 | // Generate RccPeripheral impls |
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 105bea50e..ec557da30 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -38,26 +38,6 @@ impl State { | |||
| 38 | 38 | ||
| 39 | static STATE: State = State::new(); | 39 | static STATE: State = State::new(); |
| 40 | 40 | ||
| 41 | pub(crate) unsafe fn on_irq() { | ||
| 42 | foreach_peripheral! { | ||
| 43 | (bdma, BDMA1) => { | ||
| 44 | // BDMA1 in H7 doesn't use DMAMUX, which breaks | ||
| 45 | }; | ||
| 46 | (bdma, $dma:ident) => { | ||
| 47 | let isr = pac::$dma.isr().read(); | ||
| 48 | foreach_dma_channel! { | ||
| 49 | ($channel_peri:ident, $dma, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { | ||
| 50 | let cr = pac::$dma.ch($channel_num).cr(); | ||
| 51 | if isr.tcif($channel_num) && cr.read().tcie() { | ||
| 52 | cr.write(|_| ()); // Disable channel interrupts with the default value. | ||
| 53 | STATE.ch_wakers[$index].wake(); | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | /// safety: must be called only once | 41 | /// safety: must be called only once |
| 62 | pub(crate) unsafe fn init() { | 42 | pub(crate) unsafe fn init() { |
| 63 | foreach_interrupt! { | 43 | foreach_interrupt! { |
| @@ -150,6 +130,12 @@ foreach_dma_channel! { | |||
| 150 | fn set_waker(&mut self, waker: &Waker) { | 130 | fn set_waker(&mut self, waker: &Waker) { |
| 151 | unsafe { low_level_api::set_waker($index, waker) } | 131 | unsafe { low_level_api::set_waker($index, waker) } |
| 152 | } | 132 | } |
| 133 | |||
| 134 | fn on_irq() { | ||
| 135 | unsafe { | ||
| 136 | low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | ||
| 137 | } | ||
| 138 | } | ||
| 153 | } | 139 | } |
| 154 | 140 | ||
| 155 | impl crate::dma::Channel for crate::peripherals::$channel_peri {} | 141 | impl crate::dma::Channel for crate::peripherals::$channel_peri {} |
| @@ -243,4 +229,18 @@ mod low_level_api { | |||
| 243 | w.set_teif(channel_number as _, true); | 229 | w.set_teif(channel_number as _, true); |
| 244 | }); | 230 | }); |
| 245 | } | 231 | } |
| 232 | |||
| 233 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | ||
| 234 | pub unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: u8, index: u8) { | ||
| 235 | let channel_num = channel_num as usize; | ||
| 236 | let index = index as usize; | ||
| 237 | |||
| 238 | let isr = dma.isr().read(); | ||
| 239 | let cr = dma.ch(channel_num).cr(); | ||
| 240 | |||
| 241 | if isr.tcif(channel_num) && cr.read().tcie() { | ||
| 242 | cr.write(|_| ()); // Disable channel interrupts with the default value. | ||
| 243 | STATE.ch_wakers[index].wake(); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | } | 246 | } |
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 95a6eea2f..9ef7e4288 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -36,22 +36,6 @@ impl State { | |||
| 36 | 36 | ||
| 37 | static STATE: State = State::new(); | 37 | static STATE: State = State::new(); |
| 38 | 38 | ||
| 39 | pub(crate) unsafe fn on_irq() { | ||
| 40 | foreach_peripheral! { | ||
| 41 | (dma, $dma:ident) => { | ||
| 42 | foreach_dma_channel! { | ||
| 43 | ($channel_peri:ident, $dma, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { | ||
| 44 | let cr = pac::$dma.st($channel_num).cr(); | ||
| 45 | if pac::$dma.isr($channel_num/4).read().tcif($channel_num%4) && cr.read().tcie() { | ||
| 46 | cr.write(|_| ()); // Disable channel interrupts with the default value. | ||
| 47 | STATE.ch_wakers[$index].wake(); | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | /// safety: must be called only once | 39 | /// safety: must be called only once |
| 56 | pub(crate) unsafe fn init() { | 40 | pub(crate) unsafe fn init() { |
| 57 | foreach_interrupt! { | 41 | foreach_interrupt! { |
| @@ -137,6 +121,12 @@ foreach_dma_channel! { | |||
| 137 | fn set_waker(&mut self, waker: &Waker) { | 121 | fn set_waker(&mut self, waker: &Waker) { |
| 138 | unsafe {low_level_api::set_waker($index, waker )} | 122 | unsafe {low_level_api::set_waker($index, waker )} |
| 139 | } | 123 | } |
| 124 | |||
| 125 | fn on_irq() { | ||
| 126 | unsafe { | ||
| 127 | low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | ||
| 128 | } | ||
| 129 | } | ||
| 140 | } | 130 | } |
| 141 | 131 | ||
| 142 | impl crate::dma::Channel for crate::peripherals::$channel_peri { } | 132 | impl crate::dma::Channel for crate::peripherals::$channel_peri { } |
| @@ -240,4 +230,18 @@ mod low_level_api { | |||
| 240 | w.set_teif(isrbit, true); | 230 | w.set_teif(isrbit, true); |
| 241 | }); | 231 | }); |
| 242 | } | 232 | } |
| 233 | |||
| 234 | /// Safety: Must be called with a matching set of parameters for a valid dma channel | ||
| 235 | pub unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: u8, index: u8) { | ||
| 236 | let channel_num = channel_num as usize; | ||
| 237 | let index = index as usize; | ||
| 238 | |||
| 239 | let cr = dma.st(channel_num).cr(); | ||
| 240 | let isr = dma.isr(channel_num / 4).read(); | ||
| 241 | |||
| 242 | if isr.tcif(channel_num % 4) && cr.read().tcie() { | ||
| 243 | cr.write(|_| ()); // Disable channel interrupts with the default value. | ||
| 244 | STATE.ch_wakers[index].wake(); | ||
| 245 | } | ||
| 246 | } | ||
| 243 | } | 247 | } |
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 6bca969c8..4768a448c 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -88,6 +88,11 @@ pub(crate) mod sealed { | |||
| 88 | 88 | ||
| 89 | /// Sets the waker that is called when this channel stops (either completed or manually stopped) | 89 | /// Sets the waker that is called when this channel stops (either completed or manually stopped) |
| 90 | fn set_waker(&mut self, waker: &Waker); | 90 | fn set_waker(&mut self, waker: &Waker); |
| 91 | |||
| 92 | /// This is called when this channel triggers an interrupt. | ||
| 93 | /// Note: Because some channels share an interrupt, this function might be | ||
| 94 | /// called for a channel that didn't trigger an interrupt. | ||
| 95 | fn on_irq(); | ||
| 91 | } | 96 | } |
| 92 | } | 97 | } |
| 93 | 98 | ||
diff --git a/examples/nrf/src/bin/saadc_continuous.rs b/examples/nrf/src/bin/saadc_continuous.rs index 81559237b..bdf552fba 100644 --- a/examples/nrf/src/bin/saadc_continuous.rs +++ b/examples/nrf/src/bin/saadc_continuous.rs | |||
| @@ -5,9 +5,9 @@ | |||
| 5 | #[path = "../example_common.rs"] | 5 | #[path = "../example_common.rs"] |
| 6 | mod example_common; | 6 | mod example_common; |
| 7 | use embassy::executor::Spawner; | 7 | use embassy::executor::Spawner; |
| 8 | use embassy_nrf::ppi::Ppi; | 8 | use embassy::time::Duration; |
| 9 | use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; | 9 | use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; |
| 10 | use embassy_nrf::timer::{Frequency, Timer}; | 10 | use embassy_nrf::timer::Frequency; |
| 11 | use embassy_nrf::{interrupt, Peripherals}; | 11 | use embassy_nrf::{interrupt, Peripherals}; |
| 12 | use example_common::*; | 12 | use example_common::*; |
| 13 | 13 | ||
| @@ -26,34 +26,43 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { | |||
| 26 | [channel_1_config, channel_2_config, channel_3_config], | 26 | [channel_1_config, channel_2_config, channel_3_config], |
| 27 | ); | 27 | ); |
| 28 | 28 | ||
| 29 | let mut timer = Timer::new(p.TIMER0); | 29 | // This delay demonstrates that starting the timer prior to running |
| 30 | timer.set_frequency(Frequency::F1MHz); | 30 | // the task sampler is benign given the calibration that follows. |
| 31 | timer.cc(0).write(100); // We want to sample at 10KHz | 31 | embassy::time::Timer::after(Duration::from_millis(500)).await; |
| 32 | timer.cc(0).short_compare_clear(); | 32 | saadc.calibrate().await; |
| 33 | 33 | ||
| 34 | let mut ppi = Ppi::new_one_to_one(p.PPI_CH0, timer.cc(0).event_compare(), saadc.task_sample()); | 34 | let mut bufs = [[[0; 3]; 500]; 2]; |
| 35 | ppi.enable(); | ||
| 36 | |||
| 37 | timer.start(); | ||
| 38 | |||
| 39 | let mut bufs = [[[0; 3]; 50]; 2]; | ||
| 40 | 35 | ||
| 41 | let mut c = 0; | 36 | let mut c = 0; |
| 42 | let mut a: i32 = 0; | 37 | let mut a: i32 = 0; |
| 43 | 38 | ||
| 44 | saadc | 39 | saadc |
| 45 | .run_task_sampler(&mut bufs, move |buf| { | 40 | .run_task_sampler( |
| 46 | for b in buf { | 41 | &mut p.TIMER0, |
| 47 | a += b[0] as i32; | 42 | &mut p.PPI_CH0, |
| 48 | } | 43 | &mut p.PPI_CH1, |
| 49 | c += buf.len(); | 44 | Frequency::F1MHz, |
| 50 | if c > 10000 { | 45 | 1000, // We want to sample at 1KHz |
| 51 | a = a / c as i32; | 46 | &mut bufs, |
| 52 | info!("channel 1: {=i32}", a); | 47 | move |buf| { |
| 53 | c = 0; | 48 | // NOTE: It is important that the time spent within this callback |
| 54 | a = 0; | 49 | // does not exceed the time taken to acquire the 1500 samples we |
| 55 | } | 50 | // have in this example, which would be 10us + 2us per |
| 56 | SamplerState::Sampled | 51 | // sample * 1500 = 18ms. You need to measure the time taken here |
| 57 | }) | 52 | // and set the sample buffer size accordingly. Exceeding this |
| 53 | // time can lead to the peripheral re-writing the other buffer. | ||
| 54 | for b in buf { | ||
| 55 | a += b[0] as i32; | ||
| 56 | } | ||
| 57 | c += buf.len(); | ||
| 58 | if c > 1000 { | ||
| 59 | a = a / c as i32; | ||
| 60 | info!("channel 1: {=i32}", a); | ||
| 61 | c = 0; | ||
| 62 | a = 0; | ||
| 63 | } | ||
| 64 | SamplerState::Sampled | ||
| 65 | }, | ||
| 66 | ) | ||
| 58 | .await; | 67 | .await; |
| 59 | } | 68 | } |
diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs index b4d5091b2..a9327f8fe 100644 --- a/examples/stm32l4/src/bin/spi_dma.rs +++ b/examples/stm32l4/src/bin/spi_dma.rs | |||
| @@ -21,8 +21,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 21 | p.PC10, | 21 | p.PC10, |
| 22 | p.PC12, | 22 | p.PC12, |
| 23 | p.PC11, | 23 | p.PC11, |
| 24 | p.DMA1_CH0, | ||
| 25 | p.DMA1_CH1, | 24 | p.DMA1_CH1, |
| 25 | p.DMA1_CH2, | ||
| 26 | Hertz(1_000_000), | 26 | Hertz(1_000_000), |
| 27 | Config::default(), | 27 | Config::default(), |
| 28 | ); | 28 | ); |
diff --git a/stm32-data b/stm32-data | |||
| Subproject ad77937fb81628b982d2a674a88d983ec020fec | Subproject d3e8a2fe63eeb403102559f3f9917d9fcf27e1a | ||
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index f224d3446..59a5bcd0c 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs | |||
| @@ -22,11 +22,11 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 22 | #[cfg(feature = "stm32h755zi")] | 22 | #[cfg(feature = "stm32h755zi")] |
| 23 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); | 23 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); |
| 24 | #[cfg(feature = "stm32g491re")] | 24 | #[cfg(feature = "stm32g491re")] |
| 25 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH0, p.DMA1_CH1); | 25 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); |
| 26 | #[cfg(feature = "stm32g071rb")] | 26 | #[cfg(feature = "stm32g071rb")] |
| 27 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH0, p.DMA1_CH1); | 27 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); |
| 28 | #[cfg(feature = "stm32wb55rg")] | 28 | #[cfg(feature = "stm32wb55rg")] |
| 29 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH0, p.DMA1_CH1); | 29 | let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); |
| 30 | 30 | ||
| 31 | let mut spi = Spi::new( | 31 | let mut spi = Spi::new( |
| 32 | p.SPI1, | 32 | p.SPI1, |
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index 3cf9c7860..2565409e6 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs | |||
| @@ -25,13 +25,13 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 25 | #[cfg(feature = "stm32f103c8")] | 25 | #[cfg(feature = "stm32f103c8")] |
| 26 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); | 26 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); |
| 27 | #[cfg(feature = "stm32g491re")] | 27 | #[cfg(feature = "stm32g491re")] |
| 28 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH0, p.DMA1_CH1); | 28 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); |
| 29 | #[cfg(feature = "stm32g071rb")] | 29 | #[cfg(feature = "stm32g071rb")] |
| 30 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH0, p.DMA1_CH1); | 30 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); |
| 31 | #[cfg(feature = "stm32f429zi")] | 31 | #[cfg(feature = "stm32f429zi")] |
| 32 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); | 32 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); |
| 33 | #[cfg(feature = "stm32wb55rg")] | 33 | #[cfg(feature = "stm32wb55rg")] |
| 34 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH0, p.DMA1_CH1); // TODO this is wrong | 34 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH1, p.DMA1_CH2); // TODO this is wrong |
| 35 | #[cfg(feature = "stm32h755zi")] | 35 | #[cfg(feature = "stm32h755zi")] |
| 36 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); | 36 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); |
| 37 | 37 | ||
