diff --git a/components/esp32/include/esp_spiram.h b/components/esp32/include/esp_spiram.h index 9663dcddc..aafd85cee 100644 --- a/components/esp32/include/esp_spiram.h +++ b/components/esp32/include/esp_spiram.h @@ -18,8 +18,37 @@ #include #include +#include #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. * diff --git a/components/esp32/spiram.c b/components/esp32/spiram.c index dccc3bc33..21fade5be 100644 --- a/components/esp32/spiram.c +++ b/components/esp32/spiram.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() { diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index ed20375da..2aa3b422b 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -40,26 +40,44 @@ #include "soc/rtc.h" //Commands for PSRAM chip -#define PSRAM_READ 0x03 -#define PSRAM_FAST_READ 0x0B -#define PSRAM_FAST_READ_DUMMY 0x3 -#define PSRAM_FAST_READ_QUAD 0xEB -#define PSRAM_WRITE 0x02 -#define PSRAM_QUAD_WRITE 0x38 -#define PSRAM_ENTER_QMODE 0x35 -#define PSRAM_EXIT_QMODE 0xF5 -#define PSRAM_RESET_EN 0x66 -#define PSRAM_RESET 0x99 -#define PSRAM_SET_BURST_LEN 0xC0 -#define PSRAM_DEVICE_ID 0x9F +#define PSRAM_READ 0x03 +#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 +#define PSRAM_EXIT_QMODE 0xF5 +#define PSRAM_RESET_EN 0x66 +#define PSRAM_RESET 0x99 +#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,17 +312,19 @@ 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; - break; - case PSRAM_CACHE_F80M_S40M: - case PSRAM_CACHE_F40M_S40M: - default: - cmd_exit_qpi = PSRAM_EXIT_QMODE << 8; - ps_cmd.txDataBitLen = 16; - break; + 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: + default: + cmd_exit_qpi = PSRAM_EXIT_QMODE << 8; + ps_cmd.txDataBitLen = 16; + break; + } } ps_cmd.txData = &cmd_exit_qpi; ps_cmd.cmd = 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; - 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 - break; + + 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: + break; + case PSRAM_CACHE_F80M_S40M: + case PSRAM_CACHE_F40M_S40M: + default: + 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,15 +383,18 @@ 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; - switch (s_psram_mode) { - case PSRAM_CACHE_F80M_S80M: - ps_cmd.cmdBitLen = 0; - break; - case PSRAM_CACHE_F80M_S40M: - case PSRAM_CACHE_F40M_S40M: - default: - ps_cmd.cmdBitLen = 2; - break; + + ps_cmd.cmdBitLen = 0; + 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: + default: + ps_cmd.cmdBitLen = 2; + break; + } } ps_cmd.cmd = 0; ps_cmd.addr = &addr; @@ -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 + 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_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 - 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, - SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b break; case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay case PSRAM_CACHE_F40M_S40M: default: - 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), - 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) + 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_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 diff --git a/components/esp32/spiram_psram.h b/components/esp32/spiram_psram.h index 10de4e1d6..1756eed73 100644 --- a/components/esp32/spiram_psram.h +++ b/components/esp32/spiram_psram.h @@ -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 *