366 lines
9.8 KiB
C++
366 lines
9.8 KiB
C++
#ifndef LCD_ILI9341
|
|
#define LCD_ILI9341
|
|
|
|
#include "../../Debug.h"
|
|
|
|
// https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.cpp
|
|
// https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.h
|
|
|
|
// http://datasheets.gpio.dk/dl/ILI9341.pdf
|
|
|
|
// e.g.
|
|
// TJCTM24024-SPI
|
|
// http://play.fallows.ca/wp/projects/electronics-projects/tjctm24024-mystery-modules-china/
|
|
// http://datasheets.gpio.dk/dl/2.4inch-tft-touch/2.4%25e4%25b8%25b2%25e5%258f%25a3_TJC-024-9341/Module_SCH.pdf
|
|
// http://datasheets.gpio.dk/dl/ILI9341.pdf
|
|
|
|
#define ILI9341_TFTWIDTH 240 ///< ILI9341 max TFT width
|
|
#define ILI9341_TFTHEIGHT 320 ///< ILI9341 max TFT height
|
|
|
|
#define ILI9341_NOP 0x00 ///< No-op register
|
|
#define ILI9341_SWRESET 0x01 ///< Software reset register
|
|
#define ILI9341_RDDID 0x04 ///< Read display identification information
|
|
#define ILI9341_RDDST 0x09 ///< Read Display Status
|
|
|
|
#define ILI9341_SLPIN 0x10 ///< Enter Sleep Mode
|
|
#define ILI9341_SLPOUT 0x11 ///< Sleep Out
|
|
#define ILI9341_PTLON 0x12 ///< Partial Mode ON
|
|
#define ILI9341_NORON 0x13 ///< Normal Display Mode ON
|
|
|
|
#define ILI9341_RDMODE 0x0A ///< Read Display Power Mode
|
|
#define ILI9341_RDMADCTL 0x0B ///< Read Display MADCTL
|
|
#define ILI9341_RDPIXFMT 0x0C ///< Read Display Pixel Format
|
|
#define ILI9341_RDIMGFMT 0x0D ///< Read Display Image Format
|
|
#define ILI9341_RDSELFDIAG 0x0F ///< Read Display Self-Diagnostic Result
|
|
|
|
#define ILI9341_INVOFF 0x20 ///< Display Inversion OFF
|
|
#define ILI9341_INVON 0x21 ///< Display Inversion ON
|
|
#define ILI9341_GAMMASET 0x26 ///< Gamma Set
|
|
#define ILI9341_DISPOFF 0x28 ///< Display OFF
|
|
#define ILI9341_DISPON 0x29 ///< Display ON
|
|
|
|
#define ILI9341_CASET 0x2A ///< Column Address Set
|
|
#define ILI9341_PASET 0x2B ///< Page Address Set
|
|
#define ILI9341_RAMWR 0x2C ///< Memory Write
|
|
#define ILI9341_RAMRD 0x2E ///< Memory Read
|
|
|
|
#define ILI9341_PTLAR 0x30 ///< Partial Area
|
|
#define ILI9341_MADCTL 0x36 ///< Memory Access Control
|
|
#define ILI9341_VSCRSADD 0x37 ///< Vertical Scrolling Start Address
|
|
#define ILI9341_PIXFMT 0x3A ///< COLMOD: Pixel Format Set
|
|
|
|
#define ILI9341_FRMCTR1 0xB1 ///< Frame Rate Control (In Normal Mode/Full Colors)
|
|
#define ILI9341_FRMCTR2 0xB2 ///< Frame Rate Control (In Idle Mode/8 colors)
|
|
#define ILI9341_FRMCTR3 0xB3 ///< Frame Rate control (In Partial Mode/Full Colors)
|
|
#define ILI9341_INVCTR 0xB4 ///< Display Inversion Control
|
|
#define ILI9341_DFUNCTR 0xB6 ///< Display Function Control
|
|
|
|
#define ILI9341_PWCTR1 0xC0 ///< Power Control 1
|
|
#define ILI9341_PWCTR2 0xC1 ///< Power Control 2
|
|
#define ILI9341_PWCTR3 0xC2 ///< Power Control 3
|
|
#define ILI9341_PWCTR4 0xC3 ///< Power Control 4
|
|
#define ILI9341_PWCTR5 0xC4 ///< Power Control 5
|
|
#define ILI9341_VMCTR1 0xC5 ///< VCOM Control 1
|
|
#define ILI9341_VMCTR2 0xC7 ///< VCOM Control 2
|
|
|
|
#define ILI9341_RDID1 0xDA ///< Read ID 1
|
|
#define ILI9341_RDID2 0xDB ///< Read ID 2
|
|
#define ILI9341_RDID3 0xDC ///< Read ID 3
|
|
#define ILI9341_RDID4 0xDD ///< Read ID 4
|
|
|
|
#define ILI9341_GMCTRP1 0xE0 ///< Positive Gamma Correction
|
|
#define ILI9341_GMCTRN1 0xE1 ///< Negative Gamma Correction
|
|
//#define ILI9341_PWCTR6 0xFC
|
|
|
|
|
|
|
|
|
|
|
|
#include "../../io/SoftSPI.h"
|
|
#include "../../io/HardSPI.h"
|
|
|
|
|
|
static constexpr const uint8_t 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, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
|
|
ILI9341_GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma
|
|
//ILI9341_SLPOUT, 0x80, // Exit Sleep
|
|
//ILI9341_DISPON, 0x80, // Display on
|
|
0x00 // End of list
|
|
};
|
|
|
|
//template <int PIN_CS, int PIN_MISO, int PIN_MOSI, int PIN_CLK, int PIN_DATA_COMMAND> class ILI9341 {
|
|
template <int PIN_CS, int PIN_DATA_COMMAND, typename SPI> class ILI9341 {
|
|
|
|
private:
|
|
|
|
int w = 240;
|
|
int h = 320;
|
|
|
|
static constexpr const char* MOD = "ILI9341";
|
|
|
|
//HardSPI<PIN_MISO, PIN_MOSI, PIN_CLK> spi;
|
|
//SoftSPI<PIN_MISO, PIN_MOSI, PIN_CLK, true> spi;
|
|
SPI& spi;
|
|
|
|
public:
|
|
|
|
ILI9341(SPI& spi) : spi(spi) {
|
|
|
|
GPIO::setOutput(PIN_DATA_COMMAND);
|
|
GPIO::setOutput(PIN_CS);
|
|
|
|
//spi.init();
|
|
|
|
}
|
|
|
|
void setPixel(const uint16_t x, const uint16_t y, const uint16_t color) {
|
|
chipSelect();
|
|
setAddrWindow(x,y,1,1);
|
|
sendWord(color);
|
|
chipDeselect();
|
|
}
|
|
|
|
void setPixel(const uint16_t x, const uint16_t y, const uint8_t w, const uint16_t color) {
|
|
chipSelect();
|
|
setAddrWindow(x-w/2,y-w/2,w,w);
|
|
for (int i = 0; i < w*w; ++i) {
|
|
sendWord(color);
|
|
}
|
|
chipDeselect();
|
|
}
|
|
|
|
/** perform display software reset and initialization */
|
|
void init() {
|
|
|
|
chipSelect();
|
|
|
|
// send reset command
|
|
wait();
|
|
sendCommand(ILI9341_SWRESET);
|
|
wait();
|
|
|
|
// send init sequence
|
|
const uint8_t* bytes = initcmd;
|
|
while(*bytes) {
|
|
const uint8_t cmd = *bytes; ++bytes;
|
|
uint8_t numArgs = *bytes; ++bytes;
|
|
debugMod2(MOD, "send command %d (%d bytes)", cmd, numArgs);
|
|
sendCommand(cmd);
|
|
while(numArgs--) {
|
|
sendByte(*bytes);
|
|
++bytes;
|
|
}
|
|
}
|
|
|
|
// finalize init sequence
|
|
sendCommand(ILI9341_SLPOUT); wait();
|
|
sendCommand(ILI9341_DISPON); wait();
|
|
|
|
// done
|
|
chipDeselect();
|
|
|
|
}
|
|
|
|
uint32_t getID() {
|
|
chipSelect();
|
|
sendCommand16(ILI9341_RDDID);
|
|
uint32_t res = 0xFFFFFFFF;
|
|
readBytes(reinterpret_cast<uint8_t*>(&res), 4); // dummy-byte + 3 data bytes
|
|
chipDeselect();
|
|
return res;
|
|
}
|
|
|
|
void getStatus() {
|
|
chipSelect();
|
|
uint8_t buf[5];
|
|
sendCommand16(ILI9341_RDDID);
|
|
uint32_t res = 0xFFFFFFFF;
|
|
readBytes(buf, 5); // dummy-byte + 4 data bytes
|
|
chipDeselect();
|
|
ESP_LOGI(MOD, "%d %d %d %d", buf[1],buf[2],buf[3],buf[4]);
|
|
read();
|
|
}
|
|
|
|
void read() {
|
|
chipSelect();
|
|
setAddrWindow(0,0,100,100);
|
|
sendCommand(ILI9341_RAMRD);
|
|
uint8_t buf[32];
|
|
readBytes(buf, 32);
|
|
for (int i = 0; i < 32; ++i) {
|
|
printf("%d ", buf[i]);
|
|
}
|
|
printf("\n");
|
|
chipDeselect();
|
|
}
|
|
|
|
|
|
void draw(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t* data) {
|
|
chipSelect();
|
|
setAddrWindow(x,y,w,h);
|
|
const int len = w*h;
|
|
// for (int i = 0; i < len; ++i) {
|
|
// spi::writeWord(data[i]);
|
|
// }
|
|
spi.write((const uint8_t*)data, w*h*2);
|
|
chipDeselect();
|
|
}
|
|
|
|
void fillRand() {
|
|
|
|
// chipSelect();
|
|
// setAddrWindow(0,0,w,h);
|
|
// for (int i = 0; i < w*h/2; ++i) {
|
|
// sendQuad(rand());
|
|
// }
|
|
// chipDeselect();
|
|
|
|
chipSelect();
|
|
setAddrWindow(0,0,w,h);
|
|
for (int y = 0; y < h; ++y) {
|
|
uint16_t buf[w];
|
|
for (int x = 0; x < w; ++x) {buf[x] = rand();}
|
|
sendBytes(reinterpret_cast<uint8_t*>(buf), w*2);
|
|
}
|
|
chipDeselect();
|
|
|
|
}
|
|
|
|
void fill(const uint16_t color) {
|
|
|
|
chipSelect();
|
|
setAddrWindow(0,0,w,h);
|
|
for (int y = 0; y < h; ++y) {
|
|
uint16_t buf[w];
|
|
for (int x = 0; x < w; ++x) {buf[x] = color;}
|
|
sendBytes(reinterpret_cast<uint8_t*>(buf), w*2);
|
|
}
|
|
chipDeselect();
|
|
|
|
}
|
|
|
|
void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t color) {
|
|
|
|
chipSelect();
|
|
setAddrWindow(x,y,w,h);
|
|
for (int i = 0; i < w*h; ++i) {
|
|
sendWord(color);
|
|
}
|
|
chipDeselect();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
|
|
|
|
void setAddrWindow(const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) {
|
|
|
|
const uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
|
|
const uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
|
|
|
|
sendCommand(ILI9341_CASET); // Column addr set
|
|
sendQuad(xa);
|
|
|
|
sendCommand(ILI9341_PASET); // Row addr set
|
|
sendQuad(ya);
|
|
|
|
sendCommand(ILI9341_RAMWR); // write to RAM
|
|
// transmit data now
|
|
|
|
}
|
|
|
|
void wait() {
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
}
|
|
|
|
|
|
/** select the display (CS=0) */
|
|
inline void chipSelect() {
|
|
//spi::chipSelect();
|
|
GPIO::clear(PIN_CS);
|
|
}
|
|
|
|
|
|
/** send the given command to the display */
|
|
void sendCommand(const uint8_t cmd) {
|
|
modeCMD();
|
|
spi.writeByte(cmd);
|
|
modeDATA();
|
|
}
|
|
|
|
/** send the given command to the display */
|
|
void sendCommand16(const uint8_t cmd) {
|
|
modeCMD();
|
|
spi.writeByte(cmd);
|
|
spi.writeByte(0x00);
|
|
modeDATA();
|
|
}
|
|
|
|
/** send the given data byte to the display */
|
|
void sendByte(const uint8_t data) {
|
|
spi.writeByte(data);
|
|
}
|
|
|
|
/** send the given data word to the display */
|
|
void sendWord(const uint16_t data) {
|
|
spi.writeWord(data);
|
|
}
|
|
|
|
/** send the given data quad to the display */
|
|
void sendQuad(const uint32_t data) {
|
|
spi.writeQuad(data);
|
|
}
|
|
|
|
/** send the given data to the display */
|
|
void sendBytes(const uint8_t* data, const size_t len) {
|
|
spi.write(data, len);
|
|
}
|
|
|
|
/** read the given data from the display */
|
|
void readBytes(uint8_t* data, const size_t len) {
|
|
spi.read(data, len);
|
|
}
|
|
|
|
|
|
/** unselect the display (CS=1) */
|
|
inline void chipDeselect() {
|
|
//spi::chipDeselect();
|
|
GPIO::set(PIN_CS);
|
|
}
|
|
|
|
/** switch to command-mode */
|
|
inline void modeCMD() {
|
|
//gpio_set_level((gpio_num_t)PIN_DATA_COMMAND, 0);
|
|
GPIO::clear(PIN_DATA_COMMAND);
|
|
}
|
|
|
|
/** switch to data-mode */
|
|
inline void modeDATA() {
|
|
//gpio_set_level((gpio_num_t)PIN_DATA_COMMAND, 1);
|
|
GPIO::set(PIN_DATA_COMMAND);
|
|
}
|
|
|
|
|
|
};
|
|
|
|
#endif
|