/* * GraphLCD driver library * * ili9341.c - ILI9341 TFT driver class * * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * * (c) 2015 Andreas Regel */ #include #include #include #include #include #include #include "common.h" #include "config.h" #include "ili9341.h" namespace GLCD { const int kLcdWidth = 320; const int kLcdHeight = 240; const int kSpiBus = 0; const int kGpioPwm = 13; const int kGpioReset = 23; const int kGpioDC = 24; const uint8_t kCmdNop = 0x00; const uint8_t kCmdSleepOut = 0x11; const uint8_t kCmdGammaSet = 0x26; const uint8_t kCmdDisplayOn = 0x29; const uint8_t kCmdColumnAddressSet = 0x2A; const uint8_t kCmdPageAddressSet = 0x2B; const uint8_t kCmdMemoryWrite = 0x2C; const uint8_t kCmdMemoryAccessControl = 0x36; const uint8_t kCmdPixelFormatSet = 0x3A; const uint8_t kCmdFrameRateControl = 0xB1; const uint8_t kCmdDisplayFunctionControl = 0xB6; const uint8_t kCmdPowerControl1 = 0xC0; const uint8_t kCmdPowerControl2 = 0xC1; const uint8_t kCmdVcomControl1 = 0xC5; const uint8_t kCmdVcomControl2 = 0xC7; const uint8_t kCmdPositiveGammaControl = 0xE0; const uint8_t kCmdNegativeGammaControl = 0xE1; const uint8_t kCmdPowerControlA = 0xCB; const uint8_t kCmdPowerControlB = 0xCF; const uint8_t kCmdDriverTimingControlA = 0xE8; const uint8_t kCmdDriverTimingControlB = 0xEA; const uint8_t kCmdPowerOnSequenceControl = 0xED; const uint8_t kCmdUnknownEF = 0xEF; const uint8_t kCmdEnable3G = 0xF2; const uint8_t kCmdPumpRatioControl = 0xF7; cDriverILI9341::cDriverILI9341(cDriverConfig * config) : cDriver(config) { refreshCounter = 0; wiringPiSetupGpio(); } cDriverILI9341::~cDriverILI9341() { } int cDriverILI9341::Init() { width = config->width; if (width <= 0) width = kLcdWidth; height = config->height; if (height <= 0) height = kLcdHeight; for (unsigned int i = 0; i < config->options.size(); i++) { if (config->options[i].name == "") { } } // setup lcd array (wanted state) newLCD = new uint32_t[width * height]; if (newLCD) { memset(newLCD, 0, width * height * sizeof(uint32_t)); } // setup lcd array (current state) oldLCD = new uint32_t[width * height]; if (oldLCD) { memset(oldLCD, 0, width * height * sizeof(uint32_t)); } if (config->device == "") { return -1; } pinMode(kGpioReset, OUTPUT); pinMode(kGpioDC, OUTPUT); pinMode(kGpioPwm, PWM_OUTPUT); SetBrightness(config->brightness); digitalWrite(kGpioReset, HIGH); digitalWrite(kGpioDC, LOW); wiringPiSPISetup(kSpiBus, 64000000); /* reset display */ Reset(); WriteCommand(kCmdUnknownEF); WriteData(0x03); WriteData(0x80); WriteData(0x02); WriteCommand(kCmdPowerControlB); WriteData(0x00); WriteData(0xC1); WriteData(0x30); WriteCommand(kCmdPowerOnSequenceControl); WriteData(0x64); WriteData(0x03); WriteData(0x12); WriteData(0x81); WriteCommand(kCmdDriverTimingControlA); WriteData(0x85); WriteData(0x00); WriteData(0x78); WriteCommand(kCmdPowerControlA); WriteData(0x39); WriteData(0x2C); WriteData(0x00); WriteData(0x34); WriteData(0x02); WriteCommand(kCmdPumpRatioControl); WriteData(0x20); WriteCommand(kCmdDriverTimingControlB); WriteData(0x00); WriteData(0x00); WriteCommand(kCmdPowerControl1); WriteData(0x23); WriteCommand(kCmdPowerControl2); WriteData(0x10); WriteCommand(kCmdVcomControl1); WriteData(0x3e); WriteData(0x28); WriteCommand(kCmdVcomControl2); WriteData(0x86); WriteCommand(kCmdMemoryAccessControl); WriteData(0x48); WriteCommand(kCmdPixelFormatSet); WriteData(0x55); WriteCommand(kCmdFrameRateControl); WriteData(0x00); WriteData(0x18); WriteCommand(kCmdDisplayFunctionControl); WriteData(0x08); WriteData(0x82); WriteData(0x27); WriteCommand(kCmdEnable3G); WriteData(0x00); WriteCommand(kCmdGammaSet); WriteData(0x01); WriteCommand(kCmdPositiveGammaControl); 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(kCmdNegativeGammaControl); 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(kCmdSleepOut); usleep(120000); WriteCommand(kCmdDisplayOn); *oldConfig = *config; // clear display Clear(); syslog(LOG_INFO, "%s: ILI9341 initialized.\n", config->name.c_str()); return 0; } int cDriverILI9341::DeInit() { // free lcd array (wanted state) if (newLCD) { delete[] newLCD; } // free lcd array (current state) if (oldLCD) { delete[] oldLCD; } return 0; } int cDriverILI9341::CheckSetup() { if (config->device != oldConfig->device || config->width != oldConfig->width || config->height != oldConfig->height) { DeInit(); Init(); return 0; } if (config->upsideDown != oldConfig->upsideDown) { oldConfig->upsideDown = config->upsideDown; return 1; } return 0; } void cDriverILI9341::Clear() { memset(newLCD, 0, width * height * sizeof(uint32_t)); } void cDriverILI9341::SetPixel(int x, int y, uint32_t data) { if (x >= width || y >= height) return; if (config->upsideDown) { x = width - 1 - x; y = height - 1 - y; } newLCD[y * width + x] = data; } void cDriverILI9341::Refresh(bool refreshAll) { int y; if (CheckSetup() == 1) refreshAll = true; if (config->refreshDisplay > 0) { refreshCounter = (refreshCounter + 1) % config->refreshDisplay; if (!refreshAll && !refreshCounter) refreshAll = true; } refreshAll = true; if (refreshAll) { SetWindow(0, 0, height - 1, width - 1); WriteCommand(kCmdMemoryWrite); for (y = 0; y < width; y++) { uint8_t line[height * 2]; uint32_t * pixel = &newLCD[width - 1 - y]; for (int x = 0; x < (height * 2); x += 2) { line[x] = ((*pixel & 0x00F80000) >> 16) | ((*pixel & 0x0000E000) >> 13); line[x + 1] = ((*pixel & 0x00001C00) >> 5) | ((*pixel & 0x000000F8) >> 3); pixel += width; } WriteData((uint8_t *) line, height * 2); } memcpy(oldLCD, newLCD, width * height * sizeof(uint32_t)); // and reset RefreshCounter refreshCounter = 0; } else { // draw only the changed bytes } } void cDriverILI9341::SetBrightness(unsigned int percent) { uint32_t value; if (percent == 0) value = 0; else if (percent <= 10) value = 4; else if (percent <= 20) value = 8; else if (percent <= 30) value = 16; else if (percent <= 40) value = 32; else if (percent <= 50) value = 64; else if (percent <= 60) value = 128; else if (percent <= 70) value = 192; else if (percent <= 80) value = 320; else if (percent <= 90) value = 512; else value = 1023; pwmWrite(kGpioPwm, value); } void cDriverILI9341::Reset() { digitalWrite(kGpioReset, HIGH); usleep(10000); digitalWrite(kGpioReset, LOW); usleep(20000); digitalWrite(kGpioReset, HIGH); usleep(150000); } void cDriverILI9341::SetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { WriteCommand(kCmdColumnAddressSet); WriteData(x0 >> 8); WriteData(x0); WriteData(x1 >> 8); WriteData(x1); WriteCommand(kCmdPageAddressSet); WriteData(y0 >> 8); WriteData(y0); WriteData(y1 >> 8); WriteData(y1); } void cDriverILI9341::WriteCommand(uint8_t command) { digitalWrite(kGpioDC, LOW); wiringPiSPIDataRW(kSpiBus, &command, 1); digitalWrite(kGpioDC, HIGH); } void cDriverILI9341::WriteData(uint8_t data) { wiringPiSPIDataRW(kSpiBus, &data, 1); } void cDriverILI9341::WriteData(uint8_t * buffer, uint32_t length) { wiringPiSPIDataRW(kSpiBus, buffer, length); } } // end of namespace