blob: b0a4e5775adb60422061619f6b5a8df73f7410a7 [file] [log] [blame]
/*
* Author: Shawn Hymel
* Copyright (c) 2015 SparkFun Electronics
*
* Credits to Adafruit.
* Based on Adafruit ST7735 library, see original license in license.txt file.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <iostream>
#include <string>
#include <stdexcept>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ili9341.h"
using namespace upm;
ILI9341::ILI9341(uint8_t csLCD, uint8_t csSD, uint8_t dc, uint8_t rst) :
GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT), m_csLCDPinCtx(csLCD),
m_csSDPinCtx(csSD), m_dcPinCtx(dc), m_rstPinCtx(rst), m_spi(0) {
initModule();
configModule();
}
void ILI9341::initModule() {
mraa::Result error = mraa::SUCCESS;
error = m_csLCDPinCtx.dir(mraa::DIR_OUT);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
error = m_csSDPinCtx.dir(mraa::DIR_OUT);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
error = m_dcPinCtx.dir(mraa::DIR_OUT);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
error = m_rstPinCtx.dir(mraa::DIR_OUT);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
error = m_spi.frequency(SPI_FREQ);
if (error != mraa::SUCCESS) {
mraa::printError (error);
}
lcdCSOff();
}
void ILI9341::setRotation(uint8_t r) {
writecommand(ILI9341_MADCTL);
r = r % 4; // can't be higher than 3
switch(r) {
case 0:
writedata(MADCTL_MX | MADCTL_BGR);
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
break;
case 1:
writedata(MADCTL_MV | MADCTL_BGR);
_width = ILI9341_TFTHEIGHT;
_height = ILI9341_TFTWIDTH;
break;
case 2:
writedata(MADCTL_MY | MADCTL_BGR);
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
break;
case 3:
writedata(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
_width = ILI9341_TFTHEIGHT;
_height = ILI9341_TFTWIDTH;
break;
}
}
void ILI9341::configModule() {
// Toggle RST low to reset
rstHigh();
usleep(5000);
rstLow();
usleep(20000);
rstHigh();
usleep(150000);
// Send initialization commands
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(ILI9341_PWCTR1); //Power control
writedata(0x23); //VRH[5:0]
writecommand(ILI9341_PWCTR2); //Power control
writedata(0x10); //SAP[2:0];BT[3:0]
writecommand(ILI9341_VMCTR1); //VCM control
writedata(0x3e);
writedata(0x28);
writecommand(ILI9341_VMCTR2); //VCM control2
writedata(0x86); //--
writecommand(ILI9341_MADCTL); // Memory Access Control
writedata(0x48);
writecommand(ILI9341_PIXFMT);
writedata(0x55);
writecommand(ILI9341_FRMCTR1);
writedata(0x00);
writedata(0x18);
writecommand(ILI9341_DFUNCTR); // Display Function Control
writedata(0x08);
writedata(0x82);
writedata(0x27);
writecommand(0xF2); // 3Gamma Function Disable
writedata(0x00);
writecommand(ILI9341_GAMMASET); //Gamma curve selected
writedata(0x01);
writecommand(ILI9341_GMCTRP1); //Set Gamma
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(ILI9341_GMCTRN1); //Set Gamma
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(ILI9341_SLPOUT);
usleep(120000);
writecommand(ILI9341_DISPON);
}
void ILI9341::setAddrWindow(uint16_t x0,
uint16_t y0,
uint16_t x1,
uint16_t y1) {
writecommand(ILI9341_CASET); // Column addr set
writedata(x0 >> 8);
writedata(x0 & 0xFF); // XSTART
writedata(x1 >> 8);
writedata(x1 & 0xFF); // XEND
writecommand(ILI9341_PASET); // Row addr set
writedata(y0>>8);
writedata(y0); // YSTART
writedata(y1>>8);
writedata(y1); // YEND
writecommand(ILI9341_RAMWR); // write to RAM
}
void ILI9341::drawPixel(int16_t x, int16_t y, uint16_t color) {
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) {
return;
}
setAddrWindow(x, y, x + 1, y + 1);
writedata(color >> 8);
writedata(color);
}
void ILI9341::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
// Rudimentary clipping
if((x >= _width) || (y >= _height)) {
return;
}
if((y+h-1) >= _height) {
h = _height-y;
}
setAddrWindow(x, y, x, y+h-1);
uint8_t hi = color >> 8;
uint8_t lo = color;
lcdCSOn();
dcHigh();
while (h--) {
m_spi.writeByte(hi);
m_spi.writeByte(lo);
}
lcdCSOff();
}
void ILI9341::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
// Rudimentary clipping
if((x >= _width) || (y >= _height)) {
return;
}
if((x+w-1) >= _width) {
w = _width - x;
}
setAddrWindow(x, y, x+w-1, y);
uint8_t hi = color >> 8;
uint8_t lo = color;
lcdCSOn();
dcHigh();
while (w--) {
m_spi.writeByte(hi);
m_spi.writeByte(lo);
}
lcdCSOff();
}
void ILI9341::fillRect(int16_t x,
int16_t y,
int16_t w,
int16_t h,
uint16_t color) {
// rudimentary clipping (drawChar w/big text requires this)
if((x >= _width) || (y >= _height)) 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);
uint8_t hi = color >> 8;
uint8_t lo = color;
lcdCSOn();
dcHigh();
for(y = h; y > 0; y--) {
for(x = w; x > 0; x--) {
m_spi.writeByte(hi);
m_spi.writeByte(lo);
}
}
lcdCSOff();
}
void ILI9341::fillScreen(uint16_t color) {
fillRect(0, 0, _width, _height, color);
}
void ILI9341::invertDisplay(bool i) {
writecommand(i ? ILI9341_INVON : ILI9341_INVOFF);
}
uint16_t ILI9341::color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
void ILI9341::executeCMDList(const uint8_t *addr) {
uint8_t numCommands, numArgs;
uint16_t ms;
numCommands = *(addr++); // Number of commands to follow
while (numCommands--) { // For each command...
writecommand(*(addr++)); // Read, issue command
numArgs = *(addr++); // Number of args to follow
ms = numArgs & DELAY; // If hibit set, delay follows args
numArgs &= ~DELAY; // Mask out delay bit
while (numArgs--) { // For each argument...
writedata(*(addr++)); // Read, issue argument
}
if (ms) {
ms = *(addr++); // Read post-command delay time (ms)
if (ms == 255) {
ms = 500; // If 255, delay for 500 ms
}
usleep(ms * 1000);
}
}
}
void ILI9341::writecommand(uint8_t c) {
lcdCSOn();
dcLow();
m_spi.writeByte(c);
lcdCSOff();
}
void ILI9341::writedata(uint8_t d) {
lcdCSOn();
dcHigh();
m_spi.writeByte(d);
lcdCSOff();
}
mraa::Result ILI9341::lcdCSOn() {
mraa::Result error = mraa::SUCCESS;
error = m_csLCDPinCtx.write(LOW);
if (error != mraa::SUCCESS) {
mraa::printError (error);
}
error = m_csSDPinCtx.write(HIGH);
if (error != mraa::SUCCESS) {
mraa::printError (error);
}
return error;
}
mraa::Result ILI9341::lcdCSOff() {
mraa::Result error = mraa::SUCCESS;
error = m_csLCDPinCtx.write(HIGH);
if (error != mraa::SUCCESS) {
mraa::printError (error);
}
return error;
}
mraa::Result ILI9341::sdCSOn() {
mraa::Result error = mraa::SUCCESS;
error = m_csSDPinCtx.write(LOW);
if (error != mraa::SUCCESS) {
mraa::printError (error);
}
error = m_csLCDPinCtx.write(HIGH);
if (error != mraa::SUCCESS) {
mraa::printError (error);
}
return error;
}
mraa::Result ILI9341::sdCSOff() {
mraa::Result error = mraa::SUCCESS;
error = m_csSDPinCtx.write(HIGH);
if (error != mraa::SUCCESS) {
mraa::printError (error);
}
return error;
}
mraa::Result ILI9341::dcHigh() {
mraa::Result error = mraa::SUCCESS;
error = m_dcPinCtx.write(HIGH);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
return error;
}
mraa::Result ILI9341::dcLow() {
mraa::Result error = mraa::SUCCESS;
error = m_dcPinCtx.write(LOW);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
return error;
}
mraa::Result ILI9341::rstHigh() {
mraa::Result error = mraa::SUCCESS;
error = m_rstPinCtx.write(HIGH);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
return error;
}
mraa::Result ILI9341::rstLow() {
mraa::Result error = mraa::SUCCESS;
error = m_rstPinCtx.write(LOW);
if (error != mraa::SUCCESS) {
mraa::printError(error);
}
return error;
}