Files
SyncHome/trunk/Arduino/libraries/TFT_ILI9340/TFT_ILI9340.cpp

509 lines
12 KiB
C++
Raw Normal View History

2023-03-17 11:59:21 +00:00
#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);
}