mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 04:34:31 +02:00
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:
@@ -98,9 +98,10 @@ choice SPIRAM_SPEED
|
|||||||
2. Flash SPI running at 80Mhz and RAM SPI running at 40Mhz
|
2. Flash SPI running at 80Mhz and RAM SPI running at 40Mhz
|
||||||
3. Flash SPI running at 80Mhz and RAM SPI running at 80Mhz
|
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.
|
Note: If the third mode(80Mhz+80Mhz) is enabled for SPI RAM of type 32MBit, one of the HSPI/VSPI host will
|
||||||
Application code should never touch VSPI hardware in this case. The option to select
|
be occupied by the system. Which SPI host to use can be selected by the config item SPIRAM_OCCUPY_SPI_HOST.
|
||||||
80MHz will only be visible if the flash SPI speed is also 80MHz. (ESPTOOLPY_FLASHFREQ_80M is true)
|
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
|
config SPIRAM_SPEED_40M
|
||||||
bool "40MHz clock speed"
|
bool "40MHz clock speed"
|
||||||
@@ -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
|
in PSRAM instead of internal memory, and placed most of variables of lwip,net802.11,pp,bluedroid library
|
||||||
to external memory defaultly.
|
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
|
endmenu
|
||||||
|
|
||||||
config MEMMAP_TRACEMEM
|
config MEMMAP_TRACEMEM
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include "driver/periph_ctrl.h"
|
#include "driver/periph_ctrl.h"
|
||||||
#include "xtensa/core-macros.h"
|
#include "xtensa/core-macros.h"
|
||||||
#include "bootloader_clock.h"
|
#include "bootloader_clock.h"
|
||||||
|
#include "driver/spi_common.h"
|
||||||
|
|
||||||
/* Number of cycles to wait from the 32k XTAL oscillator to consider it running.
|
/* 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
|
* 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;
|
DPORT_SPI_DMA_CLK_EN;
|
||||||
|
|
||||||
#if CONFIG_SPIRAM_SPEED_80M
|
#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'
|
//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
|
//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.
|
//not modify that state, regardless of what we calculated earlier.
|
||||||
common_perip_clk &= ~DPORT_SPI3_CLK_EN;
|
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
|
#endif
|
||||||
|
|
||||||
/* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock,
|
/* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock,
|
||||||
|
@@ -98,6 +98,27 @@ typedef enum {
|
|||||||
#define _SPI_80M_CLK_DIV 1
|
#define _SPI_80M_CLK_DIV 1
|
||||||
#define _SPI_40M_CLK_DIV 2
|
#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";
|
static const char* TAG = "psram";
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PSRAM_SPI_1 = 0x1,
|
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)) {
|
} else if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
|
||||||
s_clk_mode = PSRAM_CLK_MODE_DCLK;
|
s_clk_mode = PSRAM_CLK_MODE_DCLK;
|
||||||
if (mode == PSRAM_CACHE_F80M_S80M) {
|
if (mode == PSRAM_CACHE_F80M_S80M) {
|
||||||
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, VSPI port will be
|
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, one of HSPI/VSPI port will be
|
||||||
occupied by the system.
|
occupied by the system (according to kconfig).
|
||||||
Application code should never touch VSPI hardware in this case. We try to stop applications
|
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 */
|
from doing this using the drivers by claiming the port for ourselves */
|
||||||
periph_module_enable(PERIPH_VSPI_MODULE);
|
periph_module_enable(PSRAM_SPI_MODULE);
|
||||||
bool r=spicommon_periph_claim(VSPI_HOST, "psram");
|
bool r=spicommon_periph_claim(PSRAM_SPI_HOST, "psram");
|
||||||
if (!r) {
|
if (!r) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
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
|
//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
|
//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.
|
//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_ADDR_REG(PSRAM_SPI_NUM), 32 << 24);
|
||||||
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
|
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_3), SPI_FLASH_READ_M);
|
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_NUM), SPI_FLASH_READ_M);
|
||||||
uint32_t spi_status;
|
uint32_t spi_status;
|
||||||
while (1) {
|
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) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
* 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``.
|
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
|
* 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 memory,because the BSS segment
|
by enabling :ref: `CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` in menuconfig, this way can save some internal memory,because the BSS segment
|
||||||
originally stored in internal memory,and the rest of external RAM can be add the capability allocator and add memory to the pool of RAM as above way
|
originally stored in internal memory,and 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.
|
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:
|
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
|
`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.
|
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
|
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
|
internal memory, there is a pool reserved specifically for requests that cannot be resolved from external memory; allocating task
|
||||||
|
Reference in New Issue
Block a user