Demonstration programs for Banggood 2.4" TFT Display

Edward A. Kimble, PhD, Purdue '77



This TFT board ships from a number of Chinese web sites. Here for example is a picture of the board as shipped from Aliexpress for ~$5.00. And despite the low cost, the board sits as a shield on the Arduino UNO and performs reasonably well..... once the software is found. To install the header files mentioned in these programs, all are present on github and can be found using a Google search. They should be unzipped and placed in the libraries file that is present wherever you store your Arduino programs. In the main Arduino folder where the arduino.exe file is as another libraries folder. Do not store your header file folders there since this folder is erased whenever there is a new Arduino update installed. How do I know this? Trial AND error. Live and learn. What I've done here is find two different programs (.ino files) for running the TFT display both based on work by Adafruit, each clearly labelling as much of the protocol as possible. This is pretty trivial compared to the massive efforts of the Arduino and Adafruit folks. Still, there are several alternate sources for similar software available on the net and on Github so I do not feel too guilty offering these gleaned examples. The pinouts for the display and the default configurations for the display are the critical feature here. The first example was gleaned from a youtube video at:
"https://www.youtube.com/watch?v=2-2IjZJCNLc&feature=youtu.be" The video shows approximately how this program behaves but it is not the same display board. Note the symbols at the top of the display board in the video and the lack of same in the picture above. Your board must appear like the one above! The color table for these two boards are opposite each other, and the pinouts from the two boards are quite different despite the seeming board similarity. There also appears to be an issue with green coding on the one shown in the video which is not present in the one here.
See the second example at the bottom for use of the touchscreen. This is a very easy approach and can be quickly modified for a wide variety of projects. smile


/*************************************************** This program works for the generic Banggood 2.4" TFT board/shield mounted on an Arduino UNO It demonstrates a number of TFT library functions which are available from multiple sources and it represents a highly modified version of the open source GFX example for the Adafruit ILI9341 Breakout and Shield. Caveat emptor, you get what you pay for. The Banggood product can, without adding insulation, short out to the USB enclosure on the Arduino board and the Manufacturer often uses alternate TFT displays which may or may not work perfectly with the code below For reliability and documentation check out the link below for the Adafruit product, a stable design with fully documented software Adafruit has invested time and resources providing this open source code, and they would greatly appreciate your support by purchasing Adafruit's open-source hardware directly from Adafruit! ----> http://www.adafruit.com/products/1651 Libraries were modified by rogerclarkmelbourne and victorpv at: https://github.com/rogerclarkmelbourne/Arduino_STM32/tree/master/STM32F1/libraries/Adafruit_GFX_AS Sketch and libraries were modified by KB1UIF (A.Tedds) further modified to provide correct color palette by MODAL (E. Kimble) Uses 8bit Communication for ili9341 or Samsung Driver Chip!! Colors are 5 bits-red, 1 bit blank, 5 bits-green, 5 bits-blue, all combined in the order given into a single 16 bit unsigned integer Code was initially written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above should be included in any redistribution. All parts of this work have been modified. ****************************************************/ #include <Adafruit_GFX_AS.h> // Modified Adafruit Core graphics library #include <Adafruit_ILI9341_8bit_AS.h> // Modified Hardware-specific library, 8bit Modified from Adafruit Lib. #define LCD_CS A3 // Chip Select goes to Analog 3 #define LCD_CD A2 // Command/Data goes to Analog 2 #define LCD_WR A1 // LCD Write goes to Analog 1 #define LCD_RD A0 // LCD Read goes to Analog 0 #define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin // Assign human-readable names to some common 16-bit color values: #define BLACK 0x0000 #define BLUE 0x001F #define ORANGE 0xFF40 #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define GRAY1 0x8888 #define GRAY2 0xAAAA Adafruit_ILI9341_8bit_AS tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); void setup() { Serial.begin(9600); Serial.println("ILI9341 Test!"); tft.begin(); // read diagnostics (optional but can help debug problems) //uint8_t x = tft.readcommand8(ILI9341_RDMODE); //Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); //x = tft.readcommand8(ILI9341_RDMADCTL); //Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); //x = tft.readcommand8(ILI9341_RDPIXFMT); //Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); // x = tft.readcommand8(ILI9341_RDIMGFMT); //Serial.print("Image Format: 0x"); Serial.println(x, HEX); //x = tft.readcommand8(ILI9341_RDSELFDIAG); //Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); Serial.println(F("Benchmark Time (microseconds)")); Serial.print(F("Screen fill ")); Serial.println(testFillScreen()); delay(500); Serial.print(F("Text ")); Serial.println(testText()); delay(3000); Serial.print(F("Lines ")); Serial.println(testLines(CYAN)); delay(500); Serial.print(F("Horiz/Vert Lines ")); Serial.println(testFastLines(RED, BLUE)); delay(500); Serial.print(F("Rectangles (outline) ")); Serial.println(testRects(GREEN)); delay(500); Serial.print(F("Rectangles (filled) ")); Serial.println(testFilledRects(YELLOW, MAGENTA)); delay(500); Serial.print(F("Circles (filled) ")); Serial.println(testFilledCircles(10, MAGENTA)); Serial.print(F("Circles (outline) ")); Serial.println(testCircles(10, WHITE)); delay(500); Serial.print(F("Triangles (outline) ")); Serial.println(testTriangles()); delay(500); Serial.print(F("Triangles (filled) ")); Serial.println(testFilledTriangles()); delay(500); Serial.print(F("Rounded rects (outline) ")); Serial.println(testRoundRects()); delay(500); Serial.print(F("Rounded rects (filled) ")); Serial.println(testFilledRoundRects()); delay(500); tft.setRotation(2); testText(); Serial.println(F("Done!"));} void loop(void) { //to demo text rotation, uncomment following code including end curly bracket // for(uint8_t rotation=0; rotation<4; rotation++) { // tft.setRotation(rotation); // testText(); delay(10000); // } } //*********************************Subroutines ******************************* unsigned long testFillScreen() { unsigned long start = micros(); tft.fillScreen(BLACK); tft.fillScreen(RED); tft.fillScreen(GREEN); tft.fillScreen(WHITE); tft.fillScreen(GRAY1); tft.fillScreen(YELLOW); tft.fillScreen(BLUE); tft.fillScreen(BLACK); return micros() - start;} //********************* unsigned long testText() { tft.fillScreen(BLACK); unsigned long start = micros(); tft.setCursor(0, 0); tft.setTextColor(WHITE); tft.setTextSize(3); tft.println("Hello World!"); tft.setTextColor(YELLOW); tft.setTextSize(2); tft.println(1234.56); tft.setTextColor(RED); tft.setTextSize(3); tft.println(0xDEADBEEF, HEX); tft.println(); tft.setTextColor(ORANGE); tft.setTextSize(5); tft.println("Group"); tft.setTextSize(2); tft.setTextColor(GREEN); tft.println("I implore thee,"); tft.setTextSize(1); tft.println("my foonting turlingdromes."); tft.println("And hooptiously drangle me"); tft.println("with crinkly bindlewurdles,"); tft.println("Or I will rend thee"); tft.println("in the gobberwarts"); tft.println("with my blurglecruncheon,"); tft.println("see if I don't!"); return micros() - start;} //********************* unsigned long testLines(uint16_t color) { unsigned long start, t; uint16_t cc; int a=0; int x1, y1, x2, y2, w = tft.width(), h = tft.height(); tft.fillScreen(BLACK); x1 = y1 = 0; y2 = h - 1; start = micros(); for(x2=0; x2<w; x2+=3){ if (a<64) {a++; cc= a*64;} if (a==32) cc=YELLOW; if (a==64) cc=color; tft.drawLine(x1, y1, x2, y2, cc);} x2 = w - 1;a=0; for(y2=0; y2<h; y2+=3) { if (a<64) {a++; cc= a*64;} //Shades of green if (a==64) cc=ORANGE; tft.drawLine(x1, y1, x2, y2, cc);} t = micros() - start; // fillScreen doesn't count against timing tft.fillScreen(BLACK); x1 = w - 1; y1 = 0; y2 = h - 1; start = micros(); for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, BLUE); x2 = 0; for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, RED); t += micros() - start; tft.fillScreen(BLACK); x1 = 0; y1 = h - 1; y2 = 0; start = micros(); for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); x2 = w - 1; for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); t += micros() - start; tft.fillScreen(BLACK); x1 = w - 1; y1 = h - 1; y2 = 0; start = micros(); for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); x2 = 0; for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); return micros() - start;} //********************* unsigned long testFastLines(uint16_t color1, uint16_t color2) { unsigned long start; int x, y, w = tft.width(), h = tft.height(); tft.fillScreen(BLACK); start = micros(); for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1); for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2); return micros() - start;} //********************* unsigned long testRects(uint16_t color) { unsigned long start; int n, i, i2, cx = tft.width() / 2, cy = tft.height() / 2; tft.fillScreen(BLACK); n = min(tft.width(), tft.height()); start = micros(); for(i=2; i<n; i+=6) { i2 = i / 2; tft.drawRect(cx-i2, cy-i2, i, i, color); } return micros() - start; } //********************* unsigned long testFilledRects(uint16_t color1, uint16_t color2) { unsigned long start, t = 0; int n, i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(BLACK); n = min(tft.width(), tft.height()); for(i=n; i>0; i-=6) { i2 = i / 2; start = micros(); tft.fillRect(cx-i2, cy-i2, i, i, color1); t += micros() - start; // Outlines are not included in timing results tft.drawRect(cx-i2, cy-i2, i, i, color2); } return t;} //********************* unsigned long testFilledCircles(uint8_t radius, uint16_t color) { unsigned long start; int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; tft.fillScreen(BLACK); start = micros(); for(x=radius; x<w; x+=r2) { for(y=radius; y<h; y+=r2) { tft.fillCircle(x, y, radius, color); } } return micros() - start;} //********************* unsigned long testCircles(uint8_t radius, uint16_t color) { unsigned long start; int x, y, r2 = radius * 2, w = tft.width() + radius, h = tft.height() + radius; // Screen is not cleared for this one -- this is // intentional and does not affect the reported time. start = micros(); for(x=0; x<w; x+=r2) { for(y=0; y<h; y+=r2) { tft.drawCircle(x, y, radius, color); } } return micros() - start;} //********************* unsigned long testTriangles() { unsigned long start; int n, i, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(BLACK); n = min(cx, cy); start = micros(); for(i=0; i<n; i+=5) { tft.drawTriangle( cx , cy - i, // peak cx - i, cy + i, // bottom left cx + i, cy + i, // bottom right tft.color565(0, 0, i)); } return micros() - start;} //********************* unsigned long testFilledTriangles() { unsigned long start, t = 0; int i, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(BLACK); start = micros(); for(i=min(cx,cy); i>10; i-=5) { start = micros(); tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, tft.color565(0, i, i)); t += micros() - start; tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, tft.color565(i, i, 0)); } return t;} //********************* unsigned long testRoundRects() { unsigned long start; int w, i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(BLACK); w = min(tft.width(), tft.height()); start = micros(); for(i=0; i<w; i+=6) { i2 = i / 2; tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0)); } return micros() - start;} //********************* unsigned long testFilledRoundRects() { unsigned long start; int i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(BLACK); start = micros(); for(i=min(tft.width(), tft.height()); i>20; i-=6) { i2 = i / 2; tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); } return micros() - start;} //*********************


This is actually a little drawing game. It can be found at many places on the web but for different displays! To see it at work I tried to capture the picture while holding my wifes camera and a closeup lens. It was out of focus and I've sharpened it as best I could in Gimp (like photoshop but with an attitude).


The code appears here:
		//Program acts to draw in selected color at selected coordinates
//Warning This program differs from similar others in terms of pin assignments!!
//Check the picture of the 2.4" display.  This is not the same as
//Most others found on the internet!
#include <Adafruit_GFX.h>      // Core graphics library
#include <Adafruit_TFTLCD.h>   // Hardware-specific library
#include <TouchScreen.h>       // Touchscreen library
#include <Banggood9341_Hack.h> // Adjustments for this display

#define TS_MINX  150
#define TS_MINY  150
#define TS_MAXX  905
#define TS_MAXY  905

// See labels on display board to confirm pin assignments
// For better location control, you need to map the display
// by setting multiple targets on screen and measure the readings.
// For simplicity, read the resistance between X+ and X- Using a multimeter.
// For the one we're using, its roughly 300 ohms across the X plate
#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin
//Do touchscreen pin assignments
//Smile, A5 is still available for that cool thermistor project 
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4
//Do TFT pin assignment
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// Assign human-readable names to some common 16-bit color values
//read each hex number as 4 bits of binary so as to form 16 bits as follows
//5bit red, 1 blank bit, 5bit green, 5bit blue
#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF


#define MINPRESSURE 10
#define MAXPRESSURE 1000
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;

void setup(void) {
  Serial.begin(9600);
  Serial.println("Paint!");
  tft.reset();
  uint16_t identifier = 0x9341;
  tft.begin(identifier);
  Lcd_Init();
  tft.fillScreen(BLACK);
  // Draw colored boxes
  tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
  tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
  tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
  tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
  tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
  tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
  //identify active color by outlining in white
  tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
  currentcolor = RED;
  
  //Confirm programmed screen size....
  pinMode(13, OUTPUT);
  Serial.print("Width=");
  Serial.println(tft.width());
  Serial.print("Height=");
  Serial.println(tft.height());
  //Add some text, but restore correct rotation (2) at end of
  //Text printing (otherwise touchscreen plotting is rotated... Oops
  tft.setRotation(0);
  tft.setTextColor(YELLOW); 
  tft.setCursor(0, 0);
  tft.setTextSize(2);
  tft.println("   Press to Erase");
  //Add erase text
  tft.setRotation(3);
  tft.setTextColor(WHITE); 
  tft.setCursor(0, 0);
  tft.setTextSize(3);
  tft.println("   Attack Group 3");
  //restore orientation
  tft.setRotation(2);
 }  //End setup

void loop()
{
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
	p.x = 1023 - p.x;
	p.y = 1023 - p.y;
  int16_t tempX = p.x;
  digitalWrite(13, LOW);
  // if sharing pins, you'll need to fix the directions of the touchscreen pins
  //pinMode(XP, OUTPUT);
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  //pinMode(YM, OUTPUT);
  // we have some minimum pressure we consider 'valid'
  // pressure of 0 means no pressing!
  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
  Serial.print("x=");
  Serial.print(p.x);
  Serial.print(", y=");
  Serial.print(p.y);
  Serial.print(", z=");
  Serial.println(p.z); 
  //Erase routine    
  //Press the top of the screen to erase 
   if (p.y < (TS_MINY-5)) {
       tft.fillRect(0, BOXSIZE, tft.width(), tft.height()-BOXSIZE, BLACK);
       Serial.println("erase");
       tft.setRotation(0);
       tft.setTextColor(YELLOW); 
       tft.setCursor(0, 0);
       tft.setTextSize(2);
       tft.println("   Press to Erase");
       tft.setRotation(3);
       tft.setTextColor(WHITE); 
       tft.setCursor(0, 0);
       tft.setTextSize(3);
       tft.println("   Attack Group 3");
       tft.setRotation(2);  }
    //Change color if new colored box is selected.
    // scale from 0->1023 to tft.width 
    p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
    p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(), 0);
    if (p.y < BOXSIZE) {
       oldcolor = currentcolor;
       if (p.x < BOXSIZE) { 
         currentcolor = RED; 
         tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
       } else if (p.x < BOXSIZE*2) {
         currentcolor = YELLOW;
         tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
       } else if (p.x < BOXSIZE*3) {
         currentcolor = GREEN;
         tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, WHITE);
       } else if (p.x < BOXSIZE*4) {
         currentcolor = CYAN;
         tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, WHITE);
       } else if (p.x < BOXSIZE*5) {
         currentcolor = BLUE;
         tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, WHITE);
       } else if (p.x < BOXSIZE*6) {
         currentcolor = MAGENTA;
         tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, WHITE);
       }

       if (oldcolor != currentcolor) {
          if (oldcolor == RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
          if (oldcolor == YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
          if (oldcolor == GREEN) tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
          if (oldcolor == CYAN) tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
          if (oldcolor == BLUE) tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
          if (oldcolor == MAGENTA) tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
       }
    }
    //Screen draw a circle at current x,y coordinates
    if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
      tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
    }
  }
}
	

Edward Kimble, PhD click here to e-mail me at: kimble@gunstar1.com
Edited May 11, 2016