rp2040_hal/pwm/mod.rs
1//! Pulse Width Modulation (PWM)
2//!
3//! First you must create a Slices struct which contains all the pwm slices.
4//!
5//! ```no_run
6//! use rp2040_hal::{prelude::*, pwm::{InputHighRunning, Slices}};
7//!
8//!
9//! let mut pac = rp2040_pac::Peripherals::take().unwrap();
10//!
11//! // Init PWMs
12//! let pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS);
13//!
14//! // Configure PWM4
15//! let mut pwm = pwm_slices.pwm4;
16//! pwm.set_ph_correct();
17//! pwm.enable();
18//!
19//! // Set to run when b channel is high
20//! let pwm = pwm.into_mode::<InputHighRunning>();
21//! ```
22//!
23//! Once you have the PWM slice struct, you can add individual pins:
24//!
25//! ```no_run
26//! # use rp2040_hal::{prelude::*, gpio::Pins, Sio, pwm::{InputHighRunning, Slices}};
27//! # let mut pac = rp2040_pac::Peripherals::take().unwrap();
28//! # let pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS);
29//! # let mut pwm = pwm_slices.pwm4.into_mode::<InputHighRunning>();
30//! # let mut pac = rp2040_pac::Peripherals::take().unwrap();
31//! #
32//! # let sio = Sio::new(pac.SIO);
33//! # let pins = Pins::new(
34//! # pac.IO_BANK0,
35//! # pac.PADS_BANK0,
36//! # sio.gpio_bank0,
37//! # &mut pac.RESETS,
38//! # );
39//! #
40//! use embedded_hal::pwm::SetDutyCycle;
41//!
42//! // Use B channel (which inputs from GPIO 25)
43//! let mut channel_b = pwm.channel_b;
44//! let channel_pin_b = channel_b.input_from(pins.gpio25);
45//!
46//! // Use A channel (which outputs to GPIO 24)
47//! let mut channel_a = pwm.channel_a;
48//! let channel_pin_a = channel_a.output_to(pins.gpio24);
49//!
50//! // Set duty cycle
51//! channel_a.set_duty_cycle(0x00ff);
52//! let max_duty_cycle = channel_a.max_duty_cycle();
53//! channel_a.set_inverted(); // Invert the output
54//! channel_a.clr_inverted(); // Don't invert the output
55//! ```
56//!
57//! The following configuration options are also available:
58//!
59//! ```no_run
60//! # use rp2040_hal::{prelude::*, pwm::Slices};
61//! # let mut pac = rp2040_pac::Peripherals::take().unwrap();
62//! # let pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS);
63//! # let mut pwm = pwm_slices.pwm4;
64//! pwm.set_ph_correct(); // Run in phase correct mode
65//! pwm.clr_ph_correct(); // Don't run in phase correct mode
66//!
67//! pwm.set_div_int(1u8); // To set integer part of clock divider
68//! pwm.set_div_frac(0u8); // To set fractional part of clock divider
69//!
70//! pwm.get_top(); // To get the TOP register
71//! pwm.set_top(u16::MAX); // To set the TOP register
72//!
73//! ```
74//!
75//! default_config() sets ph_correct to false, the clock divider to 1, does not invert the output, sets top to 65535, and resets the counter.
76//! min_config() leaves those registers in the state they were before it was called (Careful, this can lead to unexpected behavior)
77//! It's recommended to only call min_config() after calling default_config() on a pin that shares a PWM block.
78
79use core::convert::Infallible;
80use core::marker::PhantomData;
81
82use embedded_dma::Word;
83use embedded_hal::pwm::{ErrorType, SetDutyCycle};
84
85use crate::{
86 atomic_register_access::{write_bitmask_clear, write_bitmask_set},
87 dma::{EndlessWriteTarget, WriteTarget},
88 gpio::{bank0::*, AnyPin, FunctionPwm, Pin, ValidFunction},
89 pac::{self, dma::ch::ch_al1_ctrl::TREQ_SEL_A, PWM},
90 resets::SubsystemReset,
91 typelevel::{Is, Sealed},
92};
93
94pub mod dyn_slice;
95pub use dyn_slice::*;
96
97mod reg;
98
99use reg::RegisterInterface;
100
101/// Used to pin traits to a specific channel (A or B)
102pub trait ChannelId: Sealed {
103 /// Corresponding [`DynChannelId`]
104 const DYN: DynChannelId;
105}
106
107/// Channel A
108///
109/// These are attached to the even gpio pins and can only do PWM output
110pub enum A {}
111
112/// Channel B
113///
114/// These are attached to the odd gpio pins and can do PWM output and edge counting for input
115pub enum B {}
116
117impl ChannelId for A {
118 const DYN: DynChannelId = DynChannelId::A;
119}
120impl ChannelId for B {
121 const DYN: DynChannelId = DynChannelId::B;
122}
123impl Sealed for A {}
124impl Sealed for B {}
125
126/// Counter is free-running, and will count continuously whenever the slice is enabled
127pub struct FreeRunning;
128/// Count continuously when a high level is detected on the B pin
129pub struct InputHighRunning;
130/// Count once with each rising edge detected on the B pin
131pub struct CountRisingEdge;
132/// Count once with each falling edge detected on the B pin
133pub struct CountFallingEdge;
134
135/// Type-level marker for tracking which slice modes are valid for which slices
136pub trait ValidSliceMode<I: SliceId>: Sealed + SliceMode {}
137
138/// Type-level marker for tracking which slice modes are valid for which slices
139pub trait ValidSliceInputMode<I: SliceId>: Sealed + ValidSliceMode<I> {}
140
141/// Mode for slice
142pub trait SliceMode: Sealed + Sized {
143 /// Corresponding [`DynSliceMode`]
144 const DYN: DynSliceMode;
145}
146
147impl Sealed for FreeRunning {}
148impl SliceMode for FreeRunning {
149 const DYN: DynSliceMode = DynSliceMode::FreeRunning;
150}
151impl Sealed for InputHighRunning {}
152impl SliceMode for InputHighRunning {
153 const DYN: DynSliceMode = DynSliceMode::InputHighRunning;
154}
155impl Sealed for CountRisingEdge {}
156impl SliceMode for CountRisingEdge {
157 const DYN: DynSliceMode = DynSliceMode::CountRisingEdge;
158}
159impl Sealed for CountFallingEdge {}
160impl SliceMode for CountFallingEdge {
161 const DYN: DynSliceMode = DynSliceMode::CountFallingEdge;
162}
163
164impl<I: SliceId> ValidSliceMode<I> for FreeRunning {}
165impl<I: SliceId> ValidSliceMode<I> for InputHighRunning {}
166impl<I: SliceId> ValidSliceMode<I> for CountRisingEdge {}
167impl<I: SliceId> ValidSliceMode<I> for CountFallingEdge {}
168impl<I: SliceId> ValidSliceInputMode<I> for InputHighRunning {}
169impl<I: SliceId> ValidSliceInputMode<I> for CountRisingEdge {}
170impl<I: SliceId> ValidSliceInputMode<I> for CountFallingEdge {}
171
172//==============================================================================
173// Slice IDs
174//==============================================================================
175
176/// Type-level `enum` for slice IDs
177pub trait SliceId: Sealed {
178 /// Corresponding [`DynSliceId`]
179 const DYN: DynSliceId;
180 /// [`SliceMode`] at reset
181 type Reset;
182
183 /// Get DREQ number of PWM wrap.
184 const WRAP_DREQ: u8 = TREQ_SEL_A::PWM_WRAP0 as u8 + Self::DYN.num;
185}
186
187macro_rules! slice_id {
188 ($Id:ident, $NUM:literal, $reset : ident) => {
189 $crate::paste::paste! {
190 #[doc = "Slice ID representing slice " $NUM]
191 pub enum $Id {}
192 impl Sealed for $Id {}
193 impl SliceId for $Id {
194 type Reset = $reset;
195 const DYN: DynSliceId = DynSliceId { num: $NUM };
196 }
197 }
198 };
199}
200
201//==============================================================================
202// AnySlice
203//==============================================================================
204
205/// Type class for [`Slice`] types
206///
207/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
208/// [`Slice`] types. See the `AnyKind` documentation for more details on the
209/// pattern.
210///
211/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
212/// [type class]: crate::typelevel#type-classes
213pub trait AnySlice
214where
215 Self: Sealed,
216 Self: Is<Type = SpecificSlice<Self>>,
217 <Self as AnySlice>::Mode: ValidSliceMode<<Self as AnySlice>::Id>,
218{
219 /// [`SliceId`] of the corresponding [`Slice`]
220 type Id: SliceId;
221 /// [`SliceMode`] of the corresponding [`Slice`]
222 type Mode: SliceMode;
223}
224
225impl<S, M> Sealed for Slice<S, M>
226where
227 S: SliceId,
228 M: ValidSliceMode<S>,
229{
230}
231
232impl<S, M> AnySlice for Slice<S, M>
233where
234 S: SliceId,
235 M: ValidSliceMode<S>,
236{
237 type Id = S;
238 type Mode = M;
239}
240
241/// Type alias to recover the specific [`Slice`] type from an implementation of
242/// [`AnySlice`]
243///
244/// See the [`AnyKind`] documentation for more details on the pattern.
245///
246/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
247type SpecificSlice<S> = Slice<<S as AnySlice>::Id, <S as AnySlice>::Mode>;
248
249//==============================================================================
250// Registers
251//==============================================================================
252
253/// Provide a safe register interface for [`Slice`]s
254///
255/// This `struct` takes ownership of a [`SliceId`] and provides an API to
256/// access the corresponding registers.
257struct Registers<I: SliceId> {
258 id: PhantomData<I>,
259}
260
261// [`Registers`] takes ownership of the [`SliceId`], and [`Slice`] guarantees that
262// each slice is a singleton, so this implementation is safe.
263unsafe impl<I: SliceId> RegisterInterface for Registers<I> {
264 #[inline]
265 fn id(&self) -> DynSliceId {
266 I::DYN
267 }
268}
269
270impl<I: SliceId> Registers<I> {
271 /// Create a new instance of [`Registers`]
272 ///
273 /// # Safety
274 ///
275 /// Users must never create two simultaneous instances of this `struct` with
276 /// the same [`SliceId`]
277 #[inline]
278 unsafe fn new() -> Self {
279 Registers { id: PhantomData }
280 }
281
282 /// Provide a type-level equivalent for the
283 /// [`RegisterInterface::change_mode`] method.
284 #[inline]
285 fn change_mode<M: ValidSliceMode<I>>(&mut self) {
286 RegisterInterface::do_change_mode(self, M::DYN);
287 }
288}
289
290/// Pwm slice
291pub struct Slice<I, M>
292where
293 I: SliceId,
294 M: ValidSliceMode<I>,
295{
296 regs: Registers<I>,
297 mode: PhantomData<M>,
298 /// Channel A (always output)
299 pub channel_a: Channel<Self, A>,
300 /// Channel B (input or output)
301 pub channel_b: Channel<Self, B>,
302}
303
304impl<I, M> Slice<I, M>
305where
306 I: SliceId,
307 M: ValidSliceMode<I>,
308{
309 /// Create a new [`Slice`]
310 ///
311 /// # Safety
312 ///
313 /// Each [`Slice`] must be a singleton. For a given [`SliceId`], there must be
314 /// at most one corresponding [`Slice`] in existence at any given time.
315 /// Violating this requirement is `unsafe`.
316 #[inline]
317 pub(crate) unsafe fn new() -> Slice<I, M> {
318 Slice {
319 regs: Registers::new(),
320 mode: PhantomData,
321 channel_a: Channel::new(0),
322 channel_b: Channel::new(0),
323 }
324 }
325
326 /// Convert the slice to the requested [`SliceMode`]
327 #[inline]
328 pub fn into_mode<N: ValidSliceMode<I>>(mut self) -> Slice<I, N> {
329 if N::DYN != M::DYN {
330 self.regs.change_mode::<N>();
331 }
332 // Safe because we drop the existing slice
333 unsafe { Slice::new() }
334 }
335
336 /// Set a default config for the slice
337 pub fn default_config(&mut self) {
338 self.regs.write_ph_correct(false);
339 self.regs.write_div_int(1); // No divisor
340 self.regs.write_div_frac(0); // No divisor
341 self.regs.write_inv_a(false); //Don't invert the channel
342 self.regs.write_inv_b(false); //Don't invert the channel
343 self.regs.write_top(0xfffe); // Wrap at 0xfffe, so cc = 0xffff can indicate 100% duty cycle
344 self.regs.write_ctr(0x0000); //Reset the counter
345 self.regs.write_cc_a(0); //Default duty cycle of 0%
346 self.regs.write_cc_b(0); //Default duty cycle of 0%
347 }
348
349 /// Advance the phase with one count
350 ///
351 /// Counter must be running at less than full speed (div_int + div_frac / 16 > 1)
352 #[inline]
353 pub fn advance_phase(&mut self) {
354 self.regs.advance_phase()
355 }
356
357 /// Retard the phase with one count
358 ///
359 /// Counter must be running at less than full speed (div_int + div_frac / 16 > 1)
360 #[inline]
361 pub fn retard_phase(&mut self) {
362 self.regs.retard_phase()
363 }
364
365 /// Enable phase correct mode
366 #[inline]
367 pub fn set_ph_correct(&mut self) {
368 self.regs.write_ph_correct(true)
369 }
370
371 /// Disables phase correct mode
372 #[inline]
373 pub fn clr_ph_correct(&mut self) {
374 self.regs.write_ph_correct(false)
375 }
376
377 /// Enable slice
378 #[inline]
379 pub fn enable(&mut self) {
380 self.regs.write_enable(true);
381 }
382
383 /// Disable slice
384 #[inline]
385 pub fn disable(&mut self) {
386 self.regs.write_enable(false)
387 }
388
389 /// Sets the integer part of the clock divider
390 #[inline]
391 pub fn set_div_int(&mut self, value: u8) {
392 self.regs.write_div_int(value)
393 }
394
395 /// Sets the fractional part of the clock divider
396 #[inline]
397 pub fn set_div_frac(&mut self, value: u8) {
398 self.regs.write_div_frac(value)
399 }
400
401 /// Get the counter register value
402 #[inline]
403 pub fn get_counter(&self) -> u16 {
404 self.regs.read_ctr()
405 }
406
407 /// Set the counter register value
408 #[inline]
409 pub fn set_counter(&mut self, value: u16) {
410 self.regs.write_ctr(value)
411 }
412
413 /// Get the top register value
414 #[inline]
415 pub fn get_top(&self) -> u16 {
416 self.regs.read_top()
417 }
418
419 /// Sets the top register value
420 ///
421 /// Don't set this to 0xffff if you need true 100% duty cycle:
422 ///
423 /// The CC register, which is used to configure the duty cycle,
424 /// must be set to TOP + 1 for 100% duty cycle, but also is a
425 /// 16 bit register.
426 ///
427 /// In case you do set TOP to 0xffff, [`SetDutyCycle::set_duty_cycle`]
428 /// will slightly violate the trait's documentation, as
429 /// `SetDutyCycle::set_duty_cycle_fully_on` and other calls that
430 /// should lead to 100% duty cycle will only reach a duty cycle of
431 /// about 99.998%.
432 #[inline]
433 pub fn set_top(&mut self, value: u16) {
434 self.regs.write_top(value)
435 }
436
437 /// Create the interrupt bitmask corresponding to this slice
438 #[inline]
439 fn bitmask(&self) -> u32 {
440 1 << I::DYN.num
441 }
442
443 /// Enable the PWM_IRQ_WRAP interrupt when this slice overflows.
444 #[inline]
445 pub fn enable_interrupt(&mut self) {
446 unsafe {
447 let pwm = &(*pac::PWM::ptr());
448 let reg = pwm.inte().as_ptr();
449 write_bitmask_set(reg, self.bitmask());
450 }
451 }
452
453 /// Disable the PWM_IRQ_WRAP interrupt for this slice.
454 #[inline]
455 pub fn disable_interrupt(&mut self) {
456 unsafe {
457 let pwm = &(*pac::PWM::ptr());
458 let reg = pwm.inte().as_ptr();
459 write_bitmask_clear(reg, self.bitmask());
460 };
461 }
462
463 /// Did this slice trigger an overflow interrupt?
464 ///
465 /// This reports the raw interrupt flag, without considering masking or
466 /// forcing bits. It may return true even if the interrupt is disabled
467 /// or false even if the interrupt is forced.
468 #[inline]
469 pub fn has_overflown(&self) -> bool {
470 let mask = self.bitmask();
471 unsafe { (*pac::PWM::ptr()).intr().read().bits() & mask == mask }
472 }
473
474 /// Mark the interrupt handled for this slice.
475 #[inline]
476 pub fn clear_interrupt(&mut self) {
477 unsafe { (*pac::PWM::ptr()).intr().write(|w| w.bits(self.bitmask())) };
478 }
479
480 /// Force the interrupt. This bit is not cleared by hardware and must be manually cleared to
481 /// stop the interrupt from continuing to be asserted.
482 #[inline]
483 pub fn force_interrupt(&mut self) {
484 unsafe {
485 let pwm = &(*pac::PWM::ptr());
486 let reg = pwm.intf().as_ptr();
487 write_bitmask_set(reg, self.bitmask());
488 }
489 }
490
491 /// Clear force interrupt. This bit is not cleared by hardware and must be manually cleared to
492 /// stop the interrupt from continuing to be asserted.
493 #[inline]
494 pub fn clear_force_interrupt(&mut self) {
495 unsafe {
496 let pwm = &(*pac::PWM::ptr());
497 let reg = pwm.intf().as_ptr();
498 write_bitmask_clear(reg, self.bitmask());
499 }
500 }
501}
502
503macro_rules! pwm {
504 ($PWMX:ident, [
505 $($SXi:ident: ($slice:literal, [$($pin_a:ident, $pin_b:ident),*], $i:expr)),+
506 ]) => {
507 $(
508 slice_id!($SXi, $slice, FreeRunning);
509
510 $(
511 impl ValidPwmOutputPin<$SXi, A> for $pin_a {}
512 impl ValidPwmOutputPin<$SXi, B> for $pin_b {}
513 impl ValidPwmInputPin<$SXi> for $pin_b {}
514 )*
515 )+
516
517 $crate::paste::paste!{
518
519 /// Collection of all the individual [`Slices`]s
520 pub struct Slices {
521 _pwm: $PWMX,
522 $(
523 #[doc = "Slice " $SXi]
524 pub [<$SXi:lower>] : Slice<$SXi,<$SXi as SliceId>::Reset>,
525 )+
526 }
527
528 impl Slices {
529 /// Take ownership of the PAC peripheral and split it into discrete [`Slice`]s
530 pub fn new(pwm: $PWMX, reset : &mut crate::pac::RESETS) -> Self {
531 pwm.reset_bring_up(reset);
532 unsafe {
533 Self {
534 _pwm: pwm,
535 $(
536 [<$SXi:lower>]: Slice::new(),
537 )+
538 }
539 }
540 }
541 }
542 }
543 }
544}
545
546pwm! {
547 PWM, [
548 Pwm0: (0, [Gpio0, Gpio1, Gpio16, Gpio17], 0),
549 Pwm1: (1, [Gpio2, Gpio3, Gpio18, Gpio19], 1),
550 Pwm2: (2, [Gpio4, Gpio5, Gpio20, Gpio21], 2),
551 Pwm3: (3, [Gpio6, Gpio7, Gpio22, Gpio23], 3),
552 Pwm4: (4, [Gpio8, Gpio9, Gpio24, Gpio25], 4),
553 Pwm5: (5, [Gpio10, Gpio11, Gpio26, Gpio27], 5),
554 Pwm6: (6, [Gpio12, Gpio13, Gpio28, Gpio29], 6),
555 Pwm7: (7, [Gpio14, Gpio15], 7)
556 ]
557}
558
559/// Marker trait for valid input pins (Channel B only)
560pub trait ValidPwmInputPin<S: SliceId>: ValidFunction<FunctionPwm> + Sealed {}
561/// Marker trait for valid output pins
562pub trait ValidPwmOutputPin<S: SliceId, C: ChannelId>: ValidFunction<FunctionPwm> + Sealed {}
563
564impl Slices {
565 /// Free the pwm registers from the pwm hal struct while consuming it.
566 pub fn free(self) -> PWM {
567 self._pwm
568 }
569
570 /// Enable multiple slices at the same time to make their counters sync up.
571 ///
572 /// You still need to call `slice` to get an actual slice
573 pub fn enable_simultaneous(&mut self, bits: u8) {
574 // Enable multiple slices at the same time
575 unsafe {
576 let reg = self._pwm.en().as_ptr();
577 write_bitmask_set(reg, bits as u32);
578 }
579 }
580
581 // /// Get pwm slice based on gpio pin
582 // pub fn borrow_mut_from_pin<
583 // S: SliceId,
584 // C: ChannelId,
585 // G: PinId + BankPinId + ValidPwmOutputPin<S, C>,
586 // PM: PinMode + ValidPinMode<G>,
587 // SM: ValidSliceMode<S>,
588 // >(&mut self, _: &Pin<G, PM>) -> &mut Slice<S, SM>{
589 // match S::DYN {
590 // DynSliceId{num} if num == 0 => &mut self.pwm0,
591 // DynSliceId{num} if num == 1 => &mut self.pwm1,
592 // DynSliceId{num} if num == 2 => &mut self.pwm2,
593 // DynSliceId{num} if num == 3 => &mut self.pwm3,
594 // DynSliceId{num} if num == 4 => &mut self.pwm4,
595 // DynSliceId{num} if num == 5 => &mut self.pwm5,
596 // DynSliceId{num} if num == 6 => &mut self.pwm6,
597 // DynSliceId{num} if num == 7 => &mut self.pwm7,
598 // _ => unreachable!()
599 // }
600 // }
601}
602
603/// A Channel from the Pwm subsystem.
604///
605/// Its attached to one of the eight slices and can be an A or B side channel
606pub struct Channel<S: AnySlice, C: ChannelId> {
607 regs: Registers<S::Id>,
608 slice_mode: PhantomData<S::Mode>,
609 channel_id: PhantomData<C>,
610 duty_cycle: u16,
611 enabled: bool,
612}
613
614impl<S: AnySlice, C: ChannelId> Channel<S, C> {
615 pub(super) unsafe fn new(duty_cycle: u16) -> Self {
616 Channel {
617 regs: Registers::new(),
618 slice_mode: PhantomData,
619 channel_id: PhantomData,
620 duty_cycle, // stores the duty cycle while the channel is disabled
621 enabled: true,
622 }
623 }
624}
625
626impl<S: AnySlice, C: ChannelId> Sealed for Channel<S, C> {}
627
628impl<S: AnySlice> embedded_hal_0_2::PwmPin for Channel<S, A> {
629 type Duty = u16;
630
631 fn disable(&mut self) {
632 self.set_enabled(false);
633 }
634
635 fn enable(&mut self) {
636 self.set_enabled(true);
637 }
638
639 fn get_duty(&self) -> Self::Duty {
640 if self.enabled {
641 self.regs.read_cc_a()
642 } else {
643 self.duty_cycle
644 }
645 }
646
647 fn get_max_duty(&self) -> Self::Duty {
648 SetDutyCycle::max_duty_cycle(self)
649 }
650
651 fn set_duty(&mut self, duty: Self::Duty) {
652 let _ = SetDutyCycle::set_duty_cycle(self, duty);
653 }
654}
655
656impl<S: AnySlice> embedded_hal_0_2::PwmPin for Channel<S, B> {
657 type Duty = u16;
658
659 fn disable(&mut self) {
660 self.set_enabled(false);
661 }
662
663 fn enable(&mut self) {
664 self.set_enabled(true);
665 }
666
667 fn get_duty(&self) -> Self::Duty {
668 if self.enabled {
669 self.regs.read_cc_b()
670 } else {
671 self.duty_cycle
672 }
673 }
674
675 fn get_max_duty(&self) -> Self::Duty {
676 SetDutyCycle::max_duty_cycle(self)
677 }
678
679 fn set_duty(&mut self, duty: Self::Duty) {
680 let _ = SetDutyCycle::set_duty_cycle(self, duty);
681 }
682}
683
684impl<S: AnySlice> ErrorType for Channel<S, A> {
685 type Error = Infallible;
686}
687
688impl<S: AnySlice> SetDutyCycle for Channel<S, A> {
689 fn max_duty_cycle(&self) -> u16 {
690 self.regs.read_top().saturating_add(1)
691 }
692
693 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
694 self.duty_cycle = duty;
695 if self.enabled {
696 self.regs.write_cc_a(duty)
697 }
698 Ok(())
699 }
700}
701
702impl<S: AnySlice> ErrorType for Channel<S, B> {
703 type Error = Infallible;
704}
705
706impl<S: AnySlice> SetDutyCycle for Channel<S, B> {
707 fn max_duty_cycle(&self) -> u16 {
708 self.regs.read_top().saturating_add(1)
709 }
710
711 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
712 self.duty_cycle = duty;
713 if self.enabled {
714 self.regs.write_cc_b(duty)
715 }
716 Ok(())
717 }
718}
719
720impl<S: AnySlice> Channel<S, A> {
721 /// Enable or disable the PWM channel
722 pub fn set_enabled(&mut self, enable: bool) {
723 if enable && !self.enabled {
724 // Restore the duty cycle.
725 self.regs.write_cc_a(self.duty_cycle);
726 self.enabled = true;
727 } else if !enable && self.enabled {
728 // We can't disable it without disturbing the other channel so this
729 // just sets the duty cycle to zero.
730 self.duty_cycle = self.regs.read_cc_a();
731 self.regs.write_cc_a(0);
732 self.enabled = false;
733 }
734 }
735
736 /// Capture a gpio pin and use it as pwm output for channel A
737 pub fn output_to<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
738 where
739 P::Id: ValidPwmOutputPin<S::Id, A>,
740 {
741 pin.into().into_function()
742 }
743
744 /// Invert channel output
745 #[inline]
746 pub fn set_inverted(&mut self) {
747 self.regs.write_inv_a(true)
748 }
749
750 /// Stop inverting channel output
751 #[inline]
752 pub fn clr_inverted(&mut self) {
753 self.regs.write_inv_a(false)
754 }
755}
756
757impl<S: AnySlice> Channel<S, B> {
758 /// Enable or disable the PWM channel
759 pub fn set_enabled(&mut self, enable: bool) {
760 if enable && !self.enabled {
761 // Restore the duty cycle.
762 self.regs.write_cc_b(self.duty_cycle);
763 self.enabled = true;
764 } else if !enable && self.enabled {
765 // We can't disable it without disturbing the other channel so this
766 // just sets the duty cycle to zero.
767 self.duty_cycle = self.regs.read_cc_b();
768 self.regs.write_cc_b(0);
769 self.enabled = false;
770 }
771 }
772
773 /// Capture a gpio pin and use it as pwm output for channel B
774 pub fn output_to<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
775 where
776 P::Id: ValidPwmOutputPin<S::Id, B>,
777 {
778 pin.into().into_function()
779 }
780
781 /// Invert channel output
782 #[inline]
783 pub fn set_inverted(&mut self) {
784 self.regs.write_inv_b(true)
785 }
786
787 /// Stop inverting channel output
788 #[inline]
789 pub fn clr_inverted(&mut self) {
790 self.regs.write_inv_b(false)
791 }
792}
793
794impl<S: AnySlice> Channel<S, B>
795where
796 S::Mode: ValidSliceInputMode<S::Id>,
797{
798 /// Capture a gpio pin and use it as pwm input for channel B
799 pub fn input_from<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
800 where
801 P::Id: ValidPwmInputPin<S::Id>,
802 {
803 pin.into().into_function()
804 }
805}
806
807impl<S: SliceId, M: ValidSliceMode<S>> Slice<S, M> {
808 /// Capture a gpio pin and use it as pwm output
809 pub fn output_to<P: AnyPin, C: ChannelId>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
810 where
811 P::Id: ValidPwmOutputPin<S, C>,
812 {
813 pin.into().into_function()
814 }
815}
816
817impl<S: SliceId, M: ValidSliceInputMode<S>> Slice<S, M> {
818 /// Capture a gpio pin and use it as pwm input for channel B
819 pub fn input_from<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
820 where
821 P::Id: ValidPwmInputPin<S>,
822 {
823 pin.into().into_function()
824 }
825}
826
827/// Type representing DMA access to PWM cc register.
828///
829/// Both channels are accessed together, because of narrow write replication.
830///
831/// ```no_run
832/// use cortex_m::singleton;
833/// use rp2040_hal::dma::{double_buffer, DMAExt};
834/// use rp2040_hal::pwm::{CcFormat, SliceDmaWrite, Slices};
835///
836///
837/// let mut pac = rp2040_pac::Peripherals::take().unwrap();
838///
839/// // Init PWMs
840/// let pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS);
841///
842/// // Configure PWM4
843/// let mut pwm = pwm_slices.pwm4;
844/// pwm.enable();
845///
846/// let buf = singleton!(: [CcFormat; 4] = [CcFormat{a: 0x1000, b: 0x9000}; 4]).unwrap();
847/// let buf2 = singleton!(: [CcFormat; 4] = [CcFormat{a: 0xf000, b: 0x5000}; 4]).unwrap();
848///
849/// let dma = pac.DMA.split(&mut pac.RESETS);
850///
851/// let dma_pwm = SliceDmaWrite::from(pwm);
852///
853/// let dma_conf = double_buffer::Config::new((dma.ch0, dma.ch1), buf, dma_pwm.cc);
854/// ```
855pub struct SliceDmaWriteCc<S: SliceId, M: ValidSliceMode<S>> {
856 slice: PhantomData<S>,
857 mode: PhantomData<M>,
858}
859
860/// Type representing DMA access to PWM top register.
861///
862/// ```no_run
863/// use cortex_m::{prelude::*, singleton};
864/// use rp2040_hal::dma::{double_buffer, DMAExt};
865/// use rp2040_hal::pwm::{SliceDmaWrite, Slices, TopFormat};
866///
867///
868/// let mut pac = rp2040_pac::Peripherals::take().unwrap();
869///
870/// // Init PWMs
871/// let pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS);
872///
873/// // Configure PWM4
874/// let mut pwm = pwm_slices.pwm4;
875/// pwm.enable();
876///
877/// // Just set to something mesurable.
878/// pwm.channel_a.set_duty(0x1000);
879/// pwm.channel_b.set_duty(0x1000);
880///
881/// let buf = singleton!(: [TopFormat; 4] = [TopFormat::new(0x7fff); 4]).unwrap();
882/// let buf2 = singleton!(: [TopFormat; 4] = [TopFormat::new(0xfffe); 4]).unwrap();
883///
884/// let dma = pac.DMA.split(&mut pac.RESETS);
885///
886/// // Reserve PWM slice for dma.
887/// let dma_pwm = SliceDmaWrite::from(pwm);
888///
889/// let dma_conf = double_buffer::Config::new((dma.ch0, dma.ch1), buf, dma_pwm.top);
890/// ```
891pub struct SliceDmaWriteTop<S: SliceId, M: ValidSliceMode<S>> {
892 slice: PhantomData<S>,
893 mode: PhantomData<M>,
894}
895
896/// PWM slice while used for DMA writes.
897/// ```no_run
898/// use rp2040_hal::{prelude::*, pwm::{SliceDmaWrite, Slices}};
899///
900///
901/// let mut pac = rp2040_pac::Peripherals::take().unwrap();
902///
903/// // Init PWMs
904/// let pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS);
905///
906/// // Configure PWM4
907/// let mut pwm = pwm_slices.pwm4;
908/// pwm.enable();
909///
910/// // Use for DMA usage
911/// let dma_pwm = SliceDmaWrite::from(pwm);
912/// ```
913///
914pub struct SliceDmaWrite<S: SliceId, M: ValidSliceMode<S>> {
915 /// Part for top writes.
916 pub top: SliceDmaWriteTop<S, M>,
917
918 /// Part for cc writes.
919 pub cc: SliceDmaWriteCc<S, M>,
920 slice: Slice<S, M>,
921}
922
923impl<S: SliceId, M: ValidSliceMode<S>> From<Slice<S, M>> for SliceDmaWrite<S, M> {
924 fn from(value: Slice<S, M>) -> Self {
925 Self {
926 slice: value,
927 top: SliceDmaWriteTop {
928 slice: PhantomData,
929 mode: PhantomData,
930 },
931 cc: SliceDmaWriteCc {
932 slice: PhantomData,
933 mode: PhantomData,
934 },
935 }
936 }
937}
938
939impl<S: SliceId, M: ValidSliceMode<S>> From<SliceDmaWrite<S, M>> for Slice<S, M> {
940 fn from(value: SliceDmaWrite<S, M>) -> Self {
941 value.slice
942 }
943}
944
945/// Format for DMA transfers to PWM CC register.
946#[derive(Clone, Copy, Eq, PartialEq)]
947#[repr(C)]
948#[repr(align(4))]
949pub struct CcFormat {
950 /// CC register part for channel a.
951 pub a: u16,
952 /// CC register part for channel b.
953 pub b: u16,
954}
955
956unsafe impl Word for CcFormat {}
957
958/// Format for DMA transfers to PWM TOP register.
959///
960/// It is forbidden to use it as DMA write destination,
961/// it is safe but it might not be compatible with a future use of reserved register fields.
962#[derive(Clone, Copy, Eq)]
963#[repr(C)]
964#[repr(align(4))]
965pub struct TopFormat {
966 /// Valid register part.
967 pub top: u16,
968 /// Reserved part.
969 /// Should always be zero
970 reserved: u16,
971}
972
973impl PartialEq<TopFormat> for TopFormat {
974 fn eq(&self, other: &TopFormat) -> bool {
975 self.top == other.top
976 }
977}
978
979impl TopFormat {
980 /// Create a valid value.
981 pub fn new(top: u16) -> Self {
982 TopFormat { top, reserved: 0 }
983 }
984}
985
986impl Default for TopFormat {
987 fn default() -> Self {
988 Self::new(u16::MAX)
989 }
990}
991
992unsafe impl Word for TopFormat {}
993
994/// Safety: tx_address_count points to a register which is always a valid
995/// write target.
996unsafe impl<S: SliceId, M: ValidSliceMode<S>> WriteTarget for SliceDmaWriteCc<S, M> {
997 type TransmittedWord = CcFormat;
998
999 fn tx_treq() -> Option<u8> {
1000 Some(S::WRAP_DREQ)
1001 }
1002
1003 fn tx_address_count(&mut self) -> (u32, u32) {
1004 let regs = Registers {
1005 id: PhantomData::<S> {},
1006 };
1007 (regs.ch().cc().as_ptr() as u32, u32::MAX)
1008 }
1009
1010 fn tx_increment(&self) -> bool {
1011 false
1012 }
1013}
1014
1015/// Safety: tx_address_count points to a register which is always a valid
1016/// write target.
1017unsafe impl<S: SliceId, M: ValidSliceMode<S>> WriteTarget for SliceDmaWriteTop<S, M> {
1018 type TransmittedWord = TopFormat;
1019
1020 fn tx_treq() -> Option<u8> {
1021 Some(S::WRAP_DREQ)
1022 }
1023
1024 fn tx_address_count(&mut self) -> (u32, u32) {
1025 let regs = Registers {
1026 id: PhantomData::<S> {},
1027 };
1028 (regs.ch().top().as_ptr() as u32, u32::MAX)
1029 }
1030
1031 fn tx_increment(&self) -> bool {
1032 false
1033 }
1034}
1035
1036impl<S: SliceId, M: ValidSliceMode<S>> EndlessWriteTarget for SliceDmaWriteCc<S, M> {}
1037impl<S: SliceId, M: ValidSliceMode<S>> EndlessWriteTarget for SliceDmaWriteTop<S, M> {}