• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /*******************************************************************************
16  * NOTICE
17  * The hal is not public api, don't use in application code.
18  * See readme.md in hal/include/hal/readme.md
19  ******************************************************************************/
20 
21 // The LL layer for ESP32 PCNT register operations
22 
23 #pragma once
24 
25 #include "soc/pcnt_periph.h"
26 #include "hal/pcnt_types.h"
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 // Get PCNT hardware instance with giving pcnt num
33 #define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT) : NULL)
34 
35 /**
36  * @brief Set PCNT channel edge mode
37  *
38  * @param hw Peripheral PCNT hardware instance address.
39  * @param unit PCNT unit number
40  * @param channel PCNT channel number
41  * @param pos_mode Counter mode when detecting positive edge
42  * @param neg_mode Counter mode when detecting negative edge
43  */
pcnt_ll_set_edge_mode(pcnt_dev_t * hw,pcnt_unit_t unit,pcnt_channel_t channel,pcnt_count_mode_t pos_mode,pcnt_count_mode_t neg_mode)44 static inline void pcnt_ll_set_edge_mode(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_channel_t channel, pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode)
45 {
46     typeof(hw->conf_unit[unit].conf0) conf0_reg = hw->conf_unit[unit].conf0;
47     if (channel == 0) {
48         conf0_reg.ch0_pos_mode = pos_mode;
49         conf0_reg.ch0_neg_mode = neg_mode;
50     } else {
51         conf0_reg.ch1_pos_mode = pos_mode;
52         conf0_reg.ch1_neg_mode = neg_mode;
53     }
54     hw->conf_unit[unit].conf0 = conf0_reg;
55 }
56 
57 /**
58  * @brief Set PCNT channel level mode
59  *
60  * @param hw Peripheral PCNT hardware instance address.
61  * @param unit PCNT unit number
62  * @param channel PCNT channel number
63  * @param hctrl_mode Counter mode when control signal is high level
64  * @param lctrl_mode Counter mode when control signal is low level
65  */
pcnt_ll_set_level_mode(pcnt_dev_t * hw,pcnt_unit_t unit,pcnt_channel_t channel,pcnt_ctrl_mode_t hctrl_mode,pcnt_ctrl_mode_t lctrl_mode)66 static inline void pcnt_ll_set_level_mode(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_channel_t channel, pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode)
67 {
68     typeof(hw->conf_unit[unit].conf0) conf0_reg = hw->conf_unit[unit].conf0;
69     if (channel == 0) {
70         conf0_reg.ch0_hctrl_mode = hctrl_mode;
71         conf0_reg.ch0_lctrl_mode = lctrl_mode;
72     } else {
73         conf0_reg.ch1_hctrl_mode = hctrl_mode;
74         conf0_reg.ch1_lctrl_mode = lctrl_mode;
75     }
76     hw->conf_unit[unit].conf0 = conf0_reg;
77 }
78 
79 /**
80  * @brief Set PCNT counter mode
81  *
82  * @param hw Peripheral PCNT hardware instance address.
83  * @param unit PCNT unit number
84  * @param channel PCNT channel number
85  * @param pos_mode Counter mode when detecting positive edge
86  * @param neg_mode Counter mode when detecting negative edge
87  * @param hctrl_mode Counter mode when control signal is high level
88  * @param lctrl_mode Counter mode when control signal is low level
89  */
pcnt_ll_set_mode(pcnt_dev_t * hw,pcnt_unit_t unit,pcnt_channel_t channel,pcnt_count_mode_t pos_mode,pcnt_count_mode_t neg_mode,pcnt_ctrl_mode_t hctrl_mode,pcnt_ctrl_mode_t lctrl_mode)90 static inline void pcnt_ll_set_mode(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_channel_t channel, pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode, pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode)
91 {
92     pcnt_ll_set_edge_mode(hw, unit, channel, pos_mode, neg_mode);
93     pcnt_ll_set_level_mode(hw, unit, channel, hctrl_mode, lctrl_mode);
94 }
95 
96 /**
97  * @brief Get pulse counter value
98  *
99  * @param hw Peripheral PCNT hardware instance address.
100  * @param unit  Pulse Counter unit number
101  * @param count Pointer to accept counter value
102  */
pcnt_ll_get_counter_value(pcnt_dev_t * hw,pcnt_unit_t unit,int16_t * count)103 static inline void pcnt_ll_get_counter_value(pcnt_dev_t *hw, pcnt_unit_t unit, int16_t *count)
104 {
105     *count = (int16_t) hw->cnt_unit[unit].cnt_val;
106 }
107 
108 /**
109  * @brief Pause PCNT counter of PCNT unit
110  *
111  * @param hw Peripheral PCNT hardware instance address.
112  * @param unit PCNT unit number
113  */
pcnt_ll_counter_pause(pcnt_dev_t * hw,pcnt_unit_t unit)114 static inline void pcnt_ll_counter_pause(pcnt_dev_t *hw, pcnt_unit_t unit)
115 {
116     hw->ctrl.val |= BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2));
117 }
118 
119 /**
120  * @brief Resume counting for PCNT counter
121  *
122  * @param hw Peripheral PCNT hardware instance address.
123  * @param unit PCNT unit number, select from pcnt_unit_t
124  */
pcnt_ll_counter_resume(pcnt_dev_t * hw,pcnt_unit_t unit)125 static inline void pcnt_ll_counter_resume(pcnt_dev_t *hw, pcnt_unit_t unit)
126 {
127     hw->ctrl.val &= (~(BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2))));
128 }
129 
130 /**
131  * @brief Clear and reset PCNT counter value to zero
132  *
133  * @param hw Peripheral PCNT hardware instance address.
134  * @param  unit PCNT unit number, select from pcnt_unit_t
135  */
pcnt_ll_counter_clear(pcnt_dev_t * hw,pcnt_unit_t unit)136 static inline void pcnt_ll_counter_clear(pcnt_dev_t *hw, pcnt_unit_t unit)
137 {
138     uint32_t reset_bit = BIT(PCNT_PLUS_CNT_RST_U0_S + (unit * 2));
139     hw->ctrl.val |= reset_bit;
140     hw->ctrl.val &= ~reset_bit;
141 }
142 
143 /**
144  * @brief Enable PCNT interrupt for PCNT unit
145  *        @note
146  *        Each Pulse counter unit has five watch point events that share the same interrupt.
147  *        Configure events with pcnt_event_enable() and pcnt_event_disable()
148  *
149  * @param hw Peripheral PCNT hardware instance address.
150  * @param unit PCNT unit number
151  */
pcnt_ll_intr_enable(pcnt_dev_t * hw,pcnt_unit_t unit)152 static inline void pcnt_ll_intr_enable(pcnt_dev_t *hw, pcnt_unit_t unit)
153 {
154     hw->int_ena.val |= BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit);
155 }
156 
157 /**
158  * @brief Disable PCNT interrupt for PCNT unit
159  *
160  * @param hw Peripheral PCNT hardware instance address.
161  * @param unit PCNT unit number
162  */
pcnt_ll_intr_disable(pcnt_dev_t * hw,pcnt_unit_t unit)163 static inline void pcnt_ll_intr_disable(pcnt_dev_t *hw, pcnt_unit_t unit)
164 {
165     hw->int_ena.val &= (~(BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit)));
166 }
167 
168 /**
169  * @brief Get PCNT interrupt status
170  *
171  * @param hw Peripheral PCNT hardware instance address.
172  * @param status Pointer to accept value
173  */
pcnt_ll_get_intr_status(pcnt_dev_t * hw,uint32_t * status)174 static inline void pcnt_ll_get_intr_status(pcnt_dev_t *hw, uint32_t *status)
175 {
176     *status = hw->int_st.val;
177 }
178 
179 /**
180  * @brief Clear PCNT interrupt status
181  *
182  * @param hw Peripheral PCNT hardware instance address.
183  * @param status value to clear interrupt status
184  */
pcnt_ll_clear_intr_status(pcnt_dev_t * hw,uint32_t status)185 static inline void pcnt_ll_clear_intr_status(pcnt_dev_t *hw, uint32_t status)
186 {
187     hw->int_clr.val = status;
188 }
189 
190 /**
191  * @brief Enable PCNT event of PCNT unit
192  *
193  * @param hw Peripheral PCNT hardware instance address.
194  * @param unit PCNT unit number
195  * @param evt_type Watch point event type.
196  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
197  */
pcnt_ll_event_enable(pcnt_dev_t * hw,pcnt_unit_t unit,pcnt_evt_type_t evt_type)198 static inline void pcnt_ll_event_enable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type)
199 {
200     if (evt_type == PCNT_EVT_L_LIM) {
201         hw->conf_unit[unit].conf0.thr_l_lim_en = 1;
202     } else if (evt_type == PCNT_EVT_H_LIM) {
203         hw->conf_unit[unit].conf0.thr_h_lim_en = 1;
204     } else if (evt_type == PCNT_EVT_THRES_0) {
205         hw->conf_unit[unit].conf0.thr_thres0_en = 1;
206     } else if (evt_type == PCNT_EVT_THRES_1) {
207         hw->conf_unit[unit].conf0.thr_thres1_en = 1;
208     } else if (evt_type == PCNT_EVT_ZERO) {
209         hw->conf_unit[unit].conf0.thr_zero_en = 1;
210     }
211 }
212 
213 /**
214  * @brief Disable PCNT event of PCNT unit
215  *
216  * @param hw Peripheral PCNT hardware instance address.
217  * @param unit PCNT unit number
218  * @param evt_type Watch point event type.
219  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
220  */
pcnt_ll_event_disable(pcnt_dev_t * hw,pcnt_unit_t unit,pcnt_evt_type_t evt_type)221 static inline void pcnt_ll_event_disable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type)
222 {
223     if (evt_type == PCNT_EVT_L_LIM) {
224         hw->conf_unit[unit].conf0.thr_l_lim_en = 0;
225     } else if (evt_type == PCNT_EVT_H_LIM) {
226         hw->conf_unit[unit].conf0.thr_h_lim_en = 0;
227     } else if (evt_type == PCNT_EVT_THRES_0) {
228         hw->conf_unit[unit].conf0.thr_thres0_en = 0;
229     } else if (evt_type == PCNT_EVT_THRES_1) {
230         hw->conf_unit[unit].conf0.thr_thres1_en = 0;
231     } else if (evt_type == PCNT_EVT_ZERO) {
232         hw->conf_unit[unit].conf0.thr_zero_en = 0;
233     }
234 }
235 
236 /**
237  * @brief Set PCNT event value of PCNT unit
238  *
239  * @param hw Peripheral PCNT hardware instance address.
240  * @param unit PCNT unit number
241  * @param evt_type Watch point event type.
242  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
243  *
244  * @param value Counter value for PCNT event
245  */
pcnt_ll_set_event_value(pcnt_dev_t * hw,pcnt_unit_t unit,pcnt_evt_type_t evt_type,int16_t value)246 static inline void pcnt_ll_set_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)
247 {
248     if (evt_type == PCNT_EVT_L_LIM) {
249         hw->conf_unit[unit].conf2.cnt_l_lim = value;
250     } else if (evt_type == PCNT_EVT_H_LIM) {
251         hw->conf_unit[unit].conf2.cnt_h_lim = value;
252     } else if (evt_type == PCNT_EVT_THRES_0) {
253         hw->conf_unit[unit].conf1.cnt_thres0 = value;
254     } else if (evt_type == PCNT_EVT_THRES_1) {
255         hw->conf_unit[unit].conf1.cnt_thres1 = value;
256     }
257 }
258 
259 /**
260  * @brief Get PCNT event value of PCNT unit
261  *
262  * @param hw Peripheral PCNT hardware instance address.
263  * @param unit PCNT unit number
264  * @param evt_type Watch point event type.
265  *                 All enabled events share the same interrupt (one interrupt per pulse counter unit).
266  * @param value Pointer to accept counter value for PCNT event
267  */
pcnt_ll_get_event_value(pcnt_dev_t * hw,pcnt_unit_t unit,pcnt_evt_type_t evt_type,int16_t * value)268 static inline void pcnt_ll_get_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value)
269 {
270     if (evt_type == PCNT_EVT_L_LIM) {
271         *value = (int16_t) hw->conf_unit[unit].conf2.cnt_l_lim;
272     } else if (evt_type == PCNT_EVT_H_LIM) {
273         *value = (int16_t) hw->conf_unit[unit].conf2.cnt_h_lim;
274     } else if (evt_type == PCNT_EVT_THRES_0) {
275         *value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres0;
276     } else if (evt_type == PCNT_EVT_THRES_1) {
277         *value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres1;
278     } else {
279         *value = 0;
280     }
281 }
282 
283 /**
284  * @brief Get PCNT event status
285  *
286  * @param hw Peripheral PCNT hardware instance address.
287  * @param unit PCNT unit number
288  * @return event status word
289  */
pcnt_ll_get_event_status(pcnt_dev_t * hw,pcnt_unit_t unit)290 static inline uint32_t pcnt_ll_get_event_status(pcnt_dev_t *hw, pcnt_unit_t unit)
291 {
292     return hw->status_unit[unit].val;
293 }
294 
295 /**
296  * @brief Set PCNT filter value
297  *
298  * @param hw Peripheral PCNT hardware instance address.
299  * @param unit PCNT unit number
300  * @param filter_val PCNT signal filter value, counter in APB_CLK cycles.
301  *        Any pulses lasting shorter than this will be ignored when the filter is enabled.
302  *        @note
303  *        filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
304  */
pcnt_ll_set_filter_value(pcnt_dev_t * hw,pcnt_unit_t unit,uint16_t filter_val)305 static inline void pcnt_ll_set_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t filter_val)
306 {
307     hw->conf_unit[unit].conf0.filter_thres = filter_val;
308 }
309 
310 /**
311  * @brief Get PCNT filter value
312  *
313  * @param hw Peripheral PCNT hardware instance address.
314  * @param unit PCNT unit number
315  * @param filter_val Pointer to accept PCNT filter value.
316  */
pcnt_ll_get_filter_value(pcnt_dev_t * hw,pcnt_unit_t unit,uint16_t * filter_val)317 static inline void pcnt_ll_get_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t *filter_val)
318 {
319     *filter_val = hw->conf_unit[unit].conf0.filter_thres;
320 }
321 
322 /**
323  * @brief Enable PCNT input filter
324  *
325  * @param hw Peripheral PCNT hardware instance address.
326  * @param unit PCNT unit number
327  */
pcnt_ll_filter_enable(pcnt_dev_t * hw,pcnt_unit_t unit)328 static inline void pcnt_ll_filter_enable(pcnt_dev_t *hw, pcnt_unit_t unit)
329 {
330     hw->conf_unit[unit].conf0.filter_en = 1;
331 }
332 
333 /**
334  * @brief Disable PCNT input filter
335  *
336  * @param hw Peripheral PCNT hardware instance address.
337  * @param unit PCNT unit number
338  */
pcnt_ll_filter_disable(pcnt_dev_t * hw,pcnt_unit_t unit)339 static inline void pcnt_ll_filter_disable(pcnt_dev_t *hw, pcnt_unit_t unit)
340 {
341     hw->conf_unit[unit].conf0.filter_en = 0;
342 }
343 
344 #ifdef __cplusplus
345 }
346 #endif
347