Skip to content

Commit ad5bdc8

Browse files
committed
feat(pcnt): support pcnt on esp32h4
1 parent 04b9349 commit ad5bdc8

File tree

30 files changed

+996
-114
lines changed

30 files changed

+996
-114
lines changed

components/esp_driver_pcnt/include/driver/pulse_cnt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef struct {
5959
* @brief PCNT unit configuration
6060
*/
6161
typedef struct {
62+
pcnt_clock_source_t clk_src; /*!< Clock source for PCNT unit */
6263
int low_limit; /*!< Low limitation of the count unit, should be lower than 0 */
6364
int high_limit; /*!< High limitation of the count unit, should be higher than 0 */
6465
int intr_priority; /*!< PCNT interrupt priority,

components/esp_driver_pcnt/src/pulse_cnt.c

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525
#include "soc/gpio_pins.h"
2626
#include "hal/pcnt_hal.h"
2727
#include "hal/pcnt_ll.h"
28+
#include "driver/gpio.h"
29+
#include "driver/pulse_cnt.h"
2830
#include "esp_private/esp_clk.h"
2931
#include "esp_private/periph_ctrl.h"
3032
#include "esp_private/sleep_retention.h"
31-
#include "driver/gpio.h"
3233
#include "esp_private/gpio.h"
33-
#include "driver/pulse_cnt.h"
34+
#include "esp_private/esp_clk_tree_common.h"
3435
#include "esp_memory_utils.h"
3536

3637
// If ISR handler is allowed to run whilst cache is disabled,
@@ -49,6 +50,12 @@
4950

5051
#define PCNT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED
5152

53+
#if SOC_PERIPH_CLK_CTRL_SHARED
54+
#define PCNT_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
55+
#else
56+
#define PCNT_CLOCK_SRC_ATOMIC()
57+
#endif
58+
5259
#if !SOC_RCC_IS_INDEPENDENT
5360
#define PCNT_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
5461
#else
@@ -75,6 +82,7 @@ struct pcnt_platform_t {
7582
struct pcnt_group_t {
7683
int group_id; // Group ID, index from 0
7784
int intr_priority; // PCNT interrupt priority
85+
pcnt_clock_source_t clk_src; // PCNT clock source
7886
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
7987
pcnt_hal_context_t hal;
8088
pcnt_unit_t *units[SOC_PCNT_ATTR(UNITS_PER_INST)]; // array of PCNT units
@@ -140,6 +148,7 @@ static pcnt_platform_t s_platform;
140148
static pcnt_group_t *pcnt_acquire_group_handle(int group_id);
141149
static void pcnt_release_group_handle(pcnt_group_t *group);
142150
static void pcnt_default_isr(void *args);
151+
static esp_err_t pcnt_select_periph_clock(pcnt_unit_t *unit, pcnt_clock_source_t clk_src);
143152

144153
static esp_err_t pcnt_register_to_group(pcnt_unit_t *unit)
145154
{
@@ -222,6 +231,10 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
222231
int group_id = group->group_id;
223232
int unit_id = unit->unit_id;
224233

234+
pcnt_clock_source_t pcnt_clk_src = config->clk_src ? config->clk_src : PCNT_CLK_SRC_DEFAULT;
235+
ESP_GOTO_ON_ERROR(pcnt_select_periph_clock(unit, pcnt_clk_src), err, TAG, "select periph clock failed");
236+
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)group->clk_src, true), err, TAG, "clock source enable failed");
237+
225238
// if interrupt priority specified before, it cannot be changed until the group is released
226239
// check if the new priority specified consistents with the old one
227240
bool intr_priority_conflict = false;
@@ -323,6 +336,8 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit)
323336
#endif // SOC_PCNT_SUPPORT_CLEAR_SIGNAL
324337

325338
ESP_LOGD(TAG, "del unit (%d,%d)", group_id, unit_id);
339+
// disable clock source
340+
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)group->clk_src, false), TAG, "clock source disable failed");
326341
// recycle memory resource
327342
ESP_RETURN_ON_ERROR(pcnt_destroy(unit), TAG, "destroy pcnt unit failed");
328343
return ESP_OK;
@@ -930,14 +945,6 @@ static pcnt_group_t *pcnt_acquire_group_handle(int group_id)
930945
_lock_release(&s_platform.mutex);
931946

932947
if (new_group) {
933-
#if CONFIG_PM_ENABLE
934-
// PCNT uses the APB as its function clock,
935-
// and its filter module is sensitive to the clock frequency
936-
// thus we choose the APM_MAX lock to prevent the function clock from being changed
937-
if (esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, pcnt_periph_signals.groups[group_id].module_name, &group->pm_lock) != ESP_OK) {
938-
ESP_LOGW(TAG, "create pm lock failed");
939-
}
940-
#endif
941948
ESP_LOGD(TAG, "new group (%d) at %p", group_id, group);
942949
}
943950

@@ -975,6 +982,48 @@ static void pcnt_release_group_handle(pcnt_group_t *group)
975982
}
976983
}
977984

985+
static esp_err_t pcnt_select_periph_clock(pcnt_unit_t *unit, pcnt_clock_source_t clk_src)
986+
{
987+
esp_err_t ret = ESP_OK;
988+
pcnt_group_t *group = unit->group;
989+
bool clock_selection_conflict = false;
990+
bool do_clock_init = false;
991+
// group clock source is shared by all units
992+
portENTER_CRITICAL(&group->spinlock);
993+
if (group->clk_src == 0) {
994+
group->clk_src = clk_src;
995+
do_clock_init = true;
996+
} else {
997+
clock_selection_conflict = (group->clk_src != clk_src);
998+
}
999+
portEXIT_CRITICAL(&group->spinlock);
1000+
ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_ARG, TAG,
1001+
"group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src);
1002+
1003+
if (do_clock_init) {
1004+
1005+
#if CONFIG_PM_ENABLE
1006+
// PCNT filter module is sensitive to the clock frequency
1007+
// to make the pcnt works reliable, the source clock must stay alive and unchanged
1008+
esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
1009+
#if PCNT_LL_CLOCK_SUPPORT_APB
1010+
if (clk_src == PCNT_CLK_SRC_APB) {
1011+
// APB clock frequency can be changed during DFS
1012+
// thus we choose the APM_MAX lock to prevent the function clock from being changed
1013+
pm_lock_type = ESP_PM_APB_FREQ_MAX;
1014+
}
1015+
#endif // PCNT_LL_CLOCK_SUPPORT_APB
1016+
ret = esp_pm_lock_create(pm_lock_type, 0, soc_pcnt_signals[group->group_id].module_name, &group->pm_lock);
1017+
ESP_RETURN_ON_ERROR(ret, TAG, "create pm lock failed");
1018+
#endif // CONFIG_PM_ENABLE
1019+
1020+
PCNT_CLOCK_SRC_ATOMIC() {
1021+
pcnt_ll_set_clock_source(group->hal.dev, clk_src);
1022+
}
1023+
}
1024+
return ret;
1025+
}
1026+
9781027
IRAM_ATTR static void pcnt_default_isr(void *args)
9791028
{
9801029
bool need_yield = false;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
2-
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
1+
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
2+
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |

components/hal/esp32/include/hal/pcnt_ll.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
#include <stdbool.h>
2020
#include <soc/soc.h>
2121
#include "soc/pcnt_struct.h"
22-
#include "hal/pcnt_types.h"
23-
#include "hal/misc.h"
2422
#include "soc/dport_access.h"
2523
#include "soc/dport_reg.h"
24+
#include "hal/pcnt_types.h"
25+
#include "hal/misc.h"
26+
#include "hal/assert.h"
2627

2728
#ifdef __cplusplus
2829
extern "C" {
@@ -45,6 +46,19 @@ typedef enum {
4546

4647
#define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1)
4748
#define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id))
49+
#define PCNT_LL_CLOCK_SUPPORT_APB 1
50+
51+
/**
52+
* @brief Set clock source for pcnt group
53+
*
54+
* @param hw Peripheral PCNT hardware instance address.
55+
* @param clk_src Clock source
56+
*/
57+
static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src)
58+
{
59+
(void)hw;
60+
HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source");
61+
}
4862

4963
/**
5064
* @brief Set PCNT channel edge action

components/hal/esp32c5/include/hal/pcnt_ll.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
#include <stdlib.h>
1111
#include <stdbool.h>
1212
#include "soc/pcnt_struct.h"
13+
#include "soc/pcr_struct.h"
1314
#include "hal/pcnt_types.h"
1415
#include "hal/misc.h"
15-
#include "soc/pcr_struct.h"
16+
#include "hal/assert.h"
1617

1718
#ifdef __cplusplus
1819
extern "C" {
@@ -40,6 +41,19 @@ typedef enum {
4041

4142
#define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1)
4243
#define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id))
44+
#define PCNT_LL_CLOCK_SUPPORT_APB 1
45+
46+
/**
47+
* @brief Set clock source for pcnt group
48+
*
49+
* @param hw Peripheral PCNT hardware instance address.
50+
* @param clk_src Clock source
51+
*/
52+
static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src)
53+
{
54+
(void)hw;
55+
HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source");
56+
}
4357

4458
/**
4559
* @brief Set PCNT channel edge action

components/hal/esp32c6/include/hal/pcnt_ll.h

Lines changed: 16 additions & 2 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-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -18,8 +18,9 @@
1818
#include <stdlib.h>
1919
#include <stdbool.h>
2020
#include "soc/pcnt_struct.h"
21-
#include "hal/pcnt_types.h"
2221
#include "soc/pcr_struct.h"
22+
#include "hal/pcnt_types.h"
23+
#include "hal/assert.h"
2324

2425
#ifdef __cplusplus
2526
extern "C" {
@@ -42,6 +43,19 @@ typedef enum {
4243

4344
#define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1)
4445
#define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id))
46+
#define PCNT_LL_CLOCK_SUPPORT_APB 1
47+
48+
/**
49+
* @brief Set clock source for pcnt group
50+
*
51+
* @param hw Peripheral PCNT hardware instance address.
52+
* @param clk_src Clock source
53+
*/
54+
static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src)
55+
{
56+
(void)hw;
57+
HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source");
58+
}
4559

4660
/**
4761
* @brief Set PCNT channel edge action

components/hal/esp32h2/include/hal/pcnt_ll.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -18,11 +18,12 @@
1818
#include <stdlib.h>
1919
#include <stdbool.h>
2020
#include "soc/pcnt_struct.h"
21+
#include "soc/chip_revision.h"
22+
#include "soc/pcr_struct.h"
2123
#include "hal/pcnt_types.h"
2224
#include "hal/misc.h"
25+
#include "hal/assert.h"
2326
#include "hal/efuse_hal.h"
24-
#include "soc/chip_revision.h"
25-
#include "soc/pcr_struct.h"
2627

2728
#ifdef __cplusplus
2829
extern "C" {
@@ -48,9 +49,22 @@ typedef enum {
4849
PCNT_LL_STEP_EVENT_REACH_INTERVAL
4950
} pcnt_ll_step_event_id_t;
5051

51-
#define PCNT_LL_STEP_NOTIFY_DIR_LIMIT 1
5252
#define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1)
5353
#define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id))
54+
#define PCNT_LL_STEP_NOTIFY_DIR_LIMIT 1
55+
#define PCNT_LL_CLOCK_SUPPORT_APB 1
56+
57+
/**
58+
* @brief Set clock source for pcnt group
59+
*
60+
* @param hw Peripheral PCNT hardware instance address.
61+
* @param clk_src Clock source
62+
*/
63+
static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src)
64+
{
65+
(void)hw;
66+
HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source");
67+
}
5468

5569
/**
5670
* @brief Set PCNT channel edge action

components/hal/esp32h21/include/hal/pcnt_ll.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
#include <stdlib.h>
1111
#include <stdbool.h>
1212
#include "soc/pcnt_struct.h"
13+
#include "soc/pcr_struct.h"
1314
#include "hal/pcnt_types.h"
1415
#include "hal/misc.h"
15-
#include "soc/pcr_struct.h"
16+
#include "hal/assert.h"
1617

1718
#ifdef __cplusplus
1819
extern "C" {
@@ -40,6 +41,19 @@ typedef enum {
4041

4142
#define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1)
4243
#define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id))
44+
#define PCNT_LL_CLOCK_SUPPORT_APB 1
45+
46+
/**
47+
* @brief Set clock source for pcnt group
48+
*
49+
* @param hw Peripheral PCNT hardware instance address.
50+
* @param clk_src Clock source
51+
*/
52+
static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src)
53+
{
54+
(void)hw;
55+
HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source");
56+
}
4357

4458
/**
4559
* @brief Set PCNT channel edge action

0 commit comments

Comments
 (0)