esp_hal/pcnt/
channel.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//! # PCNT - Channel Configuration
//!
//! ## Overview
//! The `channel` module allows users to configure and manage individual
//! channels of the `PCNT` peripheral. It provides methods to set various
//! parameters for each channel, such as control modes for signal edges, action
//! on control level, and configurations for positive and negative edge count
//! modes.

use core::marker::PhantomData;

pub use crate::pac::pcnt::unit::conf0::{CTRL_MODE as CtrlMode, EDGE_MODE as EdgeMode};
use crate::{
    gpio::{interconnect::PeripheralInput, InputSignal},
    peripheral::Peripheral,
    peripherals::PCNT,
    system::GenericPeripheralGuard,
};

/// Represents a channel within a pulse counter unit.
pub struct Channel<'d, const UNIT: usize, const NUM: usize> {
    _phantom: PhantomData<&'d ()>,
    // Individual channels are not Send, since they share registers.
    _not_send: PhantomData<*const ()>,
    _guard: GenericPeripheralGuard<{ crate::system::Peripheral::Pcnt as u8 }>,
}

impl<const UNIT: usize, const NUM: usize> Channel<'_, UNIT, NUM> {
    /// return a new Channel
    pub(super) fn new() -> Self {
        let guard = GenericPeripheralGuard::new();

        Self {
            _phantom: PhantomData,
            _not_send: PhantomData,
            _guard: guard,
        }
    }

    /// Configures how the channel behaves based on the level of the control
    /// signal.
    ///
    /// * `low` - The behaviour of the channel when the control signal is low.
    /// * `high` - The behaviour of the channel when the control signal is high.
    pub fn set_ctrl_mode(&self, low: CtrlMode, high: CtrlMode) {
        let pcnt = PCNT::regs();
        let conf0 = pcnt.unit(UNIT).conf0();

        conf0.modify(|_, w| {
            w.ch_hctrl_mode(NUM as u8)
                .variant(high)
                .ch_lctrl_mode(NUM as u8)
                .variant(low)
        });
    }

    /// Configures how the channel affects the counter based on the transition
    /// made by the input signal.
    ///
    /// * `neg_edge` - The effect on the counter when the input signal goes 1 ->
    ///   0.
    /// * `pos_edge` - The effect on the counter when the input signal goes 0 ->
    ///   1.
    pub fn set_input_mode(&self, neg_edge: EdgeMode, pos_edge: EdgeMode) {
        let pcnt = PCNT::regs();
        let conf0 = pcnt.unit(UNIT).conf0();

        conf0.modify(|_, w| {
            w.ch_neg_mode(NUM as u8).variant(neg_edge);
            w.ch_pos_mode(NUM as u8).variant(pos_edge)
        });
    }

    /// Set the control signal (pin/high/low) for this channel
    pub fn set_ctrl_signal<P: PeripheralInput>(&self, source: impl Peripheral<P = P>) -> &Self {
        let signal = match UNIT {
            0 => match NUM {
                0 => InputSignal::PCNT0_CTRL_CH0,
                1 => InputSignal::PCNT0_CTRL_CH1,
                _ => unreachable!(),
            },
            1 => match NUM {
                0 => InputSignal::PCNT1_CTRL_CH0,
                1 => InputSignal::PCNT1_CTRL_CH1,
                _ => unreachable!(),
            },
            2 => match NUM {
                0 => InputSignal::PCNT2_CTRL_CH0,
                1 => InputSignal::PCNT2_CTRL_CH1,
                _ => unreachable!(),
            },
            3 => match NUM {
                0 => InputSignal::PCNT3_CTRL_CH0,
                1 => InputSignal::PCNT3_CTRL_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            4 => match NUM {
                0 => InputSignal::PCNT4_CTRL_CH0,
                1 => InputSignal::PCNT4_CTRL_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            5 => match NUM {
                0 => InputSignal::PCNT5_CTRL_CH0,
                1 => InputSignal::PCNT5_CTRL_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            6 => match NUM {
                0 => InputSignal::PCNT6_CTRL_CH0,
                1 => InputSignal::PCNT6_CTRL_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            7 => match NUM {
                0 => InputSignal::PCNT7_CTRL_CH0,
                1 => InputSignal::PCNT7_CTRL_CH1,
                _ => unreachable!(),
            },
            _ => unreachable!(),
        };

        if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize {
            crate::into_mapped_ref!(source);
            source.enable_input(true);
            signal.connect_to(source);
        }
        self
    }

    /// Set the edge signal (pin/high/low) for this channel
    pub fn set_edge_signal<P: PeripheralInput>(&self, source: impl Peripheral<P = P>) -> &Self {
        let signal = match UNIT {
            0 => match NUM {
                0 => InputSignal::PCNT0_SIG_CH0,
                1 => InputSignal::PCNT0_SIG_CH1,
                _ => unreachable!(),
            },
            1 => match NUM {
                0 => InputSignal::PCNT1_SIG_CH0,
                1 => InputSignal::PCNT1_SIG_CH1,
                _ => unreachable!(),
            },
            2 => match NUM {
                0 => InputSignal::PCNT2_SIG_CH0,
                1 => InputSignal::PCNT2_SIG_CH1,
                _ => unreachable!(),
            },
            3 => match NUM {
                0 => InputSignal::PCNT3_SIG_CH0,
                1 => InputSignal::PCNT3_SIG_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            4 => match NUM {
                0 => InputSignal::PCNT4_SIG_CH0,
                1 => InputSignal::PCNT4_SIG_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            5 => match NUM {
                0 => InputSignal::PCNT5_SIG_CH0,
                1 => InputSignal::PCNT5_SIG_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            6 => match NUM {
                0 => InputSignal::PCNT6_SIG_CH0,
                1 => InputSignal::PCNT6_SIG_CH1,
                _ => unreachable!(),
            },
            #[cfg(esp32)]
            7 => match NUM {
                0 => InputSignal::PCNT7_SIG_CH0,
                1 => InputSignal::PCNT7_SIG_CH1,
                _ => unreachable!(),
            },
            _ => unreachable!(),
        };

        if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize {
            crate::into_mapped_ref!(source);
            source.enable_input(true);
            signal.connect_to(source);
        }
        self
    }
}