config SPIRAM_USE_MEMMAP
bool "Integrate RAM into ESP32 memory map"
config SPIRAM_USE_CAPS_ALLOC
- bool "Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPISRAM)"
- depends on TO_BE_DONE
+ bool "Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)"
config SPIRAM_USE_MALLOC
bool "Make RAM allocatable using malloc as well"
depends on TO_BE_DONE
{
esp_err_t err;
esp_setup_syscall_table();
+
+#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
+ esp_err_t r=esp_spiram_add_to_heapalloc();
+ if (r != ESP_OK) {
+ ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
+ abort();
+ }
+#endif
+
//Enable trace memory and immediately start trace.
#if CONFIG_ESP32_TRAX
#if CONFIG_ESP32_TRAX_TWOBANKS
bool esp_spiram_test();
+/**
+ * @brief Add the initialized SPI RAM to the heap allocator.
+ */
+esp_err_t esp_spiram_add_to_heapalloc();
+
+
/**
* @brief Get the size of the attached SPI RAM chip selected in menuconfig
*
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "soc/soc.h"
+#include "esp_heap_caps_init.h"
+#include "soc/soc_memory_layout.h"
#include "soc/dport_reg.h"
#include "rom/cache.h"
}
+esp_err_t esp_spiram_add_to_heapalloc()
+{
+ //Add entire external RAM region to heap allocator. Heap allocator knows the capabilities of this type of memory, so there's
+ //no need to explicitly specify them.
+ return heap_caps_add_region((intptr_t)SOC_EXTRAM_DATA_LOW, (intptr_t)SOC_EXTRAM_DATA_LOW + CONFIG_SPIRAM_SIZE-1);
+}
size_t esp_spiram_get_size()
{
void *mem[2];
res[0]=0; res[1]=0;
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
- mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
- mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
+ mem[0]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
+ mem[1]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
#else
mem[0]=(void*)0x3f800000;
mem[1]=(void*)0x3f800000+TSTSZ;
#endif
+ assert(mem[0]);
+ assert(mem[1]);
TaskHandle_t th[2];
err[0]=0; err[1]=0;
printf("Creating tasks\n");
void *mem[2];
res[0]=0; res[1]=0;
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
- mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
- mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
+ mem[0]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
+ mem[1]=heap_caps_malloc(TSTSZ, MALLOC_CAP_SPIRAM);
#else
mem[0]=(void*)0x3f800000;
mem[1]=(void*)0x3f800000+TSTSZ;
#endif
+ assert(mem[0]);
+ assert(mem[1]);
TaskHandle_t th[2];
const esp_partition_t* part = get_test_data_partition();
assert(part!=NULL);
#endif
}
+IRAM_ATTR TEST_CASE("Spiram memcmp weirdness at 80MHz", "[spiram][ignore]") {
+ char *mem1=malloc(0x10000);
+#if CONFIG_SPIRAM_USE_CAPS_ALLOC
+ char *mem2=heap_caps_malloc(0x10000, MALLOC_CAP_SPIRAM);
+#else
+ char *mem2=(void*)0x3f800000;
+#endif
+
+#if !CONFIG_SPIRAM_SPEED_80M
+ printf("**** WARNING **** Spi memory isn't running at 80MHz, so this test is somewhat meaningless.\n");
+#endif
+
+ printf("RAM: Got %p and %p\n", mem1, mem2);
+ assert(mem1);
+ assert(mem2);
+ for (int i=0; i<0x10000; i++) mem1[i]=i^0xAAAAAAAA;
+
+ for (int cycle=1; cycle<100; cycle++) {
+ memcpy(mem2, mem1, 0x10000);
+ if (memcmp(mem1, mem2, 0x10000)!=0) {
+ printf("Memcmp failed! Cycle %d\n", cycle);
+ for (int i=0; i<0x10000; i++) {
+ if (mem1[i]!=mem2[i]) {
+ printf("Found real difference at index %d: 0x%x vs 0x%x\n", i, mem1[i], mem2[i]);
+ break;
+ }
+ }
+ }
+ }
+}
+
+
#endif //CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MEMMAP
return NULL;
}
+/*
+ Default memory allocation implementation. Should return standard 8-bit memory. malloc() essentially resolves to this function.
+*/
+IRAM_ATTR void *heap_caps_malloc_default( size_t size )
+{
+ return heap_caps_malloc( size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL );
+}
+
+/*
+ Same for realloc()
+ Note: keep the logic in here the same as in heap_caps_malloc_default (or merge the two as soon as this gets more complex...)
+ */
+IRAM_ATTR void *heap_caps_realloc_default( void *ptr, size_t size )
+{
+ return heap_caps_realloc( ptr, size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL );
+}
+
+
/* Find the heap which belongs to ptr, or return NULL if it's
not in any heap.
heap_t *heaps_array = NULL;
for (int i = 0; i < num_heaps; i++) {
- if (heap_caps_match(&temp_heaps[i], MALLOC_CAP_8BIT)) {
+ if (heap_caps_match(&temp_heaps[i], MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL)) {
/* use the first DRAM heap which can fit the data */
heaps_array = multi_heap_malloc(temp_heaps[i].heap, sizeof(heap_t) * num_heaps);
if (heaps_array != NULL) {
bool heap_caps_match(const heap_t *heap, uint32_t caps);
+
+/*
+ Because we don't want to add _another_ known allocation method to the stack of functions to trace wrt memory tracing,
+ these are declared private. The newlib malloc()/realloc() implementation also calls these, so they are declared
+ separately in newlib/syscalls.c.
+*/
+void *heap_caps_realloc_default(void *p, size_t size);
+void *heap_caps_malloc_default(size_t size);
+
+
#ifdef __cplusplus
}
#endif
#include "freertos/task.h"
#include "soc/soc_memory_layout.h"
+#include "heap_private.h"
+
#define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH
static portMUX_TYPE trace_mux = portMUX_INITIALIZER_UNLOCKED;
_Static_assert(STACK_DEPTH >= 0 && STACK_DEPTH <= 10, "CONFIG_HEAP_TRACING_STACK_DEPTH must be in range 0-10");
+typedef enum {
+ TRACE_MALLOC_CAPS,
+ TRACE_MALLOC_DEFAULT
+} trace_malloc_mode_t;
+
+
void *__real_heap_caps_malloc(size_t size, uint32_t caps);
/* trace any 'malloc' event */
-static IRAM_ATTR __attribute__((noinline)) void *trace_malloc(size_t size, uint32_t caps)
+static IRAM_ATTR __attribute__((noinline)) void *trace_malloc(size_t size, uint32_t caps, trace_malloc_mode_t mode)
{
uint32_t ccount = get_ccount();
- void *p = __real_heap_caps_malloc(size, caps);
+ void *p;
+ if ( mode == TRACE_MALLOC_CAPS ) {
+ p = __real_heap_caps_malloc(size, caps);
+ } else { //TRACE_MALLOC_DEFAULT
+ p = heap_caps_malloc_default(size);
+ }
+
if (tracing && p != NULL) {
heap_trace_record_t rec = {
.address = p,
void * __real_heap_caps_realloc(void *p, size_t size, uint32_t caps);
/* trace any 'realloc' event */
-static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t size, uint32_t caps)
+static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t size, uint32_t caps, trace_malloc_mode_t mode)
{
void *callers[STACK_DEPTH];
uint32_t ccount = get_ccount();
get_call_stack(callers);
record_free(p, callers);
}
- void *r = __real_heap_caps_realloc(p, size, caps);
+ void *r;
+ if (mode == TRACE_MALLOC_CAPS ) {
+ r = __real_heap_caps_realloc(p, size, caps);
+ } else { //TRACE_MALLOC_DEFAULT
+ r = heap_caps_realloc_default(p, size);
+ }
if (tracing && r != NULL) {
get_call_stack(callers);
if (p != NULL) {
IRAM_ATTR void *__wrap_malloc(size_t size)
{
- return trace_malloc(size, MALLOC_CAP_8BIT);
+ return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void __wrap_free(void *p)
IRAM_ATTR void *__wrap_realloc(void *p, size_t size)
{
- return trace_realloc(p, size, MALLOC_CAP_8BIT);
+ return trace_realloc(p, size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void *__wrap_calloc(size_t nmemb, size_t size)
{
size = size * nmemb;
- void *result = trace_malloc(size, MALLOC_CAP_8BIT);
+ void *result = trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
if (result != NULL) {
memset(result, 0, size);
}
IRAM_ATTR void *__wrap_heap_caps_malloc(size_t size, uint32_t caps)
{
- return trace_malloc(size, caps);
+ return trace_malloc(size, caps, TRACE_MALLOC_CAPS);
}
IRAM_ATTR void __wrap_heap_caps_free(void *p) __attribute__((alias("__wrap_free")));
IRAM_ATTR void *__wrap_heap_caps_realloc(void *p, size_t size, uint32_t caps)
{
- return trace_realloc(p, size, caps);
+ return trace_realloc(p, size, caps, TRACE_MALLOC_CAPS);
}
#define MALLOC_CAP_PID5 (1<<7) ///< Memory must be mapped to PID5 memory space (PIDs are not currently used)
#define MALLOC_CAP_PID6 (1<<8) ///< Memory must be mapped to PID6 memory space (PIDs are not currently used)
#define MALLOC_CAP_PID7 (1<<9) ///< Memory must be mapped to PID7 memory space (PIDs are not currently used)
-#define MALLOC_CAP_SPISRAM (1<<10) ///< Memory must be in SPI SRAM
+#define MALLOC_CAP_SPIRAM (1<<10) ///< Memory must be in SPI RAM
+#define MALLOC_CAP_INTERNAL (1<<11) ///< Memory must be internal; specifically it should not disappear when flash/spiram cache is switched off
#define MALLOC_CAP_INVALID (1<<31) ///< Memory can't be used / list end marker
/**
*/
void *heap_caps_malloc(size_t size, uint32_t caps);
+
/**
* @brief Free memory previously allocated via heap_caps_malloc() or heap_caps_realloc().
*
#include "freertos/FreeRTOS.h"
#include "esp_heap_caps.h"
+
+/*
+ These contain the business logic for the malloc() and realloc() implementation. Because of heap tracing
+ wrapping reasons, we do not want these to be a public api, however, so they're not defined publicly.
+*/
+extern void *heap_caps_malloc_default( size_t size );
+extern void *heap_caps_realloc_default( void *ptr, size_t size );
+
+
void* IRAM_ATTR _malloc_r(struct _reent *r, size_t size)
{
- return heap_caps_malloc( size, MALLOC_CAP_8BIT );
+ return heap_caps_malloc_default( size );
}
void IRAM_ATTR _free_r(struct _reent *r, void* ptr)
void* IRAM_ATTR _realloc_r(struct _reent *r, void* ptr, size_t size)
{
- return heap_caps_realloc( ptr, size, MALLOC_CAP_8BIT );
+ return heap_caps_realloc_default( ptr, size );
}
void* IRAM_ATTR _calloc_r(struct _reent *r, size_t count, size_t size)
{
- void* result = heap_caps_malloc(count * size, MALLOC_CAP_8BIT);
+ void* result = heap_caps_malloc_default(count * size);
if (result) {
bzero(result, count * size);
}
*/
const soc_memory_type_desc_t soc_memory_types[] = {
//Type 0: Plain ole D-port RAM
- { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, false, false},
+ { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL, MALLOC_CAP_32BIT, 0 }, false, false},
//Type 1: Plain ole D-port RAM which has an alias on the I-port
//(This DRAM is also the region used by ROM during startup)
- { "D/IRAM", { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, true, true},
+ { "D/IRAM", { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, true, true},
//Type 2: IRAM
- { "IRAM", { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, false, false},
+ { "IRAM", { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT|MALLOC_CAP_INTERNAL, 0, 0 }, false, false},
//Type 3-8: PID 2-7 IRAM
- { "PID2IRAM", { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
- { "PID3IRAM", { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
- { "PID4IRAM", { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
- { "PID5IRAM", { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
- { "PID6IRAM", { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
- { "PID7IRAM", { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
+ { "PID2IRAM", { MALLOC_CAP_PID2|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
+ { "PID3IRAM", { MALLOC_CAP_PID3|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
+ { "PID4IRAM", { MALLOC_CAP_PID4|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
+ { "PID5IRAM", { MALLOC_CAP_PID5|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
+ { "PID6IRAM", { MALLOC_CAP_PID6|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
+ { "PID7IRAM", { MALLOC_CAP_PID7|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false, false},
//Type 9-14: PID 2-7 DRAM
- { "PID2DRAM", { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
- { "PID3DRAM", { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
- { "PID4DRAM", { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
- { "PID5DRAM", { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
- { "PID6DRAM", { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
- { "PID7DRAM", { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
+ { "PID2DRAM", { MALLOC_CAP_PID2|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
+ { "PID3DRAM", { MALLOC_CAP_PID3|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
+ { "PID4DRAM", { MALLOC_CAP_PID4|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
+ { "PID5DRAM", { MALLOC_CAP_PID5|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
+ { "PID6DRAM", { MALLOC_CAP_PID6|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
+ { "PID7DRAM", { MALLOC_CAP_PID7|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false, false},
//Type 15: SPI SRAM data
- { "SPISRAM", { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, false, false},
+ { "SPIRAM", { MALLOC_CAP_SPIRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, false, false},
};
const size_t soc_memory_type_count = sizeof(soc_memory_types)/sizeof(soc_memory_type_desc_t);
from low to high start address.
*/
const soc_memory_region_t soc_memory_regions[] = {
- { 0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available
+ { 0x3F800000, 0x400000, 15, 0}, //SPI SRAM, if available
{ 0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code
{ 0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- if BT is enabled, used as BT HW shared memory
{ 0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- if BT is enabled, used data memory for BT ROM functions.
#endif
#endif
-#if 1 // SPI ram not supported yet
- { 0x3f800000, 0x3f820000 }, //SPI SRAM not installed
-#endif
+ { 0x3f800000, 0x3fC00000 }, //SPI RAM gets added later if needed, in spiram.c; reserve it for now
};
const size_t soc_reserved_region_count = sizeof(soc_reserved_regions)/sizeof(soc_reserved_region_t);