Highly optimized ILI9341 (320x240 TFT color display) library

Code:
#define SPICLOCK 30000000
Yes, that's a part of the truth... in short this means "take the max freq" :) - which is 30000000 for F_BUS=60000000 but less for lower F_BUS.
In comparison to the CPU-Speed this is the bottleneck, so it's the main factor. F_CPU has only little impact, but -if you want to have a look at the list above - they are interdependent.
So..the whole truth is ... both is correct. :rolleyes:
 
I cant assume the SPI is the only limiting factor to the library.

It certainly is the largest factor by a huge margin. CPU speed helps slightly for complex stuff like fonts, circles, etc. But even then, SPI clock rate is by far the dominant factor determining overall performance.
 
Whelp in the last hour i have discovered a few interesting things.

1. I can power both the Teensy 3.1 and the Adafruit ILI19431(product ID:1770) from the same power supply just fine using the graphicstest from the ILI9431_t3 optimized library. But if I run the breakouttouchpaint example I have to have the RST pin connected with [ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST);] or I get a blank screen, if I power cycle the Teensy it starts working. And while the screen is blank if I touch the screen the led on pin 13 flashes so its talking but the screen is just ignoring the Teensy.

2. I tried setting the digital pins for the touch screen to 32 and 33 and screen would remain blank. If i removed those to wires and power cycled the screen would work again. I moved over to using pins 18 and 19, which seems to work just fine.
 
@Donziboy2: No SPICLOCK is just a define that set the maximum desired speed, however the chip can not generate a higher clock than F_BUS / 2 which is 18 MHz for Teensy 3.1 with default system clock of 72 MHz. However 18 MHz is alreay faster than allowed for this display as you can see it my other posts here. SPI read clock even have to be lower than SPI write clock. Setting any higher SPI clock is simply ignored and so not possible!
 
Why is it everyone seems to think I have issues understanding the SPI clock.... I have run 3.0's with SPI @ 25Mhz I am well aware of it and how it functions....... My original question was whether or not the numbers I was getting was normal.
 
Its me again.....

Spent the last few hours playing around, working on a basic display for my Ecart Project.

I have the redraw time down to 5-7 ms depending on the left RGB bar that I redraw, may optimize it more later.
My one issue is I can see flickering in all values that I change per refresh. I was running about 22ms per refresh and was having the same flickering issue, is there any ways to get around it?

w3b4FK2l.jpg


Code:
/**************************************************  *
Adafruit graphicstest used as a base.
 **************************************************  **/


#include "SPI.h"
#include "ILI9341_t3.h"

// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 8
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST);

#define backlight 6

//Test perams
float frequency2 = 25.987654;
float frequency2old = 0;
float BatterySOC = 0.85;     // percentage of charge (assumed)
float BatterySOCold = 0;
volatile int32_t executiontime = 0;
byte boxset = 0;
byte drivestate = 1;
byte drivestateold = 0;


void setup() {
  pinMode(backlight, OUTPUT);
  
  
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(3);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(3);
  tft.println("Initializing.....");
  delay(1000);
  tft.fillScreen(ILI9341_BLACK);
  tft.fillRect(5, 5, 20, 230, ILI9341_WHITE);     //blank battery bar once
  mainScreen();
  analogWrite(backlight, 128);    //50% backlight and 488Hz pwm
  
}


void loop() {
//  for(uint8_t rotation=0; rotation<4; rotation++) {
//    tft.setRotation(rotation);
    refreshtime();
    
    mainScreen();
    
 //   executiontime = elapsedtesttime;
    
    delay(300);
    frequency2 = frequency2 + 0.001;
    if(frequency2 >100){
      frequency2 = 0.1;
    }
    BatterySOC = BatterySOC + 0.0001;
    if(BatterySOC > 1){
     BatterySOC = 0;
    } 
//  }
}

unsigned long refreshtime(){

  
  tft.fillRect(35, 110, 75, 15, ILI9341_BLACK);
  tft.setCursor(35, 110);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.print(executiontime);
  tft.setCursor(35, 130);
  tft.print("Microseconds");

}


unsigned long mainScreen() {
  elapsedMicros elapsedtesttime;
  
  if(BatterySOCold > BatterySOC){
  tft.fillRect(5, 5, 20, 230, ILI9341_WHITE);     //blank battery bar
  }
 
 
  if(BatterySOC <= 0.3333 && BatterySOC != 0){      //red battery bar only
    float x;
    float y;
    x = BatterySOC / 0.3333;
    y = x * 76;                  //rectangle size
    x = 235 - y;                 //rectangle starting position
  tft.fillRect(6, x, 18, y, ILI9341_RED);
  }
  
  if(BatterySOC <= 0.6666 && BatterySOC > 0.3333){      //red and yellow battery bars only
    float x;
    float y;
    x = BatterySOC - 0.3333;    //remove red region
    x = x / 0.3333;
    y = x * 76;                 //rectangle size
    x = 159 - y;                //rectangle starting postion
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  tft.fillRect(6, x, 18, y, ILI9341_YELLOW);

  }
  
  if(BatterySOC <= 1 && BatterySOC > 0.6666){      //red, yellow and green battery bars only
    float x;
    float y;
    x = BatterySOC - 0.6666;    //remove red and yellow region
    x = x / 0.3333;
    y = x * 76;                 //rectangle size
    x = 83 - y;                //rectangle starting postion
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  tft.fillRect(6, 82, 18, 76, ILI9341_YELLOW);
  tft.fillRect(6, x, 18, y, ILI9341_GREEN);
  }
  
  
  if(boxset < 1){                                 //removes redraw for no reason
  tft.drawRect(145, 5, 170, 30, ILI9341_GREEN);   //drive status box 
  tft.drawRect(35, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(105, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(175, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(245, 185, 65, 50, ILI9341_WHITE);
  boxset = 1;
}
  
//  tft.fillRect(50, 5, 59, 14, ILI9341_BLACK);     //clears % value
  
  tft.setTextColor(ILI9341_BLACK); tft.setTextSize(2);
  tft.setCursor(50, 5);
  tft.print((float)BatterySOCold * 100,2);     tft.print("%");
  
  tft.setCursor(50, 5);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.print((float)BatterySOC * 100,2);    tft.print("%");
  tft.setCursor(50, 22);
  tft.print("Charge");
  BatterySOCold = BatterySOC;
 // tft.fillRect(195, 110, 115, 35, ILI9341_BLACK);   //clears MPH Value
  
  tft.setTextColor(ILI9341_BLACK); tft.setTextSize(5);
  tft.setCursor(195, 110);
  tft.print(frequency2old, 1);
  
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(195, 110);
  //math below gets rid of stupid rounding issues
  float w = 10 * frequency2;    //move decimal place over 1
  int x = w;                    //remove everything right of decimal
  float y = x;                  //convert back to float, this step is needed since dividing an int by 10 rounds the number......
  float z = y / 10;             //back to almost origil value, leaves us with 1 value to right of decimal, any more then that and it would round
  tft.print(z, 1);
  frequency2old = z;
  //tft.print((float)frequency2, 1);  // this rounds 25.98765 to 26.0  :(
  tft.setTextColor(ILI9341_BLUE);    tft.setTextSize(4);  
  tft.setCursor(240, 150);  
  tft.println("MPH");
  
  if(drivestateold != drivestate){   //only change is drivestate changes
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(2);
  tft.setCursor(170, 12);
  tft.println("DriveStatus");
  drivestateold = 1;
  }
  
  executiontime = elapsedtesttime;

}

Video, but its really hard to see.
 
Last edited:
Putting the static prints [ mph, charge, frequency, microseconds ] under boxset like checks drops update from 7.8 to 6.4 millis

Not old/new printing the MPH when it doesn't change drops it to max 4.3 millis ( under 1.1 as battery changes ). Skipping/delaying battery update bar on minor changes would probably average under 2. View attachment _26305_Cart_R.ino

Your black overprint of the prior speed - as you probably know - is way faster than a fillRect()

Taking the delay out turns the flicker to a cool flash - less so when MPH doesn't change.

Your raw graphicstest times about match mine, like those shown earlier in the thread.

Do you actually have the backlight powered from a pin? What resistor value did you put inline if so?
 
As I found out, an unclean/noisy clock/data lane can cause this unexpected full screen flickering, not 100% sure, but this should be the reason. At least my tests showed an increase in such flickering if noise was increased and and decrease of the flickering if noise was reduced.
 
Putting the static prints [ mph, charge, frequency, microseconds ] under boxset like checks drops update from 7.8 to 6.4 millis
Ya I moved a few more things around and have it counting up and down now, I get 4.5ms at the start of the new rectangles and about 5ms at the end. The count down is at around 10ms but I can fix that with more code.
Not old/new printing the MPH when it doesn't change drops it to max 4.3 millis ( under 1.1 as battery changes ). Skipping/delaying battery update bar on minor changes would probably average under 2. View attachment 3922
Ya I put all the static text in with the box's so its not getting redrawn.
Your black overprint of the prior speed - as you probably know - is way faster than a fillRect()
It made a huge difference, originally i was getting almost 20ms per refresh using fillRect() instead of reprinting the old value in black.
Taking the delay out turns the flicker to a cool flash - less so when MPH doesn't change.
Ya I experimented with 20ms delays and 100ms instead of 300ms but it was still very noticable. I plan on running the final project at 100ms and only updating information as it changes.
Your raw graphicstest times about match mine, like those shown earlier in the thread.
That was one of my biggest concerns, is not knowing what the norm should be.
Do you actually have the backlight powered from a pin? What resistor value did you put inline if so?
The Adafruit screen im using (#1770) has an internal 1k pullup to 5v and a second 1k at the base of an npn that drives the backlight. The LITE connection goes between the 2 resistors.
Im running it with the below code, based on the Adafruit schematic it should pull around 2.5mA at 50% or 5mA at 0% brightness (no RL reason to ever go to 0% but it should be safe). I had to turn it down to around 25% to get pictures and video, the colored bar was getting whited out.
Code:
  analogWrite(backlight, 128);    //50% backlight and 488Hz pwm
 
As I found out, an unclean/noisy clock/data lane can cause this unexpected full screen flickering, not 100% sure, but this should be the reason. At least my tests showed an increase in such flickering if noise was increased and and decrease of the flickering if noise was reduced.

1V/div and 200ns/div
ie2APyt.jpg


Not sure if I would consider that really noisy. That is on pin 16 of IC3 (74LVC245).
It also does not seem to matter at what frequency I run the clock, from 24Mhz to 96 it flickers.
 
Is that a picture with no delay in your update calls? When I took that out the flash and failure to redraw was evidence on the large MPH area when always drawing. Like when the camera is out of sync with a display refresh and you get blank banding - but that was refreshing the text areas 125-250 fps. I have the PJRC display - will look at current - I just powered it from 3.3 over a resistor and have decent but fixed brightness.
 
Just like in TV's its not how many Hertz (FPS) you get but how fast pixels can change and how long it takes for HW to implement that change. At high speeds like that I can imagine it looks pretty bad, im sure the screens aren't made for that speed so your getting a lot of Ghosting. At 300ms per refresh I can make out the flicker. I will try it at 1s per refresh and see.
 
Even at 500ms delay the flicker is still noticeable. But the numbers that change show no signs of flicker..... Adding a delay(1); after blacking the text and updating made it extremely noticeable, but when a number changed it did not seem to flicker. I think its our eye's playing tricks on us.
I guess the only easy way around this is to only update digits that change....

On a side not I noticed a decent amount of noise on the Lite pin when the Teensy was updating the screen.
1hxQCyY.jpg

aAtyOUV.jpg
 
Ok, updated code. I disabled the delay and the MPH numbers have almost no flicker, there is a slight flicker but you have to literally stair at the numbers as they are changed and its only on lines that are reused from previous numbers. The charge bar goes crazy on the downward run but I have plans to change how it draws. I left the other numbers alone so you can see the difference.

I do consider this way of doing it more work/annoying but it comes out better.

Code:
/***************************************************
Adafruit graphicstest used as a base.
 ****************************************************/


#include "SPI.h"
#include "ILI9341_t3.h"

// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 8
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST);

#define backlight 6

//Test perams
int frequency2 = 259;
int frequency2old = 0;
float BatterySOC = 0.85;     // percentage of charge (assumed)
float BatterySOCold = 0.85;
volatile int32_t executiontime = 0;
byte boxset = 0;
byte drivestate = 1;
byte drivestateold = 0;
byte  Redfull = 0;
byte  Yellowfull = 0;
byte  Greenfull = 0;
  int a = 0;
  int b = 0;
float wold = 0;
float xold = 0;
float yold = 0;
float zold = 0;
int i = 0;

void setup() {
  pinMode(backlight, OUTPUT);

  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(3);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(3);
  tft.println("Initializing.....");
  delay(1000);
  tft.fillScreen(ILI9341_BLACK);
  tft.fillRect(5, 5, 20, 230, ILI9341_WHITE);     //blank battery bar once
  mainScreen();
  analogWrite(backlight, 192);    //50% backlight and 488Hz pwm
 
}


void loop() {

    refreshtime();
    
    mainScreen();
    

 //   delay(50);
 // frequency2++;
    i++;
    if(i == 10){
    if(frequency2 >= 990){
      a = 1;
    }
    if(frequency2 <= 0){
     a = 0; 
    }
    if(a == 0){
      frequency2 = frequency2 + 1;   
    }
    else
        {
             frequency2 = frequency2 - 1; 
        }
        i = 0;
    }
    
    if(BatterySOC >= 0.99){
      b = 1;
    }
    if(BatterySOC <= 0){
     b = 0; 
    }
    if(b == 0){
      BatterySOC = BatterySOC + 0.0001;   
    }
    else
        {
             BatterySOC = BatterySOC - 0.0001; 
        }  
  
  
}

unsigned long refreshtime(){

  
  tft.fillRect(35, 110, 75, 15, ILI9341_BLACK);
  tft.setCursor(35, 110);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.print(executiontime);
  tft.setCursor(35, 130);
  tft.print("Microseconds");

}


unsigned long mainScreen() {
  elapsedMicros elapsedtesttime;
  
  if(boxset < 1){                                 //removes redraw for no reason
  tft.drawRect(145, 5, 170, 30, ILI9341_GREEN);   //drive status box 
  tft.drawRect(35, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(105, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(175, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(245, 185, 65, 50, ILI9341_WHITE);
  
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.setCursor(50, 22);
  tft.print("Charge");
  tft.setTextColor(ILI9341_BLUE);    tft.setTextSize(4);  
  tft.setCursor(240, 150);  
  tft.println("MPH"); 
  tft.setTextColor(ILI9341_YELLOW);   tft.setTextSize(5);
  tft.setCursor(255, 110);   
  tft.print("."); 
 
  boxset = 1;
}  
  
  
  
  
  if(BatterySOCold > BatterySOC){
  tft.fillRect(5, 5, 20, 230, ILI9341_WHITE);     //blank battery bar
  Redfull = 0;
  Yellowfull = 0;
  }
 
 
  if(BatterySOC <= 0.3333 && BatterySOC != 0){      //red battery bar only
    float x;
    float y;
    x = BatterySOC / 0.3333;
    y = x * 76;                  //rectangle size
    x = 235 - y;                 //rectangle starting position
  tft.fillRect(6, x, 18, y, ILI9341_RED);
  Redfull = 0;
  Yellowfull = 0;
  }
  
  if(BatterySOC <= 0.6666 && BatterySOC > 0.3333){      //red and yellow battery bars only
    float x;
    float y;
    x = BatterySOC - 0.3333;    //remove red region
    x = x / 0.3333;
    y = x * 76;                 //rectangle size
    x = 159 - y;                //rectangle starting postion
    if(Redfull == 0){
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  Redfull = 1;
    }
  tft.fillRect(6, x, 18, y, ILI9341_YELLOW);
  Yellowfull = 0;
  }
  
  if(BatterySOC <= 1 && BatterySOC > 0.6666){      //red, yellow and green battery bars only
    float x;
    float y;
    x = BatterySOC - 0.6666;    //remove red and yellow region
    x = x / 0.3333;
    y = x * 76;                 //rectangle size
    x = 83 - y;                //rectangle starting postion
  if(Redfull == 0){
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  Redfull = 1;
  }
  if(Yellowfull == 0){
  tft.fillRect(6, 82, 18, 76, ILI9341_YELLOW);
  Yellowfull = 1;
  }
  tft.fillRect(6, x, 18, y, ILI9341_GREEN);
  }
  
  
//  tft.fillRect(50, 5, 59, 14, ILI9341_BLACK);     //clears % value
  
  tft.setTextColor(ILI9341_BLACK); tft.setTextSize(2);
  tft.setCursor(50, 5);
  tft.print((float)BatterySOCold * 100,2);     tft.print("%");
  
  tft.setCursor(50, 5);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.print((float)BatterySOC * 100,2);    tft.print("%");
  BatterySOCold = BatterySOC;
 // tft.fillRect(195, 110, 115, 35, ILI9341_BLACK);   //clears MPH Value
  
  
 
  
                                       //239 as example
float w = frequency2 / 100;              //2
float x = (frequency2 / 10) - (10 * w);  //3
float y = frequency2 / 10;               //23
float z = frequency2 - (y * 10);         //9
  
  //math first
  //math below gets rid of stupid rounding issues
  
//  float w = 10 * frequency2;    //move decimal place over 1
 // int x = w;                    //remove everything right of decimal
 // float y = x;                  //convert back to float, this step is needed since dividing an int by 10 rounds the number......
 // float z = y / 10;             //back to almost original value, leaves us with 1 value to right of decimal, any more then that and it would round
  //blank old text
//  tft.setTextColor(ILI9341_BLACK); tft.setTextSize(5);
//  tft.setCursor(195, 110);
//  tft.print(frequency2old, 1);  
  //new text
  
  tft.setTextSize(5);
  if(w != wold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(195, 110);
  tft.print(wold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(195, 110);  
  tft.print(w, 0);
  wold = w; 
  }

  if(x != xold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(225, 110);
  tft.print(xold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(225, 110);  
  tft.print(x, 0);
  xold = x;
  }

////decimal is printed once with rest of boxes
  if(z != zold){ 
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(285, 110);
  tft.print(zold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(285, 110);  
  tft.print(z, 0);
  zold = z;
  }

  
  frequency2old = frequency2;
  
  
  //tft.print((float)frequency2, 1);  // this rounds 25.98765 to 26.0  :(

  
  
  if(drivestateold != drivestate){   //only change is drivestate changes
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(2);
  tft.setCursor(170, 12);
  tft.println("DriveStatus");
  drivestateold = 1;
  }
  
  executiontime = elapsedtesttime;

}

Creating a library to only update digits when needed would be a lifesaver but I have never had any luck creating libraries that actually worked....

EDIT...

Reworked the bar code to remove the nausea inducing flicker from the battery bar.

Code:
/***************************************************
Adafruit graphicstest used as a base.
 ****************************************************/


#include "SPI.h"
#include "ILI9341_t3.h"

// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 8
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST);

#define backlight 6

//Test perams
int frequency2 = 259;
int frequency2old = 0;
float BatterySOC = 0.85;     // percentage of charge (assumed)
float BatterySOCold = 0.85;
volatile int32_t executiontime = 0;
byte boxset = 0;
byte drivestate = 1;
byte drivestateold = 0;
byte  Redfull = 0;
byte  Yellowfull = 0;
byte  Greenfull = 0;
  int a = 0;
  int b = 0;
float wold = 0;
float xold = 0;
float yold = 0;
float zold = 0;
int i = 0;

void setup() {
  pinMode(backlight, OUTPUT);

  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(3);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(3);
  tft.println("Initializing.....");
  delay(1000);
  tft.fillScreen(ILI9341_BLACK);
  tft.fillRect(5, 5, 20, 230, ILI9341_WHITE);     //blank battery bar once
  mainScreen();
  analogWrite(backlight, 192);    //50% backlight and 488Hz pwm
 
}


void loop() {

    refreshtime();
    
    mainScreen();
    

 //   delay(50);
 // frequency2++;
    i++;
    if(i == 10){
    if(frequency2 >= 990){
      a = 1;
    }
    if(frequency2 <= 0){
     a = 0; 
    }
    if(a == 0){
      frequency2 = frequency2 + 1;   
    }
    else
        {
             frequency2 = frequency2 - 1; 
        }
        i = 0;
    }
    
    if(BatterySOC >= 0.99){
      b = 1;
    }
    if(BatterySOC <= 0){
     b = 0; 
    }
    if(b == 0){
      BatterySOC = BatterySOC + 0.0001;   
    }
    else
        {
             BatterySOC = BatterySOC - 0.0001; 
        }  
  
  
}

unsigned long refreshtime(){

  
  tft.fillRect(35, 110, 75, 15, ILI9341_BLACK);
  tft.setCursor(35, 110);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.print(executiontime);
  tft.setCursor(35, 130);
  tft.print("Microseconds");

}


unsigned long mainScreen() {
  elapsedMicros elapsedtesttime;
  
  if(boxset < 1){                                 //removes redraw for no reason
  tft.drawRect(145, 5, 170, 30, ILI9341_GREEN);   //drive status box 
  tft.drawRect(35, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(105, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(175, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(245, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(5, 5, 20, 230, ILI9341_WHITE);     //battery bar outline
  
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.setCursor(50, 22);
  tft.print("Charge");
  tft.setTextColor(ILI9341_BLUE);    tft.setTextSize(4);  
  tft.setCursor(240, 150);  
  tft.println("MPH"); 
  tft.setTextColor(ILI9341_YELLOW);   tft.setTextSize(5);
  tft.setCursor(255, 110);   
  tft.print("."); 
 
  boxset = 1;
}  
  
  
  
  
  if(BatterySOCold > BatterySOC){
    float w = (1 - BatterySOC) * 228; 
  tft.fillRect(6, 6, 18, w, ILI9341_WHITE);     //blank battery bar
  Redfull = 0;
  Yellowfull = 0;
  }
 
 
  if(BatterySOC <= 0.3333 && BatterySOC != 0){      //red battery bar only
    float x;
    float y;
    x = BatterySOC / 0.3333;
    y = x * 76;                  //rectangle size
    x = 235 - y;                 //rectangle starting position
  tft.fillRect(6, x, 18, y, ILI9341_RED);
  Redfull = 0;
  Yellowfull = 0;
  }
  
  if(BatterySOC <= 0.6666 && BatterySOC > 0.3333){      //red and yellow battery bars only
    float x;
    float y;
    x = BatterySOC - 0.3333;    //remove red region
    x = x / 0.3333;
    y = x * 76;                 //rectangle size
    x = 159 - y;                //rectangle starting postion
    if(Redfull == 0){
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  Redfull = 1;
    }
  tft.fillRect(6, x, 18, y, ILI9341_YELLOW);
  Yellowfull = 0;
  }
  
  if(BatterySOC <= 1 && BatterySOC > 0.6666){      //red, yellow and green battery bars only
    float x;
    float y;
    x = BatterySOC - 0.6666;    //remove red and yellow region
    x = x / 0.3333;
    y = x * 76;                 //rectangle size
    x = 83 - y;                //rectangle starting postion
  if(Redfull == 0){
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  Redfull = 1;
  }
  if(Yellowfull == 0){
  tft.fillRect(6, 82, 18, 76, ILI9341_YELLOW);
  Yellowfull = 1;
  }
  tft.fillRect(6, x, 18, y, ILI9341_GREEN);
  }
  
  
//  tft.fillRect(50, 5, 59, 14, ILI9341_BLACK);     //clears % value
  
  tft.setTextColor(ILI9341_BLACK); tft.setTextSize(2);
  tft.setCursor(50, 5);
  tft.print((float)BatterySOCold * 100,2);     tft.print("%");
  
  tft.setCursor(50, 5);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.print((float)BatterySOC * 100,2);    tft.print("%");
  BatterySOCold = BatterySOC;
 // tft.fillRect(195, 110, 115, 35, ILI9341_BLACK);   //clears MPH Value
  
  
 
  
                                       //239 as example
float w = frequency2 / 100;              //2
float x = (frequency2 / 10) - (10 * w);  //3
float y = frequency2 / 10;               //23
float z = frequency2 - (y * 10);         //9
  
  //math first
  //math below gets rid of stupid rounding issues
  
//  float w = 10 * frequency2;    //move decimal place over 1
 // int x = w;                    //remove everything right of decimal
 // float y = x;                  //convert back to float, this step is needed since dividing an int by 10 rounds the number......
 // float z = y / 10;             //back to almost original value, leaves us with 1 value to right of decimal, any more then that and it would round
  //blank old text
//  tft.setTextColor(ILI9341_BLACK); tft.setTextSize(5);
//  tft.setCursor(195, 110);
//  tft.print(frequency2old, 1);  
  //new text
  
  tft.setTextSize(5);
  if(w != wold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(195, 110);
  tft.print(wold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(195, 110);  
  tft.print(w, 0);
  wold = w; 
  }

  if(x != xold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(225, 110);
  tft.print(xold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(225, 110);  
  tft.print(x, 0);
  xold = x;
  }

////decimal is printed once with rest of boxes
  if(z != zold){ 
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(285, 110);
  tft.print(zold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(285, 110);  
  tft.print(z, 0);
  zold = z;
  }

  
  frequency2old = frequency2;
  
  
  //tft.print((float)frequency2, 1);  // this rounds 25.98765 to 26.0  :(

  
  
  if(drivestateold != drivestate){   //only change is drivestate changes
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(2);
  tft.setCursor(170, 12);
  tft.println("DriveStatus");
  drivestateold = 1;
  }
  
  executiontime = elapsedtesttime;

}


EDIT 2
Think I have bad C math skillz :/
 
Last edited:
My PJRC TFT backlight seems take want 18mA - and that is through 140 ohms - not the indicated 100, so I won't be powering mine from a Teensy output. Since yours is PWM powered I suppose that is why your display light gets odd when SPI gets HYPER on updates and the PWN loses its shape (if that is what I saw on your O-scope)?

Looked at your code a bit more - battery dropping takes more cycles - when battery dropping you don't need to do the Redfull = 0; or Yellowfull = 0; as the white rect moving down will take away whatever is there just fine it seems. You could get math practice only doing the white rect between the old and new battery region - the upper part will already be white - the fuller that white is the slower the updates as the battery drops. You might consider skipping the battery bar update unless it changes enough to 'see' at 3 pixels per % then +/- 1% from last draw might be cool - not like the driver is staring at it and as the pedal moves the battery will flutter with it right? Maybe pre-calc the height diff on dropping [ old-new ] at the top where you have it and then pick which R/Y/G bar should draw the whitespace with a flag and then when doing that 'last bar' draw 'the small diff' of white just over where you calculate it stopping (i.e. already have the colored bar math at hand).
 
My PJRC TFT backlight seems take want 18mA - and that is through 140 ohms - not the indicated 100, so I won't be powering mine from a Teensy output. Since yours is PWM powered I suppose that is why your display light gets odd when SPI gets HYPER on updates and the PWN loses its shape (if that is what I saw on your O-scope)?

Looked at your code a bit more - battery dropping takes more cycles - when battery dropping you don't need to do the Redfull = 0; or Yellowfull = 0; as the white rect moving down will take away whatever is there just fine it seems. You could get math practice only doing the white rect between the old and new battery region - the upper part will already be white - the fuller that white is the slower the updates as the battery drops. You might consider skipping the battery bar update unless it changes enough to 'see' at 3 pixels per % then +/- 1% from last draw might be cool - not like the driver is staring at it and as the pedal moves the battery will flutter with it right? Maybe pre-calc the height diff on dropping [ old-new ] at the top where you have it and then pick which R/Y/G bar should draw the whitespace with a flag and then when doing that 'last bar' draw 'the small diff' of white just over where you calculate it stopping (i.e. already have the colored bar math at hand).

Im thinking about hunting threw the stack or IC's I have and seeing if I have any decent buffers, I want to find out if the Teensy is creating the noise or if the LCD is doing it.

I played with the bar whiting last night and set it to only fill the area that is not being redrawn by the colors, I am actually now seeing times in the 100us range. I redid some of my poor math on the numbers and made the same change to the charge numbers. Times im seeing go from around 100us to 3ms depending on what is being redrawn. I may rewrite the bar's to use lines instead of rectangles but I want to switch gears and start testing Serial between my 2 Teensy 3.1's. And looking at all the values I may want to display I want to create a Function to convert ints to individual values for display.

Latest code update.

Code:
/***************************************************
Adafruit graphicstest used as a base.
 ****************************************************/


#include "SPI.h"
#include "ILI9341_t3.h"

// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 8
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST);

#define backlight 6

//Test perams
int frequency2 = 259;
float BatterySOC = 8500;     // percentage of charge (assumed)
float BatterySOCold = 0;
volatile int32_t executiontime = 0;
byte boxset = 0;
byte drivestate = 1;
byte drivestateold = 0;
byte  Redfull = 0;
byte  Yellowfull = 0;
byte  Greenfull = 0;
  int a = 0;
  int b = 0;
float xold = 0;
float yold = 0;
float zold = 0;
float aold;
float bold;
float cold;
float dold;
int h = 0;
int i = 0;

void setup() {
  pinMode(backlight, OUTPUT);

  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(3);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(3);
  tft.println("Initializing.....");
  delay(1000);
  tft.fillScreen(ILI9341_BLACK);
  tft.fillRect(5, 5, 20, 230, ILI9341_WHITE);     //blank battery bar once
  mainScreen();
  analogWrite(backlight, 192);    //50% backlight and 488Hz pwm
 
}


void loop() {

    refreshtime();
    
    mainScreen();
    

 //   delay(50);
 // frequency2++;
    h++;
    i++;
    if(h == 30){
    if(frequency2 >= 999){
      a = 1;
    }
    if(frequency2 <= 0){
     a = 0; 
    }
    if(a == 0){
      frequency2 = frequency2 + 1;   
    }
    else
        {
             frequency2 = frequency2 - 1; 
        }
    h = 0;
    }
    
    if(i == 2){
    if(BatterySOC >= 9999){
      b = 1;
    }
    if(BatterySOC <= 0){
     b = 0; 
    }
    if(b == 0){
      BatterySOC = BatterySOC + 1;   
    }
    else
        {
             BatterySOC = BatterySOC - 1; 
        }  
  i = 0;
    }
}

unsigned long refreshtime(){

  
  tft.fillRect(35, 110, 75, 15, ILI9341_BLACK);
  tft.setCursor(35, 110);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.print(executiontime);
  tft.setCursor(35, 130);
  tft.print("Microseconds");

}


unsigned long mainScreen() {
  elapsedMicros elapsedtesttime;
  
  if(boxset < 1){                                 //removes redraw for no reason
  tft.drawRect(145, 5, 170, 30, ILI9341_GREEN);   //drive status box 
  tft.drawRect(35, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(105, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(175, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(245, 185, 65, 50, ILI9341_WHITE);
  tft.drawRect(5, 5, 20, 230, ILI9341_WHITE);     //battery bar outline
 
  tft.setTextColor(ILI9341_WHITE);   tft.setTextSize(2);
  tft.setCursor(74, 5);   
  tft.print(".");
  tft.setCursor(110, 5);
  tft.print("%");
  
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
  tft.setCursor(50, 22);
  tft.print("Charge");
  tft.setTextColor(ILI9341_BLUE);    tft.setTextSize(4);  
  tft.setCursor(240, 150);  
  tft.println("MPH"); 
  tft.setTextColor(ILI9341_YELLOW);   tft.setTextSize(5);
  tft.setCursor(255, 110);   
  tft.print("."); 
 
  boxset = 1;
}  
  
  
  
  
  if(BatterySOCold > BatterySOC){
    float w = (1 - (BatterySOC / 10000)) * 228; 
  tft.fillRect(6, 6, 18, w, ILI9341_WHITE);     //blank battery bar
  Redfull = 0;
  Yellowfull = 0;
  }
 
 
 
 
 
  if(BatterySOC <= 3333 && BatterySOC != 0){      //red battery bar only
    float x;
    float y;
    x = BatterySOC / 3333;
    y = x * 76;                  //rectangle size
    x = 235 - y;                 //rectangle starting position
  tft.fillRect(6, x, 18, y, ILI9341_RED);
  Redfull = 0;
  Yellowfull = 0;
  }
  
  if(BatterySOC <= 6666 && BatterySOC > 3333){      //red and yellow battery bars only
    float x;
    float y;
    x = BatterySOC - 3333;    //remove red region
    x = x / 3333;
    y = x * 76;                 //rectangle size
    x = 159 - y;                //rectangle starting postion
    if(Redfull == 0){
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  Redfull = 1;
    }
  tft.fillRect(6, x, 18, y, ILI9341_YELLOW);
  Yellowfull = 0;
  }
  
  if(BatterySOC <= 10000 && BatterySOC > 6666){      //red, yellow and green battery bars only
    float x;
    float y;
    x = BatterySOC - 6666;    //remove red and yellow region
    x = x / 3333;
    y = x * 76;                 //rectangle size
    x = 83 - y;                //rectangle starting postion
  if(Redfull == 0){
  tft.fillRect(6, 158, 18, 76, ILI9341_RED);
  Redfull = 1;
  }
  if(Yellowfull == 0){
  tft.fillRect(6, 82, 18, 76, ILI9341_YELLOW);
  Yellowfull = 1;
  }
  tft.fillRect(6, x, 18, y, ILI9341_GREEN);
  }
  
  
//  tft.fillRect(50, 5, 59, 14, ILI9341_BLACK);     //clears % value
  
 // tft.setTextColor(ILI9341_BLACK); tft.setTextSize(2);
 // tft.setCursor(50, 5);
 // tft.print((float)BatterySOCold * 100,2);     tft.print("%");
  
                                                                //1234 as example
  float a = BatterySOC / 1000;                                  //1.234
  float b = BatterySOC / 100;                                   //12.34  
  float c = BatterySOC / 10;                                    //123.4
  int aa = a;                                                   //1
  int bb = b;                                                   //12
  int cc = c;                                                   //123
  float aaa = aa;                                                //1
  float bbb = bb;                                                //12
  float ccc = cc;                                                //123
  a = aaa;                                                       //1
  b = bbb - (aaa * 10);                                          //2
  c = ccc - (bbb * 10);                                          //3
  float d = BatterySOC - (ccc * 10);                             //4
  
  

  tft.setTextSize(2);
  if(a != aold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(50, 5);
  tft.print(aold, 0);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(50, 5);  
  tft.print(a, 0);
  aold = a; 
  }

  if(b != bold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(62, 5);
  tft.print(bold, 0);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(62, 5);  
  tft.print(b, 0);
  bold = b;
  }

////decimal is printed once with rest of boxes
  if(c != cold){ 
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(86, 5);
  tft.print(cold, 0);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(86, 5);  
  tft.print(c, 0);
  cold = c;
  }

  if(d != dold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(98, 5);
  tft.print(dold, 0);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(98, 5);  
  tft.print(d, 0);
  dold = d; 
  }

  BatterySOCold = BatterySOC;
  
  
  
 // tft.setCursor(50, 5);
 // tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(2);
 // tft.print((float)BatterySOC * 100,2);    tft.print("%");
 // tft.fillRect(195, 110, 115, 35, ILI9341_BLACK);   //clears MPH Value
  
  
 
  
                                                 //239 as example
float x = frequency2 / 100;                      //2.39
float y = (frequency2 / 10);                     //23.9
int xx = x;                                      //2
int yy = y;                                      //23
float xxx = xx;                                  //2
float yyy = yy;                                  //23
x = xxx;                                         //2
y = yyy - (x * 10);                              //3
float z = frequency2 - (yyy * 10);               //9

  
  
  tft.setTextSize(5);
  if(x != xold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(195, 110);
  tft.print(xold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(195, 110);  
  tft.print(x, 0);
  xold = x; 
  }

  if(y != yold){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(225, 110);
  tft.print(yold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(225, 110);  
  tft.print(y, 0);
  yold = y;
  }

////decimal is printed once with rest of boxes
  if(z != zold){ 
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(285, 110);
  tft.print(zold, 0);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(285, 110);  
  tft.print(z, 0);
  zold = z;
  }


  
  
  //tft.print((float)frequency2, 1);  // this rounds 25.98765 to 26.0  :(

  
  
  if(drivestateold != drivestate){   //only change is drivestate changes
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(2);
  tft.setCursor(170, 12);
  tft.println("DriveStatus");
  drivestateold = 1;
  }
  
  executiontime = elapsedtesttime;

}
 
Get one of Paul's $8 TFT's - it may show differently, maybe put fixed volts on your backlight not PWM. I'm assuming the 'visual' affects could as likely be noise/TFT related as 3.1.

I'm not a good thread judge - but you might start your own for this project - I'll want to see the 'offtopic' serial I/O example too - like I did the screen I/O cleanup.
 
Get one of Paul's $8 TFT's - it may show differently, maybe put fixed volts on your backlight not PWM. I'm assuming the 'visual' affects could as likely be noise/TFT related as 3.1.

I'm not a good thread judge - but you might start your own for this project - I'll want to see the 'offtopic' serial I/O example too - like I did the screen I/O cleanup.

The Lite connection on the Adafruit tft is pulled high by a 1k resistor so if i remove the PWM wire it will just be at full brightness the whole time. I noticed the flicker even then. I could not find any timing info for Adafruit tft so I have no idea what the pixel refresh rate is for going from colors > black > colors.

Im hoping the serial IO wont cause any hair loose but so far there is very little in the way of updated information for using it. Most of what im seeing is years old and many of the posts are conflicting in its use, so im forced to pull pieces from various sources and hope it works to some degree so i can troubleshoot. I got a test sketch to pass(after an hour) without errors so when I get home I will give it a shot.
 
I saw the new serial thread, thanks.

I tracked Min Max execution time in loop (enabled Serial) - impressive improvements to get current data with less overhead, there are some aberrant cases though on the high side, usually when the battery doesn't change? The min is under 30 and the max sits near 4,000 for a while then hits peaks of 5865 - I didn't track average or how many times it hits over 5000.
View attachment Cart_Display.ino
 
I saw the new serial thread, thanks.

I tracked Min Max execution time in loop (enabled Serial) - impressive improvements to get current data with less overhead, there are some aberrant cases though on the high side, usually when the battery doesn't change? The min is under 30 and the max sits near 4,000 for a while then hits peaks of 5865 - I didn't track average or how many times it hits over 5000.
View attachment 3964

Ya I had a few oddities going on, I smashed a few bugs after I posted that and started playing with Serial1, beat myself to death for a few hours and got it going, then spent a few hours today rearranging the batterySOC breakdown and refresh; and played around with a chunk of code that runs off a few arrays to cut down on having to create large swaths of repeated code later on.


This is unfinished but im sure you can see where im going, BatterySOC will get replaced with another array I think, and the textcolor, starting cords, dot posstion and where each additional digit will be set with the digitarray. I thought about trying to create a function with this but I would have to read up on how to do it.
Code:
for (i = 0; i < 3; i++) {


                                                                //1234 as example
  digitarray[i][0] = (BatterySOC / 1000) % 10;                                  //1
  digitarray[i][1] = (BatterySOC / 100) % 10;                                   //2  
  digitarray[i][2] = (BatterySOC / 10) % 10;                                    //3
  digitarray[i][3] = BatterySOC  % 10;                                          //4
  
  

  tft.setTextSize(digitarray[i][8]);
  if(digitarray[i][0] != digitarray[i][4]){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(50, 5);
  tft.print(digitarray[i][4], DEC);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(50, 5);  
  tft.print(digitarray[i][0], DEC);
  digitarray[i][4] = digitarray[i][0]; 
  }

  if(digitarray[i][1] != digitarray[i][5]){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(62, 5);
  tft.print(digitarray[i][5], DEC);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(62, 5);  
  tft.print(digitarray[i][1], DEC);
  digitarray[i][5] = digitarray[i][1];
  }

////decimal is printed once with rest of boxes
  if(digitarray[i][2] != digitarray[i][6]){ 
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(86, 5);
  tft.print(digitarray[i][6], DEC);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(86, 5);  
  tft.print(digitarray[i][2], DEC);
  digitarray[i][6] = digitarray[i][2];
  }

  if(digitarray[i][3] != digitarray[i][7]){
  tft.setTextColor(ILI9341_BLACK);    
  tft.setCursor(98, 5);
  tft.print(digitarray[i][7], DEC);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(98, 5);  
  tft.print(digitarray[i][3], DEC);
  digitarray[i][7] = digitarray[i][3]; 
  }

Here is the working pre array version, took me a few hours to get this going. The charge % is wrong but I started moving things around for my next step which is sending the 6x 12bit ADC values from one T3.1 to the second one running the Screen and display the 0-4095 values.
View attachment Ecart_screen_003_inttesting.ino
 
Last edited:
Somehow there is a problem togeter with the SD-Card, is this a known issue ?
It only works if i comment the following lines out (in ILI9341_t3.cpp):
Code:
    // verify SPI pins are valid;
/*
    if ((_mosi == 11 || _mosi == 7) && (_miso == 12 || _miso == 8) && (_sclk == 13 || _sclk == 14)) {
        SPI.setMOSI(_mosi);
        SPI.setMISO(_miso);
        SPI.setSCK(_sclk);
	} else
        return; // not valid pins...
	
	SPI.begin();
*/



Edit: Sorry, was my fault..
better call begin with all pins defined :) ILI9341_t3(TFT_CS, TFT_DC,255,7,14,12);
 
Last edited:
Hello,

I have a question about a project using a Teensy 3.1, ILI9341 displays and the associated library. I hope this is the right place to ask.

So, I was thinking about using a teensy to drive 5 ILI9341 screens. I initially thought it would be possible, since during my research on SPI, I had only read about SCK, RST, MOSI, MISO and CS (and teensy3.1 has, as far as I understand, 5 alternative CS pins). However, I now realise that I need a D/C line, and it seems to be shared with the CS pins.
My question is : is there a simple way to use these 5 displays on a single teensy3.1 ? Did I miss something ?
Or, would it be feasible to "emulate" an extra CS line with a regular digital output (setting it high or low manually, depending on which screen I want to send data to) ?

Thank you in advance
 
It may not be an issue if you aren't updating the screens at a high speed, also i'm sure someone here with more knowledge then me can say weather or not you can drive the D/C lines of all the screens from one pin but have different CS pins. I don't know enough about the D/C pin to say for sure, but its possible it will be ignored when the CS pin is not being pulled.

What kind of project did you have in mind?

Edit....

Just read this in the ILI9341 datasheet from Adafruits website, not sure what reason they used the 4-line instead of 3-line, but looks like we use the 4-line Serial with the library.

ILI9341 supplies 3-lines/ 9-bit and 4-line/8-bit bi-directional serial interfaces for communication between host
and ILI9341. The 3-line serial mode consists of the chip enable input (CSX), the serial clock input (SCL) and
serial data Input/Output (SDA or SDI/SDO). The 4-line serial mode consists of the Data/Command selection
input (D/CX), chip enable input (CSX), the serial clock input (SCL) and serial data Input/Output (SDA or
SDI/SDO) for data transmission.
 
Last edited:
So, I was thinking about using a teensy to drive 5 ILI9341 screens. I initially thought it would be possible, since during my research on SPI, I had only read about SCK, RST, MOSI, MISO and CS (and teensy3.1 has, as far as I understand, 5 alternative CS pins). However, I now realise that I need a D/C line, and it seems to be shared with the CS pins.

I've never tried more than 1 display. In theory, it ought to work, but this is untested.

In theory, up to 4 displays might be able to work. But a 5th is out of the question, at least using ILI9341. The CS and DC signals must be connected to the 5 special chip select pins (no, there isn't any way to use a regular pin and keep the incredible speed of this library). Maybe 4 displays could work with sharing the same pin for DC.

Another possible issue is the length of wire needed to connect 4 displays. The signals are very fast, so driving such long wires might be a challenge. You might need to add 50 to 100 ohm series resistors near the Teensy. If the wires are long, you might need to add buffer chips, so the Teensy drives a few buffer chips located close, and those transmit a separate copy of each signal to the the displays.

Please post some followups here if you try this. If you run into a software issue, I'll try to help.

Just know that 4 is the theoretical limit with the ILI9341 library.
 
Back
Top