1use core::convert::Infallible;
2use core::marker::PhantomData;
3
4use crate::gpio::IoPeriphPin;
5use crate::timer::enable_tim_clk;
6use crate::timer::regs::{EnableControl, StatusSelect};
7use crate::{PeripheralSelect, enable_peripheral_clock};
8
9use crate::time::Hertz;
10use crate::timer::{self, TimId, TimInstance, TimPin};
11
12const DUTY_MAX: u16 = u16::MAX;
13
14#[derive(Debug)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum PwmA {}
17#[derive(Debug)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19pub enum PwmB {}
20
21#[derive(Debug, thiserror::Error)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[error("pin tim ID {pin_tim:?} and timer tim id {tim_id:?} do not match")]
24pub struct TimMissmatchError {
25 pin_tim: TimId,
26 tim_id: TimId,
27}
28
29pub struct PwmPin<Mode = PwmA> {
35 tim_id: TimId,
36 regs: timer::regs::MmioTimer<'static>,
37 ref_clk: Hertz,
38 current_duty: u16,
40 current_lower_limit: u16,
42 current_period: Hertz,
43 current_rst_val: u32,
44 mode: PhantomData<Mode>,
45}
46
47impl<Mode> PwmPin<Mode> {
48 pub fn new<Pin: TimPin, Tim: TimInstance>(
50 _pin: Pin,
51 _tim: Tim,
52 #[cfg(feature = "vor1x")] sys_clk: Hertz,
53 #[cfg(feature = "vor4x")] clks: &crate::clock::Clocks,
54 initial_frequency: Hertz,
55 ) -> Result<Self, TimMissmatchError> {
56 if Pin::TIM_ID != Tim::ID {
57 return Err(TimMissmatchError {
58 pin_tim: Pin::TIM_ID,
59 tim_id: Tim::ID,
60 });
61 }
62 IoPeriphPin::new(Pin::PIN_ID, Pin::FUN_SEL, None);
63 let mut pin = PwmPin {
64 tim_id: Tim::ID,
65 regs: timer::regs::Timer::new_mmio(Tim::ID),
66 current_duty: 0,
67 current_lower_limit: 0,
68 current_period: initial_frequency,
69 current_rst_val: 0,
70 #[cfg(feature = "vor1x")]
71 ref_clk: sys_clk,
72 #[cfg(feature = "vor4x")]
73 ref_clk: clks.apb1(),
74 mode: PhantomData,
75 };
76 #[cfg(feature = "vor1x")]
79 enable_peripheral_clock(PeripheralSelect::Gpio);
80 enable_peripheral_clock(PeripheralSelect::IoConfig);
81 enable_tim_clk(Tim::ID);
82 pin.enable_pwm_a();
83 pin.set_period(initial_frequency);
84 Ok(pin)
85 }
86
87 #[inline]
88 fn enable_pwm_a(&mut self) {
89 self.regs.modify_control(|mut value| {
90 value.set_status_sel(StatusSelect::PwmaOutput);
91 value
92 });
93 }
94
95 #[inline]
96 fn enable_pwm_b(&mut self) {
97 self.regs.modify_control(|mut value| {
98 value.set_status_sel(StatusSelect::PwmbOutput);
99 value
100 });
101 }
102
103 #[inline]
104 pub fn get_period(&self) -> Hertz {
105 self.current_period
106 }
107
108 #[inline]
109 pub fn set_period(&mut self, period: impl Into<Hertz>) {
110 self.current_period = period.into();
111 if self.current_period.raw() == 0 {
113 return;
114 }
115 self.current_rst_val = self.ref_clk.raw() / self.current_period.raw();
116 self.regs.write_reset_value(self.current_rst_val);
117 }
118
119 #[inline]
120 pub fn disable(&mut self) {
121 self.regs.write_enable_control(EnableControl::new_disable());
122 }
123
124 #[inline]
125 pub fn enable(&mut self) {
126 self.regs.write_enable_control(EnableControl::new_enable());
127 }
128
129 #[inline]
130 pub fn period(&self) -> Hertz {
131 self.current_period
132 }
133
134 #[inline(always)]
135 pub fn duty(&self) -> u16 {
136 self.current_duty
137 }
138}
139
140impl From<PwmPin<PwmA>> for PwmPin<PwmB> {
141 fn from(other: PwmPin<PwmA>) -> Self {
142 let mut pwmb = Self {
143 mode: PhantomData,
144 regs: other.regs,
145 tim_id: other.tim_id,
146 ref_clk: other.ref_clk,
147 current_duty: other.current_duty,
148 current_lower_limit: other.current_lower_limit,
149 current_period: other.current_period,
150 current_rst_val: other.current_rst_val,
151 };
152 pwmb.enable_pwm_b();
153 pwmb
154 }
155}
156
157impl From<PwmPin<PwmB>> for PwmPin<PwmA> {
158 fn from(other: PwmPin<PwmB>) -> Self {
159 let mut pwmb = Self {
160 mode: PhantomData,
161 tim_id: other.tim_id,
162 regs: other.regs,
163 ref_clk: other.ref_clk,
164 current_duty: other.current_duty,
165 current_lower_limit: other.current_lower_limit,
166 current_period: other.current_period,
167 current_rst_val: other.current_rst_val,
168 };
169 pwmb.enable_pwm_a();
170 pwmb
171 }
172}
173
174impl PwmPin<PwmB> {
179 #[inline(always)]
180 pub fn pwmb_lower_limit(&self) -> u16 {
181 self.current_lower_limit
182 }
183
184 #[inline(always)]
185 pub fn pwmb_upper_limit(&self) -> u16 {
186 self.current_duty
187 }
188
189 #[inline(always)]
196 pub fn set_pwmb_lower_limit(&mut self, duty: u16) {
197 self.current_lower_limit = duty;
198 let pwmb_val: u64 =
199 (self.current_rst_val as u64 * self.current_lower_limit as u64) / DUTY_MAX as u64;
200 self.regs.write_pwmb_value(pwmb_val as u32);
201 }
202
203 pub fn set_pwmb_upper_limit(&mut self, duty: u16) {
210 self.current_duty = duty;
211 let pwma_val: u64 =
212 (self.current_rst_val as u64 * self.current_duty as u64) / DUTY_MAX as u64;
213 self.regs.write_pwma_value(pwma_val as u32);
214 }
215}
216
217impl embedded_hal::pwm::ErrorType for PwmPin {
222 type Error = Infallible;
223}
224
225impl embedded_hal::pwm::SetDutyCycle for PwmPin {
226 #[inline]
227 fn max_duty_cycle(&self) -> u16 {
228 DUTY_MAX
229 }
230
231 #[inline]
232 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
233 self.current_duty = duty;
234 let pwma_val: u64 = (self.current_rst_val as u64
235 * (DUTY_MAX as u64 - self.current_duty as u64))
236 / DUTY_MAX as u64;
237 self.regs.write_pwma_value(pwma_val as u32);
238 Ok(())
239 }
240}
241
242pub fn get_duty_from_percent(percent: f32) -> u16 {
247 if percent > 1.0 {
248 DUTY_MAX
249 } else if percent <= 0.0 {
250 0
251 } else {
252 (percent * DUTY_MAX as f32) as u16
253 }
254}