Is it possible to take a photo and save it to an sdcard while also using an i2c device (DS3231 RTC)?
Posted: Mon Oct 11, 2021 4:43 pm
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, it always prints 21h00 when I do
If I do not include the ability to save to SD, the code to set the time and set alarms works normally, as in another project of mine that takes a photo and sends to Telegram:
https://github.com/FBMinis/DS3231-Alarm ... legram-Bot
Is there an incompatibility between i2c and sdcard on the esp32cam?
Here's the code in attachment:
Code: Select all
DateTime now = rtc.now();
Serial.print("rtc time: "); Serial.print(now.hour(), DEC); Serial.print(" : "); Serial.println(now.minute(), DEC);
https://github.com/FBMinis/DS3231-Alarm ... legram-Bot
Is there an incompatibility between i2c and sdcard on the esp32cam?
Here's the code in attachment:
Code: Select all
/*
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, 1, 0, 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() {
}