In the display.h file the line at 59 is:
class ssd1963 //: public Print
That class is instantiated in the .ino file at line 29 with:
ssd1963 tft(RS, WR, CS, RST);
If the class definition is changed so that it inherits from Print like this:
class ssd1963 : public Print
Then the instantiation in the .ino file fails with:
Arduino: 1.8.19 (Windows 10), TD: 1.57, Board: "Teensy 4.0, Serial, 600 MHz, Faster, US English"
Teensy40_800x400:27: error: cannot declare variable 'tft' to be of abstract type 'ssd1963'
ssd1963 tft(RS, WR, CS, RST);
^
In file included from C:\Users\Mike\Desktop\Teensy40_800x400\Teensy40_800x400.ino:1:0:
C:\Users\Mike\Desktop\Teensy40_800x400\display.h:59:8: note: because the following virtual functions are pure within 'ssd1963':
class ssd1963 : public Print
^
In file included from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/Stream.h:24:0,
from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/HardwareSerial.h:115,
from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/WProgram.h:46,
from C:\Users\Mike\AppData\Local\Temp\arduino_build_191811\pch\Arduino.h:6:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/Print.h:58:17: note: virtual size_t Print::write(uint8_t)
virtual size_t write(uint8_t b) = 0;
^
Multiple libraries were found for "gfxfont.h"
Used: C:\Users\Mike\Documents\Arduino\libraries\Adafruit_GFX_Library
Not used: C:\Users\Mike\Documents\Arduino\libraries\arduino_652672
Not used: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\ssd1351
cannot declare variable 'tft' to be of abstract type 'ssd1963'
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
So, my question is, what am I doing wrong and how can I fix this?
Teensy40_800x480.ino
#include "display.h"
#include <C:\Users\Mike\Documents\Arduino\libraries\Adafruit_GFX_Library\Fonts\FreeMono24pt7b.h>
#define RS 26
#define WR 27
#define CS 25
#define RST 28
#define BL_CTL 21
#define TFT_DC 9
#define TFT_CS 10
#define DWIDTH 800
#define DHEIGHT 480
#define DELTA_C 21
#define DELTA_R 30
#define BASE_R 22
uint32_t c = 0;
uint32_t mask = 0;
int16_t cnt = 0;
bool _cp437 = false;
uint8_t w = 0;
uint8_t h = 0;
GFXfont *gfxFont;
ssd1963 tft(RS, WR, CS, RST);
void setup()
{
setFont(&FreeMono24pt7b);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(BL_CTL, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
digitalWrite(BL_CTL, HIGH);
digitalWriteFast(LED_BUILTIN, LOW);
tft.print(300, 300, "abc", WHITE, BLACK);
tft.startDisplay();
tft.setColor(BLACK);
tft.fillRect(0, 0, 799, 479);
struct GFXglyph
{
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
uint8_t width; ///< Bitmap dimensions in pixels
uint8_t height; ///< Bitmap dimensions in pixels
uint8_t xAdvance; ///< Distance to advance cursor (x axis)
int8_t xOffset; ///< X dist from cursor pos to UL corner
int8_t yOffset; ///< Y dist from cursor pos to UL corner
};
for (int i = 0; i < 26; i++)
{
drawChar(0 + 30 * i, 100, (unsigned char)'a' + i, WHITE, BLACK, 1, 1);
drawChar(0 + 30 * i, 150, (unsigned char)'A' + i, WHITE, BLACK, 1, 1);
if (i < 17)
drawChar(0 + 30 * i, 200, (unsigned char)'0' + i, WHITE, BLACK, 1, 1);
}
// dump(31);
}
/************************************************************************************/
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c)
{
return gfxFont->glyph + c;
}
/************************************************************************************/
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__
}
/************************************************************************************/
void drawChar(int16_t x, int16_t y, unsigned char c,
uint16_t fg, uint16_t bg, uint16_t size_x,
uint16_t size_y)
{
// Custom font
{
// Character is assumed previously filtered by write() to eliminate
// newlines, returns, non-printable characters, etc. Calling
// drawChar() directly with 'bad' characters of font may cause mayhem!
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);
w = pgm_read_byte(&glyph->width);
h = pgm_read_byte(&glyph->height);
int8_t xo = pgm_read_byte(&glyph->xOffset),
yo = pgm_read_byte(&glyph->yOffset);
uint8_t xx, yy, bits = 0, bit = 0;
int16_t xo16 = 0, yo16 = 0;
if (size_x > 1 || size_y > 1)
{
xo16 = xo;
yo16 = yo;
}
// Todo: Add character clipping here
// NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
// THIS IS ON PURPOSE AND BY DESIGN. The background color feature
// has typically been used with the 'classic' font to overwrite old
// screen contents with new data. This ONLY works because the
// characters are a uniform size; it's not a sensible thing to do with
// proportionally-spaced fonts with glyphs of varying sizes (and that
// may overlap). To replace previously-drawn text when using a custom
// font, use the getTextBounds() function to determine the smallest
// rectangle encompassing a string, erase the area with fillRect(),
// then draw new text. This WILL infortunately 'blink' the text, but
// is unavoidable. Drawing 'background' pixels will NOT fix this,
// only creates a new set of problems. Have an idea to work around
// this (a canvas object type for MCUs that can afford the RAM and
// displays supporting setAddrWindow() and pushColors()), but haven't
// implemented this yet.
//Serial.println("h");
// startWrite();
for (yy = 0; yy < h; yy++)
{
for (xx = 0; xx < w; xx++)
{
if (!(bit++ & 7))
{
bits = pgm_read_byte(&bitmap[bo++]);
}
if (bits & 0x80)
{
if (size_x == 1 && size_y == 1)
{
tft.drawPixel(x + xo + xx, y + yo + yy, fg);
}
else
{
tft.fillRect(x + (xo16 + xx) * size_x, y + (yo16 + yy) * size_y, size_x, size_y, fg);
}
}
bits <<= 1;
}
}
// endWrite();
} // End classic vs custom font
}
void dump(int n)
{
Serial.print(FreeMono24pt7bGlyphs[n].bitmapOffset); Serial.print(" ");
Serial.print(FreeMono24pt7bGlyphs[n].width); Serial.print(" ");
Serial.print(FreeMono24pt7bGlyphs[n].height); Serial.print(" ");
Serial.print(FreeMono24pt7bGlyphs[n].xAdvance); Serial.print(" ");
Serial.print(FreeMono24pt7bGlyphs[n].xOffset); Serial.print(" ");
Serial.print(FreeMono24pt7bGlyphs[n].yOffset);
}
void setFont(const GFXfont *f)
{
if (f) // Font struct pointer passed in?
{
if (!gfxFont) // And no current font struct?
{
// Switching from classic to new font behavior.
// Move cursor pos down 6 pixels so it's on baseline.
// cursor_y += 6;
}
}
else if (gfxFont) // NULL passed. Current font struct defined?
{
// Switching from new to classic font behavior.
// Move cursor pos up 6 pixels so it's at top-left of char.
// cursor_y -= 6;
}
gfxFont = (GFXfont *)f;
}
void loop()
{
}
display.cpp
#include "Arduino.h"
#include "display.h"
#include <mine.h>
void _swap_int16_t(int16_t &a, int16_t &b)
{
int16_t t = a;
a = b;
b = t;
}
ssd1963:: ssd1963()
{
}
ssd1963:: ssd1963(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 ssd1963::tft_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 ssd1963::tft_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 ssd1963::print(int16_t x, int16_t y, String text, uint16_t fg, uint16_t bg)
{
int16_t len = text.length();
Serial.println(len, HEX);
}
void ssd1963::tft_Write_DATA(char VL)
{
digitalWriteFast(B_RS, HIGH);
tft_Write_Bus(0x00, VL);
}
void ssd1963::tft_Write_DATA(char VH, char VL)
{
digitalWriteFast(B_RS, HIGH);
tft_Write_Bus(VH, VL);
}
void ssd1963::tft_Write_COMMAND(char VL)
{
digitalWriteFast(B_RS, LOW);
tft_Write_Bus(0x00, VL);
}
void ssd1963::startDisplay(void)
{
digitalWriteFast(B_RST, LOW);
delay(10);
digitalWriteFast(B_RST, HIGH);
delay(10);
digitalWriteFast(B_CS, LOW);
tft_Write_COMMAND(0xE2); //PLL multiplier, set PLL clock to 120M
tft_Write_DATA(0x1E); //N=0x36 for 6.5M, 0x23 for 10M crystal
tft_Write_DATA(0x02);
tft_Write_DATA(0x54);
tft_Write_COMMAND(0xE0); //PLL enable
tft_Write_DATA(0x01);
delay(10);
tft_Write_COMMAND(0xE0);
tft_Write_DATA(0x03);
delay(10);
tft_Write_COMMAND(0x01); //Software reset
delay(50);
tft_Write_COMMAND(0xE6); //PLL setting for PCLK, depends on resolution
tft_Write_DATA(0x03);
tft_Write_DATA(0xFF);
tft_Write_DATA(0xFF);
tft_Write_COMMAND(0xB0); //tft SPECIFICATION
tft_Write_DATA(0x24);
tft_Write_DATA(0x00);
tft_Write_DATA(0x03); //Set HDP 799
tft_Write_DATA(0x1F);
tft_Write_DATA(0x01); //Set VDP 479
tft_Write_DATA(0xDF);
tft_Write_DATA(0x00);
tft_Write_COMMAND(0xB4); //HSYNC
tft_Write_DATA(0x03); //Set HT 928
tft_Write_DATA(0xA0);
tft_Write_DATA(0x00); //Set HPS 46
tft_Write_DATA(0x2E);
tft_Write_DATA(0x30); //Set HPW 48
tft_Write_DATA(0x00); //Set LPS 15
tft_Write_DATA(0x0F);
tft_Write_DATA(0x00);
tft_Write_COMMAND(0xB6); //VSYNC
tft_Write_DATA(0x02); //Set VT 525
tft_Write_DATA(0x0D);
tft_Write_DATA(0x00); //Set VPS 16
tft_Write_DATA(0x10);
tft_Write_DATA(0x10); //Set VPW 16
tft_Write_DATA(0x00); //Set FPS 8
tft_Write_DATA(0x08);
tft_Write_COMMAND(0xBA);
tft_Write_DATA(0x0F); //GPIO[3:0] out 1
tft_Write_COMMAND(0xB8);
tft_Write_DATA(0x07); //GPIO3=input, GPIO[2:0]=output
tft_Write_DATA(0x01); //GPIO0 normal
tft_Write_COMMAND(0x36); //Rotation
//tft_Write_DATA(0x22);
tft_Write_DATA(0x08);
tft_Write_COMMAND(0xF0); //pixel data interface
tft_Write_DATA(0x03); // 011 16-bit (565 format)
delay(10);
tft_Write_COMMAND(0x29); //display on
tft_Write_COMMAND(0xBE); //set PWM for B/L
tft_Write_DATA(0x06);
tft_Write_DATA(0xf0);
tft_Write_DATA(0x01);
tft_Write_DATA(0xf0);
tft_Write_DATA(0x00);
tft_Write_DATA(0x00);
tft_Write_COMMAND(0xd0);
tft_Write_DATA(0x0d);
tft_Write_COMMAND(0x2C);
digitalWriteFast(B_CS, HIGH);
}
void ssd1963::setColor(byte r, byte g, byte b)
{
fch = ((r & 248) | g >> 5);
fcl = ((g & 28) << 3 | b >> 3);
}
void ssd1963::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);
}
void ssd1963::setBackColor(byte r, byte g, byte b)
{
bch = ((r & 248) | g >> 5);
bcl = ((g & 28) << 3 | b >> 3);
}
void ssd1963::setBackColor(uint16_t bg)
{
byte r = (bg & 0xF800) >> 11;
byte g = (bg & 0x07E0) >> 5;
byte b = bg & 0x001F;
r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;
setBackColor(r, g, b);
}
void ssd1963::setXY(word x1, word y1, word x2, word y2)
{
tft_Write_COMMAND(0x2a);
tft_Write_DATA(x1 >> 8);
tft_Write_DATA(x1);
tft_Write_DATA(x2 >> 8);
tft_Write_DATA(x2);
tft_Write_COMMAND(0x2b);
tft_Write_DATA(y1 >> 8);
tft_Write_DATA(y1);
tft_Write_DATA(y2 >> 8);
tft_Write_DATA(y2);
tft_Write_COMMAND(0x2c);
}
void ssd1963::_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 ssd1963::fillRect(int16_t x1, int16_t y1, int16_t x2, int16_t 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 ssd1963::fillRect(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
{
setColor(color);
fillRect(x1, y1, x2, y2);
}
/**************************************************************************/
void ssd1963::drawCircle(int16_t x0, int16_t y0, int16_t r)
{
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t 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 ssd1963::drawRect(int x1, int y1, int x2, int y2)
{
int16_t w = x2 - x1, h = y2 - y1;
startWrite();
writeFastHLine(x1, y1, w);
writeFastHLine(x1, y1 + h - 1, w);
writeFastVLine(x1, y1, h);
writeFastVLine(x1 + w - 1, y1, h);
// drawLine(x1, y1, x2, y1);
// drawLine(x2, y1, x2, y2);
// drawLine(x2, y2, x1, y2);
// drawLine(x1, y2, x1, y1);
endWrite();
}
void ssd1963::startWrite()
{
digitalWriteFast(B_CS, LOW);
digitalWriteFast(B_RS, HIGH);
}
void ssd1963::endWrite()
{
digitalWriteFast(B_CS, HIGH);
}
void ssd1963::drawPixel(int16_t x, int16_t y)
{
digitalWriteFast(B_CS, LOW);
setXY (x, y, x, y);
tft_Write_DATA (fch, fcl);
digitalWriteFast(B_CS, HIGH);
}
void ssd1963::drawPixel(int16_t x, int16_t y, uint16_t color)
{
setColor(color);
drawPixel(x, y);
}
void ssd1963::drawLine(int x1, int y1, int x2, int y2)
{
unsigned int dx = (x2 > x1 ? x2 - x1 : x1 - x2);
short xstep = x2 > x1 ? 1 : -1;
unsigned int 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);
tft_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);
tft_Write_DATA (fch, fcl);
if (col == x2)
return;
col += xstep;
t += dy;
if (t >= 0)
{
row += ystep;
t -= dx;
}
}
}
digitalWriteFast(B_CS, HIGH);
}
/*************************************************************************************************/
/*!
@brief Draw a circle with filled color
@param x0 Center-point x coordinate
@param y0 Center-point y coordinate
@param r Radius of circle
*/
/**************************************************************************/
void ssd1963::fillCircle(int16_t x0, int16_t y0, int16_t r)
{
// Serial.println(x0);
startWrite();
writeFastVLine(x0, y0 - r, 2 * r + 1);
fillCircleHelper(x0, y0, r, 3, 0);
endWrite();
}
/**************************************************************************/
/*!
@brief Quarter-circle drawer with fill, used for circles and roundrects
@param x0 Center-point x coordinate
@param y0 Center-point y coordinate
@param r Radius of circle
@param corners Mask bits indicating which quarters we're doing
@param delta Offset from center-point, used for round-rects
*/
/**************************************************************************/
void ssd1963::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t corners, int16_t delta)
{
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
int16_t px = x;
int16_t 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 ssd1963::writeFastVLine(int16_t x, int16_t y, int16_t 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);
}
/**************************************************************************/
/*!
@brief Write a perfectly horizontal line, overwrite in subclasses if
startWrite is defined!
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
*/
/**************************************************************************/
void ssd1963::writeFastHLine(int16_t x, int16_t y, int16_t 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);
}
/**************************************************************************/
/*!
@brief Draw a perfectly vertical line (this is often optimized in a
subclass!)
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
*/
/**************************************************************************/
void ssd1963::drawFastVLine(int16_t x, int16_t y, int16_t h)
{
startWrite();
writeLine(x, y, x, y + h - 1);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a perfectly horizontal line (this is often optimized in a
subclass!)
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
*/
/**************************************************************************/
void ssd1963::drawFastHLine(int16_t x, int16_t y, int16_t w)
{
startWrite();
writeLine(x, y, x + w - 1, y);
endWrite();
}
/**************************************************************************/
/*!
@brief Write a pixel, overwrite in subclasses if startWrite is defined!
@param x x coordinate
@param y y coordinate @param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void ssd1963::writePixel(int16_t x, int16_t y)
{
drawPixel(x, y);
}
/**************************************************************************/
/*!
@brief Draw a triangle with no fill color
@param x0 Vertex #0 x coordinate
@param y0 Vertex #0 y coordinate
@param x1 Vertex #1 x coordinate
@param y1 Vertex #1 y coordinate
@param x2 Vertex #2 x coordinate
@param y2 Vertex #2 y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void ssd1963::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2)
{
drawLine(x0, y0, x1, y1);
drawLine(x1, y1, x2, y2);
drawLine(x2, y2, x0, y0);
}
/**************************************************************************/
/*!
@brief Draw a triangle with color-fill
@param x0 Vertex #0 x coordinate
@param y0 Vertex #0 y coordinate
@param x1 Vertex #1 x coordinate
@param y1 Vertex #1 y coordinate
@param x2 Vertex #2 x coordinate
@param y2 Vertex #2 y coordinate
@param color 16-bit 5-6-5 Color to fill/draw with
*/
/**************************************************************************/
void ssd1963::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2)
{
int16_t a, b, y, last;
// Sort coordinates by Y order (y2 >= y1 >= y0)
if (y0 > y1)
{ //zz
_swap_int16_t(y0, y1);
_swap_int16_t(x0, x1);
}
if (y1 > y2)
{
_swap_int16_t(y1, y2);
_swap_int16_t(x1, x2);
}
if (y0 > y1)
{
_swap_int16_t(y0, y1);
_swap_int16_t(x0, x1);
}
startWrite();
if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
a = b = x0;
if (x1 < a)
a = x1;
else if (x1 > b)
b = x1;
if (x2 < a)
a = x2;
else if (x2 > b)
b = x2;
writeFastHLine(a, y0, b - a + 1);
endWrite();
return;
}
int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0,
dx12 = x2 - x1, dy12 = y2 - y1;
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 (y1 == y2)
last = y1; // Include y1 scanline
else
last = y1 - 1; // Skip it
for (y = y0; y <= last; y++) {
a = x0 + sa / dy01;
b = x0 + sb / dy02;
sa += dx01;
sb += dx02;
/* longhand:
a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if (a > b)
_swap_int16_t(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 - y1);
sb = (int32_t)dx02 * (y - y0);
for (; y <= y2; y++) {
a = x1 + sa / dy12;
b = x0 + sb / dy02;
sa += dx12;
sb += dx02;
/* longhand:
a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if (a > b)
_swap_int16_t(a, b);
writeFastHLine(a, y, b - a + 1);
}
endWrite();
}
/**************************************************************************/
void ssd1963::fillScreen(uint16_t color)
{
setColor(color);
fillRect(0, 0, DWIDTH - 1, DHEIGHT - 1);
}
/**************************************************************************/
/*!
@brief Write a line. Bresenham's algorithm - thx wikpedia
@param x0 Start point x coordinate
@param y0 Start point y coordinate
@param x1 End point x coordinate
@param y1 End point y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void ssd1963::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
{
#if defined(ESP8266)
yield();
#endif
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
_swap_int16_t(x0, y0);
_swap_int16_t(x1, y1);
}
if (x0 > x1) {
_swap_int16_t(x0, x1);
_swap_int16_t(y0, y1);
}
int16_t dx, dy;
dx = x1 - x0;
dy = abs(y1 - y0);
int16_t err = dx / 2;
int16_t 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;
}
}
}
/**************************************************************************/
/*!
@brief Draw a rounded rectangle with no fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param r Radius of corner rounding
@param color 16-bit 5-6-5 Color to draw with
*/
void ssd1963::drawRoundRect(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t r)
{
int16_t w = x2 - x1;
int16_t h = y2 - y1;
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
if (r > max_radius)
r = max_radius;
// smarter version
startWrite();
writeFastHLine(x1 + r, y1, w - 2 * r); // Top
writeFastHLine(x1 + r, y1 + h - 1, w - 2 * r); // Bottom
writeFastVLine(x1, y1 + r, h - 2 * r); // Left
writeFastVLine(x1 + w - 1, y1 + r, h - 2 * r); // Right
// draw four corners
drawCircleHelper(x1 + r, y1 + r, r, 1);
drawCircleHelper(x1 + w - r - 1, y1 + r, r, 2);
drawCircleHelper(x1 + w - r - 1, y1 + h - r - 1, r, 4);
drawCircleHelper(x1 + r, y1 + h - r - 1, r, 8);
endWrite();
}
/**************************************************************************/
/*!
@brief Quarter-circle drawer, used to do circles and roundrects
@param x0 Center-point x coordinate
@param y0 Center-point y coordinate
@param r Radius of circle
@param cornername Mask bit #1 or bit #2 to indicate which quarters of
the circle we're doing
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void ssd1963::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername)
{
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
while (x < y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
if (cornername & 0x4) {
writePixel(x0 + x, y0 + y);
writePixel(x0 + y, y0 + x);
}
if (cornername & 0x2) {
writePixel(x0 + x, y0 - y);
writePixel(x0 + y, y0 - x);
}
if (cornername & 0x8) {
writePixel(x0 - y, y0 + x);
writePixel(x0 - x, y0 + y);
}
if (cornername & 0x1) {
writePixel(x0 - y, y0 - x);
writePixel(x0 - x, y0 - y);
}
}
}
/**************************************************************************/
/*!
@brief Draw a rounded rectangle with fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param r Radius of corner rounding
@param color 16-bit 5-6-5 Color to draw/fill with
*/
/**************************************************************************/
void ssd1963::fillRoundRect(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t r)
{
int16_t w = x2 - x1;
int16_t h = y2 - y1;
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
if (r > max_radius)
r = max_radius;
// smarter version
startWrite();
writeFillRect(x1 + r, y1, w - 2 * r, h);
// draw four corners
fillCircleHelper(x1 + w - r - 1, y1 + r, r, 1, h - 2 * r - 1);
fillCircleHelper(x1 + r, y1 + r, r, 2, h - 2 * r - 1);
endWrite();
}
/**************************************************************************/
/*!
@brief Write a rectangle completely with one color, overwrite in
subclasses if startWrite is defined!
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void ssd1963::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h)
{
// Overwrite in subclasses if desired!
fillRect(x, y, x + w, y + h);
// Serial.print(x); Serial.print(" "); Serial.print(y); Serial.print(" "); Serial.print(w); Serial.print(" "); Serial.print(h);
}
/************************************************************************************************/
void ssd1963::invertDisplay()
{
digitalWriteFast(B_CS, LOW); // chip select on
tft_Write_COMMAND(0x21); // invert display
digitalWriteFast(B_CS, HIGH); // chip select off
}
/************************************************************************************************/
void ssd1963::unInvertDisplay()
{
digitalWriteFast(B_CS, LOW); // chip select on
tft_Write_COMMAND(0x20); // unInvert display
digitalWriteFast(B_CS, HIGH); // chip select off
}
display.h
#ifndef __ssd1963_H__
#define __ssd1963_H__
#include "Arduino.h"
#include "gfxfont.h"
#include "Print.h"
// Color definitions
#define NAVY 0x000F ///< 0, 0, 123
#define DARKGREEN 0x03E0 ///< 0, 125, 0
#define DARKCYAN 0x03EF ///< 0, 125, 123
#define MAROON 0x7800 ///< 123, 0, 0
#define PURPLE 0x780F ///< 123, 0, 123
#define OLIVE 0x7BE0 ///< 123, 125, 0
#define LIGHTGREY 0xC618 ///< 198, 195, 198
#define DARKGREY 0x7BEF ///< 123, 125, 123
#define BLUE 0x001F ///< 0, 0, 255
#define GREEN 0x07E0 ///< 0, 255, 0
#define CYAN 0x07FF ///< 0, 255, 255
#define RED 0xF800 ///< 255, 0, 0
#define MAGENTA 0xF81F ///< 255, 0, 255
#define YELLOW 0xFFE0 ///< 255, 255, 0
#define ORANGE 0xFD20 ///< 255, 165, 0
#define GREENYELLOW 0xAFE5 ///< 173, 255, 41
#define PINK 0xFC18 ///< 255, 130, 198
#define BACKGROUND 0xA514
#define BUTTONCOLOR 0xAD75
#define BLACK 0x0000
#define BLUE 0x001F
#define DARKBLUE 0x0016
#define YELLOW 0xFFE0
#define RED 0xF800
#define DARKRED 0xA800
#define GREEN 0x07E0
#define WHITE 0xFFFF
#define LIGHTGRAY 0xb618
#define GRAY 0x7410
#define DARKGRAY 0x3208
// 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
class ssd1963 //: public Print
{
public:
ssd1963();
ssd1963(int RS, int WR, int CS, int RST);
void startWrite();
void endWrite();
void tft_Write_Bus(char ch, char cl);
void tft_Write_DATA(char VL);
void tft_Write_COMMAND(char VL);
void writeFastVLine(int16_t x, int16_t y, int16_t h);
void writeFastHLine(int16_t x, int16_t y, int16_t w);
void drawFastHLine(int16_t x, int16_t y, int16_t w);
void drawFastVLine(int16_t x, int16_t y, int16_t h);
void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);
void writePixel(int16_t x, int16_t y);
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h);
void tft_Write_DATA(char VH, char VL);
void startDisplay(void);
void setColor(byte r, byte g, byte b);
void setColor(uint16_t color);
void setBackColor(byte r, byte g, byte b);
void setBackColor(uint16_t bg);
void invertDisplay();
void unInvertDisplay();
void print(int16_t x, int16_t y, String text, uint16_t fg, uint16_t bg);
void setXY(word x1, word y1, word x2, word y2);
void _fast_fill_16(int ch, int cl, long pix);
void fillRect(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
void fillRect(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
void drawRect(int x1, int y1, int x2, int y2);
void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r);
void fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r);
void drawCircle(int16_t x0, int16_t y0, int16_t r);
void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername);
void drawPixel(int16_t x, int16_t y);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors);
void inline tft_Write_Bus16(uint16_t data);
void drawLine(int x1, int y1, int x2, int y2);
void fillCircle(int16_t x0, int16_t y0, int16_t r);
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t corners, int16_t delta);
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2);
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2);
void fillScreen(uint16_t color);
int16_t DWIDTH = 800;
int16_t DHEIGHT = 480;
uint8_t fch, fcl, bch, bcl;
uint8_t B_RS, B_WR, B_CS, B_RST;
private:
};
#endif