I'm using the Esp32cam and platformio/VScode. I'm trying to save the image taken from the camera into the Sdcard. I manage to take the photo but I'm unable to save it using, either fwrite or fprintf.
I did try using the serial monitor but for some reason I get nothing and the esp32 kind of froze, actually did try all the baud rate combination I could find but still nothing. I have no idea if it's related to the onboard flash LED from the module - it blinks when trying to upload code if there's an SD card (I had to turn it off because it wont let me upload the program to the module, if there's an SD card).
I did follow the examples from espressif repo on GitHub and still got nothing, Most info I found is about using Arduino. I'm posting my code below.
Code
// https://github.com/espressif/esp32-camera // esp32 repo must see for camera
/**
* follow how-to inside https://github.com/espressif/esp32-camera
*
*
* This example takes a picture every 5s and print its size on serial monitor.
*/
// =============================== SETUP ======================================
// https://docs.espressif.com/projects/esp-idf/en/v4.3.1/esp32/get-started/index.html
// 1. Board setup (Uncomment):
// #define BOARD_WROVER_KIT
#define BOARD_ESP32CAM_AITHINKER
#define LED 33 // internal Led
#define FLASH_LED 4 // flash led
/**
* 2. Kconfig setup
*
* If you have a Kconfig file, copy the content from
* https://github.com/espressif/esp32-camera/blob/master/Kconfig into it.
* In case you haven't, copy and paste this Kconfig file inside the src directory.
* This Kconfig file has definitions that allows more control over the camera and
* how it will be initialized.
*/
/**
* 3. Enable PSRAM on sdkconfig:
*
* CONFIG_ESP32_SPIRAM_SUPPORT=y
*
* More info on
* https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support
*/
// ================================ CODE ======================================
#include <stdio.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <string.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
//#include "jpge.h" // esp32 jpeg compresion
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_camera.h"
//#include "FS.h"
#include "sdmmc_cmd.h"
//#define BOARD_WROVER_KIT 1
// WROVER-KIT PIN Map
/* #ifdef BOARD_WROVER_KIT
#define CAM_PIN_PWDN -1 //power down is not used
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 21
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 19
#define CAM_PIN_D2 18
#define CAM_PIN_D1 5
#define CAM_PIN_D0 4
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
#endif
*/
// // ESP32Cam (AiThinker) PIN Map
#ifdef BOARD_ESP32CAM_AITHINKER
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
#endif
#define MOUNT_POINT "/sdcard"
static const char *TAG = "security_camera_farm";
static camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
.pin_reset = CAM_PIN_RESET,
.pin_xclk = CAM_PIN_XCLK,
.pin_sscb_sda = CAM_PIN_SIOD,
.pin_sscb_scl = CAM_PIN_SIOC,
.pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6,
.pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4,
.pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2,
.pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0,
.pin_vsync = CAM_PIN_VSYNC,
.pin_href = CAM_PIN_HREF,
.pin_pclk = CAM_PIN_PCLK,
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_RGB565, //YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = FRAMESIZE_QVGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
.jpeg_quality = 12, //0-63 lower number means higher quality
.fb_count = 1, //if more than one, i2s runs in continuous mode. Use only with JPEG
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
};
static esp_err_t init_camera()
{
//initialize the camera
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK)
{
printf("Camera init fail, init_camera");
ESP_LOGE(TAG, "Camera Init Failed");
return err;
}
return ESP_OK;
}
/* bool init_SDcard(){
esp_err_t card = sdmmc_card_init(host_targ, salida ); // revisar
if (card == ESP_OK){
return true;
} else{
return false;
//add error on morse code
}
}*/
void morse_Code( int blink, int time){ // blink, number of times the led blinks; time, how fast the led blinks
int i;
if (blink == 1){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
if (blink == 2){
for (i=0;i<2; i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
if (blink == 3){
for (i=0;i<3 ;i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
if (blink == 4){
for (i=0;i<4 ;i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
if (blink == 5){
for (i=0;i<5 ;i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
if (blink == 6){
for (i=0;i<6 ;i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
if (blink == 7){
for (i=0;i<7 ;i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
if (blink == 8){
for (i=0;i<8 ;i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
if (blink == 9){
for (i=0;i<9 ;i++){
gpio_set_level(LED, 0);
vTaskDelay(time/portTICK_RATE_MS);
gpio_set_level(LED, 1);
vTaskDelay(time/portTICK_RATE_MS);
}
}
vTaskDelay(2000/portTICK_RATE_MS);
return;
}
void app_main()
{
// error management
esp_err_t ret;
int num = 0;
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
// formatted in case when mounting fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card");
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
// Please check its source code and implement error recovery when developing
// production applications.
ESP_LOGI(TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// Set bus width to use:
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
slot_config.width = 4;
#else
slot_config.width = 1;
#endif
// On chips where the GPIOs used for SD card can be configured, set them in
// the slot_config structure:
#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
slot_config.clk = CONFIG_EXAMPLE_PIN_CLK;
slot_config.cmd = CONFIG_EXAMPLE_PIN_CMD;
slot_config.d0 = CONFIG_EXAMPLE_PIN_D0;
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
slot_config.d1 = CONFIG_EXAMPLE_PIN_D1;
slot_config.d2 = CONFIG_EXAMPLE_PIN_D2;
slot_config.d3 = CONFIG_EXAMPLE_PIN_D3;
#endif // CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
#endif // CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
// Enable internal pullups on enabled pins. The internal pullups
// are insufficient however, please make sure 10k external pullups are
// connected on the bus. This is for debug / example purpose only.
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
ESP_LOGI(TAG, "Mounting filesystem");
ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
return;
}
ESP_LOGI(TAG, "Filesystem mounted");
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
// init camera
gpio_set_direction(LED, GPIO_MODE_OUTPUT); // red led
gpio_set_direction(FLASH_LED, GPIO_MODE_OUTPUT); // Flash led
gpio_set_level(FLASH_LED, 0); // set flash led to off to avoid it flash when accessing sdcard
gpio_hold_en(FLASH_LED);
if(ESP_OK != init_camera()) {
// blink twice for unable to initialized camera
printf("Camera init not OK");
morse_Code(2,100);
ESP_LOGI(TAG, "Unable to initialize the camera");
return;
} // /sdcard
char file_[260];
char str [] = "using fwrite";
FILE *file_jpg ;
FILE *file_log ;
while (1)
{
num++;
sprintf(file_, MOUNT_POINT"/picture_%d.jpg", num);
char *file_hello = file_;
ESP_LOGI(TAG, "Taking picture...");
camera_fb_t *pic = esp_camera_fb_get();
if (!pic){
printf("Unable to take picture");
// blink 3 times for error camera failed to take picture
morse_Code(3,100);
ESP_LOGE(TAG, "Camera failed to take picture");
} else{
// use pic->buf to access the image
printf("Picture taken: "); // + pic->len + pic->timestamp);
// create the picture file
ESP_LOGI(TAG, "Opening file %s", file_hello);
file_log = fopen("log.txt", "w");
fprintf(file_log, "despues de fopen usando fprintf /n");
fwrite(str, 1, sizeof(str),file_log);
fclose(file_log);
// opening jpg file
//////////////////////////////////
// it wont open regular jpeg, libjpeg or jpeg.h is needed
file_jpg = fopen(file_, "w"); // <-- FIX THIS ASAP, check jpeg.h
//////////////////////////////////
if (file_jpg == NULL) {
file_log = fopen("log.txt","w");
fprintf(file_log, "file_ : %s /n File_Hello : %s", file_, file_hello);
morse_Code(4,200);
ESP_LOGE(TAG, "Failed to open file for writing");
fclose(file_log);
return;
}
if (file_jpg !=NULL ){
morse_Code(1,200);
vTaskDelay(800/portTICK_RATE_MS);
morse_Code(5,200);
return;
}
//fwrite(pic->buf, sizeof(pic->buf), 1 , file_jpg );
fprintf(file_jpg, "%s", pic->buf); // saving the image to the file f
fclose(file_jpg);
ESP_LOGI(TAG, "File written");
ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len);
//blink once for taking picture
morse_Code(1,200);
esp_camera_fb_return(pic);
}
vTaskDelay(5000 / portTICK_RATE_MS);
}
/*
ESP_LOGI(TAG, "Opening file %s", file_hello);
FILE *f = fopen(file_hello, "w");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
fprintf(f, "Hello %s!\n", card->cid.name);
fclose(f);
ESP_LOGI(TAG, "File written");
const char *file_foo = MOUNT_POINT"/foo.txt";
// Check if destination file exists before renaming
struct stat st;
if (stat(file_foo, &st) == 0) {
// Delete it if it exists
unlink(file_foo);
}
// Rename original file
ESP_LOGI(TAG, "Renaming file %s to %s", file_hello, file_foo);
if (rename(file_hello, file_foo) != 0) {
ESP_LOGE(TAG, "Rename failed");
return;
}
// Open renamed file for reading
ESP_LOGI(TAG, "Reading file %s", file_foo);
f = fopen(file_foo, "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return;
}
// Read a line from file
char line[64];
fgets(line, sizeof(line), f);
fclose(f);
// Strip newline
char *pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGI(TAG, "Read from file: '%s'", line);
// All done, unmount partition and disable SDMMC peripheral
esp_vfs_fat_sdcard_unmount(mount_point, card);
ESP_LOGI(TAG, "Card unmounted");
*/
}
EDIT: Ok apparently fopen dont like to mess with names or change it dinamicaly, so i went down to open one file at the time and save the image to it, but for some reason it wont create a jpg file, only txt files, i did modified my code so it only take 1 photo, save it and finish but stil nothing
FILE *f = fopen("/sdcard/picture_0.jpg", "wbx);
if (f = NULL){
morse_code(2,100);
ESP_LOGE(TAG, "Fail to open for writing");
esp_vfs_fat_sdcard_unmount(mount_point,card);
return;
}
if (f != NULL){
// taking picture and saving to file using fwrite
}
Edit 2: Apparently Esp32cam have a filename restriction that you can only name the file up to 8 char only, there seems to be a way to increase the filename lengh but im dont know where it is, also, when the file is created and the data is writen to the jpg file, it is writen but no image can be seen from that file, either in plain text or binary, it makes no sense on any machine i try to see them
FILE *f = fopen("/sdcard/pic_001.jpg", "wx"); // 8 char name wont work on esp32
if (f = NULL){
morse_code(2,100);
ESP_LOGE(TAG, "Fail to open for writing");
esp_vfs_fat_sdcard_unmount(mount_point,card);
return;
}
if (f != NULL){
ESP_LOGI(TAG, "Taking picture...");
camera_fb_t *pic = esp_camera_fb_get(); // this takes the picture
if (!pic){
morse_code(2,100);
ESP_LOG(TAG, "Camera failed to take picture");
}else{
fwrite(pic->buf, pic->len, 1, f); // here i write the file, but the buffer is uint8_t not sure if i need to convert it to char* or if its needed to save it as binary
morse_code(1,200);
esp_camera_fb_return(pic);
}
}