Raspberry Pi Pico 2 drive 4.0" 320x480 TFT SPI ST7796 with FT6336U Capacitive Touch + SD, in Arduino framework

Exercise of Raspberry Pi Pico 2 (in Arduino framework) to drive 4.0" 320x480 TFT SPI ST7796 with FT6336U Capacitive Touch + SD. The Raspberry Pi Pico 2 are programmed in Arduino framework using board of Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III (arduino-pico), load bmp images from SD card, display on ST7796 using TFT_eSPI, and touch screen to switching among images.



Connection:
	ST7796 Module	Raspberry Pi Pico 2
	---------------------------------------
	SD_CS		GP15
	CTP_INT		not used
	CTP_SDA		GP4
	CTP_RST		GP14 (optional, or 3V3)
	CTP_SCL		GP5
	SDO(MISO)	GP16	
	LED		GP22
	SCK		GP18
	SDI(MOSI)	GP19
	LCD_RS		GP21
	LCD_RST		GP20
	LCD_CS		GP17
	GND		GND
	VCC		VBUS (5V)


This ST7796 display module have on board level conversion circuit, compatible with 5V and 3.3V MCU. According LCDWiKi 4.0inch Capacitive SPI Module ST7796, VCC is recommended to connect to 5V. When connected to 3.3V, the backlight brightness will be slightly dim. In my test on Raspberry Pi Pico 2 on breadboard, VCC connected to VBUS is much more stable than connect to 3V3(OUT).

In my connection, both SPI (shared by ST7796 and SD) and I2C (FT6336U) are default GPIO in the board Raspberry Pi Pico/RP2040/RP2350.

Board of Raspberry Pi Pico/RP2040/RP2350

Board of Raspberry Pi Pico/RP2040/RP2350 by Earle F. Philhower, III is a Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards. To install it on Arduino IDE, read the post Install Earle Philhower Raspberry Pi Pico Arduino core.

Prepare TFT_eSPI Library and setup

It's easy to install TFT_eSPI in Arduino IDE in its Library Manager, but take a notice on user setup file.

Read TFT_eSPI page, scroll down to Tips section. It's suggest to create a new folder in your Arduino library folder called "TFT_eSPI_Setups". You then place your custom setup.h files in there.

Setup_ST7796_pico2.h, my setup.h file.
// Setup_ST7796_pico2.h in
// ..\Arduino\libraries\TFT_eSPI_Setups\
//
// Modify
// ..\Arduino\libraries\TFT_eSPI\User_Setup_Select.h to load it.
// #include <../TFT_eSPI_Setups/Setup_ST7796_pico2.h>

#define ST7796_DRIVER

#define TFT_WIDTH  320
#define TFT_HEIGHT 480

// TFT_MOSI/TFT_SCLK for default SPI pin assignment
#define TFT_MISO -1
#define TFT_MOSI 19
#define TFT_SCLK 18
#define TFT_CS   17
#define TFT_DC   21
#define TFT_RST  20
#define TFT_BL   22            // LED back-light control pin
#define TFT_BACKLIGHT_ON HIGH  // Level to turn ON back-light (HIGH or LOW)

// if use SPI0, undefine TFT_SPI_PORT, or define as 0
// if use SPI1, define TFT_SPI_PORT as 1
//#define TFT_SPI_PORT 0

#define SPI_FREQUENCY  27000000

////////////////////////////////////////////////////////////////////////////////////////////
// Fonts to be available
////////////////////////////////////////////////////////////////////////////////////////////
#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts

#define SMOOTH_FONT
Edit \TFT_eSPI\User_Setup_Select.h to include it.
#include <../TFT_eSPI_Setups/Setup_ST7796_pico2.h>
Once you finished the setup files, you can run the TFT_eSPI examples in Arduino IDE.

Test bmp images:

All test images were generated using X Grok, resized and converted to 426*320, RGB888, .bmp using Python, read Resize jpg and convert to bmp in RGB888 and RGB565 mode, using Python/GIMP,

Exercise Code:

pico2_st7796_sd.ino
/*
A simple exercise on Raspberry Pi Pico 2,
run in Arduino framework using board of arduino-pico by earlephilhower 
(named Raspberry Pi Pico/RP2040/RP2350 in Arduino IDE Boards Manager).
List files in SD,
load a fixed bmp file from SD and display on 4.0inch Capacitive SPI Module ST7796 using TFT_eSPI library.
The ST7796 and SD share the same SPI with separated CS.

The testing images are 426*320, RGB888, .bmp.
Converted using Python in:
https://coxxect.blogspot.com/2024/11/resize-jpg-and-convert-to-bmp-in-rgb888.html

*/

#include <SPI.h>
#include <SD.h>
#include <TFT_eSPI.h>

#define SD_CS 15

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

void setup() {
  delay(500);
  Serial.begin(115200);
  delay(1000);
  Serial.println("--- Start ---");

  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
  SPI.begin();

  // Hardware Reset ST7796 at power up
  // try to fix sometimes screen blank.
  Serial.println("Hardware Reset on TFT_RST: " + String(TFT_RST));
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, HIGH);
  delay(100);
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, LOW);
  delay(100);
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, HIGH);
  delay(100);

  tft.init();
  //tft.setRotation(1);
  Serial.println("TFT_WIDTH x TFT_HEIGHT = " + String(TFT_WIDTH) + " x " + String(TFT_HEIGHT));
  Serial.println("tft.width() x tft.height() = " + String(tft.width()) + " x " + String(tft.height()));

  tft.fillScreen(TFT_BLACK);
  tft.drawRect(0, 0, tft.width(), tft.height(), TFT_GREEN);

  // Set "cursor" at top left corner of display (0,0) and select font 1
  tft.setCursor(0, 0, 1);

  //init SD
  Serial.println("Initialize SD");
  tft.println("Initialize SD");

  while (!SD.begin(SD_CS)){
    Serial.println("Fail!");
    tft.println("Fail!");
    delay(1000);
  }
  
  Serial.println("Success");
  tft.println("Success");

  listSDCard();

}

void loop() {
  tft.fillScreen(TFT_BLACK);
  drawBmp("/images/img_001_320x426_rgb888.bmp", 0, 0);
  delay(5000);
}

void listDir(File dir, int numTabs) {
    while (true) {
        File entry = dir.openNextFile();
        if (!entry) {
            break; // no more file
        }

        for (int i = 0; i < numTabs; i++) {
            Serial.print("\t");
        }
        
        Serial.print(entry.name());
        tft.print(entry.name());
        
        if (entry.isDirectory()) {
            Serial.println("/");
            tft.println("/");
            listDir(entry, numTabs + 1);
        } else {
            Serial.println(entry.size());
            tft.println(entry.size());
        }
        
        entry.close();
    }
}

void listSDCard() {
    File root = SD.open("/");
    listDir(root, 0);
}

void drawBmp(const char *filename, int16_t x, int16_t y) {
    File bmpFile;
    uint8_t bmpHeader[54];
    uint32_t dataOffset, imageWidth, imageHeight;
    uint16_t rowPadding;
    uint16_t pixel;

    // Open the BMP file
    bmpFile = SD.open(filename);
    if (!bmpFile) {
        Serial.println("Failed to open BMP file");
        return;
    }

    // Read the BMP file header
    bmpFile.read(bmpHeader, 54);

    // Check for BMP signature ("BM")
    if (bmpHeader[0] != 'B' || bmpHeader[1] != 'M') {
        Serial.println("Not a valid BMP file");
        bmpFile.close();
        return;
    }

    // Get image dimensions
    dataOffset = *(uint32_t *)&bmpHeader[10];
    imageWidth = *(uint32_t *)&bmpHeader[18];
    imageHeight = *(uint32_t *)&bmpHeader[22];
    rowPadding = (4 - (imageWidth * 3) % 4) % 4;

    // Move to image data start
    bmpFile.seek(dataOffset);

    // Draw the BMP pixel-by-pixel
    for (int16_t row = imageHeight - 1; row >= 0; row--) {  // BMPs are stored bottom-up
        for (int16_t col = 0; col < imageWidth; col++) {
            uint8_t b = bmpFile.read();
            uint8_t g = bmpFile.read();
            uint8_t r = bmpFile.read();
            pixel = tft.color565(r, g, b);
            tft.drawPixel(x + col, y + row, pixel);
        }
        // Skip row padding
        bmpFile.seek(bmpFile.position() + rowPadding);
    }

    bmpFile.close();
}




pico2_st7796_slideshow.ino
/*
Exercise on Raspberry Pi Pico 2,
run in Arduino framework using board of arduino-pico by earlephilhower 
(named Raspberry Pi Pico/RP2040/RP2350 in Arduino IDE Boards Manager).

Display bmp on 4.0inch Capacitive SPI Module ST7796 using TFT_eSPI library, in slideahow form.
In-between drawing bmp, you can touch screen to check the touch detection.
This exercise ensure all three parts (ST7796, SD and FT6336U cap. touch) work.

The testing images are 426*320, RGB888, .bmp.
Converted using Python in:
https://coxxect.blogspot.com/2024/11/resize-jpg-and-convert-to-bmp-in-rgb888.html

The bmp draw in pixel-by-pixel using drawPixel(), more than 5 seconds to read and display a 426*320 bmp.

FT6336U is accessed using Wire (I2C) directly, without using library.
*/

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <TFT_eSPI.h>  // Hardware-specific library
#include <LinkedList.h> // Have to install "LinkedList" in Library Manager

#define SD_CS 15
#define CTP_RST 14  // option, can connect to 3V3.

#define FT6336U_ADDR 0x38
#define TFT_WIDTH 320
#define TFT_HEIGHT 480

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

unsigned long nextTime;
const unsigned long duration = 5000;

LinkedList<String> bmpFiles;
String images_folder = "/images";  // target images directory in SD
int image_index = 0;

void setup() {
  delay(500);
  Serial.begin(115200);
  delay(1000);
  Serial.println("--- Start ---");

  // default SDA = 4
  // default SCL = 5
  Serial.println("SDA " + String(SDA));
  Serial.println("SCL " + String(SCL));
  Wire.begin();  // I2C

  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
  SPI.begin();

  // Hardware Reset ST7796 at power up
  // try to fix sometimes screen blank.
  Serial.println("Hardware Reset on TFT_RST: " + String(TFT_RST));
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, HIGH);
  delay(100);
  digitalWrite(TFT_RST, LOW);
  delay(100);
  digitalWrite(TFT_RST, HIGH);
  delay(100);

  // Optional CTS_RST
  // In my test, CTS_RST can be connect to 3V3.
  Serial.println("Hardware Reset on CTP_RST: ");
  pinMode(CTP_RST, OUTPUT);
  digitalWrite(CTP_RST, HIGH);
  delay(100);
  digitalWrite(CTP_RST, LOW);
  delay(100);
  digitalWrite(CTP_RST, HIGH);
  delay(100);

  tft.init();
  tft.setRotation(1);

  tft.init();
  tft.setRotation(1);
  Serial.println("TFT_WIDTH x TFT_HEIGHT = " + String(TFT_WIDTH) + " x " + String(TFT_HEIGHT));
  Serial.println("tft.width() x tft.height() = " + String(tft.width()) + " x " + String(tft.height()));

  tft.fillScreen(TFT_BLACK);
  tft.drawRect(0, 0, tft.width(), tft.height(), TFT_GREEN);

  // Set "cursor" at top left corner of display (0,0) and select font 2
  tft.setCursor(0, 0, 2);

  //init SD
  Serial.println("Initialize SD");
  tft.println("Initialize SD");

  while (!SD.begin(SD_CS)) {
    Serial.println("Fail!");
    tft.println("Fail!");
    delay(1000);
  }

  Serial.println("Success");
  tft.println("Success");

  listBmpFiles();
  sortBmpFiles();
  for (int i=0; i<bmpFiles.size(); i++){
    Serial.println(" " + String(i) + " : " + bmpFiles.get(i));
    tft.println(" " + String(i) + " : " + bmpFiles.get(i));
  }

  nextTime = millis() + 1000; // list bmp files on screen for 1 second
}

void loop() {
  if (millis() > nextTime) {
    tft.fillScreen(TFT_BLACK);

    String a = images_folder + "/" + bmpFiles.get(image_index);
    
    unsigned long begin_drawBmp = millis();
    drawBmp(a, 0, 0);
    unsigned long end_drawBmp = millis();
    Serial.println("in " + String(end_drawBmp-begin_drawBmp) + " ms");

    image_index++;
    if (image_index==bmpFiles.size()){
      image_index = 0;
    }

    nextTime = millis() + duration;
  } else {
    if (get_touch_count() > 0) {
      int x, y;
      get_touch_point(&x, &y);
      Serial.print(x);
      Serial.print(" : ");
      Serial.println(y);
      tft.fillCircle(x, y, 3, TFT_WHITE);
    }
  }
}


void listBmpFiles(){
  File dir = SD.open(images_folder);

  if(!dir){
    Serial.println("Cannot open " + images_folder);
    return;
  }

  while (true){
    File file = dir.openNextFile();
    if (!file) break;   // no more file

    String filename = String(file.name());
    if (filename.endsWith(".bmp")){
      bmpFiles.add(filename);
    }
    file.close();

  }

  Serial.println(String(bmpFiles.size()) + " bmp files:");
  tft.println(String(bmpFiles.size()) + " bmp files:");
}

void sortBmpFiles() {
    int n = bmpFiles.size();
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (bmpFiles.get(j) > bmpFiles.get(j + 1)) {
                // Swap elements
                String temp = bmpFiles.get(j);
                bmpFiles.set(j, bmpFiles.get(j + 1));
                bmpFiles.set(j + 1, temp);
            }
        }
    }
}

void drawBmp(String filename, int16_t x, int16_t y) {
  Serial.println("drawBmp(): " + filename);
  File bmpFile;
  uint8_t bmpHeader[54];
  uint32_t dataOffset, imageWidth, imageHeight;
  uint16_t rowPadding;
  uint16_t pixel;

  // Open the BMP file
  bmpFile = SD.open(filename);
  if (!bmpFile) {
    Serial.println("Failed to open BMP file");
    return;
  }

  // Read the BMP file header
  bmpFile.read(bmpHeader, 54);

  // Check for BMP signature ("BM")
  if (bmpHeader[0] != 'B' || bmpHeader[1] != 'M') {
    Serial.println("Not a valid BMP file");
    bmpFile.close();
    return;
  }

  // Get image dimensions
  dataOffset = *(uint32_t *)&bmpHeader[10];
  imageWidth = *(uint32_t *)&bmpHeader[18];
  imageHeight = *(uint32_t *)&bmpHeader[22];
  rowPadding = (4 - (imageWidth * 3) % 4) % 4;

  // Move to image data start
  bmpFile.seek(dataOffset);

  // Draw the BMP
  for (int16_t row = imageHeight - 1; row >= 0; row--) {  // BMPs are stored bottom-up
    for (int16_t col = 0; col < imageWidth; col++) {
      uint8_t b = bmpFile.read();
      uint8_t g = bmpFile.read();
      uint8_t r = bmpFile.read();
      pixel = tft.color565(r, g, b);
      tft.drawPixel(x + col, y + row, pixel);
    }
    // Skip row padding
    bmpFile.seek(bmpFile.position() + rowPadding);
  }

  bmpFile.close();
}

int get_touch_count() {

  // Register 0x02
  // Touch count, max 2.
  Wire.beginTransmission(FT6336U_ADDR);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(FT6336U_ADDR, 1);
  return (Wire.read());
}

// Read x, y
// May be have to exchange/adjust x, y according to screen rotation.
void get_touch_point(int *x, int *y) {

  // Read X:
  // Register 0x03
  // bit7-bit6 Touch event of the 1st touch point
  // bit3-bit0 Hight 4 bit of the 1st touch point
  // Register 0x04
  // Low 8 bit of the 1st touch point
  Wire.beginTransmission(FT6336U_ADDR);
  Wire.write(0x03);
  Wire.endTransmission();
  Wire.requestFrom(FT6336U_ADDR, 2);
  *y = (Wire.read() & 0x0f) << 8 | Wire.read();
  *y = TFT_WIDTH - *y;    // adjust depends on screen rotation

  // Read Y:
  // Register 0x05
  // bit7-bit6 ID of the 1st touch point
  // bit3-bit0 Hight 4 bit of the 1st touch point
  // Register 0x06
  // Low 8 bit of the 1st touch point
  Wire.beginTransmission(FT6336U_ADDR);
  Wire.write(0x05);
  Wire.endTransmission();
  Wire.requestFrom(FT6336U_ADDR, 2);
  *x = (Wire.read() & 0x0f) << 8 | Wire.read();
}


pico2_st7796_slideshow_touch.ino
/*
Exercise on Raspberry Pi Pico 2,
run in Arduino framework using board of arduino-pico by earlephilhower 
(named Raspberry Pi Pico/RP2040/RP2350 in Arduino IDE Boards Manager).

Display bmp on 4.0inch Capacitive SPI Module ST7796 using TFT_eSPI library.
After bmp drawn, touch left 1/3 of the screen to switch to previous bmp, or right 1/3 to switch to next bmp.
This exercise ensure all three parts (ST7796, SD and FT6336U cap. touch) work.

The testing images are 426*320, RGB888, .bmp.
Converted using Python in:
https://coxxect.blogspot.com/2024/11/resize-jpg-and-convert-to-bmp-in-rgb888.html

The bmp are read in 3 bytes (one pixel) together, and display in row-by-row using pushImage().
About 2.x seconds to read and display a 426*320 bmp.

FT6336U is accessed using Wire (I2C) directly, without using library.
*/

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <TFT_eSPI.h>  // Hardware-specific library
#include <LinkedList.h> // Have to install "LinkedList" in Library Manager

#define SD_CS 15
#define CTP_RST 14  // option, can connect to 3V3.

#define FT6336U_ADDR 0x38

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

LinkedList<String> bmpFiles;
String images_folder = "/images";  // target images directory in SD
int image_index = 0;
bool request_to_draw;

void setup() {
  delay(500);
  Serial.begin(115200);
  delay(1000);
  Serial.println("--- Start ---");

  // default SDA = 4
  // default SCL = 5
  Serial.println("SDA " + String(SDA));
  Serial.println("SCL " + String(SCL));
  Wire.begin();  // I2C

  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
  SPI.begin();

  // Hardware Reset ST7796 at power up
  // try to fix sometimes screen blank.
  Serial.println("Hardware Reset on TFT_RST: " + String(TFT_RST));
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, HIGH);
  delay(100);
  digitalWrite(TFT_RST, LOW);
  delay(100);
  digitalWrite(TFT_RST, HIGH);
  delay(100);

  // Optional CTS_RST
  // In my test, CTS_RST can be connect to 3V3.
  Serial.println("Hardware Reset on CTP_RST: ");
  pinMode(CTP_RST, OUTPUT);
  digitalWrite(CTP_RST, HIGH);
  delay(100);
  digitalWrite(CTP_RST, LOW);
  delay(100);
  digitalWrite(CTP_RST, HIGH);
  delay(100);

  tft.init();
  tft.setRotation(1);
  Serial.println("TFT_WIDTH x TFT_HEIGHT = " + String(TFT_WIDTH) + " x " + String(TFT_HEIGHT));
  Serial.println("tft.width() x tft.height() = " + String(tft.width()) + " x " + String(tft.height()));

  tft.fillScreen(TFT_BLACK);
  tft.drawRect(0, 0, tft.width(), tft.height(), TFT_GREEN);

  // Set "cursor" at top left corner of display (0,0) and select font 4
  tft.setCursor(0, 0, 2);

  //init SD
  Serial.println("Initialize SD");
  tft.println("Initialize SD");

  while (!SD.begin(SD_CS)) {
    Serial.println("Fail!");
    tft.println("Fail!");
    delay(1000);
  }

  Serial.println("Success");
  tft.println("Success");

  listBmpFiles();
  sortBmpFiles();
  for (int i=0; i<bmpFiles.size(); i++){
    Serial.println(" " + String(i) + " : " + bmpFiles.get(i));
    tft.println(" " + String(i) + " : " + bmpFiles.get(i));
  }

  delay(1000);
  request_to_draw = true;
}

void loop() {
  if (request_to_draw){
    tft.fillScreen(TFT_BLACK);
    String a = images_folder + "/" + bmpFiles.get(image_index);
    unsigned long begin_drawBmp = millis();
    drawBmp(a, 0, 0);
    unsigned long end_drawBmp = millis();
    Serial.println("in " + String(end_drawBmp-begin_drawBmp) + " ms");

    request_to_draw = false;
  }
  

  if (get_touch_count() > 0) {
    int x, y;
    get_touch_point(&x, &y);
    if (x<=tft.width()/3){
      Serial.println("<< Previous");
      image_index--;
      if (image_index==-1){
        image_index = bmpFiles.size()-1;
        }
      request_to_draw = true;
    }else if (x>=tft.width()*2/3){
      Serial.println(">> Next");
      image_index++;
      if (image_index==bmpFiles.size()){
        image_index = 0;
        }
      request_to_draw = true;
    }else{
      delay(100);
    }
  }else{
    delay(100);
  }
}

void listBmpFiles(){
  File dir = SD.open(images_folder);

  if(!dir){
    Serial.println("Cannot open " + images_folder);
    return;
  }

  while (true){
    File file = dir.openNextFile();
    if (!file) break;   // no more file

    String filename = String(file.name());
    if (filename.endsWith(".bmp")){
      bmpFiles.add(filename);
    }
    file.close();

  }

  Serial.println(String(bmpFiles.size()) + " bmp files:");
  tft.println(String(bmpFiles.size()) + " bmp files:");
}

void sortBmpFiles() {
    int n = bmpFiles.size();
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (bmpFiles.get(j) > bmpFiles.get(j + 1)) {
                // Swap elements
                String temp = bmpFiles.get(j);
                bmpFiles.set(j, bmpFiles.get(j + 1));
                bmpFiles.set(j + 1, temp);
            }
        }
    }
}

//Draw bmp, row-by-row
void drawBmp(String filename, int16_t x, int16_t y) {
  Serial.println("drawBmp() row-by-row: " + filename);
  File bmpFile;
  uint8_t bmpHeader[54];
  uint32_t dataOffset, imageWidth, imageHeight;
  uint16_t rowPadding;
    
  // Open the BMP file
  bmpFile = SD.open(filename);
  if (!bmpFile) {
    Serial.println("Failed to open BMP file");
    return;
  }
  
  // Read the BMP file header
  bmpFile.read(bmpHeader, 54);
  
  // Check for BMP signature ("BM")
  if (bmpHeader[0] != 'B' || bmpHeader[1] != 'M') {
    Serial.println("Not a valid BMP file");
    bmpFile.close();
    return;
  }
  
  // Get image dimensions
  dataOffset = *(uint32_t *)&bmpHeader[10];
  imageWidth = *(uint32_t *)&bmpHeader[18];
  imageHeight = *(uint32_t *)&bmpHeader[22];
  rowPadding = (4 - (imageWidth * 3) % 4) % 4;

  // Move to image data start
  bmpFile.seek(dataOffset);

  uint16_t pixelBuffer[imageWidth];

  // draw row-by-row
  for (int16_t row = imageHeight - 1; row >= 0; row--) { // in reverse order
    for (int16_t col = 0; col < imageWidth; col++) {
      uint8_t pixelData[3];
      bmpFile.read(pixelData, 3);   // Read 3 bytes at a time
      uint16_t value = tft.color565(pixelData[2], pixelData[1], pixelData[0]);
      pixelBuffer[col] = (value>>8) | (value<<8);
    }

    // Skip row padding
    bmpFile.seek(bmpFile.position() + rowPadding);

    // draw a whole row using pushImage()
    tft.pushImage(x, y + row, imageWidth, 1, pixelBuffer);
  }
  
  bmpFile.close();
}

/*
//Draw bmp, pixel-by-pixel
void drawBmp(String filename, int16_t x, int16_t y) {
  Serial.println("drawBmp() pixel-by-pixel: " + filename);
  File bmpFile;
  uint8_t bmpHeader[54];
  uint32_t dataOffset, imageWidth, imageHeight;
  uint16_t rowPadding;
  uint16_t pixel;

  // Open the BMP file
  bmpFile = SD.open(filename);
  if (!bmpFile) {
    Serial.println("Failed to open BMP file");
    return;
  }

  // Read the BMP file header
  bmpFile.read(bmpHeader, 54);

  // Check for BMP signature ("BM")
  if (bmpHeader[0] != 'B' || bmpHeader[1] != 'M') {
    Serial.println("Not a valid BMP file");
    bmpFile.close();
    return;
  }

  // Get image dimensions
  dataOffset = *(uint32_t *)&bmpHeader[10];
  imageWidth = *(uint32_t *)&bmpHeader[18];
  imageHeight = *(uint32_t *)&bmpHeader[22];
  rowPadding = (4 - (imageWidth * 3) % 4) % 4;

  // Move to image data start
  bmpFile.seek(dataOffset);

  // Draw the BMP
  for (int16_t row = imageHeight - 1; row >= 0; row--) {  // BMPs are stored bottom-up
    for (int16_t col = 0; col < imageWidth; col++) {
      uint8_t b = bmpFile.read();
      uint8_t g = bmpFile.read();
      uint8_t r = bmpFile.read();
      pixel = tft.color565(r, g, b);
      tft.drawPixel(x + col, y + row, pixel);
    }
    // Skip row padding
    bmpFile.seek(bmpFile.position() + rowPadding);
  }

  bmpFile.close();
}
*/

int get_touch_count() {

  // Register 0x02
  // Touch count, max 2.
  Wire.beginTransmission(FT6336U_ADDR);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(FT6336U_ADDR, 1);
  return (Wire.read());
}

// Read x, y
// May be have to exchange/adjust x, y according to screen rotation.
void get_touch_point(int *x, int *y) {

  // Read X:
  // Register 0x03
  // bit7-bit6 Touch event of the 1st touch point
  // bit3-bit0 Hight 4 bit of the 1st touch point
  // Register 0x04
  // Low 8 bit of the 1st touch point
  Wire.beginTransmission(FT6336U_ADDR);
  Wire.write(0x03);
  Wire.endTransmission();
  Wire.requestFrom(FT6336U_ADDR, 2);
  *y = (Wire.read() & 0x0f) << 8 | Wire.read();
  *y = TFT_HEIGHT - *y;    // adjust depends on screen rotation

  // Read Y:
  // Register 0x05
  // bit7-bit6 ID of the 1st touch point
  // bit3-bit0 Hight 4 bit of the 1st touch point
  // Register 0x06
  // Low 8 bit of the 1st touch point
  Wire.beginTransmission(FT6336U_ADDR);
  Wire.write(0x05);
  Wire.endTransmission();
  Wire.requestFrom(FT6336U_ADDR, 2);
  *x = (Wire.read() & 0x0f) << 8 | Wire.read();
}

Next:
LVGL on Raspberry Pi Pico 2 (Arduino framework/arduino-pico) with 320x480 TFT SPI ST7796 + FT6336U Capacitive Touch



Comments

Popular posts from this blog

480x320 TFT/ILI9488 SPI wih EP32C3 (arduino-esp32) using Arduino_GFX Library

Drive 320x240 ILI9341 SPI TFT using ESP32-S3 (NodeMCU ESP-S3-12K-Kit) using TFT_eSPI library, in Arduino Framework.