esp_hal/pcnt/
mod.rs

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
//! # Pulse Counter (PCNT)
//!
//! ## Overview
//! The PCNT module is designed to count the number of rising
//! and/or falling edges of input signals. They may contain multiple pulse
//! counter units in the module. Each unit is in effect an independent counter
//! with multiple channels, where each channel can increment/decrement the
//! counter on a rising/falling edge. Furthermore, each channel can be
//! configured separately.
//!
//! It consists of two main modules:
//!    * [channel]
//!    * [unit]
//!
//! ## Examples
//! ### Decoding a quadrature encoder
//! Visit the [PCNT Encoder] example for an example of using the peripheral.
//!
//! [channel]: channel/index.html
//! [unit]: unit/index.html
//! [PCNT Encoder]: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/pcnt_encoder.rs

use self::unit::Unit;
use crate::{
    interrupt::{self, InterruptHandler},
    peripheral::{Peripheral, PeripheralRef},
    peripherals::{self, Interrupt},
    system::PeripheralClockControl,
    InterruptConfigurable,
};

pub mod channel;
pub mod unit;

/// Pulse Counter (PCNT) peripheral driver.
pub struct Pcnt<'d> {
    _instance: PeripheralRef<'d, peripherals::PCNT>,

    /// Unit 0
    pub unit0: Unit<'d, 0>,
    /// Unit 1
    pub unit1: Unit<'d, 1>,
    /// Unit 2
    pub unit2: Unit<'d, 2>,
    /// Unit 3
    pub unit3: Unit<'d, 3>,
    #[cfg(esp32)]
    /// Unit 4
    pub unit4: Unit<'d, 4>,
    #[cfg(esp32)]
    /// Unit 5
    pub unit5: Unit<'d, 5>,
    #[cfg(esp32)]
    /// Unit 6
    pub unit6: Unit<'d, 6>,
    #[cfg(esp32)]
    /// Unit 7
    pub unit7: Unit<'d, 7>,
}

impl<'d> Pcnt<'d> {
    /// Return a new PCNT
    pub fn new(_instance: impl Peripheral<P = peripherals::PCNT> + 'd) -> Self {
        crate::into_ref!(_instance);

        // Enable the PCNT peripherals clock in the system peripheral
        PeripheralClockControl::reset(crate::system::Peripheral::Pcnt);
        PeripheralClockControl::enable(crate::system::Peripheral::Pcnt);

        let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };

        // disable filter, all events, and channel settings
        for unit in pcnt.unit_iter() {
            unit.conf0().write(|w| unsafe {
                // All bits are accounted for in the TRM.
                w.bits(0)
            });
        }

        // Remove reset bit from units.
        pcnt.ctrl().modify(|_, w| {
            #[cfg(not(esp32))]
            let unit_count = 4;
            #[cfg(esp32)]
            let unit_count = 8;

            for i in 0..unit_count {
                w.cnt_rst_u(i).clear_bit();
            }

            w.clk_en().set_bit()
        });

        Pcnt {
            _instance,
            unit0: Unit::new(),
            unit1: Unit::new(),
            unit2: Unit::new(),
            unit3: Unit::new(),
            #[cfg(esp32)]
            unit4: Unit::new(),
            #[cfg(esp32)]
            unit5: Unit::new(),
            #[cfg(esp32)]
            unit6: Unit::new(),
            #[cfg(esp32)]
            unit7: Unit::new(),
        }
    }
}

impl crate::private::Sealed for Pcnt<'_> {}

impl InterruptConfigurable for Pcnt<'_> {
    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
        for core in crate::Cpu::other() {
            crate::interrupt::disable(core, Interrupt::PCNT);
        }
        unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) };
        unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority()));
    }
}