1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
//! General Purpose Timer (GPT)
//!
//! # Features
//!
//! The GPTs are count-up, wrapping timers that run off of the IPG clock or the
//! crystal oscillator (24MHz). Each GPT has three compare registers,
//! called **output comparison registers (OCR)**. When the counter reaches a
//! value in an OCR, the GPT signals the comparison through status flags.
//! A comparison can generate an interrupt.
//!
//! Use GPTs to
//!
//! - detect if a timing interval has elapsed
//! - trigger an interrupt when an interval elapses
//! - measure code execution
//!
//! # GPT modes
//!
//! The table below summarizes the effects of an output comparison operation
//! when in restart mode, and when in free-running mode. See the subsequent
//! sections for a discussion of the two modes.
//!
//! | GPT Mode     | OCR1                                      | OCR2                                      | OCR3         |
//! | ------------ | ----------------------------------------- | ----------------------------------------- | ------------ |
//! | Restart      | Resets the counter to zero                | No effect; counter continues incrementing | No effect... |
//! | Free-running | No effect; counter continues incrementing | No effect ...                             | No effect... |
//!
//! In summary, **OCR1 is special in restart mode**, as it will reset the value in the GPT counter.
//!
//! Select a mode with [`set_mode()`](struct.GPT.html#method.set_mode).
//!
//! ## Restart mode
//!
//! The GPTs default to 'restart mode.' In restart mode, a compare on **channel
//! 1** will reset the GPT counter to zero. Compare events on channels 2 and 3
//! will not reset the GPT counter. If you would rather have the GPT counter continue
//! no matter the comparison event, set the GPT to free-running mode.
//!
//! ## Free-running mode
//!
//! The GPTs may be in free-running mode. When a comparion event occurs in free-running
//! mode, the counter continues to increment, eventually wrapping around. Free-running
//! mode treats all channels as equal; that is, channel 1 is no different than channel
//! 2 or 3.
//!
//! # Reset on enable
//!
//! Reset on enable is a complementary feature to the two modes. When reset on enable
//! is active, the GPT counter will reset to zero each time the timer is enabled. By default,
//! the counter will restart at whatever value is currently in the counter. The default
//! behavior lets a user 'pause' the counter by disabling the GPT. On the other hand,
//! reset on enable lets users reset the counter by disabling and re-enabling the GPT.
//!
//! The table below summarizes the 'reset on enable' behaviors. Use
//! [`set_reset_on_enable()`](struct.GPT.html#method.set_reset_on_enable) to configure
//! the reset on enable behavior.
//!
//! | State   | Behavior                                                 |
//! | ------- | -------------------------------------------------------- |
//! | `false` | When the GPT is disabled, it maintains its counter value |
//! | `true`  | When the GPT is disabled, the counter resets to zero     |
//!
//! # GPTs and system WAIT / STOP
//!
//! By default, GPTs do not run when the process is in in wait mode. Use
//! [`set_wait_mode_enable(true)`](struct.GPT.html#method.set_wait_mode_enable)
//! to enable GPTs in wait mode.
//!
//! If the GPT stops counting in WAIT / STOP system states, the counter freezes its
//! counter. When the processor transitions into RUNNING, the counter increments from
//! its previously-frozen value (provided the GPT was enabled).
//!
//! # `embedded_hal` implementations
//!
//! The module provides adapters that pair a GPT with an OCR. The
//! adapters implement the `embedded_hal` timers using the GPT and the OCR
//! Users must ensure that the selected mode is suitable for the behaviors of the adapters.
//!
//! The two adapters include
//!
//! - [`CountDown`](struct.CountDown.html), which implements the `CountDown` trait
//! - [`Periodic`](struct.Periodic.html), which implements the `Periodic` trait
//!
//! Although the adapters work on a single OCR, the timer may continue to monitor the
//! other two OCRs.
//!
//! # Example
//!
//! ```no_run
//! use imxrt_hal;
//!
//! let mut peripherals = imxrt_hal::Peripherals::take().unwrap();
//!
//! let (_, ipg_hz) = peripherals.ccm.pll1.set_arm_clock(
//!     imxrt_hal::ccm::PLL1::ARM_HZ,
//!     &mut peripherals.ccm.handle,
//!     &mut peripherals.dcdc,
//! );
//!
//! let mut cfg = peripherals.ccm.perclk.configure(
//!     &mut peripherals.ccm.handle,
//!     imxrt_hal::ccm::perclk::PODF::DIVIDE_3,
//!     imxrt_hal::ccm::perclk::CLKSEL::IPG(ipg_hz),
//! );
//!
//! let mut gpt1 = peripherals.gpt1.clock(&mut cfg);
//!
//! gpt1.set_output_interrupt_on_compare(
//!     imxrt_hal::gpt::OutputCompareRegister::Three,
//!     true,
//! );
//! gpt1.set_wait_mode_enable(true);
//! gpt1.set_mode(imxrt_hal::gpt::Mode::FreeRunning);
//!
//! gpt1.set_output_compare_duration(
//!     imxrt_hal::gpt::OutputCompareRegister::Three,
//!     core::time::Duration::from_micros(765),
//! );
//! ```
//!
//! # TODO
//!
//! - Input capture. Each GPT can capture the value of the counter
//!   when a pin state changes. When the pin state changes, the
//!   GPT can generate an interrupt.
//! - Output generation. When one of the three comparison registers
//!   match the counter, the GPT can generate a signal on an output
//!   pin.

use crate::{
    ccm::{perclk, ticks},
    ral,
};

use core::time::Duration;

/// An unclocked GPT
///
/// Each GPT starts in an unclocked state. By supplying
/// a proper clock configuration, the GPT will clock
/// itself and prepare for operation.
pub struct Unclocked {
    registers: ral::gpt::Instance,
    instance: Instance,
}

/// GPT instance
///
/// Used for runtime selection of GPT-specific configurations
enum Instance {
    One,
    Two,
}

/// Prescaler applied to each GPT's input clock.
///
/// See comments at usage for justification.
const DEFAULT_PRESCALER: u32 = 2;

/// A general purpose timer
///
/// The timers support three output compare registers. When a compare register
/// matches the value of the counter, the GPT may trigger an interrupt.
///
/// By default, the timer runs in wait mode.
pub struct GPT {
    /// Registers for this GPT instance
    registers: ral::gpt::Instance,
    /// The effective clock frequency that controls
    /// the counter.
    ///
    /// The value accounts for all prescalers and dividers.
    clock_hz: u32,
}

impl Unclocked {
    /// Create an unclocked GPT1
    pub(crate) fn one(registers: ral::gpt::Instance) -> Self {
        Unclocked {
            registers,
            instance: Instance::One,
        }
    }

    /// Create an unclocked GPT2
    pub(crate) fn two(registers: ral::gpt::Instance) -> Self {
        Unclocked {
            registers,
            instance: Instance::Two,
        }
    }

    /// Enable the clocks to the GPT, returning a GPT timer
    ///
    /// `configured` is a handle describing the clocks and clock
    /// configuration for the GPT. See the `ccm` module for more
    /// information.
    pub fn clock(self, configured: &mut perclk::Configured) -> GPT {
        let (freq, div) = match self.instance {
            Instance::One => configured.enable_gpt1_clock_gates(),
            Instance::Two => configured.enable_gpt2_clock_gates(),
        };

        match configured.clock_selection() {
            perclk::CLKSEL::OSC => {
                ral::write_reg!(
                    ral::gpt,
                    self.registers,
                    CR,
                    EN_24M: 1, // Enable crystal oscillator
                    CLKSRC: 0b101 // Crystal Oscillator
                );
                // The 24MHz prescaler register can't be non-zero. Not sure why.
                // The reference manual says its OK, but it doesn't work. The
                // se4L project noted the same issue in their kernel.
                // So, this means that there's a divider of 2 when using the
                // crystal oscillator.
                ral::write_reg!(ral::gpt, self.registers, PR, PRESCALER24M: (DEFAULT_PRESCALER - 1));
            }
            perclk::CLKSEL::IPG(_) => {
                ral::write_reg!(
                    ral::gpt,
                    self.registers,
                    CR,
                    EN_24M: 0, // No crystal oscillator
                    CLKSRC: 0b001 // Peripheral Clock
                );
                // See the above comment about needing a prescaler for the other
                // clock. This is for consistency, so that we can implement the
                // "divide by two" behavior.
                ral::write_reg!(ral::gpt, self.registers, PR, PRESCALER: (DEFAULT_PRESCALER - 1));
            }
        }

        // Clear all statuses
        ral::write_reg!(ral::gpt, self.registers, SR, 0b11_1111);

        GPT {
            registers: self.registers,
            clock_hz: (freq / div).0 / DEFAULT_PRESCALER,
        }
    }
}

/// An output compare register (OCR)
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum OutputCompareRegister {
    One,
    Two,
    Three,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Possible modes of the GPT
pub enum Mode {
    /// Reset mode
    ///
    /// A comparions event on channel 1 will reset the GPT counter.
    /// Comparison events on channels 2 and 3 do not reset the counter.
    Reset,
    /// Free running mode
    ///
    /// Comparisons on channel 1 are treated like comparions on channels
    /// 2 and 3. The counter continues to increment on comparison.
    FreeRunning,
}

impl GPT {
    /// Returns the current mode of the GPT
    pub fn mode(&self) -> Mode {
        if ral::read_reg!(ral::gpt, self.registers, CR, FRR == 0) {
            Mode::Reset
        } else {
            Mode::FreeRunning
        }
    }

    /// Set the GPT mode
    ///
    /// Refer to the module level documentation for more information on the GPT modes.
    pub fn set_mode(&mut self, mode: Mode) {
        ral::modify_reg!(ral::gpt, self.registers, CR, FRR: (mode as u32))
    }

    /// Set the reset on enable behavior
    ///
    /// See the module level docs for more information.
    pub fn set_reset_on_enable(&mut self, reset_on_enable: bool) {
        ral::modify_reg!(ral::gpt, self.registers, CR, ENMOD: (reset_on_enable as u32));
    }

    /// Returns `true` if the GPT counter will reset the next time it is enabled
    pub fn reset_on_enable(&self) -> bool {
        ral::read_reg!(ral::gpt, self.registers, CR, ENMOD == 1)
    }

    /// Enable or disable the GPT
    ///
    /// When enabled, the counter starts counting. When disabled, the counter will
    /// stop counting.
    pub fn set_enable(&mut self, enable: bool) {
        ral::modify_reg!(ral::gpt, self.registers, CR, EN: (enable as u32));
    }

    /// Indicates if the GPT is enabled (`true`) or disabled (`false`).
    pub fn enabled(&self) -> bool {
        ral::read_reg!(ral::gpt, self.registers, CR, EN == 1)
    }

    /// Allow the GPT to run in wait mode; or, prevent the GPT from running
    /// in wait mode.
    pub fn set_wait_mode_enable(&mut self, wait: bool) {
        ral::modify_reg!(ral::gpt, self.registers, CR, WAITEN: (wait as u32));
    }

    /// Indicates if the GPT runs while in wait mode
    pub fn wait_mode_enabled(&self) -> bool {
        ral::read_reg!(ral::gpt, self.registers, CR, WAITEN == 1)
    }

    /// Enable the GPT interrupt when the output compares
    pub fn set_output_interrupt_on_compare(&mut self, output: OutputCompareRegister, intr: bool) {
        let ir: u32 = ral::read_reg!(ral::gpt, self.registers, IR);
        let ir: u32 = if intr {
            ir | (1 << (output as u32))
        } else {
            ir & !(1 << (output as u32))
        };
        ral::write_reg!(ral::gpt, self.registers, IR, ir);
    }

    /// Returns `true` if a comparison triggers an interrupt
    pub fn output_interrupt_on_compare(&self, output: OutputCompareRegister) -> bool {
        ral::read_reg!(ral::gpt, self.registers, IR) & (1 << (output as u32)) != 0
    }

    /// Returns the current count of the GPT
    pub fn count(&self) -> u32 {
        ral::read_reg!(ral::gpt, self.registers, CNT)
    }

    /// Set an output compare register to trigger on the next `count` value of the
    /// counter.
    pub fn set_output_compare_count(&mut self, output: OutputCompareRegister, count: u32) {
        match output {
            OutputCompareRegister::One => ral::write_reg!(ral::gpt, self.registers, OCR1, count),
            OutputCompareRegister::Two => ral::write_reg!(ral::gpt, self.registers, OCR2, count),
            OutputCompareRegister::Three => ral::write_reg!(ral::gpt, self.registers, OCR3, count),
        }
    }

    /// Returns the current output compare count for the specified register
    pub fn output_compare_count(&self, output: OutputCompareRegister) -> u32 {
        match output {
            OutputCompareRegister::One => ral::read_reg!(ral::gpt, self.registers, OCR1),
            OutputCompareRegister::Two => ral::read_reg!(ral::gpt, self.registers, OCR2),
            OutputCompareRegister::Three => ral::read_reg!(ral::gpt, self.registers, OCR3),
        }
    }

    /// Set an output compare register to trigger when the specified duration elapses
    ///
    /// This is a convenience for an operation that resembles
    ///
    /// 1. compute the number of counts represented in the duration, based on the clock frequency
    /// 2. acquire the current GPT count
    /// 3. add the number of counts from 1 to the count of 2, accounting for wrap-around
    /// 4. set the value for the OCR
    pub fn set_output_compare_duration(
        &mut self,
        output: OutputCompareRegister,
        duration: Duration,
    ) {
        let counts: u32 = ticks(duration, self.clock_hz, 1).unwrap_or(u32::max_value());
        let next_count = self.count().wrapping_add(counts);
        self.set_output_compare_count(output, next_count);
    }

    /// Returns a handle that can query and modify the output compare status for the provided output
    pub fn output_compare_status(&mut self, output: OutputCompareRegister) -> OutputCompareStatus {
        OutputCompareStatus { gpt: self, output }
    }

    /// Returns the clock period as a duration
    ///
    /// This represents the resolution of the clock. The maximum measurement
    /// interval is `clock_period() * u32::max_value()`.
    pub fn clock_period(&self) -> Duration {
        Duration::from_nanos((1_000_000_000u32 / self.clock_hz).into())
    }

    /// Measure the execution time of an action `act` using the GPT. Returns
    /// the result of the action, along with how long it took to execute the
    /// action.
    ///
    /// User must ensure that the timer is enabled. Otherwise, the resulting
    /// duration is zero.
    ///
    /// User must ensure that the action takes less time than it takes for the
    /// timer to wrap around. We cannot distinguish a wrapped-around counter
    /// from an incrementing counter with this implementation. Consider using
    /// `time_no_overflow` if you need a better guarantee.
    pub fn time<F: FnOnce() -> R, R>(&self, act: F) -> (R, Duration) {
        let start = self.count();
        let result = act();
        let end = self.count();
        let counts = end.wrapping_sub(start);
        (result, counts * self.clock_period())
    }

    /// Time an operation, returning the result, and the amount of time the
    /// operation took.
    ///
    /// Unlike `time()`, `time_no_overflow()` uses an output compare register to check if the
    /// counter overflowed. It requires a mutable GPT, since we need to
    /// disable the timer and modify compare registers to properly measure the interval.
    /// If the timer wrapped around, the return is `None`.
    ///
    /// When `time_no_overflow()` returns,
    ///
    /// - the GPT is disabled
    /// - the interrupt on compare for the output is disabled
    /// - the compare value in the specified output compare register is undefined
    ///
    /// Users are responsible for resetting the state of the GPT as needed.
    ///
    /// Users are responsible for enabling the GPT before using `time_no_overflow()`.
    /// Otherwise, the returned duration is non-`None`, but zero.
    ///
    /// If you know that you're measuring short intervals that will not overflow the
    /// counter, consider using `time()`.
    pub fn time_no_overflow<F: FnOnce() -> R, R>(
        &mut self,
        output: OutputCompareRegister,
        act: F,
    ) -> (R, Option<Duration>) {
        self.set_enable(false);
        self.set_output_interrupt_on_compare(output, false);

        let start = self.count();
        // Set the compare to trigger if the counter elapses the wrapped start time.
        // This is how we know that the timer overflowed.
        self.set_output_compare_count(output, start.wrapping_sub(1));
        self.set_enable(true);
        let result = act();
        // We can read the count faster than we can disable the peripheral.
        let end = self.count();
        self.set_enable(false);

        let mut status = self.output_compare_status(output);
        if status.is_set() {
            status.clear();
            // Compare triggered, so we don't actually know how long this
            // took.
            (result, None)
        } else {
            let counts = end.wrapping_sub(start);
            (result, Some(counts * self.clock_period()))
        }
    }

    /// Returns an adapter that implements the count down trait
    ///
    /// Assumes that the timer is already enabled. Otherwise, the
    /// count down adapter will block forever. The adapter will never
    /// disable the counter, so the borrowed GPT may still track other
    /// times while it is borrowed.
    ///
    /// The adapter assumes the current GPT's mode. User is responsible
    /// for making sure that this mode is sensible for the qualities of
    /// the timer.
    pub fn count_down(&mut self, output: OutputCompareRegister) -> CountDown {
        CountDown(Timer::oneshot(self, output))
    }

    /// Returns an adapter that implements the periodic trait
    ///
    /// Assumes that the timer is already enabled. Otherwise, the
    /// periodic adapter will block forever. The adapter will never
    /// disable the counter. so the borrowed GPT may still track other
    /// times while it is borrowed.
    ///
    /// The adapter assumes the current GPT's mode. User is responsible for
    /// making sure this mode is sensible for the qualities of the timer.
    pub fn periodic(&mut self, output: OutputCompareRegister) -> Periodic {
        Periodic(Timer::periodic(self, output))
    }

    /// Enable / disable an interrupt when the GPT counter rolls over from `u32::max_value()` to
    /// `0`
    ///
    /// The GPT triggers a rollover regardless of the GPT mode.
    pub fn set_rollover_interrupt(&mut self, rov: bool) {
        ral::modify_reg!(ral::gpt, self.registers, IR, ROVIE: (rov as u32));
    }

    /// Returns `true` if a rollover generates an interrupt
    pub fn rollover_interrupt(&self) -> bool {
        ral::read_reg!(ral::gpt, self.registers, IR, ROVIE == 1)
    }

    /// Returns `true` if the rollover flag is set
    ///
    /// A rollover occurs when the counter rolls over from `u32::max_value()` to `0`. Rollover
    /// may occur regardless of the GPT mode.
    pub fn rollover(&self) -> bool {
        ral::read_reg!(ral::gpt, self.registers, SR, ROV == 1)
    }

    /// Clear the rollover status flag
    ///
    /// Users must clear the rollover flag if a rollover triggered an interrupt.
    pub fn clear_rollover(&self) {
        ral::write_reg!(ral::gpt, self.registers, SR, ROV: 1);
    }
}

/// A handle to evaluate and modify the output compare status
pub struct OutputCompareStatus<'a> {
    gpt: &'a mut GPT,
    output: OutputCompareRegister,
}

impl<'a> OutputCompareStatus<'a> {
    /// Returns true if this output compare has triggered
    pub fn is_set(&self) -> bool {
        let sr = ral::read_reg!(ral::gpt, self.gpt.registers, SR);
        sr & (1 << (self.output as u32)) != 0
    }

    /// Clear the output compare status flag
    ///
    /// It's necessary to clear the flag when the comparison has triggered
    /// an interrupt.
    pub fn clear(&mut self) {
        ral::write_reg!(ral::gpt, self.gpt.registers, SR, 1 << (self.output as u32));
    }
}

/// How the timer should behave
#[derive(PartialEq, Eq)]
enum Policy {
    /// Don't repeat
    Oneshot,
    /// Repeat with the specified duration
    Periodic(Option<Duration>),
}

/// Shared implementation for `embedded_hal` traits
struct Timer<'a> {
    gpt: &'a mut GPT,
    output: OutputCompareRegister,
    policy: Policy,
}

impl<'a> Timer<'a> {
    /// Constructs a timer that implements oneshot behavior (not periodic)
    fn oneshot(gpt: &'a mut GPT, output: OutputCompareRegister) -> Self {
        Timer {
            gpt,
            output,
            policy: Policy::Oneshot,
        }
    }

    /// Constructs a timer that implements periodic behavior
    fn periodic(gpt: &'a mut GPT, output: OutputCompareRegister) -> Self {
        Timer {
            gpt,
            output,
            policy: Policy::Periodic(None),
        }
    }

    /// Start the timer
    ///
    /// Assumes that the GPT is enabled.
    fn start(&mut self, duration: Duration) {
        self.gpt.set_output_compare_duration(self.output, duration);
        if let Policy::Periodic(ref mut period) = &mut self.policy {
            *period = Some(duration);
        }
    }

    /// Returns `Ok(())` when the timer has elapsed; otherwise, returns `Err(nb::WouldBlock)`.
    ///
    /// If the policy is periodic, we will restart the timer. If the user already observed an elapsed
    /// timer, but calls `wait()` again, the behavior is unspecified (as stated by the trait contract).
    fn wait(&mut self) -> nb::Result<(), void::Void> {
        let mut status = self.gpt.output_compare_status(self.output);
        if status.is_set() {
            status.clear();
            match self.policy {
                Policy::Oneshot | Policy::Periodic(None) => (),
                Policy::Periodic(Some(duration)) => {
                    self.gpt.set_output_compare_duration(self.output, duration)
                }
            }
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}

/// Adapter that implements [the `CountDown` trait][docs].
///
/// It mutably borrows the GPT, and it uses the supplied
/// output compare register to track time. If the GPT has
/// other compare channels that are active, those channels
/// remain active while the GPT is borrowed.
///
/// [docs]: https://docs.rs/embedded-hal/0.2.3/embedded_hal/timer/trait.CountDown.html
pub struct CountDown<'a>(Timer<'a>);

impl<'a> embedded_hal::timer::CountDown for CountDown<'a> {
    type Time = Duration;

    fn start<T: Into<Duration>>(&mut self, duration: T) {
        self.0.start(duration.into())
    }

    fn wait(&mut self) -> nb::Result<(), void::Void> {
        self.0.wait()
    }
}

/// Adapter that implements [ther `Periodic` trait][docs].
///
/// It mutably borrows the GPT, and it uses the supplied output
/// compare register to track time. If the GPT has other output
/// compare channels that are active, those channels remain active
/// while the GPT is borrowed.
///
/// [docs]: https://docs.rs/embedded-hal/0.2.3/embedded_hal/timer/trait.Periodic.html
pub struct Periodic<'a>(Timer<'a>);

impl<'a> embedded_hal::timer::CountDown for Periodic<'a> {
    type Time = Duration;

    fn start<T: Into<Duration>>(&mut self, duration: T) {
        self.0.start(duration.into())
    }

    fn wait(&mut self) -> nb::Result<(), void::Void> {
        self.0.wait()
    }
}

impl<'a> embedded_hal::timer::Periodic for Periodic<'a> {}