Skip to main content

esp_hal/pcnt/
channel.rs

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