Skip to main content

esp_hal/pcnt/
channel.rs

1//! # PCNT - Channel Configuration
2//!
3//! ## Overview
4//! The `channel` module configures the two channels of a PCNT unit: control
5//! modes for signal edges, action on control level, and positive/negative edge
6//! count modes.
7
8use core::marker::PhantomData;
9
10pub use crate::pac::pcnt::unit::conf0::{CTRL_MODE as CtrlMode, EDGE_MODE as EdgeMode};
11use crate::{
12    gpio::{
13        InputSignal,
14        interconnect::{self, PeripheralInput},
15    },
16    pcnt::AnyPcntUnit,
17    system::PeripheralGuard,
18};
19
20/// Represents a channel within a pulse counter unit.
21pub struct Channel<'d, const NUM: usize> {
22    unit: AnyPcntUnit<'d>,
23    // Individual channels are not Send, since they share registers.
24    _not_send: PhantomData<*const ()>,
25    _guard: PeripheralGuard,
26}
27
28impl<'d, const NUM: usize> Channel<'d, NUM> {
29    pub(super) fn new(unit: AnyPcntUnit<'d>) -> Self {
30        const { ::core::assert!(NUM < 2) };
31        let guard = PeripheralGuard::new(unit.info().peripheral);
32
33        Self {
34            unit,
35            _not_send: PhantomData,
36            _guard: guard,
37        }
38    }
39
40    /// Configures how the channel behaves based on the level of the control
41    /// signal.
42    ///
43    /// * `low` - The behaviour of the channel when the control signal is low.
44    /// * `high` - The behaviour of the channel when the control signal is high.
45    pub fn set_ctrl_mode(&self, low: CtrlMode, high: CtrlMode) {
46        let conf0 = self
47            .unit
48            .register_block()
49            .unit(self.unit.info().unit)
50            .conf0();
51
52        conf0.modify(|_, w| {
53            w.ch_hctrl_mode(NUM as u8).variant(high);
54            w.ch_lctrl_mode(NUM as u8).variant(low)
55        });
56    }
57
58    /// Configures how the channel affects the counter based on the transition
59    /// made by the input signal.
60    ///
61    /// * `neg_edge` - The effect on the counter when the input signal goes 1 -> 0.
62    /// * `pos_edge` - The effect on the counter when the input signal goes 0 -> 1.
63    pub fn set_input_mode(&self, neg_edge: EdgeMode, pos_edge: EdgeMode) {
64        let conf0 = self
65            .unit
66            .register_block()
67            .unit(self.unit.info().unit)
68            .conf0();
69
70        conf0.modify(|_, w| {
71            w.ch_neg_mode(NUM as u8).variant(neg_edge);
72            w.ch_pos_mode(NUM as u8).variant(pos_edge)
73        });
74    }
75
76    /// Set the control signal (pin/high/low) for this channel
77    pub fn set_ctrl_signal(&self, source: impl PeripheralInput<'d>) -> &Self {
78        let signal = self.unit.info().ctrl_ch[NUM];
79        self.connect_input(signal, source.into())
80    }
81
82    /// Set the edge signal (pin/high/low) for this channel
83    pub fn set_edge_signal(&self, source: impl PeripheralInput<'d>) -> &Self {
84        let signal = self.unit.info().sig_ch[NUM];
85        self.connect_input(signal, source.into())
86    }
87
88    fn connect_input(&self, signal: InputSignal, source: interconnect::InputSignal<'d>) -> &Self {
89        source.set_input_enable(true);
90        signal.connect_to(&source);
91        self
92    }
93}