Highly optimized ILI9341 (320x240 TFT color display) library

I did not get that specific error, but my clean install of 1.0.6 plus Teensyduino 1.20rc3 on Linux64, the graphictest example program failed to compile, complaining about the beginTransaction... Not being defined. My quick look at the libraries, it looks like the SPI library was not updated to the updated version of 1.20rc2

Fixed: 1.20rc4
 
Last edited:
Some quick questions about the ILI9341 display PJRC is selling: http://www.pjrc.com/store/display_ili9341.html
I picked up one, that I am just about to try out. I have also suggested them to some other people I know, but I have noticed they have been out of stock for a little while now. Are you going to restock them?

On the board you mention that the Reset pin needs to be tied to 3.3v. I assume from this that the pin is not 5v tolerant?

Right now I am trying to migrate my code that allows me to read pixel information that I added to the ILI9341_T3 library back to the Adafruit_ILI9341 library and am trying to test it out on an Arbotix-M board (Trossen Robotics, Atmega644p processor) and on their board I don't see any 3.3v outputs, except I could try to grab it from XBee socket. Will probably just do resistor divider circuit on breadboard for this...

Kurt
 
but I have noticed they have been out of stock for a little while now. Are you going to restock them?

They are in stock.

On the board you mention that the Reset pin needs to be tied to 3.3v. I assume from this that the pin is not 5v tolerant?

It does not seem to be 5V tolerant on any pins, except the power input, which is designed for 5V input. The display has a 3.3V regulator on-board.

I tried running one directly on a regular 5V Arduino Uno. It did not work. Then I connected another one with 74HC4050 buffers to reduce the signals to 3.3V and it worked great. Well, great but slowly.
 
Thanks Paul - Now showing in stock.

I looked at the ILI9341 data sheet and like you suggested the IO pins voltage levels supported is in the range 1.65-3.3v. I then looked at the Adafruit 2.8" TFT breakout board schematic and it looks like they run all of the signals through a couple of 74LVC245 chips to allow their LCD display to be connected up to Arduinos.

So for the Arbotix-M will probably use one of these (or the 2.2" one with the ILI9340 chip) to test out the library
 
In case anyone is interested, I want to use some of these ILI9341/0 displays on both Teensy based stuff as well as Arduino (actually an Atmega644 based board) based system, and I still want the ability to read pixels. In particular where I am wanting this is for Debug text output where I can scroll the text...

So for the fun of it, I added the functions (readPixel, readRect, writeRect) which I added to the ILI9341_t3 library to the Adafruit_ILI9341 library. I think I now have them working, however they are a lot slower than they are in the ILI9341_t3 library, especially on an 16mhz 8 bit Atmega processor.

I adapted the read pixel test program mentioned earlier in this thread (could not use printf on stream, change library name...) and so far it appears to work on a Teensy 3.1 with PJRC ILI9341 display as well as on an Arbotix-M board (Atmega 644p) using Adafruit 2.2" TFT display (ILI9340). So should work fine on Atmega328p based systems as well. I have not tested it on an Arduino Due yet. I have one buried around here somewhere ;)

I should do another pass through the code to cleanup some stuff, I added some commands like: writecommand_cont, writedata_cont that leave the CS line selected, which is needed in these cases. Like the _t3 library I also had to spilit up setAddrWindow and setAddr. Currently I just have the setAddrWindow calling off to setAddr, where in the T3, I believe that setAddr in inline. Always an interesting question of trade off for speed versus size... Also wondering about taking pass through such that most of the commands have the CS pin selected through the command, as compared to current version where in most cases CS line is selected/deselected on each byte (or two bytes in cases of things like X or Y position).

Again I believe the pixel reading is working. If anyone wishes to play with it, I uploaded my changes to my fork on github: https://github.com/KurtE/Adafruit_ILI9341
Note: My fork was forked yesterday with all of the previous stuff that I believe matches what is downloaded with the 1.20rc5

Kurt
 
Not sure if I should move this back to my old thread on Adafruit 2.8" display or create new thread or...

I was looking up at the Adafruit_ILI9341 library on github and noticed some Pull Requests, which I looked at and I am torn on if I should integrate those changes in my fork as well.

One of the main changes the person made was to make the library be configured either for hardware spi or for software spi...
In the header file he has:
Code:
// remove this to use software SPI
#define ILI9341_USE_HW_SPI

With this he has it when using HW_SPI and the spi.h file says it supports transactions, it uses SPI library for both Teensy and AVR... It also uses the SPI.transfer16... He has also made several more of the methods to be inline code.

Bright side of using the #ifdef ILI9341_USE_HW_SPI is that it can cut down on code that will never be used as well as always testing a variable for are we using hardware spi. Downside is, if you have multiple projects that use this library for multiple boards and on some you use HW SPI and others Software SPI, you have to edit the library files, which can be a pain. (Sure wish Arduino had per project settings...)

Thoughts?
 
In case anyone is interested, I want to use some of these ILI9341/0 displays on both Teensy based stuff as well as Arduino (actually an Atmega644 based board) based system, and I still want the ability to read pixels. In particular where I am wanting this is for Debug text output where I can scroll the text...

So for the fun of it, I added the functions (readPixel, readRect, writeRect) which I added to the ILI9341_t3 library to the Adafruit_ILI9341 library. I think I now have them working, however they are a lot slower than they are in the ILI9341_t3 library, especially on an 16mhz 8 bit Atmega processor.

I adapted the read pixel test program mentioned earlier in this thread (could not use printf on stream, change library name...) and so far it appears to work on a Teensy 3.1 with PJRC ILI9341 display as well as on an Arbotix-M board (Atmega 644p) using Adafruit 2.2" TFT display (ILI9340). So should work fine on Atmega328p based systems as well. I have not tested it on an Arduino Due yet. I have one buried around here somewhere ;)

I should do another pass through the code to cleanup some stuff, I added some commands like: writecommand_cont, writedata_cont that leave the CS line selected, which is needed in these cases. Like the _t3 library I also had to spilit up setAddrWindow and setAddr. Currently I just have the setAddrWindow calling off to setAddr, where in the T3, I believe that setAddr in inline. Always an interesting question of trade off for speed versus size... Also wondering about taking pass through such that most of the commands have the CS pin selected through the command, as compared to current version where in most cases CS line is selected/deselected on each byte (or two bytes in cases of things like X or Y position).

Again I believe the pixel reading is working. If anyone wishes to play with it, I uploaded my changes to my fork on github: https://github.com/KurtE/Adafruit_ILI9341
Note: My fork was forked yesterday with all of the previous stuff that I believe matches what is downloaded with the 1.20rc5

Kurt


Hi Kurt,

I haven't had a chance to look but the Library I linked above "ILI9341_due" now has a screenshot method, is it implemented using your read pixel function?
 
It looks like they started off with the ILI9341_t3 code base and yes it appears to have a readPixel method. I have not looked at their screenshot code. But it would not be hard to do that with our current stuff as I have a readRect, where you pass in the bounds and an array to receive the pixel data into.

But it also looks interesting that they have some different ways to use SPI, like in DMA mode... At some point it might be interesting to try that on Teensy.
 
Arduino Due's SPI port lacks a FIFO, so DMA transfers are the only way to sustain high speed.

Teensy 3.0 & 3.1 have a 4 word FIFO build into the SPI port. With programming that leverages the FIFO, it's pretty easy to sustain maximum speed without the overhead of configuring and manipulating the DMA controller.
 
Arduino Due's SPI port lacks a FIFO, so DMA transfers are the only way to sustain high speed.

Teensy 3.0 & 3.1 have a 4 word FIFO build into the SPI port. With programming that leverages the FIFO, it's pretty easy to sustain maximum speed without the overhead of configuring and manipulating the DMA controller.

Yep - I updated my Adafruit_ILI9341 library up on github. There is another person who did a PR to the main Adafruit tree that did some speed ups of the library, by adding a #ifdef which allows you to either compile for HW SPI or Software SPI. I debated with myself about this as if I had a case for SW SPI, it would imply changing the library directory which then other projects would not compile. So in my version I made two classes, the main one for HW SPI and a second class Adafruit_ILI9341S which is only software SPI. With this made more functions inline, as for example: spiwrite just compiles to SPI.transfer, so the inline gets rid of the call overhead.

To verify, I ran the graphic test on T3.1 both hardware/software, Arbotix-M both hardware/software and I found my Arduino Due in box in cabinet, so tried the HW SPI version.
I also ran my version of the testing of my read pixel code to make sure it was working on all three. So far it looks like all three are working, BUT Arduino Due is running it real real slow. Something like 1.5 times slower than Arbotix (Atmega 644p 16mhz)...

So I can see why someone did a ILI9341_DUE

FYI - Testing T3.1/Arbotix with Arduino 1.0.6 T1.20rc5 and Due on 1.5.8

Kurt
 
Last edited:
Quick question: How to setup ILI9341_t3, Teensy 3.1,SD card on the TFT and audio board?
followed: http://www.pjrc.com/store/display_ili9341.html but no SD card reading.
I have not tried to use the SD card on that display. What I noticed was that there are IO pins on the other edge of the board which appear to be associated with the SD card. My guess is you would need to setup those IO pins to connect to your teensy. Again I am guessing but for sure you probably need to hook up the CS pin. Not sure if the etch on the board connects the MOSI on one edge to the other or if you need to connect those up as well. My guess is that you will need to connect those up as well.
 
So, this may be a naive question....

But I was wondering what the process would be for implementing the enhanced spi code for teensy 3.1 onto other tft controller codes?

I was hoping to get it running with the adafruit ra8875 driver code, for some moderate speed improvements.
This thread seems to be specific to a different controller and also delves into more ambitious ideas about large font optimization.

Is it as simple as changing the ra8875 library to using the teensy spi, instead of arduono spi.h? Or does it get alot more complicated than that?

Edit: Shit, I got to this thread from the github of what I thought was the spi fifo optimization code that Paul wrote, but it looks like it was intentionally specific. So I'm going to have to go back to this on a desktop because I think my confusion is due to mobile browsing the stuff.

My initial impression = Paul made a generalized spi library with faster transfer
My newer impression = not sure if its general spi or specific to that graphics controller chip
 
Last edited:
Ok, I went back while on a PC and I see that this library still uses the arduino "spi.h', i think.

Does that mean the speedups are exclusive to this controller chip and more intrinsic to the specific library than general SPI transfer?

Thanks,
-Tomek
 
Anyone have an idea on the last Q? I am sorry to post again so soon.

Part of me is looking into maybe trying SumoToy's still-beta RA8875 library, but that will take me ages to rewrite everything. I was hoping maybe I can make use of the SPI speedups in this code for a different controller chip. Is that a valid thought?

I went ahead and looked at the two libraries, and it looks like maybe Paul's speed changes were the result of a total rewrite, and not SPI generalized changes. Please correct me if I'm wrong.

So here's an example function:

PAUL'S
Code:
void ILI9341_t3::drawPixel(int16_t x, int16_t y, uint16_t color) {

	if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;

	SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0));
	setAddr(x, y, x, y);
	writecommand_cont(ILI9341_RAMWR);
	writedata16_last(color);
	SPI.endTransaction();
}

ADAPOWER's
Code:
void Adafruit_ILI9341::drawPixel(int16_t x, int16_t y, uint16_t color) {

  if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;

  if (hwSPI) spi_begin();
  setAddrWindow(x,y,x+1,y+1);

  //digitalWrite(_dc, HIGH);
  *dcport |=  dcpinmask;
  //digitalWrite(_cs, LOW);
  *csport &= ~cspinmask;

  spiwrite(color >> 8);
  spiwrite(color);

  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
  if (hwSPI) spi_end();
}

So it looks like this is a fundamental difference [it's also real code...so not really super accessible to a newb-coder like me].
But I guess it won't be super easy to adapt:
Code:
void Adafruit_RA8875::drawPixel(int16_t x, int16_t y, uint16_t color)
{
  writeReg(RA8875_CURH0, x);
  writeReg(RA8875_CURH1, x >> 8);
  writeReg(RA8875_CURV0, y);
  writeReg(RA8875_CURV1, y >> 8);  
  writeCommand(RA8875_MRWC);
  digitalWrite(_cs, LOW);
  SPI.transfer(RA8875_DATAWRITE);
  SPI.transfer(color >> 8);
  SPI.transfer(color);
  digitalWrite(_cs, HIGH);
}
Since those are all three quite different functions.

The best thought I could have was to adapt SUMOTOYS drawPixel function, but it ended up being just the same thing except with use of digitalFastWrite for the CS pin instead of digitalWrite (i suppose that should help a little I might add it. idk if it would help meaningfully though if the slowness is on the transfer speed and not the teensy speed.)
 
Last edited:
A question for all you ILI9341 pro's.
How quickly can you update the whole screen and what is the max SPI Frequency you can use?
Also do you have to refresh the entire screen or can you do just small parts of it?
 
Working with Adafruit display Product 1480 - ILI9340C -

Edit: I am using Arduino 1.06 with TD1.20 final for the testing

I have tried to use this library with the Adafruit display Product 1480 which uses the ILI9340C TFT driver. I have this working fine with the original Adafruit library and working in a fashion with this optimised library. However, although you can see it is working in principle there is some corruption in what is drawn, see images below:

DSC08251.jpgDSC08253.jpgDSC08254.jpgDSC08256.jpg

I thought I would give it a go after reading this post:

Also, unless something else changed I believe the same code will work for the ILI9340 as I did not find any real functional differences in the code bases

I realise it is not written for this chip but if anyone can offer any advice I would appreciate it. If it just did not work I guess I would have given up, but it looks a tweak away.

Anyone?

Ex
 
Last edited:
FYI, the results (of the corrupted output):

Begin setup, ILI9341 Test!
Display Power Mode: 0xCE
MADCTL Mode: 0x24
Pixel Format: 0x2
Image Format: 0xCE
Self Diagnostic: 0x0
Benchmark Time (microseconds)
Screen fill 280137
Text 19425
Lines 73329
Horiz/Vert Lines 23145
Rectangles (outline) 14671
Rectangles (filled) 581719
Circles (filled) 95534
Circles (outline) 95515
Triangles (outline) 17807
Triangles (filled) 197549
Rounded rects (outline) 39898
Rounded rects (filled) 637655
Done!
 
It has been awhile since I played with this display, but if I remember correctly I had better luck with this one when I hooked up reset pin and told the program to use it...
 
Just as a sanity check, how do the 3 libraries (ILI9341_t3, Adafruit_ILI9340 and Adafruit_ILI9341) compare?

Does the problem only occur with ILI9341_t3, with Adafruit's 2 libraries working flawlessly? Or do you see similar results on all three?
 
Back
Top