mirror of https://github.com/arendst/Tasmota.git
283 lines
9.7 KiB
C++
283 lines
9.7 KiB
C++
|
/*!
|
||
|
* @file Adafruit_ILI9341.cpp
|
||
|
*
|
||
|
* @mainpage Adafruit ILI9341 TFT Displays
|
||
|
*
|
||
|
* @section intro_sec Introduction
|
||
|
*
|
||
|
* This is the documentation for Adafruit's ILI9341 driver for the
|
||
|
* Arduino platform.
|
||
|
*
|
||
|
* This library works with the Adafruit 2.8" Touch Shield V2 (SPI)
|
||
|
* http://www.adafruit.com/products/1651
|
||
|
*
|
||
|
* Adafruit 2.4" TFT LCD with Touchscreen Breakout w/MicroSD Socket - ILI9341
|
||
|
* https://www.adafruit.com/product/2478
|
||
|
*
|
||
|
* 2.8" TFT LCD with Touchscreen Breakout Board w/MicroSD Socket - ILI9341
|
||
|
* https://www.adafruit.com/product/1770
|
||
|
*
|
||
|
* 2.2" 18-bit color TFT LCD display with microSD card breakout - ILI9340
|
||
|
* https://www.adafruit.com/product/1770
|
||
|
*
|
||
|
* TFT FeatherWing - 2.4" 320x240 Touchscreen For All Feathers
|
||
|
* https://www.adafruit.com/product/3315
|
||
|
*
|
||
|
* These displays use SPI to communicate, 4 or 5 pins are required
|
||
|
* to interface (RST is optional).
|
||
|
*
|
||
|
* Adafruit invests time and resources providing this open source code,
|
||
|
* please support Adafruit and open-source hardware by purchasing
|
||
|
* products from Adafruit!
|
||
|
*
|
||
|
* @section dependencies Dependencies
|
||
|
*
|
||
|
* This library depends on <a href="https://github.com/adafruit/Adafruit_GFX">
|
||
|
* Adafruit_GFX</a> being present on your system. Please make sure you have
|
||
|
* installed the latest version before using this library.
|
||
|
*
|
||
|
* @section author Author
|
||
|
*
|
||
|
* Written by Limor "ladyada" Fried for Adafruit Industries.
|
||
|
*
|
||
|
* @section license License
|
||
|
*
|
||
|
* BSD license, all text here must be included in any redistribution.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "Adafruit_ILI9341.h"
|
||
|
#ifndef ARDUINO_STM32_FEATHER
|
||
|
#include "pins_arduino.h"
|
||
|
#ifndef RASPI
|
||
|
#include "wiring_private.h"
|
||
|
#endif
|
||
|
#endif
|
||
|
#include <limits.h>
|
||
|
|
||
|
#if defined (ARDUINO_ARCH_ARC32) || defined (ARDUINO_MAXIM)
|
||
|
#define SPI_DEFAULT_FREQ 16000000
|
||
|
#elif defined (__AVR__) || defined(TEENSYDUINO)
|
||
|
#define SPI_DEFAULT_FREQ 8000000
|
||
|
#elif defined(ESP8266) || defined(ESP32)
|
||
|
#define SPI_DEFAULT_FREQ 40000000
|
||
|
#elif defined(RASPI)
|
||
|
#define SPI_DEFAULT_FREQ 80000000
|
||
|
#elif defined(ARDUINO_ARCH_STM32F1)
|
||
|
#define SPI_DEFAULT_FREQ 36000000
|
||
|
#else
|
||
|
#define SPI_DEFAULT_FREQ 24000000 ///< Default SPI data clock frequency
|
||
|
#endif
|
||
|
|
||
|
#define MADCTL_MY 0x80 ///< Bottom to top
|
||
|
#define MADCTL_MX 0x40 ///< Right to left
|
||
|
#define MADCTL_MV 0x20 ///< Reverse Mode
|
||
|
#define MADCTL_ML 0x10 ///< LCD refresh Bottom to top
|
||
|
#define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order
|
||
|
#define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order
|
||
|
#define MADCTL_MH 0x04 ///< LCD refresh right to left
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Instantiate Adafruit ILI9341 driver with software SPI
|
||
|
@param cs Chip select pin #
|
||
|
@param dc Data/Command pin #
|
||
|
@param mosi SPI MOSI pin #
|
||
|
@param sclk SPI Clock pin #
|
||
|
@param rst Reset pin # (optional, pass -1 if unused)
|
||
|
@param miso SPI MISO pin # (optional, pass -1 if unused)
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t mosi,
|
||
|
int8_t sclk, int8_t rst, int8_t miso) : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, cs, dc, mosi, sclk, rst, miso) {
|
||
|
}
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Instantiate Adafruit ILI9341 driver with hardware SPI
|
||
|
@param cs Chip select pin #
|
||
|
@param dc Data/Command pin #
|
||
|
@param rst Reset pin # (optional, pass -1 if unused)
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst) : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, cs, dc, rst) {
|
||
|
}
|
||
|
|
||
|
static const uint8_t PROGMEM initcmd[] = {
|
||
|
0xEF, 3, 0x03, 0x80, 0x02,
|
||
|
0xCF, 3, 0x00, 0xC1, 0x30,
|
||
|
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
||
|
0xE8, 3, 0x85, 0x00, 0x78,
|
||
|
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
||
|
0xF7, 1, 0x20,
|
||
|
0xEA, 2, 0x00, 0x00,
|
||
|
ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
|
||
|
ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||
|
ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control
|
||
|
ILI9341_VMCTR2 , 1, 0x86, // VCM control2
|
||
|
ILI9341_MADCTL , 1, 0x48, // Memory Access Control
|
||
|
ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||
|
ILI9341_PIXFMT , 1, 0x55,
|
||
|
ILI9341_FRMCTR1 , 2, 0x00, 0x18,
|
||
|
ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
|
||
|
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||
|
ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected
|
||
|
ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||
|
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
|
||
|
ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||
|
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
|
||
|
ILI9341_SLPOUT , 0x80, // Exit Sleep
|
||
|
ILI9341_DISPON , 0x80, // Display on
|
||
|
0x00 // End of list
|
||
|
};
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Initialize ILI9341 chip
|
||
|
Connects to the ILI9341 over SPI and sends initialization procedure commands
|
||
|
@param freq Desired SPI clock frequency
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
void Adafruit_ILI9341::begin(uint32_t freq) {
|
||
|
if(!freq) freq = SPI_DEFAULT_FREQ;
|
||
|
_freq = freq;
|
||
|
|
||
|
initSPI(freq);
|
||
|
|
||
|
startWrite();
|
||
|
|
||
|
uint8_t cmd, x, numArgs;
|
||
|
const uint8_t *addr = initcmd;
|
||
|
while((cmd = pgm_read_byte(addr++)) > 0) {
|
||
|
writeCommand(cmd);
|
||
|
x = pgm_read_byte(addr++);
|
||
|
numArgs = x & 0x7F;
|
||
|
while(numArgs--) spiWrite(pgm_read_byte(addr++));
|
||
|
if(x & 0x80) delay(120);
|
||
|
}
|
||
|
|
||
|
endWrite();
|
||
|
|
||
|
_width = ILI9341_TFTWIDTH;
|
||
|
_height = ILI9341_TFTHEIGHT;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Set origin of (0,0) and orientation of TFT display
|
||
|
@param m The index for rotation, from 0-3 inclusive
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
void Adafruit_ILI9341::setRotation(uint8_t m) {
|
||
|
rotation = m % 4; // can't be higher than 3
|
||
|
switch (rotation) {
|
||
|
case 0:
|
||
|
m = (MADCTL_MX | MADCTL_BGR);
|
||
|
_width = ILI9341_TFTWIDTH;
|
||
|
_height = ILI9341_TFTHEIGHT;
|
||
|
break;
|
||
|
case 1:
|
||
|
m = (MADCTL_MV | MADCTL_BGR);
|
||
|
_width = ILI9341_TFTHEIGHT;
|
||
|
_height = ILI9341_TFTWIDTH;
|
||
|
break;
|
||
|
case 2:
|
||
|
m = (MADCTL_MY | MADCTL_BGR);
|
||
|
_width = ILI9341_TFTWIDTH;
|
||
|
_height = ILI9341_TFTHEIGHT;
|
||
|
break;
|
||
|
case 3:
|
||
|
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
|
||
|
_width = ILI9341_TFTHEIGHT;
|
||
|
_height = ILI9341_TFTWIDTH;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
startWrite();
|
||
|
writeCommand(ILI9341_MADCTL);
|
||
|
spiWrite(m);
|
||
|
endWrite();
|
||
|
}
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Enable/Disable display color inversion
|
||
|
@param invert True to invert, False to have normal color
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
void Adafruit_ILI9341::invertDisplay(boolean invert) {
|
||
|
startWrite();
|
||
|
writeCommand(invert ? ILI9341_INVON : ILI9341_INVOFF);
|
||
|
endWrite();
|
||
|
}
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Scroll display memory
|
||
|
@param y How many pixels to scroll display by
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
void Adafruit_ILI9341::scrollTo(uint16_t y) {
|
||
|
startWrite();
|
||
|
writeCommand(ILI9341_VSCRSADD);
|
||
|
SPI_WRITE16(y);
|
||
|
endWrite();
|
||
|
}
|
||
|
|
||
|
/**************************************************************************/
|
||
|
|
||
|
void Adafruit_ILI9341::setScrollMargins(uint16_t top, uint16_t bottom)
|
||
|
{
|
||
|
uint16_t height = _height - (top + bottom);
|
||
|
|
||
|
startWrite();
|
||
|
writeCommand(0x33);
|
||
|
SPI_WRITE16(top);
|
||
|
SPI_WRITE16(height);
|
||
|
SPI_WRITE16(bottom);
|
||
|
endWrite();
|
||
|
}
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Set the "address window" - the rectangle we will write to RAM with the next chunk of SPI data writes. The ILI9341 will automatically wrap the data as each row is filled
|
||
|
@param x TFT memory 'x' origin
|
||
|
@param y TFT memory 'y' origin
|
||
|
@param w Width of rectangle
|
||
|
@param h Height of rectangle
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
void Adafruit_ILI9341::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
|
||
|
uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
|
||
|
uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
|
||
|
writeCommand(ILI9341_CASET); // Column addr set
|
||
|
SPI_WRITE32(xa);
|
||
|
writeCommand(ILI9341_PASET); // Row addr set
|
||
|
SPI_WRITE32(ya);
|
||
|
writeCommand(ILI9341_RAMWR); // write to RAM
|
||
|
}
|
||
|
|
||
|
/**************************************************************************/
|
||
|
/*!
|
||
|
@brief Read 8 bits of data from ILI9341 configuration memory. NOT from RAM!
|
||
|
This is highly undocumented/supported, it's really a hack but kinda works?
|
||
|
@param command The command register to read data from
|
||
|
@param index The byte index into the command to read from
|
||
|
@return Unsigned 8-bit data read from ILI9341 register
|
||
|
*/
|
||
|
/**************************************************************************/
|
||
|
uint8_t Adafruit_ILI9341::readcommand8(uint8_t command, uint8_t index) {
|
||
|
uint32_t freq = _freq;
|
||
|
if(_freq > 24000000) _freq = 24000000;
|
||
|
startWrite();
|
||
|
writeCommand(0xD9); // woo sekret command?
|
||
|
spiWrite(0x10 + index);
|
||
|
writeCommand(command);
|
||
|
uint8_t r = spiRead();
|
||
|
endWrite();
|
||
|
_freq = freq;
|
||
|
return r;
|
||
|
}
|
||
|
|