Skip to content

Commit 84f9e5e

Browse files
committed
Merge branch 'feature/esp32p4_pcnt_support' into 'master'
feat(pcnt): add support for ESP32P4 Closes IDF-7475 See merge request espressif/esp-idf!25149
2 parents 67115a4 + 3fed3cf commit 84f9e5e

File tree

16 files changed

+816
-205
lines changed

16 files changed

+816
-205
lines changed

components/driver/Kconfig

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -308,38 +308,7 @@ menu "Driver Configurations"
308308

309309
orsource "./gptimer/Kconfig.gptimer"
310310

311-
menu "PCNT Configuration"
312-
depends on SOC_PCNT_SUPPORTED
313-
config PCNT_CTRL_FUNC_IN_IRAM
314-
bool "Place PCNT control functions into IRAM"
315-
default n
316-
help
317-
Place PCNT control functions (like start/stop) into IRAM,
318-
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
319-
Enabling this option can improve driver performance as well.
320-
321-
config PCNT_ISR_IRAM_SAFE
322-
bool "PCNT ISR IRAM-Safe"
323-
default n
324-
help
325-
Ensure the PCNT interrupt is IRAM-Safe by allowing the interrupt handler to be
326-
executable when the cache is disabled (e.g. SPI Flash write).
327-
328-
config PCNT_SUPPRESS_DEPRECATE_WARN
329-
bool "Suppress legacy driver deprecated warning"
330-
default n
331-
help
332-
Wether to suppress the deprecation warnings when using legacy PCNT driver (driver/pcnt.h).
333-
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
334-
you can enable this option.
335-
336-
config PCNT_ENABLE_DEBUG_LOG
337-
bool "Enable debug log"
338-
default n
339-
help
340-
Wether to enable the debug log message for PCNT driver.
341-
Note that, this option only controls the PCNT driver log, won't affect other drivers.
342-
endmenu # PCNT Configuration
311+
orsource "./pcnt/Kconfig.pcnt"
343312

344313
menu "RMT Configuration"
345314
depends on SOC_RMT_SUPPORTED

components/driver/pcnt/Kconfig.pcnt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
menu "PCNT Configuration"
2+
depends on SOC_PCNT_SUPPORTED
3+
config PCNT_CTRL_FUNC_IN_IRAM
4+
bool "Place PCNT control functions into IRAM"
5+
default n
6+
help
7+
Place PCNT control functions (like start/stop) into IRAM,
8+
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
9+
Enabling this option can improve driver performance as well.
10+
11+
config PCNT_ISR_IRAM_SAFE
12+
bool "PCNT ISR IRAM-Safe"
13+
default n
14+
help
15+
Ensure the PCNT interrupt is IRAM-Safe by allowing the interrupt handler to be
16+
executable when the cache is disabled (e.g. SPI Flash write).
17+
18+
config PCNT_SUPPRESS_DEPRECATE_WARN
19+
bool "Suppress legacy driver deprecated warning"
20+
default n
21+
help
22+
Wether to suppress the deprecation warnings when using legacy PCNT driver (driver/pcnt.h).
23+
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
24+
you can enable this option.
25+
26+
config PCNT_ENABLE_DEBUG_LOG
27+
bool "Enable debug log"
28+
default n
29+
help
30+
Wether to enable the debug log message for PCNT driver.
31+
Note that, this option only controls the PCNT driver log, won't affect other drivers.
32+
endmenu # PCNT Configuration

components/driver/pcnt/include/driver/pulse_cnt.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,15 @@ typedef struct {
6161
typedef struct {
6262
int low_limit; /*!< Low limitation of the count unit, should be lower than 0 */
6363
int high_limit; /*!< High limitation of the count unit, should be higher than 0 */
64+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
65+
int zero_input_gpio_num; /*!< GPIO number used by the clear signal, the default active level is high, input mode with pull down enabled. Set to -1 if unused */
66+
#endif
6467
struct {
6568
uint32_t accum_count: 1; /*!< Whether to accumulate the count value when overflows at the high/low limit */
69+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
70+
uint32_t invert_zero_input: 1; /*!< Invert the zero input signal and set input mode with pull up.*/
71+
uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */
72+
#endif
6673
} flags; /*!< Extra flags */
6774
} pcnt_unit_config_t;
6875

@@ -253,6 +260,7 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt
253260
/**
254261
* @brief Add a watch point for PCNT unit, PCNT will generate an event when the counter value reaches the watch point value
255262
*
263+
*
256264
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
257265
* @param[in] watch_point Value to be watched
258266
* @return

components/driver/pcnt/pulse_cnt.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -84,6 +84,7 @@ struct pcnt_unit_t {
8484
int unit_id; // allocated unit numerical ID
8585
int low_limit; // low limit value
8686
int high_limit; // high limit value
87+
int zero_input_gpio_num; // which gpio clear signal input
8788
int accum_value; // accumulated count value
8889
pcnt_chan_t *channels[SOC_PCNT_CHANNELS_PER_UNIT]; // array of PCNT channels
8990
pcnt_watch_point_t watchers[PCNT_LL_WATCH_EVENT_MAX]; // array of PCNT watchers
@@ -226,6 +227,30 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
226227
for (int i = 0; i < PCNT_LL_WATCH_EVENT_MAX; i++) {
227228
unit->watchers[i].event_id = PCNT_LL_WATCH_EVENT_INVALID; // invalid all watch point
228229
}
230+
231+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
232+
// GPIO configuration
233+
gpio_config_t gpio_conf = {
234+
.intr_type = GPIO_INTR_DISABLE,
235+
.mode = GPIO_MODE_INPUT | (config->flags.io_loop_back ? GPIO_MODE_OUTPUT : 0), // also enable the output path if `io_loop_back` is enabled
236+
.pull_down_en = true,
237+
.pull_up_en = false,
238+
};
239+
240+
if (config->zero_input_gpio_num >= 0) {
241+
if (config->flags.invert_zero_input) {
242+
gpio_conf.pull_down_en = false;
243+
gpio_conf.pull_up_en = true;
244+
}
245+
gpio_conf.pin_bit_mask = 1ULL << config->zero_input_gpio_num;
246+
ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config zero GPIO failed");
247+
esp_rom_gpio_connect_in_signal(config->zero_input_gpio_num,
248+
pcnt_periph_signals.groups[group_id].units[unit_id].clear_sig,
249+
config->flags.invert_zero_input);
250+
}
251+
unit->zero_input_gpio_num = config->zero_input_gpio_num;
252+
#endif // SOC_PCNT_SUPPORT_ZERO_INPUT
253+
229254
ESP_LOGD(TAG, "new pcnt unit (%d,%d) at %p, count range:[%d,%d]", group_id, unit_id, unit, unit->low_limit, unit->high_limit);
230255
*ret_unit = unit;
231256
return ESP_OK;
@@ -249,6 +274,12 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit)
249274
ESP_RETURN_ON_FALSE(!unit->channels[i], ESP_ERR_INVALID_STATE, TAG, "channel %d still in working", i);
250275
}
251276

277+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
278+
if (unit->zero_input_gpio_num >= 0) {
279+
gpio_reset_pin(unit->zero_input_gpio_num);
280+
}
281+
#endif // SOC_PCNT_SUPPORT_ZERO_INPUT
282+
252283
ESP_LOGD(TAG, "del unit (%d,%d)", group_id, unit_id);
253284
// recycle memory resource
254285
ESP_RETURN_ON_ERROR(pcnt_destroy(unit), TAG, "destroy pcnt unit failed");
@@ -742,6 +773,8 @@ IRAM_ATTR static void pcnt_default_isr(void *args)
742773
uint32_t intr_status = pcnt_ll_get_intr_status(group->hal.dev);
743774
if (intr_status & PCNT_LL_UNIT_WATCH_EVENT(unit_id)) {
744775
pcnt_ll_clear_intr_status(group->hal.dev, PCNT_LL_UNIT_WATCH_EVENT(unit_id));
776+
777+
// points watcher event
745778
uint32_t event_status = pcnt_ll_get_event_status(group->hal.dev, unit_id);
746779
// iter on each event_id
747780
while (event_status) {

components/driver/test_apps/pulse_cnt/main/test_pulse_cnt.c

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -20,6 +20,9 @@ TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]")
2020
pcnt_unit_config_t unit_config = {
2121
.low_limit = -100,
2222
.high_limit = 100,
23+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
24+
.zero_input_gpio_num = -1,
25+
#endif
2326
};
2427
pcnt_unit_handle_t units[SOC_PCNT_UNITS_PER_GROUP];
2528
int count_value = 0;
@@ -77,6 +80,9 @@ TEST_CASE("pcnt_channel_install_uninstall", "[pcnt]")
7780
pcnt_unit_config_t unit_config = {
7881
.low_limit = -100,
7982
.high_limit = 100,
83+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
84+
.zero_input_gpio_num = -1,
85+
#endif
8086
};
8187
pcnt_chan_config_t chan_config = {
8288
.edge_gpio_num = TEST_PCNT_GPIO_A, // only detect edge signal in this case
@@ -165,6 +171,9 @@ TEST_CASE("pcnt_multiple_units_pulse_count", "[pcnt]")
165171
pcnt_unit_config_t unit_config = {
166172
.low_limit = -100,
167173
.high_limit = 100,
174+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
175+
.zero_input_gpio_num = -1,
176+
#endif
168177
};
169178
pcnt_unit_handle_t units[2];
170179
for (int i = 0; i < 2; i++) {
@@ -229,7 +238,10 @@ TEST_CASE("pcnt_quadrature_decode_event", "[pcnt]")
229238
{
230239
pcnt_unit_config_t unit_config = {
231240
.low_limit = -100,
232-
.high_limit = 100
241+
.high_limit = 100,
242+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
243+
.zero_input_gpio_num = -1,
244+
#endif
233245
};
234246

235247
printf("install pcnt unit\r\n");
@@ -352,7 +364,10 @@ TEST_CASE("pcnt_zero_cross_mode", "[pcnt]")
352364
{
353365
pcnt_unit_config_t unit_config = {
354366
.low_limit = -100,
355-
.high_limit = 100
367+
.high_limit = 100,
368+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
369+
.zero_input_gpio_num = -1,
370+
#endif
356371
};
357372

358373
printf("install pcnt unit\r\n");
@@ -445,6 +460,9 @@ TEST_CASE("pcnt_virtual_io", "[pcnt]")
445460
pcnt_unit_config_t unit_config = {
446461
.low_limit = -100,
447462
.high_limit = 100,
463+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
464+
.zero_input_gpio_num = -1,
465+
#endif
448466
};
449467
pcnt_chan_config_t chan_config = {
450468
.edge_gpio_num = TEST_PCNT_GPIO_A, // only detect edge signal in this case
@@ -490,3 +508,63 @@ TEST_CASE("pcnt_virtual_io", "[pcnt]")
490508
TEST_ESP_OK(pcnt_del_channel(chan));
491509
TEST_ESP_OK(pcnt_del_unit(unit));
492510
}
511+
512+
#if SOC_PCNT_SUPPORT_ZERO_INPUT
513+
TEST_CASE("pcnt_zero_input_signal", "[pcnt]")
514+
{
515+
pcnt_unit_config_t unit_config = {
516+
.low_limit = -1000,
517+
.high_limit = 1000,
518+
.zero_input_gpio_num = TEST_PCNT_GPIO_Z,
519+
.flags.io_loop_back = true,
520+
};
521+
522+
printf("install pcnt unit\r\n");
523+
pcnt_unit_handle_t unit = NULL;
524+
TEST_ESP_OK(pcnt_new_unit(&unit_config, &unit));
525+
pcnt_glitch_filter_config_t filter_config = {
526+
.max_glitch_ns = 1000,
527+
};
528+
TEST_ESP_OK(pcnt_unit_set_glitch_filter(unit, &filter_config));
529+
530+
printf("install pcnt channels\r\n");
531+
pcnt_chan_config_t chan_config = {
532+
.level_gpio_num = -1,
533+
.edge_gpio_num = TEST_PCNT_GPIO_A,
534+
.flags.io_loop_back = true,
535+
};
536+
pcnt_channel_handle_t channel;
537+
538+
TEST_ESP_OK(pcnt_new_channel(unit, &chan_config, &channel));
539+
TEST_ESP_OK(pcnt_channel_set_edge_action(channel, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
540+
TEST_ESP_OK(pcnt_channel_set_level_action(channel, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
541+
542+
printf("enable and start unit\r\n");
543+
544+
TEST_ESP_OK(pcnt_unit_enable(unit));
545+
TEST_ESP_OK(pcnt_unit_start(unit));
546+
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_Z, 0));
547+
548+
// trigger 10 rising edge on GPIO
549+
test_gpio_simulate_rising_edge(TEST_PCNT_GPIO_A, 10);
550+
551+
int count_value = 0;
552+
553+
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
554+
printf("count_value=%d\r\n", count_value);
555+
TEST_ASSERT_EQUAL(10, count_value);
556+
557+
printf("simulating zero input signal\r\n");
558+
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_Z, 1));
559+
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_Z, 0));
560+
561+
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
562+
printf("count_value=%d\r\n", count_value);
563+
TEST_ASSERT_EQUAL(0, count_value); // 0 after rst_sig
564+
565+
TEST_ESP_OK(pcnt_del_channel(channel));
566+
TEST_ESP_OK(pcnt_unit_stop(unit));
567+
TEST_ESP_OK(pcnt_unit_disable(unit));
568+
TEST_ESP_OK(pcnt_del_unit(unit));
569+
}
570+
#endif // SOC_PCNT_SUPPORT_ZERO_INPUT

components/driver/test_apps/pulse_cnt/main/test_pulse_cnt_board.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -11,6 +11,7 @@ extern "C" {
1111

1212
#define TEST_PCNT_GPIO_A 0
1313
#define TEST_PCNT_GPIO_B 2
14+
#define TEST_PCNT_GPIO_Z 4
1415

1516
#if CONFIG_PCNT_ISR_IRAM_SAFE
1617
#define TEST_PCNT_CALLBACK_ATTR IRAM_ATTR

components/hal/esp32p4/include/hal/clk_gate_ll.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
112112
return HP_SYS_CLKRST_REG_CRYPTO_ECDSA_CLK_EN;
113113
case PERIPH_ISP_MODULE:
114114
return HP_SYS_CLKRST_REG_ISP_CLK_EN;
115+
case PERIPH_PCNT_MODULE:
116+
return HP_SYS_CLKRST_REG_PCNT_APB_CLK_EN;
115117
default:
116118
return 0;
117119
}
@@ -264,6 +266,7 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
264266
return HP_SYS_CLKRST_PERI_CLK_CTRL119_REG;
265267
case PERIPH_MCPWM0_MODULE:
266268
case PERIPH_MCPWM1_MODULE:
269+
case PERIPH_PCNT_MODULE:
267270
return HP_SYS_CLKRST_SOC_CLK_CTRL2_REG;
268271
case PERIPH_TIMG0_MODULE:
269272
return HP_SYS_CLKRST_PERI_CLK_CTRL20_REG;

0 commit comments

Comments
 (0)