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,
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
6976struct 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
7582struct 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;
140148static pcnt_group_t * pcnt_acquire_group_handle (int group_id );
141149static void pcnt_release_group_handle (pcnt_group_t * group );
142150static 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
144153static 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+
9781027IRAM_ATTR static void pcnt_default_isr (void * args )
9791028{
9801029 bool need_yield = false;
0 commit comments