Skip to main content

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).variant(high);
50            w.ch_lctrl_mode(NUM as u8).variant(low)
51        });
52    }
53
54    /// Configures how the channel affects the counter based on the transition
55    /// made by the input signal.
56    ///
57    /// * `neg_edge` - The effect on the counter when the input signal goes 1 -> 0.
58    /// * `pos_edge` - The effect on the counter when the input signal goes 0 -> 1.
59    pub fn set_input_mode(&self, neg_edge: EdgeMode, pos_edge: EdgeMode) {
60        let pcnt = PCNT::regs();
61        let conf0 = pcnt.unit(UNIT).conf0();
62
63        conf0.modify(|_, w| {
64            w.ch_neg_mode(NUM as u8).variant(neg_edge);
65            w.ch_pos_mode(NUM as u8).variant(pos_edge)
66        });
67    }
68
69    /// Set the control signal (pin/high/low) for this channel
70    pub fn set_ctrl_signal<'d>(&self, source: impl PeripheralInput<'d>) -> &Self {
71        let signal = match UNIT {
72            0 => match NUM {
73                0 => InputSignal::PCNT0_CTRL_CH0,
74                1 => InputSignal::PCNT0_CTRL_CH1,
75                _ => unreachable!(),
76            },
77            1 => match NUM {
78                0 => InputSignal::PCNT1_CTRL_CH0,
79                1 => InputSignal::PCNT1_CTRL_CH1,
80                _ => unreachable!(),
81            },
82            2 => match NUM {
83                0 => InputSignal::PCNT2_CTRL_CH0,
84                1 => InputSignal::PCNT2_CTRL_CH1,
85                _ => unreachable!(),
86            },
87            3 => match NUM {
88                0 => InputSignal::PCNT3_CTRL_CH0,
89                1 => InputSignal::PCNT3_CTRL_CH1,
90                _ => unreachable!(),
91            },
92            #[cfg(esp32)]
93            4 => match NUM {
94                0 => InputSignal::PCNT4_CTRL_CH0,
95                1 => InputSignal::PCNT4_CTRL_CH1,
96                _ => unreachable!(),
97            },
98            #[cfg(esp32)]
99            5 => match NUM {
100                0 => InputSignal::PCNT5_CTRL_CH0,
101                1 => InputSignal::PCNT5_CTRL_CH1,
102                _ => unreachable!(),
103            },
104            #[cfg(esp32)]
105            6 => match NUM {
106                0 => InputSignal::PCNT6_CTRL_CH0,
107                1 => InputSignal::PCNT6_CTRL_CH1,
108                _ => unreachable!(),
109            },
110            #[cfg(esp32)]
111            7 => match NUM {
112                0 => InputSignal::PCNT7_CTRL_CH0,
113                1 => InputSignal::PCNT7_CTRL_CH1,
114                _ => unreachable!(),
115            },
116            _ => unreachable!(),
117        };
118
119        if signal as usize <= property!("gpio.input_signal_max") {
120            let source = source.into();
121            source.set_input_enable(true);
122            signal.connect_to(&source);
123        } else {
124            warn!("Signal {:?} out of range", signal);
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        } else {
184            warn!("Signal {:?} out of range", signal);
185        }
186        self
187    }
188}