فهرست منبع

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
Wangjialin 7 سال پیش
والد
کامیت
6e9c59bfc3
4فایلهای تغییر یافته به همراه276 افزوده شده و 126 حذف شده
  1. 29 0
      components/esp32/include/esp_spiram.h
  2. 34 0
      components/esp32/spiram.c
  3. 185 126
      components/esp32/spiram_psram.c
  4. 28 0
      components/esp32/spiram_psram.h

+ 29 - 0
components/esp32/include/esp_spiram.h

@@ -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.
  *

+ 34 - 0
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()
 {

+ 185 - 126
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
-
-#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
-
-#define PSRAM_MFG_ID_M          0xff
-#define PSRAM_MFG_ID_S             8
-#define PSRAM_MFG_ID_V          0x5d
-
-#endif
+#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
+
+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;
+
+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;
+
+#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);
 
+    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) {
-        #if CONFIG_SPIRAM_TYPE_ESPPSRAM32
+    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, 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
+        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);
     }
-    uint32_t id;
-    psram_read_id(&id);
-    if (((id >> PSRAM_MFG_ID_S) & PSRAM_MFG_ID_M) != PSRAM_MFG_ID_V) {
-        return ESP_FAIL;
+    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

+ 28 - 0
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
  *