Architecture decision for shared flags

Hi there FreeRTOS team!

I’ve a working FreeRTOS application on ESP32. All my tasks are triggered only by notifications. They do their job and go back to sleep until an event triggers them. The most frequent event is a user rotatory encoder input. Every time the user moves left/right or up/down, the encoder sends a notification to the UI task to print the menu.

My problem here is that I’m using a global flag to keep count of the encoder value. When the UI task prints the menu, the task resets the encoder value to 0. Then, the user will start scrolling again from the 0th option and everyone is happy.

I would like to not use a global variable for this. I know I can use a mutex and use the encoder value as a shared resource, but I have several other similar scenarios where this is happening, so the complexity of several mutexes all around the code seems difficult to handle.

I’m doing this in ESP32, so atomic operations seem to be part of the answer here but I’m not sure.

I arrived at a FreeRTOS architecture decision that I don’t feel comfortable solving myself, and I’m not even sure how to put the right question into text, so I would appreciate the help navigating this decision

EDIT
I think part of this problem is that I know the UI task will finish printing the display way before the user can rotate the encoder again, so I know the encoder value won’t be updated in between. Its like “I’m done using this encoder value, its your turn”. I suppose this is a physical implementation rather than a FreeRTOS implementation?

Thanks a lot in advance

My personal thought would be that either you have the ISR record the rotory position, and notify the UI task, and then the UI task would, inside a critical section, read then reset the counter, and then act on it afterwords. This would allow for the UI to get behind, and still seem to have a uniform resposiveness to the knob.

The alternative would be to have the ISR record the last direction and send a notification and then the UI just process that. This might need so operation to “dejitter” the encoder, in case it sits right on a transition and thus the signal bounces periodically.

Note, Mutexes don’t help between a.task and an ISR. If ALL the actions on the resource are very quick, the critical section works and is much more light weight.