Teensy with SSD1963 controller in 16-bit mode

I have been working on a driver with simple graphics ability for a 5" display with an SSD1963 controller running in 16-bit parallel mode on a Teensy 4.0. Everything in the code below is working with one intermittent problem. When this code starts, it clears the display and places a few graphics and text on the screen then repeats every 2 seconds. The problem is that it frequently starts with the screen only partially cleared and then the graphics are messed up. I have been trying to fix this for quite some time, but I just can't see what is wrong. Just to be clear, if the initial screenClear works ok, then the graphics repeatedly display correctly. If the initial screenClear fails, then the partial graphics repeatedly show up. It is pretty clear to me the problem is only at the initial power up or code upload.

These are the good and bad images:

This is the display with a Teensy on board : Display There is a schematic on that site.
I have two of these boards and they both behave the same way.

It has a teensy 4.0 mounted on the back with 10 extra pins connected to the bottom of the Teensy. This provides enough pins for 16-bit parallel operation. It will have exceedingly fast graphics.

I think the problem is with the SSD1963 controller setup in startDisplay, but I haven't been able to find it.

Any help would be appreciated.

Here are the code files:
five_inch.ino

//#include "FOC_Code.h"
#include "Displays5.h"
#include <PID_v1.h>
#include <mine.h>
#include <Wire.h>

#define ctp_int A6  // capacitive touchscreen interrupt pin
#define RS 26
#define WR 27
#define CS 25
#define RST 28

Displays5 d(RS, WR, CS, RST);  // d display constructor
uint16_t fg = WHITE, bg = BLACK;  // foreground and background colors
volatile boolean touchInt = false;  // flag for the touchscreen touch

// setup
/***************************************************************************************************************/
void setup() {
  Serial.begin(115200);
  delay(500);

  Wire.begin();
  
  d.startDisplay(bg);
  delay(10);

  draw();
}

// loop
/***************************************************************************************************************/
void loop() {
  // d.getTouch();
  draw();
  delay(2000);
}

// draw
/***************************************************************************************************************/
void draw() {
  d.clearScreen(BLACK);
  delay(250);
  d.setColor(BLACK);
 
  d.drawRoundRect(20, 10, 100, 50, 5, WHITE);
  d.fillRoundRect(230, 7, 100, 75, 5, WHITE);
  d.fillRect(230, 200, 50, 50, BLUE);
  d.drawCircle(390, 30, 25, YELLOW);
  d.fillCircle(150, 130, 25, GREEN);
  d.drawRect(320, 150, 50, 75, WHITE);
  d.drawLine(260, 170, 360, 110, ORANGE);
  d.drawPixel(260, 120, WHITE);
  d.drawCircle(230, 130, 10, WHITE);
  d.drawFastVLine(20, 100, 180, RED);
  d.drawFastHLine(30, 90, 180, WHITE);
  d.drawTriangle(420, 100, 470, 150, 420, 150, YELLOW);
  d.myPrint(30, 180, "Tyler TX", GREEN);
  d.fillTriangle(180, 300, 290, 270, 290, 320, YELLOW);
}

displays5.h

#ifndef __Displays5_H__
#define __Displays5_H__

#include "Arduino.h"
#include "gfxfont.h"
#include "Print.h"

// Color definitions
#define NAVY 0x000F
#define DARKGREEN 0x03E0
#define DARKCYAN 0x03EF
#define MAROON 0x7800
#define PURPLE 0x780F
#define OLIVE 0x7BE0
#define LIGHTGRAY 0xC618
#define BLUE 0x001F
#define DARKBLUE 0x0016
#define GREEN 0x04A0
#define CYAN 0x07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define ORANGE 0xFD20
#define GREENYELLOW 0xAFE5
#define PINK 0xFC18
#define BACKGROUND 0xA514
#define BUTTONCOLOR 0xAD75
#define BLACK 0x0000
#define YELLOW 0xFFE0
#define DARKRED 0xA800
#define WHITE 0xFFFF
#define GRAY 0x7410
#define DARKGRAY 0x7BEF

// Teensy 4.0 pins
#define DB_0 29
#define DB_1 32
#define DB_2 33
#define DB_3 12
#define DB_4 11
#define DB_5 10
#define DB_6 9
#define DB_7 8
#define DB_8 7
#define DB_9 6
#define DB_10 5
#define DB_11 4
#define DB_12 3
#define DB_13 2
#define DB_14 1
#define DB_15 0

struct tStruct {
  String hour;
  String minute;
  String second;
  String AMPM;
};

/********************************************************** ******************************************************/
class Displays5 : public Print {
private:
  int _x;                     // x location of the button
  int _y;                     // y location of the button
  int _w;                     // width of the button text
  byte _h;                    // height of the button text
  boolean _invert;            // whether the button colors are inverted (background/text)
  String _text;               // the button text
  int _tx;                    // start x of the button text
  int _ty;                    // start y of the button text
  uint16_t fg;                // the text clr
  uint16_t bg;                // the background color
  void (*_funct)(int16_t n);  // the function to call if the button is pressed
  int _arg;                   // the argument for the called function

  struct ButtonData  // all button information is stored here
  {
    int x;                     // x location of the button
    int y;                     // y location of the button
    int w;                     // width of the button text
    byte h;                    // height of the button text
    boolean invert;            // whether the button clrs are inverted (background/text)
    String text;               // the button text
    int tx;                    // start x of the button text
    int ty;                    // start y of the button text
    int fg;                    // the text clr
    int bg;                    // the background color
    void (*funct)(int16_t n);  // the function to call if the button is pressed
    int arg;                   // the argument for the called function
  };

  ButtonData ary[10];
  uint16_t _fg = WHITE, _bg = BLACK;
  int8_t _tsize;

  void fillScreen(uint16_t color);
  size_t write(uint8_t);
  void startWrite();
  void endWrite();
  void LCD_Write_Bus(char ch, char cl);
  void LCD_Write_DATA(char VL);
  void LCD_Write_COM(char VL);
  void writeFastVLine(int x, int y, int h);
  void writeFastHLine(int x, int y, int w);
  void writeLine(int x0, int y0, int x1, int y1);
  void writeLine(int x0, int y0, int x1, int y1, uint16_t color);
  void writePixel(int x, int y);
  void writeFillRect(int x, int y, int w, int h);
  void LCD_Write_DATA(char VH, char VL);
  void setFont(const GFXfont *f);
  void _fast_fill_16(int ch, int cl, long pix);
  void drawCircleHelper(int x0, int y0, int r, uint8_t cornername);
  void LCD_Write_Bus16(uint16_t data);
  void fillCircleHelper(int x0, int y0, int r, uint8_t corners, int delta);

public:

  Displays5();
  Displays5(int RS, int WR, int CS, int RST);
  
  void setRotation(byte r);
  void drawFastHLine(int x, int y, int w);
  void drawFastHLine(int x, int y, int w, uint16_t color);
  void drawFastVLine(int x, int y, int h);
  void drawFastVLine(int x, int y, int h, uint16_t color);
  void startDisplay(void);
  void startDisplay(uint16_t color);
  void setColor(byte r, byte g, byte b);
  void setColor(uint16_t color);
  void setTextColor(uint16_t fg);
  void setTextColor(uint16_t fg, uint16_t bg);
  void setCursor(int x, int y);
  void setFontSize(int8_t sz);
  void setXY(word x1, word y1, word x2, word y2);
  void fillRect(int x, int y, int w, int h);
  void fillRect(int x, int y, int w, int h, uint16_t color);
  void drawRect(int x1, int y1, int w, int h);
  void drawRect(int x1, int y1, int w, int h, uint16_t color);
  void drawRoundRect(int x, int y, int w, int h, int r);
  void drawRoundRect(int x1, int y1, int x2, int y2, int r, uint16_t color);
  void fillRoundRect(int x, int y, int w, int h, int r);
  void fillRoundRect(int x, int y, int w, int h, int r, uint16_t color);
  void myPrint(int x, int y, String str, uint16_t color);
  void drawCircle(int x0, int y0, int r);
  void drawCircle(int x0, int y0, int r, uint16_t color);
  void drawPixel(int x, int y);
  void drawPixel(int x, int y, uint16_t color);
  void drawLine(int x1, int y1, int x2, int y2);
  void drawLine(int x1, int y1, int x2, int y2, uint16_t color);
  void fillCircle(int x, int y, int r);
  void fillCircle(int x, int y, int r, uint16_t color);
  void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3);
  void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, uint16_t color);
  void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3);
  void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, uint16_t color);
  void clearScreen(uint16_t color);
  void clearScreen();

  int DWIDTH = 800;
  int DHEIGHT = 480;
  uint8_t fch, fcl, bch, bcl;
  uint8_t B_RS, B_WR, B_CS, B_RST;
};

#endif

displays5.cpp

#include "Arduino.h"
#include "Displays5.h"
#include <mine.h>
#include <Fonts\FreeMonoBold12pt7b.h>
#include <Fonts\FreeMonoBold18pt7b.h>
#include <TimeLib.h>

GFXfont *gfxFont;
#define BL_CTL 21
int _cursor_x, _cursor_y;
int8_t bc, baseLine = 30, _tSize = 3;
int _txtw = 20, _txth = 22;

void swap(int &a, int &b);
void swap(word &x1, word &x2);
/***************************************************************************************************************/
Displays5::Displays5() {}

/***************************************************************************************************************/
Displays5::Displays5(int RS, int WR, int CS, int RST) {
  pinMode(DB_0, OUTPUT);
  pinMode(DB_1, OUTPUT);
  pinMode(DB_2, OUTPUT);
  pinMode(DB_3, OUTPUT);
  pinMode(DB_4, OUTPUT);
  pinMode(DB_5, OUTPUT);
  pinMode(DB_6, OUTPUT);
  pinMode(DB_7, OUTPUT);

  pinMode(DB_8, OUTPUT);
  pinMode(DB_9, OUTPUT);
  pinMode(DB_10, OUTPUT);
  pinMode(DB_11, OUTPUT);
  pinMode(DB_12, OUTPUT);
  pinMode(DB_13, OUTPUT);
  pinMode(DB_14, OUTPUT);
  pinMode(DB_15, OUTPUT);

  pinMode(RS, OUTPUT);
  pinMode(WR, OUTPUT);
  pinMode(CS, OUTPUT);
  pinMode(RST, OUTPUT);
  digitalWriteFast(B_RST, HIGH);
  B_RS = RS;
  B_WR = WR;
  B_CS = CS;
  B_RST = RST;
}

/***************************************************************************************************************/
void Displays5::clearScreen() {
  fillScreen(_bg);
}

/***************************************************************************************************************/
void Displays5::clearScreen(uint16_t color) {
  fillScreen(color);
}

/***************************************************************************************************************/
void Displays5::endWrite() {
  digitalWriteFast(B_CS, HIGH);
}

/***************************************************************************************************************/
void Displays5::drawFastHLine(int x, int y, int w, uint16_t color) {
  setColor(color);
  startWrite();
  writeLine(x, y, x + w - 1, y);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::drawFastVLine(int x, int y, int h, uint16_t color) {
  setColor(color);
  startWrite();
  writeLine(x, y, x, y + h - 1);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::drawPixel(int x, int y) {
  digitalWriteFast(B_CS, LOW);
  setXY(x, y, x, y);
  LCD_Write_DATA(fch, fcl);
  digitalWriteFast(B_CS, HIGH);
}

/***************************************************************************************************************/
void Displays5::drawPixel(int x, int y, uint16_t color) {
  setColor(color);
  drawPixel(x, y);
}

/***************************************************************************************************************/
void Displays5::_fast_fill_16(int ch, int cl, long pix) {
  long blocks;

  ((ch & 0x80) != 0) ? digitalWriteFast(DB_15, HIGH) : digitalWriteFast(DB_15, LOW);
  ((ch & 0x40) != 0) ? digitalWriteFast(DB_14, HIGH) : digitalWriteFast(DB_14, LOW);
  ((ch & 0x20) != 0) ? digitalWriteFast(DB_13, HIGH) : digitalWriteFast(DB_13, LOW);
  ((ch & 0x10) != 0) ? digitalWriteFast(DB_12, HIGH) : digitalWriteFast(DB_12, LOW);
  ((ch & 0x08) != 0) ? digitalWriteFast(DB_11, HIGH) : digitalWriteFast(DB_11, LOW);
  ((ch & 0x04) != 0) ? digitalWriteFast(DB_10, HIGH) : digitalWriteFast(DB_10, LOW);
  ((ch & 0x02) != 0) ? digitalWriteFast(DB_9, HIGH) : digitalWriteFast(DB_9, LOW);
  ((ch & 0x01) != 0) ? digitalWriteFast(DB_8, HIGH) : digitalWriteFast(DB_8, LOW);
  ((cl & 0x80) != 0) ? digitalWriteFast(DB_7, HIGH) : digitalWriteFast(DB_7, LOW);
  ((cl & 0x40) != 0) ? digitalWriteFast(DB_6, HIGH) : digitalWriteFast(DB_6, LOW);
  ((cl & 0x20) != 0) ? digitalWriteFast(DB_5, HIGH) : digitalWriteFast(DB_5, LOW);
  ((cl & 0x10) != 0) ? digitalWriteFast(DB_4, HIGH) : digitalWriteFast(DB_4, LOW);
  ((cl & 0x08) != 0) ? digitalWriteFast(DB_3, HIGH) : digitalWriteFast(DB_3, LOW);
  ((cl & 0x04) != 0) ? digitalWriteFast(DB_2, HIGH) : digitalWriteFast(DB_2, LOW);
  ((cl & 0x02) != 0) ? digitalWriteFast(DB_1, HIGH) : digitalWriteFast(DB_1, LOW);
  ((cl & 0x01) != 0) ? digitalWriteFast(DB_0, HIGH) : digitalWriteFast(DB_0, LOW);

  blocks = pix / 16;
  for (int i = 0; i < blocks; i++) {
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
    digitalWriteFast(B_WR, LOW);
    digitalWriteFast(B_WR, HIGH);
  }

  if ((pix % 16) != 0)
    for (int i = 0; i < (pix % 16); i++) {
      digitalWriteFast(B_WR, LOW);
      digitalWriteFast(B_WR, HIGH);
    }
}

/***************************************************************************************************************/
void Displays5::fillRect(int x1, int y1, int x2, int y2) {
  x2 = x1 + x2;
  y2 = y1 + y2;

  uint16_t temp;
  if (x1 > x2) {
    temp = x1;
    x1 = x2;
    x2 = temp;
  }
  if (y1 > y2) {
    temp = y1;
    y1 = y2;
    y2 = temp;
  }

  digitalWriteFast(B_CS, LOW);
  setXY(x1, y1, x2, y2);
  digitalWriteFast(B_RS, HIGH);

  _fast_fill_16(fch, fcl, ((long(x2 - x1) + 1) * (long(y2 - y1) + 1)));
  digitalWriteFast(B_CS, HIGH);
}

/***************************************************************************************************************/
void Displays5::fillRect(int x, int y, int w, int h, uint16_t color) {
  setColor(color);
  fillRect(x, y, w, h);
}

/***************************************************************************************************************/
void Displays5::drawLine(int x1, int y1, int x2, int y2) {
  uint16_t dx = (x2 > x1 ? x2 - x1 : x1 - x2);
  short xstep = x2 > x1 ? 1 : -1;
  uint16_t dy = (y2 > y1 ? y2 - y1 : y1 - y2);
  short ystep = y2 > y1 ? 1 : -1;
  int col = x1, row = y1;

  digitalWriteFast(B_CS, LOW);
  if (dx < dy) {
    int t = -(dy >> 1);
    while (true) {
      setXY(col, row, col, row);
      LCD_Write_DATA(fch, fcl);
      if (row == y2)
        return;
      row += ystep;
      t += dx;
      if (t >= 0) {
        col += xstep;
        t -= dy;
      }
    }
  } else {
    int t = -(dx >> 1);
    while (true) {
      setXY(col, row, col, row);
      LCD_Write_DATA(fch, fcl);
      if (col == x2)
        return;
      col += xstep;
      t += dy;
      if (t >= 0) {
        row += ystep;
        t -= dx;
      }
    }
  }
  digitalWriteFast(B_CS, HIGH);
}

/***************************************************************************************************************/
void Displays5::drawLine(int x1, int y1, int x2, int y2, uint16_t color) {
  setColor(color);
  drawLine(x1, y1, x2, y2);
}

/***************************************************************************************************************/
void Displays5::drawCircle(int x0, int y0, int r) {
  int f = 1 - r;
  int ddF_x = 1;
  int ddF_y = -2 * r;
  int x = 0;
  int y = r;

  startWrite();
  drawPixel(x0, y0 + r);
  drawPixel(x0, y0 - r);
  drawPixel(x0 + r, y0);
  drawPixel(x0 - r, y0);

  while (x < y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;

    drawPixel(x0 + x, y0 + y);
    drawPixel(x0 - x, y0 + y);
    drawPixel(x0 + x, y0 - y);
    drawPixel(x0 - x, y0 - y);
    drawPixel(x0 + y, y0 + x);
    drawPixel(x0 - y, y0 + x);
    drawPixel(x0 + y, y0 - x);
    drawPixel(x0 - y, y0 - x);
  }
  endWrite();
}

/***************************************************************************************************************/
void Displays5::drawCircle(int x, int y, int r, uint16_t color) {
  setColor(color);
  drawCircle(x, y, r);
}

/***************************************************************************************************************/
void Displays5::drawCircleHelper(int x, int y, int r, uint8_t cornername) {
  int f = 1 - r;
  int ddF_x = 1;
  int ddF_y = -2 * r;
  int xx = 0;
  int yy = r;

  while (xx < yy) {
    if (f >= 0) {
      yy--;
      ddF_y += 2;
      f += ddF_y;
    }
    xx++;
    ddF_x += 2;
    f += ddF_x;
    if (cornername & 0x4) {
      writePixel(x + xx, y + yy);
      writePixel(x + yy, y + xx);
    }
    if (cornername & 0x2) {
      writePixel(x + xx, y - yy);
      writePixel(x + yy, y - xx);
    }
    if (cornername & 0x8) {
      writePixel(x - yy, y + xx);
      writePixel(x - xx, y + yy);
    }
    if (cornername & 0x1) {
      writePixel(x - yy, y - xx);
      writePixel(x - xx, y - yy);
    }
  }
}

/***************************************************************************************************************/
void Displays5::drawFastHLine(int x, int y, int w) {
  startWrite();
  writeLine(x, y, x + w - 1, y);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::drawFastVLine(int x, int y, int h) {
  startWrite();
  writeLine(x, y, x, y + h - 1);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::drawRect(int x, int y, int w, int h) {

  startWrite();
  writeFastHLine(x, y, w);
  writeFastHLine(x, y + h - 1, w);
  writeFastVLine(x, y, h);
  writeFastVLine(x + w - 1, y, h);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::drawRect(int x, int y, int w, int h, uint16_t color) {

  setColor(color);
  drawRect(x, y, w, h);
}

/***************************************************************************************************************/
void Displays5::drawRoundRect(int x, int y, int w, int h, int r) {

  int max_radius = ((w < h) ? w : h) / 2;  // 1/2 minor axis
  if (r > max_radius)
    r = max_radius;
  // smarter version
  startWrite();
  writeFastHLine(x + r, y, w - 2 * r);          // Top
  writeFastHLine(x + r, y + h - 1, w - 2 * r);  // Bottom
  writeFastVLine(x, y + r, h - 2 * r);          // Left
  writeFastVLine(x + w - 1, y + r, h - 2 * r);  // Right

  // draw four corners
  drawCircleHelper(x + r, y + r, r, 1);
  drawCircleHelper(x + w - r - 1, y + r, r, 2);
  drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4);
  drawCircleHelper(x + r, y + h - r - 1, r, 8);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::drawRoundRect(int x, int y, int w, int h, int r, uint16_t color) {
  setColor(color);
  drawRoundRect(x, y, w, h, r);
}

/***************************************************************************************************************/
void Displays5::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
  drawLine(x1, y1, x2, y2);
  drawLine(x2, y2, x3, y3);
  drawLine(x3, y3, x1, y1);
}

/***************************************************************************************************************/
void Displays5::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, uint16_t color) {
  setColor(color);
  drawLine(x1, y1, x2, y2);
  drawLine(x2, y2, x3, y3);
  drawLine(x3, y3, x1, y1);
}

/***************************************************************************************************************/
void Displays5::fillCircle(int x, int y, int r) {
  startWrite();
  writeFastVLine(x, y - r, 2 * r + 1);
  fillCircleHelper(x, y, r, 3, 0);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::fillCircle(int x, int y, int r, uint16_t color) {
  setColor(color);
  fillCircle(x, y, r);
}

/***************************************************************************************************************/
void Displays5::fillCircleHelper(int x0, int y0, int r, uint8_t corners, int delta) {
  int f = 1 - r;
  int ddF_x = 1;
  int ddF_y = -2 * r;
  int x = 0;
  int y = r;
  int px = x;
  int py = y;

  delta++;  // Avoid some +1's in the loop

  while (x < y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    // These checks avoid double-drawing certain lines, important
    // for the SSD1306 library which has an INVERT drawing mode.
    if (x < (y + 1)) {
      if (corners & 1)
        writeFastVLine(x0 + x, y0 - y, 2 * y + delta);
      if (corners & 2)
        writeFastVLine(x0 - x, y0 - y, 2 * y + delta);
    }

    if (y != py) {
      if (corners & 1)
        writeFastVLine(x0 + py, y0 - px, 2 * px + delta);
      if (corners & 2)
        writeFastVLine(x0 - py, y0 - px, 2 * px + delta);
      py = y;
    }
    px = x;
  }
}

/***************************************************************************************************************/
void Displays5::fillRoundRect(int x, int y, int w, int h, int r) {

  int max_radius = ((w < h) ? w : h) / 2;  // 1/2 minor axis
  if (r > max_radius)
    r = max_radius;

  // smarter version
  startWrite();

  writeFillRect(x + r, y, w - 2 * r, h);

  // draw four corners
  fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1);
  fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1);
  endWrite();
}

/***************************************************************************************************************/
void Displays5::fillRoundRect(int x, int y, int w, int h, int r, uint16_t color) {

  setColor(color);
  fillRoundRect(x, y, w, h, r);
}

/***************************************************************************************************************/
void Displays5::fillScreen(uint16_t color) {
  setColor(color);
  fillRect(0, 0, DWIDTH - 1, DHEIGHT - 1);
}

/***************************************************************************************************************/
void Displays5::fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {

  int a, b, y, last;

  // Sort coordinates by Y order (y3 >= y2 >= y0)

  if (y1 > y2) {
    swap(y1, y2);
    swap(x1, x2);
  }

  if (y2 > y3) {
    swap(y2, y3);
    swap(x2, x3);
  }

  if (y1 > y2) {
    swap(y1, y2);
    swap(x1, x2);
  }

  startWrite();
  if (y1 == y3) {  // Handle awkward all-on-same-line case as its own thing
    a = b = x1;
    if (x2 < a)
      a = x2;
    else if (x2 > b)
      b = x2;
    if (x3 < a)
      a = x3;
    else if (x3 > b)
      b = x3;
    writeFastHLine(a, y1, b - a + 1);
    endWrite();
    return;
  }

  int dx01 = x2 - x1, dy01 = y2 - y1, dx02 = x3 - x1, dy02 = y3 - y1,
      dx12 = x3 - x2, dy12 = y3 - y2;
  int32_t sa = 0, sb = 0;

  // For upper part of triangle, find scanline crossings for segments
  // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
  // is included here (and second loop will be skipped, avoiding a /0
  // error there), otherwise scanline y1 is skipped here and handled
  // in the second loop...which also avoids a /0 error here if y0=y1
  // (flat-topped triangle).
  if (y2 == y3)
    last = y2;  // Include y1 scanline
  else
    last = y2 - 1;  // Skip it

  for (y = y1; y <= last; y++) {
    a = x1 + sa / dy01;
    b = x1 + sb / dy02;
    sa += dx01;
    sb += dx02;
    /* longhand:
      a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
      b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
    */
    if (a > b)
      swap(a, b);
    writeFastHLine(a, y, b - a + 1);
  }

  // For lower part of triangle, find scanline crossings for segments
  // 0-2 and 1-2.  This loop is skipped if y1=y2.
  sa = (int32_t)dx12 * (y - y2);
  sb = (int32_t)dx02 * (y - y1);
  for (; y <= y3; y++) {
    a = x2 + sa / dy12;
    b = x1 + sb / dy02;
    sa += dx12;
    sb += dx02;
    /* longhand:
      a = x2 + (x3 - x2) * (y - y2) / (y3 - y2);
      b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
    */
    if (a > b)
      swap(a, b);
    writeFastHLine(a, y, b - a + 1);
  }
  endWrite();
}

/***************************************************************************************************************/
void Displays5::fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, uint16_t color) {
  setColor(color);
  fillTriangle(x1, y1, x2, y2, x3, y3);
}

/***************************************************************************************************************/
void Displays5::LCD_Write_Bus(char ch, char cl) {
  ((ch & 0x80) != 0) ? digitalWriteFast(DB_15, HIGH) : digitalWriteFast(DB_15, LOW);
  ((ch & 0x40) != 0) ? digitalWriteFast(DB_14, HIGH) : digitalWriteFast(DB_14, LOW);
  ((ch & 0x20) != 0) ? digitalWriteFast(DB_13, HIGH) : digitalWriteFast(DB_13, LOW);
  ((ch & 0x10) != 0) ? digitalWriteFast(DB_12, HIGH) : digitalWriteFast(DB_12, LOW);
  ((ch & 0x08) != 0) ? digitalWriteFast(DB_11, HIGH) : digitalWriteFast(DB_11, LOW);
  ((ch & 0x04) != 0) ? digitalWriteFast(DB_10, HIGH) : digitalWriteFast(DB_10, LOW);
  ((ch & 0x02) != 0) ? digitalWriteFast(DB_9, HIGH) : digitalWriteFast(DB_9, LOW);
  ((ch & 0x01) != 0) ? digitalWriteFast(DB_8, HIGH) : digitalWriteFast(DB_8, LOW);
  ((cl & 0x80) != 0) ? digitalWriteFast(DB_7, HIGH) : digitalWriteFast(DB_7, LOW);
  ((cl & 0x40) != 0) ? digitalWriteFast(DB_6, HIGH) : digitalWriteFast(DB_6, LOW);
  ((cl & 0x20) != 0) ? digitalWriteFast(DB_5, HIGH) : digitalWriteFast(DB_5, LOW);
  ((cl & 0x10) != 0) ? digitalWriteFast(DB_4, HIGH) : digitalWriteFast(DB_4, LOW);
  ((cl & 0x08) != 0) ? digitalWriteFast(DB_3, HIGH) : digitalWriteFast(DB_3, LOW);
  ((cl & 0x04) != 0) ? digitalWriteFast(DB_2, HIGH) : digitalWriteFast(DB_2, LOW);
  ((cl & 0x02) != 0) ? digitalWriteFast(DB_1, HIGH) : digitalWriteFast(DB_1, LOW);
  ((cl & 0x01) != 0) ? digitalWriteFast(DB_0, HIGH) : digitalWriteFast(DB_0, LOW);

  digitalWriteFast(B_WR, LOW);
  digitalWriteFast(B_WR, HIGH);
}

/***************************************************************************************************************/
void Displays5::LCD_Write_Bus16(uint16_t data) {
  digitalWriteFast(B_RS, HIGH);
  ((data & 0x8000) != 0) ? digitalWriteFast(DB_15, HIGH) : digitalWriteFast(DB_15, LOW);
  ((data & 0x4000) != 0) ? digitalWriteFast(DB_14, HIGH) : digitalWriteFast(DB_14, LOW);
  ((data & 0x2000) != 0) ? digitalWriteFast(DB_13, HIGH) : digitalWriteFast(DB_13, LOW);
  ((data & 0x1000) != 0) ? digitalWriteFast(DB_12, HIGH) : digitalWriteFast(DB_12, LOW);
  ((data & 0x0800) != 0) ? digitalWriteFast(DB_11, HIGH) : digitalWriteFast(DB_11, LOW);
  ((data & 0x0400) != 0) ? digitalWriteFast(DB_10, HIGH) : digitalWriteFast(DB_10, LOW);
  ((data & 0x0200) != 0) ? digitalWriteFast(DB_9, HIGH) : digitalWriteFast(DB_9, LOW);
  ((data & 0x0100) != 0) ? digitalWriteFast(DB_8, HIGH) : digitalWriteFast(DB_8, LOW);
  ((data & 0x80) != 0) ? digitalWriteFast(DB_7, HIGH) : digitalWriteFast(DB_7, LOW);
  ((data & 0x40) != 0) ? digitalWriteFast(DB_6, HIGH) : digitalWriteFast(DB_6, LOW);
  ((data & 0x20) != 0) ? digitalWriteFast(DB_5, HIGH) : digitalWriteFast(DB_5, LOW);
  ((data & 0x10) != 0) ? digitalWriteFast(DB_4, HIGH) : digitalWriteFast(DB_4, LOW);
  ((data & 0x08) != 0) ? digitalWriteFast(DB_3, HIGH) : digitalWriteFast(DB_3, LOW);
  ((data & 0x04) != 0) ? digitalWriteFast(DB_2, HIGH) : digitalWriteFast(DB_2, LOW);
  ((data & 0x02) != 0) ? digitalWriteFast(DB_1, HIGH) : digitalWriteFast(DB_1, LOW);
  ((data & 0x01) != 0) ? digitalWriteFast(DB_0, HIGH) : digitalWriteFast(DB_0, LOW);

  digitalWriteFast(B_WR, LOW);
  digitalWriteFast(B_WR, HIGH);
}

/***************************************************************************************************************/
void Displays5::LCD_Write_COM(char VL) {
  digitalWriteFast(B_RS, LOW);
  LCD_Write_Bus(0x00, VL);
}

/***************************************************************************************************************/
void Displays5::LCD_Write_DATA(char VL) {
  digitalWriteFast(B_RS, HIGH);
  LCD_Write_Bus(0x00, VL);
}

/***************************************************************************************************************/
void Displays5::LCD_Write_DATA(char VH, char VL) {
  digitalWriteFast(B_RS, HIGH);
  LCD_Write_Bus(VH, VL);
}

/*****************************************************************************************************************/
void Displays5::myPrint(int x, int y, String str, uint16_t color) {
  int len = str.length() * 21;
  fillRect(x - 2, y - 1, len + 4, 32, color);
  setCursor(x, y + 1);
  setFontSize(3);
  setTextColor(LIGHTGRAY);
  print(str);
}

/***************************************************************************************************************/
uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) {
#ifdef __AVR__
  return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
#else
  // expression in __AVR__ section generates "dereferencing type-punned pointer
  // will break strict-aliasing rules" warning In fact, on other platforms (such
  // as STM32) there is no need to do this pointer magic as program memory may
  // be read in a usual way So expression may be simplified
  return gfxFont->bitmap;
#endif  //__AVR__
}

/***************************************************************************************************************/
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
  return gfxFont->glyph + c;
}

/***************************************************************************************************************/
void Displays5::setColor(byte r, byte g, byte b) {
  fch = ((r & 248) | g >> 5);
  fcl = ((g & 28) << 3 | b >> 3);
}

/***************************************************************************************************************/
void Displays5::setColor(uint16_t color) {
  byte r = (color & 0xF800) >> 11;
  byte g = (color & 0x07E0) >> 5;
  byte b = color & 0x001F;

  r = (r * 255) / 31;
  g = (g * 255) / 63;
  b = (b * 255) / 31;
  setColor(r, g, b);
  _fg = color;
}

/***************************************************************************************************************/
void Displays5::setCursor(int x, int y) {
  _cursor_x = x;
  _cursor_y = y;
}

/***************************************************************************************************************/
void Displays5::setFont(const GFXfont *f) {
  gfxFont = (GFXfont *)f;

  GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, 1);

  byte s = pgm_read_byte(&glyph->height);

  if (s == 26)
    _tSize = 3;
  else
    _tSize = 2;
}

/***************************************************************************************************************/
void Displays5::setFontSize(int8_t sz) {
  if (sz == 3) {
    setFont(&FreeMonoBold18pt7b);
    _tSize = 3;
  } else {
    setFont(&FreeMonoBold12pt7b);
    _tSize = 2;
  }
}

/***************************************************************************************************************/
void Displays5::setTextColor(uint16_t color) {
  setColor(color);
  setTextColor(fg, bg);
}

/***************************************************************************************************************/
void Displays5::setTextColor(uint16_t fg, uint16_t bg) {
}

/***************************************************************************************************************/
void Displays5::setXY(word x1, word y1, word x2, word y2) {
  LCD_Write_COM(0x2a);
  LCD_Write_DATA(x1 >> 8);
  LCD_Write_DATA(x1);
  LCD_Write_DATA(x2 >> 8);
  LCD_Write_DATA(x2);
  LCD_Write_COM(0x2b);
  LCD_Write_DATA(y1 >> 8);
  LCD_Write_DATA(y1);
  LCD_Write_DATA(y2 >> 8);
  LCD_Write_DATA(y2);
  LCD_Write_COM(0x2c);
}

/***************************************************************************************************************/
void Displays5::startDisplay(void) {
  digitalWriteFast(B_RST, LOW);
  delay(10);

  digitalWriteFast(B_RST, HIGH);
  delay(10);

  digitalWriteFast(B_CS, LOW);

  LCD_Write_COM(0xE2);   //PLL multiplier, set PLL clock to 120M
  LCD_Write_DATA(0x36);  //N=0x36 for 6.5M, 0x23 for 10M crystal
  LCD_Write_DATA(0x02);
  LCD_Write_DATA(0x54);

  LCD_Write_COM(0xE0);  // Set PLL Sequence
  LCD_Write_DATA(0x01);
  delay(1);
  LCD_Write_COM(0xE0);
  LCD_Write_DATA(0x03);
  LCD_Write_COM(0x01);
  delay(10);

  LCD_Write_COM(0x01);  // Software reset
  delay(10);

  LCD_Write_COM(0xE6);  //PLL setting for PCLK, depends on resolution
  LCD_Write_DATA(0x03);
  LCD_Write_DATA(0xFF);
  LCD_Write_DATA(0xFF);

  LCD_Write_COM(0xB0);  //LCD SPECIFICATION
  LCD_Write_DATA(0x24);
  LCD_Write_DATA(0x00);
  LCD_Write_DATA(0x03);  //Set HDP 799
  LCD_Write_DATA(0x1F);
  LCD_Write_DATA(0x01);  //Set VDP 479
  LCD_Write_DATA(0xDF);
  LCD_Write_DATA(0x00);

  LCD_Write_COM(0xB4);   //HSYNC
  LCD_Write_DATA(0x03);  //Set HT  928
  LCD_Write_DATA(0xA0);
  LCD_Write_DATA(0x00);  //Set HPS 46
  LCD_Write_DATA(0x2E);
  LCD_Write_DATA(0x30);  //Set HPW 48
  LCD_Write_DATA(0x00);  //Set LPS 15
  LCD_Write_DATA(0x0F);
  LCD_Write_DATA(0x00);

  LCD_Write_COM(0xB6);   //VSYNC
  LCD_Write_DATA(0x02);  //Set VT  525
  LCD_Write_DATA(0x0D);
  LCD_Write_DATA(0x00);  //Set VPS 16
  LCD_Write_DATA(0x10);
  LCD_Write_DATA(0x10);  //Set VPW 16
  LCD_Write_DATA(0x00);  //Set FPS 8
  LCD_Write_DATA(0x08);

  LCD_Write_COM(0xBA);
  LCD_Write_DATA(0x0F);  //GPIO[3:0] out 1

  LCD_Write_COM(0xB8);
  LCD_Write_DATA(0x07);  //GPIO3=input, GPIO[2:0]=output
  LCD_Write_DATA(0x01);  //GPIO0 normal

  LCD_Write_COM(0x36);  //Rotation
  LCD_Write_DATA(0x08);

  LCD_Write_COM(0xF0);   //pixel data interface
  LCD_Write_DATA(0x03);  // 011 16-bit (565 format)
  delay(10);

  LCD_Write_COM(0x29);  //display on

  LCD_Write_COM(0xBE);  //set PWM for B/L
  LCD_Write_DATA(0x06);
  LCD_Write_DATA(0xf0);
  LCD_Write_DATA(0x01);
  LCD_Write_DATA(0xf0);
  LCD_Write_DATA(0x00);
  LCD_Write_DATA(0x00);

  LCD_Write_COM(0xd0);
  LCD_Write_DATA(0x0d);

  LCD_Write_COM(0x2C);

  digitalWriteFast(B_CS, HIGH);
  if (_tSize == 3)
    setFont(&FreeMonoBold18pt7b);
  else
    setFont(&FreeMonoBold12pt7b);

  setFontSize(3);

  pinMode(BL_CTL, OUTPUT);     // backlight control pin, 0=off, 1 = on
  digitalWrite(BL_CTL, HIGH);  // turn the backlight on
}

/***************************************************************************************************************/
void Displays5::startDisplay(uint16_t color) {
  startDisplay();
  clearScreen(color);
  spl(color);
}

/***************************************************************************************************************/
void Displays5::startWrite() {
  digitalWriteFast(B_CS, LOW);
  digitalWriteFast(B_RS, HIGH);
}

/***************************************************************************************************************/
void swap(int &a, int &b) {
  int t = a;
  a = b;
  b = t;
}

/***************************************************************************************************************/
void swap(word &x1, word &x2) {
  word temp;
  temp = x1;
  x1 = x2;
  x2 = temp;
}

/***************************************************************************************************************/
size_t Displays5::write(uint8_t c) {
  c -= (uint8_t)pgm_read_byte(&gfxFont->first);

  GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);

  uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
  uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
  int8_t w = pgm_read_byte(&glyph->width);
  int8_t h = pgm_read_byte(&glyph->height);
  int8_t xAdv = pgm_read_byte(&glyph->xAdvance);
  int8_t xo = pgm_read_byte(&glyph->xOffset);
  int8_t yo = pgm_read_byte(&glyph->yOffset);

  uint8_t xx, yy, bits = 0, bit = 0;

  for (yy = 0; yy < h; yy++) {
    for (xx = 0; xx < w; xx++) {
      if (!(bit++ & 7)) {
        bits = pgm_read_byte(&bitmap[bo++]);
      }

      if (bits & 0x80) {
        drawPixel(_cursor_x + xx + xo, _cursor_y + yy + baseLine + yo - 8, _fg);
      }
      bits <<= 1;
    }
  }
  _cursor_x += xAdv;
  return 1;
}

/***************************************************************************************************************/
void Displays5::writeFastHLine(int x, int y, int w) {
  // Overwrite in subclasses if startWrite is defined!
  // Example: writeLine(x, y, x+w-1, y);
  // or writeFillRect(x, y, w, 1);
  drawFastHLine(x, y, w);
}

/***************************************************************************************************************/
void Displays5::writeFastVLine(int x, int y, int h) {
  // Overwrite in subclasses if startWrite is defined!
  // Can be just writeLine(x, y, x, y+h-1);
  // or writeFillRect(x, y, 1, h);
  drawFastVLine(x, y, h);
}

/***************************************************************************************************************/
void Displays5::writeFillRect(int x, int y, int w, int h) {
  // Overwrite in subclasses if desired!
  fillRect(x, y, w, h);
}

/***************************************************************************************************************/
void Displays5::writeLine(int x0, int y0, int x1, int y1) {
#if defined(ESP8266)
  yield();
#endif
  int steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    swap(x0, y0);
    swap(x1, y1);
  }

  if (x0 > x1) {
    swap(x0, x1);
    swap(y0, y1);
  }

  int dx, dy;
  dx = x1 - x0;
  dy = abs(y1 - y0);

  int err = dx / 2;
  int ystep;

  if (y0 < y1) {
    ystep = 1;
  } else {
    ystep = -1;
  }

  for (; x0 <= x1; x0++) {
    if (steep) {
      writePixel(y0, x0);
    } else {
      writePixel(x0, y0);
    }
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}

/***************************************************************************************************************/
void Displays5::writePixel(int x, int y) {
  drawPixel(x, y);
}

Circuit diagram...not fritzing...include all power supplies etc.

The only connection to this display is the USB connection to the Teensy.

The schematic is on the display's website that I linked to. Here is the specific link to the schematic for the board the teensy plugs into: teensy40_SSD1963_800x480_LCD_rev_A.pdf (shopify.com)

Nothing hardware wise has been modified from the original purchased display.

I do not jump to unknown websites...place your circuit diagram here.

teensy40_SSD1963_800x480_LCD_rev_A.pdf (176.7 KB)

I tried setting the delay out to 3.5 seconds but that didn't change anything. I also thought it might be a power shortage from the PC's USB port that typically only supplies .5A, so I plugged it into a 2.1 amp charger and that didn't help either.

This thing is delivered complete with no assembly required. You just open the box and plug the USB cable into the Teensy 4. Everything that follows is software. It comes with software that is very kludgy and is specific to CAN bus usage in the auto and marine industry. I'm not interested in that, but I am very interested in a 5" display with a 16-bit parallel interface running on a Teensy with a 600MHz clock that can be programmed using Arduino IDE2.

The SSD1963 display controller has a ton of settings and I suspect I haven't got it exactly right. What I have so far is controller start code from various examples found on the web. It could be poor HW design, but for now I'm thinking the problem is on the SSD1963 startup code.

I also thought it might be the Teensy is running too fast for it, but that doesn't seem right because when it starts correctly it just runs great.

I found a note in the docs for the SSD1963 that says the controller cannot be programmed faster that 5M words/sec until the PLL is locked. The PLL gets locked in the startup code, so I inserted a 1usec delay after each command in the startup routine and it appears to have solved the problem. It has successfully started about 35 times in a row now. Before that it was almost 50/50 good/bad starts.

That Teensy 4.0 running at 600MHz is one fast little puppy.

Now to see if I can flood it with graphics at high speed or if that too needs to be throttled.

As it turns out, there are only 2 delay Microsecond commands needed at the very beginning of the startDisplay as shown here:

 digitalWriteFast(B_RST, LOW);
  delay(10);
  digitalWriteFast(B_RST, HIGH);
  delay(10);
  digitalWriteFast(B_CS, LOW);

  LCD_Write_COM(0xE2);  //PLL multiplier, set PLL clock to 120M
  delayMicroseconds(1);
  LCD_Write_DATA(0x36);  //N=0x36 for 6.5M, 0x23 for 10M crystal
  delayMicroseconds(1);
  LCD_Write_DATA(0x02);
  LCD_Write_DATA(0x54);

Once the PLL clock and crystal frequency are set, all other delay microsecond commands were removed, and everything still works.

As for speed, this display has 800x480 pixels that is 384,000 pixels total. On my first test, I filled the screen 10 times in 25.624ms. That is screamingly fast!

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