Skip to Content

Control ESP32-CAM Flash LED

Control ESP32-CAM Flash LED

This short tutorial shows you how to turn the ESP32-CAM Flash LED on or off, with and without deep-sleep. You will also learn how to control the brightness of the LED and what to watch out for, when using the LED and the SD Card Interface together.

Required Parts

You will need an ESP32-CAM to try out the code examples. You can get a ESP32-CAM with a USB-TTL Shield for programming or an FTDI USB-TTL Adapter. I recommend the FTDI USB-TTL Adapter, since it is more convenient for programming, but I listed both options below.

If you want to use the SD Card reader you will need an SD card that is not larger than 16 GB. Though, you will not need it for this tutorial.

ESP32-CAM with USB-TTL Shield

FTDI USB-TTL Adapter

MicroSD Card 16GB

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Blink Flash LED

If you don’t use the SD card or the deep-sleep mode of the ESP32-CAM, controlling the flash LED is simple. The flash LED is connected to GPIO 4 and the usual Blink code works just fine.

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

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

If you select the AI Thinker ESP32-CAM as board, the constant GPIO_NUM_4 for GPIO 4 is defined.

Select AI Thinker ESP32-CAM  as board
Select AI Thinker ESP32-CAM as board

In the setup function we therefore can use GPIO_NUM_4 to set GPIO 4 to output mode. In the loop function we have the usual Blink code that switches the LED on for one second and off for another second.

If you don’t know how to download code to the ESP32-CAM have a look at the Programming the ESP32-CAM tutorial.

Control brightness of Flash LED

GPIO 4 also supports PWM (Pulse Width Modulation), which means you can control the brightness of the flash LED. The following example increases the brightness b from 0 (off) to the maximum brightness (255) in a loop:

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

void loop() {
  for (int b = 0; b < 256; b++) {
    analogWrite(GPIO_NUM_4, b);
    delay(10);
  }
}

Blink Flash LED with deep-sleep

Things get tricky when you want to flash the LED in combination with deep-sleep. For instance, you want to put the ESP32-CAM to sleep, wake it up when an object moves by, switch on the flash LED, take a picture, switch of the LED and go back to sleep.

The problem here that the output state of GPIO pins is normally lost when the ESP32 enters deep-sleep. The GPIO pins are just floating, without a defined value. You can avoid this by calling the rtc_gpio_hold_en(pin) for a specific pin or the rtc_gpio_force_hold_en_all() function to freeze all pins to their current state.

However, when the ESP32 wakes up from deep-sleep, you need to disable this holding of pins, otherwise you can’t set the state of pins. To disable the holding you can call the functions  rtc_gpio_hold_dis(pin) or rtc_gpio_force_hold_dis_all().

The following code examples shows how to use these functions to turn off the LED for one second, while the ESP32 is awake, and then turn on the LED, while the ESP32 sleeps for a second:

#include "driver/rtc_io.h"

void setup() {
  rtc_gpio_hold_dis(GPIO_NUM_4);
  pinMode(GPIO_NUM_4, OUTPUT);

  digitalWrite(GPIO_NUM_4, LOW);
  delay(1000);
  digitalWrite(GPIO_NUM_4, HIGH);

  rtc_gpio_hold_en(GPIO_NUM_4);
  esp_sleep_enable_timer_wakeup(1 * 1000 * 1000);
  esp_deep_sleep_start();
}

void loop() {}

Let’s discuss this in a bit more detail.

First, we import the driver/rtc_io.h file, which is needed for the rtc_gpio_hold_xxx functions.

In the setup function, we start by calling rtc_gpio_hold_dis(GPIO_NUM_4). This disables any hold we have on GPIO pin 4. Without that we would not be able to change the state of pin 4 later.

In the next line we call pinMode(GPIO_NUM_4, OUTPUT) to switch GPIO pin 4 to output mode. And then we can set pin 4 to LOW (switching of the LED) by calling digitalWrite(GPIO_NUM_4, LOW).

After a delay of one second we set pin 4 to HIGH and then it gets interesting. We want to enter deep-sleep but would loose the state of pin 4. We therefore need to call rtc_gpio_hold_en(GPIO_NUM_4) to hold the current HIGH state of pin 4.

Finally we set the deep sleep timer to one second (esp_sleep_enable_timer_wakeup) and enter deep-sleep via esp_deep_sleep_start().

When the ESP32 wakes up after a second it starts at the beginning of the setup function again. The loop function is never called.

Flash LED and SD Card Interface

Controlling the flash LED is especially tricky when you want to use the SD Card as well. This is, because the HS2_DATA1 data line of the SD Card Interface is shared by the flash LED. The following diagram shows the control circuit for the flash LED.

ESP32-CAM LED Flash wired to HS2_DATA1
ESP32-CAM LED Flash wired to HS2_DATA1 (source)

You can see that the power to LED_FLASH is switched via transistor Q1, which itself is controlled by a signal line labelled HS2_DATA1. If you look now at the wiring diagram for the SD Card Socket you will also see the HS2_DATA1 line (last wire), which is used to transfer data to the SD Card:

ESP32-CAM wiring of SD Card Socket
ESP32-CAM wiring of SD Card Socket (source)

This is the reason why the LED of the ESP32-CAM usually flashes shortly when you write to the SD Card.

Since the LED and SD Card both use HS2_DATA1, you have to make sure that you don’t hold GPIO 4 or do anything with the LED/GPIO 4, while writing to or reading from the SD Card.

The following code example demonstrates how to turn on the LED, take a picture, save it to the SD Card, turn of the LED and then sleep for 5 seconds until the next iteration.

#include "FS.h"
#include "SD_MMC.h"
#include "driver/rtc_io.h"
#include "esp32cam.h"

const auto RES = esp32cam::Resolution::find(800, 600);
RTC_DATA_ATTR uint16_t counter = 0;

void takeAndSavePic() {
  static char path[64];
  auto frame = esp32cam::capture();
  if (frame) {
    sprintf(path, "/img%d.jpg", counter++);
    File file = SD_MMC.open(path, FILE_WRITE);
    frame->writeTo(file);
    file.close();
    Serial.printf("Wrote: %s\n", path);
    delay(10);
  }
}

void initCamera() {
  using namespace esp32cam;
  Config cfg;
  cfg.setPins(pins::AiThinker);
  cfg.setResolution(RES);
  cfg.setJpeg(80);
  Camera.begin(cfg);
}

void setup() {
  Serial.begin(115200);
  rtc_gpio_hold_dis(GPIO_NUM_4);
  
  SD_MMC.begin();
  initCamera();

  pinMode(GPIO_NUM_4, OUTPUT);
  digitalWrite(GPIO_NUM_4, HIGH);
  takeAndSavePic();
  digitalWrite(GPIO_NUM_4, LOW);

  rtc_gpio_hold_en(GPIO_NUM_4);
  esp_sleep_enable_timer_wakeup(5 * 1000 * 1000);
  esp_deep_sleep_start();
}

void loop() { }

For this code you will need the esp32cam library, which makes the handling of the camera simpler. You can install it via the Library Manager in the Arduino IDE. Just search for “esp32cam”:

esp32cam library installed via Library Manager
esp32cam library installed via Library Manager

I will not go into the details how the camera code works but will focus on the interplay between taking a picture, saving it to the SD Card, controlling the flash LED and using deep-sleep. This all happens in the the setup function.

As you can see, the first thing is to call rtc_gpio_hold_dis(GPIO_NUM_4) to disable any hold on GPIO 4. Otherwise we can’t control the flash or use the SD Card.

Next we initialize the SD Card interface via SD_MMC.begin() and also initialize the camera via initCamera().

Then we switch on the flash LED by calling digitalWrite(GPIO_NUM_4, HIGH), take a picture, save it to the SD Card and then switch off the LED again.

Before we can go to deep-sleep, you have to call rtc_gpio_hold_en(GPIO_NUM_4) to ensure that GPIO 4 maintains its status (LOW) during deep-sleep and the flash LED remains off.

After that we set the timer for deep-sleep to 5 seconds and then start the deep-sleep mode. The ESP32 will automatically wake up after 5 seconds and the cycle repeats.

Switch of Flash when writing to SD Card

As mentioned before the flash LED and the SD Card share the same signal line labelled HS2_DATA1, and therefore the LED flashes briefly when you write to the SD Card. You can avoid this by enabling the 1-bit mode for the SD Card interface:

 SD_MMC.begin("/sdcard", true);

The second argument mode1bit==true, sets the 1-bit mode. In this mode the HS2_DATA1 line (GPIO 4) is not used and the LED will not flash when writing to the SD Card. Wile the writing speed will be slower, you can now freely control GPIO 4, since it is only used by the LED then.

You can try this with the following test code. It switches of the LED an writes a file 10 times:

#include "FS.h"
#include "SD_MMC.h"

void setup() {
  Serial.begin(115200);

  pinMode(GPIO_NUM_4, OUTPUT);
  digitalWrite(GPIO_NUM_4, LOW);  

  //SD_MMC.begin();  // LED will switch on
  SD_MMC.begin("/sdcard", true);  // LED remains off

  for (int i = 0; i < 10; i++) {
    delay(1000);
    File file = SD_MMC.open("/test.txt", FILE_WRITE);
    file.println("TEST");
    file.close();
    Serial.println("File written");
  }
}

void loop() { }

With SD_MMC.begin(), the LED will switch on (despite being set to be off) as soon as the code starts to write the files. With SD_MMC.begin("/sdcard", true) on the other hand, the LED is off and stays off.

Conclusions

In this tutorial you learned how to control the flash LED of the ESP32-CAM in various scenarios, most importantly in combination with deep-sleep and SD Card support.

It is worth to mentioning that you should avoid switching on the flash LED for extended periods. The circuit diagram reveals that there is no current limiting resistor for the LED. Which means it can easily overheat and burn out.

If you need more fundamental information about the ESP32-CAM have a look at the Programming the ESP32-CAM tutorial. If you want to apply what you learned here to build a motion-activated camera, see the Motion Activated ESP32-CAM tutorial. And finally, if you want to use the ESP32-CAM for object detection, the Object Detection with ESP32-CAM and YOLO will be useful.

If you have any questions, feel free to leave them in the comment section.

Happy Tinkering ; )