ESP32Cam - I'm having trouble setting time and saving a photo to an SDcard while using an DS3231 RTC

Ive had success taking a photo and saving it to an SDCard but not when using an i2c connected RTC to take the photo at specific intervals. I havent been able to adjust the time either, it always prints 21h00 when I do:

DateTime now = rtc.now();
  Serial.print("rtc time: "); Serial.print(now.hour(), DEC); Serial.print(" : "); Serial.println(now.minute(), DEC);

If I do not use the ability to save to SD, the code to set the time and set alarms works as expected, as in another project of mine that takes a photo and sends to Telegram:

https://github.com/FBMinis/DS3231-Alarm ... legram-Bot

Is there some incompatibility between i2c and sdcard on the esp32cam?

Here's the code in attachment:

ESP32-CAMsavePhotoToSDcardDS3231.ino (9.4 KB)

Did you try a simple I2C scanner program, without the SD card inserted, to see if the RTC is responding ?

1 Like

Yes, the RTC is working and I can set alarms, I just can't set the present time with the usual function.

Post your code in code tags, please.

1 Like
/*
    http://asciiflow.com/

                 5V
                  +
                  |
                  +-----------+
                 +-+          |
            10K  | |     + +--+S
                 +++     |    |
                  |    G | +  |
     +------------+--------+--+  AO3401 P-CHANNEL MOSFET
     |                   |
     |                   | +
     |                   + +--+D
     |                        |
     |                 +------+------+
     |                 |      5V     |
     |                 |             |
     |        +---+----+3.3V         |
     |        |   |    |             |
  +----+----+  +++ +++   |             |
  |   SQW   |  | | | |10K|             |
  |         |  | | | |   |  ESP32CAM   |
  |  DS3231 |  +++ +++   |             |
  |         |   |   |    |             |
  |     SDA +---+--------+IO14         |
  |         |       |    |             |
  |     SCL +-------+----+IO15         |
  |         |            |             |
  +-----+---+            +----+--------+
      |                     |
      +-----------+---------+
                  |
                  +
               GROUND

  ESP32-Cam captures a photo and saves it to an sdcard at an interval defined by DS3231 alarms.

  Based on: https://RandomNerdTutorials.com/esp32-cam-take-photo-save-microsd-card

  RTC library used:

  https://github.com/adafruit/RTClib
  https://garrysblog.com/2020/07/05/using-the-ds3231-real-time-clock-alarm-with-the-adafruit-rtclib-library/
*/

#include <RTClib.h>
#include <Wire.h>
RTC_DS3231 rtc;
#define I2C_SDA 15
#define I2C_SCL 14
#define DS3231_I2C_ADDRESS 0x68
#define DS3231_CONTROL_REG 0x0E

#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h>            // read and write from flash memory

// define the number of bytes you want to access
#define EEPROM_SIZE 1

// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

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

int pictureNumber = 0;

void enableRTCAlarmsonBackupBattery() {
  // Enable Battery-Backed Square-Wave Enable on the DS3231 RTC module:
  // Bit 6 (Battery-Backed Square-Wave Enable) of DS3231_CONTROL_REG 0x0E, can be set to 1
  // When set to 1, it forces the wake-up alarms to occur when running the RTC from the back up battery alone.
  // [note: This bit is usually disabled (logic 0) when power is FIRST applied]
  // https://github.com/EKMallon/Utilities/blob/master/setTme/setTme.ino
  Wire.beginTransmission(DS3231_I2C_ADDRESS);      // Attention device at RTC address 0x68
  Wire.write(DS3231_CONTROL_REG);                  // move the memory pointer to CONTROL_REGister
  Wire.endTransmission();                          // complete the ‘move memory pointer’ transaction
  Wire.requestFrom(DS3231_I2C_ADDRESS, 1);         // request data from register
  byte resisterData = Wire.read();                 // byte from registerAddress
  bitSet(resisterData, 6);                         // Change bit 6 to a 1 to enable
  Wire.beginTransmission(DS3231_I2C_ADDRESS);      // Attention device at RTC address 0x68
  Wire.write(DS3231_CONTROL_REG);                  // target the CONTROL_REGister
  Wire.write(resisterData);                        // put changed byte back into CONTROL_REG
  Wire.endTransmission();
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  //Serial.println();

  Wire.begin(I2C_SDA, I2C_SCL);

  // initializing the rtc
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC!");
    Serial.flush();
    abort();
  }

  // Only needed if you cut the Vcc pin supplying power to the DS3231 chip to run clock from coincell
  enableRTCAlarmsonBackupBattery();

  if (rtc.lostPower()) {
  //Serial.println("RTC lost power, let's set the time!");
  // When time needs to be set on a new device, or after a power loss, the
  // following line sets the RTC to the date & time this sketch was compiled
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  // When time needs to be re-set on a previously configured device, the
  // following line sets the RTC to the date & time this sketch was compiled
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  //rtc.adjust(DateTime(2021, 10, 11, 16, 25, 0)); // used for troubleshooting, force set time at boot

  //we don't need the 32K Pin, so disable it
  rtc.disable32K();

  // stop oscillating signals at SQW Pin
  // otherwise setAlarm1 will fail
  rtc.writeSqwPinMode(DS3231_OFF);

  // turn off alarm 2 (in case it isn't off already)
  // again, this isn't done at reboot, so a previously set alarm could easily go overlooked
  rtc.disableAlarm(2);

  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; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    //return;
  }

  //Serial.println("Starting SD Card");
  if (!SD_MMC.begin()) {
    Serial.println("SD Card Mount Failed");
    //return;
  }

  uint8_t cardType = SD_MMC.cardType();
  if (cardType == CARD_NONE) {
    Serial.println("No SD Card attached");
    //return;
  }

  // Take Picture with Camera
  camera_fb_t * fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    //return;
  }
  // initialize EEPROM with predefined size
  EEPROM.begin(EEPROM_SIZE);
  pictureNumber = EEPROM.read(0) + 1;

  // Path where new picture will be saved in SD Card
  String path = "/picture" + String(pictureNumber) + ".jpg";

  fs::FS &fs = SD_MMC;
  Serial.printf("Picture file name: %s\n", path.c_str());

  File file = fs.open(path.c_str(), FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file in writing mode");
  }
  else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    Serial.printf("Saved file to path: %s\n", path.c_str());
    EEPROM.write(0, pictureNumber);
    EEPROM.commit();
  }
  file.close();
  esp_camera_fb_return(fb);

  // Set alarm to 10min from present time
  // If present hour is 20, 21, 22h, 23h, 0h, 1h, 2h,3h, 4h or 5h, alarm should happen after 1 hour
  DateTime now = rtc.now();
  Serial.print("rtc time: "); Serial.print(now.hour(), DEC); Serial.print(" : "); Serial.println(now.minute(), DEC);
  bool night_time = false;
  int night_hours[] = {20, 21, 22, 23, 0, 1, 2, 3, 4, 5};
  for (int index = 0; index < 10; index++) {
    if (night_hours[index] == now.hour()) {
      night_time = true;
      break;
    }
  }
  if (night_time) {
    if (!rtc.setAlarm1(
          rtc.now() + TimeSpan(0, 0, 1, 0),
          DS3231_A1_Hour //
        )) {
      Serial.println("Error, alarm wasn't set!");
    } else {
      Serial.println("Alarm will happen in X hours!");
    }
  } else {
    if (!rtc.setAlarm1(
          rtc.now() + TimeSpan(0, 0, 1, 0),
          DS3231_A1_Minute //
        )) {
      Serial.println("Error, alarm wasn't set!");
    } else {
      Serial.println("Alarm will happen in Y minutes!");
    }
  }

  Serial.print("turn on alarm: "); Serial.println(millis()); delay(10);
  // set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
  // if not done, this easily leads to problems, as both register aren't reset on reboot/recompile
  // SQW becomes HIGH, P-MOSFET opens, power to the ESP2CAM is cut
  rtc.clearAlarm(1);
  rtc.clearAlarm(2);
}

void loop() {

}```

As a note:

SD Card Connections: The following pins are being used by the microSD card module in the ESP32-CAM.
SD Card ESP32
CLK GPIO 14
CMD GPIO 15
DATA0 GPIO 2
DATA1 / Flashlight GPIO 4
DATA2 GPIO 12
DATA3 GPIO 13

Notice that the SD card uses GPIO_NUM_14 and GPIO_NUM_15 and you are trying to use those same pins for SDA and SCL?

1 Like

But what's strange is that the RTC is working well enough to set the alarm for the next "take photo, save to sdcard" (and it does take a photo and save it), however it's not acquiring the correct time.

Yup.

If you are willing to work at the ESP32 API level you might be able to resolve the pin use conflict.

1 Like

After commenting and moving some lines of code pertaining to the sdcard, the clock function started working normally. There is indeed and incompatibility, thank you.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.