esp32-camera: Corrupted image when I send it to a FTP server in a separate task
Posted: Wed Oct 19, 2022 9:34 am
I want to send an image captured whit OV2640 to a FTP server when my system power-up. In my application I have some indipendent FreeRTOS task, so I created a task that manage the take & send of the picture. But when I receive the picture on the FTP server, it is corrupted: I can open it but seems that the picture buffer is not completely sent. I get something like this
But if immediately after the capture I get the same picture buffer via serial on my pc it's all ok:
I think that the issue is the memory management in FreeRTOS task and esp32-camera library: after the picture capture, I start the WiFi connection routine, that has vTaskDelay(), and soon after I start the FTP session.
Does anyone have any helpful guidance on why and how to fix it?
My camera setup is
and the part of my application code
But if immediately after the capture I get the same picture buffer via serial on my pc it's all ok:
I think that the issue is the memory management in FreeRTOS task and esp32-camera library: after the picture capture, I start the WiFi connection routine, that has vTaskDelay(), and soon after I start the FTP session.
Does anyone have any helpful guidance on why and how to fix it?
My camera setup is
Code: Select all
void Camera_Setup( void )
{
// Turn-off the 'brownout detector'
WRITE_PERI_REG( RTC_CNTL_BROWN_OUT_REG, 0 );
camera_config_t config;
esp_err_t err;
pictureBuffer = NULL;
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_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 8000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 10;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.fb_count = 1;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
err = esp_camera_init( &config );
if ( err != ESP_OK )
{
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "Camera init failed with error 0x%x", err );
esp_restart();
}
else
{
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Camera init succeeded" );
}
}
Code: Select all
#include <Arduino.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include "ArduinoJson.h"
#include <ESP32_FTPClient.h>
#include "esp_camera.h"
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include "time.h"
camera_fb_t *pictureBuffer;
ulong pictureTime;
char pictureName[ 128 ];
TaskHandle_t submissionTaskHandle;
extern nodeStatus_t nodeStatus;
extern wifiCredentials_t wifiCredentials;
extern ftpCredentials_t ftpCredentials;
static boolean Ftp_Send( void )
{
uint16_t maxConnectionWaiting;
ulong timeFromPicture;
struct tm timeinfo;
ESP32_FTPClient ftp( ftpCredentials.server, ftpCredentials.port, ftpCredentials.user, ftpCredentials.pass, 5000, 2 );
maxConnectionWaiting = 0;
ftp.OpenConnection();
while ( ftp.isConnected() == false )
{
maxConnectionWaiting++;
vTaskDelay( 1000 / portTICK_PERIOD_MS );
if ( maxConnectionWaiting > FTP_CONNECTION_MAX_WAITING )
{
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "FTP connection failed!" );
return false;
}
}
timeFromPicture = millis() - pictureTime;
if ( !getLocalTime( &timeinfo ) )
{
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "Failed to obtain time for the picture name. Using local time instead" );
sprintf( pictureName, "%d.jpg", millis() );
}
else
{
timeinfo.tm_sec -= ( int )( timeFromPicture / 1000 );
sprintf( pictureName, "%d_%02d_%02d_%02d_%02d_%02d_%s.jpg", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, nodeStatus.nodeId );
}
ftp.ChangeWorkDir( "images" );
ftp.InitFile( "Type I" );
ftp.NewFile( pictureName );
ftp.WriteData( pictureBuffer->buf, pictureBuffer->len );
ftp.CloseFile();
ftp.CloseConnection();
memset( pictureName, 0, sizeof( pictureName ) );
return true;
}
static boolean Wifi_Connect( void )
{
uint16_t maxConnectionTrials;
uint16_t maxConnectionWaiting;
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Attempting WiFi connection to %s", wifiCredentials.ssid );
maxConnectionTrials = 0;
while ( maxConnectionTrials < WIFI_CONNECTION_MAX_TRIALS )
{
WiFi.begin( wifiCredentials.ssid, wifiCredentials.pass );
maxConnectionWaiting = 0;
while ( WiFi.status() != WL_CONNECTED )
{
maxConnectionWaiting++;
vTaskDelay( 1000 / portTICK_PERIOD_MS );
if ( maxConnectionWaiting > WIFI_CONNECTION_MAX_WAITING )
{
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "WiFi connection failed!" );
break;
}
}
if ( WiFi.status() == WL_CONNECTED )
{
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Connected! My IP is %s", WiFi.localIP().toString().c_str() );
return true;
}
else
{
maxConnectionTrials++;
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Try again in a few seconds..." );
WiFi.disconnect();
vTaskDelay( 5000 / portTICK_PERIOD_MS );
}
}
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "Somethings gone wrong in attempting WiFi connection" );
return false;
}
static void Get_Picture_Buffer( void )
{
if ( pictureBuffer == NULL )
{
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Capturing image..." );
pictureBuffer = esp_camera_fb_get();
}
else
{
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "Picture buffer is not empty" );
}
}
static void Release_Picture_Buffer( void )
{
if ( pictureBuffer != NULL )
{
esp_camera_fb_return( pictureBuffer );
pictureBuffer = NULL;
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Camera buffer released" );
}
else
{
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Camera buffer NULL, nothing to release" );
}
}
static void Take_Send_Picture_Task( void *pvParameters )
{
Get_Picture_Buffer();
pictureTime = millis();
if ( !pictureBuffer )
{
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "Camera capture failed" );
}
else
{
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Done! Size of the image %d bytes", pictureBuffer->len );
if ( pictureBuffer->format != PIXFORMAT_JPEG )
{
ESP_LOGW( LOG_TAG_PICTURE_MANAGING, "Capture Error: Non-JPEG image returned by camera module" );
}
else
{
ESP_LOGI( LOG_TAG_PICTURE_MANAGING, "Capture OK: JPEG image returned by camera module" );
if ( Wifi_Connect() == true )
{
Led_Status_Set( STATUS_LED_CONNECTED ); // This function updates the status led task
Init_Time( TIMEZONE ); // This function updates the local time
if ( Ftp_Send() == true )
{
// Other code after FTP submission
}
}
Release_Picture_Buffer();
}
}
vTaskDelete( NULL );
}
void Start_Picture_Submission( void )
{
submissionTaskHandle = NULL;
xTaskCreate( Take_Send_Picture_Task, "Take_Send_Picture_Task", TASK_TAKE_SEND_PICTURE_DEPTH, NULL, TASK_TAKE_SEND_PICTURE_PRIORITY, &submissionTaskHandle );
}