From 425551ca70b54bc921df419f0fdc2099de86730f Mon Sep 17 00:00:00 2001 From: maggi Date: Thu, 20 Aug 2020 16:20:52 +0200 Subject: [PATCH] Initial commit --- TFT_ILI9163C/README.md | 221 ++++++ TFT_ILI9163C/TFT_ILI9163C.cpp | 1114 +++++++++++++++++++++++++++++++ TFT_ILI9163C/TFT_ILI9163C.h | 418 ++++++++++++ TFT_ILI9163C/keywords.txt | 21 + TFT_ILI9163C/library.properties | 9 + 5 files changed, 1783 insertions(+) create mode 100644 TFT_ILI9163C/README.md create mode 100644 TFT_ILI9163C/TFT_ILI9163C.cpp create mode 100644 TFT_ILI9163C/TFT_ILI9163C.h create mode 100644 TFT_ILI9163C/keywords.txt create mode 100644 TFT_ILI9163C/library.properties diff --git a/TFT_ILI9163C/README.md b/TFT_ILI9163C/README.md new file mode 100644 index 0000000..54940cf --- /dev/null +++ b/TFT_ILI9163C/README.md @@ -0,0 +1,221 @@ +TFT_ILI9163C + +A fast SPI driver for TFT that use Ilitek ILI9163C driver for Arduino's Teensy's and more... + +Current release: 0.9 (old! see below!) + +Version 1.0 it's one the corner!
+New version doesn't use the adafruit_GFX and have all the drawing incorporated, this because I've speedup a lot with all processors and uses less resources.
+The very last preview, completely recoded, with GPO Font Rendering an ICON support, also support all the current display around:
+https://github.com/sumotoy/TFT_ILI9163C/tree/Pre-Release-1.0p7
+ +Can be used with IDE 1.0.6 (Teensyduino 1.20) or IDE 1.6.x (Teensyduino 1.21b or better)
+ +Notice: In early 2016 appeared in the market a new version of this display with yellow pins and slight smaller.
+This version needs the 'pre-release' 1.0r6 or better that will released sunday 17/4/2016
+ +![ILI9163C](http://i1189.photobucket.com/albums/z437/theamra/github/CIMG6810.jpg) + + Link to a video: + +https://www.youtube.com/watch?v=y5f-VNBxgEk&feature=youtu.be + + Tested with: + Teensy 3.0 -> really fast + Teensy 3.1 -> really fast + Teensy LC -> still not 100% optimized but fast + UNO and similar -> still not 100% optimized but fast + DUE -> still not 100% optimized but fast + ESP8266 -> use the preview 1.0p4 and works + +========================== + +Features: + + - Very FAST!, expecially with Teensy 3.x where uses hyper fast SPI. + - Tons of examples !!! + - It uses just 4 wires (2 shared with other devices). + - Compatible at command level with Adafruit display series so it's easy to adapt existing code. + - It uses the standard Adafruit_GFX Library (you need to install). + - SPI transaction compatible (only where supported, actually only Teensy3 but soon more) + - Working with IDE 1.0.6, 1.5.8 (or newer), Energia (soon) + - Working with Arduino's (8 and 32 bit), Teensy 3, Teensy 3.1 and Teensy LC + - Working with Energia supported MCU (not yet but really soon) + - A Fast SPI DMA for Nucleo F411RE porting from MasudaNaika https://github.com/MasudaNaika + - Current version should work even with ESP8266! + +http://developer.mbed.org/users/peu605/code/TFT_ILI9163C/ + +Pay Attention to connections!!!!: + + - This display has logic at 3V3 volt so YOU NEED A VOLTAGE CONVERTER if you plan to use with arduino. + If you try to connect directly you can burn it very fast so PAY ATTENTION! + - My display works at 3V3 volt and uses 3V3 for logic but LED background has resistor for 5V. + Your can be different so carefully check out before connect it. + - Library works only in SPI mode by using MOSI,SCLK and a CS pin plus an additional pin for DC (or RS). + I've used also the reset pin but you can save it by connect it at 3V3 volt and use the constructor without + the reset pin. The initialization routine will automatically use the software reset. + + - Teensy 3 and LC cannot use any pin for CS and RS(DC) but should be choosen as follow: + pins:2,6,9 or 10,15 or 20,13 for CS and RS. + The benchmark.ino example has a routine that can help you to understand if you have choosed the right pin for your Teensy. + For reset you can use any pin, if you want to save a wire and not use reset, YOU SHOULD CONNECT TO 3V3 OR USE + A PULLUP RESISTOR (10K to 3V3) BUT NOT LEAVE FLOATING! + +Backgrounds: + + I got one of those displays from a chinese ebay seller but unfortunatly I cannot get + any working library so I decided to work on it. ILI9163C looks pretty similar to other + display driver but it uses it's own commands so it's tricky to work with it unlsess you + carefully fight with his gigantic and confused datasheet. + My display it's a 1.44"", 128x128 that suppose to substitute Nokia 5110 LCD and here's the + first confusion! Many sellers claim that it's compatible with Nokia 5110 (that use a philips + controller) but the only similarity it's the pin names since that this one it's color and + have totally different controller that's not compatible. Altrough I discovered that it's not + 128x128 but 128x160 (!??)... Check links below to see if it's similar to yours. + UPDATE: + Some chinese seller connected the TFT aligned to bottom, other aligned to top, there's not a sure + way to discover witch is yours so better try one of the configurations. + +http://www.ebay.com/itm/Replace-Nokia-5110-LCD-1-44-Red-Serial-128X128-SPI-Color-TFT-LCD-Display-Module-/141196897388 + +http://www.elecrow.com/144-128x-128-tft-lcd-with-spi-interface-p-855.html + + This TFT it's really cheap but has surprising features since it support very high speed SPI trasfer + (over 40Mhz tested!) and can be used as frame buffer, colors are quite tunable and has a tons of settings. + It also support repetitive serial transfer so it can react very fast. + +BLACK, RED or ... + + There's different strain of this display on ebay, I have try to tracking all of them but may missing some species! Actually the more popular has a RED pcb and a BLACK pcb that are completely same pcb but mount a different display that need some tweaking, in particular RED ones need offset but also some tweak for colors, etc. In the .h file in the library try to comment out one of the presets: + //#define __144_RED_PCB__ + #define __144_BLACK_PCB__ + //#define __22_RED_PCB__ + I have a discussion here where a couple of users claim that the _GRAMHEIGH propriety should be always 128. + This is true ONLY if you will never use scroll! Scroll use the entire memory mapped to screen, my RED tag one + it's 128x128 but it uses 128x160! If during scroll you have some garbage means that you have not correctly + setup the display property: + + #define _TFTWIDTH 128//the REAL W resolution of the TFT + #define _TFTHEIGHT 128//the REAL H resolution of the TFT + #define _GRAMWIDTH 128 + #define _GRAMHEIGH 160//Heh? Yes! My display uses offset! + #define _GRAMSIZE _GRAMWIDTH * _GRAMHEIGH // + #define __COLORSPC 1// 1:GBR - 0:RGB + #define __GAMMASET3 //uncomment for another gamma (1,2,3) + #define __OFFSET 32//this is the offset of my display, 160 - 128 = 32 + + You can write your own one by adding it in the .h file but let me know so I can add for other users. + The OFFSET have sense if the chinese vendor decided to align TFT at bottom lines of the controller. + This is nonsense since it will force you to use all the off-screen area as well (visible only when you use + scrolling). + +Code Optimizations: + + The purpose of this library it's SPEED. I have tried to use hardware optimized calls + where was possible and results are quite good for most applications. + Of course it can be improved so feel free to add suggestions. + You will notice that not all display command was added, this because this chip it's really fast + but have very poor hardware design, for example, the display on/off command will result in a bright + white screen since chip will pullup all display lines (at list my display act as this), a nonsense to me, + should be exact the opposite! Apart display there's other commands that act the same so I decided to + don't include to save space. + The Teensy 3 side it's almost complete and quite optimized, however Arduino's side can be tweaked a bit + by using the same Teensy3 technique (multiple transfer with just one CS call, etc), this will be the 1.0 version. + +Needed stuff you have to install first!!! + + This library use Adafruit GFX library as all my TFT,OLED and LCD libraries: + (Remember to update GFX library often to have more features with this and other library!) + + +https://github.com/adafruit/Adafruit-GFX-Library + + Since Adafruit are quite reluctant to update often I have a 100% compatible one that it's faster and has + more features, faster char rendering, ability to use different fonts etc. + +https://github.com/sumotoy/Adafruit-GFX-Library + + It's 100% compatible with the Adafruit one so don't worry about. + + If you plan to use an SD for the SD example you will need Bill Greyman's SdFat + +https://github.com/greiman/SdFat + + +Wiring: + + You are a newbie and need help? Here's: + This display has 8 pin (at the time I'm writing this): + + TFT side -------------------- microprocessor + - Vcc --> +3V3V(!!!!) + - Gnd --> Gnd + - CS --> CS pin (3v3 level!) + - RST --> connect to a MCU pin or tie to +3V3 or 10K to 3V3 (do NOT leave float!) + - A0 --> DC or RS pin (3v3 level!) + - SDA --> Mosi (3v3 level!) + - SCK --> Sclk (3v3 level!) + - LED --> Some display need a resistor (see note below) + +* Note about led: + +Some display have an internal resistor to limit current, you see on the back of the display, following LED pcb +trace with your eyes and if you see a resistor (100 Ohm mine) you can connect this line directly to +5V. +But be careful do not try connect to 5V before you check the presence of this resistor on pcb, you can try first by using a resistor of 220 ohm, if the image looks very dark, try 100 and if still very dark, tie directly to 5v. + +Utility included: + + Included you will find LCD Image Converter a free utility to convert in code a 24bit image. + +https://github.com/riuson/lcd-image-converter + + see example bigPicture.ino. + I have included datasheet as well. +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Special Thanks: + + Thanks Adafruit for his Adafruit_GFX! + Thanks to Paul Stoffregen for his beautiful Teensy3 and high speed SPI magic. + Thanks to riuson https://github.com/riuson for kindly provide lcd tool + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Version: + + 0.1a1: First release, compile correctly. Altrough not fully working! + 0.1a3: Some bugfix, still some addressing problems, partial rotation solved. + 0.1b1: Beta version! Fully working but still not tested with Arduino and DUE (altrough it compile) + 0.2b2: Code cleaned and added support for 2.2" RED PCB displays. + 0.2b4: Bug fixes and added color space support. + 0.3b1: Complete rework on Teensy SPI based on Paul Stoffregen work + SPI transaction,added BLACK TAG 2.2 display + 0.3b2: Added 24bit image display code and example. + 0.5: A lot of changes, preliminary scroll, added sleep and some other command but + most important fixed a nasty bug on fillScreen. If you have download any previous + version you should upgrade since there was several fixes. + 0.6: Added subroutines for SD fast load images (mainly for Teensy3) + 0.6b1: Rolled back clearScreen. Again the datasheet have wrong infos! Grrr + 0.6b2: scroll completed. + 0.6b3: ClearScreen v2 fix. Added idle mode. + 0.7: Gold release candidate. Fixed initialization (thanks Masuda) + 0.75: SPI transactions for Arduino's (beta) please report if troubles (not tested) + 0.8: Added compatibility with IDE 1.6.x (Teensyduino 1.21b) + 0.9: Big changes, support for Teensy LC, alt pin for Teensy's, more CPU, faster DUE, separate setting file, + etc., etc. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Legal Notes: + + This library it's free to use but if you port for other MCU or include in distribution or whatever you have + to leave intact the readme inside the library, add your text about modifications but leave intact the text + in the .h file. + If you included in distributions please leave me a note. + If you porting for other MCU or IDE, leave me a note, I will included in the readme here the link. + +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. diff --git a/TFT_ILI9163C/TFT_ILI9163C.cpp b/TFT_ILI9163C/TFT_ILI9163C.cpp new file mode 100644 index 0000000..cbad3bf --- /dev/null +++ b/TFT_ILI9163C/TFT_ILI9163C.cpp @@ -0,0 +1,1114 @@ +#include "TFT_ILI9163C.h" +#include +#include "pins_arduino.h" +#include "wiring_private.h" +#include + +#if defined(SPI_HAS_TRANSACTION) + static SPISettings ILI9163C_SPI; +#endif + + +//constructors + +#if defined(__MK20DX128__) || defined(__MK20DX256__) + TFT_ILI9163C::TFT_ILI9163C(uint8_t cspin,uint8_t dcpin,uint8_t rstpin,uint8_t mosi,uint8_t sclk) : Adafruit_GFX(_TFTWIDTH,_TFTHEIGHT) + { + _cs = cspin; + _rs = dcpin; + _rst = rstpin; + _mosi = mosi; + _sclk = sclk; + } +#elif defined(__MKL26Z64__) + TFT_ILI9163C::TFT_ILI9163C(uint8_t cspin,uint8_t dcpin,uint8_t rstpin,uint8_t mosi,uint8_t sclk) : Adafruit_GFX(_TFTWIDTH,_TFTHEIGHT) + { + _cs = cspin; + _rs = dcpin; + _rst = rstpin; + _mosi = mosi; + _sclk = sclk; + _useSPI1 = false; + if ((_mosi == 0 || _mosi == 21) && (_sclk == 20)) _useSPI1 = true; + } +#else + TFT_ILI9163C::TFT_ILI9163C(uint8_t cspin,uint8_t dcpin,uint8_t rstpin) : Adafruit_GFX(_TFTWIDTH,_TFTHEIGHT) + { + _cs = cspin; + _rs = dcpin; + _rst = rstpin; + } +#endif + + +//Arduino Uno, Leonardo, Mega, Teensy 2.0, etc +#if defined(__AVR__) + + inline void TFT_ILI9163C::spiwrite(uint8_t c) + { + SPDR = c; + while(!(SPSR & _BV(SPIF))); + } + + void TFT_ILI9163C::writecommand(uint8_t c) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + *rsport &= ~rspinmask;//low + *csport &= ~cspinmask;//low + spiwrite(c); + *csport |= cspinmask;//hi + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::writedata(uint8_t c) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + *rsport |= rspinmask;//hi + *csport &= ~cspinmask;//low + spiwrite(c); + *csport |= cspinmask;//hi + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::writedata16(uint16_t d) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + *rsport |= rspinmask;//hi + *csport &= ~cspinmask;//low + spiwrite(d >> 8); + spiwrite(d); + *csport |= cspinmask;//hi + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::setBitrate(uint32_t n) + { + #if !defined (SPI_HAS_TRANSACTION) + 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); + } + #endif + } +#elif defined(__SAM3X8E__)// Arduino Due + inline void TFT_ILI9163C::spiwrite(uint8_t c) + { + SPI.transfer(c); + } + + void TFT_ILI9163C::writecommand(uint8_t c) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + rsport->PIO_CODR |= rspinmask;//LO + csport->PIO_CODR |= cspinmask;//LO + spiwrite(c); + csport->PIO_SODR |= cspinmask;//HI + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::writedata(uint8_t c) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + rsport->PIO_SODR |= rspinmask;//HI + csport->PIO_CODR |= cspinmask;//LO + spiwrite(c); + csport->PIO_SODR |= cspinmask;//HI + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::writedata16(uint16_t d) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + rsport->PIO_SODR |= rspinmask;//HI + csport->PIO_CODR |= cspinmask;//LO + spiwrite(d >> 8); + spiwrite(d); + csport->PIO_SODR |= cspinmask;//HI + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + + void TFT_ILI9163C::setBitrate(uint32_t n) + { + #if !defined(SPI_HAS_TRANSACTION) + uint32_t divider = 1; + while (divider < 255) { + if (n >= 84000000 / divider) break; + divider = divider - 1; + } + SPI.setClockDivider(divider); + #endif + } +#elif defined(__MKL26Z64__)//Teensy LC (preliminary + + void TFT_ILI9163C::writecommand(uint8_t c) + { + if (_useSPI1){ + SPI1.beginTransaction(ILI9163C_SPI); + digitalWriteFast(_rs,LOW); + digitalWriteFast(_cs,LOW); + SPI1.transfer(c); + digitalWriteFast(_cs,HIGH); + SPI1.endTransaction(); + } else { + SPI.beginTransaction(ILI9163C_SPI); + digitalWriteFast(_rs,LOW); + digitalWriteFast(_cs,LOW); + SPI.transfer(c); + digitalWriteFast(_cs,HIGH); + SPI.endTransaction(); + } + } + + void TFT_ILI9163C::writedata(uint8_t c) + { + if (_useSPI1){ + SPI1.beginTransaction(ILI9163C_SPI); + digitalWriteFast(_rs,HIGH); + digitalWriteFast(_cs,LOW); + SPI1.transfer(c); + digitalWriteFast(_cs,HIGH); + SPI1.endTransaction(); + } else { + SPI.beginTransaction(ILI9163C_SPI); + digitalWriteFast(_rs,HIGH); + digitalWriteFast(_cs,LOW); + SPI.transfer(c); + digitalWriteFast(_cs,HIGH); + SPI.endTransaction(); + } + } + + void TFT_ILI9163C::writedata16(uint16_t d) + { + if (_useSPI1){ + SPI1.beginTransaction(ILI9163C_SPI); + digitalWriteFast(_rs,HIGH); + digitalWriteFast(_cs,LOW); + SPI1.transfer16(d); + digitalWriteFast(_cs,HIGH); + SPI1.endTransaction(); + } else { + SPI.beginTransaction(ILI9163C_SPI); + digitalWriteFast(_rs,HIGH); + digitalWriteFast(_cs,LOW); + SPI.transfer16(d); + digitalWriteFast(_cs,HIGH); + SPI.endTransaction(); + } + } + + void TFT_ILI9163C::setBitrate(uint32_t n) + { + //nop + } +#elif defined(__MK20DX128__) || defined(__MK20DX256__)//Teensy 3.0 & 3.1 + + void TFT_ILI9163C::setBitrate(uint32_t n) + { + //nop + } +#else + + void TFT_ILI9163C::writecommand(uint8_t c) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + digitalWrite(_rs,LOW); + digitalWrite(_cs,LOW); + SPI.transfer(c); + digitalWrite(_cs,HIGH); + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::writedata(uint8_t c) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + digitalWrite(_rs,HIGH); + digitalWrite(_cs,LOW); + SPI.transfer(c); + digitalWrite(_cs,HIGH); + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::writedata16(uint16_t d) + { + #if defined(SPI_HAS_TRANSACTION) + SPI.beginTransaction(ILI9163C_SPI); + #endif + digitalWrite(_rs,HIGH); + digitalWrite(_cs,LOW); + SPI.transfer(d >> 8); + SPI.transfer(d); + digitalWrite(_cs,HIGH); + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif + } + + void TFT_ILI9163C::setBitrate(uint32_t n) + { + //nop + } +#endif //#if defined(TEENSY3.x) + + +void TFT_ILI9163C::begin(void) +{ + sleep = 0; + _initError = 0b00000000; +#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(); + #if !defined(SPI_HAS_TRANSACTION) + SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + #else + ILI9163C_SPI = SPISettings(8000000, MSBFIRST, SPI_MODE0); + #endif + *csport &= ~cspinmask;// toggle CS low so it'll listen to us +#elif defined(__SAM3X8E__) + pinMode(_rs, OUTPUT); + pinMode(_cs, OUTPUT); + csport = digitalPinToPort(_cs); + rsport = digitalPinToPort(_rs); + cspinmask = digitalPinToBitMask(_cs); + rspinmask = digitalPinToBitMask(_rs); + SPI.begin(); + #if !defined(SPI_HAS_TRANSACTION) + SPI.setClockDivider(5); // 8 MHz + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + #else + ILI9163C_SPI = SPISettings(24000000, MSBFIRST, SPI_MODE0); + #endif + csport ->PIO_CODR |= cspinmask; // toggle CS low so it'll listen to us +#elif defined(__MKL26Z64__)//Teensy LC (preliminary) + pinMode(_rs, OUTPUT); + pinMode(_cs, OUTPUT); + if (_useSPI1){ + if ((_mosi == 0 || _mosi == 21) && (_sclk == 20)) {//identify alternate SPI channel 1 (24Mhz) + ILI9163C_SPI = SPISettings(24000000, MSBFIRST, SPI_MODE0); + SPI1.setMOSI(_mosi); + SPI1.setSCK(_sclk); + SPI1.begin(); + _useSPI1 = true; //confirm + } else { + bitSet(_initError,0); + return; + } + if (!SPI.pinIsChipSelect(_cs)) {//ERROR + bitSet(_initError,1); + return; + } + } else { + if ((_mosi == 11 || _mosi == 7) && (_sclk == 13 || _sclk == 14)) {//valid SPI pins? + ILI9163C_SPI = SPISettings(12000000, MSBFIRST, SPI_MODE0); + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + _useSPI1 = false; //confirm + } else { + bitSet(_initError,0); + return; + } + if (!SPI.pinIsChipSelect(_cs)) {//ERROR + bitSet(_initError,1); + return; + } + } + digitalWriteFast(_cs, LOW); +#elif defined(__MK20DX128__) || defined(__MK20DX256__) + ILI9163C_SPI = SPISettings(30000000, MSBFIRST, SPI_MODE0); + if ((_mosi == 11 || _mosi == 7) && (_sclk == 13 || _sclk == 14)) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + } else { + bitSet(_initError,0); + return; + } + SPI.begin(); + if (SPI.pinIsChipSelect(_cs, _rs)) { + pcs_data = SPI.setCS(_cs); + pcs_command = pcs_data | SPI.setCS(_rs); + } else { + pcs_data = 0; + pcs_command = 0; + bitSet(_initError,1); + return; + } +#else//all the rest of possible boards + pinMode(_rs, OUTPUT); + pinMode(_cs, OUTPUT); + SPI.begin(); + #if !defined(SPI_HAS_TRANSACTION) + SPI.setClockDivider(4); + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + #else + ILI9163C_SPI = SPISettings(8000000, MSBFIRST, SPI_MODE0); + #endif + digitalWrite(_cs, LOW); +#endif + if (_rst != 255) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(500); + digitalWrite(_rst, LOW); + delay(500); + digitalWrite(_rst, HIGH); + delay(500); + } + +/* +7) MY: 1(bottom to top), 0(top to bottom) Row Address Order +6) MX: 1(R to L), 0(L to R) Column Address Order +5) MV: 1(Exchanged), 0(normal) Row/Column exchange +4) ML: 1(bottom to top), 0(top to bottom) Vertical Refresh Order +3) RGB: 1(BGR), 0(RGB) Color Space +2) MH: 1(R to L), 0(L to R) Horizontal Refresh Order +1) +0) + + MY, MX, MV, ML,RGB, MH, D1, D0 + 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //normal + 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //Y-Mirror + 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Mirror + 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Y-Mirror + 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange + 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange, Y-Mirror + 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 //XY exchange + 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 +*/ + _Mactrl_Data = 0b00000000; + _colorspaceData = __COLORSPC;//start with default data; + chipInit(); +} + +uint8_t TFT_ILI9163C::errorCode(void) +{ + return _initError; +} + +void TFT_ILI9163C::chipInit() { + uint8_t i; + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + + writecommand_cont(CMD_SWRESET);//software reset + delay(500); + + writecommand_cont(CMD_SLPOUT);//exit sleep + delay(5); + + writecommand_cont(CMD_PIXFMT);//Set Color Format 16bit + writedata8_cont(0x05); + delay(5); + + writecommand_cont(CMD_GAMMASET);//default gamma curve 3 + writedata8_cont(0x08);//0x04 + delay(1); + + writecommand_cont(CMD_GAMRSEL);//Enable Gamma adj + writedata8_cont(0x01); + delay(1); + + writecommand_cont(CMD_NORML); + + writecommand_cont(CMD_DFUNCTR); + writedata8_cont(0b11111111);// + writedata8_cont(0b00000110);// + + writecommand_cont(CMD_PGAMMAC);//Positive Gamma Correction Setting + for (i=0;i<15;i++){ + writedata8_cont(pGammaSet[i]); + } + + writecommand_cont(CMD_NGAMMAC);//Negative Gamma Correction Setting + for (i=0;i<15;i++){ + writedata8_cont(nGammaSet[i]); + } + + writecommand_cont(CMD_FRMCTR1);//Frame Rate Control (In normal mode/Full colors) + writedata8_cont(0x08);//0x0C//0x08 + writedata8_cont(0x02);//0x14//0x08 + delay(1); + + writecommand_cont(CMD_DINVCTR);//display inversion + writedata8_cont(0x07); + delay(1); + + writecommand_cont(CMD_PWCTR1);//Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD + writedata8_cont(0x0A);//4.30 - 0x0A + writedata8_cont(0x02);//0x05 + delay(1); + + writecommand_cont(CMD_PWCTR2);//Set BT[2:0] for AVDD & VCL & VGH & VGL + writedata8_cont(0x02); + delay(1); + + writecommand_cont(CMD_VCOMCTR1);//Set VMH[6:0] & VML[6:0] for VOMH & VCOML + writedata8_cont(0x50);//0x50 + writedata8_cont(99);//0x5b + delay(1); + + writecommand_cont(CMD_VCOMOFFS); + writedata8_cont(0);//0x40 + delay(1); + + writecommand_cont(CMD_CLMADRS);//Set Column Address + writedata16_cont(0x00); + writedata16_cont(_GRAMWIDTH); + + writecommand_cont(CMD_PGEADRS);//Set Page Address + writedata16_cont(0x00); + writedata16_cont(_GRAMHEIGH); + // set scroll area (thanks Masuda) + writecommand_cont(CMD_VSCLLDEF); + writedata16_cont(__OFFSET); + writedata16_cont(_GRAMHEIGH - __OFFSET); + writedata16_last(0); + + SPI.endTransaction(); + + colorSpace(_colorspaceData); + + setRotation(0); + + SPI.beginTransaction(ILI9163C_SPI); + + writecommand_cont(CMD_DISPON);//display ON + delay(1); + writecommand_last(CMD_RAMWR);//Memory Write + + SPI.endTransaction(); + delay(1); + #else + writecommand(CMD_SWRESET);//software reset + delay(500); + + writecommand(CMD_SLPOUT);//exit sleep + delay(5); + + writecommand(CMD_PIXFMT);//Set Color Format 16bit + writedata(0x05); + delay(5); + + writecommand(CMD_GAMMASET);//default gamma curve 3 + writedata(0x04);//0x04 + delay(1); + + writecommand(CMD_GAMRSEL);//Enable Gamma adj + writedata(0x01); + delay(1); + + writecommand(CMD_NORML); + + writecommand(CMD_DFUNCTR); + writedata(0b11111111);// + writedata(0b00000110);// + + writecommand(CMD_PGAMMAC);//Positive Gamma Correction Setting + for (i=0;i<15;i++){ + writedata(pGammaSet[i]); + } + + writecommand(CMD_NGAMMAC);//Negative Gamma Correction Setting + for (i=0;i<15;i++){ + writedata(nGammaSet[i]); + } + + writecommand(CMD_FRMCTR1);//Frame Rate Control (In normal mode/Full colors) + writedata(0x08);//0x0C//0x08 + writedata(0x02);//0x14//0x08 + delay(1); + + writecommand(CMD_DINVCTR);//display inversion + writedata(0x07); + delay(1); + + writecommand(CMD_PWCTR1);//Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD + writedata(0x0A);//4.30 - 0x0A + writedata(0x02);//0x05 + delay(1); + + writecommand(CMD_PWCTR2);//Set BT[2:0] for AVDD & VCL & VGH & VGL + writedata(0x02); + delay(1); + + writecommand(CMD_VCOMCTR1);//Set VMH[6:0] & VML[6:0] for VOMH & VCOML + writedata(0x50);//0x50 + writedata(99);//0x5b + delay(1); + + writecommand(CMD_VCOMOFFS); + writedata(0);//0x40 + delay(1); + + writecommand(CMD_CLMADRS);//Set Column Address + writedata16(0x00); + writedata16(_GRAMWIDTH); + + writecommand(CMD_PGEADRS);//Set Page Address + writedata16(0X00); + writedata16(_GRAMHEIGH); + // set scroll area (thanks Masuda) + writecommand(CMD_VSCLLDEF); + writedata16(__OFFSET); + writedata16(_GRAMHEIGH - __OFFSET); + writedata16(0); + + colorSpace(_colorspaceData); + + setRotation(0); + writecommand(CMD_DISPON);//display ON + delay(1); + writecommand(CMD_RAMWR);//Memory Write + + delay(1); + #endif + fillScreen(BLACK); +} + +/* +Colorspace selection: +0: RGB +1: GBR +*/ +void TFT_ILI9163C::colorSpace(uint8_t cspace) { + if (cspace < 1){ + bitClear(_Mactrl_Data,3); + } else { + bitSet(_Mactrl_Data,3); + } +} + +void TFT_ILI9163C::invertDisplay(boolean i) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_last(i ? CMD_DINVON : CMD_DINVOF); + SPI.endTransaction(); + #else + writecommand(i ? CMD_DINVON : CMD_DINVOF); + #endif +} + +void TFT_ILI9163C::display(boolean onOff) { + if (onOff){ + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_last(CMD_DISPON); + SPI.endTransaction(); + #else + writecommand(CMD_DISPON); + #endif + } else { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_last(CMD_DISPOFF); + SPI.endTransaction(); + #else + writecommand(CMD_DISPOFF); + #endif + } +} + +void TFT_ILI9163C::idleMode(boolean onOff) { + if (onOff){ + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_last(CMD_IDLEON); + SPI.endTransaction(); + #else + writecommand(CMD_IDLEON); + #endif + } else { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_last(CMD_IDLEOF); + SPI.endTransaction(); + #else + writecommand(CMD_IDLEOF); + #endif + } +} + +void TFT_ILI9163C::sleepMode(boolean mode) { + if (mode){ + if (sleep == 1) return;//already sleeping + sleep = 1; + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_last(CMD_SLPIN); + SPI.endTransaction(); + #else + writecommand(CMD_SLPIN); + #endif + delay(5);//needed + } else { + if (sleep == 0) return; //Already awake + sleep = 0; + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_last(CMD_SLPOUT); + SPI.endTransaction(); + #else + writecommand(CMD_SLPOUT); + #endif + delay(120);//needed + } +} + +void TFT_ILI9163C::defineScrollArea(uint16_t tfa, uint16_t bfa){ + tfa += __OFFSET; + int16_t vsa = _GRAMHEIGH - tfa - bfa; + if (vsa >= 0) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_cont(CMD_VSCLLDEF); + writedata16_cont(tfa); + writedata16_cont(vsa); + writedata16_last(bfa); + SPI.endTransaction(); + #else + writecommand(CMD_VSCLLDEF); + writedata16(tfa); + writedata16(vsa); + writedata16(bfa); + #endif + } +} + +void TFT_ILI9163C::scroll(uint16_t adrs) { + if (adrs <= _GRAMHEIGH) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_cont(CMD_VSSTADRS); + writedata16_last(adrs + __OFFSET); + SPI.endTransaction(); + #else + writecommand(CMD_VSSTADRS); + writedata16(adrs + __OFFSET); + #endif + } +} + + +//corrected! v3 +void TFT_ILI9163C::clearScreen(uint16_t color) { + int px; + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + _setAddrWindow(0x00,0x00,_GRAMWIDTH,_GRAMHEIGH); + for (px = 0;px < _GRAMSIZE; px++){ + writedata16_cont(color); + } + writecommand_last(CMD_NOP); + SPI.endTransaction(); + #else + setAddr(0x00,0x00,_GRAMWIDTH,_GRAMHEIGH);//go home + for (px = 0;px < _GRAMSIZE; px++){ + writedata16(color); + } + #endif +} + +void TFT_ILI9163C::startPushData(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + setAddr(x0,y0,x1,y1); +} + +void TFT_ILI9163C::pushData(uint16_t color) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + writedata16_cont(color); + #else + writedata16(color); + #endif +} + + +void TFT_ILI9163C::endPushData() { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + writecommand_last(CMD_NOP); + SPI.endTransaction(); + #endif +} + + +void TFT_ILI9163C::pushColor(uint16_t color) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writedata16_last(color); + SPI.endTransaction(); + #else + writedata16(color); + #endif +} + +void TFT_ILI9163C::writeScreen24(const uint32_t *bitmap,uint16_t size) { + uint16_t color; + uint16_t px; + #if defined(__MK20DX128__) || defined(__MK20DX256__) + writecommand_cont(CMD_RAMWR); + for (px = 0;px < size; px++){//16384 + color = Color24To565(bitmap[px]); + writedata16_cont(color); + } + _setAddrWindow(0x00,0x00,_GRAMWIDTH,_GRAMHEIGH);//home + SPI.endTransaction(); + #else + writecommand(CMD_RAMWR); + for (px = 0;px < size; px++){ + color = Color24To565(bitmap[px]); + writedata16(color); + } + homeAddress(); + #endif +} + +void TFT_ILI9163C::homeAddress() { + setAddrWindow(0x00,0x00,_GRAMWIDTH,_GRAMHEIGH); +} + + + +void TFT_ILI9163C::setCursor(int16_t x, int16_t y) { + if (boundaryCheck(x,y)) return; + setAddrWindow(0x00,0x00,x,y); + cursor_x = x; + cursor_y = y; +} + + + + + +void TFT_ILI9163C::drawPixel(int16_t x, int16_t y, uint16_t color) { + if (boundaryCheck(x,y)) return; + if ((x < 0) || (y < 0)) return; + setAddr(x,y,x+1,y+1); + #if defined(__MK20DX128__) || defined(__MK20DX256__) + writedata16_last(color); + SPI.endTransaction(); + #else + writedata16(color); + #endif +} + + + +void TFT_ILI9163C::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { + // Rudimentary clipping + if (boundaryCheck(x,y)) return; + if (((y + h) - 1) >= _height) h = _height-y; + setAddr(x,y,x,(y+h)-1); + while (h-- > 0) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + if (h == 0){ + writedata16_last(color); + } else { + writedata16_cont(color); + } + #else + writedata16(color); + #endif + } + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif +} + +bool TFT_ILI9163C::boundaryCheck(int16_t x,int16_t y){ + if ((x >= _width) || (y >= _height)) return true; + return false; +} + +void TFT_ILI9163C::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { + // Rudimentary clipping + if (boundaryCheck(x,y)) return; + if (((x+w) - 1) >= _width) w = _width-x; + setAddr(x,y,(x+w)-1,y); + while (w-- > 0) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + if (w == 0){ + writedata16_last(color); + } else { + writedata16_cont(color); + } + #else + writedata16(color); + #endif + } + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif +} + +void TFT_ILI9163C::fillScreen(uint16_t color) { + clearScreen(color); +} + +// fill a rectangle +void TFT_ILI9163C::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; + setAddr(x,y,(x+w)-1,(y+h)-1); + for (y = h;y > 0;y--) { + for (x = w;x > 1;x--) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + writedata16_cont(color); + #else + writedata16(color); + #endif + } + #if defined(__MK20DX128__) || defined(__MK20DX256__) + writedata16_last(color); + #else + writedata16(color); + #endif + } + #if defined(SPI_HAS_TRANSACTION) + SPI.endTransaction(); + #endif +} + +#if defined(__MK20DX128__) || defined(__MK20DX256__) +void TFT_ILI9163C::drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y1, uint16_t color){ + if (y0 == y1) { + if (x1 > x0) { + drawFastHLine(x0, y0, x1 - x0 + 1, color); + } else if (x1 < x0) { + drawFastHLine(x1, y0, x0 - x1 + 1, color); + } else { + drawPixel(x0, y0, color); + } + return; + } else if (x0 == x1) { + if (y1 > y0) { + drawFastVLine(x0, y0, y1 - y0 + 1, color); + } else { + drawFastVLine(x0, y1, y0 - y1 + 1, color); + } + return; + } + + bool steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + swap(x0, y0); + swap(x1, y1); + } + if (x0 > x1) { + swap(x0, x1); + swap(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + SPI.beginTransaction(ILI9163C_SPI); + + int16_t xbegin = x0; + if (steep) { + for (; x0<=x1; x0++) { + err -= dy; + if (err < 0) { + int16_t len = x0 - xbegin; + if (len) { + VLine(y0, xbegin, len + 1, color); + } else { + Pixel(y0, x0, color); + } + xbegin = x0 + 1; + y0 += ystep; + err += dx; + } + } + if (x0 > xbegin + 1) { + VLine(y0, xbegin, x0 - xbegin, color); + } + + } else { + for (; x0<=x1; x0++) { + err -= dy; + if (err < 0) { + int16_t len = x0 - xbegin; + if (len) { + HLine(xbegin, y0, len + 1, color); + } else { + Pixel(x0, y0, color); + } + xbegin = x0 + 1; + y0 += ystep; + err += dx; + } + } + if (x0 > xbegin + 1) { + HLine(xbegin, y0, x0 - xbegin, color); + } + } + writecommand_last(CMD_NOP); + SPI.endTransaction(); +} + +void TFT_ILI9163C::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){ + SPI.beginTransaction(ILI9163C_SPI); + HLine(x, y, w, color); + HLine(x, y+h-1, w, color); + VLine(x, y, h, color); + VLine(x+w-1, y, h, color); + writecommand_last(CMD_NOP); + SPI.endTransaction(); +} + + +#endif + +void TFT_ILI9163C::setAddr(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1){ + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + _setAddrWindow(x0,y0,x1,y1); + #else + setAddrWindow(x0,y0,x1,y1); + #endif +} + +void TFT_ILI9163C::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + _setAddrWindow(x0,y0,x1,y1); + SPI.endTransaction(); + #else + writecommand(CMD_CLMADRS); // Column + if (rotation == 0 || rotation > 1){ + writedata16(x0); + writedata16(x1); + } else { + writedata16(x0 + __OFFSET); + writedata16(x1 + __OFFSET); + } + + writecommand(CMD_PGEADRS); // Page + if (rotation == 0){ + writedata16(y0 + __OFFSET); + writedata16(y1 + __OFFSET); + } else { + writedata16(y0); + writedata16(y1); + } + writecommand(CMD_RAMWR); //Into RAM + #endif +} + +#if defined(__MK20DX128__) || defined(__MK20DX256__) +void TFT_ILI9163C::_setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + writecommand_cont(CMD_CLMADRS); // Column + if (rotation == 0 || rotation > 1){ + writedata16_cont(x0); + writedata16_cont(x1); + } else { + writedata16_cont(x0 + __OFFSET); + writedata16_cont(x1 + __OFFSET); + } + writecommand_cont(CMD_PGEADRS); // Page + if (rotation == 0){ + writedata16_cont(y0 + __OFFSET); + writedata16_cont(y1 + __OFFSET); + } else { + writedata16_cont(y0); + writedata16_cont(y1); + } + writecommand_cont(CMD_RAMWR); //Into RAM +} +#endif + +void TFT_ILI9163C::setRotation(uint8_t m) { + rotation = m % 4; // can't be higher than 3 + switch (rotation) { + case 0: + _Mactrl_Data = 0b00001000; + _width = _TFTWIDTH; + _height = _TFTHEIGHT;//-__OFFSET; + break; + case 1: + _Mactrl_Data = 0b01101000; + _width = _TFTHEIGHT;//-__OFFSET; + _height = _TFTWIDTH; + break; + case 2: + _Mactrl_Data = 0b11001000; + _width = _TFTWIDTH; + _height = _TFTHEIGHT;//-__OFFSET; + break; + case 3: + _Mactrl_Data = 0b10101000; + _width = _TFTWIDTH; + _height = _TFTHEIGHT;//-__OFFSET; + break; + } + colorSpace(_colorspaceData); + #if defined(__MK20DX128__) || defined(__MK20DX256__) + SPI.beginTransaction(ILI9163C_SPI); + writecommand_cont(CMD_MADCTL); + writedata8_last(_Mactrl_Data); + SPI.endTransaction(); + #else + writecommand(CMD_MADCTL); + writedata(_Mactrl_Data); + #endif +} + + + + diff --git a/TFT_ILI9163C/TFT_ILI9163C.h b/TFT_ILI9163C/TFT_ILI9163C.h new file mode 100644 index 0000000..f00ff7b --- /dev/null +++ b/TFT_ILI9163C/TFT_ILI9163C.h @@ -0,0 +1,418 @@ +/* + ILI9163C - A fast SPI driver for TFT that use Ilitek ILI9163C. + + Features: + - Very FAST!, expecially with Teensy 3.x where uses hyper optimized SPI. + - It uses just 4 or 5 wires. + - Compatible at command level with Adafruit display series so it's easy to adapt existing code. + - It uses the standard Adafruit_GFX Library (you need to install). + + Background: + I got one of those displays from a chinese ebay seller but unfortunatly I cannot get + any working library so I decided to hack it. ILI9163C looks pretty similar to other + display driver but it uses it's own commands so it's tricky to work with it unlsess you + carefully fight with his gigantic and not so clever datasheet. + My display it's a 1.44"", 128x128 that suppose to substitute Nokia 5110 LCD and here's the + first confusion! Many sellers claim that it's compatible with Nokia 5110 (that use a philips + controller) but the only similarity it's the pin names since that this one it's color and + have totally different controller that's not compatible. + http://www.ebay.com/itm/Replace-Nokia-5110-LCD-1-44-Red-Serial-128X128-SPI-Color-TFT-LCD-Display-Module-/141196897388 + http://www.elecrow.com/144-128x-128-tft-lcd-with-spi-interface-p-855.html + Pay attention that can drive different resolutions and your display can be + 160*128 or whatever, also there's a strain of this display with a black PCB that a friend of mine + got some weeks ago and need some small changes in library to get working. + If you look at TFT_ILI9163C.h file you can add your modifications and let me know so I + can include for future versions. + + Code Optimizations: + The purpose of this library it's SPEED. I have tried to use hardware optimized calls + where was possible and results are quite good for most applications, actually nly filled circles + are still a bit slow. Many SPI call has been optimized by reduce un-needed triggers to RS and CS + lines. Of course it can be improved so feel free to add suggestions. + ------------------------------------------------------------------------------- + Copyright (c) 2014, .S.U.M.O.T.O.Y., coded by Max MC Costa. + + TFT_ILI9163C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TFT_ILI9163C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar. If not, see . + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + This file needs the following Libraries: + + Adafruit_GFX by Adafruit: + https://github.com/adafruit/Adafruit-GFX-Library + Remember to update GFX library often to have more features with this library! + From this version I'm using my version of Adafruit_GFX library: + https://github.com/sumotoy/Adafruit-GFX-Library + It has faster char rendering and some small little optimizations but you can + choose one of the two freely since are both fully compatible. + '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + Special Thanks: + Thanks Adafruit for his Adafruit_GFX! + Thanks to Paul Stoffregen for his beautiful Teensy3 and DMA SPI. + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Version: + 0.1a1: First release, compile correctly. Altrough not fully working! + 0.1a3: Better but still some addressing problems. + 0.1b1: Beta! Addressing solved, now rotation works and boundaries ok. + 0.2b1: Cleaned up. + 0.2b3: Added 2.2" Red PCB parameters + 0.2b4: Bug fixes, added colorSpace (for future send image) + 0.2b5: Cleaning + 0.3b1: Complete rework on Teensy SPI based on Paul Stoffregen work + SPI transaction,added BLACK TAG 2.2 display + 0.3b2: Minor fix, load 24bit image, Added conversion utility + 0.4: some improvement, new ballistic gauge example! + 0.5: Added scroll and more commands, optimizations + 0.6: Small fix, added SD example and subroutines + 0.6b1: Fix clearscreen, missed a parameter. + 0.6b2: Scroll completed. (thanks Masuda) + 0.6b3: Clear Screen fix v2. Added Idle mode. + 0.7: Init correction.Clear Screen fix v3 (last time?) + 0.75: SPI transactions for arduino's (beta) + 0.8: Compatiblke with IDE 1.0.6 (teensyduino 1.20) and IDE 1.6.x (teensyduino 1.21b) + 0.9: Many changes! Now works with more CPU's, alternative pins for Teensy and Teensy LC + Works (in standard SPI) with Teensy LC. + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + BugList of the current version: + + Please report any! + + +Here's the speed test between 0.2b5 and 0.3b1 on Teensy3.1 (major SPI changes) +------------------------------------------------------------------------ +Lines 17024 16115 BETTER +Horiz/Vert Lines 5360 5080 BETTER +Rectangles (outline) 4384 4217 BETTER +Rectangles (filled) 96315 91265 BETTER +Circles (filled) 16053 15829 LITTLE BETTER +Circles (outline) 11540 20320 WORST! +Triangles (outline) 5359 5143 BETTER +Triangles (filled) 19088 18741 BETTER +Rounded rects (outline) 8681 12498 LITTLE WORST +Rounded rects (filled) 105453 100213 BETTER +Done! + + +*/ +#ifndef _TFT_ILI9163CLIB_H_ +#define _TFT_ILI9163CLIB_H_ + +//defined(__MKL26Z64__) +#include "Arduino.h" +#include "Print.h" +#include + +#include "_settings/TFT_ILI9163C_settings.h" + +#if !defined(_ADAFRUIT_GFX_VARIANT) + #ifdef __AVR__ + #include + #elif defined(__SAM3X8E__) + #include + #define PROGMEM + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) + #define pgm_read_word(addr) (*(const unsigned short *)(addr)) + typedef unsigned char prog_uchar; + #endif +#endif + + +//--------- Keep out hands from here!------------- + +#define BLACK 0x0000 +#define WHITE 0xFFFF + +#include "_settings/TFT_ILI9163C_registers.h" + + + +class TFT_ILI9163C : public Adafruit_GFX { + + public: + + #if defined(__MK20DX128__) || defined(__MK20DX256__) + TFT_ILI9163C(uint8_t cspin,uint8_t dcpin,uint8_t rstpin=255,uint8_t mosi=11,uint8_t sclk=13); + #elif defined(__MKL26Z64__) + TFT_ILI9163C(uint8_t cspin,uint8_t dcpin,uint8_t rstpin=255,uint8_t mosi=11,uint8_t sclk=13); + #else + TFT_ILI9163C(uint8_t cspin,uint8_t dcpin,uint8_t rstpin=255); + #endif + //TFT_ILI9163C(uint8_t CS, uint8_t DC);//connect rst pin to VDD + + void begin(void), + setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1),//graphic Addressing + setCursor(int16_t x,int16_t y),//char addressing + pushColor(uint16_t color), + fillScreen(uint16_t color=0x0000), + clearScreen(uint16_t color=0x0000),//same as fillScreen + drawPixel(int16_t x, int16_t y, uint16_t color), + drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), + drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), + #if defined(__MK20DX128__) || defined(__MK20DX256__)//workaround to get more speed from Teensy + drawLine(int16_t x0, int16_t y0,int16_t x1, int16_t y1, uint16_t color), + drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), + #endif + fillRect(int16_t x, int16_t y, int16_t w, int16_t h,uint16_t color), + setRotation(uint8_t r), + invertDisplay(boolean i); + uint8_t errorCode(void); + void idleMode(boolean onOff); + void display(boolean onOff); + void sleepMode(boolean mode); + void defineScrollArea(uint16_t tfa, uint16_t bfa); + void scroll(uint16_t adrs); + void startPushData(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + void pushData(uint16_t color); + void endPushData(); + void writeScreen24(const uint32_t *bitmap,uint16_t size=_TFTWIDTH*_TFTHEIGHT); + inline uint16_t Color565(uint8_t r, uint8_t g, uint8_t b) {return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);}; + //convert 24bit color into packet 16 bit one (credits for this are all mine) + inline uint16_t Color24To565(int32_t color_) { return ((((color_ >> 16) & 0xFF) / 8) << 11) | ((((color_ >> 8) & 0xFF) / 4) << 5) | (((color_) & 0xFF) / 8);} + void setBitrate(uint32_t n); + protected: + volatile uint8_t _Mactrl_Data;//container for the memory access control data + uint8_t _colorspaceData; + + #if defined(__AVR__) + void spiwrite(uint8_t); + volatile uint8_t *dataport, *clkport, *csport, *rsport; + uint8_t _cs,_rs,_rst; + uint8_t datapinmask, clkpinmask, cspinmask, rspinmask; + #elif defined(__SAM3X8E__) + void spiwrite(uint8_t); + Pio *dataport, *clkport, *csport, *rsport; + uint8_t _cs,_rs,_rst; + uint32_t datapinmask, clkpinmask, cspinmask, rspinmask; + #elif defined(__MKL26Z64__) + uint8_t _cs,_rs,_rst; + uint8_t _mosi, _sclk; + bool _useSPI1; + #elif defined(__MK20DX128__) || defined(__MK20DX256__) + uint8_t _cs, _rs, _rst; + uint8_t pcs_data, pcs_command; + uint8_t _mosi, _sclk; + + void _setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);//graphic Addressing for Teensy + + + //Here's Paul Stoffregen magic in action... + void waitFifoNotFull(void) { + uint32_t sr; + uint32_t tmp __attribute__((unused)); + do { + #if ARDUINO >= 160 + sr = KINETISK_SPI0.SR; + #else + sr = SPI0.SR; + #endif + if (sr & 0xF0) tmp = SPI0_POPR; // drain RX FIFO + } while ((sr & (15 << 12)) > (3 << 12)); + } + + void waitFifoEmpty(void) { + uint32_t sr; + uint32_t tmp __attribute__((unused)); + do { + #if ARDUINO >= 160 + sr = KINETISK_SPI0.SR; + if (sr & 0xF0) tmp = KINETISK_SPI0.POPR; // drain RX FIFO + #else + sr = SPI0.SR; + if (sr & 0xF0) tmp = SPI0_POPR; // drain RX FIFO + #endif + } while ((sr & 0xF0F0) > 0); // wait both RX & TX empty + } + + #if !defined(__FORCECOMPAT_SPI)//faster + void waitTransmitComplete(void) + __attribute__((always_inline)) { + uint32_t tmp __attribute__((unused)); + #if ARDUINO >= 160 + while (!(KINETISK_SPI0.SR & SPI_SR_TCF)) ; // wait until final output done + #else + while (!(SPI0.SR & SPI_SR_TCF)) ; // wait until final output done + #endif + tmp = SPI0_POPR; // drain the final RX FIFO word + } + #else + void waitTransmitComplete(uint32_t mcr) + __attribute__((always_inline)) { + uint32_t tmp __attribute__((unused)); + #if ARDUINO >= 160 + while (1) { + uint32_t sr = KINETISK_SPI0.SR; + if (sr & SPI_SR_EOQF) break; // wait for last transmit + if (sr & 0xF0) tmp = KINETISK_SPI0.POPR; + } + KINETISK_SPI0.SR = SPI_SR_EOQF; + SPI0_MCR = mcr; + while (KINETISK_SPI0.SR & 0xF0) { + tmp = KINETISK_SPI0.POPR; + } + #else + while (1) { + uint32_t sr = SPI0.SR; + if (sr & SPI_SR_EOQF) break; // wait for last transmit + if (sr & 0xF0) tmp = SPI0_POPR; + } + SPI0.SR = SPI_SR_EOQF; + SPI0_MCR = mcr; + while (SPI0.SR & 0xF0) { + tmp = SPI0_POPR; + } + #endif + } + #endif + + void writecommand_cont(uint8_t c) + __attribute__((always_inline)) { + #if ARDUINO >= 160 + KINETISK_SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT; + #else + SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT; + #endif + waitFifoNotFull(); + } + + void writedata8_cont(uint8_t c) + __attribute__((always_inline)) { + #if ARDUINO >= 160 + KINETISK_SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT; + #else + SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT; + #endif + waitFifoNotFull(); + } + + void writedata16_cont(uint16_t d) + __attribute__((always_inline)) { + #if ARDUINO >= 160 + KINETISK_SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1) | SPI_PUSHR_CONT; + #else + SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1) | SPI_PUSHR_CONT; + #endif + waitFifoNotFull(); + } + + #if !defined(__FORCECOMPAT_SPI) + void writecommand_last(uint8_t c) + __attribute__((always_inline)) { + waitFifoEmpty(); + #if ARDUINO >= 160 + KINETISK_SPI0.SR = SPI_SR_TCF; + KINETISK_SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0); + #else + SPI0.SR = SPI_SR_TCF; + SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0); + #endif + waitTransmitComplete(); + } + + + void writedata8_last(uint8_t c) + __attribute__((always_inline)) { + waitFifoEmpty(); + #if ARDUINO >= 160 + KINETISK_SPI0.SR = SPI_SR_TCF; + KINETISK_SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0); + #else + SPI0.SR = SPI_SR_TCF; + SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0); + #endif + waitTransmitComplete(); + } + + void writedata16_last(uint16_t d) + __attribute__((always_inline)) { + waitFifoEmpty(); + #if ARDUINO >= 160 + KINETISK_SPI0.SR = SPI_SR_TCF; + KINETISK_SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1); + #else + SPI0.SR = SPI_SR_TCF; + SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1); + #endif + waitTransmitComplete(); + } + #else + void writecommand_last(uint8_t c) + __attribute__((always_inline)) { + uint32_t mcr = SPI0_MCR; + #if ARDUINO >= 160 + KINETISK_SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_EOQ; + #else + SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_EOQ; + #endif + waitTransmitComplete(mcr); + } + + + void writedata8_last(uint8_t c) + __attribute__((always_inline)) { + uint32_t mcr = SPI0_MCR; + #if ARDUINO >= 160 + KINETISK_SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_EOQ; + #else + SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_EOQ; + #endif + waitTransmitComplete(mcr); + } + + + void writedata16_last(uint16_t d) + __attribute__((always_inline)) { + uint32_t mcr = SPI0_MCR; + #if ARDUINO >= 160 + KINETISK_SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1) | SPI_PUSHR_EOQ; + #else + SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1) | SPI_PUSHR_EOQ; + #endif + waitTransmitComplete(mcr); + } + #endif + void HLine(int16_t x, int16_t y, int16_t w, uint16_t color) + __attribute__((always_inline)) { + _setAddrWindow(x, y, x+w-1, y); + do { writedata16_cont(color); } while (--w > 0); + } + + void VLine(int16_t x, int16_t y, int16_t h, uint16_t color) + __attribute__((always_inline)) { + _setAddrWindow(x, y, x, y+h-1); + do { writedata16_cont(color); } while (--h > 0); + } + + void Pixel(int16_t x, int16_t y, uint16_t color) + __attribute__((always_inline)) { + _setAddrWindow(x, y, x, y); + writedata16_cont(color); + } + #else + uint8_t _cs,_rs,_rst; + #endif + + #if !defined(__MK20DX128__) && !defined(__MK20DX256__) + void writecommand(uint8_t c); + void writedata(uint8_t d); + void writedata16(uint16_t d); + #endif + private: + void colorSpace(uint8_t cspace); + void setAddr(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + uint8_t sleep; + void chipInit(); + bool boundaryCheck(int16_t x,int16_t y); + void homeAddress(); + uint8_t _initError; +}; +#endif \ No newline at end of file diff --git a/TFT_ILI9163C/keywords.txt b/TFT_ILI9163C/keywords.txt new file mode 100644 index 0000000..91d5974 --- /dev/null +++ b/TFT_ILI9163C/keywords.txt @@ -0,0 +1,21 @@ +TFT_ILI9163C KEYWORD1 +begin KEYWORD2 +setAddrWindow KEYWORD2 +pushColor KEYWORD2 +setBrightness KEYWORD2 +writeData KEYWORD2 +setBitrate KEYWORD2 +Color565 KEYWORD2 +setBitrate KEYWORD2 +clearScreen KEYWORD2 +Color24To565 KEYWORD2 +sleepMode KEYWORD2 +display KEYWORD2 +startPushData KEYWORD2 +pushData KEYWORD2 +endPushData KEYWORD2 +defineScrollArea KEYWORD2 +writeScreen24 KEYWORD2 +idleMode KEYWORD2 +errorCode KEYWORD2 + diff --git a/TFT_ILI9163C/library.properties b/TFT_ILI9163C/library.properties new file mode 100644 index 0000000..0947fba --- /dev/null +++ b/TFT_ILI9163C/library.properties @@ -0,0 +1,9 @@ +name=TFT_ILI9163C +version=0.9 +author=Max MC Costa +maintainer=sumotoy +sentence=A fast SPI driver for TFT drived by ILI9163C, fully SPI Transaction compatible and very fast with Teensy 3 +paragraph=This library works with many MCU's included Arduino's but it's particular fast with Teensy 3, Teensy 3.1. +category=Display +url=https://github.com/sumotoy/TFT_ILI9163C +architectures=*