Guide no. 65
FireBeetle 2 ESP32-S3 and OV2640: the board takes a shot when the browser asks, one photo per second. PSRAM, settings and the manufacturer's pins.
By Ada Intelisano · informaticait.it technical team
- Camera cable in the CAM connector, pin 1 toward the white dot.
- Memory: 16 MB and octal PSRAM, a partition with 3 MB for the sketch.
- The page asks for /photo every second; the board answers with a JPEG.
- For real video there is Espressif's CameraWebServer example.
A small Wi-Fi camera: the board takes a photo every time the browser asks for one, and the page asks for one per second. To keep an eye on your front door, a bird feeder, a 3D printer at work. We use the FireBeetle 2 ESP32-S3 sold with its own camera.
1The board
- ESP32-S3 module with 16 MB of memory for sketches and 8 MB of PSRAM, the extra memory that images need.
- 2-megapixel OV2640 camera (up to 1600×1200).
- The camera's flat cable goes into the CAM connector, below the USB socket, with pin 1 toward the white dot.
2The settings
This board has to be described properly to the compiler. In PlatformIO the file below does it: it says the memories are 16 MB and “octal” PSRAM, and asks for a memory layout with room for large sketches.
; "Next steps" series - camera in the browser with the FireBeetle 2 ESP32-S3 (DFR0975, N16R8, OV2640) ; The board has 16 MB of flash and 8 MB of "octal" PSRAM: the board_... lines replace the default values (4 MB, no PSRAM). [env:esp32s3] platform = espressif32 board = dfrobot_firebeetle2_esp32s3 framework = arduino monitor_speed = 115200 board_build.arduino.memory_type = qio_opi board_upload.flash_size = 16MB board_build.partitions = default_16MB.csv build_flags = -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=1
In Arduino IDE choose the board “DFRobot Firebeetle 2 ESP32-S3” and, in the Tools menu: USB CDC On Boot: Enabled, PSRAM: OPI PSRAM, Flash Size: 16MB, Partition Scheme: 16M Flash (3MB APP/9.9MB FATFS).
3The sketch
Write your network name and password. The camera pin numbers are the ones DFRobot and Espressif give for this board: do not touch them.
// Camera in the browser: the FireBeetle 2 ESP32-S3 takes a photo when the page asks for one. // The page asks for one per second: almost a video. The LED on the board lights up with every shot. #include <WiFi.h> #include <WebServer.h> #include "esp_camera.h" #include "img_converters.h" const char* NETWORK = "your-network-name"; const char* PASSWORD = "your-network-password"; const int LED = 21; // the LED on the board (D13) WebServer server(80); bool directJpeg = true; // does the sensor already send JPEG? (see the guide) camera_config_t cameraConfig(pixformat_t format) { camera_config_t c = {}; // the camera connections on the FireBeetle 2 ESP32-S3 (DFRobot wiki and Espressif example) c.pin_pwdn = -1; c.pin_reset = -1; c.pin_xclk = 45; c.pin_sccb_sda = 1; c.pin_sccb_scl = 2; c.pin_d7 = 48; c.pin_d6 = 46; c.pin_d5 = 8; c.pin_d4 = 7; c.pin_d3 = 4; c.pin_d2 = 41; c.pin_d1 = 40; c.pin_d0 = 39; c.pin_vsync = 6; c.pin_href = 42; c.pin_pclk = 5; c.xclk_freq_hz = 20000000; c.ledc_timer = LEDC_TIMER_0; c.ledc_channel = LEDC_CHANNEL_0; c.pixel_format = format; c.frame_size = FRAMESIZE_VGA; // 640 x 480: a good compromise c.jpeg_quality = 12; // from 0 to 63: lower = nicer and heavier c.fb_count = 2; // two images in memory: smoother c.fb_location = CAMERA_FB_IN_PSRAM; // the images live in the PSRAM c.grab_mode = CAMERA_GRAB_LATEST; // always the latest image, not an old one return c; } void photo() { digitalWrite(LED, HIGH); camera_fb_t* fb = esp_camera_fb_get(); if (!fb) { server.send(500, "text/plain", "Capture failed"); digitalWrite(LED, LOW); return; } if (directJpeg) { server.send_P(200, "image/jpeg", (const char*)fb->buf, fb->len); } else { // uncompressed image: we convert it to JPEG uint8_t* jpg = nullptr; size_t len = 0; frame2jpg(fb, 80, &jpg, &len); server.send_P(200, "image/jpeg", (const char*)jpg, len); free(jpg); } esp_camera_fb_return(fb); // gives the memory back for the next shot digitalWrite(LED, LOW); } void page() { server.send(200, "text/html", "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width, initial-scale=1'><title>Camera</title></head>" "<body style='margin:0;background:#111;text-align:center'><img id='f' src='/photo' style='width:100%;max-width:640px'>" "<script>setInterval(()=>{document.getElementById('f').src='/photo?'+Date.now()},1000)</script></body></html>"); } void setup() { Serial.begin(115200); pinMode(LED, OUTPUT); if (!psramFound()) Serial.println("Warning: PSRAM not active, check the settings"); camera_config_t c = cameraConfig(PIXFORMAT_JPEG); if (esp_camera_init(&c) != ESP_OK) { // some versions of the board want the RGB565 format directJpeg = false; c = cameraConfig(PIXFORMAT_RGB565); c.frame_size = FRAMESIZE_QVGA; if (esp_camera_init(&c) != ESP_OK) { Serial.println("Camera not found: power the board off and on again"); return; } } WiFi.mode(WIFI_STA); WiFi.begin(NETWORK, PASSWORD); while (WiFi.status() != WL_CONNECTED) delay(500); Serial.print("Open http://"); Serial.println(WiFi.localIP()); server.on("/", page); server.on("/photo", photo); server.begin(); } void loop() { server.handleClient(); delay(2); }
jpeg_quality goes from 0 to 63: the lower it is, the nicer and heavier the photo. fb_count = 2 keeps two images ready in the PSRAM and CAMERA_GRAB_LATEST always gives the latest one, not an old one.4Try it
- “Camera not found”: the flat cable is not pushed all the way in or is upside down; DFRobot also recommends powering off and on again.
- “PSRAM not active”: the memory settings are not the ones from step 2.
- The upload does not start: hold down BOOT, press and release RST, then release BOOT, as DFRobot advises.
5Two things to know
- Board versions: DFRobot notes that version 1.0 needs a library to switch on the camera's power supply, and for 1.3 it recommends the RGB565 format. The sketch tries JPEG first and, if that fails, switches to RGB565 by itself and converts the photos.
- Real video: for smooth streaming there is Espressif's CameraWebServer example (File → Examples → ESP32 → Camera), choosing the model
CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3: the video is at:81/stream. - Privacy: the page has no password. Keep it on your home network and do not point the camera where other people are without telling them.
6Challenge yourself
- Add the over-the-air update from guide no. 59: the mounted camera can be updated without taking it down.
- With the board's button (GPIO 47), save the best photo in a variable and show it at
/latest. - Raise the resolution to SVGA (800×600) and see how much it slows down.
- images need PSRAM and a sketch with plenty of room;
- the board answers
/photowith a JPEG, and the page asks for it every second; - camera pins and memory settings come from the manufacturer.
Useful products
Other guides
- Resistor colour code and tolerances
- N-channel and P-channel MOSFETs
- Bipolar transistor (BJT) or MOSFET?
- Relays: how to drive them and how much current they draw
- THT and SMD/SMT components
- XIAO board pinouts
- LEDs: forward voltage and series resistor
- The multimeter: measuring voltage and current
- Wemos D1 mini: first steps
- MOSFET module with Arduino and ESP32
- Relay module with Arduino and ESP32
- 3D printing filaments: PLA, PETG and fibre-filled versions
- Analog and digital: the differences
- ADS1115: 16-bit converter with Arduino and ESP32
- From bits to real values: converting sensor readings
- DS3231 RTC clock with Arduino and ESP32
- Linear or switching regulator: which one to choose
- Step-down, step-up and buck-boost: choosing the right module
- Voltage divider: reading voltages higher than 5 V or 3.3 V
- Pull-up, pull-down and bounce: wiring a button properly
- 3.3 V and 5 V logic levels: getting an ESP32 and an Arduino to talk
- The I²C bus: addresses, pull-ups and the scanner
- Lithium batteries: voltages, charging and protection
- ESP32 power consumption and deep sleep: how long the battery lasts
- Temperature sensors compared
- ESP32: which pins to use and which to avoid
- Getting started with the ESP32 in Arduino IDE 2 and PlatformIO
- SSD1306 OLED display and 16×2 I²C LCD with Arduino and ESP32
- PIR motion sensor and HC-SR04 ultrasonic sensor
- Date and time from the Internet with the ESP32: NTP, Italian time zone and daylight saving time
- MicroSD data logger: saving measurements to CSV
- Solar-powered ESP32: panel, charger and the numbers for Italy
- Web server on the ESP32: control a relay from your phone
- Your first LED: wire it up and make it blink
- The button: let Arduino decide
- The potentiometer: turn a knob and read its value
- Soft light: adjusting the brightness of an LED
- The buzzer: playing notes and melodies
- The traffic light: three LEDs in sequence
- The thermometer: reading the temperature with the TMP36
- The servo motor: moving an arm with Arduino
- The night light: the photoresistor and your first decision
- The relay: switching on a light bulb with Arduino
- The LCD display: making Arduino write
- The electronic dice: your first complete project
- The RGB LED: every color from three lights
- The joystick: two-axis control with a shield
- The LED ring: twelve colors from a single pin
- The DC motor: driving it with a MOSFET
- Soil moisture: the plant that asks for water
- The stepper motor: turn exactly as far as you want
- The parking sensor: faster and faster beeps
- The 7-segment display: big, bright numbers
- Automatic watering: the plant that waters itself
- The keypad: a lock with a secret code
- Networked weather station: values and chart on your phone
- A Telegram bot on the ESP32: your home from your phone
- MQTT with the ESP32: the language of connected devices
- Updating the ESP32 over Wi-Fi (OTA)
- ESP-NOW: two ESP32 boards talking without a router
- WebSocket with the ESP32: the LED that follows the slider
- Readings on a Google sheet, with deep sleep
- WiFiManager: choose the Wi-Fi from your phone
- Bluetooth LE with the ESP32: the phone without a network
- A portable Bluetooth speaker you build yourself
- Bluetooth desktop speakers, 2 × 20 W
- Stereo MP3 player with two buttons
- The shelf that plays music: a Visaton exciter
- How to solder well
- How much does it draw? Current and power with the INA219
- Load-cell scale with the HX711
- CO2 traffic light: when to open the windows
- RFID card door opener
- GPS: track logger on microSD
- LoRa: how far does it go? A range test with two boards
- Battery weather sign with an e-paper display
- Web radio with an ESP32 and an I2S amplifier
- Getting started with the Raspberry Pi Pico 2 in MicroPython
- Your first amplifier: the LM386 and a speaker
- Talking Arduino: the DFR0760 speech synthesis module
- The spectrum of your music on an LED matrix
- Drawing with 64 LEDs: the 8×8 matrix with the MAX7219
- A real voltage: the 12-bit MCP4725 DAC
- The heartbeat on Arduino: an ECG with the AD8232