aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-05-19 14:41:44 +0000
committerGitHub <[email protected]>2023-05-19 14:41:44 +0000
commit9dff6b9d81a56966a815057c79898c178841b1cd (patch)
treedf30af461931c7d4f562af15883b7eeb6b7c076b
parent464018e12db16f5926f49cfc8c348baee07f5fa7 (diff)
parentcd88e39f5fed0ed128f57d2e166f68a488e37698 (diff)
Merge #1419
1419: stm32/pwm: improve dead-time api r=Dirbaio a=xoviat Co-authored-by: xoviat <[email protected]>
-rw-r--r--embassy-stm32/src/pwm/complementary_pwm.rs144
-rw-r--r--examples/stm32f4/src/bin/pwm_complementary.rs31
2 files changed, 142 insertions, 33 deletions
diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs
index 13edfbaa3..3f8b43cfa 100644
--- a/embassy-stm32/src/pwm/complementary_pwm.rs
+++ b/embassy-stm32/src/pwm/complementary_pwm.rs
@@ -1,7 +1,7 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy_hal_common::{into_ref, PeripheralRef}; 3use embassy_hal_common::{into_ref, PeripheralRef};
4pub use stm32_metapac::timer::vals::Ckd; 4use stm32_metapac::timer::vals::Ckd;
5 5
6use super::simple_pwm::*; 6use super::simple_pwm::*;
7use super::*; 7use super::*;
@@ -114,11 +114,145 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
114 unsafe { self.inner.set_compare_value(channel, duty) } 114 unsafe { self.inner.set_compare_value(channel, duty) }
115 } 115 }
116 116
117 pub fn set_dead_time_clock_division(&mut self, value: Ckd) { 117 /// Set the dead time as a proportion of max_duty
118 unsafe { self.inner.set_dead_time_clock_division(value) } 118 pub fn set_dead_time(&mut self, value: u16) {
119 let (ckd, value) = compute_dead_time_value(value);
120
121 unsafe {
122 self.inner.set_dead_time_clock_division(ckd);
123 self.inner.set_dead_time_value(value);
124 }
125 }
126}
127
128fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
129 /*
130 Dead-time = T_clk * T_dts * T_dtg
131
132 T_dts:
133 This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the
134 dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters
135 (ETR, TIx),
136 00: tDTS=tCK_INT
137 01: tDTS=2*tCK_INT
138 10: tDTS=4*tCK_INT
139
140 T_dtg:
141 This bit-field defines the duration of the dead-time inserted between the complementary
142 outputs. DT correspond to this duration.
143 DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS.
144 DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS.
145 DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS.
146 DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS.
147 Example if TDTS=125ns (8MHz), dead-time possible values are:
148 0 to 15875 ns by 125 ns steps,
149 16 us to 31750 ns by 250 ns steps,
150 32 us to 63us by 1 us steps,
151 64 us to 126 us by 2 us steps
152 */
153
154 let mut error = u16::MAX;
155 let mut ckd = Ckd::DIV1;
156 let mut bits = 0u8;
157
158 for this_ckd in [Ckd::DIV1, Ckd::DIV2, Ckd::DIV4] {
159 let outdiv = match this_ckd {
160 Ckd::DIV1 => 1,
161 Ckd::DIV2 => 2,
162 Ckd::DIV4 => 4,
163 _ => unreachable!(),
164 };
165
166 // 127
167 // 128
168 // ..
169 // 254
170 // 256
171 // ..
172 // 504
173 // 512
174 // ..
175 // 1008
176
177 let target = value / outdiv;
178 let (these_bits, result) = if target < 128 {
179 (target as u8, target)
180 } else if target < 255 {
181 (64 + (target / 2) as u8, (target - target % 2))
182 } else if target < 508 {
183 (32 + (target / 8) as u8, (target - target % 8))
184 } else if target < 1008 {
185 (32 + (target / 16) as u8, (target - target % 16))
186 } else {
187 (u8::MAX, 1008)
188 };
189
190 let this_error = value.abs_diff(result * outdiv);
191 if error > this_error {
192 ckd = this_ckd;
193 bits = these_bits;
194 error = this_error;
195 }
196
197 match error {
198 0 => break,
199 _ => {}
200 }
119 } 201 }
120 202
121 pub fn set_dead_time_value(&mut self, value: u8) { 203 (ckd, bits)
122 unsafe { self.inner.set_dead_time_value(value) } 204}
205
206#[cfg(test)]
207mod tests {
208 use super::{compute_dead_time_value, Ckd};
209
210 #[test]
211 fn test_compute_dead_time_value() {
212 struct test_run {
213 value: u16,
214 ckd: Ckd,
215 bits: u8,
216 }
217
218 let fn_results = [
219 test_run {
220 value: 1,
221 ckd: Ckd::DIV1,
222 bits: 1,
223 },
224 test_run {
225 value: 125,
226 ckd: Ckd::DIV1,
227 bits: 125,
228 },
229 test_run {
230 value: 245,
231 ckd: Ckd::DIV1,
232 bits: 64 + 245 / 2,
233 },
234 test_run {
235 value: 255,
236 ckd: Ckd::DIV2,
237 bits: 127,
238 },
239 test_run {
240 value: 400,
241 ckd: Ckd::DIV1,
242 bits: 32 + (400u16 / 8) as u8,
243 },
244 test_run {
245 value: 600,
246 ckd: Ckd::DIV4,
247 bits: 64 + (600u16 / 8) as u8,
248 },
249 ];
250
251 for test_run in fn_results {
252 let (ckd, bits) = compute_dead_time_value(test_run.value);
253
254 assert_eq!(ckd.0, test_run.ckd.0);
255 assert_eq!(bits, test_run.bits);
256 }
123 } 257 }
124} 258}
diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs
index 6e17f3fd3..a8a68ed6e 100644
--- a/examples/stm32f4/src/bin/pwm_complementary.rs
+++ b/examples/stm32f4/src/bin/pwm_complementary.rs
@@ -4,7 +4,7 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::pwm::complementary_pwm::{Ckd, ComplementaryPwm, ComplementaryPwmPin}; 7use embassy_stm32::pwm::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
8use embassy_stm32::pwm::simple_pwm::PwmPin; 8use embassy_stm32::pwm::simple_pwm::PwmPin;
9use embassy_stm32::pwm::Channel; 9use embassy_stm32::pwm::Channel;
10use embassy_stm32::time::khz; 10use embassy_stm32::time::khz;
@@ -31,34 +31,9 @@ async fn main(_spawner: Spawner) {
31 khz(10), 31 khz(10),
32 ); 32 );
33 33
34 /*
35 Dead-time = T_clk * T_dts * T_dtg
36
37 T_dts:
38 This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the
39 dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters
40 (ETR, TIx),
41 00: tDTS=tCK_INT
42 01: tDTS=2*tCK_INT
43 10: tDTS=4*tCK_INT
44
45 T_dtg:
46 This bit-field defines the duration of the dead-time inserted between the complementary
47 outputs. DT correspond to this duration.
48 DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS.
49 DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS.
50 DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS.
51 DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS.
52 Example if TDTS=125ns (8MHz), dead-time possible values are:
53 0 to 15875 ns by 125 ns steps,
54 16 us to 31750 ns by 250 ns steps,
55 32 us to 63us by 1 us steps,
56 64 us to 126 us by 2 us steps
57 */
58 pwm.set_dead_time_clock_division(Ckd::DIV1);
59 pwm.set_dead_time_value(0);
60
61 let max = pwm.get_max_duty(); 34 let max = pwm.get_max_duty();
35 pwm.set_dead_time(max / 1024);
36
62 pwm.enable(Channel::Ch1); 37 pwm.enable(Channel::Ch1);
63 38
64 info!("PWM initialized"); 39 info!("PWM initialized");