Skip to main content

esp_hal/pcnt/
unit.rs

1//! # PCNT - Unit Module
2//!
3//! ## Overview
4//! The `unit` module configures and operates a single pulse-counter unit.
5//! Construct a [`Unit`] from a `PCNTn_UNITm` singleton. Units can be paused,
6//! resumed, and cleared, and can listen for threshold and limit events.
7
8use crate::{
9    interrupt::{InterruptConfigurable, InterruptHandler},
10    pcnt::{AnyPcntUnit, Instance, channel::Channel},
11    system::PeripheralGuard,
12};
13
14/// Invalid filter threshold value
15#[derive(Debug, Clone, Copy, PartialEq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct InvalidFilterThreshold;
18
19/// Invalid low limit - must be < 0.
20#[derive(Debug, Clone, Copy, PartialEq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct InvalidLowLimit;
23
24/// Invalid high limit - must be > 0.
25#[derive(Debug, Clone, Copy, PartialEq)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub struct InvalidHighLimit;
28
29/// the current status of the counter.
30#[derive(Copy, Clone, Debug, Default, PartialEq)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub enum ZeroMode {
33    /// pulse counter decreases from positive to 0.
34    #[default]
35    PosZero  = 0,
36    /// pulse counter increases from negative to 0
37    NegZero  = 1,
38    /// pulse counter is negative (not implemented?)
39    Negative = 2,
40    /// pulse counter is positive (not implemented?)
41    Positive = 3,
42}
43
44impl From<u8> for ZeroMode {
45    fn from(value: u8) -> Self {
46        match value {
47            0 => Self::PosZero,
48            1 => Self::NegZero,
49            2 => Self::Negative,
50            3 => Self::Positive,
51            _ => unreachable!(),
52        }
53    }
54}
55
56/// Events that can occur in a pulse counter unit.
57#[derive(Copy, Clone, Debug, Default)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub struct Events {
60    /// Sets when the pulse counter reaches the low limit.
61    pub low_limit: bool,
62    /// Sets when the pulse counter reaches the high limit.
63    pub high_limit: bool,
64    /// Sets when the pulse counter crosses threshold 0.
65    pub threshold0: bool,
66    /// Sets when the pulse counter crosses threshold 1.
67    pub threshold1: bool,
68    /// Sets when the pulse counter reaches zero.
69    pub zero: bool,
70}
71
72/// Represents a pulse counter unit.
73#[non_exhaustive]
74pub struct Unit<'d> {
75    unit: AnyPcntUnit<'d>,
76    /// The counter for PCNT unit.
77    pub counter: Counter<'d>,
78    /// The first channel in PCNT unit.
79    pub channel0: Channel<'d, 0>,
80    /// The second channel in PCNT unit.
81    pub channel1: Channel<'d, 1>,
82    _guard: PeripheralGuard,
83}
84
85impl<'d> Unit<'d> {
86    /// Returns a new PCNT unit.
87    pub fn new(unit: impl Instance + 'd) -> Self {
88        let (info, _) = unit.parts();
89        let guard = PeripheralGuard::new(info.peripheral);
90        let unit = unit.degrade();
91
92        let regs = info.regs();
93        regs.unit(info.unit).conf0().write(|w| unsafe { w.bits(0) });
94        info.lock(|| {
95            // Make sure the counter is reset
96            regs.ctrl()
97                .modify(|_, w| w.cnt_rst_u(info.unit as u8).set_bit());
98            let bits = regs.ctrl().read().bits();
99            regs.ctrl().write(|w| {
100                unsafe { w.bits(bits) };
101                w.cnt_rst_u(info.unit as u8).clear_bit();
102                // Make sure we don't stay paused in case this is a re-created unit
103                w.cnt_pause_u(info.unit as u8).clear_bit();
104                w.clk_en().set_bit()
105            });
106        });
107
108        Self {
109            counter: Counter::new(unsafe { unit.clone_unchecked() }),
110            channel0: Channel::new(unsafe { unit.clone_unchecked() }),
111            channel1: Channel::new(unsafe { unit.clone_unchecked() }),
112            unit,
113            _guard: guard,
114        }
115    }
116
117    fn index(&self) -> u8 {
118        self.unit.info().unit as u8
119    }
120
121    /// Configures a lower limit to the count value.
122    ///
123    /// When the count drops to this value:
124    /// - A low limit interrupt is triggered.
125    /// - The count is reset to 0.
126    ///
127    /// If None is specified, then no interrupt is triggered and
128    /// the count wraps around after [i16::MIN].
129    ///
130    /// The specified value must be negative.
131    pub fn set_low_limit(&self, value: Option<i16>) -> Result<(), InvalidLowLimit> {
132        let unit = self.unit.register_block().unit(self.unit.info().unit);
133
134        if let Some(value) = value {
135            // low limit must be >= or the limit is -32768 and when that's
136            // hit the event status claims it was the high limit.
137            // tested on an esp32s3
138            if !value.is_negative() {
139                return Err(InvalidLowLimit);
140            } else {
141                unit.conf2()
142                    .modify(|_, w| unsafe { w.cnt_l_lim().bits(value as u16) });
143                unit.conf0().modify(|_, w| w.thr_l_lim_en().set_bit());
144            }
145        } else {
146            unit.conf0().modify(|_, w| w.thr_l_lim_en().clear_bit());
147        }
148        Ok(())
149    }
150
151    /// Configures a high limit to the count value.
152    ///
153    /// When the count rises to this value:
154    /// - A high limit interrupt is triggered.
155    /// - The count is reset to 0.
156    ///
157    /// If None is specified, then no interrupt is triggered and
158    /// the count wraps around after [i16::MAX].
159    ///
160    /// The specified value must be positive.
161    pub fn set_high_limit(&self, value: Option<i16>) -> Result<(), InvalidHighLimit> {
162        let unit = self.unit.register_block().unit(self.unit.info().unit);
163
164        if let Some(value) = value {
165            if !value.is_positive() {
166                return Err(InvalidHighLimit);
167            } else {
168                unit.conf2()
169                    .modify(|_, w| unsafe { w.cnt_h_lim().bits(value as u16) });
170                unit.conf0().modify(|_, w| w.thr_h_lim_en().set_bit());
171            }
172        } else {
173            unit.conf0().modify(|_, w| w.thr_h_lim_en().clear_bit());
174        }
175        Ok(())
176    }
177
178    /// Configures a threshold value to trigger an interrupt.
179    ///
180    /// When the count equals this value a threshold0 interrupt is triggered.
181    /// If None is specified, then no interrupt is triggered.
182    pub fn set_threshold0(&self, value: Option<i16>) {
183        let unit = self.unit.register_block().unit(self.unit.info().unit);
184
185        if let Some(value) = value {
186            unit.conf1()
187                .modify(|_, w| unsafe { w.cnt_thres0().bits(value as u16) });
188            unit.conf0().modify(|_, w| w.thr_thres0_en().set_bit());
189        } else {
190            unit.conf0().modify(|_, w| w.thr_thres0_en().clear_bit());
191        }
192    }
193
194    /// Configures a threshold value to trigger an interrupt.
195    ///
196    /// When the count equals this value a threshold1 interrupt is triggered.
197    /// If None is specified, then no interrupt is triggered.
198    pub fn set_threshold1(&self, value: Option<i16>) {
199        let unit = self.unit.register_block().unit(self.unit.info().unit);
200
201        if let Some(value) = value {
202            unit.conf1()
203                .modify(|_, w| unsafe { w.cnt_thres1().bits(value as u16) });
204            unit.conf0().modify(|_, w| w.thr_thres1_en().set_bit());
205        } else {
206            unit.conf0().modify(|_, w| w.thr_thres1_en().clear_bit());
207        }
208    }
209
210    /// Configures the glitch filter hardware of the unit.
211    ///
212    /// `threshold` is the minimum number of APB_CLK cycles for a pulse to be
213    /// considered valid. If it is None, the filter is disabled.
214    ///
215    /// The maximum possible threshold is 1023.
216    pub fn set_filter(&self, threshold: Option<u16>) -> Result<(), InvalidFilterThreshold> {
217        let unit = self.unit.register_block().unit(self.unit.info().unit);
218
219        match threshold {
220            None => {
221                unit.conf0().modify(|_, w| w.filter_en().clear_bit());
222            }
223            Some(threshold) => {
224                if threshold > 1023 {
225                    return Err(InvalidFilterThreshold);
226                }
227                unit.conf0().modify(|_, w| unsafe {
228                    w.filter_thres().bits(threshold);
229                    w.filter_en().set_bit()
230                });
231            }
232        }
233        Ok(())
234    }
235
236    /// Resets the counter value to zero.
237    pub fn clear(&self) {
238        let n = self.index();
239        self.unit.lock(|| {
240            let regs = self.unit.register_block();
241            let bits = regs.ctrl().read().bits();
242            regs.ctrl().write(|w| {
243                unsafe { w.bits(bits) };
244                w.cnt_rst_u(n).set_bit()
245            });
246            regs.ctrl().write(|w| {
247                unsafe { w.bits(bits) };
248                w.cnt_rst_u(n).clear_bit()
249            });
250        });
251    }
252
253    /// Pauses the counter.
254    pub fn pause(&self) {
255        let n = self.index();
256        self.unit.lock(|| {
257            self.unit
258                .register_block()
259                .ctrl()
260                .modify(|_, w| w.cnt_pause_u(n).set_bit());
261        });
262    }
263
264    /// Resumes the counter.
265    pub fn resume(&self) {
266        let n = self.index();
267        self.unit.lock(|| {
268            self.unit
269                .register_block()
270                .ctrl()
271                .modify(|_, w| w.cnt_pause_u(n).clear_bit());
272        });
273    }
274
275    /// Returns the latest events for this unit.
276    pub fn events(&self) -> Events {
277        let status = self
278            .unit
279            .register_block()
280            .u_status(self.unit.info().unit)
281            .read();
282
283        Events {
284            low_limit: status.l_lim().bit(),
285            high_limit: status.h_lim().bit(),
286            threshold0: status.thres0().bit(),
287            threshold1: status.thres1().bit(),
288            zero: status.zero().bit(),
289        }
290    }
291
292    /// Returns the mode of the last zero crossing.
293    pub fn zero_mode(&self) -> ZeroMode {
294        self.unit
295            .register_block()
296            .u_status(self.unit.info().unit)
297            .read()
298            .zero_mode()
299            .bits()
300            .into()
301    }
302
303    /// Enables interrupts for this unit.
304    pub fn listen(&self) {
305        let n = self.index();
306        self.unit.lock(|| {
307            self.unit
308                .register_block()
309                .int_ena()
310                .modify(|_, w| w.cnt_thr_event_u(n).set_bit());
311        });
312    }
313
314    /// Disables interrupts for this unit.
315    pub fn unlisten(&self) {
316        let n = self.index();
317        self.unit.lock(|| {
318            self.unit
319                .register_block()
320                .int_ena()
321                .modify(|_, w| w.cnt_thr_event_u(n).clear_bit());
322        });
323    }
324
325    /// Returns whether an interrupt is active for this unit.
326    pub fn interrupt_is_set(&self) -> bool {
327        self.unit
328            .register_block()
329            .int_raw()
330            .read()
331            .cnt_thr_event_u(self.index())
332            .bit()
333    }
334
335    /// Clears the interrupt bit for this unit.
336    pub fn reset_interrupt(&self) {
337        self.unit
338            .register_block()
339            .int_clr()
340            .write(|w| w.cnt_thr_event_u(self.index()).set_bit());
341    }
342
343    /// Returns the current counter value.
344    pub fn value(&self) -> i16 {
345        self.counter.get()
346    }
347
348    /// Registers a handler invoked when this unit's interrupt status bit is
349    /// set.
350    ///
351    /// The hardware interrupt is shared by every unit in the same PCNT
352    /// register block. This method installs a dispatcher on that interrupt
353    /// and records `handler` for this unit only.
354    ///
355    /// This method ignores handler priority.
356    #[instability::unstable]
357    pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
358        let info = self.unit.info();
359        self.unit.state().store(handler.handler().callback());
360        crate::interrupt::bind_handler(info.interrupt, info.dispatcher);
361    }
362}
363
364impl crate::private::Sealed for Unit<'_> {}
365
366#[instability::unstable]
367impl InterruptConfigurable for Unit<'_> {
368    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
369        self.set_interrupt_handler(handler);
370    }
371}
372
373impl Drop for Unit<'_> {
374    fn drop(&mut self) {
375        self.unlisten();
376        self.pause();
377        let info = self.unit.info();
378        info.regs()
379            .unit(info.unit)
380            .conf0()
381            .write(|w| unsafe { w.bits(0) });
382        self.unit.state().clear();
383    }
384}
385
386// The entire Unit is Send but the individual channels are not.
387unsafe impl Send for Unit<'_> {}
388
389/// Represents the counter within a pulse counter unit.
390pub struct Counter<'d> {
391    unit: AnyPcntUnit<'d>,
392    _guard: PeripheralGuard,
393}
394
395impl Clone for Counter<'_> {
396    fn clone(&self) -> Self {
397        Self {
398            unit: unsafe { self.unit.clone_unchecked() },
399            _guard: self._guard.clone(),
400        }
401    }
402}
403
404impl<'d> Counter<'d> {
405    fn new(unit: AnyPcntUnit<'d>) -> Self {
406        let guard = PeripheralGuard::new(unit.info().peripheral);
407
408        Self {
409            unit,
410            _guard: guard,
411        }
412    }
413
414    /// Returns the current counter value.
415    pub fn get(&self) -> i16 {
416        self.unit
417            .register_block()
418            .u_cnt(self.unit.info().unit)
419            .read()
420            .cnt()
421            .bits() as i16
422    }
423}