mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 14:44:32 +00:00
Merge pull request #4232 from RaulIQ/main
[embassy-stm32] add PWM multi channel waveform generation using DMA burst mode
This commit is contained in:
commit
5f3204f9c3
@ -381,6 +381,89 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
|
|||||||
self.inner.enable_update_dma(false);
|
self.inner.enable_update_dma(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
|
||||||
|
///
|
||||||
|
/// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
|
||||||
|
/// in sequence on each update event (UEV). The data is written via the DMAR register using the
|
||||||
|
/// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
|
||||||
|
///
|
||||||
|
/// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
|
||||||
|
/// represents a single update event and each column corresponds to a specific timer channel (starting
|
||||||
|
/// from `starting_channel` up to and including `ending_channel`).
|
||||||
|
///
|
||||||
|
/// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
|
||||||
|
///
|
||||||
|
/// let dma_buf: [u16; 16] = [
|
||||||
|
/// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
|
||||||
|
/// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
|
||||||
|
/// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
|
||||||
|
/// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
|
||||||
|
/// ];
|
||||||
|
///
|
||||||
|
/// Each group of N values (where N = number of channels) is transferred on one update event,
|
||||||
|
/// updating the duty cycles of all selected channels simultaneously.
|
||||||
|
///
|
||||||
|
/// Note:
|
||||||
|
/// you will need to provide corresponding TIMx_UP DMA channel to use this method.
|
||||||
|
pub async fn waveform_up_multi_channel(
|
||||||
|
&mut self,
|
||||||
|
dma: Peri<'_, impl super::UpDma<T>>,
|
||||||
|
starting_channel: Channel,
|
||||||
|
ending_channel: Channel,
|
||||||
|
duty: &[u16],
|
||||||
|
) {
|
||||||
|
let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32;
|
||||||
|
let start_ch_index = starting_channel.index();
|
||||||
|
let end_ch_index = ending_channel.index();
|
||||||
|
|
||||||
|
assert!(start_ch_index <= end_ch_index);
|
||||||
|
|
||||||
|
let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
|
||||||
|
self.inner
|
||||||
|
.regs_gp16()
|
||||||
|
.dcr()
|
||||||
|
.modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
|
||||||
|
self.inner
|
||||||
|
.regs_gp16()
|
||||||
|
.dcr()
|
||||||
|
.modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
|
||||||
|
|
||||||
|
#[allow(clippy::let_unit_value)] // eg. stm32f334
|
||||||
|
let req = dma.request();
|
||||||
|
|
||||||
|
let original_update_dma_state = self.inner.get_update_dma_state();
|
||||||
|
if !original_update_dma_state {
|
||||||
|
self.inner.enable_update_dma(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
|
use crate::dma::{Burst, FifoThreshold};
|
||||||
|
use crate::dma::{Transfer, TransferOptions};
|
||||||
|
|
||||||
|
let dma_transfer_option = TransferOptions {
|
||||||
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
|
fifo_threshold: Some(FifoThreshold::Full),
|
||||||
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
|
mburst: Burst::Incr4,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
Transfer::new_write(
|
||||||
|
dma,
|
||||||
|
req,
|
||||||
|
duty,
|
||||||
|
self.inner.regs_gp16().dmar().as_ptr() as *mut u16,
|
||||||
|
dma_transfer_option,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
};
|
||||||
|
|
||||||
|
if !original_update_dma_state {
|
||||||
|
self.inner.enable_update_dma(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_waveform_chx {
|
macro_rules! impl_waveform_chx {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user