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.peripheral_input();
45//! let input_b = pin_b.peripheral_input();
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    peripherals::{Interrupt, PCNT},
102    system::GenericPeripheralGuard,
103};
104
105pub mod channel;
106pub mod unit;
107
108/// Pulse Counter (PCNT) peripheral driver.
109pub struct Pcnt<'d> {
110    _instance: PCNT<'d>,
111
112    /// Unit 0
113    pub unit0: Unit<'d, 0>,
114    /// Unit 1
115    pub unit1: Unit<'d, 1>,
116    /// Unit 2
117    pub unit2: Unit<'d, 2>,
118    /// Unit 3
119    pub unit3: Unit<'d, 3>,
120    #[cfg(esp32)]
121    /// Unit 4
122    pub unit4: Unit<'d, 4>,
123    #[cfg(esp32)]
124    /// Unit 5
125    pub unit5: Unit<'d, 5>,
126    #[cfg(esp32)]
127    /// Unit 6
128    pub unit6: Unit<'d, 6>,
129    #[cfg(esp32)]
130    /// Unit 7
131    pub unit7: Unit<'d, 7>,
132
133    _guard: GenericPeripheralGuard<{ crate::system::Peripheral::Pcnt as u8 }>,
134}
135
136impl<'d> Pcnt<'d> {
137    /// Return a new PCNT
138    pub fn new(_instance: PCNT<'d>) -> Self {
139        let guard = GenericPeripheralGuard::new();
140        let pcnt = PCNT::regs();
141
142        // disable filter, all events, and channel settings
143        for unit in pcnt.unit_iter() {
144            unit.conf0().write(|w| unsafe {
145                // All bits are accounted for in the TRM.
146                w.bits(0)
147            });
148        }
149
150        // Remove reset bit from units.
151        pcnt.ctrl().modify(|_, w| {
152            #[cfg(not(esp32))]
153            let unit_count = 4;
154            #[cfg(esp32)]
155            let unit_count = 8;
156
157            for i in 0..unit_count {
158                w.cnt_rst_u(i).clear_bit();
159            }
160
161            w.clk_en().set_bit()
162        });
163
164        Pcnt {
165            _instance,
166            unit0: Unit::new(),
167            unit1: Unit::new(),
168            unit2: Unit::new(),
169            unit3: Unit::new(),
170            #[cfg(esp32)]
171            unit4: Unit::new(),
172            #[cfg(esp32)]
173            unit5: Unit::new(),
174            #[cfg(esp32)]
175            unit6: Unit::new(),
176            #[cfg(esp32)]
177            unit7: Unit::new(),
178            _guard: guard,
179        }
180    }
181
182    /// Set the interrupt handler for the PCNT peripheral.
183    ///
184    /// Note that this will replace any previously registered interrupt
185    /// handlers.
186    #[instability::unstable]
187    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
188        for core in crate::system::Cpu::other() {
189            crate::interrupt::disable(core, Interrupt::PCNT);
190        }
191        unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) };
192        unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority()));
193    }
194}
195
196impl crate::private::Sealed for Pcnt<'_> {}
197
198#[instability::unstable]
199impl crate::interrupt::InterruptConfigurable for Pcnt<'_> {
200    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
201        self.set_interrupt_handler(handler);
202    }
203}