v0.8.933
This commit is contained in:
80
yoRadio/src/ILI9488/GFXcanvas16T.h
Normal file
80
yoRadio/src/ILI9488/GFXcanvas16T.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef _GFXcanvas16T_H_
|
||||
#define _GFXcanvas16T_H_
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
template<const uint16_t w, uint16_t h>
|
||||
class GFXcanvas16T : public Adafruit_GFX
|
||||
{
|
||||
public:
|
||||
GFXcanvas16T() : Adafruit_GFX(w, h) {};
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
|
||||
int16_t t;
|
||||
switch (rotation) {
|
||||
case 1:
|
||||
t = x;
|
||||
x = WIDTH - 1 - y;
|
||||
y = t;
|
||||
break;
|
||||
case 2:
|
||||
x = WIDTH - 1 - x;
|
||||
y = HEIGHT - 1 - y;
|
||||
break;
|
||||
case 3:
|
||||
t = x;
|
||||
x = y;
|
||||
y = HEIGHT - 1 - t;
|
||||
break;
|
||||
}
|
||||
buffer[x + y * WIDTH] = color;
|
||||
}
|
||||
void fillScreen(uint16_t color)
|
||||
{
|
||||
uint32_t i, pixels = WIDTH * HEIGHT;
|
||||
for (i = 0; i < pixels; i++) buffer[i] = color;
|
||||
}
|
||||
uint16_t *getBuffer(void)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
#if 1
|
||||
template<class T>
|
||||
void print(T target, const char* name = 0, bool as_progmem = false)
|
||||
{
|
||||
static const uint16_t per_line = 10;
|
||||
uint32_t remain = WIDTH * HEIGHT;
|
||||
uint16_t* p = buffer;
|
||||
if (!name) name = "canvas16";
|
||||
if (as_progmem) target.print(F("const "));
|
||||
target.print(F("uint16_t ")); target.print(name); target.print(F("[] "));
|
||||
if (as_progmem) target.print(F("PROGMEM "));
|
||||
target.println(F("=")); target.println(F("{"));
|
||||
while (remain > per_line)
|
||||
{
|
||||
target.print(F(" "));
|
||||
for (uint16_t i = 0; i < per_line; i++)
|
||||
{
|
||||
target.print(F("0x")); target.print(*p++, HEX); target.print(F(", "));
|
||||
}
|
||||
remain -= per_line;
|
||||
if (remain > 0) target.println();
|
||||
#if defined (ESP8266)
|
||||
yield();
|
||||
#endif
|
||||
}
|
||||
if (remain > 0) target.print(F(" "));
|
||||
while (remain-- > 0)
|
||||
{
|
||||
target.print(F("0x")); target.print(*p++, HEX); target.print(F(", "));
|
||||
}
|
||||
target.println();
|
||||
target.println(F("};"));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
uint16_t buffer[w * h];
|
||||
};
|
||||
|
||||
#endif
|
||||
719
yoRadio/src/ILI9488/ILI9486_SPI.cpp
Normal file
719
yoRadio/src/ILI9488/ILI9486_SPI.cpp
Normal file
@@ -0,0 +1,719 @@
|
||||
// created by Jean-Marc Zingg to be a standalone ILI9486_SPI library (instead of the GxCTRL_ILI9486_SPI class for the GxTFT library)
|
||||
// code extracts taken from https://github.com/Bodmer/TFT_HX8357
|
||||
// spi kludge handling solution found in https://github.com/Bodmer/TFT_eSPI
|
||||
// code extracts taken from https://github.com/adafruit/Adafruit-GFX-Library
|
||||
//
|
||||
// License: GNU GENERAL PUBLIC LICENSE V3, see LICENSE
|
||||
//
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ILI9488 || DSP_MODEL==DSP_ILI9486
|
||||
|
||||
#include <SPI.h>
|
||||
#include "ILI9486_SPI.h"
|
||||
|
||||
#define SPI_SPEED 40000000UL
|
||||
//#define SPI_SPEED 20000000 // max reliable speed is 20Mhz for RPi SPI kludge
|
||||
//#define SPI_SPEED 4000000
|
||||
|
||||
#define ILI9486_SPI_CASET 0x2A
|
||||
#define ILI9486_SPI_PASET 0x2B
|
||||
#define ILI9486_SPI_RAMWR 0x2C
|
||||
#define ILI9486_SPI_RAMRD 0x2E
|
||||
#define ILI9486_SPI_MADCTL 0x36
|
||||
#define MADCTL_MY 0x80
|
||||
#define MADCTL_MX 0x40
|
||||
#define MADCTL_MV 0x20
|
||||
#define MADCTL_ML 0x10
|
||||
#define MADCTL_BGR 0x08
|
||||
#define MADCTL_MH 0x04
|
||||
|
||||
#define ILI9488_INVOFF 0x20
|
||||
#define ILI9488_INVON 0x21
|
||||
|
||||
//ILI9486_SPI::ILI9486_SPI(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(320, 480), _spi_settings(SPI_SPEED, MSBFIRST, SPI_MODE0)
|
||||
ILI9486_SPI::ILI9486_SPI(int8_t cs, int8_t dc, int8_t rst) : ILI9486_SPI(&SPI, cs, dc, rst) { }
|
||||
|
||||
ILI9486_SPI::ILI9486_SPI(SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(320, 480), _spi_settings(SPI_SPEED, MSBFIRST, SPI_MODE0)
|
||||
{
|
||||
_spi = spiClass;
|
||||
_spi16_mode = true;
|
||||
_cs = cs;
|
||||
_dc = dc;
|
||||
_rst = rst;
|
||||
_bgr = MADCTL_BGR;
|
||||
#if defined(ESP8266)
|
||||
if ((_cs >= 0) && (_dc >= 0))
|
||||
{
|
||||
_cs_pinmask = (uint32_t) digitalPinToBitMask(_cs);
|
||||
_dc_pinmask = (uint32_t) digitalPinToBitMask(_dc);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cs_pinmask = 0;
|
||||
_dc_pinmask = 0;
|
||||
}
|
||||
#endif
|
||||
_x_address_set = -1;
|
||||
_x_address_set = -1;
|
||||
digitalWrite(_cs, HIGH);
|
||||
digitalWrite(_dc, HIGH);
|
||||
pinMode(_cs, OUTPUT);
|
||||
pinMode(_dc, OUTPUT);
|
||||
if (rst >= 0)
|
||||
{
|
||||
digitalWrite(rst, HIGH);
|
||||
pinMode(rst, OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
// *** (overridden) virtual methods ***
|
||||
|
||||
#if defined(ESP8266) && true // This is for the RPi display that needs 16 bits
|
||||
|
||||
#define CMD_BITS (16-1)
|
||||
|
||||
void ILI9486_SPI::drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
// Range checking
|
||||
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
|
||||
if (_spi16_mode && _cs_pinmask)
|
||||
{
|
||||
_spi->beginTransaction(_spi_settings);
|
||||
GPOC = _cs_pinmask;
|
||||
SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
||||
// No need to send x if it has not changed (speeds things up)
|
||||
if (_x_address_set != x)
|
||||
{
|
||||
GPOC = _dc_pinmask;
|
||||
SPI1W0 = ILI9486_SPI_CASET << (CMD_BITS + 1 - 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _dc_pinmask;
|
||||
SPI1W0 = x >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = x << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = x >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = x << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
_x_address_set = x;
|
||||
}
|
||||
// No need to send y if it has not changed (speeds things up)
|
||||
if (_y_address_set != y)
|
||||
{
|
||||
GPOC = _dc_pinmask;
|
||||
SPI1W0 = ILI9486_SPI_PASET << (CMD_BITS + 1 - 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _dc_pinmask;
|
||||
SPI1W0 = y >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = y << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = y >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = y << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
_y_address_set = y;
|
||||
}
|
||||
GPOC = _dc_pinmask;
|
||||
SPI1W0 = ILI9486_SPI_RAMWR << (CMD_BITS + 1 - 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _dc_pinmask;
|
||||
SPI1W0 = (color >> 8) | (color << 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _cs_pinmask;
|
||||
_spi->endTransaction();
|
||||
}
|
||||
else
|
||||
{
|
||||
_startTransaction();
|
||||
_setWindow(x, y, 1, 1);
|
||||
_writeColor16(color, 1);
|
||||
_endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ILI9486_SPI::drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_startTransaction();
|
||||
_setWindow(x, y, 1, 1);
|
||||
_writeColor16(color, 1);
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ILI9486_SPI::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
||||
{
|
||||
// if ((x < 0) || (y < 0) || (w < 1) || (h < 1) || (x + w > _width) || (y + h > _height))
|
||||
// {
|
||||
// Serial.print("fillRect("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(") oops? "); delay(1);
|
||||
// }
|
||||
// a correct clipping is the goal. try to achieve this
|
||||
if (x < 0) w += x, x = 0;
|
||||
if (y < 0) h += y, y = 0;
|
||||
if (x + w > _width) w = _width - x;
|
||||
if (y + h > _height) h = _height - y;
|
||||
if ((w < 1) || (h < 1)) return;
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h);
|
||||
_writeColor16(color, uint32_t(w) * uint32_t(h));
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
|
||||
{
|
||||
fillRect(x, y, 1, h, color);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
|
||||
{
|
||||
fillRect(x, y, w, 1, color);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::fillScreen(uint16_t color)
|
||||
{
|
||||
fillRect(0, 0, _width, _height, color);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::setRotation(uint8_t r)
|
||||
{
|
||||
Adafruit_GFX::setRotation(r);
|
||||
_startTransaction();
|
||||
if (_spi16_mode)
|
||||
{
|
||||
_writeCommand16(ILI9486_SPI_MADCTL);
|
||||
switch (r & 3)
|
||||
{
|
||||
case 0:
|
||||
_writeData16(MADCTL_MX | _bgr);
|
||||
break;
|
||||
case 1:
|
||||
_writeData16(MADCTL_MV | _bgr);
|
||||
break;
|
||||
case 2:
|
||||
_writeData16(MADCTL_MY | _bgr);
|
||||
break;
|
||||
case 3:
|
||||
_writeData16(MADCTL_MX | MADCTL_MY | MADCTL_MV | _bgr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeCommand(ILI9486_SPI_MADCTL);
|
||||
switch (r & 3)
|
||||
{
|
||||
case 0:
|
||||
_writeData(MADCTL_MX | _bgr);
|
||||
break;
|
||||
case 1:
|
||||
_writeData(MADCTL_MV | _bgr);
|
||||
break;
|
||||
case 2:
|
||||
_writeData(MADCTL_MY | _bgr);
|
||||
break;
|
||||
case 3:
|
||||
_writeData(MADCTL_MX | MADCTL_MY | MADCTL_MV | _bgr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::invertDisplay(bool i)
|
||||
{
|
||||
/*_bgr = i ? MADCTL_BGR : 0x00;
|
||||
setRotation(rotation);*/
|
||||
sendCommand(i ? ILI9488_INVON : ILI9488_INVOFF);
|
||||
}
|
||||
|
||||
// *** other public methods ***
|
||||
|
||||
void ILI9486_SPI::setSpiKludge(bool rpi_spi16_mode)
|
||||
{
|
||||
_spi16_mode = rpi_spi16_mode;
|
||||
}
|
||||
|
||||
void ILI9486_SPI::init(void)
|
||||
{
|
||||
digitalWrite(_cs, HIGH);
|
||||
_spi->begin();
|
||||
_spi->beginTransaction( { SPI_SPEED, MSBFIRST, SPI_MODE0 } );
|
||||
_spi->endTransaction();
|
||||
if (_rst >= 0)
|
||||
{
|
||||
digitalWrite(_rst, LOW);
|
||||
delay(20);
|
||||
digitalWrite(_rst, HIGH);
|
||||
}
|
||||
delay(200);
|
||||
_startTransaction();
|
||||
if (_spi16_mode)
|
||||
{
|
||||
_writeCommand16(0x3A);
|
||||
_writeData16(0x55); // use 16 bits per pixel color
|
||||
_writeCommand16(0x36);
|
||||
_writeData16(0x48); // MX, BGR == rotation 0
|
||||
// PGAMCTRL(Positive Gamma Control)
|
||||
_writeCommand16(0xE0);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x1F);
|
||||
_writeData16(0x1C);
|
||||
_writeData16(0x0C);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x08);
|
||||
_writeData16(0x48);
|
||||
_writeData16(0x98);
|
||||
_writeData16(0x37);
|
||||
_writeData16(0x0A);
|
||||
_writeData16(0x13);
|
||||
_writeData16(0x04);
|
||||
_writeData16(0x11);
|
||||
_writeData16(0x0D);
|
||||
_writeData16(0x00);
|
||||
// NGAMCTRL(Negative Gamma Control)
|
||||
_writeCommand16(0xE1);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x32);
|
||||
_writeData16(0x2E);
|
||||
_writeData16(0x0B);
|
||||
_writeData16(0x0D);
|
||||
_writeData16(0x05);
|
||||
_writeData16(0x47);
|
||||
_writeData16(0x75);
|
||||
_writeData16(0x37);
|
||||
_writeData16(0x06);
|
||||
_writeData16(0x10);
|
||||
_writeData16(0x03);
|
||||
_writeData16(0x24);
|
||||
_writeData16(0x20);
|
||||
_writeData16(0x00);
|
||||
// Digital Gamma Control 1
|
||||
_writeCommand16(0xE2);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x32);
|
||||
_writeData16(0x2E);
|
||||
_writeData16(0x0B);
|
||||
_writeData16(0x0D);
|
||||
_writeData16(0x05);
|
||||
_writeData16(0x47);
|
||||
_writeData16(0x75);
|
||||
_writeData16(0x37);
|
||||
_writeData16(0x06);
|
||||
_writeData16(0x10);
|
||||
_writeData16(0x03);
|
||||
_writeData16(0x24);
|
||||
_writeData16(0x20);
|
||||
_writeData16(0x00);
|
||||
_writeCommand16(0x11); // Sleep OUT
|
||||
delay(150); // wait some time
|
||||
_writeCommand16(0x29); // Display ON
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeCommand(0x3A);
|
||||
_writeData(0x66); // 18 bit colour for native SPI
|
||||
_writeCommand(0x36);
|
||||
_writeData(0x48); // MX, BGR == rotation 0
|
||||
// PGAMCTRL(Positive Gamma Control)
|
||||
#if DSP_MODEL==DSP_ILI9486
|
||||
_writeCommand(0xE0);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x1F);
|
||||
_writeData(0x1C);
|
||||
_writeData(0x0C);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x08);
|
||||
_writeData(0x48);
|
||||
_writeData(0x98);
|
||||
_writeData(0x37);
|
||||
_writeData(0x0A);
|
||||
_writeData(0x13);
|
||||
_writeData(0x04);
|
||||
_writeData(0x11);
|
||||
_writeData(0x0D);
|
||||
_writeData(0x00);
|
||||
// NGAMCTRL(Negative Gamma Control)
|
||||
_writeCommand(0xE1);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x32);
|
||||
_writeData(0x2E);
|
||||
_writeData(0x0B);
|
||||
_writeData(0x0D);
|
||||
_writeData(0x05);
|
||||
_writeData(0x47);
|
||||
_writeData(0x75);
|
||||
_writeData(0x37);
|
||||
_writeData(0x06);
|
||||
_writeData(0x10);
|
||||
_writeData(0x03);
|
||||
_writeData(0x24);
|
||||
_writeData(0x20);
|
||||
_writeData(0x00);
|
||||
// Digital Gamma Control 1
|
||||
_writeCommand(0xE2);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x32);
|
||||
_writeData(0x2E);
|
||||
_writeData(0x0B);
|
||||
_writeData(0x0D);
|
||||
_writeData(0x05);
|
||||
_writeData(0x47);
|
||||
_writeData(0x75);
|
||||
_writeData(0x37);
|
||||
_writeData(0x06);
|
||||
_writeData(0x10);
|
||||
_writeData(0x03);
|
||||
_writeData(0x24);
|
||||
_writeData(0x20);
|
||||
_writeData(0x00);
|
||||
#endif
|
||||
_writeCommand(0x11); // Sleep OUT
|
||||
delay(150); // wait some time
|
||||
_writeCommand(0x29); // Display ON
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h);
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::pushColors(const uint16_t* data, uint16_t n)
|
||||
{
|
||||
_startTransaction();
|
||||
_writeColor16(data, n);
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::setBackLight(bool lit)
|
||||
{
|
||||
_startTransaction();
|
||||
if (_spi16_mode) _writeCommand16(lit ? 0x29 : 0x28); // Display ON / Display OFF
|
||||
else _writeCommand(lit ? 0x29 : 0x28); // Display ON / Display OFF
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
uint16_t ILI9486_SPI::color565(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||
}
|
||||
|
||||
// code extract taken from Adafruit_SPITFT::drawRGBBitmap https://github.com/adafruit/Adafruit-GFX-Library
|
||||
void ILI9486_SPI::drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, int16_t w, int16_t h)
|
||||
{
|
||||
if (!pcolors) return; // canvas might be empty
|
||||
int16_t x2, y2; // Lower-right coord
|
||||
if (( x >= _width ) || // Off-edge right
|
||||
( y >= _height) || // " top
|
||||
((x2 = (x + w - 1)) < 0 ) || // " left
|
||||
((y2 = (y + h - 1)) < 0) ) return; // " bottom
|
||||
|
||||
int16_t bx1 = 0, by1 = 0; // Clipped top-left within bitmap
|
||||
int16_t saveW = w; // Save original bitmap width value
|
||||
if (x < 0) // Clip left
|
||||
{
|
||||
w += x;
|
||||
bx1 = -x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) // Clip top
|
||||
{
|
||||
h += y;
|
||||
by1 = -y;
|
||||
y = 0;
|
||||
}
|
||||
if (x2 >= _width ) w = _width - x; // Clip right
|
||||
if (y2 >= _height) h = _height - y; // Clip bottom
|
||||
|
||||
pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h); // Clipped area
|
||||
while (h--) // For each (clipped) scanline...
|
||||
{
|
||||
_writeColor16(pcolors, w); // Push one (clipped) row
|
||||
pcolors += saveW; // Advance pointer by one full (unclipped) line
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
// code extract taken from Adafruit_SPITFT::drawRGBBitmap https://github.com/adafruit/Adafruit-GFX-Library
|
||||
void ILI9486_SPI::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h)
|
||||
{
|
||||
const uint16_t* pcolors = bitmap;
|
||||
int16_t x2, y2; // Lower-right coord
|
||||
if (( x >= _width ) || // Off-edge right
|
||||
( y >= _height) || // " top
|
||||
((x2 = (x + w - 1)) < 0 ) || // " left
|
||||
((y2 = (y + h - 1)) < 0) ) return; // " bottom
|
||||
|
||||
int16_t bx1 = 0, by1 = 0; // Clipped top-left within bitmap
|
||||
int16_t saveW = w; // Save original bitmap width value
|
||||
if (x < 0) // Clip left
|
||||
{
|
||||
w += x;
|
||||
bx1 = -x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) // Clip top
|
||||
{
|
||||
h += y;
|
||||
by1 = -y;
|
||||
y = 0;
|
||||
}
|
||||
if (x2 >= _width ) w = _width - x; // Clip right
|
||||
if (y2 >= _height) h = _height - y; // Clip bottom
|
||||
|
||||
pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h); // Clipped area
|
||||
while (h--) // For each (clipped) scanline...
|
||||
{
|
||||
for (int16_t i = 0; i < w; i++) // Push one (clipped) row
|
||||
{
|
||||
_writeColor16(pgm_read_word(pcolors + i), 1);
|
||||
}
|
||||
pcolors += saveW; // Advance pointer by one full (unclipped) line
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
// *** private methods
|
||||
|
||||
void ILI9486_SPI::_setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
uint16_t xe = x + w - 1;
|
||||
uint16_t ye = y + h - 1;
|
||||
if (_spi16_mode)
|
||||
{
|
||||
_writeCommand16(ILI9486_SPI_CASET);
|
||||
uint16_t columns[] = {uint16_t(x >> 8), uint16_t(x & 0xFF), uint16_t(xe >> 8), uint16_t(xe & 0xFF)};
|
||||
_writeData16(columns, 4);
|
||||
_writeCommand16(ILI9486_SPI_PASET);
|
||||
uint16_t rows[] = {uint16_t(y >> 8), uint16_t(y & 0xFF), uint16_t(ye >> 8), uint16_t(ye & 0xFF)};
|
||||
_writeData16(rows, 4);
|
||||
_writeCommand16(ILI9486_SPI_RAMWR);
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeCommand(ILI9486_SPI_CASET);
|
||||
_writeData16(x);
|
||||
_writeData16(xe);
|
||||
_writeCommand(ILI9486_SPI_PASET);
|
||||
_writeData16(y);
|
||||
_writeData16(ye);
|
||||
_writeCommand(ILI9486_SPI_RAMWR);
|
||||
}
|
||||
_x_address_set = -1;
|
||||
_x_address_set = -1;
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_startTransaction()
|
||||
{
|
||||
_spi->beginTransaction(_spi_settings);
|
||||
if (_cs >= 0) digitalWrite(_cs, LOW);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_endTransaction()
|
||||
{
|
||||
if (_cs >= 0) digitalWrite(_cs, HIGH);
|
||||
_spi->endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeCommand(uint8_t cmd)
|
||||
{
|
||||
digitalWrite(_dc, LOW);
|
||||
_spi->transfer(cmd);
|
||||
digitalWrite(_dc, HIGH);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::sendCommand(uint8_t cmd)
|
||||
{
|
||||
_startTransaction();
|
||||
if (_cs >= 0)
|
||||
digitalWrite(_cs, LOW);
|
||||
|
||||
digitalWrite(_dc, LOW); // Command mode
|
||||
_spi->transfer(cmd); // Send the command byte
|
||||
|
||||
digitalWrite(_dc, HIGH);
|
||||
|
||||
|
||||
if (_cs >= 0)
|
||||
digitalWrite(_cs, HIGH);
|
||||
_endTransaction();
|
||||
|
||||
|
||||
/* digitalWrite(_dc, LOW);
|
||||
_spi->transfer(cmd);
|
||||
digitalWrite(_dc, HIGH);*/
|
||||
}
|
||||
void ILI9486_SPI::_writeCommand16(uint16_t cmd)
|
||||
{
|
||||
digitalWrite(_dc, LOW);
|
||||
_writeData16(cmd);
|
||||
digitalWrite(_dc, HIGH);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData(uint8_t data)
|
||||
{
|
||||
digitalWrite(_dc, HIGH);
|
||||
_spi->transfer(data);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData16(uint16_t data)
|
||||
{
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
_spi->write16(data);
|
||||
#else
|
||||
_spi->transfer(data >> 8);
|
||||
_spi->transfer(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData16(uint16_t data, uint32_t n)
|
||||
{
|
||||
#if (defined (ESP8266) || defined(ESP32)) && true // fastest
|
||||
uint16_t swapped = ((data << 8) | (data >> 8));
|
||||
_spi->writePattern((uint8_t*)&swapped, 2, n);
|
||||
#elif (defined (ESP8266) || defined(ESP32))
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->write16(data);
|
||||
}
|
||||
#else // wdt on ESP8266
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->transfer(data >> 8);
|
||||
_spi->transfer(data);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData16(const uint16_t* data, uint32_t n)
|
||||
{
|
||||
#if (defined (ESP8266) || defined(ESP32) || (TEENSYDUINO == 147)) && true // fastest
|
||||
static const uint16_t swap_buffer_size = 64; // optimal for ESP8266 SPI
|
||||
static const uint32_t max_chunk = swap_buffer_size / 2; // uint16_t's
|
||||
uint8_t swap_buffer[swap_buffer_size];
|
||||
const uint8_t* p1 = reinterpret_cast<const uint8_t*> (data);
|
||||
const uint8_t* p2 = p1 + 1;
|
||||
while (n > 0)
|
||||
{
|
||||
uint32_t chunk = min(max_chunk, n);
|
||||
n -= chunk;
|
||||
uint8_t* p3 = swap_buffer;
|
||||
uint8_t* p4 = p3 + 1;
|
||||
uint16_t ncopy = chunk;
|
||||
while (ncopy-- > 0)
|
||||
{
|
||||
*p3 = *p2; p3 += 2; p2 += 2;
|
||||
*p4 = *p1; p4 += 2; p1 += 2;
|
||||
}
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
_spi->transferBytes(swap_buffer, 0, 2 * chunk);
|
||||
#elif defined(ARDUINO_ARCH_SAM) // same speed
|
||||
_spi->transfer(SS, swap_buffer, 2 * chunk);
|
||||
#else
|
||||
_spi->transfer(swap_buffer, 0, 2 * chunk);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
while (n-- > 0)
|
||||
{
|
||||
uint16_t color = (*data++);
|
||||
#if (defined (ESP8266) || defined(ESP32)) && false // faster
|
||||
_spi->write16(color);
|
||||
#else
|
||||
_spi->transfer(color >> 8);
|
||||
_spi->transfer(color);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeColor16(uint16_t data, uint32_t n)
|
||||
{
|
||||
if (_spi16_mode) return _writeData16(data, n);
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
uint8_t rgb888[] = {uint8_t((data & 0xF800) >> 8), uint8_t((data & 0x07E0) >> 3), uint8_t((data & 0x001F) << 3)};
|
||||
_spi->writePattern(rgb888, 3, n);
|
||||
#else // wdt on ESP8266
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->transfer(uint8_t((data & 0xF800) >> 8));
|
||||
_spi->transfer(uint8_t((data & 0x07E0) >> 3));
|
||||
_spi->transfer(uint8_t((data & 0x001F) << 3));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transferBytes(data, 0, n)
|
||||
#elif defined(ARDUINO_ARCH_SAM)
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transfer(SS, data, n)
|
||||
#elif (TEENSYDUINO == 147)
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transfer(data, 0, n)
|
||||
#elif defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4)
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->write(data, n)
|
||||
#else
|
||||
// valid for all other platforms? else comment out next line
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transfer(data, n)
|
||||
#endif
|
||||
|
||||
|
||||
void ILI9486_SPI::_writeColor16(const uint16_t* data, uint32_t n)
|
||||
{
|
||||
if (_spi16_mode) return _writeData16(data, n);
|
||||
#if defined(SPI_WRITE_BYTES)
|
||||
static const uint16_t rgb888_buffer_size = 60; // 64 optimal for ESP8266 SPI
|
||||
static const uint32_t max_chunk = rgb888_buffer_size / 3; // rgb888
|
||||
uint8_t rgb888_buffer[rgb888_buffer_size];
|
||||
while (n > 0)
|
||||
{
|
||||
uint32_t chunk = min(max_chunk, n);
|
||||
n -= chunk;
|
||||
uint8_t* p = rgb888_buffer;
|
||||
uint16_t ncopy = chunk;
|
||||
while (ncopy-- > 0)
|
||||
{
|
||||
*p++ = uint8_t((*data & 0xF800) >> 8);
|
||||
*p++ = uint8_t((*data & 0x07E0) >> 3);
|
||||
*p++ = uint8_t((*data & 0x001F) << 3);
|
||||
data++;
|
||||
}
|
||||
SPI_WRITE_BYTES(rgb888_buffer, 3 * chunk);
|
||||
}
|
||||
#else
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->transfer(uint8_t((*data & 0xF800) >> 8));
|
||||
_spi->transfer(uint8_t((*data & 0x07E0) >> 3));
|
||||
_spi->transfer(uint8_t((*data & 0x001F) << 3));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
65
yoRadio/src/ILI9488/ILI9486_SPI.h
Normal file
65
yoRadio/src/ILI9488/ILI9486_SPI.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// created by Jean-Marc Zingg to be a standalone ILI9486_SPI library (instead of the GxCTRL_ILI9486_SPI class for the GxTFT library)
|
||||
// code extracts taken from https://github.com/Bodmer/TFT_HX8357
|
||||
// spi kludge handling solution found in https://github.com/Bodmer/TFT_eSPI
|
||||
// code extracts taken from https://github.com/adafruit/Adafruit-GFX-Library
|
||||
//
|
||||
// License: GNU GENERAL PUBLIC LICENSE V3, see LICENSE
|
||||
//
|
||||
|
||||
#ifndef _ILI9486_SPI_H_
|
||||
#define _ILI9486_SPI_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "GFXcanvas16T.h"
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
class ILI9486_SPI : public Adafruit_GFX
|
||||
{
|
||||
public:
|
||||
ILI9486_SPI(int8_t cs, int8_t dc, int8_t rst);
|
||||
ILI9486_SPI(SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst);
|
||||
// (overridden) virtual methods
|
||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
virtual void fillScreen(uint16_t color);
|
||||
virtual void setRotation(uint8_t r);
|
||||
virtual void invertDisplay(bool i);
|
||||
// other public methods
|
||||
void setSpiKludge(bool rpi_spi16_mode = true); // call with false before init to disable
|
||||
void init(void);
|
||||
void setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void pushColors(const uint16_t* data, uint16_t n); // fast one
|
||||
void setBackLight(bool lit);
|
||||
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
|
||||
void drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, int16_t w, int16_t h);
|
||||
void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h);
|
||||
virtual void _startTransaction();
|
||||
virtual void _endTransaction();
|
||||
void _writeCommand(uint8_t cmd);
|
||||
void sendCommand(uint8_t cmd);
|
||||
private:
|
||||
void _setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void _writeCommand16(uint16_t cmd);
|
||||
void _writeData(uint8_t data);
|
||||
void _writeData16(uint16_t data);
|
||||
void _writeData16(uint16_t data, uint32_t n);
|
||||
void _writeData16(const uint16_t* data, uint32_t n);
|
||||
// note: only use for pixel data, RGB888 on ILI9488, ILI9486 native SPI
|
||||
void _writeColor16(uint16_t data, uint32_t n);
|
||||
void _writeColor16(const uint16_t* data, uint32_t n);
|
||||
private:
|
||||
bool _spi16_mode;
|
||||
SPISettings _spi_settings;
|
||||
SPIClass *_spi;
|
||||
int8_t _cs, _dc, _rst;
|
||||
int8_t _bgr;
|
||||
int32_t _x_address_set, _y_address_set;
|
||||
uint32_t _cs_pinmask, _dc_pinmask;
|
||||
};
|
||||
|
||||
#endif
|
||||
1699
yoRadio/src/ILI9488/test_canvas.h
Normal file
1699
yoRadio/src/ILI9488/test_canvas.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user