V1.1 of the ILI9340 driver for SPI with integrated graphics functions.

Dependents:   ILI9340_Driver SDCard_Aitendo_2p2TFT TFT22ok_test_ILI9340_Driver

This driver will drive any display that uses an ILI9340 display controller in SPI mode - such as the adafruits 2.2" 240 x 320 display found here: http://www.adafruit.com/products/1480

All this code has been ported from other peoples hard work - Thanks to All !

Revision:
0:ea46340642a9
Child:
1:216d35e347b8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ILI9340_Driver.cpp	Tue May 27 19:40:20 2014 +0000
@@ -0,0 +1,547 @@
+/***************************************************************
+    ILI9340_Driver  v1.0    26.05.14    Ian Weston
+    
+Driver and integrated graphics library for displays that use the 
+ILI9340 controller in SPI mode.
+
+The code was prted from several sources, the driver section
+was completely ported from the Adafruits Arduino source code, and
+the graphics functions were ported from the Adafruits GFX library
+and some elements were ported from code by Elmicros seeduio port.
+
+Future revisions will include more advanced graphics functions.
+
+***************************************************************/
+
+
+#include "mbed.h"
+#include "ILI9340_Driver.h"
+#include "SimpleFont.cpp"
+
+
+// Constructor, assigns the pins to the SPI object, set orientation, and sets screen dims.
+ILI9340_Display::ILI9340_Display(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst, PinName dc)
+    : spi(mosi, miso, sclk), cs(cs), rst(rst), dc(dc) {
+    _height = _TFTHEIGHT;
+    _width = _TFTWIDTH;
+    orientation = 0;
+    }
+
+
+// Command writing code
+void ILI9340_Display::WriteCommand(uint8_t command) {
+    dc = 0;
+    cs = 0;
+    spi.write(command);
+    cs = 1;
+    }
+  
+    
+// Data writing code
+void ILI9340_Display::WriteData(uint8_t data) {
+    cs = 0;
+    dc = 1;
+    spi.write(data);
+    cs = 1;    
+    }
+    
+    
+// Initilise the display
+void ILI9340_Display::DispInit(void) {
+    //CtrlOutput();
+    
+    rst = 0;
+    
+    // Setup the spi for 8 bit data, high steady state clock,
+    // second edge capture, with a 1MHz clock rate
+    //spi.format(8,3);
+    spi.frequency(24000000); // actually seems to work up to about 20Mhz... way better than the 8mhz as std.
+    
+    // Toggle rst to reset
+    rst = 1;
+    wait(0.005);
+    rst = 0;
+    wait(0.020);
+    rst = 1;
+    wait(0.150);
+    
+    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(ILI9340_PWCTR1);    //Power control 
+    WriteData(0x23);   //VRH[5:0] 
+ 
+    WriteCommand(ILI9340_PWCTR2);    //Power control 
+    WriteData(0x10);   //SAP[2:0];BT[3:0] 
+ 
+    WriteCommand(ILI9340_VMCTR1);    //VCM control 
+    WriteData(0x3e); //�Աȶȵ���
+    WriteData(0x28); 
+  
+    WriteCommand(ILI9340_VMCTR2);    //VCM control2 
+    WriteData(0x86);  //--
+ 
+    WriteCommand(ILI9340_MADCTL);    // Memory Access Control 
+    WriteData(ILI9340_MADCTL_MX | ILI9340_MADCTL_BGR);
+
+    WriteCommand(ILI9340_PIXFMT);    
+    WriteData(0x55); 
+  
+    WriteCommand(ILI9340_FRMCTR1);    
+    WriteData(0x00);  
+    WriteData(0x18); 
+ 
+    WriteCommand(ILI9340_DFUNCTR);    // Display Function Control 
+    WriteData(0x08); 
+    WriteData(0x82);
+    WriteData(0x27);  
+ 
+    WriteCommand(0xF2);    // 3Gamma Function Disable 
+    WriteData(0x00); 
+ 
+    WriteCommand(ILI9340_GAMMASET);    //Gamma curve selected 
+    WriteData(0x01); 
+ 
+    WriteCommand(ILI9340_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(ILI9340_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(ILI9340_SLPOUT);    //Exit Sleep 
+    wait(0.120);       
+    WriteCommand(ILI9340_DISPON);    //Display on 
+    
+    }
+    
+
+// Sets the rotation of the display
+void ILI9340_Display::SetRotation(uint8_t m) {
+
+  WriteCommand(ILI9340_MADCTL);
+  orientation = m % 4; // can't be higher than 3
+  
+  switch (orientation) {
+   case 0:
+     WriteData(ILI9340_MADCTL_MX | ILI9340_MADCTL_BGR);
+     _width  = _TFTWIDTH;
+     _height = _TFTHEIGHT;
+     break;
+   case 1:
+     WriteData(ILI9340_MADCTL_MV | ILI9340_MADCTL_BGR);
+     _width  = _TFTHEIGHT;
+     _height = _TFTWIDTH;
+     break;
+  case 2:
+    WriteData(ILI9340_MADCTL_MY | ILI9340_MADCTL_BGR);
+     _width  = _TFTWIDTH;
+     _height = _TFTHEIGHT;
+    break;
+   case 3:
+     WriteData(ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX | ILI9340_MADCTL_BGR);
+     _width  = _TFTHEIGHT;
+     _height = _TFTWIDTH;
+     break;
+  }
+}
+
+
+// Invert the colours of the display in hardware
+void ILI9340_Display::InvertDisplay(bool i) {
+  WriteCommand(i ? ILI9340_INVON : ILI9340_INVOFF);
+}
+
+
+    
+// Set address window for writing data to.
+void ILI9340_Display::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
+
+  WriteCommand(ILI9340_CASET); // Column addr set
+  WriteData(x0 >> 8);
+  WriteData(x0 & 0xFF);     // XSTART 
+  WriteData(x1 >> 8);
+  WriteData(x1 & 0xFF);     // XEND
+
+  WriteCommand(ILI9340_PASET); // Row addr set
+  WriteData(y0>>8);
+  WriteData(y0);     // YSTART
+  WriteData(y1>>8);
+  WriteData(y1);     // YEND
+
+  WriteCommand(ILI9340_RAMWR); // write to RAM
+}
+
+
+
+// To draw the humble pixel
+void ILI9340_Display::DrawPixel(uint16_t x, uint16_t y, uint16_t colour) {
+    if((x < 1) ||(x >= _width) || (y < 1) || (y >= _height)) return;
+   
+    SetAddrWindow(x,y,x+1,y+1);
+    
+    dc = 1;
+    cs = 0;
+    
+    spi.write(colour >> 8);
+    spi.write(colour);
+    
+    cs = 1;
+    }
+    
+
+// Fill the screen with a colour
+void ILI9340_Display::FillScreen(uint16_t colour) {
+    SetAddrWindow(0,0,_width,_height);
+    
+    dc = 1;
+    cs = 0;
+    
+    unsigned int total = _width * _height;
+    unsigned int position = 0;
+    
+    while (position < total) {
+        spi.write(colour >> 8);
+        spi.write(colour);
+        position++;
+        }
+    cs = 1;
+    }
+    
+
+// Draws a vertical line fast
+void ILI9340_Display::DrawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t colour) {
+
+  // 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 = colour >> 8, lo = colour;
+
+  dc = 1;
+  cs = 0;
+
+  while (h--) {
+    spi.write(hi);
+    spi.write(lo);
+  }
+  cs = 1;
+}
+
+
+// Draws a horizontal line fast
+void ILI9340_Display::DrawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t colour) {
+
+  // Rudimentary clipping
+  if((x >= _width) || (y >= _height)) return;
+  if((x+w-1) >= _height)  w = _width-x;
+  SetAddrWindow(x, y, x+w-1, y);
+
+  uint8_t hi = colour >> 8, lo = colour;
+  dc = 1;
+  cs = 0;
+  while (w--) {
+    spi.write(hi);
+    spi.write(lo);
+  }
+  cs = 1;
+}
+
+
+// Draws a filled rectangle 
+void ILI9340_Display::FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t colour) {
+
+  // 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 = colour >> 8, lo = colour;
+
+  dc = 1;
+  cs = 0;
+
+  for(y=h; y>0; y--) {
+    for(x=w; x>0; x--) {
+      spi.write(hi);
+      spi.write(lo);
+    }
+  }
+  cs = 1;
+}
+
+
+
+// Draw an unfilled rectangle
+void ILI9340_Display::DrawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
+    DrawFastHLine(x, y, w, color);
+    DrawFastHLine(x, y+h-1, w, color);
+    DrawFastVLine(x, y, h, color);
+    DrawFastVLine(x+w-1, y, h, color);
+}
+
+
+// draw an unfilled circle
+void ILI9340_Display::DrawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t colour){
+    int16_t f = 1 - r;
+    int16_t ddF_x = 1;
+    int16_t ddF_y = -2 * r;
+    int16_t x = 0;
+    int16_t y = r;
+ 
+    DrawPixel(x0  , y0+r, colour);
+    DrawPixel(x0  , y0-r, colour);
+    DrawPixel(x0+r, y0  , colour);
+    DrawPixel(x0-r, y0  , colour);
+ 
+    while (x<y) {
+        if (f >= 0) {
+            y--;
+            ddF_y += 2;
+            f += ddF_y;
+        }
+        x++;
+        ddF_x += 2;
+        f += ddF_x;
+ 
+        DrawPixel(x0 + x, y0 + y, colour);
+        DrawPixel(x0 - x, y0 + y, colour);
+        DrawPixel(x0 + x, y0 - y, colour);
+        DrawPixel(x0 - x, y0 - y, colour);
+        DrawPixel(x0 + y, y0 + x, colour);
+        DrawPixel(x0 - y, y0 + x, colour);
+        DrawPixel(x0 + y, y0 - x, colour);
+        DrawPixel(x0 - y, y0 - x, colour);
+    }
+}
+
+
+// Pass 8-bit (each) R,G,B, get back 16-bit packed color
+uint16_t ILI9340_Display::Colour565(uint8_t r, uint8_t g, uint8_t b) {
+  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
+}
+
+
+// Writes an ascii character to the display
+void ILI9340_Display::DrawAscii(unsigned char ascii, uint16_t x, uint16_t y, uint16_t size, uint16_t colour) {
+    SetAddrWindow(x, y, x+size, y+size);
+    
+    if( (ascii < 0x20) || (ascii > 0x7e) )      //check for valid ASCII char
+    {
+        ascii = '?';                            //char not supported
+    }
+    for(unsigned char i=0; i<8; i++)
+    {
+        unsigned char temp = simpleFont[ascii - 0x20][i];
+        for(unsigned char f=0; f<8; f++)
+        {
+            if( (temp>>f) & 0x01 )
+            {
+                switch(orientation)
+                {                
+                case '0':
+                    FillRect(x+f*size, y-i*size, size, size, colour);
+                    break;
+                case '1':
+                     FillRect(x-i*size, x-f*size, size, size, colour);
+                     break;
+                case '2':
+                     FillRect(x-f*size, y+i*size, size, size, colour);
+                     break;
+                case '3':
+                default:
+                       FillRect(x+i*size, y+f*size, size, size, colour);
+                }
+            }    
+        }
+    }
+}
+
+
+// Writes a character array to the display
+void ILI9340_Display::DrawString(char *string, uint16_t x, uint16_t y, uint8_t size, uint16_t colour)
+{
+    while(*string)
+    {
+        DrawAscii(*string, x, y, size, colour);
+        *string++;
+        switch(orientation)
+        {        
+        case '0':          
+            if(y > 0) y-=8*size;              //Change position to next char 
+              break;
+        case '1':        
+            if(x > 0) x-=8*size;                       
+            break;
+        case '2':          
+            if(y < _height) y+=8*size;   
+            break;
+        case '3':
+        default:        
+              if(x < _width) x+=8*size; 
+        }          
+    }
+}
+
+// Converts integers into a character array
+void ILI9340_Display::IntToChars (char* buffer, int value, uint8_t spaceonbuffer, uint8_t countbase, uint16_t x, uint16_t y, uint8_t size, uint16_t colour) {
+    int workvalue = value;
+    int i;
+    int valuetowrite;
+    int  end_i = 0;
+
+    if (value < 0)
+    {
+        workvalue = -value;
+        end_i = 1;
+        buffer[0] = '-';
+    }
+
+    for (i = spaceonbuffer - 1; i >= end_i; i--)
+    {
+        valuetowrite = (workvalue % countbase);
+        if (workvalue == 0)
+        {
+            if (i == (spaceonbuffer - 1))
+            {
+                buffer[i] = 48;                        // ASCII 0
+            } else {
+                buffer[i] = 32;                        // ASCII SPACE
+            }
+        } else {
+            if (valuetowrite > 9)
+            {
+                buffer[i] = valuetowrite + 55;        // ASCII A-Z
+            } else {
+                buffer[i] = valuetowrite + 48;        // ASCII of that character
+            }
+        };
+        workvalue = (workvalue - valuetowrite) / countbase;
+    }
+    
+    DrawString(buffer, x, y, size, colour);
+}
+
+
+
+// Functional code to swap data contents of 16bit registers
+void ILI9340_Display::Swap(int16_t *a, int16_t *b) {
+    
+    int16_t x = *a;
+    *a = *b;
+    *b = x;    
+    }
+
+
+// Draws a line with any length and orientation
+void ILI9340_Display::DrawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t colour){
+    int16_t 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;
+    }
+ 
+    for (; x0<=x1; x0++) {
+        if (steep) {
+            DrawPixel(y0, x0, colour);
+        } else {
+            DrawPixel(x0, y0, colour);
+        }
+        err -= dy;
+        if (err < 0) {
+            y0 += ystep;
+            err += dx;
+        }
+    }
+}
+
+
+
+
+
+
+
+