1use core::convert::Infallible;
2use core::marker::PhantomData;
3
4use crate::gpio::{DynPinId, IoPeriphPin};
5use crate::timer::enable_tim_clk;
6use crate::timer::regs::{EnableControl, StatusSelect};
7use crate::{FunctionSelect, PeripheralSelect, enable_peripheral_clock};
8
9use crate::time::Hertz;
10use crate::timer::{self, TimId};
11use crate::timer::{
12 Tim0Instance, Tim0Pin, Tim1Instance, Tim1Pin, Tim2Instance, Tim2Pin, Tim3Instance, Tim3Pin,
13 Tim4Instance, Tim4Pin, Tim5Instance, Tim5Pin, Tim6Instance, Tim6Pin, Tim7Instance, Tim7Pin,
14 Tim8Instance, Tim8Pin, Tim9Instance, Tim9Pin, Tim10Instance, Tim10Pin, Tim11Instance, Tim11Pin,
15 Tim12Instance, Tim12Pin, Tim13Instance, Tim13Pin, Tim14Instance, Tim14Pin, Tim15Instance,
16 Tim15Pin, Tim16Instance, Tim16Pin, Tim17Instance, Tim17Pin, Tim18Instance, Tim18Pin,
17 Tim19Instance, Tim19Pin, Tim20Instance, Tim20Pin, Tim21Instance, Tim21Pin, Tim22Instance,
18 Tim22Pin, Tim23Instance, Tim23Pin,
19};
20
21const DUTY_MAX: u16 = u16::MAX;
22
23#[derive(Debug)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum PwmA {}
26#[derive(Debug)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub enum PwmB {}
29
30pub struct PwmPin<Mode = PwmA> {
36 tim_id: TimId,
37 regs: timer::regs::MmioTimer<'static>,
38 ref_clk: Hertz,
39 current_duty: u16,
41 current_lower_limit: u16,
43 current_period: Hertz,
44 current_rst_val: u32,
45 mode: PhantomData<Mode>,
46}
47
48macro_rules! impl_pwm_new_methods {
49 (
50 $(
51 ($tim_name:ident, $pin_trait:ident, $instance_trait:ident)
52 ),*
53 $(,)?
54 ) => {
55 paste::paste! {
56 $(
57 #[doc = concat!("Create a new PWM pin using ", stringify!($tim_name))]
58 pub fn [<new_with_ $tim_name:lower>] <Pin: $pin_trait, Tim: $instance_trait>(
59 _pin: Pin,
60 _tim: Tim,
61 #[cfg(feature = "vor1x")] sys_clk: Hertz,
62 #[cfg(feature = "vor4x")] clks: &crate::clock::Clocks,
63 initial_frequency: Hertz,
64 ) -> Self {
65 Self::new(
66 Pin::PIN_ID,
67 Pin::FUNC_SEL,
68 Tim::ID,
69 #[cfg(feature = "vor1x")]
70 sys_clk,
71 #[cfg(feature = "vor4x")]
72 clks,
73 initial_frequency,
74 )
75 }
76 )*
77 }
78 };
79}
80
81impl<Mode> PwmPin<Mode> {
82 impl_pwm_new_methods! {
83 (Tim0, Tim0Pin, Tim0Instance),
84 (Tim1, Tim1Pin, Tim1Instance),
85 (Tim2, Tim2Pin, Tim2Instance),
86 (Tim3, Tim3Pin, Tim3Instance),
87 (Tim4, Tim4Pin, Tim4Instance),
88 (Tim5, Tim5Pin, Tim5Instance),
89 (Tim6, Tim6Pin, Tim6Instance),
90 (Tim7, Tim7Pin, Tim7Instance),
91 (Tim8, Tim8Pin, Tim8Instance),
92 (Tim9, Tim9Pin, Tim9Instance),
93 (Tim10, Tim10Pin, Tim10Instance),
94 (Tim11, Tim11Pin, Tim11Instance),
95 (Tim12, Tim12Pin, Tim12Instance),
96 (Tim13, Tim13Pin, Tim13Instance),
97 (Tim14, Tim14Pin, Tim14Instance),
98 (Tim15, Tim15Pin, Tim15Instance),
99 (Tim16, Tim16Pin, Tim16Instance),
100 (Tim17, Tim17Pin, Tim17Instance),
101 (Tim18, Tim18Pin, Tim18Instance),
102 (Tim19, Tim19Pin, Tim19Instance),
103 (Tim20, Tim20Pin, Tim20Instance),
104 (Tim21, Tim21Pin, Tim21Instance),
105 (Tim22, Tim22Pin, Tim22Instance),
106 (Tim23, Tim23Pin, Tim23Instance),
107 }
108
109 fn new(
110 pin_id: DynPinId,
111 func_sel: FunctionSelect,
112 tim_id: TimId,
113 #[cfg(feature = "vor1x")] sys_clk: Hertz,
114 #[cfg(feature = "vor4x")] clks: &crate::clock::Clocks,
115 initial_frequency: Hertz,
116 ) -> Self {
117 IoPeriphPin::new(pin_id, func_sel, None);
118 let mut pin = PwmPin {
119 tim_id,
120 regs: timer::regs::Timer::new_mmio(tim_id),
121 current_duty: 0,
122 current_lower_limit: 0,
123 current_period: initial_frequency,
124 current_rst_val: 0,
125 #[cfg(feature = "vor1x")]
126 ref_clk: sys_clk,
127 #[cfg(feature = "vor4x")]
128 ref_clk: clks.apb1(),
129 mode: PhantomData,
130 };
131 #[cfg(feature = "vor1x")]
134 enable_peripheral_clock(PeripheralSelect::Gpio);
135 enable_peripheral_clock(PeripheralSelect::IoConfig);
136 enable_tim_clk(tim_id);
137 pin.enable_pwm_a();
138 pin.set_period(initial_frequency);
139 pin
140 }
141
142 #[inline]
143 fn enable_pwm_a(&mut self) {
144 self.regs.modify_control(|mut value| {
145 value.set_status_sel(StatusSelect::PwmaOutput);
146 value
147 });
148 }
149
150 #[inline]
151 fn enable_pwm_b(&mut self) {
152 self.regs.modify_control(|mut value| {
153 value.set_status_sel(StatusSelect::PwmbOutput);
154 value
155 });
156 }
157
158 #[inline]
159 pub fn get_period(&self) -> Hertz {
160 self.current_period
161 }
162
163 #[inline]
164 pub fn set_period(&mut self, period: impl Into<Hertz>) {
165 self.current_period = period.into();
166 if self.current_period.to_raw() == 0 {
168 return;
169 }
170 self.current_rst_val = self.ref_clk.to_raw() / self.current_period.to_raw();
171 self.regs.write_reset_value(self.current_rst_val);
172 }
173
174 #[inline]
175 pub fn disable(&mut self) {
176 self.regs.write_enable_control(EnableControl::new_disable());
177 }
178
179 #[inline]
180 pub fn enable(&mut self) {
181 self.regs.write_enable_control(EnableControl::new_enable());
182 }
183
184 #[inline]
185 pub fn period(&self) -> Hertz {
186 self.current_period
187 }
188
189 #[inline(always)]
190 pub fn duty(&self) -> u16 {
191 self.current_duty
192 }
193}
194
195impl From<PwmPin<PwmA>> for PwmPin<PwmB> {
196 fn from(other: PwmPin<PwmA>) -> Self {
197 let mut pwmb = Self {
198 mode: PhantomData,
199 regs: other.regs,
200 tim_id: other.tim_id,
201 ref_clk: other.ref_clk,
202 current_duty: other.current_duty,
203 current_lower_limit: other.current_lower_limit,
204 current_period: other.current_period,
205 current_rst_val: other.current_rst_val,
206 };
207 pwmb.enable_pwm_b();
208 pwmb
209 }
210}
211
212impl From<PwmPin<PwmB>> for PwmPin<PwmA> {
213 fn from(other: PwmPin<PwmB>) -> Self {
214 let mut pwmb = Self {
215 mode: PhantomData,
216 tim_id: other.tim_id,
217 regs: other.regs,
218 ref_clk: other.ref_clk,
219 current_duty: other.current_duty,
220 current_lower_limit: other.current_lower_limit,
221 current_period: other.current_period,
222 current_rst_val: other.current_rst_val,
223 };
224 pwmb.enable_pwm_a();
225 pwmb
226 }
227}
228
229impl PwmPin<PwmB> {
234 #[inline(always)]
235 pub fn pwmb_lower_limit(&self) -> u16 {
236 self.current_lower_limit
237 }
238
239 #[inline(always)]
240 pub fn pwmb_upper_limit(&self) -> u16 {
241 self.current_duty
242 }
243
244 #[inline(always)]
251 pub fn set_pwmb_lower_limit(&mut self, duty: u16) {
252 self.current_lower_limit = duty;
253 let pwmb_val: u64 =
254 (self.current_rst_val as u64 * self.current_lower_limit as u64) / DUTY_MAX as u64;
255 self.regs.write_pwmb_value(pwmb_val as u32);
256 }
257
258 pub fn set_pwmb_upper_limit(&mut self, duty: u16) {
265 self.current_duty = duty;
266 let pwma_val: u64 =
267 (self.current_rst_val as u64 * self.current_duty as u64) / DUTY_MAX as u64;
268 self.regs.write_pwma_value(pwma_val as u32);
269 }
270}
271
272impl embedded_hal::pwm::ErrorType for PwmPin {
277 type Error = Infallible;
278}
279
280impl embedded_hal::pwm::SetDutyCycle for PwmPin {
281 #[inline]
282 fn max_duty_cycle(&self) -> u16 {
283 DUTY_MAX
284 }
285
286 #[inline]
287 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
288 self.current_duty = duty;
289 let pwma_val: u64 = (self.current_rst_val as u64
290 * (DUTY_MAX as u64 - self.current_duty as u64))
291 / DUTY_MAX as u64;
292 self.regs.write_pwma_value(pwma_val as u32);
293 Ok(())
294 }
295}
296
297pub fn get_duty_from_percent(percent: f32) -> u16 {
302 if percent > 1.0 {
303 DUTY_MAX
304 } else if percent <= 0.0 {
305 0
306 } else {
307 (percent * DUTY_MAX as f32) as u16
308 }
309}