Skip to content

Commit 012318d

Browse files
committed
Merge branch 'feat/support_pcnt_on_h4' into 'master'
feat(pcnt): support pcnt on esp32h4 Closes IDF-12338 and IDF-13637 See merge request espressif/esp-idf!41526
2 parents 6e45f4d + ad5bdc8 commit 012318d

File tree

67 files changed

+1543
-792
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1543
-792
lines changed

components/esp_driver_dac/test_apps/dac/main/test_dac.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ TEST_CASE("DAC_dma_convert_frequency_test", "[dac]")
257257
gpio_set_direction(GPIO_NUM_4, GPIO_MODE_INPUT_OUTPUT);
258258
// The DAC conversion frequency is equal to I2S bclk.
259259
esp_rom_gpio_connect_out_signal(GPIO_NUM_4, i2s_periph_signal[0].m_tx_ws_sig, 0, 0);
260-
esp_rom_gpio_connect_in_signal(GPIO_NUM_4, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0);
260+
esp_rom_gpio_connect_in_signal(GPIO_NUM_4, soc_pcnt_signals[0].units[0].channels[0].pulse_sig_id_matrix, 0);
261261

262262
size_t len = 800;
263263
uint8_t data[len];

components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c
847847
gpio_func_sel(MASTER_WS_IO, PIN_FUNC_GPIO);
848848
gpio_set_direction(MASTER_WS_IO, GPIO_MODE_INPUT_OUTPUT);
849849
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_rx_ws_sig, 0, 0);
850-
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0);
850+
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, soc_pcnt_signals[0].units[0].channels[0].pulse_sig_id_matrix, 0);
851851

852852
const uint32_t test_freq[] = {
853853
8000, 10000, 11025, 12000, 16000, 22050,

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: 78 additions & 29 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
@@ -68,16 +75,17 @@ typedef struct pcnt_chan_t pcnt_chan_t;
6875

6976
struct pcnt_platform_t {
7077
_lock_t mutex; // platform level mutex lock
71-
pcnt_group_t *groups[SOC_PCNT_GROUPS]; // pcnt group pool
72-
int group_ref_counts[SOC_PCNT_GROUPS]; // reference count used to protect group install/uninstall
78+
pcnt_group_t *groups[SOC_PCNT_ATTR(INST_NUM)]; // pcnt group pool
79+
int group_ref_counts[SOC_PCNT_ATTR(INST_NUM)]; // reference count used to protect group install/uninstall
7380
};
7481

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;
80-
pcnt_unit_t *units[SOC_PCNT_UNITS_PER_GROUP]; // array of PCNT units
88+
pcnt_unit_t *units[SOC_PCNT_ATTR(UNITS_PER_INST)]; // array of PCNT units
8189
#if CONFIG_PM_ENABLE
8290
esp_pm_lock_handle_t pm_lock; // power management lock
8391
#endif
@@ -112,7 +120,7 @@ struct pcnt_unit_t {
112120
int clear_signal_gpio_num; // which gpio clear signal input
113121
int accum_value; // accumulated count value
114122
pcnt_step_interval_t step_info; // step interval info
115-
pcnt_chan_t *channels[SOC_PCNT_CHANNELS_PER_UNIT]; // array of PCNT channels
123+
pcnt_chan_t *channels[SOC_PCNT_ATTR(CHANS_PER_UNIT)]; // array of PCNT channels
116124
pcnt_watch_point_t watchers[PCNT_LL_WATCH_EVENT_MAX]; // array of PCNT watchers
117125
intr_handle_t intr; // interrupt handle
118126
pcnt_unit_fsm_t fsm; // record PCNT unit's driver state
@@ -140,17 +148,18 @@ 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
{
146155
pcnt_group_t *group = NULL;
147156
int unit_id = -1;
148-
for (int i = 0; i < SOC_PCNT_GROUPS; i++) {
157+
for (int i = 0; i < SOC_PCNT_ATTR(INST_NUM); i++) {
149158
group = pcnt_acquire_group_handle(i);
150159
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", i);
151160
// loop to search free unit in the group
152161
portENTER_CRITICAL(&group->spinlock);
153-
for (int j = 0; j < SOC_PCNT_UNITS_PER_GROUP; j++) {
162+
for (int j = 0; j < SOC_PCNT_ATTR(UNITS_PER_INST); j++) {
154163
if (!group->units[j]) {
155164
unit_id = j;
156165
group->units[j] = unit;
@@ -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;
@@ -243,7 +256,7 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
243256
} else {
244257
isr_flags |= PCNT_ALLOW_INTR_PRIORITY_MASK;
245258
}
246-
ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(pcnt_periph_signals.groups[group_id].irq, isr_flags,
259+
ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(soc_pcnt_signals[group_id].irq_id, isr_flags,
247260
(uint32_t)pcnt_ll_get_intr_status_reg(group->hal.dev), PCNT_LL_UNIT_WATCH_EVENT(unit_id),
248261
pcnt_default_isr, unit, &unit->intr), err,
249262
TAG, "install interrupt service failed");
@@ -311,18 +324,20 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit)
311324
int group_id = group->group_id;
312325
int unit_id = unit->unit_id;
313326

314-
for (int i = 0; i < SOC_PCNT_CHANNELS_PER_UNIT; i++) {
327+
for (int i = 0; i < SOC_PCNT_ATTR(CHANS_PER_UNIT); i++) {
315328
ESP_RETURN_ON_FALSE(!unit->channels[i], ESP_ERR_INVALID_STATE, TAG, "channel %d still in working", i);
316329
}
317330

318331
#if SOC_PCNT_SUPPORT_CLEAR_SIGNAL
319332
if (unit->clear_signal_gpio_num >= 0) {
320-
uint32_t clear_signal_idx = pcnt_periph_signals.groups[group_id].units[unit_id].clear_sig;
333+
uint32_t clear_signal_idx = soc_pcnt_signals[group_id].units[unit_id].clear_sig_id_matrix;
321334
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, clear_signal_idx, 0);
322335
}
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;
@@ -335,7 +350,7 @@ esp_err_t pcnt_unit_set_clear_signal(pcnt_unit_handle_t unit, const pcnt_clear_s
335350
pcnt_group_t *group = unit->group;
336351
int group_id = group->group_id;
337352
int unit_id = unit->unit_id;
338-
uint32_t clear_signal_idx = pcnt_periph_signals.groups[group_id].units[unit_id].clear_sig;
353+
uint32_t clear_signal_idx = soc_pcnt_signals[group_id].units[unit_id].clear_sig_id_matrix;
339354

340355
if (config) {
341356
int io_num = config->clear_signal_gpio_num;
@@ -534,7 +549,7 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt
534549
} else {
535550
isr_flags |= PCNT_ALLOW_INTR_PRIORITY_MASK;
536551
}
537-
ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(pcnt_periph_signals.groups[group_id].irq, isr_flags,
552+
ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(soc_pcnt_signals[group_id].irq_id, isr_flags,
538553
(uint32_t)pcnt_ll_get_intr_status_reg(group->hal.dev), PCNT_LL_UNIT_WATCH_EVENT(unit_id),
539554
pcnt_default_isr, unit, &unit->intr),
540555
TAG, "install interrupt service failed");
@@ -592,7 +607,7 @@ esp_err_t pcnt_unit_add_watch_point(pcnt_unit_handle_t unit, int watch_point)
592607
}
593608
// other threshold watch point
594609
else {
595-
int thres_num = SOC_PCNT_THRES_POINT_PER_UNIT - 1;
610+
int thres_num = SOC_PCNT_ATTR(THRES_POINT_PER_UNIT) - 1;
596611
switch (thres_num) {
597612
case 1:
598613
if (unit->watchers[PCNT_LL_WATCH_EVENT_THRES1].event_id == PCNT_LL_WATCH_EVENT_INVALID) {
@@ -779,7 +794,7 @@ esp_err_t pcnt_new_channel(pcnt_unit_handle_t unit, const pcnt_chan_config_t *co
779794
// search for a free channel
780795
int channel_id = -1;
781796
portENTER_CRITICAL(&unit->spinlock);
782-
for (int i = 0; i < SOC_PCNT_CHANNELS_PER_UNIT; i++) {
797+
for (int i = 0; i < SOC_PCNT_ATTR(CHANS_PER_UNIT); i++) {
783798
if (!unit->channels[i]) {
784799
channel_id = i;
785800
unit->channels[channel_id] = channel;
@@ -794,25 +809,25 @@ esp_err_t pcnt_new_channel(pcnt_unit_handle_t unit, const pcnt_chan_config_t *co
794809
gpio_func_sel(config->edge_gpio_num, PIN_FUNC_GPIO);
795810
gpio_input_enable(config->edge_gpio_num);
796811
esp_rom_gpio_connect_in_signal(config->edge_gpio_num,
797-
pcnt_periph_signals.groups[group_id].units[unit_id].channels[channel_id].pulse_sig,
812+
soc_pcnt_signals[group_id].units[unit_id].channels[channel_id].pulse_sig_id_matrix,
798813
config->flags.invert_edge_input);
799814
} else {
800815
// using virtual IO
801816
esp_rom_gpio_connect_in_signal(config->flags.virt_edge_io_level ? GPIO_MATRIX_CONST_ONE_INPUT : GPIO_MATRIX_CONST_ZERO_INPUT,
802-
pcnt_periph_signals.groups[group_id].units[unit_id].channels[channel_id].pulse_sig,
817+
soc_pcnt_signals[group_id].units[unit_id].channels[channel_id].pulse_sig_id_matrix,
803818
config->flags.invert_edge_input);
804819
}
805820

806821
if (config->level_gpio_num >= 0) {
807822
gpio_func_sel(config->level_gpio_num, PIN_FUNC_GPIO);
808823
gpio_input_enable(config->level_gpio_num);
809824
esp_rom_gpio_connect_in_signal(config->level_gpio_num,
810-
pcnt_periph_signals.groups[group_id].units[unit_id].channels[channel_id].control_sig,
825+
soc_pcnt_signals[group_id].units[unit_id].channels[channel_id].ctl_sig_id_matrix,
811826
config->flags.invert_level_input);
812827
} else {
813828
// using virtual IO
814829
esp_rom_gpio_connect_in_signal(config->flags.virt_level_io_level ? GPIO_MATRIX_CONST_ONE_INPUT : GPIO_MATRIX_CONST_ZERO_INPUT,
815-
pcnt_periph_signals.groups[group_id].units[unit_id].channels[channel_id].control_sig,
830+
soc_pcnt_signals[group_id].units[unit_id].channels[channel_id].ctl_sig_id_matrix,
816831
config->flags.invert_level_input);
817832
}
818833

@@ -846,12 +861,12 @@ esp_err_t pcnt_del_channel(pcnt_channel_handle_t chan)
846861

847862
if (chan->level_gpio_num >= 0) {
848863
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT,
849-
pcnt_periph_signals.groups[group_id].units[unit_id].channels[channel_id].control_sig,
864+
soc_pcnt_signals[group_id].units[unit_id].channels[channel_id].ctl_sig_id_matrix,
850865
0);
851866
}
852867
if (chan->edge_gpio_num >= 0) {
853868
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT,
854-
pcnt_periph_signals.groups[group_id].units[unit_id].channels[channel_id].pulse_sig,
869+
soc_pcnt_signals[group_id].units[unit_id].channels[channel_id].pulse_sig_id_matrix,
855870
0);
856871
}
857872

@@ -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+
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |

0 commit comments

Comments
 (0)