2022-02-10 21:16:24 +00:00
|
|
|
/* SmartyKit 1 - 2.8" TFT 320x240 Display driver
|
|
|
|
* http://www.smartykit.io/
|
|
|
|
* Copyright (C) 2019-2022, Sergey Panarin <contact@smartykit.io>
|
|
|
|
*
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Smarty_TFT.h"
|
|
|
|
|
|
|
|
int tftPortrait = TFT_PORTRAIT;
|
|
|
|
|
|
|
|
volatile int screenRow = 0;
|
|
|
|
volatile int screenCol = 0;
|
|
|
|
|
|
|
|
// TO-DO: blinking cursor (driver function)
|
|
|
|
|
|
|
|
|
|
|
|
SmartyKit_DisplayDriver::SmartyKit_DisplayDriver(int cs, int dc, int mosi, int clk, int rst, int miso)
|
|
|
|
{
|
|
|
|
_dc = dc;
|
|
|
|
_rst = rst;
|
|
|
|
_cs = cs;
|
|
|
|
_sck = clk;
|
|
|
|
_mosi = mosi;
|
|
|
|
_miso = miso;
|
|
|
|
|
|
|
|
connection = TFT_SOFT_SPI;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::setup(uint16_t setupColor, uint16_t setupBgColor, char* madeWithLoveString)
|
|
|
|
{
|
|
|
|
initSPI();
|
|
|
|
|
|
|
|
uint8_t cmd, x, numArgs;
|
|
|
|
const uint8_t *addr = initcmd;
|
|
|
|
while ((cmd = pgm_read_byte(addr++)) > 0) {
|
|
|
|
x = pgm_read_byte(addr++);
|
|
|
|
numArgs = x & 0x7F;
|
|
|
|
|
|
|
|
#if defined(_SMARTY_DEBUG_)
|
|
|
|
Serial.print(F("Initcmd: cmd = "));Serial.print(cmd, HEX);
|
|
|
|
Serial.print(F(", x = "));Serial.print(x, HEX);
|
|
|
|
Serial.print(F(", addr = "));Serial.print((uint8_t)addr, HEX);
|
|
|
|
Serial.print(F(", numArgs = "));Serial.print(numArgs, HEX);
|
|
|
|
Serial.println();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sendCommand(cmd, addr, numArgs);
|
|
|
|
delay(10);
|
|
|
|
addr += numArgs;
|
|
|
|
if (x & 0x80)
|
|
|
|
delay(150);
|
|
|
|
}
|
|
|
|
|
|
|
|
clipScreen = SCREEN_FULL_SCREEN;
|
|
|
|
scrollLine = 0;
|
|
|
|
cursor_x = 0;
|
|
|
|
cursor_y = 0;
|
|
|
|
textsize_x = 1;
|
|
|
|
textsize_y = 1;
|
|
|
|
_TFTwidth = ILI9341_TFTWIDTH;
|
|
|
|
_TFTheight = ILI9341_TFTHEIGHT;
|
|
|
|
_workingScreenWidth = SCREEN_WIDTH;
|
|
|
|
_workingScreenHeight = SCREEN_HEIGHT;
|
|
|
|
screen_col = 0;
|
|
|
|
screen_row = 0;
|
|
|
|
|
|
|
|
color = setupColor;
|
|
|
|
bgColor = setupBgColor;
|
|
|
|
|
|
|
|
if (tftPortrait == TFT_PORTRAIT)
|
|
|
|
{
|
|
|
|
setRotation(0);
|
|
|
|
clearFullScreen(bgColor);
|
|
|
|
//start right from the top-left corner
|
|
|
|
_workingScreenTopMargin = 0;
|
|
|
|
_workingScreenLeftMargin = 0;
|
|
|
|
}
|
|
|
|
if (tftPortrait == TFT_LANDSCAPE)
|
|
|
|
{
|
|
|
|
setRotation(3);
|
|
|
|
clearFullScreen(bgColor);
|
|
|
|
_workingScreenTopMargin = (_TFTheight - SCREEN_ROWS*LINE_HEIGHT)/2;
|
|
|
|
_workingScreenLeftMargin = (_TFTwidth - SCREEN_COLS*LINE_WIDTH)/2;
|
|
|
|
}
|
|
|
|
//drawing splash screen
|
|
|
|
strcpy(madeWithLove, madeWithLoveString);
|
|
|
|
splashScreen();
|
|
|
|
|
|
|
|
if (tftPortrait == TFT_PORTRAIT)
|
|
|
|
{
|
|
|
|
//set built-in hardware scrolling
|
|
|
|
setScrollMargins(0, ILI9341_TFTHEIGHT - SCREEN_HEIGHT);
|
|
|
|
clipScreen = SCREEN_CLIPPED;
|
|
|
|
}
|
|
|
|
|
|
|
|
bCursorOn = false;
|
|
|
|
setCursor(0,0);
|
|
|
|
clearScreen(bgColor);
|
2022-04-27 19:13:27 +00:00
|
|
|
// test ASCII art (a person)
|
|
|
|
// print(' ',color);print('o', color);print(' ', color); print('\n', color);
|
|
|
|
// print('/',color);print('|', color);print('\\', color); print('\n', color);
|
|
|
|
// print('/',color);print(' ', color);print('\\', color); print('\n', color);
|
2022-02-10 21:16:24 +00:00
|
|
|
// startup ASCII art
|
2022-04-27 19:13:27 +00:00
|
|
|
ASCIIart();
|
2022-02-10 21:16:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-27 19:13:27 +00:00
|
|
|
void SmartyKit_DisplayDriver::ASCIIart(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
char c = '\0';
|
|
|
|
char* ptrBuffer;
|
|
|
|
|
|
|
|
for (int i = 0; i < SCREEN_ROWS; i++)
|
|
|
|
{
|
|
|
|
ptrBuffer = (char*) malloc(2*SCREEN_COLS);
|
|
|
|
if (ptrBuffer != NULL)
|
|
|
|
{
|
|
|
|
//reading current string from PROGMEM to RAM
|
|
|
|
strcpy_P(ptrBuffer, (char *)pgm_read_word(&(string_table[i])));
|
|
|
|
|
|
|
|
for (int j = 0; j < SCREEN_COLS; j++)
|
|
|
|
{
|
|
|
|
c = ptrBuffer[j];
|
|
|
|
print(c,color);
|
|
|
|
}
|
|
|
|
free(ptrBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-10 21:16:24 +00:00
|
|
|
void SmartyKit_DisplayDriver::initSPI(void)
|
|
|
|
{
|
|
|
|
if (_cs >= 0) {
|
|
|
|
pinMode(_cs, OUTPUT);
|
|
|
|
digitalWrite(_cs, HIGH); // Deselect
|
|
|
|
delay(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
pinMode(_dc, OUTPUT);
|
|
|
|
digitalWrite(_dc, HIGH); // Data mode
|
|
|
|
|
|
|
|
if (connection == TFT_HARD_SPI)
|
|
|
|
{
|
|
|
|
pinMode(SS, OUTPUT);
|
|
|
|
// SPI.begin();
|
|
|
|
spiClass = &SPI;
|
|
|
|
|
|
|
|
#if defined(_SMARTY_DEBUG_)
|
|
|
|
Serial.print(F("SmartyKit TFT_HARD_SPI freq = "));Serial.println(DEFAULT_SPI_FREQ, DEC);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
spiSettings = SPISettings(DEFAULT_SPI_FREQ, MSBFIRST, SPI_MODE0);
|
|
|
|
spiClass->begin();
|
|
|
|
spiClass->beginTransaction(spiSettings);
|
|
|
|
pinMode(SS, OUTPUT);
|
|
|
|
}
|
|
|
|
else if (connection == TFT_SOFT_SPI)
|
|
|
|
{
|
|
|
|
#if defined(_SMARTY_DEBUG_)
|
|
|
|
Serial.println(F("SmartyKit TFT_SOFT_SPI"));
|
|
|
|
#endif
|
|
|
|
pinMode(_mosi, OUTPUT);
|
|
|
|
digitalWrite(_mosi, LOW);
|
|
|
|
pinMode(_sck, OUTPUT);
|
|
|
|
digitalWrite(_sck, LOW);
|
|
|
|
if (_miso >= 0) {
|
|
|
|
pinMode(_miso, INPUT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_rst >= 0) {
|
|
|
|
// Toggle _rst low to reset
|
|
|
|
pinMode(_rst, OUTPUT);
|
|
|
|
digitalWrite(_rst, HIGH);
|
|
|
|
delay(100);
|
|
|
|
digitalWrite(_rst, LOW);
|
|
|
|
delay(100);
|
|
|
|
digitalWrite(_rst, HIGH);
|
|
|
|
delay(200);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::splashScreen()
|
|
|
|
{
|
|
|
|
int logoWidth = 19;
|
|
|
|
//draw Smarty logo in the center
|
|
|
|
if (rotation == 0 || rotation == 3)
|
|
|
|
{
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(_TFTwidth / 2 - logoWidth/2, _TFTheight / 2 - logoWidth/2, logoWidth, logoWidth);
|
|
|
|
//white filled square
|
|
|
|
for (uint16_t i = 0; i < logoWidth; i++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < logoWidth; x++)
|
|
|
|
SPI_WRITE16(ILI9341_WHITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
int logoInnerWidth = logoWidth/2;
|
|
|
|
setAddrWindow(_TFTwidth / 2 - logoInnerWidth/2, _TFTheight / 2 - logoInnerWidth/2, logoInnerWidth, logoInnerWidth);
|
|
|
|
//black filled square inside the white one
|
|
|
|
for (uint16_t i = 0; i < logoInnerWidth; i++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < logoInnerWidth; x++)
|
|
|
|
SPI_WRITE16(ILI9341_BLACK);
|
|
|
|
}
|
|
|
|
endWrite();
|
|
|
|
|
|
|
|
delay(1000);
|
|
|
|
|
|
|
|
//print 'Made with love by...'
|
|
|
|
int madeWithLoveLength = strlen(madeWithLove);
|
|
|
|
setCursor(_TFTwidth / 2 - (madeWithLoveLength*LINE_WIDTH)/2, _TFTheight - LINE_HEIGHT- 4, CURSOR_ABSOLUTE);
|
|
|
|
for (int i = 0; i < madeWithLoveLength; i++)
|
|
|
|
{
|
|
|
|
if (madeWithLove[i] == '\x03') //heart
|
|
|
|
print(madeWithLove[i], ILI9341_RED);
|
|
|
|
else
|
|
|
|
print(madeWithLove[i], ILI9341_WHITE);
|
|
|
|
delay(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
delay(500);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void SmartyKit_DisplayDriver::startWrite(void) {
|
|
|
|
SPI_BEGIN_TRANSACTION();
|
|
|
|
if (_cs >= 0)
|
|
|
|
SPI_CS_LOW();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void SmartyKit_DisplayDriver::endWrite(void) {
|
|
|
|
if (_cs >= 0)
|
|
|
|
SPI_CS_HIGH();
|
|
|
|
SPI_END_TRANSACTION();
|
|
|
|
}
|
|
|
|
void SmartyKit_DisplayDriver::writeCommand(uint8_t cmd) {
|
|
|
|
SPI_DC_LOW();
|
|
|
|
spiWrite(cmd);
|
|
|
|
SPI_DC_HIGH();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::sendCommand(uint8_t commandByte, const uint8_t *dataBytes,
|
|
|
|
uint8_t numDataBytes) {
|
|
|
|
startWrite();
|
|
|
|
|
|
|
|
#if defined(_SMARTY_DEBUG_)
|
|
|
|
Serial.print(F("PGM -> "));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
writeCommand(commandByte);
|
|
|
|
|
|
|
|
for (int i = 0; i < numDataBytes; i++) {
|
|
|
|
#if defined(_SMARTY_DEBUG_)
|
|
|
|
Serial.print(F("arg")); Serial.print(i+1, DEC); Serial.print(F(" = "));
|
|
|
|
#endif
|
|
|
|
uint8_t dataByte = pgm_read_byte(dataBytes++);
|
|
|
|
dataByte &= 0xFF;
|
|
|
|
spiWrite(dataByte);
|
|
|
|
}
|
|
|
|
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::sendCommand(uint8_t commandByte, uint8_t *dataBytes,
|
|
|
|
uint8_t numDataBytes) {
|
|
|
|
startWrite();
|
|
|
|
|
|
|
|
writeCommand(commandByte);
|
|
|
|
|
|
|
|
for (int i = 0; i < numDataBytes; i++) {
|
|
|
|
spiWrite(*dataBytes); // Send the data bytes
|
|
|
|
dataBytes++;
|
|
|
|
}
|
|
|
|
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::spiWrite(uint8_t b) {
|
|
|
|
if (connection == TFT_HARD_SPI) {
|
|
|
|
#if defined(__AVR__)
|
|
|
|
AVR_WRITESPI(b);
|
|
|
|
#else
|
|
|
|
char c = spiClass->transfer(b);
|
|
|
|
#if defined(_SMARTY_DEBUG_)
|
|
|
|
Serial.print(F("spiWrite = "));Serial.println(c, HEX);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
} else if (connection == TFT_SOFT_SPI)
|
|
|
|
{
|
|
|
|
for (uint8_t bit = 0; bit < 8; bit++) {
|
|
|
|
if (b & 0x80)
|
|
|
|
SPI_MOSI_HIGH();
|
|
|
|
else
|
|
|
|
SPI_MOSI_LOW();
|
|
|
|
SPI_SCK_HIGH();
|
|
|
|
b <<= 1;
|
|
|
|
SPI_SCK_LOW();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::setAddrWindow(uint16_t x1, uint16_t y1, uint16_t w,
|
|
|
|
uint16_t h) {
|
|
|
|
uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1);
|
|
|
|
writeCommand(ILI9341_CASET); // Column address set
|
|
|
|
SPI_WRITE16(x1);
|
|
|
|
SPI_WRITE16(x2);
|
|
|
|
writeCommand(ILI9341_PASET); // Row address set
|
|
|
|
SPI_WRITE16(y1);
|
|
|
|
SPI_WRITE16(y2);
|
|
|
|
writeCommand(ILI9341_RAMWR); // Write to RAM
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::SPI_WRITE16(uint16_t w) {
|
|
|
|
|
|
|
|
if (connection == TFT_HARD_SPI) {
|
|
|
|
#if defined(__AVR__)
|
|
|
|
AVR_WRITESPI(w >> 8);
|
|
|
|
AVR_WRITESPI(w);
|
|
|
|
#endif
|
|
|
|
} else if (connection == TFT_SOFT_SPI) {
|
|
|
|
for (uint8_t bit = 0; bit < 16; bit++) {
|
|
|
|
if (w & 0x8000)
|
|
|
|
SPI_MOSI_HIGH();
|
|
|
|
else
|
|
|
|
SPI_MOSI_LOW();
|
|
|
|
SPI_SCK_HIGH();
|
|
|
|
SPI_SCK_LOW();
|
|
|
|
w <<= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void SmartyKit_DisplayDriver::writeColor(uint16_t color, uint32_t len)
|
|
|
|
{
|
|
|
|
for (uint16_t i = 0; i < len; i++)
|
|
|
|
SPI_WRITE16(color);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* user functions */
|
|
|
|
void SmartyKit_DisplayDriver::setCursor(int16_t x, int16_t y, uint8_t relative = CURSOR_RELATIVE) {
|
|
|
|
if (relative == CURSOR_RELATIVE)
|
|
|
|
{
|
|
|
|
cursor_x = _workingScreenLeftMargin + x;
|
|
|
|
cursor_y = _workingScreenTopMargin + y;
|
|
|
|
}
|
|
|
|
else if (relative == CURSOR_ABSOLUTE)
|
|
|
|
{
|
|
|
|
cursor_x = x;
|
|
|
|
cursor_y = y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::print(uint8_t c, uint16_t color = ILI9341_GREEN)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (c == '\n') { // Newline?
|
|
|
|
cursor_x = _workingScreenLeftMargin; // Reset x to zero,
|
|
|
|
cursor_y += textsize_y * 8; // advance y one line
|
|
|
|
|
|
|
|
int maxHeight = _TFTheight;
|
|
|
|
if (clipScreen == SCREEN_CLIPPED)
|
|
|
|
maxHeight = _workingScreenHeight + _workingScreenTopMargin;
|
|
|
|
if (cursor_y >= maxHeight )
|
|
|
|
{
|
|
|
|
scrollToNextLine();
|
|
|
|
cursor_y -= textsize_y * 8;
|
|
|
|
}
|
|
|
|
} else if (c != '\r') { // Ignore carriage returns
|
|
|
|
if ((cursor_x + textsize_x * 6) > _workingScreenLeftMargin + _workingScreenWidth) { // Off right?
|
|
|
|
cursor_x = _workingScreenLeftMargin; // Reset x to zero,
|
|
|
|
cursor_y += textsize_y * 8; // advance y one line
|
|
|
|
}
|
|
|
|
|
|
|
|
//autoscroll mode
|
|
|
|
int maxHeight = _TFTheight;
|
|
|
|
if (clipScreen == SCREEN_CLIPPED)
|
|
|
|
maxHeight = _workingScreenHeight + _workingScreenTopMargin;
|
|
|
|
if (cursor_y >= maxHeight)
|
|
|
|
{
|
|
|
|
scrollToNextLine();
|
|
|
|
cursor_y -= textsize_y * 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
//converting screen coordinates to memory coordinates
|
|
|
|
int yLine;
|
|
|
|
if ((scrollLine + cursor_y) < maxHeight)
|
|
|
|
yLine = scrollLine + cursor_y;
|
|
|
|
else
|
|
|
|
yLine = (scrollLine + cursor_y) - maxHeight;
|
|
|
|
|
|
|
|
drawChar(cursor_x, yLine, c, color, bgColor, textsize_x);
|
|
|
|
cursor_x += textsize_x * 6; // Advance x one char
|
|
|
|
|
|
|
|
//TO-DO: set blinking cursor position next to printed char
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)
|
|
|
|
{
|
|
|
|
uint8_t size_x = size;
|
|
|
|
uint8_t size_y = size;
|
|
|
|
|
|
|
|
if ((x >= _TFTwidth) || // Clip right
|
|
|
|
(y >= _TFTheight) || // Clip bottom
|
|
|
|
((x + 6 * size_x - 1) < 0) || // Clip left
|
|
|
|
((y + 8 * size_y - 1) < 0)) // Clip top
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
startWrite();
|
|
|
|
|
|
|
|
for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns
|
|
|
|
uint8_t line = pgm_read_byte(&font[c * 5 + i]);
|
|
|
|
|
|
|
|
for (int8_t j = 0; j < 8; j++, line >>= 1) {
|
|
|
|
if (line & 1) {
|
|
|
|
if (size_x == 1 && size_y == 1)
|
|
|
|
writePixel(x + i, y + j, color);
|
|
|
|
else
|
|
|
|
writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y,
|
|
|
|
color);
|
|
|
|
} else if (bg != color) {
|
|
|
|
if (size_x == 1 && size_y == 1)
|
|
|
|
writePixel(x + i, y + j, bg);
|
|
|
|
else
|
|
|
|
writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bg != color) { // If opaque, draw vertical line for last column
|
|
|
|
if (size_x == 1 && size_y == 1)
|
|
|
|
writeFastVLine(x + 5, y, 8, bg);
|
|
|
|
else
|
|
|
|
writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg);
|
|
|
|
}
|
|
|
|
|
|
|
|
endWrite();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::writePixel(int16_t x, int16_t y, uint16_t color)
|
|
|
|
{
|
|
|
|
// Clip first...
|
|
|
|
if ((x >= 0) && (x < _TFTwidth) && (y >= 0) && (y < _TFTheight)) {
|
|
|
|
// THEN set up transaction (if needed) and draw...
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(x, y, 1, 1);
|
|
|
|
SPI_WRITE16(color);
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
|
|
|
|
{
|
|
|
|
if ((x >= 0) && (x < _TFTwidth) && h) { // X on screen, nonzero height
|
|
|
|
if (h < 0) { // If negative height...
|
|
|
|
y += h + 1; // Move Y to top edge
|
|
|
|
h = -h; // Use positive height
|
|
|
|
}
|
|
|
|
if (y < _TFTheight) { // Not off bottom
|
|
|
|
int16_t y2 = y + h - 1;
|
|
|
|
if (y2 >= 0) { // Not off top
|
|
|
|
// Line partly or fully overlaps screen
|
|
|
|
if (y < 0) {
|
|
|
|
y = 0;
|
|
|
|
h = y2 + 1;
|
|
|
|
} // Clip top
|
|
|
|
if (y2 >= _TFTheight) {
|
|
|
|
h = _TFTheight - y;
|
|
|
|
} // Clip bottom
|
|
|
|
writeFillRectPreclipped(x, y, 1, h, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
void SmartyKit_DisplayDriver::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
|
|
|
{
|
|
|
|
if (w && h) { // Nonzero width and height?
|
|
|
|
if (w < 0) { // If negative width...
|
|
|
|
x += w + 1; // Move X to left edge
|
|
|
|
w = -w; // Use positive width
|
|
|
|
}
|
|
|
|
if (x < _TFTwidth) { // Not off right
|
|
|
|
if (h < 0) { // If negative height...
|
|
|
|
y += h + 1; // Move Y to top edge
|
|
|
|
h = -h; // Use positive height
|
|
|
|
}
|
|
|
|
if (y < _TFTheight) { // Not off bottom
|
|
|
|
int16_t x2 = x + w - 1;
|
|
|
|
if (x2 >= 0) { // Not off left
|
|
|
|
int16_t y2 = y + h - 1;
|
|
|
|
if (y2 >= 0) { // Not off top
|
|
|
|
// Rectangle partly or fully overlaps screen
|
|
|
|
if (x < 0) {
|
|
|
|
x = 0;
|
|
|
|
w = x2 + 1;
|
|
|
|
} // Clip left
|
|
|
|
if (y < 0) {
|
|
|
|
y = 0;
|
|
|
|
h = y2 + 1;
|
|
|
|
} // Clip top
|
|
|
|
if (x2 >= _TFTwidth) {
|
|
|
|
w = _TFTwidth - x;
|
|
|
|
} // Clip right
|
|
|
|
if (y2 >= _TFTheight) {
|
|
|
|
h = _TFTheight - y;
|
|
|
|
} // Clip bottom
|
|
|
|
writeFillRectPreclipped(x, y, w, h, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void SmartyKit_DisplayDriver::writeFillRectPreclipped(int16_t x, int16_t y,
|
|
|
|
int16_t w, int16_t h,
|
|
|
|
uint16_t color) {
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(x, y, w, h);
|
|
|
|
writeColor(color, (uint32_t)w * h);
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::setRotation(uint8_t m) {
|
|
|
|
rotation = m % 4; // can't be higher than 3
|
|
|
|
switch (rotation) {
|
|
|
|
case 0:
|
|
|
|
m = (MADCTL_MX | MADCTL_BGR);
|
|
|
|
_TFTwidth = ILI9341_TFTWIDTH;
|
|
|
|
_TFTheight = ILI9341_TFTHEIGHT;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
m = (MADCTL_MV | MADCTL_BGR);
|
|
|
|
_TFTwidth = ILI9341_TFTHEIGHT;
|
|
|
|
_TFTheight = ILI9341_TFTWIDTH;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m = (MADCTL_MY | MADCTL_BGR);
|
|
|
|
_TFTwidth = ILI9341_TFTWIDTH;
|
|
|
|
_TFTheight = ILI9341_TFTHEIGHT;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
// m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
|
|
|
|
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
|
|
|
|
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_ML | MADCTL_MH | MADCTL_BGR);
|
|
|
|
_TFTwidth = ILI9341_TFTHEIGHT;
|
|
|
|
_TFTheight = ILI9341_TFTWIDTH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sendCommand(ILI9341_MADCTL, &m, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::clearFullScreen(uint16_t color = ILI9341_WHITE)
|
|
|
|
{
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(0, 0, _TFTwidth, _TFTheight);
|
|
|
|
for (int y = 0; y < _TFTheight; y++)
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int x = 0; x < _TFTwidth; x++)
|
|
|
|
{
|
|
|
|
SPI_WRITE16(color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::clearScreen(uint16_t color = ILI9341_WHITE)
|
|
|
|
{
|
|
|
|
if (rotation == 3)
|
|
|
|
{
|
|
|
|
uint16_t color2 = color;
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(_workingScreenLeftMargin, _workingScreenTopMargin, _workingScreenWidth, _workingScreenHeight);
|
|
|
|
for (int y = 0; y < _workingScreenHeight; y++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < _workingScreenWidth; x++)
|
|
|
|
{
|
|
|
|
if (y % 2 == 0)
|
|
|
|
SPI_WRITE16(color);
|
|
|
|
else
|
|
|
|
SPI_WRITE16(color2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
else if (rotation == 0)
|
|
|
|
{
|
|
|
|
uint16_t color2 = color;
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(_workingScreenLeftMargin, _workingScreenTopMargin, _workingScreenWidth, _workingScreenHeight);
|
|
|
|
for (int y = 0; y < _workingScreenHeight; y++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < _workingScreenWidth; x++)
|
|
|
|
{
|
|
|
|
if (y % 2 == 0)
|
|
|
|
SPI_WRITE16(color);
|
|
|
|
else
|
|
|
|
SPI_WRITE16(color2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::scrollTo(uint16_t y) {
|
|
|
|
|
|
|
|
int scroll = y;
|
|
|
|
if (y > SCREEN_HEIGHT)
|
|
|
|
scroll = SCREEN_HEIGHT;
|
|
|
|
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(0, 0, SCREEN_WIDTH, scroll);
|
|
|
|
//draw bgColor line to erase
|
|
|
|
for (uint16_t i = 0; i < scroll; i++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < SCREEN_WIDTH; x++)
|
|
|
|
SPI_WRITE16(bgColor);
|
|
|
|
}
|
|
|
|
endWrite();
|
|
|
|
//scroll screen
|
|
|
|
uint8_t data[2];
|
|
|
|
data[0] = (y) >> 8;
|
|
|
|
data[1] = (y) & 0xff;
|
|
|
|
sendCommand(ILI9341_VSCRSADD, (uint8_t *)data, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::drawScreenRect(uint16_t color)
|
|
|
|
{
|
|
|
|
if (rotation == 0 || rotation == 3)
|
|
|
|
{
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(_workingScreenLeftMargin, _workingScreenTopMargin + _workingScreenHeight, _workingScreenWidth, 1);
|
|
|
|
for (int x = 0; x < _workingScreenWidth; x++)
|
|
|
|
SPI_WRITE16(color);
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::drawHLine(uint16_t y, uint16_t color)
|
|
|
|
{
|
|
|
|
//converting screen coordinates to memory coordinates
|
|
|
|
int yLine;
|
|
|
|
if ((scrollLine + y) < SCREEN_HEIGHT)
|
|
|
|
yLine = scrollLine + y;
|
|
|
|
else
|
|
|
|
yLine = (scrollLine + y) - SCREEN_HEIGHT;
|
|
|
|
|
|
|
|
if (rotation == 0)
|
|
|
|
{
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(0, yLine, SCREEN_WIDTH, 1);
|
|
|
|
for (int x = 0; x < SCREEN_WIDTH; x++)
|
|
|
|
{
|
|
|
|
SPI_WRITE16(color);
|
|
|
|
}
|
|
|
|
endWrite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::setScrollMargins(uint16_t top, uint16_t bottom) {
|
|
|
|
// TFA+VSA+BFA must equal 320
|
|
|
|
if (top + bottom <= ILI9341_TFTHEIGHT) {
|
|
|
|
uint16_t middle = ILI9341_TFTHEIGHT - top - bottom;
|
|
|
|
uint8_t data[6];
|
|
|
|
data[0] = top >> 8;
|
|
|
|
data[1] = top & 0xff;
|
|
|
|
data[2] = middle >> 8;
|
|
|
|
data[3] = middle & 0xff;
|
|
|
|
data[4] = bottom >> 8;
|
|
|
|
data[5] = bottom & 0xff;
|
|
|
|
sendCommand(ILI9341_VSCRDEF, (uint8_t *)data, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmartyKit_DisplayDriver::scrollToNextLine(void)
|
|
|
|
{
|
|
|
|
if (rotation == 0 || rotation == 3) //build-in hardware scroll
|
|
|
|
{
|
|
|
|
startWrite();
|
|
|
|
setAddrWindow(0, scrollLine, _workingScreenWidth, LINE_HEIGHT);
|
|
|
|
//draw bgColor line to erase
|
|
|
|
for (uint16_t i = 0; i < LINE_HEIGHT; i++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < SCREEN_WIDTH; x++)
|
|
|
|
SPI_WRITE16(bgColor);
|
|
|
|
}
|
|
|
|
endWrite();
|
|
|
|
|
|
|
|
if ((scrollLine + LINE_HEIGHT) < SCREEN_HEIGHT)
|
|
|
|
scrollLine += LINE_HEIGHT;
|
|
|
|
else
|
|
|
|
scrollLine = (scrollLine + LINE_HEIGHT) - SCREEN_HEIGHT;
|
|
|
|
|
|
|
|
//scroll screen
|
|
|
|
uint8_t data[2];
|
|
|
|
data[0] = (scrollLine) >> 8;
|
|
|
|
data[1] = (scrollLine) & 0xff;
|
|
|
|
sendCommand(ILI9341_VSCRSADD, (uint8_t *)data, 2);
|
|
|
|
}
|
|
|
|
}
|