Highly optimized ILI9341 (320x240 TFT color display) library

Try plugging headphones into the audio board, and do NOT make any physical audio connections to anything other than those headphones.

If you get good sound on headphones, it's a ground loop problem, which is the most common and (often) the most annoying type.

If the noise is also on the headphones, then something is wrong in the hardware or software. This is much less common.

The first step is always to figure out which class of problem you're dealing with.
 
Thank you Paul,
i am using the headphones actually.

The buzz is very audible when I use a simple sine wave.
If I play with removing the "tft.*" lines, the buzz starts with the first tft.fillScreen.
The audio board and teensy 3.1 are stacked together, I am running MISO, MOSI, etc to the color display (about 2 inch length wires).

I am wondering if I need to use pull up resistors for MISO and MOSI....
I will do some more debugging and post my findings.

Any additional ideas/pointers are welcome !
 
Any known conflicts with with flash_spi.h and ILI9341_t3.h?

I am getting closer, the good news is that I am not facing a ground loop.

I need to investigate the interaction of the optional eeprom in the audio shield (I installed the W25Q128, and I loaded it successfully with samples from SD card - the code provided by Frank B works like a charm) and the color display.


This is what I see without instantiating the color display code.

Flash Status: 0x0, ID:0xEF,0x40,0x18,0x0 is ok.
File(s) fit(s) in serial flash, 16777216 Bytes remaining.
Check flash content: 7F 82 85 88 8B 8E 91 94 97 9A 9D A0

This is what I see when I do instantiate the color display code.
Flash Status: 0x0, ID:0x0,0xEF,0x40,0x18 is not ok.
0 7F 82 85 88 8B 8E 91 94 97 9A 9D A0 A3 A6 A9 AC AF B2 B5

It looks like something is slightly off by one byte.
The 0 value at the beginning of my sine wave is where the buzzing sound comes from.

this is the snippet of code that I am using to test the flash (code per Mr Frank B - thank you!)
if (fsize < FLASHSIZE) {
flash_init();
int flashstatus = flash_read_status();
flash_read_id(id_tab);
Serial.printf("Flash Status: 0x%X, ID:0x%X,0x%X,0x%X,0x%X ", flashstatus , id_tab[0], id_tab[1], id_tab[2], id_tab[3]);
if (id_tab[0]!=0xef || id_tab[1]!=0x40 || id_tab[2]!=0x18 || id_tab[3]!=0x00)
{Serial.println(" is not ok."); goto end;}
Serial.printf(" is ok.\r\nFile(s) fit(s) in serial flash, %d Bytes remaining.\r\n\r\n", FLASHSIZE - fsize);
Serial.print("Check flash content: ");

end:
{;}
}
 
Last edited:
Nothing changes by applying 2.2K resistors between 3.3V and the CS for the color display (pin 21 in my case) and the CS for the audio shield (pin 6).

Didn't have much time to look at the SW part, but I am the point where I think it is clear that flash_read_pages loses the first byte.

Help :)
 
No success.
I did re-write the equivalent of flash_read_pages using SPI.beginTransaction (see below), but as soon as I perform any tft operations (such as tft.fillScreen(ILI9341_BLACK) ) I miss the first byte from my read function.

void flash_read_wave(unsigned char *p, int pn)
{
int address;
unsigned char *rp = p;
write_pause();
address = pn << 8;

SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4,MSBFIRST,SPI_MODE0));
digitalWrite(f_cs, LOW);
SPI.transfer(CMD_READ_DATA);
// Send the 3 byte address
SPI.transfer((address >> 16) & 0xff);
SPI.transfer((address >> 8) & 0xff);
SPI.transfer(address & 0xff);
// Now read the page's data bytes
for(int i = 0;i < 256; i++)
*rp++ = SPI.transfer(0);
digitalWrite(f_cs, HIGH);
SPI.endTransaction();
}
 
edit. nevermind

and fwiw... : this seems to work (should work) in tandem with SD.h*, W25 clocked at 30 MHz, and as long as CS is one of hardware pins (for whatever reason):

Code:
void AudioPlaySerialFlash::spififo_flash_read_page(unsigned char *p, int pn)
{ 
  int address;
  unsigned char *rp = p;

  write_pause();
  SPIFIFO.write(CMD_READ_DATA, SPI_CONTINUE);
  SPIFIFO.read();
  // Send the 3 byte address
  address = page_to_address(pn);
  SPIFIFO.write((address >> 16) & 0xff, SPI_CONTINUE);
  SPIFIFO.write((address >> 8)  & 0xff, SPI_CONTINUE);
  SPIFIFO.write(address & 0xff, SPI_CONTINUE);
  SPIFIFO.read();
  SPIFIFO.read();
  SPIFIFO.read();

  //Now read the page's data bytes
  for(int i = 0;i < 255; i++) {
       SPIFIFO.write(0x00, SPI_CONTINUE);
       *rp++ = SPIFIFO.read();
  }
  SPIFIFO.write(0x00); 
  *rp++ = SPIFIFO.read();
}

*i have no experience with ILI9341_t3.h, which seems to do its own thing, so i'm not sure SPIFIFO would make any difference.
 
Last edited:
I also have a strange behaviour when using ILI9341_t3 library. In my case, some data written to USB serial where lost, never gets to the other side. Also reading some Microchip SPI devices behaves strange in combination with the TFT library. Data readout was corrupted and unexpected.

However I havn't paid any more attention to this problem because I'm busy with other projects.
 
Last edited:
Hello Donziboy2, thank you for the digitalWriteFast suggestion, unfortunately that did not work.
I also tried SPICLOCK, but i keep missing the first byte of the page read .... :(
 
@mxxx
thank you for your suggestion.
I was not familiar with SPIFIFO, but after adding

SPIFIFO.begin(f_cs, f_mosi, f_sck);

in the setup, I also included
digitalWrite(f_cs, LOW); and digitalWrite(f_cs,HIGH); to your code to get a complete page read.
Unfortunately, this behaves exactly like the routine that I was using.

Does the ILI9341 library "steal" one additional byte from other SPI transactions ?
 
I did include the Adafruit_ILI9341 (instead of ILI9341_t3) and now my code works.

After these experiments I came to the conclusion that the library has a small bug that prevents us from correctly accessing the optional EEPROM in the Audio Board. It appears that the data from the *first* SPI read is lost.

@ Paul,
I don't know enough about SPI to be of additional help here, email me if you need any additional code.

Thank you all for your help
 
alfa66: you don't need to manually set the CS with SPIFIFO, and begin has
Code:
inline void begin(uint8_t pin, uint32_t speed, uint32_t mode=SPI_MODE0)

at any rate, sounds like there might be a little bug in ILI9341. (though i'm not sure then why this shouldn't apply across the board, ie rather than affect flash_spi only).
 
Last edited:
I don't know enough about SPI to be of additional help here, email me if you need any additional code.

I need a complete (and hopefully small) program that demonstrates the problem. As a general rule, I investigate issues when a complete program is posted.

Please, double check that your program compiles and reproduces the problem when copied into a clean install of Arduino+Teensyduino.
 
Hi Paul,
hopefully the code below will help.

The bug shows whether or not I add 2.2K pull up resistors to the CS lines of the TFT display and of the EEPROM in your audio shield.

The first incarnation of the bug shows up performing a simple flash_read_id(id_tab), i think this is really all you need.
You would need to pre-load the first few bytes of the EEPROM if you want to see the second manifestation of the bug - which I think is the same bug, still related to a read function.
I did not test writing to EEPROM while using ILI9341

While I am able to get going with the project, I already miss the speed of ILI9341_t3 ....

Thank you
alfa66


//#include "Adafruit_GFX.h"
//#include "Adafruit_ILI9341.h"
#include "ILI9341_t3.h"
#include "flash_spi.h"
#include "SPI.h"


#define PAGE 256 //dimension of 1 EEPROM page (in bytes)

unsigned char buf2[PAGE]; // we are using this buffer for reading from the EEPROM
unsigned char id_tab[32];

// Set DC and CS, no conflict with Paul's Audio Adapter
#define TFT_DC 20
#define TFT_CS 21

// Use hardware SPI and the above for CS/DC. Reset is tied to 3.3V, no need for a 3rd pin
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);


void setup() {

Serial.begin(19200);
while (!Serial) {;}

// Needed when using ILI9341 with the Audio Board, also needed for reading W25Q128
SPI.setMOSI(7);
SPI.setSCK(14);

tft.begin();

// About the following line
// if not commented out and compiled with t3 library, we miss reading the id_tab correctly. Also we miss reading the first byte on the first page
// if it is commented out it works fine
// It also works if not commented out and compiled with the Adafruit version of ILI9341
//tft.drawLine( 0, 0, 100, 100, ILI9341_YELLOW);

flash_init();
int flashstatus = flash_read_status();
flash_read_id(id_tab);
Serial.printf("Flash Status: 0x%X, ID:0x%X,0x%X,0x%X,0x%X ", flashstatus , id_tab[0], id_tab[1], id_tab[2], id_tab[3]);

if (id_tab[0]!=0xef || id_tab[1]!=0x40 || id_tab[2]!=0x18 || id_tab[3]!=0x00)
{Serial.println(" is not ok."); goto end;}
else Serial.println("");

end:

// this is what caused the buzz sound in my code. The first byte of page 0 always reads zero
// you would have to pre-load the first page of the EEPROM to check on this one
// I used Frank B code SD2SerialFlash to pre-load the EEPROM

flash_read_pages(buf2, 0, 1);
for (int i=0; i<PAGE; i++) {
Serial.print(buf2, HEX);
Serial.print(" ");
}
Serial.println("Done");

}

void loop(void) {
int i;

}
 
Hi, I have a question about this library, does this library work with the Arduino 2560 and the adafruit 2.8 tft arduino shield V2? When I install the library and try to run an example I have a lot of errors:

Arduino: 1.0.6 (Windows 7), Board: "Arduino Mega 2560 or Mega ADK"
In file included from graphicstest.ino:18:
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::waitFifoNotFull()':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:177: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:178: error: 'SPI0_POPR' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::waitFifoEmpty()':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:186: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:187: error: 'SPI0_POPR' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::waitTransmitComplete()':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:192: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:192: error: 'SPI_SR_TCF' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:193: error: 'SPI0_POPR' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::writecommand_cont(uint8_t)':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:196: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:196: error: 'SPI_PUSHR_CTAS' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:196: error: 'SPI_PUSHR_CONT' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::writedata8_cont(uint8_t)':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:200: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:200: error: 'SPI_PUSHR_CTAS' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:200: error: 'SPI_PUSHR_CONT' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::writedata16_cont(uint16_t)':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:204: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:204: error: 'SPI_PUSHR_CTAS' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:204: error: 'SPI_PUSHR_CONT' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::writecommand_last(uint8_t)':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:209: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:209: error: 'SPI_SR_TCF' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:210: error: 'SPI_PUSHR_CTAS' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::writedata8_last(uint8_t)':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:215: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:215: error: 'SPI_SR_TCF' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:216: error: 'SPI_PUSHR_CTAS' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h: In member function 'void ILI9341_t3::writedata16_last(uint16_t)':
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:221: error: 'SPI0' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:221: error: 'SPI_SR_TCF' was not declared in this scope
C:\Users\kiki\Documents\Arduino\libraries\ILI9341_t3/ILI9341_t3.h:222: error: 'SPI_PUSHR_CTAS' was not declared in this scope
 
@vertigo: These are control registers/addresses specific to Teensy SPI FIFO that is included in the Freescale Kinetis MK200X256 microcontroller. It is different for every platform. Your board uses Atmel ATmega2560 microcontroller. This is a totally different platform. You could take a look on this forum thread that discusses optimization of SPI on ATmega series

http://www.avrfreaks.net/forum/optimizing-atmega-spi-speed
 
Last edited:
Thanks bkausbk for your reply, I will look at the link that you sent me...


@vertigo: These are control registers/addresses specific to Teensy SPI FIFO that is included in the Freescale Kinetis MK200X256 microcontroller. It is different for every platform. Your board uses Atmel ATmega2560 microcontroller. This is a totally different platform. You could take a look on this forum thread that discusses optimization of SPI on ATmega series

http://www.avrfreaks.net/forum/optimizing-atmega-spi-speed
 
Question on readcommand8():
Hi Paul - I am trying to use your library with another display from Buy Display. As I was debugging, I got looking into the results of the graphictest - using one of your displays I get the following:

ILI9341 Test!
Display Power Mode: 0xDE
MADCTL Mode: 0x6C
Pixel Format: 0x7
Image Format: 0xDE
Self Diagnostic: 0x0 (this is sometimes 0xE0)

Just zeroing in on Pixel format for a minute, the result of 0x7 doesn't make sense to me. The register was set to 0x55 in the init code, and reading the documentation for the controller for the read command it seems is should return the same as what was sent. oh, and 0x07 is a reserved value!

Looking through this thread I see others getting the same results, although sometimes 0x05 for pixel format. MADCTL is also different from what we set (0x6c vs the 0x48 set it the init code) Oh and while we are at it I notice the Self Diagnostic is sometimes 0x0 and sometimes 0xE0.

So really three questions:
1) is readcommand8() working properly or does it have an issue?
2) if it is working why the different return values?
3) what are the correct values that should be returned in graphictest?

thanks for any help - my display appears to need slightly different init code so any help would help me to continue to look in the right direction.
 
Diagnostics Read

@GuitarHack: Please first take a look at this thread https://forum.pjrc.com/threads/27860-ILI9341_t3-readRect()-writeRect()-bug and test if lowering SPI clock solves your problem.

Hi bkausbk - thanks so much! - that helped. I suspected that the SPI clock was too fast yesterday, but didn't test well enough with a slower clock. I have bumped it arbitrarily down to 10 MHz. and now I seem to be getting consistent results.

A couple of things I found:

on line 40 of ILI341_t3.h: the value for ILI9341_RDIMGFMT is incorrect at 0x0A (I was wondering why I always saw the same value as ILI9341_RDMODE). The line should be:

#define ILI9341_RDIMGFMT 0x0D


Here are the results:
ILI9341 Test!
Display Power Mode: 0x9C
MADCTL Mode: 0x48
Pixel Format: 0x5
Image Format: 0x0
Self Diagnostic: 0xC0 (or sometimes 0x0)

The Display Power Mode looks correct - indicating the following: Booster On, Idle Mode off, Partial Mode Off, Sleep Out Mode, Display Normal Mode, Display On. So it appears to me that 0x9C is the right value people should expect. (and not what I get on my other display, so a clue to my problem)

MADCTL: 0x48 is what we sent to it, so again this looks correct

Pixel Format: Still something weird here - we should get 0x55. The 5 for DBI is correct, MCU interface mode is 16 bit color mode. I tried changing the bottom nibble in the init code, and sure enough the read function followed what I changed in the init code, so this seems good. FWIW, the default value for DPI on reset shows as 000b (reserved) in the read function and 110b (18 bit mode) in the write function. Weird. Anyone know the right answer here? Chip Bug?

Image Format: 0x0 - This indicates Gamma Curve 1, seems this is the right answer

Self Diagnostic: Multiple reset sequences give me either 0x0 or 0xC0. 0xC0 indicates that register loading is working and the display is functional. Getting 0x00 indicates a problem, but I don't see any difference off hand in the display itself - it is possible that there is a latent problem here

Anyone else care to try themselves and report on Pixel Format and Self Diagnostics?


thanks everyone!
 
Just ran the ILI9341_t3 graphics test and was wondering if the below numbers are what I should expect.
Based on the 25% increase from 72 to 96Mhz it seems about right.

72Mhz
Code:
ILI9341 Test!
Display Power Mode: 0x9C
MADCTL Mode: 0x48
Pixel Format: 0x5
Image Format: 0x9C
Self Diagnostic: 0xC0
Benchmark                Time (microseconds)
Screen fill              373480
Text                     24515
Lines                    97656
Horiz/Vert Lines         30810
Rectangles (outline)     19538
Rectangles (filled)      775594
Circles (filled)         124428
Circles (outline)        121276
Triangles (outline)      23679
Triangles (filled)       261579
Rounded rects (outline)  51214
Rounded rects (filled)   848985
Done!

96Mhz

Code:
ILI9341 Test!
Display Power Mode: 0xCE
MADCTL Mode: 0x6C
Pixel Format: 0x2
Image Format: 0xCE
Self Diagnostic: 0x0
Benchmark                Time (microseconds)
Screen fill              280112
Text                     19593
Lines                    73321
Horiz/Vert Lines         23153
Rectangles (outline)     14668
Rectangles (filled)      581706
Circles (filled)         95754
Circles (outline)        96134
Triangles (outline)      17806
Triangles (filled)       197587
Rounded rects (outline)  40188
Rounded rects (filled)   637581
Done!
 
@Donziboy2

More important than the CPU Speed (F_CPU) is the speed of the SPI which is - if i remember correctly - set to the max (=1/2 * F_BUS) in the library.
Edit: For "Highly-optimized-ILI9341"

Code:
#if (F_CPU == 168000000)
 #define F_PLL 168000000
 #define F_BUS 56000000
 #define F_MEM 33600000
#elif (F_CPU == 144000000)
 #define F_PLL 144000000
 #define F_BUS 48000000
 #define F_MEM 28800000
#elif (F_CPU == 120000000)
 #define F_PLL 120000000
 #define F_BUS 60000000
 #define F_MEM 24000000
#elif (F_CPU == 96000000)
 #define F_PLL 96000000
 #define F_BUS 48000000
 #define F_MEM 24000000
#elif (F_CPU == 72000000)
 #define F_PLL 72000000
 #define F_BUS 36000000
 #define F_MEM 24000000
#elif (F_CPU == 48000000)
 #define F_PLL 96000000
 #if defined(KINETISK)
 #define F_BUS 48000000
 #elif defined(KINETISL)
 #define F_BUS 24000000
 #endif
 #define F_MEM 24000000
#elif (F_CPU == 24000000)
 #define F_PLL 96000000
 #define F_BUS 24000000
 #define F_MEM 24000000
#elif (F_CPU == 16000000)
 #define F_PLL 16000000
 #define F_BUS 16000000
 #define F_MEM 16000000
#elif (F_CPU == 8000000)
 #define F_PLL 8000000
 #define F_BUS 8000000
 #define F_MEM 8000000
#elif (F_CPU == 4000000)
 #define F_PLL 4000000
 #define F_BUS 4000000
 #define F_MEM 4000000
#elif (F_CPU == 2000000)
 #define F_PLL 2000000
 #define F_BUS 2000000
 #define F_MEM 1000000
#endif
 
Last edited:
@Frank B

The limits are defined in the ILI9341_T3.cpp. I cant assume the SPI is the only limiting factor to the library.

Code:
// Teensy 3.1 can only generate 30 MHz SPI when running at 120 MHz (overclock)
// At all other speeds, SPI.beginTransaction() will use the fastest available clock
#define SPICLOCK 30000000

Im just trying to insure the numbers I am seeing are normal. I have to have a good grasp of the amount of time needed to perform tasks.
 
Back
Top