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