Random errors with the PDQ_ILI9341 library

This is not the first time I've encountered an error like this so I'm skeptical of the actual exceptions that are being thrown.

I'm happily writing my code, using native functions like drawing text, rectangles, etc. when all of a sudden I need to draw a line and the code spews out all sorts of errors when I try to compile. Checked the syntax a million times, nothing wrong with that. In fact a nearly identical piece of code with the drawLine function works without a hitch. I decided to try if I could get my working program to break so I deleted some lines that merely used the serial function to display some text in the terminal window and it also broke, saying all this stuff about "undefined reference to..." this or that in PDQ_ILI9341.h.

There's nothing wrong with that header file, I checked. But when I do a certain random thing... like draw a line, when I've already drawn a bunch of other stuff with no issues, the code suddenly takes a dump and I'm like WTF?

Either of the 2 lines that are currently commented out, will cause the code not to compile.

#include <SPI.h>        // must include this here (or else IDE can't find it)
                                           
#include <PDQ_GFX.h>        // PDQ: Core graphics library
#include "PDQ_ILI9341_config.h"     // PDQ: ILI9341 pins and other setup for this sketch
#include <PDQ_ILI9341.h>      // PDQ: Hardware-specific driver library
PDQ_ILI9341 tft;      // PDQ: create LCD object (using pins in "PDQ_ILI9341_config.h")

#include <Fonts/FreeSerif12pt7b.h>  // include fancy serif font
#include <Fonts/FreeSans12pt7b.h> // include fancy sans-serif font

#define ILI9341_GREY    0x8410
#define ILI9341_PINK    0xF8FF

void setup() {
  
  tft.begin();      // initialize LCD
}

void loop(void)
{

  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);

  statusDisp();
  
  while(1) {}
  
}


void statusDisp(void) {

  tft.setCursor(35, 5);
  tft.setTextColor(ILI9341_WHITE);   
  tft.setTextSize(3);
  tft.println("STATUS DISPLAY"); 
  tft.drawFastHLine(0, 30, 320, ILI9341_WHITE);
  tft.drawFastVLine(85, 45, 120, ILI9341_WHITE);
  tft.drawFastVLine(145, 45, 120, ILI9341_WHITE);
  tft.drawFastVLine(205, 45, 120, ILI9341_WHITE);
  tft.drawFastVLine(265, 45, 120, ILI9341_WHITE);

  tft.drawRect(1, 45, 318, 120, ILI9341_WHITE);
  tft.drawFastHLine(1, 73, 318, ILI9341_WHITE);
  tft.drawFastHLine(1, 103, 318, ILI9341_WHITE);
  tft.drawFastHLine(1, 133, 318, ILI9341_WHITE);

  tft.drawRoundRect(5, 175, 130, 60, 12, ILI9341_WHITE);
  tft.drawRoundRect(140, 175, 175, 60, 12, ILI9341_WHITE);

//  tft.drawLine(0, 0, 64, 64, ILI9341_WHITE);

//  tft.drawTriangle(10, 200, 20, 195, 20, 205, ILI9341_WHITE);

  tft.setCursor(45, 195);
  tft.setTextColor(ILI9341_WHITE);   
  tft.setTextSize(2);
  tft.println("OPTIONS");   

  tft.setCursor(147, 195);   
  tft.println("CNTRL PANEL");    

  tft.setCursor(5, 55);
  tft.setTextColor(ILI9341_PINK); 
  tft.setTextSize(1);
  tft.println("POWER SUPPLY");

  tft.setCursor(90, 55);
  tft.setTextColor(ILI9341_GREEN); 
  tft.println("ENABLED");

  tft.setCursor(150, 55);
  tft.setTextColor(ILI9341_RED); 
  tft.println("ERROR"); 

  tft.setCursor(210, 55);
  tft.println("HOT");

  tft.setCursor(270, 55);
  tft.setTextColor(ILI9341_CYAN); 
  tft.println("96.3 V");  

  tft.setCursor(5, 85);
  tft.setTextColor(ILI9341_PINK); 
  tft.println("SUPERCHARGER");

  tft.setCursor(90, 85);
  tft.setTextColor(ILI9341_GREEN); 
  tft.println("ENABLED");    

  tft.setCursor(150, 85); 
  tft.println("NOMINAL"); 

  tft.setCursor(210, 85); 
  tft.println("IDLE"); 

  tft.setCursor(270, 85);
  tft.setTextColor(ILI9341_CYAN); 
  tft.println("3 %");       

  tft.setCursor(5, 115);
  tft.setTextColor(ILI9341_PINK); 
  tft.println("NITROUS");

  tft.setCursor(90, 115);
  tft.setTextColor(ILI9341_GREY); 
  tft.println("DISABLED");    

  tft.setCursor(150, 115); 
  tft.println("NOMINAL"); 

  tft.setCursor(210, 115); 
  tft.println("UNSTABLE"); 

  tft.setCursor(270, 115); 
  tft.println("CLOSED");  

  tft.setCursor(5, 145);
  tft.setTextColor(ILI9341_PINK); 
  tft.println("KNOCK");

  tft.setCursor(90, 145);
  tft.setTextColor(ILI9341_GREEN); 
  tft.println("ENABLED");    

  tft.setCursor(150, 145); 
  tft.println("NOMINAL"); 

  tft.setCursor(210, 145); 
  tft.setTextColor(ILI9341_YELLOW); 
  tft.println("CAUTION"); 

  tft.setCursor(270, 145); 
  tft.setTextColor(ILI9341_CYAN);
  tft.println("0.9");    
  
  
}

void controls(void) {
  
}

void options(void) {
  
}

When your code requires a library that's not included with the Arduino IDE please always post a link (using the chain link icon on the toolbar to make it clickable) to where you downloaded that library from or if you installed it using Library Manger(Sketch > Include Library > Manage Libraries) then say so and state the full name of the library.

When you encounter an error you'll see a button on the right side of the orange bar "Copy error messages". Click that button. Paste the error in a message here using code tags.

Sorry here's some additional info:

dump.txt (5.71 KB)

PDQ_ILI9341.h (26.4 KB)

PDQ_ILI9341_config.h (2.33 KB)

This appears to be a clash between the inlined coding style of the library and the compiler. For example if the first few lines of your function are:

void statusDisp(void) {
  tft.drawLine(0, 0,64, 64, ILI9341_WHITE);

  //tft.setCursor(35, 5);
  tft.setTextColor(ILI9341_WHITE);   
  //tft.setTextSize(3);
  tft.println("STATUS DISPLAY");

It compiles fine. Change to:

void statusDisp(void) {
  tft.drawLine(0, 0,64, 64, ILI9341_WHITE);

  tft.setCursor(35, 5);
  tft.setTextColor(ILI9341_WHITE);   
  tft.setTextSize(3);
  tft.println("STATUS DISPLAY");

And you get errors even though setCursor and setTextSize only sets some variables.

I would post your problem as an Issue on the authors Github site.

I had a feeling something screwy was going in. Question is... is there any way to band-aid it in the meantime while the author may or may not fix it? Unfortunately I really need the speed boost offered by this library for my application.

I noticed the errors that occur when compiling fails, always have to do with these odd delay functions. Having a look in the library's header file, they don't appear to do much and their purpose is mysterious to me. Would it be possible (or wise) to bypass them somehow so that the errors go away? I'm not sure I understand this "inlined coding style" and what it means or how it relates to these delay functions but just to get my code working again, shouldn't there be a way to jerry rig the library to disregard these functions?

The PDQ library seems to be unstable. I am not sure why. I find the source code fairly unreadable.

I built your program with Bodmer's TFT_ILI9341 library. That works fine except for the triangle rendering.
Your program should work ok with any GFX-style library. Even Adafruit_ILI9341.

Ok, PDQ libraries are pretty damn quick. But if the code is unstable, you are better off with conventional libraries.

David.

One band-aid approach is to replace all delays e.g. delayXX() where XX is 17 etc, with the line:

while (!(SPSR & _BV(SPIF)));

This waits for the processor to flag that the SPI transfer is complete.

I have assembled a library here that has equivalent or faster performance to the PDQ library, it uses more compiler friendly approaches to adding delays, it has some very fast rendering fonts but does not support the FreeFonts.

david_prentice:
The PDQ library seems to be unstable. I am not sure why. I find the source code fairly unreadable.

I built your program with Bodmer's TFT_ILI9341 library. That works fine except for the triangle rendering.
Your program should work ok with any GFX-style library. Even Adafruit_ILI9341.

Ok, PDQ libraries are pretty damn quick. But if the code is unstable, you are better off with conventional libraries.

David.

I tend to agree. Something that only works when it feels like it is potentially hazardous to use... but it's so tempting to use because it is so fast! The benchmark example sketch is rather impressive.

bodmer:
One band-aid approach is to replace all delays e.g. delayXX() where XX is 17 etc, with the line:

while (!(SPSR & _BV(SPIF)));

This waits for the processor to flag that the SPI transfer is complete.

I have assembled a library here that has equivalent or faster performance to the PDQ library, it uses more compiler friendly approaches to adding delays, it has some very fast rendering fonts but does not support the FreeFonts.

You re-wrote the library to be even faster??? That's amazing! And thank you so much for the fix to the header! I will try both!

So are you saying that these 4 delay functions only exist to waste time so that the spi bus can finish a data exchange before moving on? Is it the case that your while conditional does the same thing by simply checking the bus over and over until it's free? This would seem a more robust piece of code if I understand it correctly.

EDIT: Duhhh... I just realized David pointed out that you have your own library already for this. I suspect that's why you know so much about this topic. It's nice to have choice in a cruel programming world so thank's for providing an alternative.

Bodmer, I ended up installing your library because I couldn't fix the other one. It sounded like an easy fix but once I got into the code and realized how confusing it was to me, nothing I did made it any better so I gave up and tried yours.

Yours seems to work with all the functions and does compile but for some reason, after painting the screen and going into my idle while loop, it paints the screen white and stays that way, even though my last function is to print text. So as soon as it's done printing the last piece of text on the screen it deletes everything to white a fraction of a second later but for a brief moment I can see that everything painted correctly.

Why do you suppose it's painting white?

#include <SPI.h>        // must include this here (or else IDE can't find it)
                                           
//#include <PDQ_GFX.h>        // PDQ: Core graphics library
//#include "PDQ_ILI9341_config.h"     // PDQ: ILI9341 pins and other setup for this sketch
//#include <PDQ_ILI9341.h>      // PDQ: Hardware-specific driver library

#include "TFT_ILI9341.h"

#include "TouchScreen.h"      // For the touch screen functionality
//PDQ_ILI9341 tft;      // PDQ: create LCD object (using pins in "PDQ_ILI9341_config.h")
TFT_ILI9341 tft = TFT_ILI9341();

//#include <Fonts/FreeSerif12pt7b.h>  // include fancy serif font
//#include <Fonts/FreeSans12pt7b.h> // include fancy sans-serif font

#define ILI9341_GREY    0x8410
#define ILI9341_PINK    0xF8FF

// These are the four touchscreen analog pins
#define YP A2  // must be an analog pin, use "An" notation!
#define XM A3  // must be an analog pin, use "An" notation!
#define YM 5   // can be a digital pin
#define XP 4   // can be a digital pin

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940

#define MINPRESSURE 10
#define MAXPRESSURE 1000

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

void setup() {
  
//  tft.begin();      // initialize LCD
  tft.init();

}

void loop(void) {

  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);

  statusDisp();
  
  while(1) {
/*
    TSPoint p = ts.getPoint();

    if (p.z < MINPRESSURE || p.z > MAXPRESSURE) {
      return;
    }

    // Scale from ~0->1000 to tft.width using the calibration #'s
    p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
    p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());

    if((p.x < 135) & (p.y > 175)) {

      tft.fillScreen(ILI9341_YELLOW);
      delay(3000);
      break;
      
    }

    if((p.x > 140) & (p.y > 175)) {

      tft.fillScreen(ILI9341_BLUE);
      delay(3000);
      break;
      
    }    
*/    
  } 
  
}


void statusDisp(void) {

  tft.setCursor(35, 5);
  tft.setTextColor(ILI9341_WHITE);   
  tft.setTextSize(3);
  tft.println("STATUS DISPLAY"); 
  tft.drawFastHLine(0, 30, 320, ILI9341_WHITE);
  tft.drawFastVLine(85, 45, 120, ILI9341_WHITE);
  tft.drawFastVLine(145, 45, 120, ILI9341_WHITE);
  tft.drawFastVLine(205, 45, 120, ILI9341_WHITE);
  tft.drawFastVLine(265, 45, 120, ILI9341_WHITE);

  tft.drawRect(1, 45, 318, 120, ILI9341_WHITE);
  tft.drawFastHLine(1, 73, 318, ILI9341_WHITE);
  tft.drawFastHLine(1, 103, 318, ILI9341_WHITE);
  tft.drawFastHLine(1, 133, 318, ILI9341_WHITE);

  tft.drawRoundRect(5, 175, 130, 60, 12, ILI9341_WHITE);
  tft.drawRoundRect(140, 175, 175, 60, 12, ILI9341_WHITE);

  tft.drawLine(0, 0, 64, 64, ILI9341_WHITE);

  tft.drawTriangle(10, 200, 20, 195, 20, 205, ILI9341_WHITE);

  tft.setCursor(45, 195);
  tft.setTextColor(ILI9341_WHITE);   
  tft.setTextSize(2);
  tft.println("OPTIONS");   

  tft.setCursor(147, 195);   
  tft.println("CNTRL PANEL");    

  tft.setCursor(5, 55);
  tft.setTextColor(ILI9341_PINK); 
  tft.setTextSize(1);
  tft.println("POWER SUPPLY");

  tft.setCursor(90, 55);
  tft.setTextColor(ILI9341_GREEN); 
  tft.println("ENABLED");

  tft.setCursor(150, 55);
  tft.setTextColor(ILI9341_RED); 
  tft.println("ERROR"); 

  tft.setCursor(210, 55);
  tft.println("HOT");

  tft.setCursor(270, 55);
  tft.setTextColor(ILI9341_CYAN); 
  tft.println("96.3 V");  

  tft.setCursor(5, 85);
  tft.setTextColor(ILI9341_PINK); 
  tft.println("SUPERCHARGER");

  tft.setCursor(90, 85);
  tft.setTextColor(ILI9341_GREEN); 
  tft.println("ENABLED");    

  tft.setCursor(150, 85); 
  tft.println("NOMINAL"); 

  tft.setCursor(210, 85); 
  tft.println("IDLE"); 

  tft.setCursor(270, 85);
  tft.setTextColor(ILI9341_CYAN); 
  tft.println("3 %");       

  tft.setCursor(5, 115);
  tft.setTextColor(ILI9341_PINK); 
  tft.println("NITROUS");

  tft.setCursor(90, 115);
  tft.setTextColor(ILI9341_GREY); 
  tft.println("DISABLED");    

  tft.setCursor(150, 115); 
  tft.println("NOMINAL"); 

  tft.setCursor(210, 115); 
  tft.println("UNSTABLE"); 

  tft.setCursor(270, 115); 
  tft.println("CLOSED");  

  tft.setCursor(5, 145);
  tft.setTextColor(ILI9341_PINK); 
  tft.println("KNOCK");

  tft.setCursor(90, 145);
  tft.setTextColor(ILI9341_GREEN); 
  tft.println("ENABLED");    

  tft.setCursor(150, 145); 
  tft.println("NOMINAL"); 

  tft.setCursor(210, 145); 
  tft.setTextColor(ILI9341_YELLOW); 
  tft.println("CAUTION"); 

  tft.setCursor(270, 145); 
  tft.setTextColor(ILI9341_CYAN);
  tft.println("0.9");    
  
  return;
}

void controls(void) {
  
}

void options(void) {
  
}

EDIT: Nevermind... I failed to set the config file as instructed. Had to remap 2 pins and now it works.

Bodmer, sorry to bother you again, but it looks like a function I had been relying on, drawXBitmap(), is not supported in your library. Only the drawBitmap() function works. I had resorted to drawXBitmap() because a particular image I had made was rendering backwards or inside out or something like that and drawXBitmap fixed that. What should I do to get the same effect in your library? Speed is not an issue since it's only for a splash screen.

@ Gahhhrrrlic

I will check to see what the drawXBitmap(), but it will be a few days before I have time to do this.

Special functions like this can usually be included inside the users sketch.

Thank you kind sir. If I had any clue what it did (best I can guess is drawing the HEX backwards?) I would make a meek attempt but I really tear my hair out with stuff like this. Just determining I needed drawXBitmap before was a week+ long endeavor of internet research and forum spamming :frowning:

Sorry for the necro but it's a continuation of the same project.

I recently migrated to a new computer and re-installed all my arduino stuff. I ran my sketch, compiled and uploaded and this is the exact save revision as what was already loaded on my Mega at the time. I noticed 2 immediate problems: 1) the colors are all inverted - yellow is purple, black is white, red is cyan, etc. and 2) my bitmap draw function has jagged edges like it did before I fixed it.

It's possible that somehow my fixes didn't make their way to the new computer, explaining 2 but for 1 I'm stumped. What causes the colors to be inverted like that? It can't be wiring because everything has long since been soldered into place and worked just fine. The code has never produced an inverted output and so I don't think it's the code. I'm trying to think what else it could be...

Please quote which library versions you are using.

Please post your code in a Code Window or as an attached file.

David.

david_prentice:
Please quote which library versions you are using.

Please post your code in a Code Window or as an attached file.

David.

Ok, I will check the version when I get home and have access to it. Not sure where the version number might be but I'll search around.

100% sure it's not anything related to the code. Aside from the fact that the same code is now inverted whereas it wasn't before, also every single example sketch for that LCD is also inverted. If I had to guess, the only things I can think of are, maybe it's the pin config in one of the config files, which would kind of make it a hardware problem but not really, since the hardware works but maybe isn't mapped properly. OR it's the library itself being somehow different than it was before. These are the 2 possibilities I can think of but of course there may be others.

Will respond again with version info.

I have PDQ_ILI9341 on my PC. I have not tried it recently.

It does not appear to be supported by the Library Manager.
My copy is v1.1.5 and comes from GitHub
where it says latest commit ("v1.1.5" 2016-04-09)

There does not seem to be any recent changes in the last 2 years except for cosmetic "library Properties"

I doubt if a change of IDE or even change of Library version would affect the "invertDisplay()" state.

I have just run my standard sketch with PDQ_ILI9341 on IDE v1.8.1
It worked fine.

If you have a problem, re-install the library. Write a fresh PDQ_ILI9341_Config.h file.

David.

My version says 0.17. Arduino is 1.6.5

I guess i just don't know what "could" invert colors like that.

Oh it's not pdq it's ILI_9431by Bodmer