Merge branch 'feature/ext_ram_allocatable_using_heap_alloc_cap' into 'master'

Make external RAM allocatable using heap_alloc_cap

See merge request !1226
This commit is contained in:
Ivan Grokhotkov 2017-09-14 14:28:12 +08:00
commit 2a0e6c40d0
14 changed files with 164 additions and 45 deletions

View file

@ -57,8 +57,7 @@ choice SPIRAM_USE
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

View file

@ -174,7 +174,10 @@ void esp_perip_clk_init(void)
DPORT_LEDC_CLK_EN |
DPORT_UHCI1_CLK_EN |
DPORT_TIMERGROUP1_CLK_EN |
//80MHz SPIRAM uses SPI2 as well; it's initialized before this is called. Do not disable the clock for that if this is enabled.
#if !CONFIG_SPIRAM_SPEED_80M
DPORT_SPI_CLK_EN_2 |
#endif
DPORT_PWM0_CLK_EN |
DPORT_I2C_EXT1_CLK_EN |
DPORT_CAN_CLK_EN |
@ -196,6 +199,7 @@ void esp_perip_clk_init(void)
DPORT_WIFI_CLK_SDIO_HOST_EN |
DPORT_WIFI_CLK_EMAC_EN;
}
/* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock,
* the current is not reduced when disable I2S clock.
*/

View file

@ -255,6 +255,15 @@ void start_cpu0_default(void)
{
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

View file

@ -39,6 +39,12 @@ esp_err_t esp_spiram_init();
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
*

View file

@ -28,6 +28,8 @@ we add more types of external RAM memory, this can be made into a more intellige
#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"
@ -120,6 +122,12 @@ esp_err_t esp_spiram_init()
}
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()
{

View file

@ -94,9 +94,6 @@ typedef enum {
static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
//For now, we only use F40M + S40M, and we don't have to go through gpio matrix
#define ENABLE_GPIO_MATRIX_SPI 1
/* dummy_len_plus values defined in ROM for SPI flash configuration */
extern uint8_t g_rom_spiflash_dummy_len_plus[];
@ -528,9 +525,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
}
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_SETUP_M);
#if ENABLE_GPIO_MATRIX_SPI
psram_gpio_config(mode);
#endif
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO));
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], 2);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], 2);

View file

@ -56,12 +56,15 @@ TEST_CASE("Spiram cache flush on mmap", "[spiram][ignore]")
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);
printf("Allocating SPI RAM chunk...\n");
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");
@ -99,12 +102,15 @@ TEST_CASE("Spiram cache flush on write/read", "[spiram][ignore]")
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);
printf("Allocating SPI RAM chunk...\n");
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);
@ -138,4 +144,40 @@ TEST_CASE("Spiram cache flush on write/read", "[spiram][ignore]")
#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

View file

@ -133,6 +133,24 @@ IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps )
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.

View file

@ -180,7 +180,7 @@ void heap_caps_init()
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) {

View file

@ -48,6 +48,16 @@ extern SLIST_HEAD(registered_heap_ll, heap_t_) registered_heaps;
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

View file

@ -25,6 +25,8 @@
#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;
@ -303,13 +305,25 @@ static IRAM_ATTR __attribute__((noinline)) void get_call_stack(void **callers)
_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,
@ -338,7 +352,7 @@ static IRAM_ATTR __attribute__((noinline)) void trace_free(void *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();
@ -346,7 +360,12 @@ static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t s
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) {
@ -370,7 +389,7 @@ static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t s
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)
@ -380,13 +399,13 @@ 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);
}
@ -395,12 +414,12 @@ IRAM_ATTR void *__wrap_calloc(size_t nmemb, size_t 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);
}

View file

@ -30,7 +30,8 @@
#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
/**
@ -48,6 +49,7 @@
*/
void *heap_caps_malloc(size_t size, uint32_t caps);
/**
* @brief Free memory previously allocated via heap_caps_malloc() or heap_caps_realloc().
*

View file

@ -23,9 +23,18 @@
#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)
@ -35,12 +44,12 @@ 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);
}

View file

@ -40,28 +40,28 @@ The prioritised capabilities work roughly like this:
*/
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);
@ -73,7 +73,7 @@ Because of requirements in the coalescing code which merges adjacent regions, th
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.
@ -170,9 +170,7 @@ const soc_reserved_region_t soc_reserved_regions[] = {
#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);