diff options
| author | RaulIQ <[email protected]> | 2025-05-21 12:27:25 +0300 |
|---|---|---|
| committer | RaulIQ <[email protected]> | 2025-05-21 12:27:25 +0300 |
| commit | 05c511355638c3a55ab509ef9b2e30f5564b6282 (patch) | |
| tree | 966394083ec0626dc566e73b08c1f7ccb22b0e4d | |
| parent | 7cbc9058bc726900571a7858c581f60cd8cb0266 (diff) | |
add waveform_up_multichannel using DMAR/DCR
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 8fd7e8df4..c6fd169fc 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -381,6 +381,74 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 381 | self.inner.enable_update_dma(false); | 381 | self.inner.enable_update_dma(false); |
| 382 | } | 382 | } |
| 383 | } | 383 | } |
| 384 | |||
| 385 | /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. | ||
| 386 | /// | ||
| 387 | /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers | ||
| 388 | /// in sequence on each update event (UEV). The data is written via the DMAR register using the | ||
| 389 | /// DMA base address (DBA) and burst length (DBL) configured in the DCR register. | ||
| 390 | /// | ||
| 391 | /// Note: | ||
| 392 | /// you will need to provide corresponding TIMx_UP DMA channel to use this method. | ||
| 393 | pub async fn waveform_up_multichannel( | ||
| 394 | &mut self, | ||
| 395 | dma: Peri<'_, impl super::UpDma<T>>, | ||
| 396 | starting_channel: Channel, | ||
| 397 | ending_channel: Channel, | ||
| 398 | duty: &[u16], | ||
| 399 | ) { | ||
| 400 | let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32; | ||
| 401 | let start_ch_index = starting_channel.index(); | ||
| 402 | let end_ch_index = ending_channel.index(); | ||
| 403 | |||
| 404 | assert!(start_ch_index <= end_ch_index); | ||
| 405 | |||
| 406 | let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32; | ||
| 407 | self.inner | ||
| 408 | .regs_gp16() | ||
| 409 | .dcr() | ||
| 410 | .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8)); | ||
| 411 | self.inner | ||
| 412 | .regs_gp16() | ||
| 413 | .dcr() | ||
| 414 | .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8)); | ||
| 415 | |||
| 416 | #[allow(clippy::let_unit_value)] // eg. stm32f334 | ||
| 417 | let req = dma.request(); | ||
| 418 | |||
| 419 | let original_update_dma_state = self.inner.get_update_dma_state(); | ||
| 420 | if !original_update_dma_state { | ||
| 421 | self.inner.enable_update_dma(true); | ||
| 422 | } | ||
| 423 | |||
| 424 | unsafe { | ||
| 425 | #[cfg(not(any(bdma, gpdma)))] | ||
| 426 | use crate::dma::{Burst, FifoThreshold}; | ||
| 427 | use crate::dma::{Transfer, TransferOptions}; | ||
| 428 | |||
| 429 | let dma_transfer_option = TransferOptions { | ||
| 430 | #[cfg(not(any(bdma, gpdma)))] | ||
| 431 | fifo_threshold: Some(FifoThreshold::Full), | ||
| 432 | #[cfg(not(any(bdma, gpdma)))] | ||
| 433 | mburst: Burst::Incr4, | ||
| 434 | ..Default::default() | ||
| 435 | }; | ||
| 436 | |||
| 437 | Transfer::new_write( | ||
| 438 | dma, | ||
| 439 | req, | ||
| 440 | duty, | ||
| 441 | self.inner.regs_gp16().dmar().as_ptr() as *mut u16, | ||
| 442 | dma_transfer_option, | ||
| 443 | ) | ||
| 444 | .await | ||
| 445 | }; | ||
| 446 | |||
| 447 | if !original_update_dma_state { | ||
| 448 | self.inner.enable_update_dma(false); | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 384 | } | 452 | } |
| 385 | 453 | ||
| 386 | macro_rules! impl_waveform_chx { | 454 | macro_rules! impl_waveform_chx { |
