mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
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:
commit
23584e094f
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,\
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
27
components/spi_flash/include/spi_flash_chip_winbond.h
Normal file
27
components/spi_flash/include/spi_flash_chip_winbond.h
Normal 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;
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
214
components/spi_flash/spi_flash_chip_winbond.c
Normal file
214
components/spi_flash/spi_flash_chip_winbond.c
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user