aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreZio Pan <[email protected]>2024-01-02 13:30:13 +0800
committereZio Pan <[email protected]>2024-01-02 14:01:09 +0800
commitc276da5fcb93ce20da0c2f3bfccdeb7e0fee67a7 (patch)
tree2da944cf42dedda8c15a186ec725a49a0025dc03
parentf5a218a018d3ecd899db0ec5460a4e00dac78abe (diff)
ask a DMA Channel only when use .gen_waveform()
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs78
-rw-r--r--examples/stm32f4/src/bin/pwm.rs12
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs6
-rw-r--r--examples/stm32g4/src/bin/pwm.rs12
-rw-r--r--examples/stm32h7/src/bin/pwm.rs13
5 files changed, 35 insertions, 86 deletions
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 7a5475c31..77d902e35 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -55,19 +55,12 @@ channel_impl!(new_ch3, Ch3, Channel3Pin);
55channel_impl!(new_ch4, Ch4, Channel4Pin); 55channel_impl!(new_ch4, Ch4, Channel4Pin);
56 56
57/// Simple PWM driver. 57/// Simple PWM driver.
58pub struct SimplePwm<'d, T, Dma> { 58pub struct SimplePwm<'d, T> {
59 inner: PeripheralRef<'d, T>, 59 inner: PeripheralRef<'d, T>,
60 dma: PeripheralRef<'d, Dma>,
61} 60}
62 61
63impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> { 62impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
64 /// Create a new simple PWM driver. 63 /// Create a new simple PWM driver.
65 ///
66 /// Note:
67 /// If you want to use [`Self::gen_waveform()`], you need to provide corresponding TIMx_UP DMA channel.
68 /// Otherwise you can just put a [`dma::NoDma`](crate::dma::NoDma)
69 /// Currently, you can only use one channel at a time to generate waveform with [`Self::gen_waveform()`].
70 /// But you can always use multiple TIM to generate multiple waveform simultaneously.
71 pub fn new( 64 pub fn new(
72 tim: impl Peripheral<P = T> + 'd, 65 tim: impl Peripheral<P = T> + 'd,
73 _ch1: Option<PwmPin<'d, T, Ch1>>, 66 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -76,22 +69,16 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> {
76 _ch4: Option<PwmPin<'d, T, Ch4>>, 69 _ch4: Option<PwmPin<'d, T, Ch4>>,
77 freq: Hertz, 70 freq: Hertz,
78 counting_mode: CountingMode, 71 counting_mode: CountingMode,
79 dma: impl Peripheral<P = Dma> + 'd,
80 ) -> Self { 72 ) -> Self {
81 Self::new_inner(tim, freq, counting_mode, dma) 73 Self::new_inner(tim, freq, counting_mode)
82 } 74 }
83 75
84 fn new_inner( 76 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
85 tim: impl Peripheral<P = T> + 'd, 77 into_ref!(tim);
86 freq: Hertz,
87 counting_mode: CountingMode,
88 dma: impl Peripheral<P = Dma> + 'd,
89 ) -> Self {
90 into_ref!(tim, dma);
91 78
92 T::enable_and_reset(); 79 T::enable_and_reset();
93 80
94 let mut this = Self { inner: tim, dma }; 81 let mut this = Self { inner: tim };
95 82
96 this.inner.set_counting_mode(counting_mode); 83 this.inner.set_counting_mode(counting_mode);
97 this.set_frequency(freq); 84 this.set_frequency(freq);
@@ -165,32 +152,23 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> {
165 } 152 }
166} 153}
167 154
168impl<'d, T: CaptureCompare16bitInstance + Basic16bitInstance, Dma> SimplePwm<'d, T, Dma> 155impl<'d, T: CaptureCompare16bitInstance + Basic16bitInstance> SimplePwm<'d, T> {
169where
170 Dma: super::UpDma<T>,
171{
172 /// Generate a sequence of PWM waveform 156 /// Generate a sequence of PWM waveform
173 pub async fn gen_waveform(&mut self, channel: Channel, duty: &[u16]) { 157 ///
158 /// Note:
159 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
160 pub async fn gen_waveform(
161 &mut self,
162 dma: impl Peripheral<P = impl super::UpDma<T>>,
163 channel: Channel,
164 duty: &[u16],
165 ) {
174 assert!(duty.iter().all(|v| *v <= self.get_max_duty())); 166 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
175 167
176 #[cfg_attr(any(stm32f334, stm32f378), allow(clippy::let_unit_value))] 168 into_ref!(dma);
177 let req = self.dma.request();
178
179 #[cfg(not(any(bdma, gpdma)))]
180 let (isr_bit, isr_reg, ifcr_reg) = {
181 let dma_regs = self.dma.regs();
182 let isr_num = self.dma.num() / 4;
183 let isr_bit = self.dma.num() % 4;
184 let isr_reg = dma_regs.isr(isr_num);
185 let ifcr_reg = dma_regs.ifcr(isr_num);
186 (isr_bit, isr_reg, ifcr_reg)
187 };
188 169
189 #[cfg(not(any(bdma, gpdma)))] 170 #[allow(clippy::let_unit_value)] // eg. stm32f334
190 // clean DMA FIFO error before a transfer 171 let req = dma.request();
191 if isr_reg.read().feif(isr_bit) {
192 ifcr_reg.write(|v| v.set_feif(isr_bit, true));
193 }
194 172
195 let original_duty_state = self.get_duty(channel); 173 let original_duty_state = self.get_duty(channel);
196 let original_enable_state = self.is_enabled(channel); 174 let original_enable_state = self.is_enabled(channel);
@@ -218,7 +196,7 @@ where
218 }; 196 };
219 197
220 Transfer::new_write( 198 Transfer::new_write(
221 &mut self.dma, 199 &mut dma,
222 req, 200 req,
223 duty, 201 duty,
224 T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _, 202 T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _,
@@ -231,21 +209,21 @@ where
231 if !original_enable_state { 209 if !original_enable_state {
232 self.disable(channel); 210 self.disable(channel);
233 } 211 }
212
234 self.set_duty(channel, original_duty_state); 213 self.set_duty(channel, original_duty_state);
214
215 // Since DMA is closed before timer update event trigger DMA is turn off,
216 // this can almost always trigger a DMA FIFO error.
217 //
218 // optional TODO:
219 // clean FEIF after disable UDE
235 if !original_update_dma_state { 220 if !original_update_dma_state {
236 self.inner.enable_update_dma(false); 221 self.inner.enable_update_dma(false);
237
238 #[cfg(not(any(bdma, gpdma)))]
239 // Since DMA could be closed before timer update event trigger DMA is turn off, this can almost always trigger a DMA FIFO error.
240 // Thus, we will try clean DMA FEIF after each transfer
241 if isr_reg.read().feif(isr_bit) {
242 ifcr_reg.write(|v| v.set_feif(isr_bit, true));
243 }
244 } 222 }
245 } 223 }
246} 224}
247 225
248impl<'d, T: CaptureCompare16bitInstance, Dma> embedded_hal_02::Pwm for SimplePwm<'d, T, Dma> { 226impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> {
249 type Channel = Channel; 227 type Channel = Channel;
250 type Time = Hertz; 228 type Time = Hertz;
251 type Duty = u16; 229 type Duty = u16;
diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs
index 92bc42ec8..8844a9f0e 100644
--- a/examples/stm32f4/src/bin/pwm.rs
+++ b/examples/stm32f4/src/bin/pwm.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma;
7use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
8use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
9use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
@@ -17,16 +16,7 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 16 info!("Hello World!");
18 17
19 let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull); 18 let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull);
20 let mut pwm = SimplePwm::new( 19 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default());
21 p.TIM1,
22 Some(ch1),
23 None,
24 None,
25 None,
26 khz(10),
27 Default::default(),
28 dma::NoDma,
29 );
30 let max = pwm.get_max_duty(); 20 let max = pwm.get_max_duty();
31 pwm.enable(Channel::Ch1); 21 pwm.enable(Channel::Ch1);
32 22
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index 93a89f16a..239709253 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) {
45 device_config.rcc.sys = Sysclk::PLL1_P; 45 device_config.rcc.sys = Sysclk::PLL1_P;
46 } 46 }
47 47
48 let dp = embassy_stm32::init(device_config); 48 let mut dp = embassy_stm32::init(device_config);
49 49
50 let mut ws2812_pwm = SimplePwm::new( 50 let mut ws2812_pwm = SimplePwm::new(
51 dp.TIM3, 51 dp.TIM3,
@@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) {
55 None, 55 None,
56 khz(800), // data rate of ws2812 56 khz(800), // data rate of ws2812
57 CountingMode::EdgeAlignedUp, 57 CountingMode::EdgeAlignedUp,
58 dp.DMA1_CH2,
59 ); 58 );
60 59
61 // construct ws2812 non-return-to-zero (NRZ) code bit by bit 60 // construct ws2812 non-return-to-zero (NRZ) code bit by bit
@@ -91,7 +90,8 @@ async fn main(_spawner: Spawner) {
91 90
92 loop { 91 loop {
93 for &color in color_list { 92 for &color in color_list {
94 ws2812_pwm.gen_waveform(pwm_channel, color).await; 93 // with &mut, we can easily reuse same DMA channel multiple times
94 ws2812_pwm.gen_waveform(&mut dp.DMA1_CH2, pwm_channel, color).await;
95 // ws2812 need at least 50 us low level input to confirm the input data and change it's state 95 // ws2812 need at least 50 us low level input to confirm the input data and change it's state
96 Timer::after_micros(50).await; 96 Timer::after_micros(50).await;
97 // wait until ticker tick 97 // wait until ticker tick
diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs
index 9fa004c3e..d4809a481 100644
--- a/examples/stm32g4/src/bin/pwm.rs
+++ b/examples/stm32g4/src/bin/pwm.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma;
7use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
8use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
9use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
@@ -17,16 +16,7 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 16 info!("Hello World!");
18 17
19 let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull); 18 let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull);
20 let mut pwm = SimplePwm::new( 19 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default());
21 p.TIM1,
22 Some(ch1),
23 None,
24 None,
25 None,
26 khz(10),
27 Default::default(),
28 dma::NoDma,
29 );
30 let max = pwm.get_max_duty(); 20 let max = pwm.get_max_duty();
31 pwm.enable(Channel::Ch1); 21 pwm.enable(Channel::Ch1);
32 22
diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs
index de155fc94..1e48ba67b 100644
--- a/examples/stm32h7/src/bin/pwm.rs
+++ b/examples/stm32h7/src/bin/pwm.rs
@@ -7,7 +7,7 @@ use embassy_stm32::gpio::OutputType;
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 8use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
9use embassy_stm32::timer::Channel; 9use embassy_stm32::timer::Channel;
10use embassy_stm32::{dma, Config}; 10use embassy_stm32::Config;
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
@@ -38,16 +38,7 @@ async fn main(_spawner: Spawner) {
38 info!("Hello World!"); 38 info!("Hello World!");
39 39
40 let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull); 40 let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull);
41 let mut pwm = SimplePwm::new( 41 let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10), Default::default());
42 p.TIM3,
43 Some(ch1),
44 None,
45 None,
46 None,
47 khz(10),
48 Default::default(),
49 dma::NoDma,
50 );
51 let max = pwm.get_max_duty(); 42 let max = pwm.get_max_duty();
52 pwm.enable(Channel::Ch1); 43 pwm.enable(Channel::Ch1);
53 44