diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 6b661bd8e..bafb280ee 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -155,9 +155,10 @@ config MEMMAP_SPIRAM_ENABLE RAM chip. This only works correctly with v1 (post Feb 2017) silicon. +if MEMMAP_SPIRAM_ENABLE + choice MEMMAP_SPIRAM_TYPE prompt "Type of SPI RAM chip in use" - depends on MEMMAP_SPIRAM_ENABLE default MEMMAP_SPIRAM_TYPE_ESPPSRAM32 config MEMMAP_SPIRAM_TYPE_ESPPSRAM32 @@ -165,16 +166,21 @@ config MEMMAP_SPIRAM_TYPE_ESPPSRAM32 endchoice +config MEMMAP_SPIRAM_SIZE + int + default 4194304 if MEMMAP_SPIRAM_ENABLE && MEMMAP_SPIRAM_TYPE_ESPPSRAM32 + default 0 + help + Size of external SPI RAM + config MEMMAP_SPIRAM_TEST bool "On SPI RAM init, do a quick memory test" - depends on MEMMAP_SPIRAM_ENABLE default "n" help This does a quick memory test on boot-up. This takes about a second for 4MiB of SPI RAM. config MEMMAP_SPIRAM_ENABLE_MALLOC bool "malloc() can also allocate in SPI SRAM" - depends on MEMMAP_SPIRAM_ENABLE default "n" help If enabled, malloc() will return pointers to both internal as well as external @@ -187,6 +193,8 @@ config MEMMAP_SPIRAM_ALLOC_LIMIT_INTERNAL depends on MEMMAP_SPIRAM_ENABLE_MALLOC default 1024 +endif + choice NUMBER_OF_MAC_ADDRESS_GENERATED_FROM_EFUSE bool "Number of MAC address generated from the hardware MAC address in efuse" default FOUR_MAC_ADDRESS_FROM_EFUSE diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 0a81b487e..18adeb879 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -95,10 +95,10 @@ extern volatile int port_xSchedulerRunning[2]; static const char* TAG = "cpu_start"; -#if CONFIG_FREERTOS_UNICORE -#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL -#else +#if CONFIG_MEMMAP_SMP #define PSRAM_MODE PSRAM_VADDR_MODE_EVENODD +#else +#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL #endif /* diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 169f9b195..63db225e1 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -230,7 +230,9 @@ void heap_alloc_caps_init() { disable_mem_region(&_data_start, &_heap_start); //DRAM used by bss/data static variables disable_mem_region(&_init_start, &_iram_text_end); //IRAM used by code disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region +#ifdef CONFIG_MEMMAP_SMP disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region +#endif /* Warning: The ROM stack is located in the 0x3ffe0000 area. We do not specifically disable that area here because after the scheduler has started, the ROM stack is not used anymore by anything. We handle it instead by not allowing @@ -270,10 +272,13 @@ void heap_alloc_caps_init() { #endif #if CONFIG_MEMMAP_SPIRAM_ENABLE + if (CONFIG_MEMMAP_SPIRAM_SIZE < 0x400000) { + disable_mem_region((void*)0x3f800000+CONFIG_MEMMAP_SPIRAM_SIZE, (void*)0x3fc00000); //Disable unused SPI SRAM region + } #if CONFIG_MEMMAP_SPIRAM_TEST - if (!test_spiram(4*1024*1024)) abort(); + if (!test_spiram(CONFIG_MEMMAP_SPIRAM_SIZE)) abort(); #endif -#else +#else //!CONFIG_MEMMAP_SPIRAM_ENABLE disable_mem_region((void*)0x3f800000, (void*)0x3fc00000); //SPI SRAM not installed #endif diff --git a/components/esp32/include/esp_psram.h b/components/esp32/include/esp_psram.h index bee36e1ad..2e91449fb 100644 --- a/components/esp32/include/esp_psram.h +++ b/components/esp32/include/esp_psram.h @@ -1,3 +1,18 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + #ifndef _PSRAM_H #define _PSRAM_H #include "soc/spi_reg.h" @@ -10,12 +25,30 @@ typedef enum { PSRAM_CACHE_MAX, } psram_cache_mode_t; + +/* +See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes. + +Important is that NORMAL works with the app CPU cache disabled, but gives huge cache coherency +issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency +issues but cannot be used when the app CPU cache is disabled. +*/ typedef enum { - PSRAM_VADDR_MODE_NORMAL=0, - PSRAM_VADDR_MODE_LOWHIGH, - PSRAM_VADDR_MODE_EVENODD, + PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access + PSRAM_VADDR_MODE_LOWHIGH, ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M + PSRAM_VADDR_MODE_EVENODD, ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones. } psram_vaddr_mode_t; +/** + * @brief psram cache enable function + * + * Esp-idf uses this to initialize cache for psram, mapping it into the main memory + * address space. + * + * @param mode SPI mode to access psram in + * @param vaddrmode Mode the psram cache works in. + * @return ESP_OK on success + */ esp_err_t psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode); #endif diff --git a/components/esp32/psram.c b/components/esp32/psram.c index 29c615562..6cc6b26f0 100644 --- a/components/esp32/psram.c +++ b/components/esp32/psram.c @@ -270,98 +270,9 @@ static int psram_cmd_config(psram_spi_num_t spiNum, psram_cmd_t* pInData) return 0; } -//read psram data in fast read mode -static void psram_read_data(psram_spi_num_t spiNum,uint32_t* dst,uint32_t src,uint32_t len) -{ - uint32_t addr = 0; - uint32_t dummy_bits = 0; - psram_cmd_t pDat; - addr = (PSRAM_FAST_READ <<24) | src; - switch(g_PsramMode){ - case PSRAM_CACHE_F80M_S80M: - dummy_bits = 4+extra_dummy; - pDat.cmdBitLen = 0; - break; - case PSRAM_CACHE_F80M_S40M: - case PSRAM_CACHE_F40M_S40M: - default: - dummy_bits = 4+extra_dummy; - pDat.cmdBitLen = 2; - break; - } - pDat.cmd = 0; - pDat.addr = &addr; - pDat.addrBitLen = 4*8; - pDat.txDataBitLen = 0; - pDat.txData = NULL; - pDat.rxDataBitLen = len*8 ; - pDat.rxData = dst; - pDat.dummyBitLen = dummy_bits; - psram_cmd_config(spiNum,&pDat); - psram_clear_spi_fifo(spiNum); - psram_recv_start(spiNum,pDat.rxData,pDat.rxDataBitLen/8, PSRAM_CMD_QPI); -} -//read psram data in fast read quad mode -static void psram_read_data_quad(psram_spi_num_t spiNum,uint32_t* dst,uint32_t src,uint32_t len) -{ - uint32_t addr = (PSRAM_FAST_READ_QUAD <<24) | src; - uint32_t dummy_bits = 0; - psram_cmd_t pDat; - switch(g_PsramMode){ - case PSRAM_CACHE_F80M_S80M: - dummy_bits = 6+extra_dummy; - pDat.cmdBitLen = 0; - break; - case PSRAM_CACHE_F80M_S40M: - case PSRAM_CACHE_F40M_S40M: - default: - dummy_bits = 6+extra_dummy; - pDat.cmdBitLen = 2; - break; - } - pDat.cmd = 0; - pDat.addr = &addr; - pDat.addrBitLen = 4*8; - pDat.txDataBitLen = 0; - pDat.txData = NULL; - pDat.rxDataBitLen = len*8 ; - pDat.rxData = dst; - pDat.dummyBitLen = dummy_bits; - psram_cmd_config(spiNum,&pDat); - psram_clear_spi_fifo(spiNum); - psram_recv_start(spiNum,pDat.rxData,pDat.rxDataBitLen/8, PSRAM_CMD_QPI); -} - -//write data to psram -static void psram_write_data(uint32_t dst,uint32_t* src,uint32_t len) -{ - uint32_t addr = (PSRAM_QUAD_WRITE <<24) | dst; - psram_cmd_t pDat; - int dummy_bits = 0; - switch(g_PsramMode){ - case PSRAM_CACHE_F80M_S80M: - dummy_bits = 0 + 0; - pDat.cmdBitLen = 0; - break; - case PSRAM_CACHE_F80M_S40M: - case PSRAM_CACHE_F40M_S40M: - default: - dummy_bits = 0 + 0; - pDat.cmdBitLen = 2; - break; - } - pDat.cmd = 0; - pDat.addr = &addr; - pDat.addrBitLen = 32; - pDat.txData = src; - pDat.txDataBitLen = len*8; - pDat.rxData = NULL; - pDat.rxDataBitLen = 0; - pDat.dummyBitLen = dummy_bits; - psram_cmd_config(PSRAM_SPI_1, &pDat); - psram_cmd_start(PSRAM_SPI_1, PSRAM_CMD_QPI); -} +//The following helper functions aren't used in this code right now, but may be useful for other SPI RAM chips. +#if 0 static void psram_dma_cmd_write_config(uint32_t dst, uint32_t len, uint32_t dummy_bits) { @@ -417,40 +328,6 @@ static void psram_dma_qio_read_config(psram_spi_num_t spiNum, uint32_t src, uint // psram_clear_spi_fifo(spiNum); } -//read psram id -static void psram_read_id(uint32_t* dev_id) -{ - psram_spi_num_t spiNum = PSRAM_SPI_1; -// psram_set_basic_write_mode(spiNum); -// psram_set_basic_read_mode(spiNum); - uint32_t addr = (PSRAM_DEVICE_ID <<24) | 0; - uint32_t dummy_bits = 0; - psram_cmd_t pDat; - switch(g_PsramMode){ - case PSRAM_CACHE_F80M_S80M: - dummy_bits = 0+extra_dummy; - pDat.cmdBitLen = 0; - break; - case PSRAM_CACHE_F80M_S40M: - case PSRAM_CACHE_F40M_S40M: - default: - dummy_bits = 0+extra_dummy; - pDat.cmdBitLen = 2; //this two bits is used for delay one byte in qio mode - break; - } - pDat.cmd = 0; - pDat.addr = &addr; - pDat.addrBitLen = 4*8; - pDat.txDataBitLen = 0; - pDat.txData = NULL; - pDat.rxDataBitLen = 4*8 ; - pDat.rxData = dev_id; - pDat.dummyBitLen = dummy_bits; - psram_cmd_config(spiNum,&pDat); - psram_clear_spi_fifo(spiNum); - psram_recv_start(spiNum,pDat.rxData,pDat.rxDataBitLen/8, PSRAM_CMD_SPI); -} - //switch psram burst length(32 bytes or 1024 bytes) //datasheet says it should be 1024 bytes by default //but they sent us a correction doc and told us it is 32 bytes for these samples @@ -498,6 +375,7 @@ static void psram_reset_mode(psram_spi_num_t spiNum) psram_cmd_config(spiNum, &pDat); psram_cmd_start(spiNum, PSRAM_CMD_QPI); } + //exit QPI mode(set back to SPI mode) static void psram_disable_qio_mode(psram_spi_num_t spiNum) { @@ -526,33 +404,6 @@ static void psram_disable_qio_mode(psram_spi_num_t spiNum) psram_cmd_config(spiNum, &pDat); psram_cmd_start(spiNum, PSRAM_CMD_QPI); } -//enter QPI mode -static void IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spiNum) -{ - psram_cmd_t pDat; - switch(g_PsramMode){ - case PSRAM_CACHE_F80M_S80M: - pDat.cmd = PSRAM_ENTER_QMODE; - pDat.cmdBitLen = 8; - break; - case PSRAM_CACHE_F80M_S40M: - case PSRAM_CACHE_F40M_S40M: - default: - pDat.cmd = 0x400d; - pDat.cmdBitLen = 10; - break; - } - pDat.addr = 0; - pDat.addrBitLen = 0; - pDat.txData = NULL; - pDat.txDataBitLen = 0; - pDat.rxData = NULL; - pDat.rxDataBitLen = 0; - pDat.dummyBitLen = 0; - psram_cmd_config(spiNum, &pDat); - psram_cmd_start(spiNum, PSRAM_CMD_SPI); -} - static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode) { @@ -598,6 +449,72 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode) } +#endif + +//read psram id +static void psram_read_id(uint32_t* dev_id) +{ + psram_spi_num_t spiNum = PSRAM_SPI_1; +// psram_set_basic_write_mode(spiNum); +// psram_set_basic_read_mode(spiNum); + uint32_t addr = (PSRAM_DEVICE_ID <<24) | 0; + uint32_t dummy_bits = 0; + psram_cmd_t pDat; + switch(g_PsramMode){ + case PSRAM_CACHE_F80M_S80M: + dummy_bits = 0+extra_dummy; + pDat.cmdBitLen = 0; + break; + case PSRAM_CACHE_F80M_S40M: + case PSRAM_CACHE_F40M_S40M: + default: + dummy_bits = 0+extra_dummy; + pDat.cmdBitLen = 2; //this two bits is used for delay one byte in qio mode + break; + } + pDat.cmd = 0; + pDat.addr = &addr; + pDat.addrBitLen = 4*8; + pDat.txDataBitLen = 0; + pDat.txData = NULL; + pDat.rxDataBitLen = 4*8 ; + pDat.rxData = dev_id; + pDat.dummyBitLen = dummy_bits; + psram_cmd_config(spiNum,&pDat); + psram_clear_spi_fifo(spiNum); + psram_recv_start(spiNum,pDat.rxData,pDat.rxDataBitLen/8, PSRAM_CMD_SPI); +} + + +//enter QPI mode +static void IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spiNum) +{ + psram_cmd_t pDat; + switch(g_PsramMode){ + case PSRAM_CACHE_F80M_S80M: + pDat.cmd = PSRAM_ENTER_QMODE; + pDat.cmdBitLen = 8; + break; + case PSRAM_CACHE_F80M_S40M: + case PSRAM_CACHE_F40M_S40M: + default: + pDat.cmd = 0x400d; + pDat.cmdBitLen = 10; + break; + } + pDat.addr = 0; + pDat.addrBitLen = 0; + pDat.txData = NULL; + pDat.txDataBitLen = 0; + pDat.rxData = NULL; + pDat.rxDataBitLen = 0; + pDat.dummyBitLen = 0; + psram_cmd_config(spiNum, &pDat); + psram_cmd_start(spiNum, PSRAM_CMD_SPI); +} + + + //spi param init for psram void IRAM_ATTR psram_spi_init(psram_spi_num_t spiNum,psram_cache_mode_t mode) { @@ -644,7 +561,9 @@ void IRAM_ATTR psram_spi_init(psram_spi_num_t spiNum,psram_cache_mode_t mode) //psram gpio init , different working frequency we have different solutions esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init { - WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG,BIT16|BIT17);//DISALBE OUPUT FOR IO16/17 + WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG,BIT16|BIT17);//DISABLE OUPUT FOR IO16/17 + + assert(mode==PSRAM_CACHE_F40M_S40M); //we don't support any other mode for now. g_PsramMode = mode; diff --git a/components/esp32/test/test_psram_silicon_bug.c b/components/esp32/test/test_psram_silicon_bug.c index 73e342e24..3a2e3843e 100644 --- a/components/esp32/test/test_psram_silicon_bug.c +++ b/components/esp32/test/test_psram_silicon_bug.c @@ -19,6 +19,7 @@ This code triggers a psram-related silicon bug in rev0 silicon. The bug is fixed #include #include #include "rom/ets_sys.h" +#include "esp_heap_alloc_caps.h" typedef struct { @@ -38,12 +39,12 @@ static int isValidPtr(void *ptr) { } -void test_weird_corruption() { - //crashes +int test_weird_corruption() { + int err=0; xlumpinfo_t *marked = (xlumpinfo_t*)0x3fff2824; size_t i, num_marked = 0, num_unmarked = 0; - int is_marked = 0, mark_end = 0; +// int is_marked = 0, mark_end = 0; xlumpinfo_t *lump = xlumpinfo; int x; @@ -81,20 +82,43 @@ void test_weird_corruption() { ets_printf("%08x ", ((uint32_t*)&xlumpinfo[x-1])[j]); } ets_printf("\n"); + err++; } } + return err; } TEST_CASE("PSram big in rev0 silicon (Doom bug)", "[psram]") { - int i; + int i, r=0; + xlumpinfo_t *p; +#if MEMMAP_SMP + printf("WARNING\n"); + printf("WARNING - This bug only shows up when MEMMAP_SMP is disabled. You have it enabled now, so the test will erroneously pass.\n"); + printf("WARNING\n"); +#endif +#if !MEMMAP_SPIRAM_ENABLE + printf("WARNING\n"); + printf("WARNING - This test needs psram enabled. You don't seem to have that; the test is likely to crash.\n"); + printf("WARNING\n"); +#endif printf("Stack ptr %p\n", &i); + p=pvPortMallocCaps(sizeof(xlumpinfo_t)*5600, MALLOC_CAP_SPIRAM); + xlumpinfo=p; + //Bug seems to only trigger when address ends in 2C + while (((int)xlumpinfo&0xff)!=0x2c) xlumpinfo=(xlumpinfo_t*)(((char*)xlumpinfo)+1); + printf("lumpinfo ptr %p\n", xlumpinfo); + for (i=0; i