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);
}