瀏覽代碼

Shared PSRAM memory (#2285)

* enable PSRAM logging

* add extra functions for psram shared memroy handling

* CImageBasis objects still should used dynamic memory (eg. rawImage), haw ever tmpImage must be placed inside the shared memory

* Place all STBI allocs inside the shared memory

* The models are placed in the shared PSRAM reagion and must be allocated through the dedicated functions

* .

* renaming

* fix cast warning

* add flag to switch STBI PSRAM usage

* improve PSRAM shared handling

* reserve shared PSRAM as early as possible

* init logging eralier so we can use it in PSRAM shared alloc

* move Wifi_LWIP, BSS_SEG and MQTT Outbox into PSRAM to ffree internal memory

* Check if model fits into reserved shared memory

* Update code/components/jomjol_tfliteclass/CTfLiteClass.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_flowcontroll/ClassFlowControll.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_image_proc/CImageBasis.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* .

* .

* .

* .

* Korrektur Merge Conflict in main.cpp

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
CaCO3 2 年之前
父節點
當前提交
de92c29245

+ 2 - 2
code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp

@@ -190,10 +190,10 @@ bool ClassFlowAlignment::doFlow(string time)
 
     if (!ImageTMP) 
     {
-        ImageTMP = new CImageBasis("ImageTMP", ImageBasis);
+        ImageTMP = new CImageBasis("tmpImage", ImageBasis); // Make sure the name does not get change, it is relevant for the PSRAM allocation!
         if (!ImageTMP) 
         {
-            LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate ImageTMP -> Exec this round aborted!");
+            LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate tmpImage -> Exec this round aborted!");
             LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
             return false;
         }

+ 4 - 1
code/components/jomjol_flowcontroll/ClassFlowCNNGeneral.cpp

@@ -374,8 +374,11 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
         }
     }
 
-    if (!getNetworkParameter())
+    if (!getNetworkParameter()) {
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "An error occured on setting up the Network -> Disabling it!");
+        disabled = true; // An error occured, disable this CNN!
         return false;
+    }
 
 
     for (int _ana = 0; _ana < GENERAL.size(); ++_ana)

+ 1 - 1
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -373,7 +373,7 @@ bool ClassFlowControll::doFlow(string time)
         zw_time = getCurrentTimeString("%H:%M:%S");
         aktstatus = TranslateAktstatus(FlowControll[i]->name());
         aktstatusWithTime = aktstatus + " (" + zw_time + ")";
-        //LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatusWithTime);
+        LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Status: " + aktstatusWithTime);
         #ifdef ENABLE_MQTT
             MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, qos, false);
         #endif //ENABLE_MQTT

+ 3 - 0
code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp

@@ -8,6 +8,7 @@
 #include "esp_wifi.h"
 #include "esp_log.h"
 #include "../../include/defines.h"
+#include "psram.h"
 
 #include <time.h>
 
@@ -183,6 +184,8 @@ string ClassFlowTakeImage::getHTMLSingleStep(string host)
 
 bool ClassFlowTakeImage::doFlow(string zwtime)
 {
+    psram_init_shared_memory_for_take_image_step();
+
     string logPath = CreateLogFolder(zwtime);
 
     int flash_duration = (int) (waitbeforepicture * 1000);

+ 133 - 3
code/components/jomjol_helper/psram.cpp

@@ -1,11 +1,128 @@
 #include "ClassLogFile.h"
-#include "esp_heap_caps.h"
+#include "../../include/defines.h"
+#include "psram.h"
 
 static const char* TAG = "PSRAM";
 
 using namespace std;
 
 
+void *shared_region = NULL;
+uint32_t allocatedBytesForSTBI = 0;
+
+
+/** Reserve a large block in the PSRAM which will be shared between the different steps.
+ * Each step uses it differently but only wiuthin itself. */
+bool reserve_psram_shared_region(void) {
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating shared PSRAM region (" + 
+            std::to_string(TENSOR_ARENA_SIZE + MAX_MODEL_SIZE) + " bytes)...");
+    shared_region = malloc_psram_heap("Shared PSRAM region", TENSOR_ARENA_SIZE + MAX_MODEL_SIZE, 
+            MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
+
+    if (shared_region == NULL) {
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to allocating shared PSRAM region!");
+        return false;
+    }
+    else {
+        return true;
+    }
+}
+
+
+
+/*******************************************************************
+ * Memory used in Take Image (STBI)
+ *******************************************************************/
+void psram_init_shared_memory_for_take_image_step(void) {
+        LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init shared memory for step 'Take Image' (STBI buffers)");
+    allocatedBytesForSTBI = 0;
+}
+
+
+void *psram_reserve_shared_stbi_memory(size_t size) {
+    /* Only large buffers should be placed in the shared PSRAM 
+     * If we also place all smaller STBI buffers here, we get artefacts for some reasons. */
+    if (size >= 100000) {
+        if ((allocatedBytesForSTBI + size) > TENSOR_ARENA_SIZE + MAX_MODEL_SIZE) { // Check if it still fits in the shared region
+            LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Shared memory in PSRAM too small (STBI) to fit additional " + 
+                    std::to_string(size) + "bytes! Available: " + std::to_string(TENSOR_ARENA_SIZE + MAX_MODEL_SIZE - allocatedBytesForSTBI) + " bytes!");
+            return NULL;
+        }
+        
+        LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating memory (" + std::to_string(size) + " bytes) for STBI (use shared memory in PSRAM)...");
+        allocatedBytesForSTBI += size;
+        return (uint8_t *)shared_region + allocatedBytesForSTBI - size;
+    }
+    else { // Normal PSRAM
+        return malloc_psram_heap("STBI", size, MALLOC_CAP_SPIRAM);
+    }
+}
+
+
+void *psram_reallocate_shared_stbi_memory(void *ptr, size_t newsize) {
+    char buf[20];
+    sprintf(buf, "%p", ptr);
+    LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "STBI requested realloc for " + std::string(buf) + " but this is currently unsupported!");
+    return NULL;
+}
+
+
+void psram_free_shared_stbi_memory(void *p) {
+    if ((p >= shared_region) && (p <= ((uint8_t *)shared_region + allocatedBytesForSTBI))) { // was allocated inside the shared memory
+        LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Part of shared memory used for STBI (PSRAM, part of shared memory) is free again");
+    }
+    else { // Normal PSRAM
+        free_psram_heap("STBI", p);
+    }
+}
+
+
+
+/*******************************************************************
+ * Memory used in Aligning Step 
+ * During this step we only use the shared part of the PSRAM
+ * for the tmpImage. 
+ *******************************************************************/
+void *psram_reserve_shared_tmp_image_memory(void) {  
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating tmpImage (" + std::to_string(IMAGE_SIZE) + " bytes, use shared memory in PSRAM)...");
+    return shared_region; // Use 1th part of the shared memory for the tmpImage (only user)
+}
+
+
+void psram_free_shared_temp_image_memory(void) {
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Shared memory used for tmpImage (PSRAM, part of shared memory) is free again");
+}
+
+
+
+/*******************************************************************
+ * Memory used in Digitalization Steps
+ * During this step we only use the shared part of the PSRAM for the
+ * Tensor Arena and one of the Models.
+ * The shared memory is large enough for the largest model and the
+ * Tensor Arena. Therefore we do not need to monitor the usage.
+ *******************************************************************/
+void *psram_get_shared_tensor_arena_memory(void) {
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating Tensor Arena (" + std::to_string(TENSOR_ARENA_SIZE) + " bytes, use shared memory in PSRAM)...");
+    return shared_region; // Use 1th part of the shared memory for Tensor
+}
+
+
+void *psram_get_shared_model_memory(void) {
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating Model memory (" + std::to_string(MAX_MODEL_SIZE) + " bytes, use shared memory in PSRAM)...");
+    return (uint8_t *)shared_region + TENSOR_ARENA_SIZE; // Use 2nd part of the shared memory (after Tensor Arena) for the model
+}
+
+
+void psram_free_shared_tensor_arena_and_model_memory(void) {
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Shared memory used for Tensor Arena and model (PSRAM, part of shared memory) is free again");
+}
+
+
+
+/*******************************************************************
+ * General
+ *******************************************************************/
 void *malloc_psram_heap(std::string name, size_t size, uint32_t caps) {
 	void *ptr;
 
@@ -21,12 +138,25 @@ void *malloc_psram_heap(std::string name, size_t size, uint32_t caps) {
 }
 
 
+void *realloc_psram_heap(std::string name, void *ptr, size_t size, uint32_t caps) {
+	ptr = heap_caps_realloc(ptr, size, caps);
+    if (ptr != NULL) {
+	    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Reallocated " + to_string(size) + " bytes in PSRAM for '" + name + "'");
+	}
+    else {
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to reallocate " + to_string(size) + " bytes in PSRAM for '" + name + "'!");
+    }
+
+	return ptr;
+}
+
+
 void *calloc_psram_heap(std::string name, size_t n, size_t size, uint32_t caps) {
 	void *ptr;
 
 	ptr = heap_caps_calloc(n, size, caps);
     if (ptr != NULL) {
-	    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocated " + to_string(size) + " bytes in PSRAM for '" + name + "'");
+	    LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Allocated " + to_string(size) + " bytes in PSRAM for '" + name + "'");
 	}
     else {
         LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to allocate " + to_string(size) + " bytes in PSRAM for '" + name + "'!");
@@ -39,4 +169,4 @@ void *calloc_psram_heap(std::string name, size_t n, size_t size, uint32_t caps)
 void free_psram_heap(std::string name, void *ptr) {
     LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Freeing memory in PSRAM used for '" + name + "'...");
     heap_caps_free(ptr);
-}
+}

+ 28 - 1
code/components/jomjol_helper/psram.h

@@ -1,7 +1,34 @@
+#pragma once
+#ifndef PSRAM_h
+#define PSRAM_h
 
 #include "esp_heap_caps.h"
 
+
+bool reserve_psram_shared_region(void);
+
+
+/* Memory used in Take Image Step */
+void psram_init_shared_memory_for_take_image_step(void);
+void *psram_reserve_shared_stbi_memory(size_t size);
+void *psram_reallocate_shared_stbi_memory(void *ptr, size_t newsize);
+void psram_free_shared_stbi_memory(void *p);
+
+
+/* Memory used in Aligning Step */
+void *psram_reserve_shared_tmp_image_memory(void);
+void psram_free_shared_temp_image_memory(void);
+
+/* Memory used in Digitalization Steps */
+void *psram_get_shared_tensor_arena_memory(void);
+void *psram_get_shared_model_memory(void);
+void psram_free_shared_tensor_arena_and_model_memory(void);
+
+/* General */
 void *malloc_psram_heap(std::string name, size_t size, uint32_t caps);
+void *realloc_psram_heap(std::string name, void *ptr, size_t size, uint32_t caps);
 void *calloc_psram_heap(std::string name, size_t n, size_t size, uint32_t caps);
 
-void free_psram_heap(std::string name, void *ptr);
+void free_psram_heap(std::string name, void *ptr);
+
+#endif // PSRAM_h

+ 20 - 3
code/components/jomjol_image_proc/CImageBasis.cpp

@@ -477,7 +477,13 @@ CImageBasis::CImageBasis(string _name, CImageBasis *_copyfrom)
 
     memsize = width * height * channels;
 
-    rgb_image = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
+
+    if (name == "tmpImage") {
+        rgb_image = (unsigned char*)psram_reserve_shared_tmp_image_memory();
+    }
+    else {
+        rgb_image = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
+    }
 
     if (rgb_image == NULL)
     {
@@ -618,9 +624,20 @@ CImageBasis::~CImageBasis()
 {
     RGBImageLock();
 
+
     if (!externalImage) {
-        //stbi_image_free(rgb_image);
-        free_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ", " + to_string(memsize) + ")", rgb_image);
+        if (name == "tmpImage") { // This image should be placed in the shared part of PSRAM
+            psram_free_shared_temp_image_memory();
+        }
+        else { // All other images are much smaller and can go into the normal PSRAM region
+            //stbi_image_free(rgb_image);
+            if (memsize == 0) {
+                LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Not freeing (" + name + " as there was never PSRAM allocated for it)");
+            }
+            else {
+                free_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ", " + to_string(memsize) + ")", rgb_image);
+            }
+        }
     }
 
     RGBImageRelease();

+ 15 - 0
code/components/jomjol_image_proc/make_stb.cpp

@@ -1,8 +1,23 @@
 #include <stdint.h>
 #include <string>
+#include "psram.h"
 
 #include "../../include/defines.h"
 
+
+#define USE_SHARED_PSRAM_FOR_STBI
+
+#ifdef USE_SHARED_PSRAM_FOR_STBI
+#define STBI_MALLOC(sz)           psram_reserve_shared_stbi_memory(sz)
+#define STBI_REALLOC(p,newsz)     psram_reallocate_shared_stbi_memory(p, newsz)
+#define STBI_FREE(p)              psram_free_shared_stbi_memory(p)
+#else // Use normal PSRAM
+#define STBI_MALLOC(sz)           malloc_psram_heap("STBI", sz, MALLOC_CAP_SPIRAM)
+#define STBI_REALLOC(p,newsz)     realloc_psram_heap("STBI", p, newsz, MALLOC_CAP_SPIRAM)
+#define STBI_FREE(p)              free_psram_heap("STBI", p)
+#endif
+
+
 #define STB_IMAGE_IMPLEMENTATION
 #include "../stb/stb_image.h"
 

+ 13 - 7
code/components/jomjol_tfliteclass/CTfLiteClass.cpp

@@ -243,15 +243,22 @@ bool CTfLiteClass::ReadFileToModel(std::string _fn)
 
     if (size == -1)
     {
-        ESP_LOGE(TAG, "CTfLiteClass::ReadFileToModel: Model file doesn't exist: %s", _fn.c_str());
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Model file doesn't exist: " + _fn + "!");
         return false;
     }
+    else if(size > MAX_MODEL_SIZE) {
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to load model '" + _fn + "'! It does not fit in the reserved shared memory in PSRAM!");
+        return false;
+    }
+
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Loading Model " + _fn + " /size: " + std::to_string(size) + " bytes...");
+
 
 #ifdef DEBUG_DETAIL_ON      
         LogFile.WriteHeapInfo("CTLiteClass::Alloc modelfile start");
 #endif
 
-    modelfile = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->modelfile", size, MALLOC_CAP_SPIRAM);
+    modelfile = (unsigned char*)psram_get_shared_model_memory();
   
 	  if(modelfile != NULL) 
     {
@@ -304,9 +311,9 @@ CTfLiteClass::CTfLiteClass()
     this->modelfile = NULL;
     this->interpreter = nullptr;
     this->input = nullptr;
-    this->output = nullptr;  
-    this->kTensorArenaSize = 800 * 1024;   /// according to testfile: 108000 - so far 600;; 2021-09-11: 200 * 1024
-    this->tensor_arena = (uint8_t*)malloc_psram_heap(std::string(TAG) + "->tensor_arena", kTensorArenaSize, MALLOC_CAP_SPIRAM);
+    this->output = nullptr;
+    this->kTensorArenaSize = TENSOR_ARENA_SIZE;
+    this->tensor_arena = (uint8_t*)psram_get_shared_tensor_arena_memory();
 }
 
 
@@ -315,8 +322,7 @@ CTfLiteClass::~CTfLiteClass()
   delete this->interpreter;
   delete this->error_reporter;
 
-  free_psram_heap(std::string(TAG) + "->modelfile", modelfile);
-  free_psram_heap(std::string(TAG) + "->tensor_arena", this->tensor_arena);
+  psram_free_shared_tensor_arena_and_model_memory();
 }        
 
 

+ 6 - 0
code/include/defines.h

@@ -208,6 +208,12 @@
     //#define DEBUG_DETAIL_ON 
 
 
+/////////////////////////////////////////////
+////      PSRAM Allocations              ////
+/////////////////////////////////////////////
+#define MAX_MODEL_SIZE            (unsigned int)(1.3 * 1024 * 1024) // Space for the currently largest model (1.1 MB) + some spare
+#define TENSOR_ARENA_SIZE         800 * 1024 // Space for the Tensor Arena, (819200 Bytes)
+#define IMAGE_SIZE                640 * 480 * 3 // Space for a extracted image (921600 Bytes)
 /////////////////////////////////////////////
 ////      Conditionnal definitions       ////
 /////////////////////////////////////////////

+ 103 - 86
code/main/main.cpp

@@ -11,9 +11,13 @@
 //#include "sdkconfig.h"
 #include "esp_psram.h"
 #include "esp_pm.h"
+
+#include "psram.h"
+
 #include "esp_chip_info.h"
 
 
+
 // SD-Card ////////////////////
 //#include "nvs_flash.h"
 #include "esp_vfs_fat.h"
@@ -190,15 +194,6 @@ extern "C" void app_main(void)
     // ********************************************
     ESP_LOGI(TAG, "\n\n\n\n================ Start app_main =================");
  
-    // Init camera
-    // ********************************************
-    PowerResetCamera();
-    esp_err_t camStatus = Camera.InitCam();
-    Camera.LightOnOff(false);
-
-    xDelay = 2000 / portTICK_PERIOD_MS;
-    ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
-    vTaskDelay( xDelay );
 
     // Init SD card
     // ********************************************
@@ -220,6 +215,105 @@ extern "C" void app_main(void)
     LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Start ======================");
     LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
 
+
+    // Init external PSRAM
+    // ********************************************
+    esp_err_t PSRAMStatus = esp_psram_init();
+    if (PSRAMStatus != ESP_OK) {  // ESP_FAIL -> Failed to init PSRAM
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM init failed (" + std::to_string(PSRAMStatus) + ")! PSRAM not found or defective");
+        setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
+        StatusLED(PSRAM_INIT, 1, true);
+    }
+    else { // ESP_OK -> PSRAM init OK --> continue to check PSRAM size
+        size_t psram_size = esp_psram_get_size(); // size_t psram_size = esp_psram_get_size(); // comming in IDF 5.0
+        LogFile.WriteToFile(ESP_LOG_INFO, TAG, "PSRAM size: " + std::to_string(psram_size) + " byte (" + std::to_string(psram_size/1024/1024) + 
+                                               "MB / " + std::to_string(psram_size/1024/1024*8) + "MBit)");
+
+        // Check PSRAM size
+        // ********************************************
+        if (psram_size < (4*1024*1024)) { // PSRAM is below 4 MBytes (32Mbit)
+            LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM size >= 4MB (32Mbit) is mandatory to run this application");
+            setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
+            StatusLED(PSRAM_INIT, 2, true);
+        }
+        else { // PSRAM size OK --> continue to check heap size
+            size_t _hsize = getESPHeapSize();
+            LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Total heap: " + std::to_string(_hsize) + " byte");
+
+            // Check heap memory
+            // ********************************************
+            if (_hsize < 4000000) { // Check available Heap memory for a bit less than 4 MB (a test on a good device showed 4187558 bytes to be available)
+                LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Total heap >= 4000000 byte is mandatory to run this application");
+                setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL);
+                StatusLED(PSRAM_INIT, 3, true);
+            }
+            else { // HEAP size OK --> continue to reserve shared memory block and check camera init
+                /* Allocate static PSRAM memory regions */
+                if (! reserve_psram_shared_region()) {
+                    setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL);
+                    StatusLED(PSRAM_INIT, 3, true);
+                }
+                else { // OK
+                    // Init camera
+                    // ********************************************
+                    PowerResetCamera();
+                    esp_err_t camStatus = Camera.InitCam();
+                    Camera.LightOnOff(false);
+
+                    xDelay = 2000 / portTICK_PERIOD_MS;
+                    ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
+                    vTaskDelay( xDelay );
+
+
+                    // Check camera init
+                    // ********************************************
+                    if (camStatus != ESP_OK) { // Camera init failed, retry to init
+                        char camStatusHex[33];
+                        sprintf(camStatusHex,"0x%02x", camStatus);
+                        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Camera init failed (" + std::string(camStatusHex) + "), retrying...");
+
+                        PowerResetCamera();
+                        camStatus = Camera.InitCam();
+                        Camera.LightOnOff(false);
+
+                        xDelay = 2000 / portTICK_PERIOD_MS;
+                        ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
+                        vTaskDelay( xDelay ); 
+
+                        if (camStatus != ESP_OK) { // Camera init failed again
+                            sprintf(camStatusHex,"0x%02x", camStatus);
+                            LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera init failed (" + std::string(camStatusHex) +
+                                                                    ")! Check camera module and/or proper electrical connection");
+                            setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD);
+                            StatusLED(CAM_INIT, 1, true);
+                        }
+                    }
+                    else { // ESP_OK -> Camera init OK --> continue to perform camera framebuffer check
+                        // Camera framebuffer check
+                        // ********************************************
+                        if (!Camera.testCamera()) {
+                            LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera framebuffer check failed");
+                            // Easiest would be to simply restart here and try again,
+                            // how ever there seem to be systems where it fails at startup but still work correctly later.
+                            // Therefore we treat it still as successed! */
+                            setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
+                            StatusLED(CAM_INIT, 2, false);
+                        }
+                        Camera.LightOnOff(false);   // make sure flashlight is off before start of flow
+
+                        // Print camera infos
+                        // ********************************************
+                        char caminfo[50];
+                        sensor_t * s = esp_camera_sensor_get();
+                        sprintf(caminfo, "PID: 0x%02x, VER: 0x%02x, MIDL: 0x%02x, MIDH: 0x%02x", s->id.PID, s->id.VER, s->id.MIDH, s->id.MIDL);
+                        LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Camera info: " + std::string(caminfo));
+                    }
+                }
+            }
+        }
+    }
+
+
     // SD card: basic R/W check
     // ********************************************
     int iSDCardStatus = SDCardCheckRW();
@@ -374,84 +468,7 @@ extern "C" void app_main(void)
         #endif
     #endif
    
-    // Init external PSRAM
-    // ********************************************
-    esp_err_t PSRAMStatus = esp_psram_init();
-    if (PSRAMStatus == ESP_FAIL) {  // ESP_FAIL -> Failed to init PSRAM
-        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM init failed (" + std::to_string(PSRAMStatus) + ")! PSRAM not found or defective");
-        setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
-        StatusLED(PSRAM_INIT, 1, true);
-    }
-    else { // ESP_OK -> PSRAM init OK --> continue to check PSRAM size
-        size_t psram_size = esp_psram_get_size(); // size_t psram_size = esp_psram_get_size(); // comming in IDF 5.0
-        LogFile.WriteToFile(ESP_LOG_INFO, TAG, "PSRAM size: " + std::to_string(psram_size) + " byte (" + std::to_string(psram_size/1024/1024) + 
-                                               "MB / " + std::to_string(psram_size/1024/1024*8) + "MBit)");
-
-        // Check PSRAM size
-        // ********************************************
-        if (psram_size < (4*1024*1024)) { // PSRAM is below 4 MBytes (32Mbit)
-            LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM size >= 4MB (32Mbit) is mandatory to run this application");
-            setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
-            StatusLED(PSRAM_INIT, 2, true);
-        }
-        else { // PSRAM size OK --> continue to check heap size
-            size_t _hsize = getESPHeapSize();
-            LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Total heap: " + std::to_string(_hsize) + " byte");
-
-            // Check heap memory
-            // ********************************************
-            if (_hsize < 4000000) { // Check available Heap memory for a bit less than 4 MB (a test on a good device showed 4187558 bytes to be available)
-                LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Total heap >= 4000000 byte is mandatory to run this application");
-                setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL);
-                StatusLED(PSRAM_INIT, 3, true);
-            }
-            else { // HEAP size OK --> continue to check camera init
-                // Check camera init
-                // ********************************************
-                if (camStatus != ESP_OK) { // Camera init failed, retry to init
-                    char camStatusHex[33];
-                    sprintf(camStatusHex,"0x%02x", camStatus);
-                    LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Camera init failed (" + std::string(camStatusHex) + "), retrying...");
-
-                    PowerResetCamera();
-                    camStatus = Camera.InitCam();
-                    Camera.LightOnOff(false);
-
-                    xDelay = 2000 / portTICK_PERIOD_MS;
-                    ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
-                    vTaskDelay( xDelay ); 
 
-                    if (camStatus != ESP_OK) { // Camera init failed again
-                        sprintf(camStatusHex,"0x%02x", camStatus);
-                        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera init failed (" + std::string(camStatusHex) +
-                                                                ")! Check camera module and/or proper electrical connection");
-                        setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD);
-                        StatusLED(CAM_INIT, 1, true);
-                    }
-                }
-                else { // ESP_OK -> Camera init OK --> continue to perform camera framebuffer check
-                    // Camera framebuffer check
-                    // ********************************************
-                    if (!Camera.testCamera()) {
-                        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera framebuffer check failed");
-                        // Easiest would be to simply restart here and try again,
-                        // how ever there seem to be systems where it fails at startup but still work correctly later.
-                        // Therefore we treat it still as successed! */
-                        setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
-                        StatusLED(CAM_INIT, 2, false);
-                    }
-                    Camera.LightOnOff(false);   // make sure flashlight is off before start of flow
-
-                    // Print camera infos
-                    // ********************************************
-                    char caminfo[50];
-                    sensor_t * s = esp_camera_sensor_get();
-                    sprintf(caminfo, "PID: 0x%02x, VER: 0x%02x, MIDL: 0x%02x, MIDH: 0x%02x", s->id.PID, s->id.VER, s->id.MIDH, s->id.MIDL);
-                    LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Camera info: " + std::string(caminfo));
-                }
-            }
-        }
-    }
 
     // Print Device info
     // ********************************************

+ 4 - 3
code/sdkconfig.defaults

@@ -101,8 +101,9 @@ CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
 CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=40960
 CONFIG_SPIRAM_CACHE_WORKAROUND=y
 CONFIG_SPIRAM_IGNORE_NOTFOUND=y
-#CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y => Leads to memory fragmentation, see https://github.com/jomjol/AI-on-the-edge-device/issues/2200
-#CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y => Leads to memory fragmentation, see https://github.com/jomjol/AI-on-the-edge-device/issues/2200
+
+CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
+CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
 
 CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
 
@@ -124,7 +125,7 @@ CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED=y
 CONFIG_MQTT_USE_CORE_0=y
 CONFIG_MQTT_USE_CUSTOM_CONFIG=y
 #CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS=5000
-#CONFIG_MQTT_CUSTOM_OUTBOX=y # -> Use custom outbox in components/jomjol_mqtt/mqtt_outbox.h/cpp. If USE_PSRAM is enabled in there, it will save 10 kBytes of internal RAM. How ever it also leads to memory fragmentation, see https://github.com/jomjol/AI-on-the-edge-device/issues/2200
+CONFIG_MQTT_CUSTOM_OUTBOX=y
 
 CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=n