This ESP32-CAM Project covers how to use ESP32-CAM with a TFT display to show the picture captured by the cam. We have covered several times how to use ESP32-CAM in different projects and we have described how to use ESP32-CAM in Machine Learning projects. Even if we can use ESP32-CAM with a Web server to show pictures, in this post we want to cover how to show a picture on a TFT screen (ST7735). Therefore, we would like to visualize the picture taken by the ESP32-CAM directly on the display. In this case, we use an ST7735s display, anyway, you can select a different TFT if you like.
ESP32-CAM with TFT project overview
To build this project you will need the following components:
- ESP32-CAM
- TFT display (ST7735s)
- Button (to take the picture)
- FTDI232 to program the ESP32-CAM
The project works in this way:
- Using the button we take the picture (as it happens in a real camera)
- as soon as the picture is taken, the ESP32 displays it on the TFT
How to connect ESP32-CAM to TFT display
This is ESP32-cam with TFT schematic:

This table shows the ESP32-CAM Pins and the ST7735s Pins:
ESP32-CAM | TFT (ST7735s) |
13 | MOSI |
14 | CLK |
15 | CS |
2 | DC |
12 | RESET |
Display picture from ESP32-CAM to TFT display
This is the source:
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <TJpg_Decoder.h>
#include "esp_camera.h"
#define CAMERA_MODEL_AI_THINKER // Has PSRAM
#include "camera_pins.h"
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS 15 // Chip select control pin
#define TFT_DC 2 // Data Command control pin
#define TFT_RST 12
#define PIN_BTN 4
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
// Stop further decoding as image is running off bottom of screen
if ( y >= tft.height() ) return 0;
tft.drawRGBBitmap(x, y, bitmap, w, h);
// Return 1 to decode next block
return 1;
}
void init_camera() {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(psramFound()){
config.frame_size = FRAMESIZE_QQVGA;
config.jpeg_quality = 10;
config.fb_count = 1;
Serial.println("PSRAM");
} else {
config.frame_size = FRAMESIZE_QQVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
sensor_t * s = esp_camera_sensor_get();
// initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
Serial.println("PID");
s->set_vflip(s, 1); // flip it back
s->set_brightness(s, 2); // up the brightness just a bit
s->set_saturation(s, 0);
}
}
void setup() {
Serial.begin(9600);
Serial.println("ESP32-CAM Picture");
tft.initR(INITR_BLACKTAB);
tft.setRotation(1);
tft.fillScreen(ST77XX_GREEN);
init_camera();
pinMode(PIN_BTN, INPUT);
TJpgDec.setJpgScale(1);
// The decoder must be given the exact name of the rendering function above
TJpgDec.setCallback(tft_output);
}
void take_picture(){
Serial.println("Taking picture..");
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
}
uint16_t w = 0, h = 0;
TJpgDec.getJpgSize(&w, &h, fb->buf, fb->len);
Serial.print("- Width = "); Serial.print(fb->width); Serial.print(", height = "); Serial.println(fb->height);
Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h);
// Draw the image, top left at 0,0
TJpgDec.drawJpg(0, 0, fb->buf, fb->len);
}
void loop() {
while (true) {
int state = digitalRead(PIN_BTN);
if (state == HIGH) {
Serial.println("Button pressed");
take_picture();
}
delay(200);
}
}
Code language: C++ (cpp)
If you use PlatformIO to develop this project, this the platformio.ini
:
[env:esp32cam]
platform = espressif32
board = esp32cam
framework = arduino
lib_deps =
adafruit/Adafruit GFX Library @ ^1.10.5
adafruit/Adafruit ST7735 and ST7789 Library @ ^1.6.0
adafruit/Adafruit BusIO @ ^1.7.2
bodmer/TJpg_Decoder @ ^0.2.0
Therefore we will use the following libraries:
- Adafruit GFX Library
- Adafruit ST7735 and ST7789
- Adafruit BusIO
- TJpg_Decoder (link)
You should already know how to take a picture using an ESP32-CAM therefore we will focus on two aspects only:
- How to connect the ESP32-CAM to TFT display
- How to show the picture on the TFT display
Initializing the TFT display
This is simple and requies only a few lines of code:
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS 15 // Chip select control pin
#define TFT_DC 2 // Data Command control pin
#define TFT_RST 12
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
Code language: PHP (php)
next, in the setup()
method, the code initializes the display:
tft.initR(INITR_BLACKTAB);
tft.setRotation(1);
tft.fillScreen(ST77XX_GREEN);
Code language: C++ (cpp)
How to display the picture on the TFT
This is the most interesting part because here we will show the picture taken by the ESP32-CAM on the TFT display. To do it, we will use the TJpg_Decoder library because it simplifies our work. First of all, we use a low-resolution such as 120×160 so that the picture fits in the TFT.
The code below is derived from the examples provided with the library. In the setup() method, the code initializes the library:
TJpgDec.setJpgScale(1);
// The decoder must be given the exact name of the rendering function above
TJpgDec.setCallback(tft_output);
Code language: PHP (php)
defining the scale and the callback method used to render the picture:
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
// Stop further decoding as image is running off bottom of screen
if ( y >= tft.height() ) return 0;
tft.drawRGBBitmap(x, y, bitmap, w, h);
// Return 1 to decode next block
return 1;
}
Code language: C++ (cpp)
Finally, when we take the picture, the code runs the rendering process:
uint16_t w = 0, h = 0;
TJpgDec.getJpgSize(&w, &h, fb->buf, fb->len);
Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h);
// Draw the image, top left at 0,0
TJpgDec.drawJpg(0, 0, fb->buf, fb->len);
Code language: PHP (php)
remember that fb->buf
contains the picture acquired while fb->len
is the array length.
More useful resources:
How to monitor Pulse Heart rate with ESP32
How to measure CO2 with ESP32
Handling the button to take the picture
The last step is the easiest where we will handle the button:
void loop() {
while (true) {
int state = digitalRead(PIN_BTN);
if (state == HIGH) {
Serial.println("Button pressed");
take_picture();
}
delay(200);
}
}
Code language: C++ (cpp)
Testing ESP32-CAM with TFT display
Now it is time to test the ESP32-CAM project. Let us capture a picture. The result is shown below:

Wrapping up..
At the end of this tutorial, you have learned how to use ESP32-CAM with TFT display. In this project we have integrated ESP32-CAM with ST7735 to show the image captured. We have build a simple camera machine using ESP32-CAM.
Hi,
Thanks for the nice project.
I made a test followed your steps, with a AI Thinker 0.96 inch lcd, nothing shown on it, would you please help on what can be the reasons?
Thanks
Adam
Have you tried to check if the connections are OK? Are you using an AI Thinker with a built-in display?
Thanks for reply.
I used same module as you shown here ESP32CAM. and TFT display of ST7735.
I just wonder if it is possible for ESP32CAM to set SPI?
How to make high resolutuon image and can you give me link for other driver based tft touch display
Hallo,
I includes all the libarys and tried to compile the code, but it says “…Documents\Arduino\libraries\TJpg_Decoder-master\src/TJpg_Decoder.h:23:26: fatal error: LittleFS.h: No such file or directory
compilation terminated.
exit status 1
…” I also downloaded the LittleFS.h Libary for esp 32 because some websides say not all LittleFS libarys support esp.
I also tried to ignore TJpg Decoder, because i dont need to make fotos. Now, i have this problem: “Cam_to_Display:9:25: fatal error: camera_pins.h: No such file or directory
compilation terminated.
exit status 1
camera_pins.h: No such file or directory
“.
What can I do? I just want to bring live video footage from the cam to the display. I dont need fotos or such.
I keep getting the error littleFS.h no such file or directory do you have any idea what i have done wrong? Thanks