esp32: support to use hspi to output clock for 4MB PSRAM

Resolves https://github.com/espressif/esp-idf/issues/2128.
This commit is contained in:
Michael (XIAO Xufeng) 2018-09-27 01:48:22 +08:00
parent 9b5d0f3322
commit 20a666fe03
4 changed files with 144 additions and 101 deletions

View file

@ -98,8 +98,9 @@ choice SPIRAM_SPEED
2. Flash SPI running at 80Mhz and RAM SPI running at 40Mhz
3. Flash SPI running at 80Mhz and RAM SPI running at 80Mhz
Note: If the third mode(80Mhz+80Mhz) is enabled, the VSPI port will be occupied by the system.
Application code should never touch VSPI hardware in this case. The option to select
Note: If the third mode(80Mhz+80Mhz) is enabled for SPI RAM of type 32MBit, one of the HSPI/VSPI host will
be occupied by the system. Which SPI host to use can be selected by the config item SPIRAM_OCCUPY_SPI_HOST.
Application code should never touch HSPI/VSPI hardware in this case. The option to select
80MHz will only be visible if the flash SPI speed is also 80MHz. (ESPTOOLPY_FLASHFREQ_80M is true)
config SPIRAM_SPEED_40M
@ -213,6 +214,20 @@ config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
in PSRAM instead of internal memory, and placed most of variables of lwip,net802.11,pp,bluedroid library
to external memory defaultly.
choice SPIRAM_OCCUPY_SPI_HOST
prompt "SPI host to use for 32MBit PSRAM"
default SPIRAM_OCCUPY_VSPI_HOST
depends on SPIRAM_SPEED_80M
help
When both flash and PSRAM is working under 80MHz, and the PSRAM is of type 32MBit, one of the HSPI/VSPI
host will be used to output the clock. Select which one to use here.
config SPIRAM_OCCUPY_HSPI_HOST
bool "HSPI host (SPI2)"
config SPIRAM_OCCUPY_VSPI_HOST
bool "VSPI host (SPI3)"
endchoice
endmenu
config MEMMAP_TRACEMEM

View file

@ -32,6 +32,7 @@
#include "driver/periph_ctrl.h"
#include "xtensa/core-macros.h"
#include "bootloader_clock.h"
#include "driver/spi_common.h"
/* Number of cycles to wait from the 32k XTAL oscillator to consider it running.
* Larger values increase startup delay. Smaller values may cause false positive
@ -288,11 +289,16 @@ void esp_perip_clk_init(void)
DPORT_SPI_DMA_CLK_EN;
#if CONFIG_SPIRAM_SPEED_80M
//80MHz SPIRAM uses SPI3 as well; it's initialized before this is called. Because it is used in
//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in
//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs'
//in a state where it outputs a continuous 80MHz signal. Mask its bit here because we should
//not modify that state, regardless of what we calculated earlier.
if (!spicommon_periph_in_use(HSPI_HOST)) {
common_perip_clk &= ~DPORT_SPI2_CLK_EN;
}
if (!spicommon_periph_in_use(VSPI_HOST)) {
common_perip_clk &= ~DPORT_SPI3_CLK_EN;
}
#endif
/* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock,

View file

@ -98,6 +98,27 @@ typedef enum {
#define _SPI_80M_CLK_DIV 1
#define _SPI_40M_CLK_DIV 2
//For 4MB PSRAM, we need one more SPI host, select which one to use by kconfig
#ifdef CONFIG_SPIRAM_OCCUPY_HSPI_HOST
#define PSRAM_SPI_MODULE PERIPH_HSPI_MODULE
#define PSRAM_SPI_HOST HSPI_HOST
#define PSRAM_CLK_SIGNAL HSPICLK_OUT_IDX
#define PSRAM_SPI_NUM PSRAM_SPI_2
#define PSRAM_SPICLKEN DPORT_SPI2_CLK_EN
#elif defined CONFIG_SPIRAM_OCCUPY_VSPI_HOST
#define PSRAM_SPI_MODULE PERIPH_VSPI_MODULE
#define PSRAM_SPI_HOST VSPI_HOST
#define PSRAM_CLK_SIGNAL VSPICLK_OUT_IDX
#define PSRAM_SPI_NUM PSRAM_SPI_3
#define PSRAM_SPICLKEN DPORT_SPI3_CLK_EN
#else //set to SPI avoid HSPI and VSPI being used
#define PSRAM_SPI_MODULE PERIPH_SPI_MODULE
#define PSRAM_SPI_HOST SPI_HOST
#define PSRAM_CLK_SIGNAL SPICLK_OUT_IDX
#define PSRAM_SPI_NUM PSRAM_SPI_1
#define PSRAM_SPICLKEN DPORT_SPI01_CLK_EN
#endif
static const char* TAG = "psram";
typedef enum {
PSRAM_SPI_1 = 0x1,
@ -621,27 +642,27 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
} else if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
s_clk_mode = PSRAM_CLK_MODE_DCLK;
if (mode == PSRAM_CACHE_F80M_S80M) {
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, VSPI port will be
occupied by the system.
Application code should never touch VSPI hardware in this case. We try to stop applications
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, one of HSPI/VSPI port will be
occupied by the system (according to kconfig).
Application code should never touch HSPI/VSPI hardware in this case. We try to stop applications
from doing this using the drivers by claiming the port for ourselves */
periph_module_enable(PERIPH_VSPI_MODULE);
bool r=spicommon_periph_claim(VSPI_HOST, "psram");
periph_module_enable(PSRAM_SPI_MODULE);
bool r=spicommon_periph_claim(PSRAM_SPI_HOST, "psram");
if (!r) {
return ESP_ERR_INVALID_STATE;
}
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_CLK_IO, PSRAM_CLK_SIGNAL, 0, 0);
//use spi3 clock,but use spi1 data/cs wires
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_NUM), 32 << 24);
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_NUM), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_NUM), SPI_FLASH_READ_M);
uint32_t spi_status;
while (1) {
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_NUM));
if (spi_status != 0 && spi_status != 1) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, PSRAM_SPICLKEN);
break;
}
}

View file

@ -47,7 +47,7 @@ ESP-IDF fully supports integrating external memory use into your applications. E
* Initialize RAM, add it to the capability allocator and add memory to the pool of RAM that can be returned by ``malloc()``. This allows
any application to use the external RAM without having to rewrite the code to use ``heap_caps_malloc``.
* Initialize RAM, use a region start from 0x3F800000 for storing zero initialized data(BSS segment) of lwip,net802.11,pp,bluedroid library
by enabling :ref: `CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` in menuconfig,this way can save some internal memorybecause the BSS segment
by enabling :ref: `CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` in menuconfig, this way can save some internal memorybecause the BSS segment
originally stored in internal memoryand the rest of external RAM can be add the capability allocator and add memory to the pool of RAM as above way
All these options can be selected from the menuconfig menu.
@ -75,6 +75,7 @@ The use of external RAM has a few restrictions:
them is defined by linkfile, the :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND` can't handle this situation,if you want to enable :ref:
`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` the :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND` will be disabled, and if initialize SPIRAM failed,the system
will invoke abort.
* External RAM of 4MBit (test up to know) has to be used with one of HSPI/VSPI occupied under 80MHz. Select which SPI host to be used by :ref:`CONFIG_SPIRAM_OCCUPY_SPI_HOST`.
Because there are a fair few situations that have a specific need for internal memory, but it is also possible to use malloc() to exhaust
internal memory, there is a pool reserved specifically for requests that cannot be resolved from external memory; allocating task