509 lines
12 KiB
C++
509 lines
12 KiB
C++
|
|
#include "Adafruit_GFX.h"
|
|
#include "TFT_ILI9340.h"
|
|
#include "pins_arduino.h"
|
|
#include "wiring_private.h"
|
|
#include <SPI.h>
|
|
|
|
#if defined(__SAM3X8E__)
|
|
#include <include/pio.h>
|
|
#define SET_BIT(port, bitMask) (port)->PIO_SODR |= (bitMask)
|
|
#define CLEAR_BIT(port, bitMask) (port)->PIO_CODR |= (bitMask)
|
|
#define USE_SPI_LIBRARY
|
|
#endif
|
|
#ifdef __AVR__
|
|
#define SET_BIT(port, bitMask) *(port) |= (bitMask)
|
|
#define CLEAR_BIT(port, bitMask) *(port) &= ~(bitMask)
|
|
#endif
|
|
#if defined(__arm__) && defined(CORE_TEENSY)
|
|
#define USE_SPI_LIBRARY
|
|
#define SET_BIT(port, bitMask) digitalWrite(*(port), HIGH);
|
|
#define CLEAR_BIT(port, bitMask) digitalWrite(*(port), LOW);
|
|
#endif
|
|
|
|
|
|
TFT_ILI9340::TFT_ILI9340(uint8_t cs, uint8_t dc, uint8_t rst) : Adafruit_GFX(TFT_WIDTH, TFT_HEIGHT) {
|
|
_cs = cs;
|
|
_rs = dc;
|
|
_rst = rst;
|
|
_inited = false;
|
|
}
|
|
|
|
TFT_ILI9340::TFT_ILI9340(uint8_t cs, uint8_t dc) : Adafruit_GFX(TFT_WIDTH, TFT_HEIGHT) {
|
|
_cs = cs;
|
|
_rs = dc;
|
|
_rst = 0;
|
|
_inited = false;
|
|
}
|
|
|
|
//helper
|
|
void TFT_ILI9340::setRegister(const uint8_t reg,uint8_t val){
|
|
uint8_t cmd[2] = {reg,val};
|
|
writeCommands(cmd,2);
|
|
}
|
|
|
|
/********************************** low level pin and SPI transfer based on MCU */
|
|
#ifdef __AVR__
|
|
|
|
inline void TFT_ILI9340::spiwrite(uint8_t c){
|
|
SPDR = c;
|
|
while(!(SPSR & _BV(SPIF)));
|
|
}
|
|
|
|
void TFT_ILI9340::writeCommand(uint8_t c){
|
|
*rsport &= ~rspinmask;
|
|
*csport &= ~cspinmask;
|
|
spiwrite(c);
|
|
*csport |= cspinmask;
|
|
}
|
|
|
|
void TFT_ILI9340::writeCommands(uint8_t *cmd, uint8_t length){
|
|
*rsport &= ~rspinmask;
|
|
*csport &= ~cspinmask;
|
|
for (uint8_t i = 0; i < length; i++) {
|
|
spiwrite(*cmd++);
|
|
}
|
|
*csport |= cspinmask;
|
|
}
|
|
|
|
void TFT_ILI9340::writeData(uint8_t c){
|
|
*rsport |= rspinmask;
|
|
*csport &= ~cspinmask;
|
|
spiwrite(c);
|
|
*csport |= cspinmask;
|
|
}
|
|
|
|
void TFT_ILI9340::writedata16(uint16_t d){
|
|
*rsport |= rspinmask;
|
|
*csport &= ~cspinmask;
|
|
spiwrite(d >> 8);
|
|
spiwrite(d);
|
|
*csport |= cspinmask;
|
|
}
|
|
|
|
void TFT_ILI9340::setBitrate(uint32_t n){
|
|
if (n >= 8000000) {
|
|
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
|
} else if (n >= 4000000) {
|
|
SPI.setClockDivider(SPI_CLOCK_DIV4);
|
|
} else if (n >= 2000000) {
|
|
SPI.setClockDivider(SPI_CLOCK_DIV8);
|
|
} else {
|
|
SPI.setClockDivider(SPI_CLOCK_DIV16);
|
|
}
|
|
}
|
|
#elif defined(__SAM3X8E__)
|
|
|
|
inline void TFT_ILI9340::spiwrite(uint8_t c){
|
|
SPI.transfer(c);
|
|
}
|
|
|
|
void TFT_ILI9340::writeCommand(uint8_t c){
|
|
rsport->PIO_CODR |= rspinmask;
|
|
csport->PIO_CODR |= cspinmask;
|
|
spiwrite(c);
|
|
csport->PIO_SODR |= cspinmask;
|
|
}
|
|
|
|
void TFT_ILI9340::writeCommands(uint8_t *cmd, uint8_t length){
|
|
rsport->PIO_CODR |= rspinmask;
|
|
csport->PIO_CODR |= cspinmask;
|
|
for (uint8_t i = 0; i < length; i++) {
|
|
spiwrite(*cmd++);
|
|
}
|
|
csport->PIO_SODR |= cspinmask;
|
|
}
|
|
|
|
void TFT_ILI9340::writeData(uint8_t c){
|
|
rsport->PIO_SODR |= rspinmask;
|
|
csport->PIO_CODR |= cspinmask;
|
|
spiwrite(c);
|
|
csport->PIO_SODR |= cspinmask;
|
|
}
|
|
|
|
void TFT_ILI9340::writedata16(uint16_t d){
|
|
rsport->PIO_SODR |= rspinmask;//HI
|
|
csport->PIO_CODR |= cspinmask;//LO
|
|
spiwrite(d >> 8);
|
|
spiwrite(d);
|
|
csport->PIO_SODR |= cspinmask;//HI
|
|
}
|
|
|
|
void TFT_ILI9340::setBitrate(uint32_t n){
|
|
uint32_t divider=1;
|
|
while (divider < 255) {
|
|
if (n >= 84000000 / divider) break;
|
|
divider = divider - 1;
|
|
}
|
|
SPI.setClockDivider(divider);
|
|
}
|
|
#elif defined(__MK20DX128__) || defined(__MK20DX256__)
|
|
|
|
void TFT_ILI9340::writeCommand(uint8_t c){
|
|
SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0);
|
|
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
|
|
}
|
|
|
|
void TFT_ILI9340::writeCommands(uint8_t *cmd, uint8_t length){
|
|
for (uint8_t i = 0; i < length; i++) {
|
|
SPI0.PUSHR = *cmd++ | (pcs_command << 16) | SPI_PUSHR_CTAS(0);
|
|
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
|
|
}
|
|
}
|
|
|
|
void TFT_ILI9340::writeData(uint8_t c){
|
|
SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0);
|
|
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
|
|
}
|
|
|
|
void TFT_ILI9340::writedata16(uint16_t d){
|
|
SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1);
|
|
while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
|
|
}
|
|
/*
|
|
Helper:
|
|
This function return true only if the choosed pin can be used for CS or RS
|
|
*/
|
|
static bool spi_pin_is_cs(uint8_t pin){
|
|
if (pin == 2 || pin == 6 || pin == 9) return true;
|
|
if (pin == 10 || pin == 15) return true;
|
|
if (pin >= 20 && pin <= 23) return true;
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
Helper:
|
|
This function configure register in relation to pin
|
|
*/
|
|
static uint8_t spi_configure_cs_pin(uint8_t pin){
|
|
switch (pin) {
|
|
case 10: CORE_PIN10_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTC4
|
|
case 2: CORE_PIN2_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTD0
|
|
case 9: CORE_PIN9_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTC3
|
|
case 6: CORE_PIN6_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTD4
|
|
case 20: CORE_PIN20_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTD5
|
|
case 23: CORE_PIN23_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTC2
|
|
case 21: CORE_PIN21_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTD6
|
|
case 22: CORE_PIN22_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTC1
|
|
case 15: CORE_PIN15_CONFIG = PORT_PCR_MUX(2); return 0x10; // PTC0
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Helper:
|
|
This function set the speed of the SPI interface
|
|
*/
|
|
void TFT_ILI9340::setBitrate(uint32_t n){
|
|
if (n >= 24000000) {
|
|
ctar = CTAR_24MHz;
|
|
} else if (n >= 16000000) {
|
|
ctar = CTAR_16MHz;
|
|
} else if (n >= 12000000) {
|
|
ctar = CTAR_12MHz;
|
|
} else if (n >= 8000000) {
|
|
ctar = CTAR_8MHz;
|
|
} else if (n >= 6000000) {
|
|
ctar = CTAR_6MHz;
|
|
} else {
|
|
ctar = CTAR_4MHz;
|
|
}
|
|
SIM_SCGC6 |= SIM_SCGC6_SPI0;
|
|
SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
|
|
SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7);
|
|
SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15);
|
|
SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
|
|
}
|
|
#endif
|
|
|
|
void TFT_ILI9340::commonInit(){
|
|
#if defined(__AVR__)
|
|
pinMode(_rs, OUTPUT);
|
|
pinMode(_cs, OUTPUT);
|
|
csport = portOutputRegister(digitalPinToPort(_cs));
|
|
rsport = portOutputRegister(digitalPinToPort(_rs));
|
|
cspinmask = digitalPinToBitMask(_cs);
|
|
rspinmask = digitalPinToBitMask(_rs);
|
|
SPI.begin();
|
|
SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz (half speed)
|
|
//Due defaults to 4mHz (clock divider setting of 21)
|
|
SPI.setBitOrder(MSBFIRST);
|
|
SPI.setDataMode(SPI_MODE0);
|
|
*csport &= ~cspinmask;
|
|
_inited = true;
|
|
#elif defined(__SAM3X8E__)
|
|
pinMode(_rs, OUTPUT);
|
|
pinMode(_cs, OUTPUT);
|
|
csport = digitalPinToPort(_cs);
|
|
rsport = digitalPinToPort(_rs);
|
|
cspinmask = digitalPinToBitMask(_cs);
|
|
rspinmask = digitalPinToBitMask(_rs);
|
|
SPI.begin();
|
|
SPI.setClockDivider(21); // 4 MHz
|
|
//Due defaults to 4mHz (clock divider setting of 21), but we'll set it anyway
|
|
SPI.setBitOrder(MSBFIRST);
|
|
SPI.setDataMode(SPI_MODE0);
|
|
// toggle RST low to reset; CS low so it'll listen to us
|
|
csport ->PIO_CODR |= cspinmask; // Set control bits to LOW (idle)
|
|
_inited = true;
|
|
#elif defined(__MK20DX128__) || defined(__MK20DX256__)
|
|
if (spi_pin_is_cs(_cs) && spi_pin_is_cs(_rs)
|
|
&& !(_cs == 2 && _rs == 10) && !(_rs == 2 && _cs == 10)
|
|
&& !(_cs == 6 && _rs == 9) && !(_rs == 6 && _cs == 9)
|
|
&& !(_cs == 20 && _rs == 23) && !(_rs == 20 && _cs == 23)
|
|
&& !(_cs == 21 && _rs == 22) && !(_rs == 21 && _cs == 22)) {
|
|
#if defined (_SPIINTERFACE_A)
|
|
CORE_PIN13_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE;
|
|
SPCR.setSCK(13);
|
|
CORE_PIN11_CONFIG = PORT_PCR_MUX(2);
|
|
SPCR.setMOSI(11);
|
|
#else
|
|
CORE_PIN14_CONFIG = PORT_PCR_MUX(2);
|
|
SPCR.setSCK(14);
|
|
CORE_PIN7_CONFIG = PORT_PCR_MUX(2);
|
|
SPCR.setMOSI(7);
|
|
#endif
|
|
ctar = CTAR_12MHz;
|
|
pcs_data = spi_configure_cs_pin(_cs);
|
|
pcs_command = pcs_data | spi_configure_cs_pin(_rs);
|
|
SIM_SCGC6 |= SIM_SCGC6_SPI0;
|
|
SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
|
|
SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7);
|
|
SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15);
|
|
SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
|
|
_inited = true;
|
|
} else {
|
|
_inited = false;
|
|
//error! cannot continue
|
|
// TODO! Escape code to stop all
|
|
}
|
|
#endif
|
|
if (_inited && _rst) {
|
|
pinMode(_rst, OUTPUT);
|
|
digitalWrite(_rst, HIGH);
|
|
delay(500);
|
|
digitalWrite(_rst, LOW);
|
|
delay(500);
|
|
digitalWrite(_rst, HIGH);
|
|
delay(500);
|
|
}
|
|
}
|
|
|
|
void TFT_ILI9340::begin(void) {
|
|
commonInit();
|
|
if (_inited) chipInit();
|
|
}
|
|
|
|
|
|
void TFT_ILI9340::chipInit() {
|
|
writeCommand(0xEF);
|
|
writeData(0x03);
|
|
writeData(0x80);
|
|
writeData(0x02);
|
|
|
|
writeCommand(0xCF);
|
|
writeData(0x00);
|
|
writeData(0XC1);
|
|
writeData(0X30);
|
|
|
|
writeCommand(0xED);
|
|
writeData(0x64);
|
|
writeData(0x03);
|
|
writeData(0X12);
|
|
writeData(0X81);
|
|
|
|
writeCommand(0xE8);
|
|
writeData(0x85);
|
|
writeData(0x00);
|
|
writeData(0x78);
|
|
|
|
writeCommand(0xCB);
|
|
writeData(0x39);
|
|
writeData(0x2C);
|
|
writeData(0x00);
|
|
writeData(0x34);
|
|
writeData(0x02);
|
|
|
|
writeCommand(0xF7);
|
|
writeData(0x20);
|
|
|
|
writeCommand(0xEA);
|
|
writeData(0x00);
|
|
writeData(0x00);
|
|
|
|
writeCommand(_CMD_PWCTR1);
|
|
writeData(0x23);
|
|
writeCommand(_CMD_PWCTR2);
|
|
writeData(0x10);
|
|
|
|
writeCommand(_CMD_VMCTR1);
|
|
writeData(0x3e);
|
|
writeData(0x28);
|
|
writeCommand(_CMD_VMCTR2);
|
|
writeData(0x86);
|
|
writeCommand(_CMD_MADCTL);
|
|
writeData(BIT_MADCTL_MX | BIT_MADCTL_BGR);
|
|
writeCommand(_CMD_PIXFMT);
|
|
writeData(0x55);
|
|
|
|
writeCommand(_CMD_FRMCTR1);
|
|
writeData(0x00);
|
|
writeData(0x18);
|
|
|
|
writeCommand(_CMD_DFUNCTR);
|
|
writeData(0x08);
|
|
writeData(0x82);
|
|
writeData(0x27);
|
|
|
|
writeCommand(0xF2);
|
|
writeData(0x00);
|
|
writeCommand(_CMD_GAMMASET);
|
|
writeData(0x01);
|
|
|
|
writeCommand(_CMD_GMCTRP1);
|
|
writeData(0x0F);
|
|
writeData(0x31);
|
|
writeData(0x2B);
|
|
writeData(0x0C);
|
|
writeData(0x0E);
|
|
writeData(0x08);
|
|
writeData(0x4E);
|
|
writeData(0xF1);
|
|
writeData(0x37);
|
|
writeData(0x07);
|
|
writeData(0x10);
|
|
writeData(0x03);
|
|
writeData(0x0E);
|
|
writeData(0x09);
|
|
writeData(0x00);
|
|
|
|
writeCommand(_CMD_GMCTRN1);
|
|
writeData(0x00);
|
|
writeData(0x0E);
|
|
writeData(0x14);
|
|
writeData(0x03);
|
|
writeData(0x11);
|
|
writeData(0x07);
|
|
writeData(0x31);
|
|
writeData(0xC1);
|
|
writeData(0x48);
|
|
writeData(0x08);
|
|
writeData(0x0F);
|
|
writeData(0x0C);
|
|
writeData(0x31);
|
|
writeData(0x36);
|
|
writeData(0x0F);
|
|
|
|
writeCommand(_CMD_SLPOUT);
|
|
delay(120);
|
|
writeCommand(_CMD_DISPON);
|
|
}
|
|
|
|
|
|
void TFT_ILI9340::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
|
|
writeCommand(_CMD_CASET);
|
|
writedata16(x0);
|
|
writedata16(x1);
|
|
writeCommand(_CMD_PASET);
|
|
writedata16(y0);
|
|
writedata16(y1);
|
|
writeCommand(_CMD_RAMWR);
|
|
}
|
|
|
|
bool TFT_ILI9340::boundaryCheck(int16_t x,int16_t y){
|
|
if ((x >= _width) || (y >= _height)) return true;
|
|
return false;
|
|
}
|
|
|
|
void TFT_ILI9340::pushColor(uint16_t color) {
|
|
writedata16(color);
|
|
}
|
|
|
|
void TFT_ILI9340::drawPixel(int16_t x, int16_t y, uint16_t color) {
|
|
if (boundaryCheck(x,y)) return;
|
|
if ((x < 0) || (y < 0)) return;
|
|
setAddrWindow(x,y,x+1,y+1);
|
|
writedata16(color);
|
|
}
|
|
|
|
|
|
void TFT_ILI9340::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
|
|
if (boundaryCheck(x,y)) return;
|
|
if (((y + h) - 1) >= _height) h = _height - y;
|
|
setAddrWindow(x,y,x,(y+h)-1);
|
|
while (h--) {
|
|
writedata16(color);
|
|
}
|
|
}
|
|
|
|
|
|
void TFT_ILI9340::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
|
|
if (boundaryCheck(x,y)) return;
|
|
if (((x+w) - 1) >= _width) w = _width-x;
|
|
setAddrWindow(x,y,(x+w)-1,y);
|
|
while (w--) {
|
|
writedata16(color);
|
|
}
|
|
}
|
|
|
|
void TFT_ILI9340::fillScreen(uint16_t color) {
|
|
fillRect(0,0,_width,_height,color);
|
|
}
|
|
|
|
// fill a rectangle
|
|
void TFT_ILI9340::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
|
if (boundaryCheck(x,y)) return;
|
|
if (((x + w) - 1) >= _width) w = _width - x;
|
|
if (((y + h) - 1) >= _height) h = _height - y;
|
|
setAddrWindow(x,y,(x+w)-1,(y+h)-1);
|
|
for (y = h;y > 0;y--) {
|
|
for (x = w;x > 0;x--) {
|
|
writedata16(color);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
|
|
uint16_t TFT_ILI9340::Color565(uint8_t r, uint8_t g, uint8_t b) {
|
|
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
|
}
|
|
|
|
|
|
void TFT_ILI9340::setRotation(uint8_t m) {
|
|
uint8_t _dta;
|
|
rotation = m % 4; // can't be higher than 3
|
|
switch (rotation) {
|
|
case 0:
|
|
_dta = BIT_MADCTL_MX | BIT_MADCTL_BGR;
|
|
_width = TFT_WIDTH;
|
|
_height = TFT_HEIGHT;
|
|
break;
|
|
case 1:
|
|
_dta = BIT_MADCTL_MV | BIT_MADCTL_BGR;
|
|
_width = TFT_HEIGHT;
|
|
_height = TFT_WIDTH;
|
|
break;
|
|
case 2:
|
|
_dta = BIT_MADCTL_MY | BIT_MADCTL_BGR;
|
|
_width = TFT_WIDTH;
|
|
_height = TFT_HEIGHT;
|
|
break;
|
|
case 3:
|
|
_dta = BIT_MADCTL_MV | BIT_MADCTL_MY | BIT_MADCTL_MX | BIT_MADCTL_BGR;
|
|
_width = TFT_HEIGHT;
|
|
_height = TFT_WIDTH;
|
|
break;
|
|
}
|
|
writeCommand(_CMD_MADCTL);
|
|
writeData(_dta);
|
|
}
|
|
|
|
|
|
void TFT_ILI9340::invertDisplay(boolean i) {
|
|
writeCommand(i ? _CMD_INVON : _CMD_INVOFF);
|
|
}
|
|
|
|
|
|
|