3.5 inch RPi LCD with Teensy 4.0 problem

Status
Not open for further replies.

guzu

Well-known member
Hello.
I want to use a 3.5 inch RPi LCD + Touchscreen with the Teensy 4.0. The display can be seen here. I know the page is not in English, but I could not find something else. At least, you can see how it looks like.

I made a small hardware modification to the display in order to make it work with 3.3V instead of the 5V supplied by the Raspberry Pi.
You can see the modification in the image bellow (I have to clean the flux from the black PCB in which the display is soldered). I just removed the LDO and bridged the IN and OUT traces. Now the display turns on.
WhatsApp Image 2020-10-08 at 20.35.32.jpg

I have connected it to the Teensy 4.0 like this:
Teensy conections.jpg
And the 3.3V and GND of course.

I used this image for determining the pins:
RPi 3.5inch Pins.jpg

I used the graphics test sketch from the Examples in the Arduino IDE (Examples > ILI9341_t3 > graphicstest)
Here is the code:
Code:
/***************************************************
  This is our GFX example for the Adafruit ILI9341 Breakout and Shield
  ----> http://www.adafruit.com/products/1651

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/


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

// For the Adafruit shield, these are the default.
#define TFT_DC  27
#define TFT_CS 26

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

void setup() {
  tft.begin();
// Note: you can now set the SPI speed to any value
// the default value is 30Mhz, but most ILI9341 displays
// can handle at least 60Mhz and as much as 100Mhz
//  tft.setClock(60000000);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println("Waiting for Arduino Serial Monitor...");

  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("ILI9341 Test!"); 

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); 
  
  Serial.println(F("Benchmark                Time (microseconds)"));

  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(200);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(600);

  Serial.print(F("Proportional Text        "));
  Serial.println(testProportionalText());
  delay(600);

  Serial.print(F("Lines                    "));
  Serial.println(testLines(ILI9341_CYAN));
  delay(200);

  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
  delay(200);

  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(ILI9341_GREEN));
  delay(200);

  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
  delay(200);

  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, ILI9341_MAGENTA));

  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, ILI9341_WHITE));
  delay(200);

  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(200);

  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(200);

  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(200);

  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(200);

  Serial.println(F("Done!"));

}


void loop(void) {
  for(uint8_t rotation=0; rotation<4; rotation++) {
    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}

unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  tft.fillScreen(ILI9341_RED);
  tft.fillScreen(ILI9341_GREEN);
  tft.fillScreen(ILI9341_BLUE);
  tft.fillScreen(ILI9341_BLACK);
  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testProportionalText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setFont(Arial_10);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setFont(Arial_16);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setFont(Arial_24);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setFont(Arial_40);
  tft.println("Groop");
  tft.setFont(Arial_16);
  tft.println("I implore thee,");
  tft.setFont(Arial_10);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  tft.setFontAdafruit();
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(ILI9341_BLACK);

  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  tft.fillScreen(ILI9341_BLACK);

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(ILI9341_BLACK);

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(ILI9341_BLACK);

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height()) - 1;
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(0, 0, i));
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i, i));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i, i, 0));
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  w     = min(tft.width(), tft.height()) - 1;
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()) - 1; i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
  }

  return micros() - start;
}

I also used this code with a
Code:
# define TFT_RST 30
...
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST);
The problem is that the display is not working. It is just a white screen. I tried other examples too but nothing made the screen display something.
When I run the above code the Serial monitor shows this:
Oled_CS.jpg

The touchscreen is working. I tested it with the XPT2046_Touchscreen example code in the Arduino IDE examples folder (the one that comes with Teensyduino) and it shows the X and Y coordinates of the touch and the pressure.
If instead of the #define TFT_CS 26 i use #define TFT_CS 2 (the CS pin for the touchscreen) the Serial Monitor shows this:
Touch_CS.jpg

Am I doing something wrong? What could be the problem?

Thank you very much in advance for your time.
 
I haven't tried this particular model screen, but I did have success with a different RPi SPI screen, the 125Mhz SPI model C. For that model, it basically has a SPI interface to the MCU but uses the 16 bit parallel interface to communicate with the screen, so it is probably just using a shift register to directly convert the SPI data to parallel data. It's been a few weeks and I cleaned away my code sadly, but I recall basically just tweaking the ILI9341_t3 libraries. In the case of my screen, it blindly shifts the SPI data to the 16 bit parallel interface to the screen, so it requires 16 bit SPI data too. In ILI9341_t3.h, I changed LPSPI_TCR_FRAMESZ(7) to LPSPI_TCR_FRAMESZ(15) in writecommand_cont, writecommand_last, writedata8_cont and writedata8_last, effectively sending the 8 bit data as 16 bit data, and I think that worked, or at least took me from white screen to flickering updates. I probably modified the init commands too, from the ILI9341 to the ILI9486 commands in the "stock" examples you can find out there. Hope this pointer helps a little.
 
The latest "high speed SPI" RPi screens are intriguing. The WaveShare Model C uses an ILI9486 controller, I believe. I bought one thinking it would be a ton of work to get running via the Teensy, but it turned out to be a cinch with the tweaks above to the wonderful ILI9341_t3 library, the gift that keeps on giving :) They clearly refined the chipset and processing from the model A as the circuitry on the back is quite different and very little effort was needed to modify "regular" Teensy SPI driver code to work with it. Anyway, the upshot was, on T4.1 @ 600Mhz, I went from a respectable 51ms for a fullscreen 480x320x16bpp refresh on a BuyDisplay SPI ILI9488 @ 80Mhz, to 26ms on the WaveShare Model C, pushing the SPI bus to 119Mhz. The extra bus speed in conjunction with a 2 byte data transfer for 16bpp (vs 3 byte on the ILI9488) effectively doubled the transfer speed.

I have, though, now moved on to using a parallel interface, as the same BuyDisplay ILI9488 TFT configured for 8 bit parallel takes a hair over 6.5ms for the same 480x320x16bpp refresh, and I had exactly 9 edge pins to spare on my project so with some juggling (thanks Paul for the wonderful flexibility of alternate pins), I was able to use pins that map to 8 consecutive bits on GPIO6, for blazing fast update speed. Additionally, I have managed to achieve 24fps video streamed from the T4.1 SD card @ a whopping 800x480x16bpp on a 4" BuyDisplay TFT with the NT35510 controller in 8 bit parallel mode, and just failed to stream 24fps 800x480x24bpp, although the gating factor was the SD card read of that much data at ~37ms per frame. I think I will live in this parallel world now, for a bit :)
 
The latest "high speed SPI" RPi screens are intriguing. The WaveShare Model C uses an ILI9486 controller, I believe. I bought one thinking it would be a ton of work to get running via the Teensy, but it turned out to be a cinch with the tweaks above to the wonderful ILI9341_t3 library, the gift that keeps on giving :) They clearly refined the chipset and processing from the model A as the circuitry on the back is quite different and very little effort was needed to modify "regular" Teensy SPI driver code to work with it. Anyway, the upshot was, on T4.1 @ 600Mhz, I went from a respectable 51ms for a fullscreen 480x320x16bpp refresh on a BuyDisplay SPI ILI9488 @ 80Mhz, to 26ms on the WaveShare Model C, pushing the SPI bus to 119Mhz. The extra bus speed in conjunction with a 2 byte data transfer for 16bpp (vs 3 byte on the ILI9488) effectively doubled the transfer speed.

Never mind I only now saw the code cleaning away part....

Hi beermat if possible share your Teensy library for the Waveshare 125 MHz SPI type C - I have a few of these...
 
A while ago @KurtE and I and others worked on getting a RPI Kedei display working with the T3x-T4. You might want to give the library we developed for that a try:
https://github.com/KurtE/KeDeiRPI35_t3. Its based on the ILI9341 library.

Thank you @mjs513
I have downloaded your library and used the graphicstestKeDei sketch. However the display is still white.
Here is the code I used:
Code:
/***************************************************
  This is our GFX example for the Adafruit ILI9488 Breakout and Shield
  ----> http://www.adafruit.com/products/1651

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/


#include "SPI.h"
#include "KeDeiRPI35_t3.h"
//#define TEENSY64

// For the Adafruit shield, these are the default.
#if defined(__MK66FX1M0__) && !defined(TEENSY64)
#define TOUCH_CS 2
#define TFT_CS 26
KEDEIRPI35_t3 tft = KEDEIRPI35_t3(&SPI, TFT_CS, TOUCH_CS);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
// On Teensy 4 beta with Paul's breakout out:
// Using pins (MOSI, MISO, SCK which are labeled on Audio board breakout location
// which are not in the Normal processor positions
// Also DC=10(CS), CS=9(BCLK) and RST 23(MCLK)
#define TOUCH_CS 2
#define TFT_CS 26
KEDEIRPI35_t3 tft = KEDEIRPI35_t3(&SPI, TFT_CS, TOUCH_CS);
#elif defined(TEENSY64)
#define TFT_DC 27
#define TFT_CS 26
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
KEDEIRPI35_t3 tft = KEDEIRPI35_t3(&SPI, TFT_CS, TOUCH_CS, TFT_MOSI, TFT_SCK, TFT_MISO);
#else
#error "This example App will only work with Teensy 3.6 or Teensy 4."
#endif
void setup() {
  tft.begin();
  tft.fillScreen(KEDEIRPI35_BLACK);
  tft.setTextColor(KEDEIRPI35_YELLOW);
  tft.setTextSize(2);
  tft.println("Waiting for Arduino Serial Monitor...");
  tft.setOrigin(0,0);
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("ILI9488 Test!"); 

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(KEDEIRPI35_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(KEDEIRPI35_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(KEDEIRPI35_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(KEDEIRPI35_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(KEDEIRPI35_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); 
  
  Serial.println(F("Benchmark                Time (microseconds)"));

  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(200);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(600);

  Serial.print(F("Lines                    "));
  Serial.println(testLines(KEDEIRPI35_CYAN));
  delay(500);

  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(KEDEIRPI35_RED, KEDEIRPI35_BLUE));
  delay(500);

  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(KEDEIRPI35_GREEN));
  delay(500);

  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(KEDEIRPI35_YELLOW, KEDEIRPI35_MAGENTA));
  delay(500);

  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, KEDEIRPI35_MAGENTA));

  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, KEDEIRPI35_WHITE));
  delay(200);

  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(200);

  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(200);

  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(200);

  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(200);

  Serial.println(F("Done!"));

}


void loop(void) {
  for(uint8_t rotation=0; rotation<4; rotation++) {
    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}

unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(KEDEIRPI35_BLACK);
  tft.fillScreen(KEDEIRPI35_RED);
  tft.fillScreen(KEDEIRPI35_GREEN);
  tft.fillScreen(KEDEIRPI35_BLUE);
  tft.fillScreen(KEDEIRPI35_BLACK);
  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(KEDEIRPI35_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(KEDEIRPI35_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(KEDEIRPI35_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(KEDEIRPI35_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(KEDEIRPI35_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(KEDEIRPI35_BLACK);

  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  tft.fillScreen(KEDEIRPI35_BLACK);

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(KEDEIRPI35_BLACK);

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(KEDEIRPI35_BLACK);

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(KEDEIRPI35_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(KEDEIRPI35_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(KEDEIRPI35_BLACK);
  n = min(tft.width(), tft.height()) - 1;
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(KEDEIRPI35_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(KEDEIRPI35_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(0, 0, i));
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(KEDEIRPI35_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i, i));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i, i, 0));
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(KEDEIRPI35_BLACK);
  w     = min(tft.width(), tft.height()) - 1;
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(KEDEIRPI35_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()) - 1; i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
  }

  return micros() - start;
}

And here is the serial monitor printout:
Code:
ILI9488 Test!

Display Power Mode: 0xFF

MADCTL Mode: 0xFF

Pixel Format: 0xFF

Image Format: 0xFF

Self Diagnostic: 0xFF

Benchmark                Time (microseconds)

Screen fill              1003641

Text                     31099

Lines                    456853

Horiz/Vert Lines         82701

Rectangles (outline)     46945

Rectangles (filled)      2424419

Circles (filled)         374118

Circles (outline)        377290

Triangles (outline)      94516

Triangles (filled)       774477

Rounded rects (outline)  136058

Rounded rects (filled)   2651014

Done!

Shouldn't there be some #defines for the DC and RST pins of the display?
 
I haven't tried this particular model screen, but I did have success with a different RPi SPI screen, the 125Mhz SPI model C. For that model, it basically has a SPI interface to the MCU but uses the 16 bit parallel interface to communicate with the screen, so it is probably just using a shift register to directly convert the SPI data to parallel data. It's been a few weeks and I cleaned away my code sadly, but I recall basically just tweaking the ILI9341_t3 libraries. In the case of my screen, it blindly shifts the SPI data to the 16 bit parallel interface to the screen, so it requires 16 bit SPI data too. In ILI9341_t3.h, I changed LPSPI_TCR_FRAMESZ(7) to LPSPI_TCR_FRAMESZ(15) in writecommand_cont, writecommand_last, writedata8_cont and writedata8_last, effectively sending the 8 bit data as 16 bit data, and I think that worked, or at least took me from white screen to flickering updates. I probably modified the init commands too, from the ILI9341 to the ILI9486 commands in the "stock" examples you can find out there. Hope this pointer helps a little.

Thank you for this information.
I have done this but the display is still white.
In ILI9341_t3.h, I changed LPSPI_TCR_FRAMESZ(7) to LPSPI_TCR_FRAMESZ(15) in writecommand_cont, writecommand_last, writedata8_cont and writedata8_last


I don't know what you meant by
modified the init commands too, from the ILI9341 to the ILI9486 commands in the "stock" examples

Where in the files could I find these commands?

Thank you.
 
After much searching, I think I have found the actual LCD used in my display. It is this one (the 42 pin version).
It says there that it uses the R61581 driver.

Is this a discrete driver? Or the ili9341 should work with this?
 
The ILI9341 is setup for ILI9341 and not for this device. This device is more likely usable with the ILI9488 driver (as at least it has the same resolution). The KeDei was another screwy RPI display.
Also there is another driver we have for that resolution.

I think there may be some support, but not sure...

Edit: You might look through the thread: https://forum.pjrc.com/threads/55735-ILI9488_t3-Support-for-the-ILI9488-on-T3-x-and-beyond

Also I think they have had a few different RPI versions out, so may need to see which one it is.
Do you have a link to the one you have?
 
Last edited:
Do you have a link to the one you have?
This is the one I bought. The silkscreen on the back is a little different, but the placement of the parts is exactly the same.

The ILI9341 is setup for ILI9341 and not for this device. This device is more likely usable with the ILI9488 driver (as at least it has the same resolution). The KeDei was another screwy RPI display.
Also there is another driver we have for that resolution.

I think there may be some support, but not sure...

Edit: You might look through the thread: https://forum.pjrc.com/threads/55735-ILI9488_t3-Support-for-the-ILI9488-on-T3-x-and-beyond

Also I think they have had a few different RPI versions out, so may need to see which one it is.
Do you have a link to the one you have?

Thank you KurtE. I made some progress with the library in the post.
Now the display turns on and something appears.
Se here:
WhatsApp Image 2020-10-09 at 21.33.08.jpg

And the image "moves" as the test unfolds. (The lines move as a pattern in sync with the data on the serial monitor.)

Is there anything else I could do to make it better? :)

Thanks.
 
You might out of curiosity try out the https://github.com/mjs513/HX8357_t3n
one... And see if it looks any better.

What I don't remember is things like with the ILI9486 if it is like the 9488 in that you can not do 16 bit color per pixel over SPI, so instead we are outputting 24 bits. The HX... does allow 16 bit per pixel... But again different manufacturer...

But if it does need the 24 bits (actually 18 bits) per pixel than my guess is that most things could probably be fixed by changing one or two places.

In particular the init commands...
Code:
static const uint8_t init_commands[] = {
	16, 0xE0, 0x00,0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F,
	16, 0XE1, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F,
	3, 0XC0, 0x17, 0x15,
	2, 0xC1, 0x41,       //Power Control 2
	4, 0xC5, 0x00, 0x12, 0x80,        //Power Control 3
	2, 0x36, 0x48,      //Memory Access
	2, 0x3A, 0x66,      // Interface Pixel Format, 18bit
	2, 0xB0, 0x80,      // Interface Mode Control
	2, 0xB1, 0xA0,      //Frame rate, 60hz
	2, 0xB4, 0x02,      //Display Inversion Control
	1, 0XB6, 			//Display Function Control  RGB/MCU Interface Control
	2, 0x02, 0x02,		//MCU
	2, 0xE9, 0x00,      // Set Image Functio,Disable 24 bit data
	5, 0xF7, 0xA9, 0x51, 0x2C, 0x82,          // Adjust Control

	//4, 0xE8, 0x85, 0x00, 0x78,
	//6, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
	//2, 0xF7, 0x20,
	//3, 0xEA, 0x00, 0x00,   //Power Control 1
	
	0
};
And the other possible change needed is in the rotation settings:
Code:
#define MADCTL_MY  0x80
#define MADCTL_MX  0x40
#define MADCTL_MV  0x20
#define MADCTL_ML  0x10
#define MADCTL_RGB 0x00
#define MADCTL_BGR 0x08
#define MADCTL_MH  0x04

void ILI9488_t3::setRotation(uint8_t m)
{
	rotation = m % 4; // can't be higher than 3
	beginSPITransaction();
	writecommand_cont(ILI9488_MADCTL);
	switch (rotation) {
	case 0:
		writedata8_last(MADCTL_MX | MADCTL_BGR);
		_width  = ILI9488_TFTWIDTH;
		_height = ILI9488_TFTHEIGHT;
		break;
	case 1:
		writedata8_last(MADCTL_MV | MADCTL_BGR);
		_width  = ILI9488_TFTHEIGHT;
		_height = ILI9488_TFTWIDTH;
		break;
	case 2:
		writedata8_last(MADCTL_MY | MADCTL_BGR);
		_width  = ILI9488_TFTWIDTH;
		_height = ILI9488_TFTHEIGHT;
		break;
	case 3:
		writedata8_last(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
		_width  = ILI9488_TFTHEIGHT;
		_height = ILI9488_TFTWIDTH;
		break;
	}
	endSPITransaction();
	setClipRect();
	setOrigin();
	
	cursor_x = 0;
	cursor_y = 0;
}

So you might be able to search the ILI9488 thread and see if anyone maybe has a fix for this... I will try see if I has something similar sitting around here.
 
Status
Not open for further replies.
Back
Top