Display 800x480 with SSD1963

Hello,

I'm facing an issue with TFT displays from buydisplay. I need to display a BMP file from an SD card.

The display with the RA8875 controller works fine with a Due, using the example code from the library.

https://www.buydisplay.com/serial-spi-arduino-8-inch-tft-lcd-touch-shield-ra8875-for-mega-due-uno

But the one with the SSD1963 doesn't work with the library examples. I tried several libraries and sketches found on the web (included UTFT_SdRaw), but never managed to get a picture on the screen. The SD card gets a connection confirmation, I get the Serial message showing that the picture has been loaded, but the screen remains white.

https://www.buydisplay.com/8-inch-arduino-touch-screen-shield-ssd1963-library-for-mega-due

Screen jumpers J1-J2-J3 are open, J4-J5-J6 are closed. Shield hardware SPI jumpers are closed.

I want to switch from the RA8875 to the SSD1963 as I read that the pictures from SD card can be displayed much faster with the SSD1963. If someone can advice me another way to go faster with the RA8875, that could also solve my issue.

Changing from MEGA to DUE to GIGA doesn't help. All work fine with the RA8875, none with the SSD1963.

Here are the 2 examples codes from the Buydisplay libraries : the 1st one works fine with RA8875, while the 2nd one doesn't work with SSD1963:

/***************************************************
// Web: http://www.buydisplay.com
EastRising Technology Co.,LTD
Examples for 800x480 TFT LCD Module with RA8875 Controller
Hardware SPI,4-Wire SPI Interface,5V Power Supply
Micro SD Card (TF Card) Demonstration
Don't foget to copy images from bmp folder to your TF card and insert to SD card slot of shield.
****************************************************/
#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>
#include <Wire.h>   
#include <SD.h>
#include "Adafruit_RA8875.h"
#define sd_cs 5                          // uding ethernet shield sd

// Library only supports hardware SPI at this time
//Arduino DUE,Arduino mega2560,Arduino UNO
#define RA8875_INT 4
#define RA8875_CS 10
#define RA8875_RESET 9

Adafruit_RA8875 tft = Adafruit_RA8875(RA8875_CS, RA8875_RESET);

void setup () {
  Serial.begin(9600);

  if (!SD.begin(sd_cs)) 
  {
    Serial.println("initialization failed!");
    return;
  }

  Serial.println("initialization done.");

  Serial.println("RA8875 start");

  /* Initialise the display using 'RA8875_480x272' or 'RA8875_800x480' */
  if (!tft.begin(RA8875_800x480)) {
    Serial.println("RA8875 Not Found!");
    while (1);
  }

  Serial.println("Found RA8875");

  tft.displayOn(true);
  tft.GPIOX(true);      // Enable TFT - display enable tied to GPIOX
  tft.PWM1config(true, RA8875_PWM_CLK_DIV1024); // PWM output for backlight
  tft.PWM1out(255);

  Serial.print("("); 
  Serial.print(tft.width());
  Serial.print(", "); 
  Serial.print(tft.height());
  Serial.println(")");
  tft.graphicsMode();                 // go back to graphics mode
  tft.fillScreen(RA8875_BLACK);
  tft.graphicsMode();     
   bmpDraw("BMP_1.bmp", 0, 0);
   delay(1000);
   bmpDraw("BMP_2.bmp", 0, 0); 
  delay(1000);
   bmpDraw("BMP_3.bmp", 0, 0); 
  delay(1000);
   bmpDraw("BMP_4.bmp", 0, 0);    
    delay(1000);
   bmpDraw("BMP_5.bmp", 0, 0);   
     delay(1000);
   bmpDraw("BMP_6.bmp", 0, 0); 
    delay(1000);
   bmpDraw("BMP_7.bmp", 0, 0);   
     delay(1000);
   bmpDraw("BMP_8.bmp", 0, 0);  
     delay(1000);
   bmpDraw("BMP_9.bmp", 0, 0);  
     delay(1000);
   bmpDraw("BMP_10.bmp", 0, 0);  
}

void loop()
{
}    

// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates.  It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel).  Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster.  20 pixels seems a
// good balance.

#define BUFFPIXEL 20

void bmpDraw(char *filename, int x, int y) {
  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
  uint16_t lcdbuffer[BUFFPIXEL];  // pixel out buffer (16-bit per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();
  uint8_t  lcdidx = 0;
  boolean  first = true;

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print(F("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.println(F("File not found"));
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.println(F("File size: ")); 
    Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: ")); 
    Serial.println(bmpImageoffset, DEC);

    // Read DIB header
    Serial.print(F("Header size: ")); 
    Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);

    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: ")); 
      Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("Image size: "));
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds

        for (row=0; row<h; row++) { // For each scanline...
          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
          pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col=0; col<w; col++) { // For each column...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              // Push LCD buffer to the display first
              if(lcdidx > 0) {
                tft.drawPixel(col, row, lcdbuffer[lcdidx]);
                lcdidx = 0;
                first  = false;
              }

              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            lcdbuffer[lcdidx] = color565(r,g,b);
            tft.drawPixel(col, row, lcdbuffer[lcdidx]);
          } // end pixel

        } // end scanline

        // Write any remaining data to LCD
        if(lcdidx > 0) {
          tft.drawPixel(col, row, lcdbuffer[lcdidx]);
        } 

        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");

      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println(F("BMP format not recognized."));

}

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

uint16_t color565(uint8_t r, uint8_t g, uint8_t b) {
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

byte decToBcd(byte val){
  // Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}

/***************************************************
//Web: http://www.buydisplay.com
EastRising Technology Co.,LTD
Micro SD Card (TF Card) Demonstration
Examples for ER-TFTM070-4V2.1(800x480 Pixels) 

ER-TFTM070-4V2.1 with no touch panel sets power supply to 5V and 8080-16BIT parallel interface.Meanwhile the Hardware SPI on shield should be short and Software SPI should be open.Capacitive Touch Screen on shield should be short and Resistive Touch Panel should be open. 

ER-TFTM070-4V2.1 with Resistive touch panel sets power supply to 5V and 8080-16BIT Parallel interface. Meanwhile the Hardware SPI on shield should be open and Software SPI should be short.Capacitive Touch Screen on shield should be open and Resistive Touch Panel should be open either.

Don't foget to copy images from bmp folder to your TF card and insert to SD card slot of arduino shield.

Tested and worked with:
Arduino Mega 2560,Arduino Due
Works with Arduino 1.6.0 IDE
****************************************************/
   
#include <Wire.h>  
#include <UTFT.h> 
#include <SPI.h> 
#include <SD.h> 
   
// TFT display and SD card will share the hardware SPI interface. 
// Hardware SPI pins are specific to the Arduino board type and 
// cannot be remapped to alternate pins.  
   
// Standard Arduino Mega/Due shield            : <display model>,38,39,40,41

// Remember to change the model parameter to suit your display module!
UTFT myGLCD(SSD1963_800480,38,39,40,41);  //(byte model, int RS, int WR, int CS, int RST, int SER)
   
#define SD_CS 47 
int dispx, dispy;   

void setup(void) { 
  
  // Setup the LCD
  myGLCD.InitLCD();
 // -------------------------------------------------------------
  pinMode(8, OUTPUT);  //backlight 
  digitalWrite(8, HIGH);//on
// -------------------------------------------------------------
  
  Serial.begin(9600); 
  
  myGLCD.setColor(255, 0, 0);
  myGLCD.fillRect(0, 0, 799, 479);  
  
  dispx=myGLCD.getDisplayXSize();
  dispy=myGLCD.getDisplayYSize();  
   
  Serial.print("Initializing SD card..."); 
  if (!SD.begin(SD_CS)) { 
    Serial.println("failed!"); 
  } 
  Serial.println("OK!"); 
   
     bmpDraw("BMP_1.bmp", 0, 0);
   delay(1000);
   bmpDraw("BMP_2.bmp", 0, 0); 
  delay(1000);
   bmpDraw("BMP_3.bmp", 0, 0); 
  delay(1000);
   bmpDraw("BMP_4.bmp", 0, 0);    
    delay(1000);
   bmpDraw("BMP_5.bmp", 0, 0);   
     delay(1000);
   bmpDraw("BMP_6.bmp", 0, 0); 
    delay(1000);
   bmpDraw("BMP_7.bmp", 0, 0);   
     delay(1000);
   bmpDraw("BMP_8.bmp", 0, 0);  
     delay(1000);
   bmpDraw("BMP_9.bmp", 0, 0);  
     delay(1000);
   bmpDraw("BMP_10.bmp", 0, 0);  
  delay(1000);
} 
   
void loop() { 
} 
   
// This function opens a Windows Bitmap (BMP) file and 
// displays it at the given coordinates.  It's sped up 
// by reading many pixels worth of data at a time 
// (rather than pixel by pixel).  Increasing the buffer 
// size takes more of the Arduino's precious RAM but 
// makes loading a little faster.  20 pixels seems a 
// good balance. 
   
#define BUFFPIXEL 20

void bmpDraw(char *filename, int x, int y) {
  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
  uint16_t lcdbuffer[BUFFPIXEL];  // pixel out buffer (16-bit per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();
  uint8_t  lcdidx = 0;
  boolean  first = true;

  if((x >= dispx) || (y >= dispy)) return;

  Serial.println();
  Serial.print(F("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.println(F("File not found"));
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.println(F("File size: ")); 
    Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: ")); 
    Serial.println(bmpImageoffset, DEC);

    // Read DIB header
    Serial.print(F("Header size: ")); 
    Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);

    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: ")); 
      Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("Image size: "));
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= dispx)  w = dispx  - x;
        if((y+h-1) >= dispy) h = dispy - y;

        // Set TFT address window to clipped image bounds

        for (row=0; row<h; row++) { // For each scanline...
          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
          pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col=0; col<w; col++) { // For each column...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              // Push LCD buffer to the display first
              if(lcdidx > 0) {
                myGLCD.setColor(lcdbuffer[lcdidx]);
                myGLCD.drawPixel(col, row);
                lcdidx = 0;
                first  = false;
              }

              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            myGLCD.setColor(r,g,b);
            myGLCD.drawPixel(col, row);
          } // end pixel

        } // end scanline

        // Write any remaining data to LCD
        if(lcdidx > 0) {
           myGLCD.setColor(lcdbuffer[lcdidx]);
          myGLCD.drawPixel(col, row);
        } 

        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");

      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println(F("BMP format not recognized."));

}

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

Hi @phil_h, I had played with both 7" RA8875 and 7" SSD1963 some time ago.

But not with the SSD1963 from Buydisplay. I have the cheap one with only 16bit parallel interface.

From your post I assume you didn't get it to work, neither with text or graphics, nor with SD BMPs.

If you search for SSD1963 in the forum, you certainly will find some related posts.
You could also take a look at the libraries I used: GxTFT (old, standalone) and GFX_TFT (newer, uses an Adafruit_GFX clone, depends on additional libraries).

But hopefully you will also get an answer from someone with experience with the Buydisplay one.
-jz-

Hello @ZinggJM ,

Thank you for your time and your answer.

I confirm that nothing works : neither text or graphics, nor BMP files. White screen with all my tests!

I'm going to dug in the 2 libraries you mention.

Thanks for your help. :+1:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.