From 6d253b4394a9dc1cce546eedceaf2e936cf92319 Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Wed, 4 Jul 2018 11:43:30 +0800 Subject: [PATCH 1/3] 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 --- components/esp32/include/esp_spiram.h | 29 +++ components/esp32/spiram.c | 34 +++ components/esp32/spiram_psram.c | 296 ++++++++++++++++---------- components/esp32/spiram_psram.h | 28 +++ 4 files changed, 276 insertions(+), 111 deletions(-) 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 d07444a92..f3684a63b 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 39bb0a388..9eccdec6f 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -39,26 +39,44 @@ #if CONFIG_SPIRAM_SUPPORT //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. @@ -98,6 +116,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[]; @@ -286,7 +306,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]); @@ -298,17 +318,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; @@ -328,29 +350,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); @@ -362,15 +389,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; @@ -473,6 +503,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 { @@ -489,17 +541,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; @@ -514,21 +555,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_SPI_CLK_EN_2); - break; - } - } + gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0); break; case PSRAM_CACHE_F80M_S40M: case PSRAM_CACHE_F40M_S40M: @@ -554,13 +581,59 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO)); 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 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; } @@ -579,27 +652,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 @@ -607,30 +668,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; } @@ -653,6 +722,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 * From 8cfb0b207a2f25f1d1237388162834a6d6b70b67 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Thu, 27 Sep 2018 17:00:48 +0800 Subject: [PATCH 2/3] bugfix(psram): fix psram driver 1. remove use EID to distinguish psram voltage 2. 1V8 64Mbit psram and 3V3 64Mbit psram use the same psram driver(standard spi interface) 3. set cs hold time register as 1 --- components/esp32/include/esp_spiram.h | 14 --------- components/esp32/spiram.c | 17 ----------- components/esp32/spiram_psram.c | 42 +++++++++------------------ components/esp32/spiram_psram.h | 14 --------- 4 files changed, 13 insertions(+), 74 deletions(-) diff --git a/components/esp32/include/esp_spiram.h b/components/esp32/include/esp_spiram.h index aafd85cee..c12da6802 100644 --- a/components/esp32/include/esp_spiram.h +++ b/components/esp32/include/esp_spiram.h @@ -21,26 +21,12 @@ #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 diff --git a/components/esp32/spiram.c b/components/esp32/spiram.c index f3684a63b..34627cf04 100644 --- a/components/esp32/spiram.c +++ b/components/esp32/spiram.c @@ -103,23 +103,6 @@ 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) { diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index 9eccdec6f..52d40bb5a 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -53,12 +53,6 @@ #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 */ @@ -73,10 +67,11 @@ typedef enum { #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) + +// PSRAM_EID = 0x26 or 0x4x ----> 64MBit psram +// PSRAM_EID = 0x20 ------------> 32MBit psram +#define PSRAM_IS_64MBIT(id) ((PSRAM_EID(id) == 0x26) || ((PSRAM_EID(id) & 0xf0) == 0x40)) +#define PSRAM_IS_32MBIT_VER0(id) (PSRAM_EID(id) == 0x20) // IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we // currently support are 1.8V parts. @@ -503,20 +498,9 @@ 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)) { + if (PSRAM_IS_32MBIT_VER0(s_psram_id)) { return PSRAM_SIZE_32MBITS; } else if (PSRAM_IS_64MBIT(s_psram_id)) { return PSRAM_SIZE_64MBITS; @@ -587,7 +571,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad return ESP_FAIL; } uint32_t flash_id = g_rom_flashchip.device_id; - if (flash_id == FLASH_ID_GD25LQ32C && PSRAM_IS_1V8(s_psram_id)) { + if (flash_id == FLASH_ID_GD25LQ32C) { // 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); @@ -598,19 +582,19 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad 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) { + if (PSRAM_IS_64MBIT(s_psram_id)) { // 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) { + } 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 and 64MBit 3.3v psram, - VSPI port will be occupied by the system. + /* 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 - 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); bool r=spicommon_periph_claim(VSPI_HOST); if (!r) { @@ -725,7 +709,7 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra 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); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); } } diff --git a/components/esp32/spiram_psram.h b/components/esp32/spiram_psram.h index 1756eed73..226a213dd 100644 --- a/components/esp32/spiram_psram.h +++ b/components/esp32/spiram_psram.h @@ -26,12 +26,6 @@ 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, @@ -52,14 +46,6 @@ typedef enum { 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 From 80c013ee5af897ef555fbad1ad98600f148a7f21 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Wed, 10 Oct 2018 20:21:01 +0800 Subject: [PATCH 3/3] bugfix(psram): fix the error that two macro definitions are undeclared 1. add definition of FLASH_ID_GD25LQ32C 2. modify DPORT_SPI3_CLK_EN as DPORT_SPI_CLK_EN_2 --- components/esp32/include/rom/spi_flash.h | 2 ++ components/esp32/spiram_psram.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index 35d010d79..cc9856f45 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -117,6 +117,8 @@ extern "C" { #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 +#define FLASH_ID_GD25LQ32C 0xC86016 + typedef enum { ESP_ROM_SPIFLASH_QIO_MODE = 0, ESP_ROM_SPIFLASH_QOUT_MODE, diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index 52d40bb5a..c2481d37c 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -611,7 +611,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad 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); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2); break; } }