aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer
diff options
context:
space:
mode:
authoreZio Pan <[email protected]>2024-01-06 22:22:38 +0800
committereZio Pan <[email protected]>2024-01-06 22:22:38 +0800
commit424ddaf3d95417bcfe8b46475c8135aead3792d2 (patch)
treec7da31ded7549d103e5b557f057c666afb795a89 /embassy-stm32/src/timer
parent294046cddbdd485a99f7531c29af92c326124123 (diff)
impl waveform with TIM Channel
Diffstat (limited to 'embassy-stm32/src/timer')
-rw-r--r--embassy-stm32/src/timer/mod.rs25
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs90
2 files changed, 114 insertions, 1 deletions
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index d07fd2776..957098cde 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -311,6 +311,26 @@ pub(crate) mod sealed {
311 .ccmr_output(channel_index / 2) 311 .ccmr_output(channel_index / 2)
312 .modify(|w| w.set_ocpe(channel_index % 2, preload)); 312 .modify(|w| w.set_ocpe(channel_index % 2, preload));
313 } 313 }
314
315 /// Get capture compare DMA selection
316 fn get_cc_dma_selection(&self) -> super::vals::Ccds {
317 Self::regs_gp16().cr2().read().ccds()
318 }
319
320 /// Set capture compare DMA selection
321 fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) {
322 Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
323 }
324
325 /// Get capture compare DMA enable state
326 fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
327 Self::regs_gp16().dier().read().ccde(channel.index())
328 }
329
330 /// Set capture compare DMA enable state
331 fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) {
332 Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
333 }
314 } 334 }
315 335
316 /// Capture/Compare 16-bit timer instance with complementary pin support. 336 /// Capture/Compare 16-bit timer instance with complementary pin support.
@@ -705,3 +725,8 @@ foreach_interrupt! {
705 725
706// Update Event trigger DMA for every timer 726// Update Event trigger DMA for every timer
707dma_trait!(UpDma, Basic16bitInstance); 727dma_trait!(UpDma, Basic16bitInstance);
728
729dma_trait!(Ch1Dma, CaptureCompare16bitInstance);
730dma_trait!(Ch2Dma, CaptureCompare16bitInstance);
731dma_trait!(Ch3Dma, CaptureCompare16bitInstance);
732dma_trait!(Ch4Dma, CaptureCompare16bitInstance);
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 80f10424c..665557354 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -155,7 +155,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
155 /// 155 ///
156 /// Note: 156 /// Note:
157 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 157 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
158 pub async fn gen_waveform( 158 pub async fn waveform_up(
159 &mut self, 159 &mut self,
160 dma: impl Peripheral<P = impl super::UpDma<T>>, 160 dma: impl Peripheral<P = impl super::UpDma<T>>,
161 channel: Channel, 161 channel: Channel,
@@ -221,6 +221,94 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
221 } 221 }
222} 222}
223 223
224macro_rules! impl_waveform_chx {
225 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
226 impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
227 /// Generate a sequence of PWM waveform
228 ///
229 /// Note:
230 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
231 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
232 use super::vals::Ccds;
233
234 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
235
236 into_ref!(dma);
237
238 #[allow(clippy::let_unit_value)] // eg. stm32f334
239 let req = dma.request();
240
241 let cc_channel = super::Channel::$cc_ch;
242
243 let original_duty_state = self.get_duty(cc_channel);
244 let original_enable_state = self.is_enabled(cc_channel);
245 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE;
246 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
247
248 if original_cc_dma_on_update {
249 self.inner.set_cc_dma_selection(Ccds::ONUPDATE)
250 }
251
252 if !original_cc_dma_enabled {
253 self.inner.set_cc_dma_enable_state(cc_channel, true);
254 }
255
256 if !original_enable_state {
257 self.enable(cc_channel);
258 }
259
260 unsafe {
261 #[cfg(not(any(bdma, gpdma)))]
262 use crate::dma::{Burst, FifoThreshold};
263 use crate::dma::{Transfer, TransferOptions};
264
265 let dma_transfer_option = TransferOptions {
266 #[cfg(not(any(bdma, gpdma)))]
267 fifo_threshold: Some(FifoThreshold::Full),
268 #[cfg(not(any(bdma, gpdma)))]
269 mburst: Burst::Incr8,
270 ..Default::default()
271 };
272
273 Transfer::new_write(
274 &mut dma,
275 req,
276 duty,
277 T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _,
278 dma_transfer_option,
279 )
280 .await
281 };
282
283 // restore output compare state
284 if !original_enable_state {
285 self.disable(cc_channel);
286 }
287
288 self.set_duty(cc_channel, original_duty_state);
289
290 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
291 // this can almost always trigger a DMA FIFO error.
292 //
293 // optional TODO:
294 // clean FEIF after disable UDE
295 if !original_cc_dma_enabled {
296 self.inner.set_cc_dma_enable_state(cc_channel, false);
297 }
298
299 if !original_cc_dma_on_update {
300 self.inner.set_cc_dma_selection(Ccds::ONCOMPARE)
301 }
302 }
303 }
304 };
305}
306
307impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1);
308impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
309impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
310impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
311
224impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { 312impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> {
225 type Channel = Channel; 313 type Channel = Channel;
226 type Time = Hertz; 314 type Time = Hertz;