aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer/complementary_pwm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/timer/complementary_pwm.rs')
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs108
1 files changed, 52 insertions, 56 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 9a56a41fb..77f19a37b 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -77,8 +77,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
77 77
78 this.inner.set_counting_mode(counting_mode); 78 this.inner.set_counting_mode(counting_mode);
79 this.set_frequency(freq); 79 this.set_frequency(freq);
80 this.inner.start();
81
82 this.inner.enable_outputs(); 80 this.inner.enable_outputs();
83 81
84 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 82 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
@@ -89,6 +87,10 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
89 }); 87 });
90 this.inner.set_autoreload_preload(true); 88 this.inner.set_autoreload_preload(true);
91 89
90 // Generate update event so pre-load registers are written to the shadow registers
91 this.inner.generate_update_event();
92 this.inner.start();
93
92 this 94 this
93 } 95 }
94 96
@@ -160,8 +162,8 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
160 162
161 /// Set PWM frequency. 163 /// Set PWM frequency.
162 /// 164 ///
163 /// Note: when you call this, the max duty value changes, so you will have to 165 /// Note: that the frequency will not be applied in the timer until an update event
164 /// call `set_duty` on all channels with the duty calculated based on the new max duty. 166 /// occurs.
165 pub fn set_frequency(&mut self, freq: Hertz) { 167 pub fn set_frequency(&mut self, freq: Hertz) {
166 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 168 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
167 2u8 169 2u8
@@ -219,59 +221,53 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
219 /// Note: 221 /// Note:
220 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 222 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
221 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 223 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
222 #[allow(clippy::let_unit_value)] // eg. stm32f334 224 self.inner.enable_channel(channel, true);
223 let req = dma.request(); 225 self.inner.enable_update_dma(true);
224 226 self.inner.setup_update_dma(dma, channel, duty).await;
225 let original_duty_state = self.inner.get_compare_value(channel); 227 self.inner.enable_update_dma(false);
226 let original_enable_state = self.inner.get_channel_enable_state(channel); 228 }
227 let original_update_dma_state = self.inner.get_update_dma_state();
228
229 if !original_update_dma_state {
230 self.inner.enable_update_dma(true);
231 }
232
233 if !original_enable_state {
234 self.inner.enable_channel(channel, true);
235 }
236
237 unsafe {
238 #[cfg(not(any(bdma, gpdma)))]
239 use crate::dma::{Burst, FifoThreshold};
240 use crate::dma::{Transfer, TransferOptions};
241
242 let dma_transfer_option = TransferOptions {
243 #[cfg(not(any(bdma, gpdma)))]
244 fifo_threshold: Some(FifoThreshold::Full),
245 #[cfg(not(any(bdma, gpdma)))]
246 mburst: Burst::Incr8,
247 ..Default::default()
248 };
249
250 Transfer::new_write(
251 dma,
252 req,
253 duty,
254 self.inner.regs_gp16().ccr(channel.index()).as_ptr() as *mut u16,
255 dma_transfer_option,
256 )
257 .await
258 };
259
260 // restore output compare state
261 if !original_enable_state {
262 self.inner.enable_channel(channel, false);
263 }
264
265 self.inner.set_compare_value(channel, original_duty_state);
266 229
267 // Since DMA is closed before timer update event trigger DMA is turn off, 230 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
268 // this can almost always trigger a DMA FIFO error. 231 ///
269 // 232 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
270 // optional TODO: 233 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
271 // clean FEIF after disable UDE 234 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
272 if !original_update_dma_state { 235 ///
273 self.inner.enable_update_dma(false); 236 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
274 } 237 /// represents a single update event and each column corresponds to a specific timer channel (starting
238 /// from `starting_channel` up to and including `ending_channel`).
239 ///
240 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
241 ///
242 /// ```rust,ignore
243 /// let dma_buf: [u16; 16] = [
244 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
245 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
246 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
247 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
248 /// ];
249 /// ```
250 ///
251 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
252 /// updating the duty cycles of all selected channels simultaneously.
253 ///
254 /// Note:
255 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
256 /// Also be aware that embassy timers use one of timers internally. It is possible to
257 /// switch this timer by using `time-driver-timX` feature.
258 ///
259 pub async fn waveform_up_multi_channel(
260 &mut self,
261 dma: Peri<'_, impl super::UpDma<T>>,
262 starting_channel: Channel,
263 ending_channel: Channel,
264 duty: &[u16],
265 ) {
266 self.inner.enable_update_dma(true);
267 self.inner
268 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
269 .await;
270 self.inner.enable_update_dma(false);
275 } 271 }
276} 272}
277 273