feature(psram): add support for 64MBit psram of 1.8v and 3.3v.
1. Add reading psram EID. 2. Configure different clock mode for different EID. 3. add API to get psram size and voltage. 4. Remove unnecessary VSPI claim. For 32MBit@1.8V and 64MBit@3.3V psram, there should be 2 extra clock cycles after CS get high level. For 64MBit@1.8 psram, we can just use standard SPI protocol to drive the psram. We also need to increase the HOLD time for CS in this case. EID for psram: 32MBit 1.8v: 0x20 64MBit 1.8v: 0x26 64MBit 3.3v: 0x46
This commit is contained in:
parent
3cf2f09469
commit
b26b1389de
4 changed files with 275 additions and 125 deletions
|
@ -18,8 +18,37 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef enum {
|
||||
ESP_SPIRAM_VOLT_3V3 = 0, /*!< SPI RAM voltage is 3.3v */
|
||||
ESP_SPIRAM_VOLT_1V8 = 1, /*!< SPI RAM voltage is 1.8v */
|
||||
ESP_SPIRAM_VOLT_INVALID, /*!< SPI RAM voltage is invalid*/
|
||||
} esp_spiram_volt_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_SPIRAM_SIZE_32MBITS = 0, /*!< SPI RAM size is 32 MBits */
|
||||
ESP_SPIRAM_SIZE_64MBITS = 1, /*!< SPI RAM size is 64 MBits */
|
||||
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
|
||||
} esp_spiram_size_t;
|
||||
|
||||
/**
|
||||
* @brief get SPI RAM voltage
|
||||
* @return
|
||||
* - ESP_SPIRAM_VOLT_INVALID if SPI RAM not enabled or not valid.
|
||||
* - SPI RAM voltage
|
||||
*/
|
||||
esp_spiram_volt_t esp_spiram_get_chip_volt();
|
||||
|
||||
/**
|
||||
* @brief get SPI RAM size
|
||||
* @return
|
||||
* - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid
|
||||
* - SPI RAM size
|
||||
*/
|
||||
esp_spiram_size_t esp_spiram_get_chip_size();
|
||||
|
||||
/**
|
||||
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
|
||||
*
|
||||
|
|
|
@ -23,6 +23,7 @@ we add more types of external RAM memory, this can be made into a more intellige
|
|||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_spiram.h"
|
||||
#include "spiram_psram.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
@ -102,6 +103,39 @@ void IRAM_ATTR esp_spiram_init_cache()
|
|||
#endif
|
||||
}
|
||||
|
||||
esp_spiram_volt_t esp_spiram_get_chip_volt()
|
||||
{
|
||||
if (!spiram_inited) {
|
||||
ESP_LOGE(TAG, "SPI RAM not initialized");
|
||||
return ESP_SPIRAM_VOLT_INVALID;
|
||||
}
|
||||
psram_volt_t volt = psram_get_volt();
|
||||
switch (volt) {
|
||||
case PSRAM_VOLT_1V8:
|
||||
return ESP_SPIRAM_VOLT_1V8;
|
||||
case PSRAM_VOLT_3V3:
|
||||
return ESP_SPIRAM_VOLT_3V3;
|
||||
default:
|
||||
return ESP_SPIRAM_VOLT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
esp_spiram_size_t esp_spiram_get_chip_size()
|
||||
{
|
||||
if (!spiram_inited) {
|
||||
ESP_LOGE(TAG, "SPI RAM not initialized");
|
||||
return ESP_SPIRAM_SIZE_INVALID;
|
||||
}
|
||||
psram_size_t psram_size = psram_get_size();
|
||||
switch (psram_size) {
|
||||
case PSRAM_SIZE_32MBITS:
|
||||
return ESP_SPIRAM_SIZE_32MBITS;
|
||||
case PSRAM_SIZE_64MBITS:
|
||||
return ESP_SPIRAM_SIZE_64MBITS;
|
||||
default:
|
||||
return ESP_SPIRAM_SIZE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_spiram_init()
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#define PSRAM_FAST_READ 0x0B
|
||||
#define PSRAM_FAST_READ_DUMMY 0x3
|
||||
#define PSRAM_FAST_READ_QUAD 0xEB
|
||||
#define PSRAM_FAST_READ_QUAD_DUMMY 0x5
|
||||
#define PSRAM_WRITE 0x02
|
||||
#define PSRAM_QUAD_WRITE 0x38
|
||||
#define PSRAM_ENTER_QMODE 0x35
|
||||
|
@ -53,13 +54,30 @@
|
|||
#define PSRAM_SET_BURST_LEN 0xC0
|
||||
#define PSRAM_DEVICE_ID 0x9F
|
||||
|
||||
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
|
||||
typedef enum {
|
||||
PSRAM_EID_32MBIT_1V8 = 0x20, /*!< psram EID for 32MBit 1.8V */
|
||||
PSRAM_EID_64MBIT_1V8 = 0x26, /*!< psram EID for 64MBit 1.8V */
|
||||
PSRAM_EID_64MBIT_3V3 = 0x46, /*!< psram EID for 64MBit 3.3V */
|
||||
} psram_type_t;
|
||||
|
||||
#define PSRAM_MFG_ID_M 0xff
|
||||
#define PSRAM_MFG_ID_S 8
|
||||
#define PSRAM_MFG_ID_V 0x5d
|
||||
typedef enum {
|
||||
PSRAM_CLK_MODE_NORM = 0, /*!< Normal SPI mode */
|
||||
PSRAM_CLK_MODE_DCLK = 1, /*!< Two extra clock cycles after CS is set high level */
|
||||
} psram_clk_mode_t;
|
||||
|
||||
#endif
|
||||
#define PSRAM_ID_KGD_M 0xff
|
||||
#define PSRAM_ID_KGD_S 8
|
||||
#define PSRAM_ID_KGD 0x5d
|
||||
#define PSRAM_ID_EID_M 0xff
|
||||
#define PSRAM_ID_EID_S 16
|
||||
|
||||
#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
|
||||
#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
|
||||
#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD)
|
||||
#define PSRAM_IS_1V8(id) ((PSRAM_EID(id) == PSRAM_EID_32MBIT_1V8) || (PSRAM_EID(id) == PSRAM_EID_64MBIT_1V8))
|
||||
#define PSRAM_IS_3V3(id) (PSRAM_EID(id) == PSRAM_EID_64MBIT_3V3)
|
||||
#define PSRAM_IS_64MBIT(id) ((PSRAM_EID(id) == PSRAM_EID_64MBIT_3V3) || (PSRAM_EID(id) == PSRAM_EID_64MBIT_1V8))
|
||||
#define PSRAM_IS_32MBIT(id) (PSRAM_EID(id) == PSRAM_EID_32MBIT_1V8)
|
||||
|
||||
// IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we
|
||||
// currently support are 1.8V parts.
|
||||
|
@ -94,6 +112,8 @@ typedef enum {
|
|||
} psram_spi_num_t;
|
||||
|
||||
static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
|
||||
static psram_clk_mode_t s_clk_mode = PSRAM_CLK_MODE_DCLK;
|
||||
static uint32_t s_psram_id = 0;
|
||||
|
||||
/* dummy_len_plus values defined in ROM for SPI flash configuration */
|
||||
extern uint8_t g_rom_spiflash_dummy_len_plus[];
|
||||
|
@ -280,7 +300,7 @@ static int psram_cmd_config(psram_spi_num_t spi_num, psram_cmd_t* pInData)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void psram_cmd_end(int spi_num) {
|
||||
static void psram_cmd_end(int spi_num) {
|
||||
while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR);
|
||||
WRITE_PERI_REG(SPI_USER_REG(spi_num), backup_usr[spi_num]);
|
||||
WRITE_PERI_REG(SPI_USER1_REG(spi_num), backup_usr1[spi_num]);
|
||||
|
@ -292,10 +312,11 @@ static void psram_disable_qio_mode(psram_spi_num_t spi_num)
|
|||
{
|
||||
psram_cmd_t ps_cmd;
|
||||
uint32_t cmd_exit_qpi;
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
cmd_exit_qpi = PSRAM_EXIT_QMODE;
|
||||
ps_cmd.txDataBitLen = 8;
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
|
@ -304,6 +325,7 @@ static void psram_disable_qio_mode(psram_spi_num_t spi_num)
|
|||
ps_cmd.txDataBitLen = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ps_cmd.txData = &cmd_exit_qpi;
|
||||
ps_cmd.cmd = 0;
|
||||
ps_cmd.cmdBitLen = 0;
|
||||
|
@ -322,29 +344,34 @@ static void psram_read_id(uint32_t* dev_id)
|
|||
{
|
||||
psram_spi_num_t spi_num = PSRAM_SPI_1;
|
||||
psram_disable_qio_mode(spi_num);
|
||||
uint32_t addr = (PSRAM_DEVICE_ID << 24) | 0;
|
||||
uint32_t dummy_bits = 0;
|
||||
uint32_t dummy_bits = 0 + extra_dummy;
|
||||
psram_cmd_t ps_cmd;
|
||||
|
||||
uint32_t addr = 0;
|
||||
ps_cmd.addrBitLen = 3 * 8;
|
||||
ps_cmd.cmd = PSRAM_DEVICE_ID;
|
||||
ps_cmd.cmdBitLen = 8;
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
dummy_bits = 0 + extra_dummy;
|
||||
ps_cmd.cmdBitLen = 0;
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
dummy_bits = 0 + extra_dummy;
|
||||
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle
|
||||
ps_cmd.cmd = 0;
|
||||
addr = (PSRAM_DEVICE_ID << 24) | 0;
|
||||
ps_cmd.addrBitLen = 4 * 8;
|
||||
break;
|
||||
}
|
||||
ps_cmd.cmd = 0;
|
||||
}
|
||||
ps_cmd.addr = &addr;
|
||||
ps_cmd.addrBitLen = 4 * 8;
|
||||
ps_cmd.txDataBitLen = 0;
|
||||
ps_cmd.txData = NULL;
|
||||
ps_cmd.rxDataBitLen = 4 * 8;
|
||||
ps_cmd.rxData = dev_id;
|
||||
ps_cmd.dummyBitLen = dummy_bits;
|
||||
|
||||
psram_cmd_config(spi_num, &ps_cmd);
|
||||
psram_clear_spi_fifo(spi_num);
|
||||
psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI);
|
||||
|
@ -356,9 +383,11 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
|
|||
{
|
||||
psram_cmd_t ps_cmd;
|
||||
uint32_t addr = (PSRAM_ENTER_QMODE << 24) | 0;
|
||||
|
||||
ps_cmd.cmdBitLen = 0;
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
switch (s_psram_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M:
|
||||
ps_cmd.cmdBitLen = 0;
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
|
@ -366,6 +395,7 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
|
|||
ps_cmd.cmdBitLen = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ps_cmd.cmd = 0;
|
||||
ps_cmd.addr = &addr;
|
||||
ps_cmd.addrBitLen = 8;
|
||||
|
@ -491,6 +521,28 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
|
|||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
}
|
||||
|
||||
psram_volt_t psram_get_volt()
|
||||
{
|
||||
if (PSRAM_IS_1V8(s_psram_id)) {
|
||||
return PSRAM_VOLT_1V8;
|
||||
} else if (PSRAM_IS_3V3(s_psram_id)) {
|
||||
return PSRAM_VOLT_3V3;
|
||||
} else {
|
||||
return PSRAM_VOLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
psram_size_t psram_get_size()
|
||||
{
|
||||
if (PSRAM_IS_32MBIT(s_psram_id)) {
|
||||
return PSRAM_SIZE_32MBITS;
|
||||
} else if (PSRAM_IS_64MBIT(s_psram_id)) {
|
||||
return PSRAM_SIZE_64MBITS;
|
||||
} else {
|
||||
return PSRAM_SIZE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
{
|
||||
|
@ -507,17 +559,6 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
|||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* note: If the third mode(80Mhz+80Mhz) is enabled, VSPI port will be occupied by the system,
|
||||
Application code should never touch VSPI hardware in this case. We try to stop applications
|
||||
from doing this using the drivers by claiming the port for ourselves*/
|
||||
if (mode == PSRAM_CACHE_F80M_S80M) {
|
||||
periph_module_enable(PERIPH_VSPI_MODULE);
|
||||
bool r=spicommon_periph_claim(VSPI_HOST);
|
||||
if (!r) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO)); //DISABLE OUPUT FOR IO16/17
|
||||
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
|
||||
s_psram_mode = mode;
|
||||
|
@ -532,21 +573,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
|||
psram_spi_init(PSRAM_SPI_1, mode);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
|
||||
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 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);
|
||||
uint32_t spi_status;
|
||||
while (1) {
|
||||
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
|
||||
if (spi_status != 0 && spi_status != 1) {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
|
@ -585,27 +612,58 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
|||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], PIN_FUNC_GPIO);
|
||||
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
if (flash_id == FLASH_ID_GD25LQ32C) {
|
||||
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
|
||||
// Set drive ability for 1.8v flash in 80Mhz.
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO], FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV, 3, FUN_DRV_S);
|
||||
#endif
|
||||
}
|
||||
uint32_t id;
|
||||
psram_read_id(&id);
|
||||
if (((id >> PSRAM_MFG_ID_S) & PSRAM_MFG_ID_M) != PSRAM_MFG_ID_V) {
|
||||
psram_read_id(&s_psram_id);
|
||||
if (!PSRAM_IS_VALID(s_psram_id)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
if (flash_id == FLASH_ID_GD25LQ32C && PSRAM_IS_1V8(s_psram_id)) {
|
||||
// Set drive ability for 1.8v flash in 80Mhz.
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV_V, 3, FUN_DRV_S);
|
||||
}
|
||||
if (PSRAM_EID(s_psram_id) == PSRAM_EID_64MBIT_1V8) {
|
||||
// For this psram, we don't need any extra clock cycles after cs get back to high level
|
||||
s_clk_mode = PSRAM_CLK_MODE_NORM;
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
|
||||
} else if (PSRAM_EID(s_psram_id) == PSRAM_EID_32MBIT_1V8 || PSRAM_EID(s_psram_id) == PSRAM_EID_64MBIT_3V3) {
|
||||
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 and 64MBit 3.3v psram,
|
||||
VSPI port will be occupied by the system.
|
||||
Application code should never touch 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);
|
||||
if (!r) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 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);
|
||||
uint32_t spi_status;
|
||||
while (1) {
|
||||
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
|
||||
if (spi_status != 0 && spi_status != 1) {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
psram_enable_qio_mode(PSRAM_SPI_1);
|
||||
|
||||
psram_cache_init(mode, vaddrmode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -624,27 +682,15 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
|
|||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk,80+40;
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M); //SET 1DIV CLOCK AND RESET OTHER PARAMS
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M:
|
||||
SET_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0.
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
break;
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
|
||||
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
break;
|
||||
}
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_WCMD_M); // cache write command enable
|
||||
|
@ -652,30 +698,38 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
|
|||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_QIO_M); //enable qio mode for cache command
|
||||
CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_DIO_M); //disable dio mode for cache command
|
||||
|
||||
|
||||
//config sram cache r/w command
|
||||
switch (psram_cache_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ,
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ_QUAD,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
|
||||
//config sram cache r/w command
|
||||
switch (psram_cache_mode) {
|
||||
case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
|
||||
break;
|
||||
case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay
|
||||
case PSRAM_CACHE_F40M_S40M:
|
||||
default:
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ) << 8),
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ_QUAD) << 8),
|
||||
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
|
||||
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
|
||||
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
|
||||
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
|
||||
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -698,6 +752,11 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
|
|||
|
||||
CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
|
||||
|
||||
if (s_clk_mode == PSRAM_CLK_MODE_NORM) { //different
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD);
|
||||
// Set cs time.
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 1, SPI_SETUP_TIME_S);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_SPIRAM_SUPPORT
|
||||
|
|
|
@ -26,6 +26,17 @@ typedef enum {
|
|||
PSRAM_CACHE_MAX,
|
||||
} psram_cache_mode_t;
|
||||
|
||||
typedef enum {
|
||||
PSRAM_VOLT_3V3 = 0,
|
||||
PSRAM_VOLT_1V8 = 1,
|
||||
PSRAM_VOLT_MAX,
|
||||
} psram_volt_t;
|
||||
|
||||
typedef enum {
|
||||
PSRAM_SIZE_32MBITS = 0,
|
||||
PSRAM_SIZE_64MBITS = 1,
|
||||
PSRAM_SIZE_MAX,
|
||||
} psram_size_t;
|
||||
|
||||
/*
|
||||
See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
|
||||
|
@ -34,12 +45,29 @@ Important is that NORMAL works with the app CPU cache disabled, but gives huge c
|
|||
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, ///< 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 get psram voltage
|
||||
* @return
|
||||
* - PSRAM_VOLT_MAX if psram not enabled or not valid.
|
||||
* - PSRAM voltage
|
||||
*/
|
||||
psram_volt_t psram_get_volt();
|
||||
|
||||
/**
|
||||
* @brief get psram size
|
||||
* @return
|
||||
* - PSRAM_SIZE_MAX if psram not enabled or not valid
|
||||
* - PSRAM size
|
||||
*/
|
||||
psram_size_t psram_get_size();
|
||||
|
||||
/**
|
||||
* @brief psram cache enable function
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue