Screen Buffer - Confusion over function pointers

Hi,

I've been upset with the tft I'm using with a teensy synth project flickering when I call functions that update the screen. Someone told me that I need to make a buffer so that it sends the commands synchronised to the screens refresh rate.

The code I have come up with complies, runs and does pretty much what I want it to do, but it's throwing up a few warnings in VScode.

here's the code trimmed down as much as possible but still showing the problem:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <Arduino.h>
#define bufMaxScreens 20

//  globals
uint64_t currentTime = 0;          //   keep track of time (micros)
uint64_t prevTime= 0;
uint64_t refreshRate = 2000000;    //  in micros

typedef void(*FunctionPointer);     // typedef a FunctionPointer

void (*scrBuf[bufMaxScreens])();    //  create array of function pointers as screen buffer

byte drawnFlag = (LOW);           
int inQueue = 0;


void setup() {
  Serial.begin(9600);
  delay(2000);                        //  to allow time for serial monitor to start before program commences
  Serial.println("setup complete");
}



//  draws screens in queue when time interval passes
void refresher()
{
  currentTime = micros();         // check the time

  if (currentTime > prevTime + refreshRate)   //  if time has passed the refreshRate
  {
      Serial.println("refreshRate passed, so draw screens in buffer");

      for (int i = 0; i < inQueue; i++)
      {
        Serial.print("draw screen: ");
        Serial.println(i);
        
        (*scrBuf[i])();         //   draw the screen whose pointer is stored in i
      }

    prevTime = currentTime;
    drawnFlag = (HIGH);       //  yes we have completed the drawings, so it's OK to add more to the queue
    inQueue = 0;              //  reset the queue
  }

}


//  adds screen to queue, returns 1 if sucessful, 0 if buffer full
int addtoQueue(void (*function))
{
  if(inQueue >= bufMaxScreens)          // if the buffer is full
  {
    Serial.println("buffer full");
    return 0;
  }

  else if (inQueue < bufMaxScreens)     // if the buffer is not full
  {
    //queue[inQueue] = function;
    scrBuf[inQueue] = function;     //** WARNING a value of type "void *" cannot be assigned to an entity of type "void (*)()"
    inQueue++;                      //** WARNING invalid conversion from 'void*' to 'void (*)()' [-fpermissive]
    Serial.print("queue++, number in q: ");
    Serial.println(inQueue);
    return 1;
  }
  return 0;
}


//  some functions to simulate screens being drawn
void homeScreen() {Serial.println("showing home screen");}
void debugScreen() {Serial.println("showing debug screen");}
void mainScreen() {Serial.println("showing main screen");}



//  simulates events that need screens to be drawn
void addStuff()
{
 
 if (drawnFlag == (LOW)) return;

 if (drawnFlag == (HIGH));
 {
    Serial.println("flag high, so add screens to queue");
    
    FunctionPointer main = (FunctionPointer)mainScreen;
    
    addtoQueue(main);               //**   no warning, but requres main to be defined above
    addtoQueue(homeScreen);         //**   WARNING ***  invalid conversion from 'void (*)()' to 'void*
    addtoQueue(debugScreen);        //**   WARNING ***  invalid conversion from 'void (*)()' to 'void*

    drawnFlag = (LOW);        //  set the flag LOW so we know the screens have been added to queue
                              // (stop buffer filling up with same things repeatedly)
  }
}


void loop()
{
  refresher();
  addStuff();
  delay(100);     //  slow things down so serial monitor doesn't crash

  long time = currentTime;
  Serial.print("time :");
  Serial.println(time);       // print timestamp on screen
}



I've highlighted the warnings I get on the relevant lines with //**WARNING, there are 4 of them.

I guess the first question I have is: is what I've programmed here suitable for the job? am I barking up the right tree? and if not, what should I be doing? (I am very much a novice at programming)

The second question would be, if this is the right sort of thing to do, how do I get rid of the warnings? I've played around with the syntax for a few hours and read a lot online but haven't made any real progress.

I think the problem is I'm getting confused with function pointers and have possibly made things worse by using the typedef.

Thanks for reading!
You're forgetting the parentheses around the function parameters (even if empty) that actually make the pointer a function pointer.

I.e., not this:
 
typedef void(*FunctionPointer);   // this is just void *FunctionPointer; 

but this:
 
typedef void(*FunctionPointer)();


And not this
 
int addtoQueue(void (*function))

but this
 
int addtoQueue(void (*function)())

Or, since you have a typedef, this
 
int addtoQueue(FunctionPointer function)


And you don't need the (FunctionPointer) typecast in front of mainScreen. It's already of the correct type.
ah that fixed it! Thank you for the clear explanation dutch!


do you think the code is suitable to use as a screen buffer like I describe?
do you think the code is suitable to use as a screen buffer like I describe?

I don't know. It's worth a try, I guess. But I think you might need hardware support to properly sync with the vertical blanking interval. So some kind of OS (or library) function might be needed.
But I don't really know anything about it.
no worries! many thanks again for your help
Are you using this?
https://www.arduino.cc/en/Guide/TFT


> Serial.println("refreshRate passed, so draw screens in buffer");
> Serial.print("draw screen: ");
All this debug in time-sensitive code isn't going to do you any favours.

> Serial.begin(9600);
This is bits per second, which roughly translates as 960 characters per second.
Which, in say a minimum acceptable refresh rate of 20Hz (50ms) gets you just 48 characters.

You're making the code slow with your excessive logging.

> if (drawnFlag == (HIGH));
Watch the ; at the end of this line.
It's a good job you already returned for LOW, because this test does nothing.
Hi Salem


Thanks for the tips!

The Serial.prints were just so I could see what was happening in the program without the rigmarole and complexity of using an actual display, I understand that they slow things down quite a bit. Same with the baud rate, the eventual program will be running much faster, but I was just using the default value for the initial proof of concept.


Great spot on the semicolon, would have taken ages for me to find that.


That's not the TFT i'm using, I'm actually using a 800x480 5" jobby, with this as the driver: https://www.adafruit.com/product/1590. I'm running it all off a teensy 3.6 rather than an Arduino (although the teensy still uses the Arduino framework) so it's got a fair bit more grunt/potential than the puny Arduino Uno.

Topic archived. No new replies allowed.