arduino crashes when receiving bytes over uart, trying to draw to screen

Hi. My setup is this: I've got a computer program sending 5 byte messages to Arduino Uno, the first one (0x80) just says to write the next bytes into a buffer, the last one (0x81) just says to stop writing to the buffer and declare that there is new data, so the buffer itself is only 3 bytes. I am drawing info to an ILI9341 screen using a library called PDQ_GFX, which is nearly identical to the Adafruit GFX library except it draws much faster. the first byte dictates whether the messages deals with a parameter value, or a parameter name. if byte Buffer[0] is 0x82, then it will draw the value of byte Buffer[2] in decimal form at an x/y position dictated by byte Buffer[1]. The Buffer[2] value never goes above 0x7F, which is how this all works. if Buffer[0] is 0x83, then it grabs a parameter name from program memory at Buffer[2] and draws it at Buffer[1]. The serial code is mostly taken from the Serial Input Basics thread. This works mostly well, until the parameter values from the computer change too quickly, and then the Arduino freezes. I'm sure there's a way to get around this. Here is my code

#include <SPI.h>
#include <PDQ_GFX.h>
#include "ilicfg.h"
#include <PDQ_ILI9341.h>
#include <Fonts/ElfBoyClassic11.pck.h>

PDQ_ILI9341 tft;

byte Buffer[3];
bool newData = false;
const char s1[] PROGMEM = "P01";
const char s2[] PROGMEM = "P02";
const char s3[] PROGMEM = "P03";
const char s4[] PROGMEM = "P04";
const char s5[] PROGMEM = "P05";
const char s6[] PROGMEM = "P06";
const char s7[] PROGMEM = "P07";
const char s8[] PROGMEM = "P08";
const char s9[] PROGMEM = "P09";
const char s10[] PROGMEM = "P10";
const char s11[] PROGMEM = "P11";
const char s12[] PROGMEM = "P12";
const char s13[] PROGMEM = "P13";
const char s14[] PROGMEM = "P14";
const char s15[] PROGMEM = "P15";
const char s16[] PROGMEM = "P16";
const char* const stab[] PROGMEM = {s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16};
char prmBuf[3];

void setup() {
#if defined(ILI9341_RST_PIN)
  FastPin<ILI9341_RST_PIN>::setOutput();
  FastPin<ILI9341_RST_PIN>::hi();
  FastPin<ILI9341_RST_PIN>::lo();
  delay(1);
  FastPin<ILI9341_RST_PIN>::hi();
#endif
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(0x0000);
  tft.setFont(&ElfBoyClassic11);
  tft.setTextColor(0xffff);
  tft.setTextSize(2);
  Serial.begin(115200);
}

void loop() {
  recv();
  drawShit();
}

void recv() {
  static bool readState = false;
  static byte ndx = 0;
  byte rb;
  while(Serial.available() > 0 && newData == false) {
    rb = Serial.read();
    if(readState == true) {
      if(rb != 0x81) {
        Buffer[ndx] = rb;
        ndx++;
        if(ndx >= 3) {
          ndx = 2;
        }
      }
      else {
        readState = false;
        ndx = 0;
        newData = true;
      }
    }
    else if(rb == 0x80) {
      readState = true;
    }
  }
}

void drawShit() {
  if(newData == true) {
    if(Buffer[0] == 0x82) {
      tft.fillRect((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+8, 60, 20, 0x0000);
      tft.setCursor((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+20);
      tft.print(Buffer[2], DEC);
      newData = false;
    }
    if(Buffer[0] == 0x83) {
      tft.fillRect((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+38, 60, 20, 0x0000);
      tft.setCursor((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+50);
      strcpy_P(prmBuf, (char*)pgm_read_word(&(stab[Buffer[2]])));
      tft.print(prmBuf);
      newData = false;
    }
  }
}

Any help is appreciated, thanks.

Your recv() function is very similar to recvWithStartEndMarkers() in Serial Input Basics but because you have changed things I'm not sure if it works identically.

Assuming it does work identically then I doubt if the problem is caused by your recv() function. Presumably the byte values 0x80 and 0x81 can never appear in the body of the message.

...R

const char s16[] PROGMEM = "P16";

char prmBuf[3];
  :
      strcpy_P(prmBuf, (char*)pgm_read_word(&(stab[Buffer[2]])));

It looks to me like you are copying strings of 4 bytes (once you include the terminating null) into a 3byte buffer.

The freezing is probably caused by 'newData' being 'true' but

if(Buffer[0] == 0x82) {
if(Buffer[0] == 0x83) {

neither of these conditions being true. I would change it like such :

void drawShit() {
  if(newData == true) {
    if(Buffer[0] == 0x82) {
      tft.fillRect((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+8, 60, 20, 0x0000);
      tft.setCursor((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+20);
      tft.print(Buffer[2], DEC);
      newData = false;
    }
    else if(Buffer[0] == 0x83) {
      tft.fillRect((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+38, 60, 20, 0x0000);
      tft.setCursor((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+50);
      strcpy_P(prmBuf, (char*)pgm_read_word(&(stab[Buffer[2]])));
      tft.print(prmBuf);
      newData = false;
    }
    else {  // no correct data received
      newData = false;
    }
  }
}

@Robin2 The recv function is identical except it does not add the \0 terminator when the endmarker hits, as I did not believe I needed it since I'm not really working with strings like that. I'll give it a try with the terminator but I'm not thinking it will perform much different. also, every byte within an actual message falls between 0x00 and 0x7F (0-127), the only bytes beyond that range are the start and end markers. I'm inclined to believe the arduino can't draw to the screen as fast as it can receive messages and so maybe there's some sort of overflowing or something, but I'm not sure how to fix that nor do I know if that is indeed the problem. thanks for responding

westfw:
It looks to me like you are copying strings of 4 bytes (once you include the terminating null) into a 3byte buffer.

I was not thinking about the terminating character. Nice catch, I will fix that, but the parameter name change isn't what causes the freeze. It's the value change.

Basically the screen looks like
P01 P02 P03 P04
75 23 92 127

P05 P06 P07 P08
12 28 45 72

the numbers are whatever the the computer is sending. it is the rapid changing of those numbers that causes the freeze.

Deva_Rishi:
The freezing is probably caused by 'newData' being 'true' but

if(Buffer[0] == 0x82) {

if(Buffer[0] == 0x83) {



neither of these conditions being true. I would change it like such : 


void drawShit() {
  if(newData == true) {
    if(Buffer[0] == 0x82) {
      tft.fillRect((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+8, 60, 20, 0x0000);
      tft.setCursor((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+20);
      tft.print(Buffer[2], DEC);
      newData = false;
    }
    else if(Buffer[0] == 0x83) {
      tft.fillRect((Buffer[1]%4)*65+20, (Buffer[1]/4)*60+38, 60, 20, 0x0000);
      tft.setCursor((Buffer[1]%4)*65+20, (Buffer[1]/4)60+50);
      strcpy_P(prmBuf, (char
)pgm_read_word(&(stab[Buffer[2]])));
      tft.print(prmBuf);
      newData = false;
    }
    else {  // no correct data received
      newData = false;
    }
  }
}

This is it! I knew it was something stupid. People in other places were telling me to use serial interrupts and all this other stuff. I owe you one, thanks

dag69:
@Robin2 The recv function is identical except it does not add the \0 terminator when the endmarker hits, as I did not believe I needed it since I'm not really working with strings like that.

That makes sense. But it would be easier to help if you had left the rest of the code unchanged (and familiar) and just commented out that line that adds the \0

..R

I'll remember that next time :smiley: I just noticed you are the author of the Serial Basics thread. Thanks for the code!

I knew it was something stupid.

It is not that stupid, but you do always have to keep in mind that you may receive incorrect data. And then you need to discard that and get ready to receive new data anyway. There may be other things that you could do as well in that case, like sending error reports, clearing the buffer etc etc. But main thing is that you reset the latch. There is still the issue of why you received incorrect data, that may need investigation. I suspect that the drawing on the tft may be disturbing reception, but there may be other causes.

I'm almost certain the drawing is what's causing the slowdown, I don't think there's any real way of fixing that unfortunately :frowning: but let me know if you do. I will add a memset command to clear the buffer after the drawing and hopefully the messages won't get so scrambled, though everything is working fine for now, but I can't help but think that once I start adding more things to the code, things might get messier

I don't think there's any real way of fixing that

It could be an issue with the library, apparently it's quicker, but that may be a side effect.

but I can't help but think that once I start adding more things to the code, things might get messier

as long as you do not return error messages in case of incorrect data, you may never know.