How to share TFT calls between loop() and ISR

Hi -- I'm drawing with TFT_eSPI. I have a clock showing on the screen that updates via loop() every second, but my loop() can take upwards of 500ms with the various things it does, so while the clock updates correctly, it stutters a bit.

To make it more smooth, I want to make a timer ISR that updates the clock every second, but since it will share the tft object with the loop() thread I know I need some kind of synchronization mechanism.

What's the simple/easy way to do this? Do I have to make a mutex object and then acquire it every time I want to call tft.something() from the loop thread?

Is there any easy way to mark my tft instance (say, with "volatile"?) so that it will be accessed atomically between threads? My threading experience was all in other languages, and there seem to be a dozen different mechanisms in C/C++, so it's unclear what the smart move is here.

Thanks!

Please post your sketch so that we can see what takes the time

Thanks Bob -- I think it's too involved to be useful to post (many hundreds of lines, multiple files, etc) -- it's logging temperature/humidity readings, drawing/updating a graph, serving webserver requests, checking for touch screen events, etc. The 500ms is probably overstated; it's on average probably closer to 20-75ms, and sometimes 100-200ms (estimation) mostly in drawing calls to the shared tft instance, scroll()'ing a large sprite, etc. It's just enough to make the seconds in the time display look a little wonky.

Thinking it through some more, though, I think I would need to just acquire a mutex... even though the time update is an isolated action, I would still have to sync across not just the tft instance but the several sprites linked to the main tft instance as well, so there will be critical sections of code that need synchronizing. In other words, probably no simple one-protected-variable solution.

I think I just answered my own question, but any other opinions welcome. :slight_smile:

Don't be silly. There are many professionals on this forum -- not scared by some code.

So that for an ESP32-based board, correct? Which one?

Given an eSP32, then I wouldn't do this:

Rather take advantage of the Real Time Operating System (known as FreeRTOS) that's already running in the ESP32. You could have one task to handle the clock and another to handle the other stuff. There are a couple of ways to handle access to the TFT object. You could use a mutex as you mentioned. Or perhaps, have a third task that exclusively owns the TFT and feed jobs to it through a FreeRTOS queue.

Yeah, an ESP32 dev board.

Ah, thanks -- I'd seen reference to that but didn't realize it was already running; (thought it was something I needed to enable or install, etc.)

@jremington -- gotcha, noted, and if I need more help on this I'll post the code. Thanks.

The pattern I typically use is

volatile bool _triggered = false;

void loop()
{
  if (_triggered)
  {
    _triggered = false; 
    do stuff
  }
}

void triggerISR()
{
   _triggered = true;
}
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.