TTGO T-Journal ESP32 Camera: Built-in Programmer, OLED, Antenna and Project Examples

This is a getting started guide for the TTGO T-Journal ESP32 Camera Development Board. The TTGO T-Journal features an OV2640 camera, an OLED display, several GPIOs to connect peripherals and a built-in programmer, which makes it easy to upload code. We’ll take a quick look at the camera dev board and learn how to program it using Arduino IDE.

TTGO T-Journal ESP32 Camera: Built-in Programmer, OLED, Antenna and Project Examples

Where to Buy?

You can go to the TTGO T-Journal page on Maker Advisor to compare the board on different stores.

TTGO T-Journal ESP32 Camera + OLED +Antenna + Built-in Programmer

Introducing the TTGO T-Journal ESP32 Camera

The TTGO T-Journal is a $12-$15 ESP32 Camera Development Board with an OV2640 camera, an antenna, an I2C SSD1306 0.91 inch OLED display, some exposed GPIOs, and a micro-USB interface that makes it easy and quick to upload code to the board.

For a complete overview of this board you can watch the following video or read this article: TTGO T-Journal ESP32 Camera Dev Board Review.

TTGO T-Journal ESP32 Features

Here’s a summary of the TTGO T-Journal features:

  • Chipset ESPRESSIF-ESP32-PCIO-D4 240MHz Xtensa® single-/dual-core 32-bit LX6 microprocessor
  • FLASH QSPI flash/SRAM, up to 4 x 16 MBSRAM 520 kB SRAM
  • Reset button and button on GPIO 32
  • 0.91 inch SSD1306 OLED display
  • Power indicator red LED
  • USB to TTL CP2104 (you can upload code via USB cable);
  • Camera OV2640  2 Megapixel
  • Steering engine analog servo (comes with two sets of pins ideal to connect servos)
  • Working voltage: 2.3V-3.6V
  • Working current: about 160mA
  • Size: 64.57mm x 23.98mm

Power supply specifications: 

  • Power Supply USB 5V/1A
  • Charging current 1A
  • Battery 3.7V lithium battery

Read our in-depth review: TTGO T-Journal ESP32 Camera Development Board

TTGO T-Journal ESP32 Board Pinout

Having the right pinout for your camera board is very important. If you don’t assign the right camera pins in your code, the camera will not work. The following image shows the TTGO T-Journal ESP32 board pinout.

TTGO T-Journal ESP32 Camera Connections

TTGO T-Journal ESP32 OV2640 Camera

Here’s a table with the connections between the ESP32 and the camera:

OV2640 CameraESP32
D2GPIO 17
D3GPIO 35
D4GPIO 34
D5GPIO 5
D6GPIO 39
D7GPIO 18
D8GPIO 36
D9GPIO 19
SIOCGPIO 23
SIODGPIO 25
XCLKGPIO 27
VSYNCGPIO 22
HREFGPIO 26
PCLKGPIO 21
RSTGPIO 15
PWDNGPIO 0

So, the pin assignment in your Arduino sketch should be as follows:

#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     25
#define SIOC_GPIO_NUM     23
#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM       5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       17
#define VSYNC_GPIO_NUM    22
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

Because this board uses the same camera used in the ESP32-CAM board, the examples for the ESP32-CAM (that don’t use microSD card) should also work with the TTGO T-Journal by changing the pin definition. We’ll show you a couple of examples in a moment.

TTGO T-Journal ESP32 Board OLED Connections

TTGO T-Journal ESP32 Board OLED Connections Pins SCL SDA I2C

This board comes with an I2C SSD1306 0.91 inch OLED display. To interact with the display you can use the Adafruit SSD1306, the oled-ssd1306 or other compatible libraries. We usually use the Adafruit SSD1306 along with the Adafruit_GFX to interact with OLED displays.

The OLED communicates with the ESP32 using the following pins:

OLEDESP32
SDAGPIO 14
SCLGPIO 13

TTGO T-Journal ESP32 Board Control OLED Display

In this section, well show you quick tips on how to control the OLED display of the TTGO T-Journal ESP32 board.

Installing Libraries

To control the OLED display, we’ll use the Adafruit SSD1306 and Adafruit GFX libraries. These libraries can be installed through the Arduino IDE Library Manager.

In your Arduino IDE, go to Sketch > Include Library > Manage Libraries. Then, search for the library name and install it.

OLED I2C Pins and Display Size

Controlling this OLED display is similar to control a regular 0.96 OLED display connected to an ESP32. The only difference is the way you initialize the display.

You need to take into account the I2C pins used by this display (because it doesn’t use the default I2C pins), and the size of the display.

  • I2C pins:
    • SDA (GPIO 14)
    • SCL (GPIO 13)
  • Display size:
    • Width: 128 px
    • Height: 32 px

Arduino Sketch

To control the OLED display, first, you need to import the required libraries:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Define the OLED size:

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32

Define the I2C pins:

#define I2C_SDA 14
#define I2C_SCL 13

Next create an Adafruit_SSD1306 object called display as follows:

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

In the setup(), you need to initialize an I2C communication on the I2C pins you’ve defined earlier as follows:

Wire.begin(I2C_SDA, I2C_SCL);

Then, initialize the OLED display as follows:

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {
  Serial.println(F("SSD1306 allocation failed"));
  for(;;);
}

After properly initializing the display, you can use the usual functions to write text and display shapes on the OLED. Read our OLED tutorial with the ESP32 to learn more on how to interact with the OLED display.

For testing purposes, you can upload the following code to your board. It simply displays “Hello World”.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/ttgo-t-journal-esp32-camera-getting-started/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define I2C_SDA 14
#define I2C_SCL 13

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  
  Wire.begin(I2C_SDA, I2C_SCL);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.print("Hello World!");;
  display.display();
}

void loop() {
  // put your main code here, to run repeatedly:
}

View raw code

TTGO T-Journal ESP32 Board Control OLED Display Sample Message Hello World

TTGO T-Journal ESP32 Camera Projects

We’ve modified some of our existing ESP32-CAM projects to be compatible with the TTGO T-Journal.

Video Streaming Web Server

The following code creates a video streaming web server on the camera IP address. So, you can create an IP CAM that can be integrated in Home Automation platforms like Home Assistant or Node-RED.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/ttgo-t-journal-esp32-camera-getting-started/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h"  //disable brownout problems
#include "esp_http_server.h"

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define I2C_SDA 14
#define I2C_SCL 13

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

//Replace with your network credentials
const char* ssid = "MEO-D32A40";
const char* password = "384e6d3cec";

#define PART_BOUNDARY "123456789000000000000987654321"

// OV2640 camera module pins (CAMERA_MODEL_TTGO-T-Journal)
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     25
#define SIOC_GPIO_NUM     23
#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM       5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       17
#define VSYNC_GPIO_NUM    22
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

httpd_handle_t stream_httpd = NULL;

static esp_err_t stream_handler(httpd_req_t *req){
  camera_fb_t * fb = NULL;
  esp_err_t res = ESP_OK;
  size_t _jpg_buf_len = 0;
  uint8_t * _jpg_buf = NULL;
  char * part_buf[64];

  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  if(res != ESP_OK){
    return res;
  }

  while(true){
    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      res = ESP_FAIL;
    } else {
      if(fb->width > 400){
        if(fb->format != PIXFORMAT_JPEG){
          bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
          esp_camera_fb_return(fb);
          fb = NULL;
          if(!jpeg_converted){
            Serial.println("JPEG compression failed");
            res = ESP_FAIL;
          }
        } else {
          _jpg_buf_len = fb->len;
          _jpg_buf = fb->buf;
        }
      }
    }
    if(res == ESP_OK){
      size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
      res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
    }
    if(res == ESP_OK){
      res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
    }
    if(res == ESP_OK){
      res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    }
    if(fb){
      esp_camera_fb_return(fb);
      fb = NULL;
      _jpg_buf = NULL;
    } else if(_jpg_buf){
      free(_jpg_buf);
      _jpg_buf = NULL;
    }
    if(res != ESP_OK){
      break;
    }
    //Serial.printf("MJPG: %uB\n",(uint32_t)(_jpg_buf_len));
  }
  return res;
}

void startCameraServer(){
  httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  config.server_port = 80;

  httpd_uri_t index_uri = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = stream_handler,
    .user_ctx  = NULL
  };
  
  //Serial.printf("Starting web server on port: '%d'\n", config.server_port);
  if (httpd_start(&stream_httpd, &config) == ESP_OK) {
    httpd_register_uri_handler(stream_httpd, &index_uri);
  }
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);
  Serial.setDebugOutput(false);
  
  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(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }
  
  // 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;
  }
  // Wi-Fi connection
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  Serial.print("Camera Stream Ready! Go to: http://");
  Serial.print(WiFi.localIP());

  // Init OLED
  Wire.begin(I2C_SDA, I2C_SCL);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(5, 5);
  display.print(WiFi.localIP());;
  display.display();
  
  // Start streaming web server
  startCameraServer();
}

void loop() {
  delay(1);
}

View raw code

ESP32-CAM Video Streaming Web Server Example

Learn more about this project: ESP32-CAM Video Streaming Web Server

Take Photo and Display in Web Server

The following code creates a web server that you can access to take and display photos. The web server IP address is displayed on the OLED.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/ttgo-t-journal-esp32-camera-getting-started/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include "WiFi.h"
#include "esp_camera.h"
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include <ESPAsyncWebServer.h>
#include <StringArray.h>
#include <SPIFFS.h>
#include <FS.h>

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define I2C_SDA 14
#define I2C_SCL 13

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Replace with your network credentials
const char* ssid = "MEO-D32A40";
const char* password = "384e6d3cec";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

boolean takeNewPhoto = false;

// Photo File Name to save in SPIFFS
#define FILE_PHOTO "/photo.jpg"

// OV2640 camera module pins (CAMERA_MODEL_TTGO-T-Journal)
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     25
#define SIOC_GPIO_NUM     23
#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM       5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       17
#define VSYNC_GPIO_NUM    22
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    body { text-align:center; }
    .vert { margin-bottom: 10%; }
    .hori{ margin-bottom: 0%; }
  </style>
</head>
<body>
  <div id="container">
    <h2>ESP32-CAM Last Photo</h2>
    <p>It might take more than 5 seconds to capture a photo.</p>
    <p>
      <button onclick="rotatePhoto();">ROTATE</button>
      <button onclick="capturePhoto()">CAPTURE PHOTO</button>
      <button onclick="location.reload();">REFRESH PAGE</button>
    </p>
  </div>
  <div><img src="saved-photo" id="photo" width="70%"></div>
</body>
<script>
  var deg = 0;
  function capturePhoto() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', "/capture", true);
    xhr.send();
  }
  function rotatePhoto() {
    var img = document.getElementById("photo");
    deg += 90;
    if(isOdd(deg/90)){ document.getElementById("container").className = "vert"; }
    else{ document.getElementById("container").className = "hori"; }
    img.style.transform = "rotate(" + deg + "deg)";
  }
  function isOdd(n) { return Math.abs(n % 2) == 1; }
</script>
</html>)rawliteral";

void setup() {
  // Serial port for debugging purposes
  Serial.begin(115200);

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  if (!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    ESP.restart();
  }
  else {
    delay(500);
    Serial.println("SPIFFS mounted successfully");
  }

  // Print ESP32 Local IP Address
  Serial.print("IP Address: http://");
  Serial.println(WiFi.localIP());

  // Init OLED
  Wire.begin(I2C_SDA, I2C_SCL);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(5, 5);
  display.print(WiFi.localIP());;
  display.display();


  // Turn-off the 'brownout detector'
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);

  // OV2640 camera module
  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 (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }
  // Camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    ESP.restart();
  }

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/html", index_html);
  });

  server.on("/capture", HTTP_GET, [](AsyncWebServerRequest * request) {
    takeNewPhoto = true;
    request->send_P(200, "text/plain", "Taking Photo");
  });

  server.on("/saved-photo", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, FILE_PHOTO, "image/jpg", false);
  });

  // Start server
  server.begin();

}

void loop() {
  if (takeNewPhoto) {
    capturePhotoSaveSpiffs();
    takeNewPhoto = false;
  }
  delay(1);
}

// Check if photo capture was successful
bool checkPhoto( fs::FS &fs ) {
  File f_pic = fs.open( FILE_PHOTO );
  unsigned int pic_sz = f_pic.size();
  return ( pic_sz > 100 );
}

// Capture Photo and Save it to SPIFFS
void capturePhotoSaveSpiffs( void ) {
  camera_fb_t * fb = NULL; // pointer
  bool ok = 0; // Boolean indicating if the picture has been taken correctly

  do {
    // Take a photo with the camera
    Serial.println("Taking a photo...");

    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      return;
    }

    // Photo file name
    Serial.printf("Picture file name: %s\n", FILE_PHOTO);
    File file = SPIFFS.open(FILE_PHOTO, FILE_WRITE);

    // Insert the data in the photo file
    if (!file) {
      Serial.println("Failed to open file in writing mode");
    }
    else {
      file.write(fb->buf, fb->len); // payload (image), payload length
      Serial.print("The picture has been saved in ");
      Serial.print(FILE_PHOTO);
      Serial.print(" - Size: ");
      Serial.print(file.size());
      Serial.println(" bytes");
    }
    // Close the file
    file.close();
    esp_camera_fb_return(fb);

    // check if file has been correctly saved in SPIFFS
    ok = checkPhoto(SPIFFS);
  } while ( !ok );
}

View raw code

ESP32-CAM Take Photo and Display in Web Server

Learn more about this project: ESP32-CAM Take Photo and Display in Web Server

CameraWebServer Example

You can also run the default CameraWebServer example that comes with the Arduino IDE. In your Arduino IDE, go to File Examples ESP32 Camera and open the CameraWebServer example.

You can click the next link to download the .zip with the final code:

Otherwise, you need to add the TTGO T-Journal pinout to the camera_pins.h tab.

CameraWebServer Example ESP32-CAM for Arduino IDE

Copy the following to the camera_pins.h file.

#if defined(CAMERA_MODEL_T_JOURNAL)
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     25
#define SIOC_GPIO_NUM     23

#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM       5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       17
#define VSYNC_GPIO_NUM    22
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

Then, in the CameraWebServer tab, comment all the existing camera models, and add your camera, as follows:

// Select camera model
#define CAMERA_MODEL_T_JOURNAL
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
//#define CAMERA_MODEL_AI_THINKER

Because this camera doesn’t have PSRAM, the face recognition and detection features of this project don’t work with this camera. All the other functionalities work well.

CameraWebServer Example ESP32-CAM for Arduino IDE Web Server

Upload Code to the TTGO T-Journal ESP32 Camera

To upload code, you just need to connect the board to your computer, then in the Arduino IDE, go to Tools > Port and select the COM port it is connected to.

Then, you also need to select a Board model. The TTGO T-Journal is not available on the ESP32 models. So, select the following settings:

  • Board: “ESP32 Wrover Module”
  • Partition Scheme: “Huge APP (3MB No OTA)”
Board ESP32 Wrover Module and Partition Scheme Huge APP (3MB No OTA)

Then, simply click the Arduino IDE upload button and it is done!

Arduino IDE Compile and upload sketch button

Wrapping Up

This tutorial was a quick getting started guide for the TTGO T-Journal ESP32 Camera Development board. You’ve learned how to control the OLED display and how to adapt existing ESP32 camera projects to your board.

We hope you’ve found this tutorial useful. To learn more about this board, you can read our complete overview on Maker Advisor as well as our ESP32-CAM development boards comparison post:

You may also be interested in other ESP32 development boards:

Thanks for reading.


Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »

Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our weekly newsletter!

14 thoughts on “TTGO T-Journal ESP32 Camera: Built-in Programmer, OLED, Antenna and Project Examples”

  1. HI,
    Thanks a lot for this project.
    Very interesting. I’ll compare it with the AiThinker one.

    But I’ve a (stupid perhaps) question.
    What does “TTGO” mean?
    As exemple: TTGo Lora … and Lora …
    Thanks again.

    Reply
  2. Great post!, something I’ve been waiting for for some time since I got tired of running the sample code 🙂

    Couple of thoughts:
    1. Need not be an either/or since both boards are cheap enough. Thinking of using the ESP32-CAM for unlocking a door through face recognition, which the T-Journal doesn’t have. The T-Journal, OTOH, in conjunction with a RCWL-0516 for motion detection, can take a photo of potential intruders and send it through sftp to a Beaglebone Black.
    2. Can’t you define the T-Journal pins in a .h which you would then #include in your sketch?
    3. One more diff between the two boards is the obvious size difference, although I’m guessing you didn’t mention that since it might not matter in your own projects. Besides, both boards are small anyway.
    4. There are other TTGO boards, which is why I made sure to explicitly cite the T-Journal

    Reply
  3. Hello again, Rui and Sarah. Have you tried accessing GPIO2 and GPIO4 in a sketch? I tried both “#define GPIO2 2” and “#define GPIO2 4” — even if I didn’t think the latter would work. Couldn’t get as simple a thing as blinking an LED.

    Or are there .h files specific to T-Journal or ESP32 that #define the GPIOs?

    Thanks in advance for any guidance.

    Reply
    • Hi Daniel.
      In theory, you should be able to blink an LED with the usual blink an LED sketch.
      Can you show me your code to blink an LED?
      Regards,
      Sara

      Reply
      • Hi Sara, thanks for getting back to me.

        First, my code was faulty, set pinMode to INPUT instead of OUTPUT .

        Then, it was my wiring through my breadboard. Connected the LED+ to IO2, LED- to GND directly, and my LED’s happily blinking away 🙂

        As an aside, I may try using IO4, which will probably mean #define outputPin 4 instead of 2.

        Which brings me to another question: does the TTGO family have header files somewhere — or maybe a library or something — where the pin names are defined, much like LED_BUILTIN is defined for the Arduino family?

        Code’s embarrassingly simple, but you asked for it:

        #define outputPin 2

        void setup() {
        pinMode(outputPin, OUTPUT);
        }

        void loop() {
        digitalWrite(outputPin, HIGH);
        delay (1000);
        digitalWrite(outputPin, LOW);
        delay (1000);
        }

        Warmest regards, and thanks again

        Reply
        • Hehe, pseudo-HTML tags disappeared, trying again, just because

          First, my code was faulty, <face-palm>set pinMode to INPUT instead of OUTPUT </face-palm>.

          On another, slightly related topic, I check the button to “Notify me of follow-up comments by email.” but don’t get anything. Not that it really matters, since I’d check manually anyways, just wanted to let you know.

          Regards

          Reply
        • Hi Daniel.
          I’m glad it is working now.
          I don’t know if there are any header files.
          But you can always define whenever pin you want and give it the name you want 😀
          I think you get notification by email when I answer your question (at least it should work like that).
          Anyway, thanks for telling me that.
          Regards,
          Sara

          Reply
  4. I am great fan of your fine and many well documented examples how to use ESP32.
    I have purchased a number of these including the ESP32-CAm all from Banggood.
    However I cannot duplicate Your efforts because I never can make Arduino -IDe nor the PlatformIO to recognize the boards – ie. no COM port is visible.
    It seem sit is necessary to by a FTDI board for a serial port setup and connect this to the ESP32 boards – but You never mentions this????

    Reply
  5. I’ve followed these excellent instructions to the letter but I cannot get the sketch into the TTGO module. I’ve installed the CP210x drivers and can see a port (15) connected to the computer but it always fails with error message:

    serial.serialutil.SerialException: could not open port ‘COM15’: WindowsError(5, ‘Access is denied.’)
    Failed to execute script esptool
    the selected serial port Failed to execute script esptool
    does not exist or your board is not connected

    Any suggestions?
    Thank you.

    Reply
    • Hi Michael.
      Check that you have selected the COM15 in Tools > Port.
      Also, check that you don’t have any serial monitor window open.
      Regards,
      Sara

      Reply

Leave a Comment

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.