1use super::{
13 low_level,
14 timer::{TimerIFace, TimerSpeed},
15};
16use crate::{
17 gpio::{
18 DriveMode,
19 OutputConfig,
20 interconnect::{self, PeripheralOutput},
21 },
22 pac::ledc::RegisterBlock,
23 peripherals::LEDC,
24};
25
26#[derive(Debug, Clone, Copy, PartialEq)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub enum FadeError {
30 StartDuty,
32 EndDuty,
34 DutyRange,
36 Duration,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub enum Error {
44 Duty,
46 Timer,
48 Channel,
50 Fade(FadeError),
52}
53
54#[derive(PartialEq, Eq, Copy, Clone, Debug)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57pub enum Number {
58 Channel0 = 0,
60 Channel1 = 1,
62 Channel2 = 2,
64 Channel3 = 3,
66 Channel4 = 4,
68 Channel5 = 5,
70 #[cfg(ledc_channel_count = "8")]
71 Channel6 = 6,
73 #[cfg(ledc_channel_count = "8")]
74 Channel7 = 7,
76}
77
78pub mod config {
80 use crate::{
81 gpio::DriveMode,
82 ledc::timer::{TimerIFace, TimerSpeed},
83 };
84
85 #[derive(Copy, Clone)]
87 pub struct Config<'a, S: TimerSpeed> {
88 pub timer: &'a dyn TimerIFace<S>,
90 pub duty_pct: u8,
92 pub drive_mode: DriveMode,
94 }
95}
96
97pub trait ChannelIFace<'a, S: TimerSpeed + 'a>
99where
100 Channel<'a, S>: ChannelHW,
101{
102 fn configure(&mut self, config: config::Config<'a, S>) -> Result<(), Error>;
104
105 fn set_duty(&self, duty_pct: u8) -> Result<(), Error>;
107
108 fn start_duty_fade(
110 &self,
111 start_duty_pct: u8,
112 end_duty_pct: u8,
113 duration_ms: u16,
114 ) -> Result<(), Error>;
115
116 fn is_duty_fade_running(&self) -> bool;
118}
119
120pub trait ChannelHW {
122 fn configure_hw(&mut self) -> Result<(), Error>;
125 fn configure_hw_with_drive_mode(&mut self, cfg: DriveMode) -> Result<(), Error>;
128
129 fn set_duty_hw(&self, duty: u32);
131
132 fn start_duty_fade_hw(
134 &self,
135 start_duty: u32,
136 duty_inc: bool,
137 duty_steps: u16,
138 cycles_per_step: u16,
139 duty_per_cycle: u16,
140 );
141
142 fn is_duty_fade_running_hw(&self) -> bool;
144}
145
146pub struct Channel<'a, S: TimerSpeed> {
148 ledc: &'a RegisterBlock,
149 timer: Option<&'a dyn TimerIFace<S>>,
150 number: Number,
151 output_pin: interconnect::OutputSignal<'a>,
152}
153
154impl<'a, S: TimerSpeed> Channel<'a, S> {
155 pub fn new(number: Number, output_pin: impl PeripheralOutput<'a>) -> Self {
157 let ledc = LEDC::regs();
158 Channel {
159 ledc,
160 timer: None,
161 number,
162 output_pin: output_pin.into(),
163 }
164 }
165}
166
167impl<'a, S: TimerSpeed> ChannelIFace<'a, S> for Channel<'a, S>
168where
169 Channel<'a, S>: ChannelHW,
170{
171 fn configure(&mut self, config: config::Config<'a, S>) -> Result<(), Error> {
173 self.timer = Some(config.timer);
174
175 self.set_duty(config.duty_pct)?;
176 self.configure_hw_with_drive_mode(config.drive_mode)?;
177
178 Ok(())
179 }
180
181 fn set_duty(&self, duty_pct: u8) -> Result<(), Error> {
183 let duty_exp;
184 if let Some(timer) = self.timer {
185 if let Some(timer_duty) = timer.duty() {
186 duty_exp = timer_duty as u32;
187 } else {
188 return Err(Error::Timer);
189 }
190 } else {
191 return Err(Error::Channel);
192 }
193
194 let duty_range = 2u32.pow(duty_exp);
195 let duty_value = (duty_range * duty_pct as u32) / 100;
196
197 if duty_pct > 100u8 {
198 return Err(Error::Duty);
200 }
201
202 self.set_duty_hw(duty_value);
203
204 Ok(())
205 }
206
207 fn start_duty_fade(
219 &self,
220 start_duty_pct: u8,
221 end_duty_pct: u8,
222 duration_ms: u16,
223 ) -> Result<(), Error> {
224 let duty_exp;
225 let frequency;
226 if start_duty_pct > 100u8 {
227 return Err(Error::Fade(FadeError::StartDuty));
228 }
229 if end_duty_pct > 100u8 {
230 return Err(Error::Fade(FadeError::EndDuty));
231 }
232 if let Some(timer) = self.timer {
233 if let Some(timer_duty) = timer.duty() {
234 if timer.frequency() > 0 {
235 duty_exp = timer_duty as u32;
236 frequency = timer.frequency();
237 } else {
238 return Err(Error::Timer);
239 }
240 } else {
241 return Err(Error::Timer);
242 }
243 } else {
244 return Err(Error::Channel);
245 }
246
247 let duty_range = (1u32 << duty_exp) - 1;
248 let start_duty_value = (duty_range * start_duty_pct as u32) / 100;
249 let end_duty_value = (duty_range * end_duty_pct as u32) / 100;
250
251 let pwm_cycles = (duration_ms as u32) * frequency / 1000;
254
255 let abs_duty_diff = end_duty_value.abs_diff(start_duty_value);
256 let duty_steps: u32 = u16::try_from(abs_duty_diff).unwrap_or(65535).into();
257 let cycles_per_step: u16 = (pwm_cycles / duty_steps)
262 .try_into()
263 .map_err(|_| Error::Fade(FadeError::Duration))
264 .and_then(|res| {
265 if res > 1023 {
266 Err(Error::Fade(FadeError::Duration))
267 } else {
268 Ok(res)
269 }
270 })?;
271 let duty_per_cycle: u16 = (abs_duty_diff / duty_steps)
276 .try_into()
277 .map_err(|_| Error::Fade(FadeError::DutyRange))?;
278
279 self.start_duty_fade_hw(
280 start_duty_value,
281 end_duty_value > start_duty_value,
282 duty_steps.try_into().unwrap(),
283 cycles_per_step,
284 duty_per_cycle,
285 );
286
287 Ok(())
288 }
289
290 fn is_duty_fade_running(&self) -> bool {
291 self.is_duty_fade_running_hw()
292 }
293}
294
295mod ehal1 {
296 use embedded_hal::pwm::{self, ErrorKind, ErrorType, SetDutyCycle};
297
298 use super::{Channel, ChannelHW, Error};
299 use crate::ledc::timer::TimerSpeed;
300
301 impl pwm::Error for Error {
302 fn kind(&self) -> pwm::ErrorKind {
303 ErrorKind::Other
304 }
305 }
306
307 impl<S: TimerSpeed> ErrorType for Channel<'_, S> {
308 type Error = Error;
309 }
310
311 impl<'a, S: TimerSpeed> SetDutyCycle for Channel<'a, S>
312 where
313 Channel<'a, S>: ChannelHW,
314 {
315 fn max_duty_cycle(&self) -> u16 {
316 let duty_exp;
317
318 if let Some(timer_duty) = self.timer.and_then(|timer| timer.duty()) {
319 duty_exp = timer_duty as u32;
320 } else {
321 return 0;
322 }
323
324 let duty_range = 2u32.pow(duty_exp);
325
326 duty_range as u16
327 }
328
329 fn set_duty_cycle(&mut self, mut duty: u16) -> Result<(), Self::Error> {
330 let max = self.max_duty_cycle();
331 duty = if duty > max { max } else { duty };
332 self.set_duty_hw(duty.into());
333 Ok(())
334 }
335 }
336}
337
338impl<S: crate::ledc::timer::TimerSpeed> Channel<'_, S> {
339 fn set_channel(&mut self, timer_number: u8) {
340 low_level::set_channel(self.ledc, self.number, timer_number, S::IS_HS);
341 low_level::start_duty_without_fading(self.ledc, self.number, S::IS_HS);
342 }
343
344 fn start_duty_without_fading(&self) {
345 low_level::start_duty_without_fading(self.ledc, self.number, S::IS_HS);
346 }
347
348 fn update_channel(&self) {
349 low_level::update_channel(self.ledc, self.number, S::IS_HS);
350 }
351}
352
353impl<S> ChannelHW for Channel<'_, S>
354where
355 S: crate::ledc::timer::TimerSpeed,
356{
357 fn configure_hw(&mut self) -> Result<(), Error> {
359 self.configure_hw_with_drive_mode(DriveMode::PushPull)
360 }
361
362 fn configure_hw_with_drive_mode(&mut self, cfg: DriveMode) -> Result<(), Error> {
363 if let Some(timer) = self.timer {
364 if !timer.is_configured() {
365 return Err(Error::Timer);
366 }
367
368 self.output_pin
369 .apply_output_config(&OutputConfig::default().with_drive_mode(cfg));
370 self.output_pin.set_output_enable(true);
371
372 let timer_number = timer.number() as u8;
373
374 self.set_channel(timer_number);
375 self.update_channel();
376
377 let signal = low_level::output_signal(self.number, S::IS_HS);
378 signal.connect_to(&self.output_pin);
379 } else {
380 return Err(Error::Timer);
381 }
382
383 Ok(())
384 }
385
386 fn set_duty_hw(&self, duty: u32) {
388 low_level::set_duty_hw(self.ledc, self.number, S::IS_HS, duty);
389 self.start_duty_without_fading();
390 self.update_channel();
391 }
392
393 fn start_duty_fade_hw(
395 &self,
396 start_duty: u32,
397 duty_inc: bool,
398 duty_steps: u16,
399 cycles_per_step: u16,
400 duty_per_cycle: u16,
401 ) {
402 low_level::start_duty_fade_hw(
403 self.ledc,
404 self.number,
405 S::IS_HS,
406 start_duty,
407 duty_inc,
408 duty_steps,
409 cycles_per_step,
410 duty_per_cycle,
411 );
412 self.update_channel();
413 }
414
415 fn is_duty_fade_running_hw(&self) -> bool {
416 low_level::is_duty_fade_running_hw(self.ledc, self.number, S::IS_HS)
417 }
418}