imxrt_hal/common/flexpwm.rs
1//! Pulse width modulation.
2//!
3//! Each PWM peripheral, [`Pwm`], interacts with four submodules, [`Submodule`].
4//! Each submodule acts as a timer with multiple compare registers, called
5//! [`ValueRegister`]s. A comparison event
6//!
7//! - is signaled through a [`Status`] flag (see [`Submodule::status`]).
8//! - can generate an interrupt (see [`Submodule::interrupts`]).
9//! - sets a PWM [`Output`] high or low, depending on the turn on / off values.
10//!
11//! > Note: PWM outputs can also be manipulated directly with [`Submodule`], without
12//! > using [`Output`].
13//!
14//! The PWM driver does not implement any of the embedded-hal PWM traits. You should
15//! use these APIs to create your own PWM implementation that satisfies your driver.
16//!
17//! # Example
18//!
19//! The PWM submodule counts over the range of `i16` values. The counter runs at
20//! the IPG clock frequency. The PWM outputs produce independent, phase-shifted
21//! outputs.
22//!
23//! ```no_run
24//! use imxrt_hal as hal;
25//! use imxrt_ral as ral;
26//!
27//! use hal::flexpwm;
28//!
29//! # || -> Option<()> {
30//! let pwm2 = unsafe { ral::pwm::PWM2::instance() };
31//! let (mut pwm, (_, _, mut sm2, _)) = flexpwm::new(pwm2);
32//!
33//! // Keep running in wait, debug modes.
34//! sm2.set_debug_enable(true);
35//! sm2.set_wait_enable(true);
36//! // Run on the IPG clock.
37//! sm2.set_clock_select(flexpwm::ClockSelect::Ipg);
38//! // Divide the IPG clock by 1.
39//! sm2.set_prescaler(flexpwm::Prescaler::Prescaler1);
40//! // Allow PWM outputs to operate independently.
41//! sm2.set_pair_operation(flexpwm::PairOperation::Independent);
42//!
43//! // Reload every time the full reload value register compares.
44//! sm2.set_load_mode(flexpwm::LoadMode::reload_full());
45//! sm2.set_load_frequency(1);
46//! // Count over the full range of i16 values.
47//! sm2.set_initial_count(&pwm, i16::MIN);
48//! sm2.set_value(flexpwm::FULL_RELOAD_VALUE_REGISTER, i16::MAX);
49//!
50//! let gpio_b0_10 = // Handle to the pad
51//! # unsafe { imxrt_iomuxc::imxrt1060::gpio_b0::GPIO_B0_10::new() };
52//! let gpio_b0_11 = // Handle to the pad
53//! # unsafe { imxrt_iomuxc::imxrt1060::gpio_b0::GPIO_B0_11::new() };
54//! let output_a = flexpwm::Output::new_a(gpio_b0_10);
55//! let output_b = flexpwm::Output::new_b(gpio_b0_11);
56//! // Set the turn on / off count values.
57//! output_a.set_turn_on(&sm2, i16::MIN / 2);
58//! output_a.set_turn_off(&sm2, i16::MAX / 2);
59//! // Output B generates the same duty cycle as A
60//! // with a lagging phase shift of 5000 counts.
61//! output_b.set_turn_on(&sm2, output_a.turn_on(&sm2) + 5000);
62//! output_b.set_turn_off(&sm2, output_a.turn_off(&sm2) + 5000);
63//!
64//! // Enable the PWM output.
65//! output_a.set_output_enable(&mut pwm, true);
66//! output_b.set_output_enable(&mut pwm, true);
67//! // Load the values into the PWM registers.
68//! sm2.set_load_ok(&mut pwm);
69//! // Start running.
70//! sm2.set_running(&mut pwm, true);
71//! # Some(())}();
72//! ```
73
74mod output;
75mod ral;
76
77pub use self::ral::{Submodule, Submodules};
78use crate::ral::pwm;
79pub use output::Output;
80
81/// A PWM peripheral.
82///
83/// The PWM peripheral provides access to peripheral-wide registers,
84/// or registers that cannot be owned by any one [`Submodule`].
85/// Use a `Pwm` to synchronously control submodules and pin outputs.
86///
87/// For a simpler interface, prefer `Submodule` and / or [`Output`].
88pub struct Pwm<const N: u8> {
89 pwm: pwm::Instance<N>,
90}
91
92bitflags::bitflags! {
93 /// Bitmask for representing submodules.
94 ///
95 /// `Mask` is used throughout the PWM API. The interpretation of the
96 /// bits depends on the function.
97 ///
98 /// If you have a [`Submodule`], use
99 /// `MASK` or `mask()` to easily obtain its bitmask.
100 pub struct Mask : u8 {
101 /// Submodule 0.
102 const SM0 = 1 << 0;
103 /// Submodule 1.
104 const SM1 = 1 << 1;
105 /// Submodule 2.
106 const SM2 = 1 << 2;
107 /// Submodule 3.
108 const SM3 = 1 << 3;
109 }
110}
111
112impl<const N: u8> Pwm<N> {
113 /// The peripheral instance.
114 pub const N: u8 = N;
115
116 // TODO: MCTRL should be byte accessible (unlike other PWM modules, which are explicitly
117 // documented as "not bye accessible"). If we could load and store directly from the low
118 // byte -- where LDOK and CLDOK reside -- we might be able to drop the &mut receiver on
119 // the LDOK methods. This requires us to re-define the MCTRL register into two halves.
120 // Ideally, this happens in the RAL, but it could also happen in our custom RAL module.
121 // Any solution needs to account for the differences between the 1010 and all other chips.
122
123 /// Read the `LDOK` bits.
124 ///
125 /// Note that the hardware will deassert `LDOK` after the values are loaded.
126 pub fn load_ok(&self) -> Mask {
127 let ldok = crate::ral::read_reg!(crate::ral::pwm, self.pwm, MCTRL, LDOK);
128 Mask::from_bits_truncate(ldok as u8)
129 }
130 /// Set `LDOK` for zero or more submodules.
131 ///
132 /// A *high bit* indicates which `LDOK` bit(s) will be *set*.
133 pub fn set_load_ok(&mut self, mask: Mask) {
134 crate::ral::modify_reg!(crate::ral::pwm, self.pwm, MCTRL, LDOK: mask.bits() as u16);
135 }
136 /// Clear `LDOK` for zero or more submodules.
137 ///
138 /// A *high bit* indicates which `LDOK` bit(s) will be *cleared*.
139 pub fn clear_load_ok(&mut self, mask: Mask) {
140 crate::ral::modify_reg!(crate::ral::pwm, self.pwm, MCTRL, CLDOK: mask.bits() as u16);
141 }
142 /// Read the `RUN` bit(s).
143 pub fn run(&self) -> Mask {
144 let run = crate::ral::read_reg!(crate::ral::pwm, self.pwm, MCTRL, RUN);
145 Mask::from_bits_truncate(run as u8)
146 }
147 /// Set or clear the `RUN` bit(s) for one or more submodules.
148 ///
149 /// This bitmask is written directly to the hardware. To perform a read-modify-write
150 /// operation on these bits, make sure to read the initial values with [`Pwm::run`].
151 pub fn set_run(&mut self, mask: Mask) {
152 crate::ral::modify_reg!(crate::ral::pwm, self.pwm, MCTRL, RUN: mask.bits() as u16);
153 }
154 /// Read a PWM channel's output enable bits.
155 pub fn output_enable(&self, channel: Channel) -> Mask {
156 let mask = match channel {
157 Channel::A => crate::ral::read_reg!(crate::ral::pwm, self.pwm, OUTEN, PWMA_EN),
158 Channel::B => crate::ral::read_reg!(crate::ral::pwm, self.pwm, OUTEN, PWMB_EN),
159 };
160 Mask::from_bits_truncate(mask as u8)
161 }
162 /// Set a PWM channel's output enable.
163 ///
164 /// A high bit indicates the channel is enabled. A low bit disables the channel.
165 pub fn set_output_enable(&mut self, channel: Channel, mask: Mask) {
166 let mask = mask.bits() as u16;
167 match channel {
168 Channel::A => crate::ral::modify_reg!(crate::ral::pwm, self.pwm, OUTEN, PWMA_EN: mask),
169 Channel::B => crate::ral::modify_reg!(crate::ral::pwm, self.pwm, OUTEN, PWMB_EN: mask),
170 }
171 }
172
173 fn rmw_outen(&mut self, channel: Channel, mask: Mask, enable: bool) {
174 let mut outen = self.output_enable(channel);
175 outen.set(mask, enable);
176 self.set_output_enable(channel, outen);
177 }
178}
179
180/// Create a PWM peripheral with its submodules.
181pub fn new<const N: u8>(pwm: pwm::Instance<N>) -> (Pwm<N>, Submodules<N>) {
182 // Clear fault levels.
183 crate::ral::write_reg!(crate::ral::pwm, pwm, FCTRL0, FLVL: 0xF);
184 // Clear fault flags.
185 crate::ral::write_reg!(crate::ral::pwm, pwm, FSTS0, FFLAG: 0xF);
186
187 let submodules = self::ral::submodules(&pwm);
188 (Pwm { pwm }, submodules)
189}
190
191impl<const N: u8, const M: u8> Submodule<N, M> {
192 /// The mask for this submodule.
193 pub const MASK: Mask = Mask::from_bits_truncate(1 << M);
194
195 /// Returns the mask for this submodule.
196 pub const fn mask(&self) -> Mask {
197 Self::MASK
198 }
199
200 /// Read the counter register.
201 pub fn count(&self) -> i16 {
202 crate::ral::read_reg!(self::ral, self, SMCNT)
203 }
204
205 /// Read the initial counter register.
206 ///
207 /// This is the value loaded into the submodule counter
208 /// when a reload event happens. Note: this reads the
209 /// buffered value set with `set_initial_counter` when
210 /// the hardware is waiting to load the value.
211 pub fn initial_count(&self) -> i16 {
212 crate::ral::read_reg!(self::ral, self, SMINIT)
213 }
214
215 /// Set the initial counter register.
216 ///
217 /// Note: this value is buffered. It is not reloaded
218 /// until the LDOK signal is set and the reload cycle
219 /// happens. You cannot write the value when LDOK is
220 /// set.
221 pub fn set_initial_count(&self, pwm: &Pwm<N>, counter: i16) {
222 if !self.load_ok(pwm) {
223 crate::ral::write_reg!(self::ral, self, SMINIT, counter);
224 }
225 }
226
227 /// Returns the load frequency.
228 ///
229 /// The load frequency describes how many PWM "opportuntities" it will take
230 /// before the hardware loads buffered register values into their registers.
231 /// This value is between 1 and 16.
232 ///
233 /// An "opportunity" is one of
234 ///
235 /// - a full cycle reload (VAL1 matches), if full reload is set.
236 /// - a half cycle reload (VAL0 matches), if half reload is set.
237 pub fn load_frequency(&self) -> u16 {
238 crate::ral::read_reg!(self::ral, self, SMCTRL, LDFQ) + 1
239 }
240
241 /// Set the load frequency.
242 ///
243 /// See [`load_frequency`](crate::flexpwm::Submodule::load_frequency) for a
244 /// description of load frequency. The implementation clamps the values
245 /// between 1 and 16.
246 pub fn set_load_frequency(&mut self, ldfq: u16) {
247 let ldfq = ldfq.clamp(1, 16) - 1;
248 crate::ral::modify_reg!(self::ral, self, SMCTRL, LDFQ: ldfq);
249 }
250
251 /// Returns the prescaler value.
252 pub fn prescaler(&self) -> Prescaler {
253 let prescaler = crate::ral::read_reg!(self::ral, self, SMCTRL, PRSC);
254
255 #[allow(clippy::assertions_on_constants)]
256 {
257 use self::ral::SMCTRL;
258 const _: () = assert!(SMCTRL::PRSC::mask >> SMCTRL::PRSC::offset == 7u16);
259 const _: () = assert!(Prescaler::Prescaler128 as u16 == 7u16);
260 }
261
262 // Safety: field is three bits wide. Prescaler represents all values in
263 // the enum. See the asserts above for tests.
264 unsafe { core::mem::transmute(prescaler) }
265 }
266
267 /// Set the PWM clock prescaler.
268 pub fn set_prescaler(&mut self, prescaler: Prescaler) {
269 crate::ral::modify_reg!(self::ral, self, SMCTRL, PRSC: prescaler as u16)
270 }
271
272 /// Returns the pair operation setting.
273 pub fn pair_operation(&self) -> PairOperation {
274 let indep = crate::ral::read_reg!(self::ral, self, SMCTRL2, INDEP);
275
276 #[allow(clippy::assertions_on_constants)]
277 {
278 use self::ral::SMCTRL2;
279 const _: () = assert!(SMCTRL2::INDEP::mask >> SMCTRL2::INDEP::offset == 1u16);
280 }
281
282 // Safety: field is one bit. Enum is two variants, representing all values
283 // in this one bit state.
284 unsafe { core::mem::transmute(indep) }
285 }
286
287 /// Set the pair operation setting.
288 pub fn set_pair_operation(&mut self, pair_operation: PairOperation) {
289 crate::ral::modify_reg!(self::ral, self, SMCTRL2, INDEP: pair_operation as u16);
290 }
291
292 /// Returns `true` if debug enable is set.
293 ///
294 /// When set, the PWM continues to run when in debug mode. When clear, the
295 /// PWM stops in debug mode, and restarts when debug mode exits.
296 pub fn debug_enable(&self) -> bool {
297 crate::ral::read_reg!(self::ral, self, SMCTRL2, DBGEN == 1)
298 }
299
300 /// Set debug enable.
301 ///
302 /// See [`debug_enable`](Submodule::debug_enable) for more information on debug
303 /// enable.
304 pub fn set_debug_enable(&mut self, enable: bool) {
305 crate::ral::modify_reg!(self::ral, self, SMCTRL2, DBGEN: enable as u16);
306 }
307
308 /// Returns `true` if wait enable is set.
309 ///
310 /// When set, the PWM continues to run when in wait mode. When clear, the PWM
311 /// stops in wait mode, and restarts when wait mode exits.
312 pub fn wait_enable(&self) -> bool {
313 crate::ral::read_reg!(self::ral, self, SMCTRL2, WAITEN == 1)
314 }
315
316 /// Set wait enable.
317 ///
318 /// See [`wait_enable`](Submodule::wait_enable) for more information on debug
319 /// enable.
320 pub fn set_wait_enable(&mut self, enable: bool) {
321 crate::ral::modify_reg!(self::ral, self, SMCTRL2, WAITEN: enable as u16);
322 }
323
324 /// Returns the clock selection.
325 pub fn clock_select(&self) -> ClockSelect {
326 const IPG: u16 = ClockSelect::Ipg as u16;
327 const EXT: u16 = ClockSelect::External as u16;
328 const SM0: u16 = ClockSelect::Submodule0 as u16;
329
330 match crate::ral::read_reg!(self::ral, self, SMCTRL2, CLK_SEL) {
331 IPG => ClockSelect::Ipg,
332 EXT => ClockSelect::External,
333 SM0 => ClockSelect::Submodule0,
334 _ => unreachable!("Reserved value"),
335 }
336 }
337
338 /// Set the clock selection.
339 ///
340 /// # Panics
341 ///
342 /// You cannot use submodule 0's clock for submodule 0. If the submodule 0 clock
343 /// is selected for submodule 0, this call panics.
344 pub fn set_clock_select(&mut self, clock_select: ClockSelect) {
345 assert!(0 != M || clock_select != ClockSelect::Submodule0);
346 crate::ral::modify_reg!(self::ral, self, SMCTRL2, CLK_SEL: clock_select as u16);
347 }
348
349 /// Returns the load mode.
350 pub fn load_mode(&self) -> LoadMode {
351 let (immediate, full, half) =
352 crate::ral::read_reg!(self::ral, self, SMCTRL, LDMOD, FULL, HALF);
353 if immediate != 0 {
354 LoadMode::Immediate
355 } else {
356 LoadMode::ReloadCycle {
357 full: full != 0,
358 half: half != 0,
359 }
360 }
361 }
362
363 /// Set the load mode.
364 ///
365 /// # Panics
366 ///
367 /// Panics if the load mode is reload cycle, yet neither `full` nor `half` is set.
368 /// Use the [`LoadMode`] helper methods to ensure one of these flags are set.
369 pub fn set_load_mode(&mut self, load_mode: LoadMode) {
370 match load_mode {
371 LoadMode::Immediate => crate::ral::modify_reg!(self::ral, self, SMCTRL, LDMOD: 1),
372 LoadMode::ReloadCycle { full, half } => {
373 assert!(
374 full || half,
375 "LoadMode::ReloadCycle must set at least full or half"
376 );
377 crate::ral::modify_reg!(self::ral, self, SMCTRL, LDMOD: 0, FULL: full as u16, HALF: half as u16)
378 }
379 }
380 }
381
382 /// Read the status flags.
383 pub fn status(&self) -> Status {
384 let sts = crate::ral::read_reg!(self::ral, self, SMSTS);
385 Status::from_bits_truncate(sts)
386 }
387
388 /// Clear status flags.
389 ///
390 /// The high bits are cleared. The implementation will clear the non-W1C bits,
391 /// so it's safe to call this with [`Status::all()`].
392 pub fn clear_status(&self, status: Status) {
393 let sts = status & Status::W1C;
394 crate::ral::write_reg!(self::ral, self, SMSTS, sts.bits())
395 }
396
397 /// Read the interrupt flags.
398 pub fn interrupts(&self) -> Interrupts {
399 let inten = crate::ral::read_reg!(self::ral, self, SMINTEN);
400 Interrupts::from_bits_truncate(inten)
401 }
402
403 /// Set the interrupt flags.
404 pub fn set_interrupts(&self, interrupts: Interrupts) {
405 crate::ral::write_reg!(self::ral, self, SMINTEN, interrupts.bits());
406 }
407
408 /// Read one of the six value registers.
409 ///
410 /// The return indicates the count value that will cause a comparison.
411 pub fn value(&self, value_register: ValueRegister) -> i16 {
412 match value_register {
413 ValueRegister::Val0 => crate::ral::read_reg!(self::ral, self, SMVAL0),
414 ValueRegister::Val1 => crate::ral::read_reg!(self::ral, self, SMVAL1),
415 ValueRegister::Val2 => crate::ral::read_reg!(self::ral, self, SMVAL2),
416 ValueRegister::Val3 => crate::ral::read_reg!(self::ral, self, SMVAL3),
417 ValueRegister::Val4 => crate::ral::read_reg!(self::ral, self, SMVAL4),
418 ValueRegister::Val5 => crate::ral::read_reg!(self::ral, self, SMVAL5),
419 }
420 }
421
422 /// Get the turn on value for a channel.
423 ///
424 /// This is the same as using [`turn_on()`] to produce a value register, then
425 /// calling [`value()`](Self::value) with that result.
426 pub fn turn_on(&self, channel: Channel) -> i16 {
427 self.value(turn_on(channel))
428 }
429
430 /// Get the turn off value for a channel.
431 ///
432 /// This is the same as using [`turn_off()`] to produce a value register, then
433 /// calling [`value()`](Self::value) with that result.
434 pub fn turn_off(&self, channel: Channel) -> i16 {
435 self.value(turn_off(channel))
436 }
437
438 /// Set one of the six value registers to compare at `value`.
439 pub fn set_value(&self, value_register: ValueRegister, value: i16) {
440 match value_register {
441 ValueRegister::Val0 => crate::ral::write_reg!(self::ral, self, SMVAL0, value),
442 ValueRegister::Val1 => crate::ral::write_reg!(self::ral, self, SMVAL1, value),
443 ValueRegister::Val2 => crate::ral::write_reg!(self::ral, self, SMVAL2, value),
444 ValueRegister::Val3 => crate::ral::write_reg!(self::ral, self, SMVAL3, value),
445 ValueRegister::Val4 => crate::ral::write_reg!(self::ral, self, SMVAL4, value),
446 ValueRegister::Val5 => crate::ral::write_reg!(self::ral, self, SMVAL5, value),
447 }
448 }
449
450 /// Set the turn on compare for a channel.
451 ///
452 /// This is the same as using [`turn_on()`] to produce a value register, then
453 /// calling [`set_value()`](Self::set_value) with that result.
454 pub fn set_turn_on(&self, channel: Channel, compare: i16) {
455 self.set_value(turn_on(channel), compare);
456 }
457
458 /// Set the turn off compare for a channel.
459 ///
460 /// This is the same as using [`turn_off()`] to produce a value register, then
461 /// calling [`set_value()`](Self::set_value) with that result.
462 pub fn set_turn_off(&self, channel: Channel, compare: i16) {
463 self.set_value(turn_off(channel), compare);
464 }
465
466 /// Returns `true` if this submodule's `LDOK` bit is set.
467 pub fn load_ok(&self, pwm: &Pwm<N>) -> bool {
468 pwm.load_ok().intersects(Self::MASK)
469 }
470
471 /// Set the `LDOK` bit for this submodule.
472 pub fn set_load_ok(&self, pwm: &mut Pwm<N>) {
473 pwm.set_load_ok(Self::MASK);
474 }
475
476 /// Clear the `LDOK` bit for this submodule.
477 pub fn clear_load_ok(&self, pwm: &mut Pwm<N>) {
478 pwm.clear_load_ok(Self::MASK);
479 }
480
481 /// Returns `true` if the submodule is running.
482 pub fn is_running(&self, pwm: &Pwm<N>) -> bool {
483 pwm.run().intersects(Self::MASK)
484 }
485
486 /// Indicates if a PWM output channel is enabled.
487 pub fn output_enable(&self, pwm: &Pwm<N>, channel: Channel) -> bool {
488 pwm.output_enable(channel).intersects(Self::MASK)
489 }
490
491 /// Enable or disable an output channel.
492 pub fn set_output_enable(&self, pwm: &mut Pwm<N>, channel: Channel, enable: bool) {
493 pwm.rmw_outen(channel, Self::MASK, enable);
494 }
495
496 /// Set or clear the running bit for this submodule.
497 pub fn set_running(&self, pwm: &mut Pwm<N>, run: bool) {
498 let mut mask = pwm.run();
499 mask.set(Self::MASK, run);
500 pwm.set_run(mask);
501 }
502}
503
504/// PWM clock prescaler.
505///
506/// Affects all timing, except for the glitch filters.
507#[derive(Debug, Clone, Copy, PartialEq, Eq)]
508#[repr(u16)]
509pub enum Prescaler {
510 /// Divide the PWM clock by 1.
511 Prescaler1,
512 /// Divide the PWM clock by 2.
513 Prescaler2,
514 /// Divide the PWM clock by 4.
515 Prescaler4,
516 /// Divide the PWM clock by 8.
517 Prescaler8,
518 /// Divide the PWM clock by 16.
519 Prescaler16,
520 /// Divide the PWM clock by 32.
521 Prescaler32,
522 /// Divide the PWM clock by 64.
523 Prescaler64,
524 /// Divide the PWM clock by 128.
525 Prescaler128,
526}
527
528impl Prescaler {
529 /// Returns the prescalar value as a divisor.
530 pub const fn divider(self) -> u32 {
531 1 << self as u32
532 }
533}
534
535/// Describes how PWM channels A and B operate.
536#[derive(Debug, Clone, Copy, PartialEq, Eq)]
537#[repr(u16)]
538pub enum PairOperation {
539 /// A and B form a complementary pair.
540 Complementary,
541 /// A and B operate independently.
542 Independent,
543}
544
545/// PWM input clock selection.
546#[derive(Debug, Clone, Copy, PartialEq, Eq)]
547#[repr(u16)]
548pub enum ClockSelect {
549 /// Derive from the IPG clock.
550 Ipg,
551 /// Use EXT_CLK, an external clock.
552 External,
553 /// Use submodule 0's clock.
554 ///
555 /// The clock is controlled by SM0's run bit. It's
556 /// affected by the SM0 prescaler.
557 ///
558 /// You cannot use this clock for submodule 0 itself.
559 Submodule0,
560}
561
562/// PWM (re)load mode.
563///
564/// Use the associated methods to simply define `ReloadCycle`
565/// values.
566#[derive(Debug, Clone, Copy, PartialEq, Eq)]
567pub enum LoadMode {
568 /// Reload on the next cycle after `LDOK` is set.
569 ///
570 /// One of these should be set. You may set both
571 /// to increase the reload opportunity frequency.
572 ReloadCycle {
573 /// Reload on a full cycle (VAL1 compares).
574 full: bool,
575 /// Reload on a half cycle (VAL0 compares).
576 half: bool,
577 },
578 /// Reload immediately after `LDOK` is set.
579 Immediate,
580}
581
582impl LoadMode {
583 /// Full reload cycle.
584 pub const fn reload_full() -> Self {
585 Self::ReloadCycle {
586 full: true,
587 half: false,
588 }
589 }
590 /// Half reload cycle.
591 pub const fn reload_half() -> Self {
592 Self::ReloadCycle {
593 full: false,
594 half: true,
595 }
596 }
597 /// Full and half reload cycle.
598 pub const fn reload_both() -> Self {
599 Self::ReloadCycle {
600 full: true,
601 half: true,
602 }
603 }
604}
605
606bitflags::bitflags! {
607 /// Status register flags.
608 pub struct Status : u16 {
609 /// Registers updated flag.
610 ///
611 /// This read-only flag is set to 1 when there's a
612 /// buffered value that the hardware will load on
613 /// the next LDOK assertion. Use this flag to know
614 /// if there is data in a buffered register.
615 const REGISTER_UPDATED = 1 << 14;
616 /// Reload error flag.
617 ///
618 /// Set when a reload cycle passed, there's something
619 /// in the buffered registers, and LDOK was 0. Cleared
620 /// by writing 1.
621 const RELOAD_ERROR = 1 << 13;
622 /// Reload flag.
623 ///
624 /// Set at the beginning of every reload cycle, regardless
625 /// of LDOK. Cleared by writing 1.
626 const RELOAD = 1 << 12;
627
628 /// VAL5 compared to the counter value.
629 const COMPARE_VAL5 = 1 << 5;
630 /// VAL4 compared to the counter value.
631 const COMPARE_VAL4 = 1 << 4;
632 /// VAL3 compared to the counter value.
633 const COMPARE_VAL3 = 1 << 3;
634 /// VAL2 compared to the counter value.
635 const COMPARE_VAL2 = 1 << 2;
636 /// VAL1 compared to the counter value.
637 const COMPARE_VAL1 = 1 << 1;
638 /// VAL0 compared to the counter value.
639 const COMPARE_VAL0 = 1 << 0;
640 }
641}
642
643impl Status {
644 /// The set of write-1-clear status bits.
645 pub const W1C: Status = Self::REGISTER_UPDATED.complement();
646}
647
648bitflags::bitflags! {
649 /// Interrupt flags.
650 pub struct Interrupts : u16 {
651 /// Reload error interrupt enable.
652 const RELOAD_ERROR = 1 << 13;
653 /// Reload interrupt enable.
654 const RELOAD = 1 << 12;
655
656 /// VAL5 compare interrupt enable.
657 const COMPARE_VAL5 = 1 << 5;
658 /// VAL4 compare interrupt enable.
659 const COMPARE_VAL4 = 1 << 4;
660 /// VAL3 compare interrupt enable.
661 const COMPARE_VAL3 = 1 << 3;
662 /// VAL2 compare interrupt enable.
663 const COMPARE_VAL2 = 1 << 2;
664 /// VAL1 compare interrupt enable.
665 const COMPARE_VAL1 = 1 << 1;
666 /// VAL0 compare interrupt enable.
667 const COMPARE_VAL0 = 1 << 0;
668 }
669}
670
671/// PWM value registers.
672///
673/// These value registers describe when PWM counters reset, and when outputs
674/// turn on and off. Consider using more descriptive constants, enums, and
675/// const functions to describe these values.
676#[derive(Debug, Clone, Copy, PartialEq, Eq)]
677pub enum ValueRegister {
678 /// The [`HALF_RELOAD_VALUE_REGISTER`].
679 Val0,
680 /// The [`FULL_RELOAD_VALUE_REGISTER`].
681 Val1,
682 /// The [`turn_on()`] register for [`Channel::A`].
683 Val2,
684 /// The [`turn_off()`] register for [`Channel::A`].
685 Val3,
686 /// The [`turn_on()`] register for [`Channel::B`].
687 Val4,
688 /// The [`turn_off()`] register for [`Channel::B`].
689 Val5,
690}
691
692/// The full reload value register.
693///
694/// When this register compares to the counter value, the counter
695/// resets.
696pub const FULL_RELOAD_VALUE_REGISTER: ValueRegister = ValueRegister::Val1;
697/// The half reload value register.
698///
699/// When this register compares to the counter value, it represents
700/// a half reload opportunity.
701pub const HALF_RELOAD_VALUE_REGISTER: ValueRegister = ValueRegister::Val0;
702
703/// Returns the "turn on" value register for an output channel.
704///
705/// When the counter compares to this value register, the PWM output
706/// turns on.
707pub const fn turn_on(channel: Channel) -> ValueRegister {
708 match channel {
709 Channel::A => ValueRegister::Val2,
710 Channel::B => ValueRegister::Val4,
711 }
712}
713
714/// Returns the "turn off" value register for an output channel.
715///
716/// When the counter compares to this value register, the PWM output
717/// turns off.
718pub const fn turn_off(channel: Channel) -> ValueRegister {
719 match channel {
720 Channel::A => ValueRegister::Val3,
721 Channel::B => ValueRegister::Val5,
722 }
723}
724
725/// PWM channels.
726#[derive(Debug, Clone, Copy, PartialEq, Eq)]
727pub enum Channel {
728 /// Channel A.
729 A,
730 /// Channel B.
731 B,
732}