add HIMEM debugging tools (check free size, and memory test) (#1852)

* Update defines.h

* Update esp_sys.h

* Update esp_sys.cpp

* Add files via upload

* Update perfmon.c

* Update main.cpp

* Update main.cpp

* Delete himem_memory_check.c

* Add files via upload

* Update defines.h

* Update himem_memory_check.cpp

* Update main.cpp

* Update himem_memory_check.cpp

* Update himem_memory_check.h

* Update main.cpp
This commit is contained in:
Nicolas Liaudat
2023-01-15 22:42:11 +01:00
committed by GitHub
parent 284f7b1180
commit 5a8b39f246
7 changed files with 242 additions and 32 deletions

View File

@@ -9,13 +9,6 @@
#include "esp_chip_info.h" #include "esp_chip_info.h"
// for esp_spiram_get_size
extern "C" {
#include <esp32/spiram.h>
#include <esp32/himem.h>
}
void Restart() { void Restart() {
esp_restart(); esp_restart();
@@ -126,6 +119,8 @@ std::string get_device_info()
else else
espInfoResultStr += " External Flash memory\n"; espInfoResultStr += " External Flash memory\n";
} }
#ifdef USE_HIMEM_IF_AVAILABLE
sprintf(aMsgBuf,"spiram size %u\n", esp_spiram_get_size()); sprintf(aMsgBuf,"spiram size %u\n", esp_spiram_get_size());
espInfoResultStr += std::string(aMsgBuf); espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"himem free %u\n", esp_himem_get_free_size()); sprintf(aMsgBuf,"himem free %u\n", esp_himem_get_free_size());
@@ -133,6 +128,8 @@ std::string get_device_info()
sprintf(aMsgBuf,"himem phys %u\n", esp_himem_get_phys_size()); sprintf(aMsgBuf,"himem phys %u\n", esp_himem_get_phys_size());
espInfoResultStr += std::string(aMsgBuf); espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"himem reserved %u\n", esp_himem_reserved_area_size()); sprintf(aMsgBuf,"himem reserved %u\n", esp_himem_reserved_area_size());
espInfoResultStr += std::string(aMsgBuf);
#endif
return espInfoResultStr; return espInfoResultStr;
} }
@@ -163,6 +160,19 @@ size_t getMinEverFreeMemInternal(){ //Min. Ever Free Size
size_t getMinEverFreeMemSPIRAM(){ //Min. Ever Free Size size_t getMinEverFreeMemSPIRAM(){ //Min. Ever Free Size
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM); return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
} }
//#endif // ESP_IDF_VERSION
#ifdef USE_HIMEM_IF_AVAILABLE
size_t getHimemTotSpace(){
return esp_himem_get_phys_size();
}
size_t getHimemFreeSpace(){
return esp_himem_get_free_size();
}
size_t getHimemReservedArea(){
return esp_himem_reserved_area_size();
}
#endif
#endif //DEBUG_ENABLE_SYSINFO #endif //DEBUG_ENABLE_SYSINFO

View File

@@ -16,6 +16,14 @@
#include <esp_spi_flash.h> #include <esp_spi_flash.h>
#include <esp_heap_caps.h> #include <esp_heap_caps.h>
// for esp_spiram_get_size
extern "C" {
#include <esp32/spiram.h>
#ifdef USE_HIMEM_IF_AVAILABLE
#include <esp32/himem.h>
#endif
}
void Restart(); void Restart();
@@ -26,15 +34,6 @@
uint32_t GetFreeHeap(); uint32_t GetFreeHeap();
uint32_t GetLeastHeapFreeSinceBoot(); uint32_t GetLeastHeapFreeSinceBoot();
/*
bool CHIP_FEATURE_EMB_FLASH; //Chip has embedded flash memory.
bool CHIP_FEATURE_WIFI_BGN; //Chip has 2.4GHz WiFi.
bool CHIP_FEATURE_BLE; //Chip has Bluetooth LE.
bool CHIP_FEATURE_BT; //Chip has Bluetooth Classic.
bool CHIP_FEATURE_IEEE802154; //Chip has IEEE 802.15.4 (Zigbee/Thread)
bool CHIP_FEATURE_EMB_PSRAM; //Chip has embedded psram.
*/
std::string get_device_info(); std::string get_device_info();
size_t getFreeMemoryInternal(); size_t getFreeMemoryInternal();
@@ -43,6 +42,12 @@
size_t getLargestFreeBlockSPIRAM(); size_t getLargestFreeBlockSPIRAM();
size_t getMinEverFreeMemInternal(); size_t getMinEverFreeMemInternal();
size_t getMinEverFreeMemSPIRAM(); size_t getMinEverFreeMemSPIRAM();
#ifdef USE_HIMEM_IF_AVAILABLE
size_t getHimemTotSpace();
size_t getHimemFreeSpace();
size_t getHimemReservedArea();
#endif
#endif //ESP_SYS_H #endif //ESP_SYS_H

View File

@@ -0,0 +1,115 @@
// need [env:esp32cam-dev-himem]
//CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
//CONFIG_SPIRAM_BANKSWITCH_RESERVE=4
#include "../../include/defines.h"
#ifdef DEBUG_HIMEM_MEMORY_CHECK
#include "himem_memory_check.h"
//source adapted from : https://github.com/espressif/esp-idf/blob/master/examples/system/himem/main/himem_example_main.c
//Fill memory with pseudo-random data generated from the given seed.
//Fills the memory in 32-bit words for speed.
static void fill_mem_seed(int seed, void *mem, int len)
{
uint32_t *p = (uint32_t *)mem;
unsigned int rseed = seed ^ 0xa5a5a5a5;
for (int i = 0; i < len / 4; i++) {
*p++ = rand_r(&rseed);
}
}
//Check the memory filled by fill_mem_seed. Returns true if the data matches the data
//that fill_mem_seed wrote (when given the same seed).
//Returns true if there's a match, false when the region differs from what should be there.
static bool check_mem_seed(int seed, void *mem, int len, int phys_addr)
{
uint32_t *p = (uint32_t *)mem;
unsigned int rseed = seed ^ 0xa5a5a5a5;
for (int i = 0; i < len / 4; i++) {
uint32_t ex = rand_r(&rseed);
if (ex != *p) {
//printf("check_mem_seed: %x has 0x%08"PRIx32" expected 0x%08"PRIx32"\n", phys_addr+((char*)p-(char*)mem), *p, ex);
return false;
}
p++;
}
return true;
}
//Allocate a himem region, fill it with data, check it and release it.
static bool test_region(int check_size, int seed)
{
esp_himem_handle_t mh; //Handle for the address space we're using
esp_himem_rangehandle_t rh; //Handle for the actual RAM.
bool ret = true;
//Allocate the memory we're going to check.
ESP_ERROR_CHECK(esp_himem_alloc(check_size, &mh));
//Allocate a block of address range
ESP_ERROR_CHECK(esp_himem_alloc_map_range(ESP_HIMEM_BLKSZ, &rh));
for (int i = 0; i < check_size; i += ESP_HIMEM_BLKSZ) {
uint32_t *ptr = NULL;
//Map in block, write pseudo-random data, unmap block.
ESP_ERROR_CHECK(esp_himem_map(mh, rh, i, 0, ESP_HIMEM_BLKSZ, 0, (void**)&ptr));
fill_mem_seed(i ^ seed, ptr, ESP_HIMEM_BLKSZ); //
ESP_ERROR_CHECK(esp_himem_unmap(rh, ptr, ESP_HIMEM_BLKSZ));
}
vTaskDelay(5); //give the OS some time to do things so the task watchdog doesn't bark
for (int i = 0; i < check_size; i += ESP_HIMEM_BLKSZ) {
uint32_t *ptr;
//Map in block, check against earlier written pseudo-random data, unmap block.
ESP_ERROR_CHECK(esp_himem_map(mh, rh, i, 0, ESP_HIMEM_BLKSZ, 0, (void**)&ptr));
if (!check_mem_seed(i ^ seed, ptr, ESP_HIMEM_BLKSZ, i)) {
//printf("Error in block %d\n", i / ESP_HIMEM_BLKSZ);
ret = false;
}
ESP_ERROR_CHECK(esp_himem_unmap(rh, ptr, ESP_HIMEM_BLKSZ));
if (!ret) break; //don't check rest of blocks if error occurred
}
//Okay, all done!
ESP_ERROR_CHECK(esp_himem_free(mh));
ESP_ERROR_CHECK(esp_himem_free_map_range(rh));
return ret;
}
std::string himem_memory_check()
{
size_t memcnt=esp_himem_get_phys_size();
size_t memfree=esp_himem_get_free_size();
std::string espInfoResultStr = "";
char aMsgBuf[40];
espInfoResultStr += "Running HIMEM memory check";
sprintf(aMsgBuf,"Himem has %dKiB of memory", (int)memcnt/1024);
espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"%dKiB of which is free", (int)memfree/1024);
espInfoResultStr += std::string(aMsgBuf);
espInfoResultStr += "\n please wait ....\n";
//running memory checks
//assert(test_region(memfree, 0xaaaa));
if(test_region(memfree, 0xaaaa)) {
espInfoResultStr += "Himem check Failed!\n";
} else {
espInfoResultStr += "Himem check Done!\n";
}
return espInfoResultStr;
}
#endif // DEBUG_HIMEM_MEMORY_CHECK

View File

@@ -0,0 +1,41 @@
// need [env:esp32cam-dev-himem]
//CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
//CONFIG_SPIRAM_BANKSWITCH_RESERVE=4
#pragma once
#include "../../include/defines.h"
#ifdef DEBUG_HIMEM_MEMORY_CHECK
#ifndef HIMEM_MEMORY_CHECK_H
#define HIMEM_MEMORY_CHECK_H
//source : //source : https://github.com/espressif/esp-idf/blob/master/examples/system/himem/main/himem_example_main.c
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_heap_caps.h"
#include "esp32/himem.h"
#include <string>
#include "esp32/himem.h"
std::string himem_memory_check();
#endif //HIMEM_MEMORY_CHECK_H
#endif // DEBUG_HIMEM_MEMORY_CHECK

View File

@@ -2,6 +2,23 @@
#include "../../include/defines.h" #include "../../include/defines.h"
/*
ESP32 CPU usage monitor
Gives you a rough idea of how the Xtensa cores are utilized.
Works by attaching idle hooks and measuring how often they get called. The core usage is calculated: usage% = idle ticks since last measurement / expected idle ticks if core were idle * 100%. The expected idle tick count was measured by running an empty program.
Limitations:
Should only be used for user information, not in logic that needs accurate values
New IDF versions could optimize performance and therefore introduce an error to usage estimation.
When one core is at 100% the other might report a negative value
Usage:
#include "perfmon.h"
Call perfmon_start() once
*/
#ifdef DEBUG_ENABLE_PERFMON #ifdef DEBUG_ENABLE_PERFMON
#include "perfmon.h" #include "perfmon.h"

View File

@@ -14,8 +14,14 @@
//#define DEBUG_DISABLE_BROWNOUT_DETECTOR //#define DEBUG_DISABLE_BROWNOUT_DETECTOR
//#define DEBUG_ENABLE_SYSINFO //#define DEBUG_ENABLE_SYSINFO
//#define DEBUG_ENABLE_PERFMON //#define DEBUG_ENABLE_PERFMON
//#define DEBUG_HIMEM_MEMORY_CHECK
// need [env:esp32cam-dev-himem]
//=> CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
//=> CONFIG_SPIRAM_BANKSWITCH_RESERVE=4
// use himem //https://github.com/jomjol/AI-on-the-edge-device/issues/1842
#define USE_HIMEM_IF_AVAILABLE
/* Uncomment this to generate task list with stack sizes using the /heap handler /* Uncomment this to generate task list with stack sizes using the /heap handler
PLEASE BE AWARE: The following CONFIG parameters have to to be set in PLEASE BE AWARE: The following CONFIG parameters have to to be set in

View File

@@ -54,6 +54,14 @@
#endif #endif
#endif //DEBUG_ENABLE_SYSINFO #endif //DEBUG_ENABLE_SYSINFO
#ifdef USE_HIMEM_IF_AVAILABLE
#include "esp32/himem.h"
#ifdef DEBUG_HIMEM_MEMORY_CHECK
#include "himem_memory_check.h"
#endif
#endif
extern const char* GIT_TAG; extern const char* GIT_TAG;
extern const char* GIT_REV; extern const char* GIT_REV;
extern const char* GIT_BRANCH; extern const char* GIT_BRANCH;
@@ -160,12 +168,6 @@ extern "C" void app_main(void)
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
#endif #endif
#ifdef DEBUG_ENABLE_SYSINFO
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Device Info" + get_device_info() );
ESP_LOGD(TAG, "Device infos %s", get_device_info().c_str());
#endif
#endif //DEBUG_ENABLE_SYSINFO
ESP_LOGI(TAG, "\n\n\n\n\n"); // Add mark on log to see when it restarted ESP_LOGI(TAG, "\n\n\n\n\n"); // Add mark on log to see when it restarted
@@ -201,6 +203,20 @@ extern "C" void app_main(void)
LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated); LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason()); LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason());
#ifdef DEBUG_ENABLE_SYSINFO
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device Info : " + get_device_info() );
ESP_LOGD(TAG, "Device infos %s", get_device_info().c_str());
#endif
#endif //DEBUG_ENABLE_SYSINFO
#ifdef USE_HIMEM_IF_AVAILABLE
#ifdef DEBUG_HIMEM_MEMORY_CHECK
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Himem mem check : " + himem_memory_check() );
ESP_LOGD(TAG, "Himem mem check %s", himem_memory_check().c_str());
#endif
#endif
CheckIsPlannedReboot(); CheckIsPlannedReboot();
CheckOTAUpdate(); CheckOTAUpdate();
CheckUpdate(); CheckUpdate();