Merge branch 'feature/esp_flash_32b_addr' into 'master'

esp_flash: support high capacity flash chips (32-bit address)

See merge request espressif/esp-idf!9475
This commit is contained in:
Michael (XIAO Xufeng) 2020-10-30 15:22:44 +08:00
commit 23584e094f
40 changed files with 850 additions and 244 deletions

View File

@ -316,17 +316,18 @@ static inline void spi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
}
/**
* Set the command with fixed length (8 bits).
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void spi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command)
static inline void spi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (8 - 1),
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
@ -362,7 +363,14 @@ static inline void spi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen)
*/
static inline void spi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, int bit_len)
{
dev->addr = (addr << (32 - bit_len));
// The blank region should be all ones
if (bit_len >= 32) {
dev->addr = addr;
dev->slv_wr_status = UINT32_MAX;
} else {
uint32_t padding_ones = (bit_len == 32? 0 : UINT32_MAX >> bit_len);
dev->addr = (addr << (32 - bit_len)) | padding_ones;
}
}
/**
@ -388,6 +396,12 @@ static inline void spi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n)
dev->user1.usr_dummy_cyclelen = dummy_n - 1;
}
static inline void spi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.hold_time = hold_n;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -275,17 +275,18 @@ static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitle
}
/**
* Set the command with fixed length (8 bits).
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void gpspi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command)
static inline void gpspi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (8 - 1),
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
@ -321,7 +322,9 @@ static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitle
*/
static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
dev->addr = (addr << (32 - bitlen));
// The blank region should be all ones
uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen);
dev->addr = (addr << (32 - bitlen)) | padding_ones;
}
/**
@ -361,6 +364,12 @@ static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en,
dev->ctrl.d_pol = out_lev;
}
static inline void gpspi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -54,6 +54,7 @@ typedef union {
} spi_flash_ll_clock_reg_t;
#ifdef GPSPI_BUILD
#define spi_flash_ll_reset(dev) gpspi_flash_ll_reset((spi_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) gpspi_flash_ll_cmd_is_done((spi_dev_t*)dev)
#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) gpspi_flash_ll_get_buffer_data((spi_dev_t*)dev, buffer, read_len)
@ -66,14 +67,17 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) gpspi_flash_ll_set_command8((spi_dev_t*)dev, cmd)
#define spi_flash_ll_set_command(dev, cmd, bitlen) gpspi_flash_ll_set_command((spi_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev)
#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev)
@ -91,13 +95,15 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) spimem_flash_ll_set_command8((spi_mem_dev_t*)dev, cmd)
#define spi_flash_ll_set_command(dev, cmd, bitlen) spimem_flash_ll_set_command((spi_mem_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev)
#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_usr_address((spi_mem_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#endif
#ifdef __cplusplus

View File

@ -308,17 +308,18 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t
}
/**
* Set the command with fixed length (8 bits).
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void spimem_flash_ll_set_command8(spi_mem_dev_t *dev, uint8_t command)
static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (8 - 1),
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
@ -357,6 +358,18 @@ static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr
dev->addr = addr;
}
/**
* Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
(void)bitlen;
spimem_flash_ll_set_address(dev, addr);
}
/**
* Set the length of dummy cycles.
*
@ -383,6 +396,13 @@ static inline void spimem_flash_ll_set_dummy_out(spi_mem_dev_t *dev, uint32_t ou
dev->ctrl.d_pol = out_lev;
}
static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -57,7 +57,7 @@ typedef typeof(GPSPI2.clock) gpspi_flash_ll_clock_reg_t;
* Control
*----------------------------------------------------------------------------*/
/**
* Reset peripheral registers before configuration and starting control
* Reset peripheral registers before configuration and starting control.
*
* @param dev Beginning address of the peripheral registers.
*/
@ -65,6 +65,15 @@ static inline void gpspi_flash_ll_reset(spi_dev_t *dev)
{
dev->user.val = 0;
dev->ctrl.val = 0;
dev->clk_gate.clk_en = 1;
dev->clk_gate.mst_clk_active = 1;
dev->clk_gate.mst_clk_sel = 1;
dev->dma_conf.val = 0;
dev->dma_conf.tx_seg_trans_clr_en = 1;
dev->dma_conf.rx_seg_trans_clr_en = 1;
dev->dma_conf.dma_seg_trans_en = 0;
}
/**
@ -144,6 +153,8 @@ static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *bu
*/
static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
{
dev->cmd.update = 1;
while (dev->cmd.update);
dev->cmd.usr = 1;
}
@ -156,7 +167,7 @@ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
*/
static inline bool gpspi_flash_ll_host_idle(const spi_dev_t *dev)
{
return false;
return dev->cmd.usr == 0;
}
/**
@ -203,10 +214,10 @@ static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mod
ctrl.val &= ~(SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M | SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M);
user.val &= ~(SPI_FWRITE_QUAD_M | SPI_FWRITE_DUAL_M);
// ctrl.val |= SPI_FAST_RD_MODE_M;
switch (read_mode) {
case SPI_FLASH_FASTRD:
//the default option
case SPI_FLASH_SLOWRD:
break;
case SPI_FLASH_QIO:
ctrl.fread_quad = 1;
@ -226,9 +237,6 @@ static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mod
ctrl.fread_dual = 1;
user.fwrite_dual = 1;
break;
// case SPI_FLASH_SLOWRD:
// ctrl.fast_rd_mode = 0;
// break;
default:
abort();
}
@ -257,6 +265,9 @@ static inline void gpspi_flash_ll_set_clock(spi_dev_t *dev, gpspi_flash_ll_clock
static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_miso = bitlen > 0;
if (bitlen) {
dev->ms_dlen.ms_data_bitlen = bitlen - 1;
}
}
/**
@ -269,20 +280,24 @@ static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitle
static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_mosi = bitlen > 0;
if (bitlen) {
dev->ms_dlen.ms_data_bitlen = bitlen - 1;
}
}
/**
* Set the command with fixed length (8 bits).
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void gpspi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command)
static inline void gpspi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (8 - 1),
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
@ -318,9 +333,12 @@ static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitle
*/
static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
dev->addr = (addr << (32 - bitlen));
// The blank region should be all ones
uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen);
dev->addr = (addr << (32 - bitlen)) | padding_ones;
}
/**
* Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write...
*
@ -358,6 +376,12 @@ static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en,
dev->ctrl.d_pol = out_lev;
}
static inline void gpspi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->user1.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -66,13 +66,15 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) gpspi_flash_ll_set_command8((spi_dev_t*)dev, cmd)
#define spi_flash_ll_set_command(dev, cmd, bitlen) gpspi_flash_ll_set_command((spi_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev)
#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
@ -91,13 +93,14 @@ typedef union {
#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command8(dev, cmd) spimem_flash_ll_set_command8((spi_mem_dev_t*)dev, cmd)
#define spi_flash_ll_set_command(dev, cmd, bitlen) spimem_flash_ll_set_command((spi_mem_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev)
#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_usr_address((spi_mem_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#endif
#ifdef __cplusplus

View File

@ -308,17 +308,18 @@ static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t
}
/**
* Set the command with fixed length (8 bits).
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void spimem_flash_ll_set_command8(spi_mem_dev_t *dev, uint8_t command)
static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (8 - 1),
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
@ -357,6 +358,18 @@ static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr
dev->addr = addr;
}
/**
* Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
(void)bitlen;
spimem_flash_ll_set_address(dev, addr);
}
/**
* Set the length of dummy cycles.
*
@ -383,6 +396,12 @@ static inline void spimem_flash_ll_set_dummy_out(spi_mem_dev_t *dev, uint32_t ou
dev->ctrl.d_pol = out_lev;
}
static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -40,10 +40,17 @@ typedef struct {
spi_flash_host_inst_t inst; ///< Host instance, containing host data and function pointer table. May update with the host (hardware version).
spi_dev_t *spi; ///< Pointer to SPI peripheral registers (SP1, SPI2 or SPI3). Set before initialisation.
int cs_num; ///< Which cs pin is used, 0-2.
int extra_dummy; ///< Pre-calculated extra dummy used for compensation
struct {
uint8_t extra_dummy; ///< Pre-calculated extra dummy used for compensation
uint8_t reserved1; ///< Reserved, set to 0.
uint8_t cs_hold; ///< CS hold time config used by the host
uint8_t reserved2; ///< Reserved, set to 0.
};
spi_flash_ll_clock_reg_t clock_conf; ///< Pre-calculated clock configuration value
uint32_t reserved_config[2]; ///< The ROM has reserved some memory for configurations with one set of driver code. (e.g. QPI mode, 64-bit address mode, etc.)
esp_flash_io_mode_t base_io_mode; ///< Default IO mode mask for common commands
uint32_t reserved_config[1]; ///< The ROM has reserved some memory for configurations with one set of driver code. (e.g. QPI mode, 64-bit address mode, etc.)
} spi_flash_hal_context_t;
_Static_assert(sizeof(spi_flash_hal_context_t) == 28, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
/// Configuration structure for the SPI driver.
typedef struct {
@ -52,6 +59,7 @@ typedef struct {
bool iomux; ///< Whether the IOMUX is used, used for timing compensation.
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock used for timing compensation.
esp_flash_speed_t speed;///< SPI flash clock speed to work at.
uint32_t cs_hold; ///< CS hold time config used by the host
} spi_flash_hal_config_t;
/**
@ -98,7 +106,7 @@ void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host);
/**
* Erase a specific sector by its start address through the sector erase (20h)
* command.
* command. For 24bit address only.
*
* @param host The driver context.
* @param start_address Start address of the sector to erase.
@ -107,7 +115,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addr
/**
* Erase a specific 64KB block by its start address through the 64KB block
* erase (D8h) command.
* erase (D8h) command. For 24bit address only.
*
* @param host The driver context.
* @param start_address Start address of the block to erase.
@ -115,7 +123,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addr
void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Program a page of the flash using the page program (02h) command.
* Program a page of the flash using the page program (02h) command. For 24bit address only.
*
* @param host The driver context.
* @param address Address of the page to program

View File

@ -15,6 +15,7 @@
#pragma once
#include <esp_types.h>
#include <esp_bit_defs.h>
#include "esp_flash_err.h"
#ifdef __cplusplus
@ -23,13 +24,19 @@ extern "C" {
/** Definition of a common transaction. Also holds the return value. */
typedef struct {
uint8_t command; ///< Command to send, always 8bits
uint8_t reserved; ///< Reserved, must be 0.
uint8_t mosi_len; ///< Output data length, in bytes
uint8_t miso_len; ///< Input data length, in bytes
uint8_t address_bitlen; ///< Length of address in bits, set to 0 if command does not need an address
uint32_t address; ///< Address to perform operation on
const uint8_t *mosi_data; ///< Output data to salve
uint8_t *miso_data; ///< [out] Input data from slave, little endian
uint32_t flags; ///< Flags for this transaction. Set to 0 for now.
#define SPI_FLASH_TRANS_FLAG_CMD16 BIT(0) ///< Send command of 16 bits
#define SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO BIT(1) ///< Not applying the basic io mode configuration for this transaction
#define SPI_FLASH_TRANS_FLAG_BYTE_SWAP BIT(2) ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge
uint16_t command; ///< Command to send
uint8_t dummy_bitlen; ///< Basic dummy bits to use
} spi_flash_trans_t;
/**
@ -53,6 +60,9 @@ typedef enum {
///Lowest speed supported by the driver, currently 5 MHz
#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ
// These bits are not quite like "IO mode", but are able to be appended into the io mode and used by the HAL.
#define SPI_FLASH_CONFIG_CONF_BITS BIT(31) ///< OR the io_mode with this mask, to enable the dummy output feature or replace the first several dummy bits into address to meet the requirements of conf bits. (Used in DIO/QIO/OIO mode)
/** @brief Mode used for reading from SPI flash */
typedef enum {
SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed

View File

@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// HAL for SPI Flash (non-IRAM part)
// The IRAM part is in spi_flash_hal_iram.c, spi_flash_hal_gpspi.c, spi_flash_hal_common.inc.
#include <stdlib.h>
#include "hal/spi_flash_hal.h"
#include "string.h"
@ -87,6 +90,7 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
.cs_num = cfg->cs_num,
.extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, clock_cfg.freq),
.clock_conf = clock_cfg.clock_reg_val,
.cs_hold = cfg->cs_hold,
};
ESP_EARLY_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy);

View File

@ -16,6 +16,7 @@
#include "hal/spi_flash_hal.h"
#include "string.h"
#include "hal/hal_defs.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#define ADDRESS_MASK_24BIT 0xFFFFFF
@ -26,6 +27,12 @@ static inline spi_dev_t *get_spi_dev(spi_flash_host_inst_t *host)
return ((spi_flash_hal_context_t*)host)->spi;
}
static inline int get_host_id(spi_flash_host_inst_t* host)
{
spi_dev_t *dev = get_spi_dev(host);
return spi_flash_ll_hw_get_id(dev);
}
void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host)
{
while (!spi_flash_ll_cmd_is_done(get_spi_dev(host))) {
@ -35,10 +42,14 @@ void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host)
esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host)
{
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_reset(dev);
spi_flash_ll_set_cs_pin(dev, ((spi_flash_hal_context_t*)host)->cs_num);
spi_flash_ll_set_clock(dev, &((spi_flash_hal_context_t*)host)->clock_conf);
spi_flash_ll_set_cs_pin(dev, ctx->cs_num);
spi_flash_ll_set_clock(dev, &ctx->clock_conf);
int cs_hold = ctx->cs_hold;
spi_flash_ll_set_hold(dev, cs_hold);
return ESP_OK;
}
@ -52,32 +63,39 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
spi_dev_t *dev = get_spi_dev(host);
int host_id = spi_flash_ll_hw_get_id(dev);
uint32_t extra_bits = io_mode & 0xFFFF0000;
io_mode = io_mode & 0xFFFF;
/*
* Some flash chips, when working under some IO modes (DIO, QIO and OIO in the future), treat
* the first 8 bits of the dummy bits as the bits. When the bits meet some pattern, the chip
* will go into a "continuous (XIP)" mode, where the command field will be skipped in the next
* transaction. We have to output all ones in these cycles because we don't need this feature.
*/
bool conf_required = ((extra_bits & SPI_FLASH_CONFIG_CONF_BITS) != 0);
if (!SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) && io_mode > SPI_FLASH_FASTRD) {
return ESP_ERR_NOT_SUPPORTED;
}
if (addr_bitlen > 24 && SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(host_id)) {
/*
* The extra address bits (24-addr_bitlen) are used to control the M7-M0 bits right after
* the address field, to avoid the flash going into continuous read mode.
*
* On ESP32-S2 the MEMSPI (that SUPPORT_CONTROL_DUMMY_OUTPUT), the least significant
* addr_bitlen bits of the address will be used, instead of the MSBs. The driver is
* required to set the address according to the extra address bits.
*
* To reduce the time consuming for the read() function to calculate the shift of address,
* the addr_bitlen is kept to 24 bits. And the CONTROL_DUMMY_OUTPUT feature is used to
* control those bits instead.
*/
//This block is only reached when SPI_FLASH_QIO or SPI_FLASH_DIO
assert(io_mode == SPI_FLASH_DIO || io_mode == SPI_FLASH_QIO);
#if SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT
// The CONTROL_DUMMY_OUTPUT feature is used to control M7-M0 bits.
spi_flash_ll_set_dummy_out(dev, (conf_required? 1: 0), 1);
#else
// On ESP32, dummy output is not supported. These dummy bits will be moved into the address
// phase (and appended as ones).
if (conf_required) {
int line_width = (io_mode == SPI_FLASH_DIO? 2: 4);
dummy_cyclelen_base += (addr_bitlen - 24) / line_width;
addr_bitlen = 24;
spi_flash_ll_set_dummy_out(dev, 1, 1);
dummy_cyclelen_base -= 4 / line_width;
addr_bitlen += 4; //extra 4 bits indicate the conf bits is included
}
#endif
spi_flash_ll_set_command8(dev, command);
if (command >= 0x100) {
spi_flash_ll_set_command(dev, command, 16);
} else {
spi_flash_ll_set_command(dev, command, 8);
}
spi_flash_ll_set_addr_bitlen(dev, addr_bitlen);
// Add dummy cycles to compensate for latency of GPIO matrix and external delay, if necessary...
spi_flash_ll_set_dummy(dev, COMPUTE_DUMMY_CYCLELEN(host, dummy_cyclelen_base));
@ -90,16 +108,23 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans)
{
host->driver->configure_host_io_mode(host, trans->command, trans->address_bitlen, 0, SPI_FLASH_FASTRD);
spi_dev_t *dev = get_spi_dev(host);
esp_flash_io_mode_t io_mode = ((spi_flash_hal_context_t*)host)->base_io_mode;
uint16_t command = trans->command;
uint8_t dummy_bitlen = trans->dummy_bitlen;
//disable dummy if no input phase
if (trans->miso_len == 0) {
spi_flash_ll_set_dummy(dev, 0);
if ((trans->flags & SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO) != 0) {
io_mode = 0;
}
host->driver->configure_host_io_mode(host, command, trans->address_bitlen, dummy_bitlen, io_mode);
spi_flash_ll_set_usr_address(dev, trans->address, trans->address_bitlen);
//No extra dummy cycles for compensation if no input data
if (trans->miso_len == 0) {
spi_flash_ll_set_dummy(dev, dummy_bitlen);
}
spi_flash_ll_set_usr_address(dev, (trans->address & ADDRESS_MASK_24BIT), spi_flash_ll_get_addr_bitlen(dev));
spi_flash_ll_set_mosi_bitlen(dev, trans->mosi_len * 8);
spi_flash_ll_set_buffer_data(dev, trans->mosi_data, trans->mosi_len);
@ -114,7 +139,9 @@ esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t
{
spi_dev_t *dev = get_spi_dev(host);
int bitlen = spi_flash_ll_get_addr_bitlen(dev);
spi_flash_ll_set_usr_address(dev, address << (bitlen - 24), bitlen);
//Only 24-bit and 32-bit address are supported. The extra length are for M7-M0, which should be
//filled with ones by the function below
spi_flash_ll_set_usr_address(dev, address, bitlen & (~7));
spi_flash_ll_set_miso_bitlen(dev, read_len * 8);
spi_flash_ll_user_start(dev);
host->driver->poll_cmd_done(host);

View File

@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// HAL for
// - GPSPI (SP2, SPI3) on ESP32-S2 and later
// The common part is in spi_flash_hal_common.inc
#define GPSPI_BUILD
#define spi_flash_hal_common_command spi_flash_hal_gpspi_common_command

View File

@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// HAL for
// - MEMSPI
// - SPI1~3 on ESP32
// The common part is in spi_flash_hal_common.inc
#include "spi_flash_hal_common.inc"
void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
@ -21,6 +26,7 @@ void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
host->driver->poll_cmd_done(host);
}
// Only support 24bit address
void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{
spi_dev_t *dev = get_spi_dev(host);
@ -30,6 +36,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addr
host->driver->poll_cmd_done(host);
}
// Only support 24bit address
void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{
spi_dev_t *dev = get_spi_dev(host);
@ -39,6 +46,7 @@ void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_addre
host->driver->poll_cmd_done(host);
}
// Only support 24bit address
void spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{
spi_dev_t *dev = get_spi_dev(host);

View File

@ -18,8 +18,18 @@
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 30
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 27
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 50600
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 50300
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 68900
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (359*1000)
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (338*1000)
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_2KB

View File

@ -17,6 +17,17 @@
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 32
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 30
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 53400
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 53600
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 64900
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (309*1000)
#endif
@ -26,5 +37,5 @@
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_ERASE
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_ERASE 40300
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_ERASE 37500
#endif

View File

@ -16,6 +16,17 @@
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 32
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 30
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 53400
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 53600
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 68900
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B (309*1000)
#endif

View File

@ -93,9 +93,7 @@
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_4B 22200
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B 53400
#endif
// IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_RD_4B in target file
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_2KB
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_LEGACY_WR_2KB (701*1000)
#endif
@ -110,9 +108,7 @@
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_4B 27400
#endif
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B 53600
#endif
// IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_RD_4B in target file
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_2KB
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_WR_2KB (694*1000)
#endif
@ -140,9 +136,7 @@
#endif
// Some performance value based on the test against GD chip with single_core config.
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B 68900
#endif
// IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_4B in target file
// IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_RD_4B in target file
#ifndef IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_2KB
#define IDF_PERFORMANCE_MIN_FLASH_SPEED_BYTE_PER_SEC_EXT_WR_2KB (475*1000)

View File

@ -183,7 +183,7 @@
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_host) ({(void)spi_host; 1;})
// Peripheral doesn't support output given level during its "dummy phase"
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(spi_host) ({(void)spi_host; 0;})
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 0
/*-------------------------- TIMER GROUP CAPS --------------------------------*/
// No contents here

View File

@ -178,7 +178,7 @@
// Peripheral supports output given level during its "dummy phase"
// Only SPI1 supports this feature
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(host_id) ((host_id) == 0)
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 1
#define SOC_MEMSPI_IS_INDEPENDENT 1

View File

@ -27,9 +27,10 @@
#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1
// Peripheral supports DIO, DOUT, QIO, or QOUT
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_dev) (!((void*)spi_dev == (void*)&GPSPI3))
// VSPI (SPI3) only support 1-bit mode
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) ((host_id) != 2)
// Peripheral supports output given level during its "dummy phase"
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT(spi_dev) (!((void*)spi_dev == (void*)&SPIMEM1))
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 1
#define SOC_MEMSPI_IS_INDEPENDENT 1

View File

@ -31,6 +31,7 @@ else()
"spi_flash_chip_issi.c"
"spi_flash_chip_mxic.c"
"spi_flash_chip_gd.c"
"spi_flash_chip_winbond.c"
"memspi_host_driver.c")
list(APPEND cache_srcs

View File

@ -188,6 +188,14 @@ menu "SPI Flash driver"
size. Note that the default chip driver supports the GD chips with product ID
60H.
config SPI_FLASH_SUPPORT_WINBOND_CHIP
bool "Winbond"
default y
help
Enable this to support auto detection of Winbond chips if chip vendor not directly
given by ``chip_drv`` member of the chip struct. This adds support for variant
chips, however will extend detecting time.
endmenu #auto detect flash chips
endmenu

View File

@ -149,6 +149,11 @@ bool esp_flash_chip_driver_initialized(const esp_flash_t *chip)
esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
{
// Chip init flow
// 1. Read chip id
// 2. (optional) Detect chip vendor
// 3. Get basic parameters of the chip (size, dummy count, etc.)
// 4. Init chip into desired mode (without breaking the cache!)
esp_err_t err = ESP_OK;
if (chip == NULL || chip->host == NULL || chip->host->driver == NULL ||
((memspi_host_inst_t*)chip->host)->spi == NULL) {
@ -201,22 +206,33 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
return rom_spiflash_api_funcs->end(chip, err);
}
//this is not public, but useful in unit tests
esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id)
static esp_err_t IRAM_ATTR read_id_core(esp_flash_t* chip, uint32_t* out_id, bool sanity_check)
{
bool installed = esp_flash_chip_driver_initialized(chip);
esp_err_t err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
// Send generic RDID command twice, check for a matching result and retry in case we just powered on (inner
// function fails if it sees all-ones or all-zeroes.)
err = chip->host->driver->read_id(chip->host, flash_id);
esp_err_t (*read_id_func)(void*, uint32_t*);
void* read_id_arg;
if (installed && chip->chip_drv->read_id) {
read_id_func = (void*)chip->chip_drv->read_id;
read_id_arg = (void*)chip;
} else {
//default option if the chip is not detected/chosen yet.
read_id_func = (void*)chip->host->driver->read_id;
read_id_arg = (void*)chip->host;
}
if (err == ESP_OK) { // check we see the same ID twice, in case of transient power-on errors
// Inner function fails if it sees all-ones or all-zeroes.
err = read_id_func(read_id_arg, out_id);
if (sanity_check && err == ESP_OK) {
// Send RDID command twice, check for a matching result and retry in case we just powered on
uint32_t new_id;
err = chip->host->driver->read_id(chip->host, &new_id);
if (err == ESP_OK && (new_id != *flash_id)) {
err = read_id_func(read_id_arg, &new_id);
if (err == ESP_OK && (new_id != *out_id)) {
err = ESP_ERR_FLASH_NOT_INITIALISED;
}
}
@ -224,6 +240,23 @@ esp_err_t IRAM_ATTR esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id
return rom_spiflash_api_funcs->end(chip, err);
}
// Faster version with sanity check.
// Called in esp_flash_init and unit test (though not public)
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* out_id)
{
return read_id_core(chip, out_id, true);
}
esp_err_t esp_flash_read_id(esp_flash_t* chip, uint32_t* out_id)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
//Accept uninitialized chip when reading chip id
if (err != ESP_OK && !(err == ESP_ERR_FLASH_NOT_INITIALISED && chip != NULL)) return err;
if (out_id == NULL) return ESP_ERR_INVALID_ARG;
return read_id_core(chip, out_id, false);
}
static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
{
esp_err_t err;
@ -271,23 +304,6 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
} \
} while (0)
esp_err_t IRAM_ATTR esp_flash_read_id(esp_flash_t *chip, uint32_t *out_id)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
//Accept uninitialized chip when reading chip id
if (err != ESP_OK && !(err == ESP_ERR_FLASH_NOT_INITIALISED && chip != NULL)) return err;
if (out_id == NULL) return ESP_ERR_INVALID_ARG;
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}
err = chip->host->driver->read_id(chip->host, out_id);
return rom_spiflash_api_funcs->end(chip, err);
}
esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);

View File

@ -59,6 +59,7 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
#define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD
#endif
//TODO: modify cs hold to meet requirements of all chips!!!
#if CONFIG_IDF_TARGET_ESP32
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI_HOST,\

View File

@ -107,7 +107,7 @@ esp_err_t memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, ui
void memspi_host_erase_chip(spi_flash_host_inst_t *host);
/**
* Erase a sector starting from a given address.
* Erase a sector starting from a given address. For 24bit address only.
*
* @param host The driver context.
* @param start_address Starting address of the sector.
@ -115,7 +115,7 @@ void memspi_host_erase_chip(spi_flash_host_inst_t *host);
void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a block starting from a given address.
* Erase a block starting from a given address. For 24bit address only.
*
* @param host The driver context.
* @param start_address Starting address of the block.
@ -123,7 +123,7 @@ void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addres
void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Program a page with contents of a buffer.
* Program a page with contents of a buffer. For 24bit address only.
*
* @param host The driver context.
* @param buffer Buffer which contains the data to be flashed.

View File

@ -29,6 +29,10 @@ typedef struct {
uint32_t page_program_timeout; ///< Timeout for page program operation
} flash_chip_op_timeout_t;
typedef enum {
SPI_FLASH_REG_STATUS = 1,
} spi_flash_register_t;
/** @brief SPI flash chip driver definition structure.
*
* The chip driver structure contains chip-specific pointers to functions to perform SPI flash operations, and some
@ -167,6 +171,17 @@ struct spi_flash_chip_t {
* enabled, otherwise disabled
*/
esp_err_t (*get_io_mode)(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode);
/*
* Read the chip ID. Called when chip driver is set, but we want to know the exact chip id (to
* get the size, etc.).
*/
esp_err_t (*read_id)(esp_flash_t *chip, uint32_t* out_chip_id);
/*
* Read the requested register (status, etc.).
*/
esp_err_t (*read_reg)(esp_flash_t *chip, spi_flash_register_t reg_id, uint32_t* out_reg);
};
/* Pointer to an array of pointers to all known drivers for flash chips. This array is used

View File

@ -189,6 +189,16 @@ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write
esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect);
#define ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT -1
/**
* @brief Send commands to read one of the reg of the chip
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param reg_id Type of the register to read
* @param out_reg Output of the register value
* @return esp_err_t Error code passed from the ``read_status`` function of host driver.
*/
esp_err_t spi_flash_chip_generic_read_reg(esp_flash_t* chip, spi_flash_register_t reg_id, uint32_t* out_reg);
/**
* @brief Read flash status via the RDSR command and wait for bit 0 (write in
* progress bit) to be cleared.
@ -362,13 +372,14 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
* transactions. Also prepare the command to be sent in read functions.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param addr_32bit Whether 32 bit commands will be used (Currently only W25Q256 is supported)
*
* @return
* - ESP_OK if success
* - ESP_ERR_FLASH_NOT_INITIALISED if chip not initialized properly
* - or other error passed from the ``configure_host_mode`` function of host driver
*/
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip);
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool addr_32bit);
/// Default timeout configuration used by most chips
const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;

View File

@ -0,0 +1,27 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "spi_flash_chip_driver.h"
/**
* Winbond SPI flash chip_drv, uses all the above functions for its operations. In
* default autodetection, this is used as a catchall if a more specific chip_drv
* is not found.
*/
extern const spi_flash_chip_t esp_flash_chip_winbond;

View File

@ -5,5 +5,6 @@ entries:
spi_flash_chip_generic (noflash)
spi_flash_chip_issi (noflash)
spi_flash_chip_mxic (noflash)
spi_flash_chip_gd(noflash)
spi_flash_chip_gd (noflash)
spi_flash_chip_winbond (noflash)
memspi_host_driver (noflash)

View File

@ -135,8 +135,10 @@ void memspi_host_erase_chip(spi_flash_host_inst_t *host)
host->driver->common_command(host, &t);
}
// Only support 24bit address
void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
{
assert(start_address < 0x1000000);
spi_flash_trans_t t = {
.command = CMD_SECTOR_ERASE,
.address_bitlen = 24,
@ -145,8 +147,10 @@ void memspi_host_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addres
host->driver->common_command(host, &t);
}
// Only support 24bit address
void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address)
{
assert(start_address < 0x1000000);
spi_flash_trans_t t = {
.command = CMD_LARGE_BLOCK_ERASE,
.address_bitlen = 24,
@ -155,8 +159,10 @@ void memspi_host_erase_block(spi_flash_host_inst_t *host, uint32_t start_address
host->driver->common_command(host, &t);
}
// Only support 24bit address
void memspi_host_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
{
assert(address + length <= 0x1000000);
spi_flash_trans_t t = {
.command = CMD_PROGRAM_PAGE,
.address_bitlen = 24,

View File

@ -27,25 +27,34 @@
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_FASTRD_QIO 0xEB
#define CMD_FASTRD_QUAD 0x6B
#define CMD_FASTRD_DIO 0xBB
#define CMD_FASTRD_DUAL 0x3B
#define CMD_FASTRD 0x0B
#define CMD_READ 0x03 /* Speed limited */
#define CMD_FASTRD_QIO 0xEB
#define CMD_FASTRD_QIO_4B 0xEC
#define CMD_FASTRD_QUAD 0x6B
#define CMD_FASTRD_QUAD_4B 0x6C
#define CMD_FASTRD_DIO 0xBB
#define CMD_FASTRD_DIO_4B 0xBC
#define CMD_FASTRD_DUAL 0x3B
#define CMD_FASTRD_DUAL_4B 0x3C
#define CMD_FASTRD 0x0B
#define CMD_FASTRD_4B 0x0C
#define CMD_READ 0x03 /* Speed limited */
#define CMD_READ_4B 0x13 /* Speed limited */
#define CMD_CHIP_ERASE 0xC7
#define CMD_SECTOR_ERASE 0x20
#define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */
#define CMD_PROGRAM_PAGE 0x02
#define CMD_CHIP_ERASE 0xC7
#define CMD_SECTOR_ERASE 0x20
#define CMD_SECTOR_ERASE_4B 0x21
#define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */
#define CMD_LARGE_BLOCK_ERASE_4B 0xDC /* 64KB block erase command */
#define CMD_PROGRAM_PAGE 0x02
#define CMD_PROGRAM_PAGE_4B 0x12
#define CMD_RST_EN 0x66
#define CMD_RST_DEV 0x99
#define SPI_FLASH_DIO_ADDR_BITLEN (24+4)
#define SPI_FLASH_DIO_DUMMY_BITLEN 2
#define SPI_FLASH_QIO_ADDR_BITLEN (24+8)
#define SPI_FLASH_QIO_DUMMY_BITLEN 4
#define SPI_FLASH_DIO_ADDR_BITLEN 24
#define SPI_FLASH_DIO_DUMMY_BITLEN 4
#define SPI_FLASH_QIO_ADDR_BITLEN 24
#define SPI_FLASH_QIO_DUMMY_BITLEN 6
#define SPI_FLASH_QOUT_ADDR_BITLEN 24
#define SPI_FLASH_QOUT_DUMMY_BITLEN 8
#define SPI_FLASH_DOUT_ADDR_BITLEN 24

View File

@ -18,6 +18,7 @@
#include "spi_flash_chip_issi.h"
#include "spi_flash_chip_mxic.h"
#include "spi_flash_chip_gd.h"
#include "spi_flash_chip_winbond.h"
#include "sdkconfig.h"
/*
@ -38,6 +39,9 @@ static const spi_flash_chip_t *default_registered_chips[] = {
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP
&esp_flash_chip_mxic,
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP
&esp_flash_chip_winbond,
#endif
// Default chip drivers that will accept all chip ID.
// FM, Winbond and XMC chips are supposed to be supported by this chip driver.

View File

@ -91,7 +91,6 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// TODO support protected regions on ISSI flash
.num_protectable_regions = 0,
.protectable_regions = NULL,
.get_protected_regions = NULL,
@ -106,4 +105,6 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_gd_set_io_mode,
.get_io_mode = spi_flash_chip_gd_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
};

View File

@ -191,7 +191,7 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t
uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte
// Configure the host, and return
err = spi_flash_chip_generic_config_host_io_mode(chip);
err = spi_flash_chip_generic_config_host_io_mode(chip, false);
if (err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(TAG, "configure host io mode failed - unsupported");
@ -313,6 +313,11 @@ esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_
return ESP_OK;
}
esp_err_t spi_flash_chip_generic_read_reg(esp_flash_t* chip, spi_flash_register_t reg_id, uint32_t* out_reg)
{
return chip->host->driver->read_status(chip->host, (uint8_t*)out_reg);
}
esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_us)
{
bool timeout_en = (timeout_us != ESP_FLASH_CHIP_GENERIC_NO_TIMEOUT);
@ -330,10 +335,13 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return err;
}
err = chip->host->driver->read_status(chip->host, &status);
uint32_t read;
err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read);
if (err != ESP_OK) {
return err;
}
status = read;
if ((status & SR_WIP) == 0) {
break; // Write in progress is complete
}
@ -349,51 +357,62 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
return (timeout_us > 0) ? ESP_OK : ESP_ERR_TIMEOUT;
}
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip)
esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool addr_32bit)
{
uint32_t dummy_cyclelen_base;
uint32_t addr_bitlen;
uint32_t read_command;
bool conf_required = false;
esp_flash_io_mode_t read_mode = chip->read_mode;
switch (chip->read_mode) {
switch (read_mode & 0xFFFF) {
case SPI_FLASH_QIO:
//for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_QIO_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->qio_dummy_bitlen;
read_command = CMD_FASTRD_QIO;
read_command = (addr_32bit? CMD_FASTRD_QIO_4B: CMD_FASTRD_QIO);
conf_required = true;
break;
case SPI_FLASH_QOUT:
addr_bitlen = SPI_FLASH_QOUT_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->qout_dummy_bitlen;
read_command = CMD_FASTRD_QUAD;
read_command = (addr_32bit? CMD_FASTRD_QUAD_4B: CMD_FASTRD_QUAD);
break;
case SPI_FLASH_DIO:
//for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
addr_bitlen = SPI_FLASH_DIO_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->dio_dummy_bitlen;
read_command = CMD_FASTRD_DIO;
read_command = (addr_32bit? CMD_FASTRD_DIO_4B: CMD_FASTRD_DIO);
conf_required = true;
break;
case SPI_FLASH_DOUT:
addr_bitlen = SPI_FLASH_DOUT_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->dout_dummy_bitlen;
read_command = CMD_FASTRD_DUAL;
read_command = (addr_32bit? CMD_FASTRD_DUAL_4B: CMD_FASTRD_DUAL);
break;
case SPI_FLASH_FASTRD:
addr_bitlen = SPI_FLASH_FASTRD_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->fastrd_dummy_bitlen;
read_command = CMD_FASTRD;
read_command = (addr_32bit? CMD_FASTRD_4B: CMD_FASTRD);
break;
case SPI_FLASH_SLOWRD:
addr_bitlen = SPI_FLASH_SLOWRD_ADDR_BITLEN;
dummy_cyclelen_base = rom_flash_chip_dummy->slowrd_dummy_bitlen;
read_command = CMD_READ;
read_command = (addr_32bit? CMD_READ_4B: CMD_READ);
break;
default:
return ESP_ERR_FLASH_NOT_INITIALISED;
}
//For W25Q256 chip, the only difference between 4-Byte address command and 3-Byte version is the command value and the address bit length.
if (addr_32bit) {
addr_bitlen += 8;
}
return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base,
chip->read_mode);
if (conf_required) {
read_mode |= SPI_FLASH_CONFIG_CONF_BITS;
}
return chip->host->driver->configure_host_io_mode(chip->host, read_command, addr_bitlen, dummy_cyclelen_base, read_mode);
}
esp_err_t spi_flash_chip_generic_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
@ -455,6 +474,8 @@ const spi_flash_chip_t esp_flash_chip_generic = {
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_generic_set_io_mode,
.get_io_mode = spi_flash_chip_generic_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
};
/*******************************************************************************
@ -586,4 +607,4 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
chip->chip_drv->set_chip_write_protect(chip, true);
}
return ret;
}
}

View File

@ -77,7 +77,6 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// TODO support protected regions on ISSI flash
.num_protectable_regions = 0,
.protectable_regions = NULL,
.get_protected_regions = NULL,
@ -92,4 +91,6 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_issi_set_io_mode,
.get_io_mode = spi_flash_chip_issi_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
};

View File

@ -35,6 +35,7 @@ esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t
// Use the same implementation as ISSI chips
#define spi_flash_chip_mxic_set_io_mode spi_flash_chip_issi_set_io_mode
#define spi_flash_chip_mxic_get_io_mode spi_flash_chip_issi_get_io_mode
#define spi_flash_chip_mxic_read_reg spi_flash_chip_generic_read_reg
static const char chip_name[] = "mxic";
@ -55,7 +56,6 @@ const spi_flash_chip_t esp_flash_chip_mxic = {
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// TODO support protected regions on MXIC flash
.num_protectable_regions = 0,
.protectable_regions = NULL,
.get_protected_regions = NULL,
@ -70,4 +70,6 @@ const spi_flash_chip_t esp_flash_chip_mxic = {
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_mxic_set_io_mode,
.get_io_mode = spi_flash_chip_mxic_get_io_mode,
.read_reg = spi_flash_chip_mxic_read_reg,
};

View File

@ -0,0 +1,214 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include <sys/param.h> // For MIN/MAX
#include "esp_log.h"
#include "spi_flash_chip_generic.h"
#include "spi_flash_defs.h"
#define REGION_32BIT(start, len) ((start) + (len) > (1<<24))
#define ADDR_32BIT(addr) (addr >= (1<<24))
static const char TAG[] = "chip_wb";
/* Driver for Winbond flash chip */
static esp_err_t spi_flash_command_winbond_program_4B(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
static esp_err_t spi_flash_command_winbond_erase_sector_4B(esp_flash_t *chip, uint32_t start_address);
static esp_err_t spi_flash_command_erase_block_4B(esp_flash_t *chip, uint32_t start_address);
esp_err_t spi_flash_chip_winbond_probe(esp_flash_t *chip, uint32_t flash_id)
{
/* Check manufacturer and product IDs match our desired masks */
const uint8_t MFG_ID = 0xEF;
if (flash_id >> 16 != MFG_ID) {
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
esp_err_t spi_flash_chip_winbond_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err = ESP_OK;
const uint32_t page_size = chip->chip_drv->page_size;
uint32_t align_address;
uint8_t temp_buffer[64]; //spiflash hal max length of read no longer than 64byte
// Configure the host, and return
err = spi_flash_chip_generic_config_host_io_mode(chip, REGION_32BIT(address, length));
if (err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGE(TAG, "configure host io mode failed - unsupported");
return err;
}
while (err == ESP_OK && length > 0) {
memset(temp_buffer, 0xFF, sizeof(temp_buffer));
uint32_t read_len = chip->host->driver->read_data_slicer(chip->host, address, length, &align_address, page_size);
uint32_t left_off = address - align_address;
uint32_t data_len = MIN(align_address + read_len, address + length) - address;
err = chip->host->driver->read(chip->host, temp_buffer, align_address, read_len);
memcpy(buffer, temp_buffer + left_off, data_len);
address += data_len;
buffer = (void *)((intptr_t)buffer + data_len);
length = length - data_len;
}
return err;
}
esp_err_t spi_flash_chip_winbond_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err;
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
if (err == ESP_OK) {
// Perform the actual Page Program command
err = spi_flash_command_winbond_program_4B(chip, buffer, address, length);
if (err != ESP_OK) {
return err;
}
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->page_program_timeout);
}
return err;
}
esp_err_t spi_flash_chip_winbond_erase_sector(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
err = spi_flash_command_winbond_erase_sector_4B(chip, start_address);
if (err != ESP_OK) {
return err;
}
//to save time, flush cache here
if (chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->sector_size);
if (err != ESP_OK) {
return err;
}
}
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->sector_erase_timeout);
}
return err;
}
esp_err_t spi_flash_chip_winbond_erase_block(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->idle_timeout);
}
if (err == ESP_OK) {
err = spi_flash_command_erase_block_4B(chip, start_address);
if (err != ESP_OK) {
return err;
}
//to save time, flush cache here
if (chip->host->driver->flush_cache) {
err = chip->host->driver->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size);
if (err != ESP_OK) {
return err;
}
}
err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->block_erase_timeout);
}
return err;
}
static const char chip_name[] = "winbond";
// The issi chip can use the functions for generic chips except from set read mode and probe,
// So we only replace these two functions.
const spi_flash_chip_t esp_flash_chip_winbond = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_winbond_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,
.erase_chip = spi_flash_chip_generic_erase_chip,
.erase_sector = spi_flash_chip_winbond_erase_sector,
.erase_block = spi_flash_chip_winbond_erase_block,
.sector_size = 4 * 1024,
.block_erase_size = 64 * 1024,
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
.num_protectable_regions = 0,
.protectable_regions = NULL,
.get_protected_regions = NULL,
.set_protected_regions = NULL,
.read = spi_flash_chip_winbond_read,
.write = spi_flash_chip_generic_write,
.program_page = spi_flash_chip_winbond_page_program,
.page_size = 256,
.write_encrypted = spi_flash_chip_generic_write_encrypted,
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_generic_set_io_mode,
.get_io_mode = spi_flash_chip_generic_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
};
static esp_err_t spi_flash_command_winbond_program_4B(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
bool addr_4b = ADDR_32BIT(address);
spi_flash_trans_t t = {
.command = (addr_4b? CMD_PROGRAM_PAGE_4B: CMD_PROGRAM_PAGE),
.address_bitlen = (addr_4b? 32: 24),
.address = address,
.mosi_len = length,
.mosi_data = buffer,
};
return chip->host->driver->common_command(chip->host, &t);
}
esp_err_t spi_flash_command_winbond_erase_sector_4B(esp_flash_t *chip, uint32_t start_address)
{
bool addr_4b = ADDR_32BIT(start_address);
spi_flash_trans_t t = {
.command = (addr_4b? CMD_SECTOR_ERASE_4B: CMD_SECTOR_ERASE),
.address_bitlen = (addr_4b? 32: 24),
.address = start_address,
};
return chip->host->driver->common_command(chip->host, &t);
}
esp_err_t spi_flash_command_erase_block_4B(esp_flash_t *chip, uint32_t start_address)
{
bool addr_4b = ADDR_32BIT(start_address);
spi_flash_trans_t t = {
.command = (addr_4b? CMD_LARGE_BLOCK_ERASE_4B: CMD_LARGE_BLOCK_ERASE),
.address_bitlen = (addr_4b? 32: 24),
.address = start_address,
};
return chip->host->driver->common_command(chip->host, &t);
}

View File

@ -27,6 +27,7 @@
static uint8_t sector_buf[4096];
#define MAX_ADDR_24BIT 0x1000000
#define TEST_SPI_SPEED ESP_FLASH_10MHZ
#define TEST_SPI_READ_MODE SPI_FLASH_FASTRD
// #define FORCE_GPIO_MATRIX
@ -92,7 +93,7 @@ static uint8_t sector_buf[4096];
#define TEST_CONFIG_NUM (sizeof(config_list)/sizeof(flashtest_config_t))
typedef void (*flash_test_func_t)(esp_flash_t* chip);
typedef void (*flash_test_func_t)(const esp_partition_t *part);
/* Use FLASH_TEST_CASE for SPI flash tests that only use the main SPI flash chip
*/
@ -348,39 +349,63 @@ static void setup_new_chip(const flashtest_config_t* test_cfg, esp_flash_t** out
TEST_ESP_OK(err);
err = esp_flash_init(init_chip);
TEST_ESP_OK(err);
uint32_t size;
err = esp_flash_get_size(init_chip, &size);
TEST_ESP_OK(err);
ESP_LOGI(TAG, "Flash size: 0x%08X", size);
*out_chip = init_chip;
}
void teardown_test_chip(esp_flash_t* chip, spi_host_device_t host)
static void teardown_test_chip(esp_flash_t* chip)
{
spi_host_device_t host_id;
get_chip_host(chip, &host_id, NULL);
//happen to work when chip==NULL
spi_bus_remove_flash_device(chip);
release_bus(host);
release_bus(host_id);
}
static void flash_test_core(flash_test_func_t func, const flashtest_config_t* config)
{
esp_flash_t* chip;
setup_new_chip(config, &chip);
uint32_t size;
esp_err_t err = esp_flash_get_size(chip, &size);
TEST_ESP_OK(err);
ESP_LOGI(TAG, "Flash size: 0x%08X", size);
const esp_partition_t* test_part = get_test_data_partition();
TEST_ASSERT_NOT_EQUAL(NULL, test_part->flash_chip);
esp_partition_t part = *test_part;
part.flash_chip = chip;
ESP_LOGI(TAG, "Testing chip %p, address 0x%08X...", part.flash_chip, part.address);
(*func)(&part);
// For flash with size over 16MB, add one extra round of test for the 32-bit address area
if (size > MAX_ADDR_24BIT) {
part.address = 0x1030000;
part.size = 0x0010000;
ESP_LOGI(TAG, "Testing chip %p, address 0x%08X...", part.flash_chip, part.address);
(*func)(&part);
}
teardown_test_chip(chip);
}
static void flash_test_func(flash_test_func_t func, int test_num)
{
esp_log_level_set("gpio", ESP_LOG_NONE);
for (int i = 0; i < test_num; i++) {
ESP_LOGI(TAG, "Testing config %d/%d", i, test_num);
flashtest_config_t* config = &config_list[i];
esp_flash_t* chip;
setup_new_chip(config, &chip);
(*func)(chip);
teardown_test_chip(chip, config->host_id);
ESP_LOGI(TAG, "Testing config %d/%d", i+1, test_num);
flash_test_core(func, &config_list[i]);
}
ESP_LOGI(TAG, "Completed %d configs", test_num);
}
/* ---------- Test code start ------------*/
static void test_metadata(esp_flash_t *chip)
static void test_metadata(const esp_partition_t* part)
{
ESP_LOGI(TAG, "Testing chip %p...", chip);
esp_flash_t* chip = part->flash_chip;
uint32_t id, size;
TEST_ESP_OK(esp_flash_read_id(chip, &id));
TEST_ESP_OK(esp_flash_get_size(chip, &size));
@ -390,9 +415,9 @@ static void test_metadata(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash metadata functions", test_metadata);
FLASH_TEST_CASE_3("SPI flash metadata functions", test_metadata);
static uint32_t erase_test_region(esp_flash_t *chip, int num_sectors)
static uint32_t erase_test_region(const esp_partition_t *part, int num_sectors)
{
const esp_partition_t *part = get_test_data_partition();
esp_flash_t* chip = part->flash_chip;
uint32_t offs = part->address;
/* chip should be initialised */
@ -419,10 +444,10 @@ static uint32_t erase_test_region(esp_flash_t *chip, int num_sectors)
return offs;
}
void test_simple_read_write(esp_flash_t *chip)
void test_simple_read_write(const esp_partition_t* part)
{
ESP_LOGI(TAG, "Testing chip %p...", chip);
uint32_t offs = erase_test_region(chip, 1);
esp_flash_t* chip = part->flash_chip;
uint32_t offs = erase_test_region(part, 1);
const int test_seed = 778;
srand(test_seed);
@ -450,10 +475,10 @@ void test_simple_read_write(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash simple read/write", test_simple_read_write);
FLASH_TEST_CASE_3("SPI flash simple read/write", test_simple_read_write);
void test_unaligned_read_write(esp_flash_t *chip)
void test_unaligned_read_write(const esp_partition_t* part)
{
ESP_LOGI(TAG, "Testing chip %p...", chip);
uint32_t offs = erase_test_region(chip, 2);
esp_flash_t* chip = part->flash_chip;
uint32_t offs = erase_test_region(part, 2);
const char *msg = "i am a message";
TEST_ASSERT(strlen(msg) + 1 % 4 != 0);
@ -471,12 +496,12 @@ void test_unaligned_read_write(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash unaligned read/write", test_unaligned_read_write);
FLASH_TEST_CASE_3("SPI flash unaligned read/write", test_unaligned_read_write);
void test_single_read_write(esp_flash_t* chip)
void test_single_read_write(const esp_partition_t* part)
{
const int seed = 699;
ESP_LOGI(TAG, "Testing chip %p...", chip);
uint32_t offs = erase_test_region(chip, 2);
esp_flash_t* chip = part->flash_chip;
uint32_t offs = erase_test_region(part, 2);
const int seed = 699;
srand(seed);
for (unsigned v = 0; v < 512; v++) {
uint32_t data = rand();
@ -499,11 +524,12 @@ FLASH_TEST_CASE_3("SPI flash single byte reads/writes", test_single_read_write);
/* this test is notable because it generates a lot of unaligned reads/writes,
and also reads/writes across both a sector boundary & many page boundaries.
*/
void test_three_byte_read_write(esp_flash_t *chip)
void test_three_byte_read_write(const esp_partition_t* part)
{
esp_flash_t* chip = part->flash_chip;
uint32_t offs = erase_test_region(part, 2);
const int seed = 700;
ESP_LOGI(TAG, "Testing chip %p...", chip);
uint32_t offs = erase_test_region(chip, 2);
esp_rom_printf("offs:%X\n", offs);
srand(seed);
@ -524,11 +550,9 @@ void test_three_byte_read_write(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash three byte reads/writes", test_three_byte_read_write);
FLASH_TEST_CASE_3("SPI flash three byte reads/writes", test_three_byte_read_write);
void test_erase_large_region(esp_flash_t *chip)
void test_erase_large_region(const esp_partition_t *part)
{
ESP_LOGI(TAG, "Testing chip %p...", chip);
const esp_partition_t *part = get_test_data_partition();
esp_flash_t* chip = part->flash_chip;
/* Write some noise at the start and the end of the region */
const char *ohai = "OHAI";
@ -557,8 +581,10 @@ void test_erase_large_region(esp_flash_t *chip)
FLASH_TEST_CASE("SPI flash erase large region", test_erase_large_region);
FLASH_TEST_CASE_3("SPI flash erase large region", test_erase_large_region);
static void test_write_protection(esp_flash_t* chip)
static void test_write_protection(const esp_partition_t* part)
{
esp_flash_t* chip = part->flash_chip;
bool wp = true;
esp_err_t ret = ESP_OK;
ret = esp_flash_get_chip_write_protect(chip, &wp);
@ -591,9 +617,9 @@ static const uint8_t large_const_buffer[16400] = {
43 // last byte
};
static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length);
static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length);
static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length);
static void test_write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length);
static void write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length);
static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length);
// Internal functions for testing, from esp_flash_api.c
esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe);
@ -621,8 +647,10 @@ static bool is_mxic_chip(esp_flash_t* chip)
return (spi_flash_chip_mxic_probe(chip, flash_id)==ESP_OK);
}
IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(esp_flash_t* chip)
IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(const esp_partition_t* part)
{
esp_flash_t* chip = part->flash_chip;
bool qe;
if (chip == NULL) {
chip = esp_flash_default_chip;
@ -669,33 +697,8 @@ IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(esp_flash_t* chip)
FLASH_TEST_CASE_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
FLASH_TEST_CASE_3_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
void test_permutations(flashtest_config_t* config)
void test_permutations_part(const flashtest_config_t* config, esp_partition_t* part, void* source_buf, size_t length)
{
//replace config pointer with pointer to internal temporary config
flashtest_config_t temp_cfg;
memcpy(&temp_cfg, config, sizeof(flashtest_config_t));
flashtest_config_t* cfg = &temp_cfg;
esp_flash_t* chip;
const int length = sizeof(large_const_buffer);
uint8_t *source_buf = malloc(length);
TEST_ASSERT_NOT_NULL(source_buf);
srand(778);
for (int i = 0; i < length; i++) {
source_buf[i] = rand();
}
const esp_partition_t *part = get_test_data_partition();
TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE);
//write data to be read, and use the lowest speed to write and read to make sure success
cfg->io_mode = SPI_FLASH_READ_MODE_MIN;
cfg->speed = ESP_FLASH_SPEED_MIN;
setup_new_chip(cfg, &chip);
write_large_buffer(chip, part, source_buf, length);
read_and_check(chip, part, source_buf, length);
teardown_test_chip(chip, cfg->host_id);
if (config->host_id != -1) {
esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN;
while (speed != ESP_FLASH_SPEED_MAX) {
@ -703,27 +706,90 @@ void test_permutations(flashtest_config_t* config)
//the io mode will switch frequently.
esp_flash_io_mode_t io_mode = SPI_FLASH_READ_MODE_MIN;
while (io_mode != SPI_FLASH_READ_MODE_MAX) {
cfg->io_mode = io_mode;
cfg->speed = speed;
if (io_mode > SPI_FLASH_FASTRD\
&& !SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(cfg->host_id)) {
if (io_mode > SPI_FLASH_FASTRD &&
!SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(config->host_id)) {
io_mode++;
continue;
}
setup_new_chip(cfg, &chip);
esp_flash_t* chip;
flashtest_config_t temp_config = *config;
temp_config.io_mode = io_mode;
temp_config.speed = speed;
setup_new_chip(&temp_config, &chip);
ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed);
read_and_check(chip, part, source_buf, length);
teardown_test_chip(chip, cfg->host_id);
part->flash_chip = chip;
read_and_check(part, source_buf, length);
teardown_test_chip(chip);
io_mode++;
}
speed++;
}
} else {
//test main flash
write_large_buffer(NULL, part, source_buf, length);
read_and_check(NULL, part, source_buf, length);
part->flash_chip = NULL;
read_and_check(part, source_buf, length);
}
}
void test_permutations_chip(const flashtest_config_t* config)
{
esp_log_level_set("gpio", ESP_LOG_NONE);
esp_flash_t* chip;
flashtest_config_t temp_config = *config;
// Use the lowest speed to read configs, data and write data to make sure success
temp_config.io_mode = SPI_FLASH_READ_MODE_MIN;
temp_config.speed = ESP_FLASH_SPEED_MIN;
setup_new_chip(&temp_config, &chip);
//Get size to determine whether to test one extra partition
uint32_t size;
esp_err_t err = esp_flash_get_size(chip, &size);
TEST_ESP_OK(err);
ESP_LOGI(TAG, "Flash size: 0x%08X", size);
bool addr_32bit = (size > MAX_ADDR_24BIT);
// Get test partition, and locate temporary partitions according to the default one
const esp_partition_t* test_part = get_test_data_partition();
const int length = sizeof(large_const_buffer);
TEST_ASSERT(test_part->size > length + 2 + SPI_FLASH_SEC_SIZE);
esp_partition_t part[2] = {};
part[0] = *test_part;
part[0].flash_chip = chip;
// For flash with size over 16MB, add one extra round of test for the 32-bit address area
if (addr_32bit) {
part[1] = *test_part;
part[1].flash_chip = chip;
part[1].address = 0x1030000;
part[1].size = 0x0010000;
} else {
part[1].size = 0;
}
// Prepare test data and write to the specified region
uint8_t *source_buf = malloc(length);
TEST_ASSERT_NOT_NULL(source_buf);
srand(778);
for (int i = 0; i < length; i++) {
source_buf[i] = rand();
}
for (int i = 0; i < 2; i++) {
if (part[i].size == 0) continue;
write_large_buffer(&part[i], source_buf, length);
}
teardown_test_chip(chip);
for (int i = 0; i < 2; i++) {
if (part[i].size == 0) continue;
part[i].flash_chip = (esp_flash_t*)-1;
ESP_LOGI(TAG, "Testing address 0x%08X...", part[i].address);
test_permutations_part(config, &part[i], source_buf, length);
}
free(source_buf);
@ -731,42 +797,44 @@ void test_permutations(flashtest_config_t* config)
TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash]")
{
test_permutations(&config_list[0]);
test_permutations_chip(&config_list[0]);
}
#ifndef CONFIG_SPIRAM
TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]")
{
for (int i = 0; i < TEST_CONFIG_NUM; i++) {
test_permutations(&config_list[i]);
test_permutations_chip(&config_list[i]);
}
}
#endif
static void test_write_large_const_buffer(esp_flash_t* chip)
static void test_write_large_const_buffer(const esp_partition_t* part)
{
test_write_large_buffer(chip, large_const_buffer, sizeof(large_const_buffer));
test_write_large_buffer(part, large_const_buffer, sizeof(large_const_buffer));
}
FLASH_TEST_CASE("Test esp_flash_write large const buffer", test_write_large_const_buffer);
FLASH_TEST_CASE_3("Test esp_flash_write large const buffer", test_write_large_const_buffer);
static void test_write_large_ram_buffer(esp_flash_t* chip)
static void test_write_large_ram_buffer(const esp_partition_t* part)
{
// buffer in RAM
uint8_t *source_buf = malloc(sizeof(large_const_buffer));
TEST_ASSERT_NOT_NULL(source_buf);
memcpy(source_buf, large_const_buffer, sizeof(large_const_buffer));
test_write_large_buffer(chip, source_buf, sizeof(large_const_buffer));
test_write_large_buffer(part, source_buf, sizeof(large_const_buffer));
free(source_buf);
}
FLASH_TEST_CASE("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer);
FLASH_TEST_CASE_3("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer);
static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length)
static void write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length)
{
printf("Writing chip %p, %d bytes from source %p\n", chip, length, source);
esp_flash_t* chip = part->flash_chip;
printf("Writing chip %p %p, %d bytes from source %p\n", chip, (void*)part->address, length, source);
ESP_ERROR_CHECK( esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)) );
@ -774,9 +842,10 @@ static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, c
ESP_ERROR_CHECK( esp_flash_write(chip, source, part->address + 1, length) );
}
static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length)
static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length)
{
printf("Checking chip %p, %d bytes\n", chip, length);
esp_flash_t* chip = part->flash_chip;
printf("Checking chip %p 0x%08X, %d bytes\n", chip, part->address, length);
uint8_t *buf = malloc(length);
TEST_ASSERT_NOT_NULL(buf);
ESP_ERROR_CHECK( esp_flash_read(chip, buf, part->address + 1, length) );
@ -798,14 +867,12 @@ static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[3]);
}
static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length)
static void test_write_large_buffer(const esp_partition_t* part, const uint8_t *source, size_t length)
{
ESP_LOGI(TAG, "Testing chip %p...", chip);
const esp_partition_t *part = get_test_data_partition();
TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE);
write_large_buffer(chip, part, source, length);
read_and_check(chip, part, source, length);
write_large_buffer(part, source, length);
read_and_check(part, source, length);
}
typedef struct {
@ -889,18 +956,12 @@ static uint32_t measure_read(const char* name, const esp_partition_t* part, uint
return time_measure_end(&time_ctx);
}
#define MEAS_WRITE(n) (measure_write("write in "#n"-byte chunks", &test_part, data_to_write, n))
#define MEAS_READ(n) (measure_read("read in "#n"-byte chunks", &test_part, data_read, n))
#define MEAS_WRITE(n) (measure_write("write in "#n"-byte chunks", part, data_to_write, n))
#define MEAS_READ(n) (measure_read("read in "#n"-byte chunks", part, data_read, n))
static void test_flash_read_write_performance(esp_flash_t* chip)
static void test_flash_read_write_performance(const esp_partition_t *part)
{
const esp_partition_t *part = get_test_data_partition();
// Copy to new partition variable and replace the chip member
// Actually there's no "partition" in the external flash on runners. We just don't bother creating a new partition variable.
esp_partition_t test_part;
memcpy(&test_part, part, sizeof(esp_partition_t));
test_part.flash_chip = chip;
esp_flash_t* chip = part->flash_chip;
const int total_len = SPI_FLASH_SEC_SIZE;
uint8_t *data_to_write = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
uint8_t *data_read = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
@ -910,10 +971,10 @@ static void test_flash_read_write_performance(esp_flash_t* chip)
data_to_write[i] = rand();
}
uint32_t erase_1 = measure_erase(&test_part);
uint32_t erase_1 = measure_erase(part);
uint32_t speed_WR_4B = MEAS_WRITE(4);
uint32_t speed_RD_4B = MEAS_READ(4);
uint32_t erase_2 = measure_erase(&test_part);
uint32_t erase_2 = measure_erase(part);
uint32_t speed_WR_2KB = MEAS_WRITE(2048);
uint32_t speed_RD_2KB = MEAS_READ(2048);
@ -958,7 +1019,6 @@ static void test_flash_read_write_performance(esp_flash_t* chip)
FLASH_TEST_CASE("Test esp_flash read/write performance", test_flash_read_write_performance);
FLASH_TEST_CASE_3("Test esp_flash read/write performance", test_flash_read_write_performance);
#ifdef CONFIG_SPIRAM_USE_MALLOC
/* Utility: Read into a small internal RAM buffer using esp_flash_read() and compare what
@ -978,8 +1038,9 @@ static void s_test_compare_flash_contents_small_reads(esp_flash_t *chip, const u
free(ibuf);
}
static void test_flash_read_large_psram_buffer(esp_flash_t *chip)
static void test_flash_read_large_psram_buffer(const esp_partition_t *part)
{
esp_flash_t* chip = part->flash_chip;
const size_t BUF_SZ = 256 * 1024; // Too large for internal RAM
const size_t TEST_OFFS = 0x1000; // Can be any offset, really
@ -998,8 +1059,9 @@ FLASH_TEST_CASE("esp_flash_read large PSRAM buffer", test_flash_read_large_psram
/* similar to above test, but perform it under memory pressure */
static void test_flash_read_large_psram_buffer_low_internal_mem(esp_flash_t *chip)
static void test_flash_read_large_psram_buffer_low_internal_mem(const esp_partition_t *part)
{
esp_flash_t* chip = part->flash_chip;
const size_t BUF_SZ = 256 * 1024; // Too large for internal RAM
const size_t REMAINING_INTERNAL = 1024; // Exhaust internal memory until maximum free block is less than this
const size_t TEST_OFFS = 0x8000;

View File

@ -69,6 +69,26 @@ static int cmp_or_dump(const void *a, const void *b, size_t len)
return r;
}
static void IRAM_ATTR fix_rom_func(void)
{
#ifdef CONFIG_IDF_TARGET_ESP32S2
esp_rom_spiflash_read_mode_t read_mode;
# if defined CONFIG_ESPTOOLPY_FLASHMODE_QIO
read_mode = ESP_ROM_SPIFLASH_QIO_MODE;
# elif defined CONFIG_ESPTOOLPY_FLASHMODE_QOUT
read_mode = ESP_ROM_SPIFLASH_QOUT_MODE;
# elif defined CONFIG_ESPTOOLPY_FLASHMODE_DIO
read_mode = ESP_ROM_SPIFLASH_DIO_MODE;
# elif defined CONFIG_ESPTOOLPY_FLASHMODE_DOUT
read_mode = ESP_ROM_SPIFLASH_DOUT_MODE;
# endif
//Currently only call this can fix the rom_read issue, maybe we need to call more functions (freq, dummy, etc) in the future
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_spiflash_config_readmode(read_mode);
spi_flash_enable_interrupts_caches_and_other_cpu();
#endif
}
static void IRAM_ATTR test_read(int src_off, int dst_off, int len)
{
uint32_t src_buf[16];
@ -161,6 +181,8 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len)
}
ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len));
fix_rom_func();
spi_flash_disable_interrupts_caches_and_other_cpu();
esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(start, dst_buf, sizeof(dst_buf));
spi_flash_enable_interrupts_caches_and_other_cpu();

View File

@ -41,6 +41,7 @@ components/esp_wifi/esp32/include/phy_init_data.h
components/spi_flash/include/spi_flash_chip_issi.h
components/spi_flash/include/spi_flash_chip_mxic.h
components/spi_flash/include/spi_flash_chip_gd.h
components/spi_flash/include/spi_flash_chip_winbond.h
components/spi_flash/include/memspi_host_driver.h
components/spi_flash/include/spi_flash_chip_driver.h
components/spi_flash/include/spi_flash_chip_generic.h