Playing around with yet another version of ILI9341_t3 library (ILI9341_t3n)

Grabbed two other ili9341's - both come up white on T$ - checked wiring - maybe bad wires or cheap mini breadboard that was handy.

Have to go pull any updates to t3n and SPIN … though not sure SPIN changed? I should make sure I know the right branches to grab?

Will go grab the #defines for FrankB's C64 with T_3.6 and try that - @KurtE - did T_3.6 need other changes? for the Bbrot?
 
@defragster

Kurt merged the WIP branches into the main branches for ILI9341_t3n and SPIN so don't have to worry about which branch to pull.
 
Got the latest -master of both into my libs:
Using library ILI9341_t3n at version 1.0 in folder: T:\tCode\libraries\ILI9341_t3n
Using library SPI at version 1.0 in folder: T:\arduino_1.8.9_146\hardware\teensy\avr\libraries\SPI
Using library SPIN in folder: T:\tCode\libraries\SPIN (legacy)

T$ pressed into breakout - Still just a white screen - the other two I brought over have the J1 soldered - so it isn't that on the other one. Gotta be my wiring/wires.
 
Hi @defragster as @mjs513 mentioned, I merged the WIP branch of spin and ILI9341_t3n libraries into their master branch.

Also with it not working for you on T4, The posted program above uses DC=9 and CS=10, which up till recent changes to the ILI9341_t3n library would not run as it required DC to be on a hardware CS pin (only pin 10), which I recently put in a workaround to make it work without hardware CS in.

Note: I might be sidetracked for a little bit of time. I received some other stuff in the mail today, which I may need to play with:
A couple of small wifi repeater boards that for the heck of I supported on Kickstarter:
IMG_0721.jpg

Also A RC remote control, that has a Serial communications setup, which I thought I might try out on Hexapod...
 
@KurtE

Have a question that I can't seem to find an answer to - sure it obvious. How to save generated images on the ILI9341 as a bmp to a sdcard? Can you point me in the right direction.
 
Hi @mjs513,

Sorry, I have never done it. But if I were to try doing it, I would probably start off looking at one of the example apps that does the reverse of this.
Like spitftbitmap (I know the Adafruit_ili9341 library has this one as well as the ili9341_t3...).

And then you would need to reverse the operations: like output the signature 4D42 and some create bytes....
Probably assume and setup for 24 bit format, and then loop through either reading the image from the display and convert colors to write them out, or in case of app that has data already in memory, convert that data into 24 bit color info...

Sorry I know that is a bit vague.
 
@KurtE

Thanks - had a feeling you were going to say that - surprised no one tried to do it before this
 
Note knowing anything about the internals, I wonder if you could create an Adafruit_GFX 'display' that acts as a normal display and records the screen information for circle, draw line, etc. Each call then would call the real display with the same arguments, and then when the command is given to update the screen, you take a snapshot and write a BMP or similar file to the SD.
 
@KurtE and @MichaelMeissner

Did a quick search just now (been busy with Kicad). Not much out there on writing BMP's - plenty on reading though :). Anyway found three links of interest that I am posting here just in case some one else is interested.

https://forum.arduino.cc/index.php?topic=112733.0 which pointed to https://stackoverflow.com/questions...e-c-c-without-other-libraries/2654860#2654860. The other one: https://stackoverflow.com/questions/16724214/writing-images-with-an-arduino.

So another project for the list :)
 
@KurtE, @defragster and @MichaelMeissner

Since I don't like reinventing the wheel :) I gave the program to write a BMP from the Arduino forum a test run (a few minor mods) and it worked. Windows even opened the bmp file no problem. In case you are interested here it is:
Code:
#include <SD.h>
#include <SPI.h>

/*
WRITE BMP TO SD CARD
Jeff Thompson
Summer 2012

TO USE MEGA:
The SdFat library must be edited slightly to use a Mega - in line 87
of SdFatConfig.h, change to:

   #define MEGA_SOFT_SPI 1

(this uses pins 10-13 for writing to the card)

Writes pixel data to an SD card, saved as a BMP file.  Lots of code
via the following...

BMP header and pixel format:
   http://stackoverflow.com/a/2654860

SD save:
   http://arduino.cc/forum/index.php?topic=112733 (lots of thanks!)
... and the SdFat example files too

www.jeffreythompson.org
*/

char name[] = "9px_0000.bmp";       // filename convention (will auto-increment)
const int w = 16;                   // image width in pixels
const int h = 9;                    // " height
const boolean debugPrint = true;    // print details of process over serial?

const int imgSize = w*h;
int px[w*h];                        // actual pixel data (grayscale - added programatically below)

File file;
const int cardPin = 18;          // pin that the SD is connected to (d8 for SparkFun MicroSD shield)

void setup() {
  
  // iteratively create pixel data
  int increment = 256/(w*h);        // divide color range (0-255) by total # of px
  for (int i=0; i<imgSize; i++) {
    px[i] = i * increment;          // creates a gradient across pixels for testing
  }

  // SD setup
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  if (!SD.begin(cardPin)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");


  // if name exists, create new filename
  for (int i=0; i<10000; i++) {
    name[4] = (i/1000)%10 + '0';    // thousands place
    name[5] = (i/100)%10 + '0';     // hundreds
    name[6] = (i/10)%10 + '0';      // tens
    name[7] = i%10 + '0';           // ones
    file = SD.open(name, O_CREAT | O_EXCL | O_WRITE);
    if (file) {
      break;
    }
  }

  // set fileSize (used in bmp header)
  int rowSize = 4 * ((3*w + 3)/4);      // how many bytes in the row (used to create padding)
  int fileSize = 54 + h*rowSize;        // headers (54 bytes) + pixel data

  // create image data; heavily modified version via:
  // http://stackoverflow.com/a/2654860
  unsigned char *img = NULL;            // image data
  if (img) {                            // if there's already data in the array, clear it
    free(img);
  }
  img = (unsigned char *)malloc(3*imgSize);

  for (int y=0; y<h; y++) {
    for (int x=0; x<w; x++) {
      int colorVal = px[y*w + x];                        // classic formula for px listed in line
      img[(y*w + x)*3+0] = (unsigned char)(colorVal);    // R
      img[(y*w + x)*3+1] = (unsigned char)(colorVal);    // G
      img[(y*w + x)*3+2] = (unsigned char)(colorVal);    // B
      // padding (the 4th byte) will be added later as needed...
    }
  }

  // print px and img data for debugging
  if (debugPrint) {
    Serial.print("\nWriting \"");
    Serial.print(name);
    Serial.print("\" to file...\n");
    for (int i=0; i<imgSize; i++) {
      Serial.print(px[i]);
      Serial.print("  ");
    }
  }

  // create padding (based on the number of pixels in a row
  unsigned char bmpPad[rowSize - 3*w];
  for (int i=0; i<sizeof(bmpPad); i++) {         // fill with 0s
    bmpPad[i] = 0;
  }

  // create file headers (also taken from StackOverflow example)
  unsigned char bmpFileHeader[14] = {            // file header (always starts with BM!)
    'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0   };
  unsigned char bmpInfoHeader[40] = {            // info about the file (size, etc)
    40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0   };

  bmpFileHeader[ 2] = (unsigned char)(fileSize      );
  bmpFileHeader[ 3] = (unsigned char)(fileSize >>  8);
  bmpFileHeader[ 4] = (unsigned char)(fileSize >> 16);
  bmpFileHeader[ 5] = (unsigned char)(fileSize >> 24);

  bmpInfoHeader[ 4] = (unsigned char)(       w      );
  bmpInfoHeader[ 5] = (unsigned char)(       w >>  8);
  bmpInfoHeader[ 6] = (unsigned char)(       w >> 16);
  bmpInfoHeader[ 7] = (unsigned char)(       w >> 24);
  bmpInfoHeader[ 8] = (unsigned char)(       h      );
  bmpInfoHeader[ 9] = (unsigned char)(       h >>  8);
  bmpInfoHeader[10] = (unsigned char)(       h >> 16);
  bmpInfoHeader[11] = (unsigned char)(       h >> 24);

  // write the file (thanks forum!)
  file.write(bmpFileHeader, sizeof(bmpFileHeader));    // write file header
  file.write(bmpInfoHeader, sizeof(bmpInfoHeader));    // " info header

  for (int i=0; i<h; i++) {                            // iterate image array
    file.write(img+(w*(h-i-1)*3), 3*w);                // write px data
    file.write(bmpPad, (4-(w*3)%4)%4);                 // and padding as needed
  }
  file.close();                                        // close file when done writing

  if (debugPrint) {
    Serial.print("\n\n---\n");
  }
}

void loop() { }
Now to incorporate it into "Butterbrot" as @Frank B called it on the other thread :)
 
@KurtE and @defragster

I know we are kind of jumping all over the place but was wondering about the ILI93488 - mine seems to work with the T$ for Graphics but not with FB_Teensy64 for some reason have to look a little closer maybe I typed something wrong.

But anyway, was looking at what it would take to use the ILI9388 with the ILI9341_t3n library? Right now besides addresses maybe (didn't check) and commands like:
Code:
  uint8_t  readdata(void),
    readcommand8(uint8_t reg, uint8_t index = 0);
    writecommand(uint8_t c),
    write16BitColor(uint16_t color),
    writedata(uint8_t d),
would change - just not sure the equivalent - didn't look yet. That is should work?
 
@KurtE and @defragster
I know we are kind of jumping all over the place but was wondering about the ILI93488 - mine seems to work with the T$ for Graphics but not with FB_Teensy64 for some reason have to look a little closer maybe I typed something wrong.
But anyway, was looking at what it would take to use the ILI9388

Sorry to be a little OT but what is the part number: ILI93488 or ILI9388? I couldn't google data sheets for either.

We are using the ILI9341 displays from BuyDisplay but their quality has been spotty - some whole displays just fade away after about a year. We are not using a lot of them; mostly on mfg test fixtures as the GUI.

I'd like to find a good display from a reliable source we could use going forward. Still looking. For now, BuyDisplay is hard to beat even if they have to be replaced every 12 months. The ILI9341 limit of 320x240 is OK for small displays.

Some open source drivers I've seen ignore the speed limit for reading and writing the ILI9341. Not a good idea for reliability.
 
Ooopss…

My fat fingering got me again - its a ILI9488. Have you tried the ILI9341_t3n or the ILI9341_t3 libraries. They do support framebuffering and dma I believe. I have been doing mandelbrots on them without a problem.
 
@mjs513, @defragster, @Paul, @Frank B ...

Yes - I was wondering if someone (we?) should create a version of ILI9388_t3? I was sort of waiting to see if Paul was going to use these displays or not... For example do I need to pick up one that has the same wiring as the ones you might have?

There are some interesting things about these displays that I am not sure how we would update the display...

Most importantly is, they don't appear to support 16 bit color, they instead only support 8 color or 262K(18 bit)

So all of the output code would have to be changed when they do outputs, to either have us pas in 18 bit colors or to translate the colors.

Then there is frame buffer stuff... I am guessing we would need to have 24 bits per pixel, so the storage of values would have to change, at least if we then supported DMA stuff. Without DMA we could do color translation as we pull stuff out of FB and output to SPI register.

And then there is the size of the frame buffer: 3*320*480= 460800 bytes or 3 times the FB of ili9341... Which currently does not fit into memory of T4 (beta 1), I think the high memory area is 256K, but may work on T4 (beta 2), which I think has 512K...

I sure wish there was some form of DMA, that did something like:

8 bit frame buffer -> color look up table -> SPI queue...

Also wondering for SPI, if we might add: SPI.transfer24()... As we can setup framesize to this (also can do frame size of 32)...

But some of this discussion maybe should propagate back to t$ thread.
 
Ok Guess back to the T$ library.

Yes - I was wondering if someone (we?) should create a version of ILI9388_t3? I was sort of waiting to see if Paul was going to use these displays or not... For example do I need to pick up one that has the same wiring as the ones you might have?
I picked up the ones that Paul is using.
 
The ILI9488 (nine FOUR eighty-eight) units I got closest to working - except no tri-state on the TFT_MISO - look to be the same ones Paul ordered - posted on T4_Beta thread. Maybe a fix is simple using a daughter board adding tristate to the OSH Purple Display board - it is Touch and Pin compatible with ili9341.

It would be awesome if there was a better/best version out there that allowed 16 bit color selection - the RasPi board I got silkscreen suggests that is an option - but that board has not D/C control pin exposed? IIRC there are RasPi drivers that use that mode - just 1GB driver downloads no docs or details I saw.

I found using the 9488 library but plugging in a 9341 TFT WORKED to some extent - pixels rendered image with wrong colors. So the general controller commands are otherwise common - but the reverse did not work for 9341 lib to do any good on 9488.

FrankB made a DEMO library with 8 bit color storage that did color look up translation on posting to the display. That would use less memory for image buffer - but still has slowness involved in the manipulation and write of 3 byte ( non DMA ) data to display.

I have a partial working 'line write' copy of that - FrankB said it was 'mine' to finish as he was not going to explore further use. It tracks DIRTY line segments [as changed in the buffer] and only writes buffer areas that have been changed. That of course adds overhead as each line is 'handled' then. Frank said completion of this CLUT version should just take an hour :) - seems I should be able to share that if it would show promise.
 
If you look in the lib it takes a 24bit color and converts it to uint8's for r, g, b values. He also has code commented out for the ST32 to use dma sends
 
@mjs513, @defragster, @Paul, @Frank B ...

Yes - I was wondering if someone (we?) should create a version of ILI9388_t3? I was sort of waiting to see if Paul was going to use these displays or not... For example do I need to pick up one that has the same wiring as the ones you might have?

There are some interesting things about these displays that I am not sure how we would update the display...

Most importantly is, they don't appear to support 16 bit color, they instead only support 8 color or 262K(18 bit)

So all of the output code would have to be changed when they do outputs, to either have us pas in 18 bit colors or to translate the colors.

Then there is frame buffer stuff... I am guessing we would need to have 24 bits per pixel, so the storage of values would have to change, at least if we then supported DMA stuff. Without DMA we could do color translation as we pull stuff out of FB and output to SPI register.

And then there is the size of the frame buffer: 3*320*480= 460800 bytes or 3 times the FB of ili9341... Which currently does not fit into memory of T4 (beta 1), I think the high memory area is 256K, but may work on T4 (beta 2), which I think has 512K...

I sure wish there was some form of DMA, that did something like:

8 bit frame buffer -> color look up table -> SPI queue...

Also wondering for SPI, if we might add: SPI.transfer24()... As we can setup framesize to this (also can do frame size of 32)...

But some of this discussion maybe should propagate back to t$ thread.



Hi KurtE & @mjs513, @defragster, @Paul, @Frank B ...


So now we have a released T4.0, it looks like there is room all the way up to 800x600x24bpp frame buffer, still with ~512KB ram left over for applications. This is larger than any available SPI display I could find.

At this point is it pragmatic to have a step back and consider the best way forward on supporting serial displays at the moment and the future?
I believe this question/discussion has been posed a few times but, my thoughts are that there are only going to be more and newer serial displays that will need supporting..

For example we have:

ili9341_t3 - the original optimised ili9341 version
ili9341_t3DMA - franks testing DMA version
ili9341_t3n - kurtE updated frambuffer and DMA version (with many forks)
ST7735_t3 - kurtE with updated 7789 support DMA and framebuffer
ili9488_t3 - mjs513 9488 library
RA8875 - sumotoys RA8875 large format display library

I've played with about half of these and there is significant amount of overlap between the libraries in terms of code, graphic functions, overall structure

Would it not be better to bring all the separate efforts together to build a polylithic?? library that supports multiple spi displays now and in the future, a teensy version of adafruit_gfx and adafruit_spitft essentially?

"Teensy_SerialTFT"

For example:

[GFX Libraries] > [Driver - ili9341, ili9488, ra8875, st77xx etc] >[HAL - T3.2,T3.5,T3.6,T4.0 etc]>[Frame Buffer - Opt] > [DMA - Opt] > [SPI/SPIN]


I think it would be less confusing for new users (consolidating forks etc), moving between displays and devices would be alot easier, and it provides a solid foundation for future hardware (displays and teensys).

thoughts?
 
@kjn - yes it would be nice to have a full complete set of libraries all under one roof, ... But as there are a collection of diverse people all doing their own thing, it may be difficult to achieve!

I do think we can take some baby steps, for example Adafruit has a whole pretty complete set of drivers for lots of displays. However for the most part they have not been optimized for the Teensy.

My impression with communicating some with them, is they would welcome taking in Pull Requests from us to improve the performance of the screen drivers. That is many/most of their drivers drive from Adafruit_GFX, and more specificially spitft class. So we hopefully over time, we can bring in some of the basics that originally started with ili9341_t3 library and integrate some of the speed ups into that library for those cases that we can speed up. Example on T3.x where DC is in a hardware CS....

As for a Teensy version of SPITFT like library. The issue is on the PJRC side there is only Paul, who is stretched very thin. So many of us just do are own thing... But hopefully over time they will converge. At least hopefully API wise enough to make it easier to port sketches from one display to another.

@all - On a different topic. There have been some recent questions about how to read from SD cards and display on the screen as fast as possible... So far on the T3.6, so far I am not having much luck reading in more than about 4 240x320 BMP files per second. Here is a version of the ili9341_t3n code that cycles through reading in 3 different bmp files and displaying them as quick as possible:View attachment ili9341_t3_spitftbitmap_fast-190904a.zip

Again there are probably quicker ways. But right now the majority of the time is spent in reading in the BMP files
 
@all - On a different topic. There have been some recent questions about how to read from SD cards and display on the screen as fast as possible... So far on the T3.6, so far I am not having much luck reading in more than about 4 240x320 BMP files per second. Here is a version of the ili9341_t3n code that cycles through reading in 3 different bmp files and displaying them as quick as possible:View attachment 17492

Again there are probably quicker ways. But right now the majority of the time is spent in reading in the BMP files

So some stats from my code:

read from SD card to frame buffer = ~22ms.
(this is a 240x320 565 formatted bitmap - using SDFat on the 3.6 SDIO port)

flush frame buffer to display (dma) = ~44ms.

= 66ms

or 15FPS - but there is strobing if I use single shot DMA to refresh the screen

EDIT: I'll post some sample code later.
 
Last edited:
Sounds good, here is a version using SDFat...

View attachment ili9341_t3_spitftbitmap_fast-190905a.zip

So far I have not tried to optimize it at all from the sort of original bitmap viewer program...

For example, I don't remember with SDFat on what is the best way to read in this stuff. Example right now it looks through all of the header info one byte at a time, then it tries to read in enough bytes for n pixels (3*n). But question is what is the fastest read in speed? 128 byte reads?

Or should I use some of the information from Cardinfo:
Code:
cardSize: 31914.98 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true

OCR: 0XC0FF8000

SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X0,0X82,0X3,0X0,0XC,0XFE,0XFF,0XFF,8192,62325760
2,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
3,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
4,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 64
clusterCount:      973584
freeClusterCount:  973556
fatStartSector:    9362
dataStartSector:   24576
And try to read in 128*64? 8192 bytes? or???

Anyway the current one is getting about 7.8fps
 
Sounds good, here is a version using SDFat...

View attachment 17517

So far I have not tried to optimize it at all from the sort of original bitmap viewer program...

For example, I don't remember with SDFat on what is the best way to read in this stuff. Example right now it looks through all of the header info one byte at a time, then it tries to read in enough bytes for n pixels (3*n). But question is what is the fastest read in speed? 128 byte reads?

Or should I use some of the information from Cardinfo:
Code:
cardSize: 31914.98 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true

OCR: 0XC0FF8000

SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X0,0X82,0X3,0X0,0XC,0XFE,0XFF,0XFF,8192,62325760
2,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
3,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
4,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 64
clusterCount:      973584
freeClusterCount:  973556
fatStartSector:    9362
dataStartSector:   24576
And try to read in 128*64? 8192 bytes? or???

Anyway the current one is getting about 7.8fps

So my benchmark was way off - it was actually 66ms to load a 150kB file from the sd card to the frame buffer. Time to flush the framebuffer seems very constant at 44ms.

I went back into my code and did some more optimisation, I now load a whole row of pixels (320 @ 16bpp) in one hit and changed to the (blocking) SDFatSDIOEx class which has an impressive speed gain.

The code can now load a full frame in 14-15ms into the frame-buffer , if you could push out to the display any quicker you could achieve 60FPS.

Currently with 44ms to flush the frame buffer - maximum achievable is about 22FPS. I think i have seen examples of it running quicker, does anyone know what the limit of these displays are for a full screen pixel by pixel over SPI?


Code attached, along with files for the SD card, with a few demos. using the blocking UpdateScreen its about 17FPS and has visible strobing, if you run it flat out you get really bad tearing as 4 frames have been through the frambuffer in a single refresh.


I use a $10 16GB Sandisk Ultra - the cheapest one at the office supplies store. You need the latest version of SdFat:https://github.com/greiman/SdFat


Insight / Feedback appreciated.

View attachment spitftbitmapt36_sdfat_demo.zip
 
Back
Top