esp_hal/pcnt/
mod.rs

1//! # Pulse Counter (PCNT)
2//!
3//! ## Overview
4//! The PCNT module is designed to count the number of rising
5//! and/or falling edges of input signals. They may contain multiple pulse
6//! counter units in the module. Each unit is in effect an independent counter
7//! with multiple channels, where each channel can increment/decrement the
8//! counter on a rising/falling edge. Furthermore, each channel can be
9//! configured separately.
10//!
11//! It consists of two main modules:
12//!    * [channel]
13//!    * [unit]
14//!
15//! ## Examples
16//! ### Decoding a quadrature encoder
17//!
18//! ```rust, no_run
19#![doc = crate::before_snippet!()]
20//! # use esp_hal::gpio::{Input, InputConfig, Pull};
21//! # use esp_hal::interrupt::Priority;
22//! # use esp_hal::pcnt::{channel, unit, Pcnt};
23//! # use core::{sync::atomic::Ordering, cell::RefCell, cmp::min};
24//! # use critical_section::Mutex;
25//! # use portable_atomic::AtomicI32;
26//!
27//! static UNIT0: Mutex<RefCell<Option<unit::Unit<'static, 1>>>> =
28//! Mutex::new(RefCell::new(None)); static VALUE: AtomicI32 = AtomicI32::new(0);
29//!
30//! // Initialize Pulse Counter (PCNT) unit with limits and filter settings
31//! let mut pcnt = Pcnt::new(peripherals.PCNT);
32//! pcnt.set_interrupt_handler(interrupt_handler);
33//! let u0 = pcnt.unit1;
34//! u0.set_low_limit(Some(-100))?;
35//! u0.set_high_limit(Some(100))?;
36//! u0.set_filter(Some(min(10u16 * 80, 1023u16)))?;
37//! u0.clear();
38//!
39//! // Set up channels with control and edge signals
40//! let ch0 = &u0.channel0;
41//! let config = InputConfig::default().with_pull(Pull::Up);
42//! let pin_a = Input::new(peripherals.GPIO4, config);
43//! let pin_b = Input::new(peripherals.GPIO5, config);
44//! let (input_a, _) = pin_a.split();
45//! let (input_b, _) = pin_b.split();
46//! ch0.set_ctrl_signal(input_a.clone());
47//! ch0.set_edge_signal(input_b.clone());
48//! ch0.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep);
49//! ch0.set_input_mode(channel::EdgeMode::Increment,
50//! channel::EdgeMode::Decrement);
51//!
52//! let ch1 = &u0.channel1;
53//! ch1.set_ctrl_signal(input_b);
54//! ch1.set_edge_signal(input_a);
55//! ch1.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep);
56//! ch1.set_input_mode(channel::EdgeMode::Decrement,
57//! channel::EdgeMode::Increment);
58//!
59//! // Enable interrupts and resume pulse counter unit
60//! u0.listen();
61//! u0.resume();
62//! let counter = u0.counter.clone();
63//!
64//! critical_section::with(|cs| UNIT0.borrow_ref_mut(cs).replace(u0));
65//!
66//! // Monitor counter value and print updates
67//! let mut last_value: i32 = 0;
68//! loop {
69//!     let value: i32 = counter.get() as i32 + VALUE.load(Ordering::SeqCst);
70//!     if value != last_value {
71//!         last_value = value;
72//!     }
73//! }
74//!
75//! #[handler(priority = Priority::Priority2)]
76//! fn interrupt_handler() {
77//!     critical_section::with(|cs| {
78//!         let mut u0 = UNIT0.borrow_ref_mut(cs);
79//!         if let Some(u0) = u0.as_mut() {
80//!             if u0.interrupt_is_set() {
81//!                 let events = u0.events();
82//!                 if events.high_limit {
83//!                     VALUE.fetch_add(100, Ordering::SeqCst);
84//!                 } else if events.low_limit {
85//!                     VALUE.fetch_add(-100, Ordering::SeqCst);
86//!                 }
87//!                 u0.reset_interrupt();
88//!             }
89//!         }
90//!     });
91//! }
92//! # }
93//! ```
94//! 
95//! [channel]: channel/index.html
96//! [unit]: unit/index.html
97
98use self::unit::Unit;
99use crate::{
100    interrupt::{self, InterruptHandler},
101    peripheral::{Peripheral, PeripheralRef},
102    peripherals::{Interrupt, PCNT},
103    system::GenericPeripheralGuard,
104};
105
106pub mod channel;
107pub mod unit;
108
109/// Pulse Counter (PCNT) peripheral driver.
110pub struct Pcnt<'d> {
111    _instance: PeripheralRef<'d, PCNT>,
112
113    /// Unit 0
114    pub unit0: Unit<'d, 0>,
115    /// Unit 1
116    pub unit1: Unit<'d, 1>,
117    /// Unit 2
118    pub unit2: Unit<'d, 2>,
119    /// Unit 3
120    pub unit3: Unit<'d, 3>,
121    #[cfg(esp32)]
122    /// Unit 4
123    pub unit4: Unit<'d, 4>,
124    #[cfg(esp32)]
125    /// Unit 5
126    pub unit5: Unit<'d, 5>,
127    #[cfg(esp32)]
128    /// Unit 6
129    pub unit6: Unit<'d, 6>,
130    #[cfg(esp32)]
131    /// Unit 7
132    pub unit7: Unit<'d, 7>,
133
134    _guard: GenericPeripheralGuard<{ crate::system::Peripheral::Pcnt as u8 }>,
135}
136
137impl<'d> Pcnt<'d> {
138    /// Return a new PCNT
139    pub fn new(_instance: impl Peripheral<P = PCNT> + 'd) -> Self {
140        crate::into_ref!(_instance);
141
142        let guard = GenericPeripheralGuard::new();
143        let pcnt = PCNT::regs();
144
145        // disable filter, all events, and channel settings
146        for unit in pcnt.unit_iter() {
147            unit.conf0().write(|w| unsafe {
148                // All bits are accounted for in the TRM.
149                w.bits(0)
150            });
151        }
152
153        // Remove reset bit from units.
154        pcnt.ctrl().modify(|_, w| {
155            #[cfg(not(esp32))]
156            let unit_count = 4;
157            #[cfg(esp32)]
158            let unit_count = 8;
159
160            for i in 0..unit_count {
161                w.cnt_rst_u(i).clear_bit();
162            }
163
164            w.clk_en().set_bit()
165        });
166
167        Pcnt {
168            _instance,
169            unit0: Unit::new(),
170            unit1: Unit::new(),
171            unit2: Unit::new(),
172            unit3: Unit::new(),
173            #[cfg(esp32)]
174            unit4: Unit::new(),
175            #[cfg(esp32)]
176            unit5: Unit::new(),
177            #[cfg(esp32)]
178            unit6: Unit::new(),
179            #[cfg(esp32)]
180            unit7: Unit::new(),
181            _guard: guard,
182        }
183    }
184
185    /// Set the interrupt handler for the PCNT peripheral.
186    ///
187    /// Note that this will replace any previously registered interrupt
188    /// handlers.
189    #[instability::unstable]
190    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
191        for core in crate::system::Cpu::other() {
192            crate::interrupt::disable(core, Interrupt::PCNT);
193        }
194        unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) };
195        unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority()));
196    }
197}
198
199impl crate::private::Sealed for Pcnt<'_> {}
200
201#[instability::unstable]
202impl crate::interrupt::InterruptConfigurable for Pcnt<'_> {
203    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
204        self.set_interrupt_handler(handler);
205    }
206}