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(
220 &self,
221 start_duty_pct: u8,
222 end_duty_pct: u8,
223 duration_ms: u16,
224 ) -> Result<(), Error> {
225 let duty_exp;
226 let frequency;
227 if start_duty_pct > 100u8 {
228 return Err(Error::Fade(FadeError::StartDuty));
229 }
230 if end_duty_pct > 100u8 {
231 return Err(Error::Fade(FadeError::EndDuty));
232 }
233 if let Some(timer) = self.timer {
234 if let Some(timer_duty) = timer.duty() {
235 if timer.frequency() > 0 {
236 duty_exp = timer_duty as u32;
237 frequency = timer.frequency();
238 } else {
239 return Err(Error::Timer);
240 }
241 } else {
242 return Err(Error::Timer);
243 }
244 } else {
245 return Err(Error::Channel);
246 }
247
248 let duty_range = (1u32 << duty_exp) - 1;
249 let start_duty_value = (duty_range * start_duty_pct as u32) / 100;
250 let end_duty_value = (duty_range * end_duty_pct as u32) / 100;
251
252 let pwm_cycles = (duration_ms as u32) * frequency / 1000;
255
256 let abs_duty_diff = end_duty_value.abs_diff(start_duty_value);
257 let duty_steps: u32 = u16::try_from(abs_duty_diff).unwrap_or(65535).into();
258 let cycles_per_step: u16 = (pwm_cycles / duty_steps)
263 .try_into()
264 .map_err(|_| Error::Fade(FadeError::Duration))
265 .and_then(|res| {
266 if res > 1023 {
267 Err(Error::Fade(FadeError::Duration))
268 } else {
269 Ok(res)
270 }
271 })?;
272 let duty_per_cycle: u16 = (abs_duty_diff / duty_steps)
277 .try_into()
278 .map_err(|_| Error::Fade(FadeError::DutyRange))?;
279
280 self.start_duty_fade_hw(
281 start_duty_value,
282 end_duty_value > start_duty_value,
283 duty_steps.try_into().unwrap(),
284 cycles_per_step,
285 duty_per_cycle,
286 );
287
288 Ok(())
289 }
290
291 fn is_duty_fade_running(&self) -> bool {
292 self.is_duty_fade_running_hw()
293 }
294}
295
296mod ehal1 {
297 use embedded_hal::pwm::{self, ErrorKind, ErrorType, SetDutyCycle};
298
299 use super::{Channel, ChannelHW, Error};
300 use crate::ledc::timer::TimerSpeed;
301
302 impl pwm::Error for Error {
303 fn kind(&self) -> pwm::ErrorKind {
304 ErrorKind::Other
305 }
306 }
307
308 impl<S: TimerSpeed> ErrorType for Channel<'_, S> {
309 type Error = Error;
310 }
311
312 impl<'a, S: TimerSpeed> SetDutyCycle for Channel<'a, S>
313 where
314 Channel<'a, S>: ChannelHW,
315 {
316 fn max_duty_cycle(&self) -> u16 {
317 let duty_exp;
318
319 if let Some(timer_duty) = self.timer.and_then(|timer| timer.duty()) {
320 duty_exp = timer_duty as u32;
321 } else {
322 return 0;
323 }
324
325 let duty_range = 2u32.pow(duty_exp);
326
327 duty_range as u16
328 }
329
330 fn set_duty_cycle(&mut self, mut duty: u16) -> Result<(), Self::Error> {
331 let max = self.max_duty_cycle();
332 duty = if duty > max { max } else { duty };
333 self.set_duty_hw(duty.into());
334 Ok(())
335 }
336 }
337}
338
339impl<S: crate::ledc::timer::TimerSpeed> Channel<'_, S> {
340 fn set_channel(&mut self, timer_number: u8) {
341 low_level::set_channel(self.ledc, self.number, timer_number, S::IS_HS);
342 low_level::start_duty_without_fading(self.ledc, self.number, S::IS_HS);
343 }
344
345 fn start_duty_without_fading(&self) {
346 low_level::start_duty_without_fading(self.ledc, self.number, S::IS_HS);
347 }
348
349 fn update_channel(&self) {
350 low_level::update_channel(self.ledc, self.number, S::IS_HS);
351 }
352}
353
354impl<S> ChannelHW for Channel<'_, S>
355where
356 S: crate::ledc::timer::TimerSpeed,
357{
358 fn configure_hw(&mut self) -> Result<(), Error> {
360 self.configure_hw_with_drive_mode(DriveMode::PushPull)
361 }
362
363 fn configure_hw_with_drive_mode(&mut self, cfg: DriveMode) -> Result<(), Error> {
364 if let Some(timer) = self.timer {
365 if !timer.is_configured() {
366 return Err(Error::Timer);
367 }
368
369 self.output_pin
370 .apply_output_config(&OutputConfig::default().with_drive_mode(cfg));
371 self.output_pin.set_output_enable(true);
372
373 let timer_number = timer.number() as u8;
374
375 self.set_channel(timer_number);
376 self.update_channel();
377
378 let signal = low_level::output_signal(self.number, S::IS_HS);
379 signal.connect_to(&self.output_pin);
380 } else {
381 return Err(Error::Timer);
382 }
383
384 Ok(())
385 }
386
387 fn set_duty_hw(&self, duty: u32) {
389 low_level::set_duty_hw(self.ledc, self.number, S::IS_HS, duty);
390 self.start_duty_without_fading();
391 self.update_channel();
392 }
393
394 fn start_duty_fade_hw(
396 &self,
397 start_duty: u32,
398 duty_inc: bool,
399 duty_steps: u16,
400 cycles_per_step: u16,
401 duty_per_cycle: u16,
402 ) {
403 low_level::start_duty_fade_hw(
404 self.ledc,
405 self.number,
406 S::IS_HS,
407 start_duty,
408 duty_inc,
409 duty_steps,
410 cycles_per_step,
411 duty_per_cycle,
412 );
413 self.update_channel();
414 }
415
416 fn is_duty_fade_running_hw(&self) -> bool {
417 low_level::is_duty_fade_running_hw(self.ledc, self.number, S::IS_HS)
418 }
419}