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.
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.
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:
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”:
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 ; )
Stefan is a professional software developer and researcher. He has worked in robotics, bioinformatics, image/audio processing and education at Siemens, IBM and Google. He specializes in AI and machine learning and has a keen interest in DIY projects involving Arduino and 3D printing.