Showing posts with label ILI9341 SPI. Show all posts
Showing posts with label ILI9341 SPI. Show all posts

Thursday, June 24, 2021

Arduino Nano RP2040 Connect + ILI9341 SPI TFT, using adafruit_ILI9341 library.

To drive ILI9341 SPI TFT on Arduino Nano RP2040 Connect (Arduino framework), Adafruit_ILI9341 library can be used.

Install Library:

In Arduino IDE, open Library Manager, search and install Adafruit ILI9341, Adafruit GFX library is needed also.


You will be asked to install extra libraries needed, click Install All.

Connection:

Connection:
ILI9341 TFT	Nano RP2040 Connect
-------------------------------
VCC		3V3
GND		GND
CS		D10
RESET		RESET
DC		D9
SDI(MOSI)	D11 (SPI0 TX)
SCK		D13 (SPI0 SCK)
LED		3V3
SDA(MISO)	D12 (SPI0 RX)
After then, you can try Adafruit_ILI9341 example graphicstest.

~ More exercise of Arduino Nano RP2040 Connect.

Tuesday, January 12, 2021

ESP32 (NodeMCU-32S) capture Analog input, display on SPI ILI9341 screen in waveform, base on Timer Interrupt.

The code run on NodeMCU-32S (ESP32 in Arduino framework) capture analog input in background base on timer interrupt, display on SPI ILI9341 screen graphically.


The timer interrupt is prepared in setup(), refer to Arduino IDE Examples > ESP32 > Timer > RepeatTimer.

bfr[][] is a 2x300 double buffer to store captured analog data. When one page (300 elements) is filled in interrupt service routine, it will switch to fill the another page and set bfr_filled flag to display the filled page in main loop(). Such that the main loop have to finish display within one page filled, 300 x sampling interval.

ESP32_AIN_TmrInt_20210112b.ino
#include "SPI.h"

#include "TFT_eSPI.h"
#define TFT_GREY 0x7BEF

TFT_eSPI myGLCD = TFT_eSPI();

#define FRAME_TOPX    10
#define FRAME_TOPY    5
#define FRAME_WIDTH   300
#define FRAME_HEIGHT  200
#define FRAME_BOTTOMY FRAME_TOPY + FRAME_HEIGHT

#define LAMP_PLOTTING_X FRAME_TOPX+290
#define LAMP_PLOTTING_Y FRAME_BOTTOMY+10
#define LAMP_PLOTTING_R 5

#define NO_OF_BFR_PAGE  2
#define NO_OF_BFR_ELE   300
unsigned int bfr[NO_OF_BFR_PAGE][NO_OF_BFR_ELE];
volatile int   bfr_page;
volatile int   bfr_idx;
volatile bool  bfr_filled;
volatile int   bfr_filled_page;
volatile bool  bfr_run = false;

volatile int   updateDot = -1;
volatile unsigned long prvSamplingTime;
#define PrgressDot_X  FRAME_TOPX
#define PrgressDot_Y  FRAME_BOTTOMY+4

#define PinAnalogIn 36

unsigned long previousTime = 0;

hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;

void IRAM_ATTR onTimer(){
  toFillBfr();
  // Give a semaphore that we can check in the loop
  xSemaphoreGiveFromISR(timerSemaphore, NULL);
}

void setup() {
  
  Serial.begin(115200);
  myGLCD.init();
  myGLCD.setRotation(1);
  myGLCD.fillScreen(TFT_BLACK);
  delay(500);
  myGLCD.fillRect(FRAME_TOPX-1, FRAME_TOPY-1, 
                  FRAME_WIDTH+2, FRAME_HEIGHT+2, TFT_WHITE);
  myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                  FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);

  myGLCD.setTextColor(TFT_WHITE,TFT_BLACK);
  myGLCD.drawString("Double Buffer", FRAME_TOPX, FRAME_BOTTOMY+20);

  // prepare bfr
  bfr_run = false;
  bfr_filled = false;
  bfr_page = 0;
  bfr_idx = 0;
  bfr_run = true;

  // --- Prepare Timer Intrrupt ---
  // Create semaphore to inform us when the timer has fired
  timerSemaphore = xSemaphoreCreateBinary();

  // Use 1st timer of 4 (counted from zero).
  // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
  // info).
  timer = timerBegin(0, 80, true);

  // Attach onTimer function to our timer.
  timerAttachInterrupt(timer, &onTimer, true);

  // Set alarm to call onTimer function every second (value in microseconds).
  // Repeat the alarm (third parameter)
  timerAlarmWrite(timer, 10000, true);  //10ms
  //timerAlarmWrite(timer, 1000, true);   //1ms

  // Start an alarm
  timerAlarmEnable(timer);
  prvSamplingTime = micros();
  // --- End of Prepare Timer Intrrupt ---

  Serial.println("\n --- Start ---\n");
  Serial.println("CPU Frequency (Mhz): " + String(getCpuFrequencyMhz()));
}

void handle_screen(){
  if(bfr_filled){
    //unsigned long beforeScreen = micros();
    
    bfr_filled = false;
    myGLCD.fillCircle(LAMP_PLOTTING_X, LAMP_PLOTTING_Y, LAMP_PLOTTING_R, TFT_RED);
    
    myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                  FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);
    int yPrv = bfr[bfr_filled_page][0];
    for(int i=1; i<NO_OF_BFR_ELE; i++){
      int yCur = bfr[bfr_filled_page][i];
      myGLCD.drawLine(FRAME_TOPX+i-1, FRAME_BOTTOMY-yPrv, 
                      FRAME_TOPX+i, FRAME_BOTTOMY-yCur, 
                      TFT_WHITE);
      yPrv = yCur;
        
    }

    myGLCD.fillCircle(LAMP_PLOTTING_X, LAMP_PLOTTING_Y, LAMP_PLOTTING_R, TFT_GREEN);
    myGLCD.drawLine(PrgressDot_X, PrgressDot_Y, PrgressDot_X+299, PrgressDot_Y, TFT_BLACK);

    //Serial.println("Fil duration: " + String(micros()-beforeScreen) + " (microsecond)");
  }

  //to draw alblue line under the graph for indicate the sample progress
  if(int x=updateDot){
    updateDot = -1;
    myGLCD.drawPixel(PrgressDot_X+x, PrgressDot_Y, TFT_BLUE);
  }
  
}

void loop() {

  if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
    handle_screen();
  }
}

void toFillBfr(){
  //unsigned long beforeFill = micros();

  unsigned long int curSamplingTime = micros();
  
  if(bfr_run){
    bfr[bfr_page][bfr_idx] = map(analogRead(PinAnalogIn),0, 4096, 0, 200);

    updateDot = bfr_idx;
    bfr_idx++;
    
    if(bfr_idx >= NO_OF_BFR_ELE){
      bfr_filled_page = bfr_page;
      bfr_idx=0;
      if(bfr_page==0){
        bfr_page = 1;
      }else{
        bfr_page = 0;
      }
      bfr_filled = true;
    }
  }

  //Send sampling interval to Serial Monitor for evaluation only,
  //remove it before finalize.
  Serial.println(curSamplingTime - prvSamplingTime);
  prvSamplingTime = curSamplingTime;

  //Serial.println("Fil duration: " + String(micros()-beforeFill) + " (microsecond)");
}

To setup TFT_eSPI using SPI ILI9342 for ESP32, read the post "ESP32 + 2.4" 320X240 Display (SPI ILI9341), using TFT_eSPI, prepare user setup file".


Sunday, January 10, 2021

ESP32 get time from pool.ntp.org (timeserver) display on 320x240 SPI ILI9341 Screen

Exercise run on ESP32 (NodeMCU-32S), Combine the examples of ESP32_SimpleTime and TFT_DIGITAL_CLOCK, get time from ntpServer "pool.ntp.org", and display on 2.4" 320x240 SPI ILI9341 screen in digital clock form.


ESP32_ILI9341_ntp_Clock_Digital_2021-01-10a.ino
/*
 * ESP32_ILI9341_ntp_Clock_Digital
 * 
 * Combine the examples of
 * Examples > ESP32 > Time > ESP32_SimpleTime and
 * Examples > TFT_eSPI > 320 x 240 > TFT_DIGITAL_CLOCK
 * 
 * Get time from ntpServer "pool.ntp.org",
 * display on SPI ILI9341 screen in digital clock form.
 * 
 * You have to change ssid/password to match with your wifi network.
 * and change gmtOffset_sec to match your timezone.
 =========================================================================
 Make sure all the display driver and pin comnenctions are correct by
 editting the User_Setup.h file in the TFT_eSPI library folder.
 
 #########################################################################
 ###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
 #########################################################################
For using SPI ILI9341 screen on ESP32,
refer Arduino-er: ESP32 + 2.4" 320X240 Display (SPI ILI9341), 
using TFT_eSPI, prepare user setup file.
http://arduino-er.blogspot.com/2021/01/esp32-24-320x240-display-spi-ili9341.html

A few colour codes:

code	color
0x0000	Black
0xFFFF	White
0xBDF7	Light Gray
0x7BEF	Dark Gray
0xF800	Red
0xFFE0	Yellow
0xFBE0	Orange
0x79E0	Brown
0x7E0	Green
0x7FF	Cyan
0x1F	Blue
0xF81F	Pink

 */

#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include <WiFi.h>
#include "time.h"


const char* ssid       = "ssid";
const char* password   = "password";

const char* ntpServer = "pool.ntp.org";
//+8 hr@HongKong
//8 * 60 * 60 = 28800
const long  gmtOffset_sec = 28800; //-8hr@Hong Kong
const int   daylightOffset_sec = 3600;

#define TFT_GREY 0x5AEB

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library

uint32_t targetTime = 0;                    // for next 1 second timeout


/* The original example get H, M, S from compile time
static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x

uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), 
        ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
*/

/*
 *  Get H,M, S after ntp server connected, 
 *  will load in printLocalTime()
 */
uint8_t hh,mm,ss;


byte omm = 99, oss = 99;
byte xcolon = 0, xsecs = 0;
unsigned int colour = 0;

void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  /* to read elements from getLocalTime(&timeinfo)
   * ref:
   * http://www.cplusplus.com/reference/ctime/tm/
   */
  int time_yday = timeinfo.tm_yday; //days since January 1
  int time_wday = timeinfo.tm_wday; //days since Sunday
  int time_year = timeinfo.tm_year; // years since 1900
  int time_mon  = timeinfo.tm_mon;   //months since January
  int time_mday = timeinfo.tm_mday; //day of the month
  int time_hr   = timeinfo.tm_hour;
  int time_min  = timeinfo.tm_min;
  int time_sec  = timeinfo.tm_sec;
  Serial.println("tm_yday: " + String(time_yday));
  Serial.println("tm_wday: " + String(time_wday));
  Serial.println("tm_year: " + String(time_year));
  Serial.println("tm_mon:  " + String(time_mon));
  Serial.println("tm_mday: " + String(time_mday));
  Serial.println("tm_hr:   " + String(time_hr));
  Serial.println("tm_min:  " + String(time_min));
  Serial.println("tm_sec:  " + String(time_sec)); 
  hh = time_hr;
  mm = time_min;
  ss = time_sec;
}

void setup(void) {
  Serial.begin(115200);
  /*
   * Connect to WiFi, and get time from ntpServer
   * To simplify, only once when power-up.
   */
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" CONNECTED");
  
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  
  /*
   * Prepare for TFT
   */
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  tft.setTextSize(1);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);

  targetTime = millis() + 1000;
}

void loop() {
  if (targetTime < millis()) {
    // Set next update for 1 second later
    targetTime = millis() + 1000;

    // Adjust the time values by adding 1 second
    ss++;              // Advance second
    if (ss == 60) {    // Check for roll-over
      ss = 0;          // Reset seconds to zero
      omm = mm;        // Save last minute time for display update
      mm++;            // Advance minute
      if (mm > 59) {   // Check for roll-over
        mm = 0;
        hh++;          // Advance hour
        if (hh > 23) { // Check for 24hr roll-over (could roll-over on 13)
          hh = 0;      // 0 for 24 hour clock, set to 1 for 12 hour clock
        }
      }
    }


    // Update digital time
    int xpos = 0;
    int ypos = 85; // Top left corner ot clock text, about half way down
    int ysecs = ypos + 24;

    if (omm != mm) { // Redraw hours and minutes time every minute
      omm = mm;
      // Draw hours and minutes
      if (hh < 10) xpos += tft.drawChar('0', xpos, ypos, 8); // Add hours leading zero for 24 hr clock
      xpos += tft.drawNumber(hh, xpos, ypos, 8);             // Draw hours
      xcolon = xpos; // Save colon coord for later to flash on/off later
      xpos += tft.drawChar(':', xpos, ypos - 8, 8);
      if (mm < 10) xpos += tft.drawChar('0', xpos, ypos, 8); // Add minutes leading zero
      xpos += tft.drawNumber(mm, xpos, ypos, 8);             // Draw minutes
      xsecs = xpos; // Sae seconds 'x' position for later display updates
    }
    if (oss != ss) { // Redraw seconds time every second
      oss = ss;
      xpos = xsecs;

      if (ss % 2) { // Flash the colons on/off
        tft.setTextColor(0x39C4, TFT_BLACK);        // Set colour to grey to dim colon
        tft.drawChar(':', xcolon, ypos - 8, 8);     // Hour:minute colon
        xpos += tft.drawChar(':', xsecs, ysecs, 6); // Seconds colon
        tft.setTextColor(TFT_YELLOW, TFT_BLACK);    // Set colour back to yellow
      }
      else {
        tft.drawChar(':', xcolon, ypos - 8, 8);     // Hour:minute colon
        xpos += tft.drawChar(':', xsecs, ysecs, 6); // Seconds colon
      }

      //Draw seconds
      if (ss < 10) xpos += tft.drawChar('0', xpos, ysecs, 6); // Add leading zero
      tft.drawNumber(ss, xpos, ysecs, 6);                     // Draw seconds
    }
  }
}

/*
// Function to extract numbers from compile time string
static uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
*/


Thursday, January 7, 2021

ESP32 (Arduino) ADC (Analog to Digital Converter), analogRead() and plot on 2.4" 320X240 Display (SPI ILI9341).

Example run on NodeMCU-32S, analogRead() from GPIO36, and plot on 2.4" 320X240 Display (SPI ILI9341).

To setup of the display, refer last post "ESP32 + 2.4" 320X240 Display (SPI ILI9341), using TFT_eSPI, prepare user setup file".


ESP32_ILI9341_AIN_20210108a.ino
/*
 * ESP32 + SPI ILI9341
 * Read Analog In and
 * plot on 2.4" 320x240 SPI ILI9341 screen
 */

#include "SPI.h"
#include "TFT_eSPI.h"

#define TFT_GREY 0x7BEF

TFT_eSPI myGLCD = TFT_eSPI();

#define FRAME_TOPX    10
#define FRAME_TOPY    5
#define FRAME_WIDTH   300
#define FRAME_HEIGHT  200
#define FRAME_BOTTOMY FRAME_TOPY + FRAME_HEIGHT

#define PinAnalogIn 36
int idx = 0;
#define IDX_MAX     300

void setup(){
  Serial.begin(115200);
  myGLCD.init();
  myGLCD.setRotation(1);
  myGLCD.fillScreen(TFT_BLACK);
  delay(500);
  myGLCD.fillRect(FRAME_TOPX-1, FRAME_TOPY-1, 
                  FRAME_WIDTH+2, FRAME_HEIGHT+2, TFT_WHITE);
  myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                  FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);

  myGLCD.setTextColor(TFT_WHITE,TFT_BLACK);
  myGLCD.drawString("ESP32 (Arduino framework) + SPI ILI9341", 
                  FRAME_TOPX, FRAME_BOTTOMY+10);
  myGLCD.drawString("ADC exercise", FRAME_TOPX, FRAME_BOTTOMY+20);

  Serial.println("\n --- Start ---\n");
}

void loop(){
  int val = analogRead(PinAnalogIn);
  int AnalogInVal = map(val, 0, 4096, 0, 200);

  Serial.print(val);
  Serial.print(" : ");
  Serial.println(AnalogInVal);
  
  myGLCD.drawLine(
      FRAME_TOPX+idx, FRAME_BOTTOMY, 
      FRAME_TOPX+idx, FRAME_BOTTOMY-AnalogInVal, 
      TFT_WHITE);
  
  //Serial.println(hall);
  delay(100);
  
  idx++;
  if(idx >= IDX_MAX){
    idx = 0;
    myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                    FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);
  }

}

Next:

Tuesday, January 5, 2021

ESP32 + 2.4" 320X240 Display (SPI ILI9341), using TFT_eSPI, prepare user setup file.

Install TFT_eSPI library in Arduino IDE Library Manager.

Reading the TFT_eSPI GitHub page, if you update TFT_eSPI then it will over-write your setups if they are kept within the TFT_eSPI folder. It's suggested to create a new folder in your Arduino library folder called "TFT_eSPI_Setups". You then place your custom setup.h files in there. After an upgrade simply edit the User_Setup_Select.h file to point to your custom setup file.

Here is how to prepare my custom setup file for using SPI ILI9341 on ESP32 (NodeMCU-32S).

- Create a new folder in your Arduino library folder called "TFT_eSPI_Setups"

- Copy default User_Setup.h (checked it match with using SPI ILI9341) to "TFT_eSPI_Setups" folder, rename it if you want.


- Edit the User_Setup_Select.h file to point to the custom setup file.


- Edit the custom user setup file:

ILI9341_DRIVER is selected by default, keep it no change.


Comment and un-comment the pin assignment code as shown:

Saturday, June 27, 2020

ESP32-DevKitC + 2.8inch 240x320 SPI TFT (ILI9341) using TFT_eSPI library

This post show how to use ESP32-DevKitC to drive a 2.8inch 240x320 SPI TFT (wih ILI9314 using serial interface), using TFT_eSPI library.




Connection:


I connect ESP32-DevKitC and Display board follow the default setting of TFT_eSPI library.
TFT_MISO 19
TFT_MOSI 23
TFT_SCLK 18
TFT_CS   15
TFT_DC    2
TFT_RST   4

I found the Fritzing parts here:
ESP32S-HiLetgo Dev Boad with Pinout Template
https://forum.fritzing.org/t/esp32s-hiletgo-dev-boad-with-pinout-template/5357

2.2 320x240 TFT ILI9341.fzpz (it should be logically same as the 2.8" display I use)
https://forum.fritzing.org/t/2-2-ili9342-tft/1813

Setup Library in Arduino IDE:
Menu > Sketch > Include Library > Manager Libraries...
Search and install TFT_eSPI


Then have to edit User_Setup.h to fix your circuit.


- Confirm ILI9341_DRIVER is defined

- comment the original define of:
TFT_CS, TFT_DC and TFT_RST.

- un-comment the pin define under "For ESP32 Dev board (only tested with ILI9341 display)"
TFT_MISO, TFT_MOSI 23, TFT_SCLK, TFT_CS, TFT_DC and TFT_RST.

Then, you can try any example under TFT_eSPI.



Using TFT_eSPI, if you load a new copy of TFT_eSPI then it will over-write your setups if they are kept within the TFT_eSPI folder. It's suggested to create a new folder in your Arduino library folder called "TFT_eSPI_Setups". You then place your custom setup.h files in there. After an upgrade simply edit the User_Setup_Select.h file to point to your custom setup file.

check it:
ESP32 + 1.3 inch 240x240 IPS LCD (ST7789 SPI interface), using TFT_eSPI library