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 ->
60    ///   0.
61    /// * `pos_edge` - The effect on the counter when the input signal goes 0 ->
62    ///   1.
63    pub fn set_input_mode(&self, neg_edge: EdgeMode, pos_edge: EdgeMode) {
64        let pcnt = PCNT::regs();
65        let conf0 = pcnt.unit(UNIT).conf0();
66
67        conf0.modify(|_, w| {
68            w.ch_neg_mode(NUM as u8).variant(neg_edge);
69            w.ch_pos_mode(NUM as u8).variant(pos_edge)
70        });
71    }
72
73    /// Set the control signal (pin/high/low) for this channel
74    pub fn set_ctrl_signal<'d>(&self, source: impl PeripheralInput<'d>) -> &Self {
75        let signal = match UNIT {
76            0 => match NUM {
77                0 => InputSignal::PCNT0_CTRL_CH0,
78                1 => InputSignal::PCNT0_CTRL_CH1,
79                _ => unreachable!(),
80            },
81            1 => match NUM {
82                0 => InputSignal::PCNT1_CTRL_CH0,
83                1 => InputSignal::PCNT1_CTRL_CH1,
84                _ => unreachable!(),
85            },
86            2 => match NUM {
87                0 => InputSignal::PCNT2_CTRL_CH0,
88                1 => InputSignal::PCNT2_CTRL_CH1,
89                _ => unreachable!(),
90            },
91            3 => match NUM {
92                0 => InputSignal::PCNT3_CTRL_CH0,
93                1 => InputSignal::PCNT3_CTRL_CH1,
94                _ => unreachable!(),
95            },
96            #[cfg(esp32)]
97            4 => match NUM {
98                0 => InputSignal::PCNT4_CTRL_CH0,
99                1 => InputSignal::PCNT4_CTRL_CH1,
100                _ => unreachable!(),
101            },
102            #[cfg(esp32)]
103            5 => match NUM {
104                0 => InputSignal::PCNT5_CTRL_CH0,
105                1 => InputSignal::PCNT5_CTRL_CH1,
106                _ => unreachable!(),
107            },
108            #[cfg(esp32)]
109            6 => match NUM {
110                0 => InputSignal::PCNT6_CTRL_CH0,
111                1 => InputSignal::PCNT6_CTRL_CH1,
112                _ => unreachable!(),
113            },
114            #[cfg(esp32)]
115            7 => match NUM {
116                0 => InputSignal::PCNT7_CTRL_CH0,
117                1 => InputSignal::PCNT7_CTRL_CH1,
118                _ => unreachable!(),
119            },
120            _ => unreachable!(),
121        };
122
123        if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize {
124            let source = source.into();
125            source.set_input_enable(true);
126            signal.connect_to(&source);
127        }
128        self
129    }
130
131    /// Set the edge signal (pin/high/low) for this channel
132    pub fn set_edge_signal<'d>(&self, source: impl PeripheralInput<'d>) -> &Self {
133        let signal = match UNIT {
134            0 => match NUM {
135                0 => InputSignal::PCNT0_SIG_CH0,
136                1 => InputSignal::PCNT0_SIG_CH1,
137                _ => unreachable!(),
138            },
139            1 => match NUM {
140                0 => InputSignal::PCNT1_SIG_CH0,
141                1 => InputSignal::PCNT1_SIG_CH1,
142                _ => unreachable!(),
143            },
144            2 => match NUM {
145                0 => InputSignal::PCNT2_SIG_CH0,
146                1 => InputSignal::PCNT2_SIG_CH1,
147                _ => unreachable!(),
148            },
149            3 => match NUM {
150                0 => InputSignal::PCNT3_SIG_CH0,
151                1 => InputSignal::PCNT3_SIG_CH1,
152                _ => unreachable!(),
153            },
154            #[cfg(esp32)]
155            4 => match NUM {
156                0 => InputSignal::PCNT4_SIG_CH0,
157                1 => InputSignal::PCNT4_SIG_CH1,
158                _ => unreachable!(),
159            },
160            #[cfg(esp32)]
161            5 => match NUM {
162                0 => InputSignal::PCNT5_SIG_CH0,
163                1 => InputSignal::PCNT5_SIG_CH1,
164                _ => unreachable!(),
165            },
166            #[cfg(esp32)]
167            6 => match NUM {
168                0 => InputSignal::PCNT6_SIG_CH0,
169                1 => InputSignal::PCNT6_SIG_CH1,
170                _ => unreachable!(),
171            },
172            #[cfg(esp32)]
173            7 => match NUM {
174                0 => InputSignal::PCNT7_SIG_CH0,
175                1 => InputSignal::PCNT7_SIG_CH1,
176                _ => unreachable!(),
177            },
178            _ => unreachable!(),
179        };
180
181        if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize {
182            let source = source.into();
183            source.set_input_enable(true);
184            signal.connect_to(&source);
185        }
186        self
187    }
188}