// 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