Drawing graphics with ILI9341_t3.h breaks FreqMeasure.h EDIT: Looks specific to a T4.0

KrisKasprzak

Well-known member
All,

I have a telemetry system that measures wheel rotations where the sensor generates a pulse for every revolution. When displaying the speed I'm computing rpm using the example in <FreqMeasure.h> and displaying the data along with graphics and such. Input pin is pin 22, I have several units based on T3.2 and T4.0. My test stand my wheel is generating a 25 hz pulse and very square as my scope shows. I was using #include <FreqMeasureMulti.h> and results were... [EDIT] Results were very bad, hence why I moved to FreqMeasure.h

Moving my code to FreqMeasure.h breaks when drawing graphics. When drawing only speed to an ILI9341 (2.8"), results are 27.0 +/- 0.1 (which is correct by the math). When I start drawing graphics, FreqMeasure jumps around 60 to 120.

I'm guessing it's a clock timing issue, but I'm not sure. Can anyone help?

Code:
#include <FreqMeasure.h>
#include <TimeLib.h>
#include <ILI9341_t3.h>

ILI9341_t3 Display(9, 2);

elapsedMillis UpdateDiaplay = 0;

void setup() {
  Serial.begin(115200);
  FreqMeasure.begin();
  Serial.println("Starting");

  Display.begin();
  Display.setTextWrap(false);
  Display.setRotation(1);
  Display.fillScreen(0);
}

double sum = 0.0, WRPM = 0.0;
float CarSpeed = 0.0;
int count = 0;

void loop() {
  delay(5);
  if (FreqMeasure.available()) {
    sum = sum + FreqMeasure.read();
    count = count + 1;
    if (UpdateDiaplay > 200) {
      UpdateDiaplay = 0;
      ComputeSpeed();
      DisplaySpeed();
    }
  }
}

void ComputeSpeed() {
  WRPM = 15.0 * FreqMeasure.countToFrequency(sum / count);
  CarSpeed = (WRPM * 9.125 * 2.0f * 3.14159f * 60.0f / (12.0f * 5280.0f));
  sum = 0;
  count = 0;
}

void DisplaySpeed() {

  // I need to draw graphics--small stuff will not break the FreqMeasure code
  // Display.fillRect(0,0,300,50, 2000);

  // larger will
  Display.fillRect(0, 0, 300, 150, 2000);

  Display.setTextSize(4);
  Display.setCursor(5, 200);
  Display.setTextColor(65535, 0);
  Display.println(CarSpeed, 1);
  Serial.println(CarSpeed);

  // if I restart FreqMeasure, results are less irratic, but incorrect
  FreqMeasure.begin();
}
 
Last edited:
Adding serial plotter of the data, clearly there is an issue.
 

Attachments

  • NoDisplay.jpg
    NoDisplay.jpg
    113.9 KB · Views: 27
  • WithDisplay.jpg
    WithDisplay.jpg
    139.7 KB · Views: 27
First thing I would try is changing loop() to be as shown below. With your original code, you may not include all of the freqMeasure data that is available.

Code:
void loop() {
  //delay(5);
  while (FreqMeasure.available()) {
    sum = sum + FreqMeasure.read();
    count = count + 1;
  }
  if (UpdateDiaplay > 200) {
    UpdateDiaplay = 0;
    ComputeSpeed();
    DisplaySpeed();
  }
}
 
Caveat: I did not test it, it is just wild guess based on what I am seeing in the code. I guess that Display.fillRect blocks interrupts (due to its use of beginSPITransaction), therefore FreqMeasure receives interrupt only once screen fill is complete leading to incorrect measurement. You could try calling FreqMeasure.begin(); again after screen update, so measurement is restarted after screen update. Or divide single fillRect() into multiple rectangles (say four rectangles each being 1/4 of screen area).
 
Code:
void DisplaySpeed() {

  // I need to draw graphics--small stuff will not break the FreqMeasure code
  // Display.fillRect(0,0,300,50, 2000);

  // larger will
  Display.fillRect(0, 0, 300, 150, 2000);

  Display.setTextSize(4);
  Display.setCursor(5, 200);
  Display.setTextColor(65535, 0);
  Display.println(CarSpeed, 1);
  Serial.println(CarSpeed);

  // if I restart FreqMeasure, results are less irratic, but incorrect
  FreqMeasure.begin();

Remove "Display.fillRect(0, 0, 300, 150, 2000);" and use


Rumour has it that the author can be found wandering around this forum
 
a) I would do what @joepasquariello mentioned and loop reading in the readings...
That is loop while available. I would also probably make that into a subroutine and call it after each display call

like:
Code:
void read_freqs() {
  while (FreqMeasure.available()) {
    sum = sum + FreqMeasure.read();
    count = count + 1;
  }
}

Code:
void DisplaySpeed() {

  // I need to draw graphics--small stuff will not break the FreqMeasure code
  // Display.fillRect(0,0,300,50, 2000);

  // larger will
  Display.fillRect(0, 0, 300, 150, 2000);
  read_freqs();

  Display.setTextSize(4);
  Display.setCursor(5, 200);
  Display.setTextColor(65535, 0);
  Display.println(CarSpeed, 1);
  read_freqs();
  Serial.println(CarSpeed);
  read_freqs();
}
last read_freqs();
not needed as it will through to call again...

b) Might try updating FreqMeasure library, and up the buffer size: #define FREQMEASURE_BUFFER_LEN 12
And see if that helps.

c) Could optimize the output code to reduce the need for fillRect. As you are using Opaque text output, it will fill in the old pixels with the new. Except if text is shorter than previous text on the right hand edges: So
1) probably don't need to fill in with color 2000 on left hand edge on every call only once...
2) You could fill in right hand edge several different ways, like: get the text origin X and remember it for each line. if less than the previous output, could use fill rect, could set text color to something like(65535, 2000) and output blanks until Text X is >= previous ...

d) Could use ili9341_t3n or other, that has some form of frame buffering, and use an async update...

Good luck
 
Back
Top