@@ -92,6 +92,16 @@ typedef struct {
9292 int watch_point_value ; // value to be watched
9393} pcnt_watch_point_t ;
9494
95+ typedef struct {
96+ #if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
97+ int step_interval ; // step interval
98+ int step_limit ; // step limit value
99+ #else
100+ int step_interval_forward ; // step interval for forward direction
101+ int step_interval_backward ; // step interval for backward direction
102+ #endif
103+ } pcnt_step_interval_t ;
104+
95105typedef enum {
96106 PCNT_UNIT_FSM_INIT ,
97107 PCNT_UNIT_FSM_ENABLE ,
@@ -103,10 +113,9 @@ struct pcnt_unit_t {
103113 int unit_id ; // allocated unit numerical ID
104114 int low_limit ; // low limit value
105115 int high_limit ; // high limit value
106- int step_limit ; // step limit value
107116 int clear_signal_gpio_num ; // which gpio clear signal input
108117 int accum_value ; // accumulated count value
109- int step_interval ; // PCNT step notify interval value
118+ pcnt_step_interval_t step_info ; // step interval info
110119 pcnt_chan_t * channels [SOC_PCNT_CHANNELS_PER_UNIT ]; // array of PCNT channels
111120 pcnt_watch_point_t watchers [PCNT_LL_WATCH_EVENT_MAX ]; // array of PCNT watchers
112121 intr_handle_t intr ; // interrupt handle
@@ -281,11 +290,11 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
281290 unit -> flags .en_step_notify_up = config -> flags .en_step_notify_up ;
282291#if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
283292 if (config -> flags .en_step_notify_up ) {
284- unit -> step_limit = config -> high_limit ;
293+ unit -> step_info . step_limit = config -> high_limit ;
285294 } else if (config -> flags .en_step_notify_down ) {
286- unit -> step_limit = config -> low_limit ;
295+ unit -> step_info . step_limit = config -> low_limit ;
287296 }
288- pcnt_ll_set_step_limit_value (group -> hal .dev , unit_id , unit -> step_limit );
297+ pcnt_ll_set_step_limit_value (group -> hal .dev , unit_id , unit -> step_info . step_limit );
289298#endif
290299#endif
291300
@@ -679,11 +688,26 @@ esp_err_t pcnt_unit_add_watch_step(pcnt_unit_handle_t unit, int step_interval)
679688 ESP_ERR_INVALID_ARG , TAG , "invalid step interval" );
680689 ESP_RETURN_ON_FALSE (step_interval >= unit -> low_limit && step_interval <= unit -> high_limit ,
681690 ESP_ERR_INVALID_ARG , TAG , "step interval out of range [%d,%d]" , unit -> low_limit , unit -> high_limit );
682- ESP_RETURN_ON_FALSE (unit -> step_interval == 0 ,
683- ESP_ERR_INVALID_STATE , TAG , "watch step has been set to %d already" , unit -> step_interval );
684691
685- unit -> step_interval = step_interval ;
686- pcnt_ll_set_step_value (group -> hal .dev , unit -> unit_id , step_interval );
692+ #if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
693+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval == 0 ,
694+ ESP_ERR_INVALID_STATE , TAG , "watch step has been set to %d already" , unit -> step_info .step_interval );
695+ pcnt_ll_set_step_value (group -> hal .dev , unit -> unit_id , step_interval > 0 ? PCNT_STEP_FORWARD : PCNT_STEP_BACKWARD , (uint16_t )step_interval );
696+ unit -> step_info .step_interval = step_interval ;
697+ #else
698+ if (step_interval > 0 ) {
699+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval_forward == 0 ,
700+ ESP_ERR_INVALID_STATE , TAG , "watch step in forward has been set to %d already" , unit -> step_info .step_interval_forward );
701+ pcnt_ll_set_step_value (group -> hal .dev , unit -> unit_id , PCNT_STEP_FORWARD , (uint16_t )step_interval );
702+ unit -> step_info .step_interval_forward = step_interval ;
703+ } else {
704+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval_backward == 0 ,
705+ ESP_ERR_INVALID_STATE , TAG , "watch step in backward has been set to %d already" , unit -> step_info .step_interval_backward );
706+ pcnt_ll_set_step_value (group -> hal .dev , unit -> unit_id , PCNT_STEP_BACKWARD , (uint16_t )step_interval );
707+ unit -> step_info .step_interval_backward = step_interval ;
708+ }
709+ #endif //PCNT_LL_STEP_NOTIFY_DIR_LIMIT
710+
687711 // different units are mixing in the same register, so we use the group's spinlock here
688712 portENTER_CRITICAL (& group -> spinlock );
689713 pcnt_ll_enable_step_notify (group -> hal .dev , unit -> unit_id , true);
@@ -692,21 +716,57 @@ esp_err_t pcnt_unit_add_watch_step(pcnt_unit_handle_t unit, int step_interval)
692716 return ESP_OK ;
693717}
694718
695- esp_err_t pcnt_unit_remove_watch_step (pcnt_unit_handle_t unit )
719+ esp_err_t pcnt_unit_remove_all_watch_step (pcnt_unit_handle_t unit )
696720{
697721 pcnt_group_t * group = NULL ;
698722 ESP_RETURN_ON_FALSE (unit , ESP_ERR_INVALID_ARG , TAG , "invalid argument" );
699723 group = unit -> group ;
700- ESP_RETURN_ON_FALSE (unit -> step_interval != 0 , ESP_ERR_INVALID_STATE , TAG , "watch step not added yet" );
701-
702- unit -> step_interval = 0 ;
724+ #if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
725+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval != 0 , ESP_ERR_INVALID_STATE , TAG , "watch step not added yet" );
726+ unit -> step_info .step_interval = 0 ;
727+ #else
728+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval_forward != 0 || unit -> step_info .step_interval_backward != 0 ,
729+ ESP_ERR_INVALID_STATE , TAG , "watch step in forward or backward not added yet" );
730+ unit -> step_info .step_interval_forward = 0 ;
731+ unit -> step_info .step_interval_backward = 0 ;
732+ #endif
703733
704734 portENTER_CRITICAL (& group -> spinlock );
705735 pcnt_ll_enable_step_notify (group -> hal .dev , unit -> unit_id , false);
706736 portEXIT_CRITICAL (& group -> spinlock );
707737
708738 return ESP_OK ;
709739}
740+
741+ esp_err_t pcnt_unit_remove_single_watch_step (pcnt_unit_handle_t unit , int step_interval )
742+ {
743+ pcnt_group_t * group = NULL ;
744+ ESP_RETURN_ON_FALSE (unit , ESP_ERR_INVALID_ARG , TAG , "invalid argument" );
745+ group = unit -> group ;
746+ #if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
747+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval == step_interval , ESP_ERR_INVALID_STATE , TAG , "watch step %d not added yet" , step_interval );
748+ unit -> step_info .step_interval = 0 ;
749+ portENTER_CRITICAL (& group -> spinlock );
750+ pcnt_ll_enable_step_notify (group -> hal .dev , unit -> unit_id , false);
751+ portEXIT_CRITICAL (& group -> spinlock );
752+ #else
753+ if (step_interval > 0 ) {
754+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval_forward == step_interval , ESP_ERR_INVALID_STATE , TAG , "watch step %d not added yet" , step_interval );
755+ pcnt_ll_set_step_value (group -> hal .dev , unit -> unit_id , PCNT_STEP_FORWARD , 0 );
756+ unit -> step_info .step_interval_forward = 0 ;
757+ } else {
758+ ESP_RETURN_ON_FALSE (unit -> step_info .step_interval_backward == step_interval , ESP_ERR_INVALID_STATE , TAG , "watch step %d not added yet" , step_interval );
759+ pcnt_ll_set_step_value (group -> hal .dev , unit -> unit_id , PCNT_STEP_BACKWARD , 0 );
760+ unit -> step_info .step_interval_backward = 0 ;
761+ }
762+ if (unit -> step_info .step_interval_forward == 0 && unit -> step_info .step_interval_backward == 0 ) {
763+ portENTER_CRITICAL (& group -> spinlock );
764+ pcnt_ll_enable_step_notify (group -> hal .dev , unit -> unit_id , false);
765+ portEXIT_CRITICAL (& group -> spinlock );
766+ }
767+ #endif
768+ return ESP_OK ;
769+ }
710770#endif //SOC_PCNT_SUPPORT_STEP_NOTIFY
711771
712772esp_err_t pcnt_new_channel (pcnt_unit_handle_t unit , const pcnt_chan_config_t * config , pcnt_channel_handle_t * ret_chan )
@@ -962,6 +1022,7 @@ IRAM_ATTR static void pcnt_default_isr(void *args)
9621022 // using while loop so that we don't miss any event
9631023 while (event_status ) {
9641024#if SOC_PCNT_SUPPORT_STEP_NOTIFY
1025+ #if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
9651026 // step event has higher priority than pointer event
9661027 if (event_status & (BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL ) | BIT (PCNT_LL_STEP_EVENT_REACH_LIMIT ))) {
9671028 if (event_status & BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL )) {
@@ -972,13 +1033,27 @@ IRAM_ATTR static void pcnt_default_isr(void *args)
9721033 if (event_status & BIT (PCNT_LL_STEP_EVENT_REACH_LIMIT )) {
9731034 event_status &= ~BIT (PCNT_LL_STEP_EVENT_REACH_LIMIT );
9741035 // adjust current count value to the step limit
975- count_value = unit -> step_limit ;
1036+ count_value = unit -> step_info . step_limit ;
9761037 if (unit -> flags .accum_count ) {
9771038 portENTER_CRITICAL_ISR (& unit -> spinlock );
978- unit -> accum_value += unit -> step_limit ;
1039+ unit -> accum_value += unit -> step_info . step_limit ;
9791040 portEXIT_CRITICAL_ISR (& unit -> spinlock );
9801041 }
9811042 }
1043+ #else
1044+ // step event has higher priority than pointer event
1045+ if (event_status & (BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL_FORWARD ) | BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL_BACKWARD ))) {
1046+ if (event_status & BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL_FORWARD )) {
1047+ event_status &= ~BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL_FORWARD );
1048+ // align current count value to the step interval
1049+ count_value = pcnt_ll_get_count (group -> hal .dev , unit_id );
1050+ }
1051+ if (event_status & BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL_BACKWARD )) {
1052+ event_status &= ~BIT (PCNT_LL_STEP_EVENT_REACH_INTERVAL_BACKWARD );
1053+ // align current count value to the step interval
1054+ count_value = pcnt_ll_get_count (group -> hal .dev , unit_id );
1055+ }
1056+ #endif // PCNT_LL_STEP_NOTIFY_DIR_LIMIT
9821057 // step event may happen with other pointer event at the same time, we don't need to process them again
9831058 event_status &= ~(BIT (PCNT_LL_WATCH_EVENT_LOW_LIMIT ) | BIT (PCNT_LL_WATCH_EVENT_HIGH_LIMIT ) |
9841059 BIT (PCNT_LL_WATCH_EVENT_THRES0 ) | BIT (PCNT_LL_WATCH_EVENT_THRES1 ));
0 commit comments