esp_hal/pcnt/
channel.rs

1//! # PCNT - Channel Configuration
2//!
3//! ## Overview
4//! The `channel` module allows users to configure and manage individual
5//! channels of the `PCNT` peripheral. It provides methods to set various
6//! parameters for each channel, such as control modes for signal edges, action
7//! on control level, and configurations for positive and negative edge count
8//! modes.
9
10use core::marker::PhantomData;
11
12pub use crate::pac::pcnt::unit::conf0::{CTRL_MODE as CtrlMode, EDGE_MODE as EdgeMode};
13use crate::{
14    gpio::{InputSignal, interconnect::PeripheralInput},
15    peripherals::PCNT,
16    system::GenericPeripheralGuard,
17};
18
19/// Represents a channel within a pulse counter unit.
20pub struct Channel<'d, const UNIT: usize, const NUM: usize> {
21    _phantom: PhantomData<&'d ()>,
22    // Individual channels are not Send, since they share registers.
23    _not_send: PhantomData<*const ()>,
24    _guard: GenericPeripheralGuard<{ crate::system::Peripheral::Pcnt as u8 }>,
25}
26
27impl<const UNIT: usize, const NUM: usize> Channel<'_, UNIT, NUM> {
28    /// return a new Channel
29    pub(super) fn new() -> Self {
30        let guard = GenericPeripheralGuard::new();
31
32        Self {
33            _phantom: PhantomData,
34            _not_send: PhantomData,
35            _guard: guard,
36        }
37    }
38
39    /// Configures how the channel behaves based on the level of the control
40    /// signal.
41    ///
42    /// * `low` - The behaviour of the channel when the control signal is low.
43    /// * `high` - The behaviour of the channel when the control signal is high.
44    pub fn set_ctrl_mode(&self, low: CtrlMode, high: CtrlMode) {
45        let pcnt = PCNT::regs();
46        let conf0 = pcnt.unit(UNIT).conf0();
47
48        conf0.modify(|_, w| {
49            w.ch_hctrl_mode(NUM as u8)
50                .variant(high)
51                .ch_lctrl_mode(NUM as u8)
52                .variant(low)
53        });
54    }
55
56    /// Configures how the channel affects the counter based on the transition
57    /// made by the input signal.
58    ///
59    /// * `neg_edge` - The effect on the counter when the input signal goes 1 -> 0.
60    /// * `pos_edge` - The effect on the counter when the input signal goes 0 -> 1.
61    pub fn set_input_mode(&self, neg_edge: EdgeMode, pos_edge: EdgeMode) {
62        let pcnt = PCNT::regs();
63        let conf0 = pcnt.unit(UNIT).conf0();
64
65        conf0.modify(|_, w| {
66            w.ch_neg_mode(NUM as u8).variant(neg_edge);
67            w.ch_pos_mode(NUM as u8).variant(pos_edge)
68        });
69    }
70
71    /// Set the control signal (pin/high/low) for this channel
72    pub fn set_ctrl_signal<'d>(&self, source: impl PeripheralInput<'d>) -> &Self {
73        let signal = match UNIT {
74            0 => match NUM {
75                0 => InputSignal::PCNT0_CTRL_CH0,
76                1 => InputSignal::PCNT0_CTRL_CH1,
77                _ => unreachable!(),
78            },
79            1 => match NUM {
80                0 => InputSignal::PCNT1_CTRL_CH0,
81                1 => InputSignal::PCNT1_CTRL_CH1,
82                _ => unreachable!(),
83            },
84            2 => match NUM {
85                0 => InputSignal::PCNT2_CTRL_CH0,
86                1 => InputSignal::PCNT2_CTRL_CH1,
87                _ => unreachable!(),
88            },
89            3 => match NUM {
90                0 => InputSignal::PCNT3_CTRL_CH0,
91                1 => InputSignal::PCNT3_CTRL_CH1,
92                _ => unreachable!(),
93            },
94            #[cfg(esp32)]
95            4 => match NUM {
96                0 => InputSignal::PCNT4_CTRL_CH0,
97                1 => InputSignal::PCNT4_CTRL_CH1,
98                _ => unreachable!(),
99            },
100            #[cfg(esp32)]
101            5 => match NUM {
102                0 => InputSignal::PCNT5_CTRL_CH0,
103                1 => InputSignal::PCNT5_CTRL_CH1,
104                _ => unreachable!(),
105            },
106            #[cfg(esp32)]
107            6 => match NUM {
108                0 => InputSignal::PCNT6_CTRL_CH0,
109                1 => InputSignal::PCNT6_CTRL_CH1,
110                _ => unreachable!(),
111            },
112            #[cfg(esp32)]
113            7 => match NUM {
114                0 => InputSignal::PCNT7_CTRL_CH0,
115                1 => InputSignal::PCNT7_CTRL_CH1,
116                _ => unreachable!(),
117            },
118            _ => unreachable!(),
119        };
120
121        if signal as usize <= property!("gpio.input_signal_max") {
122            let source = source.into();
123            source.set_input_enable(true);
124            signal.connect_to(&source);
125        }
126        self
127    }
128
129    /// Set the edge signal (pin/high/low) for this channel
130    pub fn set_edge_signal<'d>(&self, source: impl PeripheralInput<'d>) -> &Self {
131        let signal = match UNIT {
132            0 => match NUM {
133                0 => InputSignal::PCNT0_SIG_CH0,
134                1 => InputSignal::PCNT0_SIG_CH1,
135                _ => unreachable!(),
136            },
137            1 => match NUM {
138                0 => InputSignal::PCNT1_SIG_CH0,
139                1 => InputSignal::PCNT1_SIG_CH1,
140                _ => unreachable!(),
141            },
142            2 => match NUM {
143                0 => InputSignal::PCNT2_SIG_CH0,
144                1 => InputSignal::PCNT2_SIG_CH1,
145                _ => unreachable!(),
146            },
147            3 => match NUM {
148                0 => InputSignal::PCNT3_SIG_CH0,
149                1 => InputSignal::PCNT3_SIG_CH1,
150                _ => unreachable!(),
151            },
152            #[cfg(esp32)]
153            4 => match NUM {
154                0 => InputSignal::PCNT4_SIG_CH0,
155                1 => InputSignal::PCNT4_SIG_CH1,
156                _ => unreachable!(),
157            },
158            #[cfg(esp32)]
159            5 => match NUM {
160                0 => InputSignal::PCNT5_SIG_CH0,
161                1 => InputSignal::PCNT5_SIG_CH1,
162                _ => unreachable!(),
163            },
164            #[cfg(esp32)]
165            6 => match NUM {
166                0 => InputSignal::PCNT6_SIG_CH0,
167                1 => InputSignal::PCNT6_SIG_CH1,
168                _ => unreachable!(),
169            },
170            #[cfg(esp32)]
171            7 => match NUM {
172                0 => InputSignal::PCNT7_SIG_CH0,
173                1 => InputSignal::PCNT7_SIG_CH1,
174                _ => unreachable!(),
175            },
176            _ => unreachable!(),
177        };
178
179        if signal as usize <= property!("gpio.input_signal_max") {
180            let source = source.into();
181            source.set_input_enable(true);
182            signal.connect_to(&source);
183        }
184        self
185    }
186}