mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
spi_flash: Add option to verify all writes by reading back data
Helpful when debugging SPI flash hardware related issues. TW15203
This commit is contained in:
parent
582b731c23
commit
892b3ff14b
@ -1,5 +1,22 @@
|
|||||||
menu "SPI Flash driver"
|
menu "SPI Flash driver"
|
||||||
|
|
||||||
|
config SPI_FLASH_VERIFY_WRITE
|
||||||
|
bool "Verify SPI flash writes"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
If this option is enabled, any time SPI flash is written then the data will be read
|
||||||
|
back and verified. This can catch hardware problems with SPI flash, or flash which
|
||||||
|
was not erased before verification.
|
||||||
|
|
||||||
|
config SPI_FLASH_LOG_FAILED_WRITE
|
||||||
|
bool "Log errors if verification fails"
|
||||||
|
depends on SPI_FLASH_VERIFY_WRITE
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
If this option is enabled, if SPI flash write verification fails then a log error line
|
||||||
|
will be written with the address, expected & actual values. This can be useful when
|
||||||
|
debugging hardware SPI flash problems.
|
||||||
|
|
||||||
config SPI_FLASH_ENABLE_COUNTERS
|
config SPI_FLASH_ENABLE_COUNTERS
|
||||||
bool "Enable operation counters"
|
bool "Enable operation counters"
|
||||||
default 0
|
default 0
|
||||||
|
@ -44,8 +44,9 @@
|
|||||||
#define MAX_WRITE_CHUNK 8192
|
#define MAX_WRITE_CHUNK 8192
|
||||||
#define MAX_READ_CHUNK 16384
|
#define MAX_READ_CHUNK 16384
|
||||||
|
|
||||||
|
static const char *TAG __attribute__((unused)) = "spi_flash";
|
||||||
|
|
||||||
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
|
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
|
||||||
static const char *TAG = "spi_flash";
|
|
||||||
static spi_flash_counters_t s_flash_stats;
|
static spi_flash_counters_t s_flash_stats;
|
||||||
|
|
||||||
#define COUNTER_START() uint32_t ts_begin = xthal_get_ccount()
|
#define COUNTER_START() uint32_t ts_begin = xthal_get_ccount()
|
||||||
@ -233,6 +234,66 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
|
|||||||
return spi_flash_translate_rc(rc);
|
return spi_flash_translate_rc(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Wrapper around esp_rom_spiflash_write() that verifies data as written if CONFIG_SPI_FLASH_VERIFY_WRITE is set.
|
||||||
|
|
||||||
|
If CONFIG_SPI_FLASH_VERIFY_WRITE is not set, this is esp_rom_spiflash_write().
|
||||||
|
*/
|
||||||
|
static IRAM_ATTR esp_rom_spiflash_result_t spi_flash_write_inner(uint32_t target, const uint32_t *src_addr, int32_t len)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_SPI_FLASH_VERIFY_WRITE
|
||||||
|
return esp_rom_spiflash_write(target, src_addr, len);
|
||||||
|
#else // CONFIG_SPI_FLASH_VERIFY_WRITE
|
||||||
|
esp_rom_spiflash_result_t res = ESP_ROM_SPIFLASH_RESULT_OK;
|
||||||
|
assert(len % sizeof(uint32_t) == 0);
|
||||||
|
|
||||||
|
uint32_t before_buf[ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM / sizeof(uint32_t)];
|
||||||
|
uint32_t after_buf[ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM / sizeof(uint32_t)];
|
||||||
|
int32_t remaining = len;
|
||||||
|
for(int i = 0; i < len; i += sizeof(before_buf)) {
|
||||||
|
int i_w = i / sizeof(uint32_t); // index in words (i is an index in bytes)
|
||||||
|
|
||||||
|
int32_t read_len = MIN(sizeof(before_buf), remaining);
|
||||||
|
|
||||||
|
// Read "before" contents from flash
|
||||||
|
res = esp_rom_spiflash_read(target + i, before_buf, read_len);
|
||||||
|
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = esp_rom_spiflash_write(target + i, &src_addr[i_w], read_len);
|
||||||
|
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = esp_rom_spiflash_read(target + i, after_buf, read_len);
|
||||||
|
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int r = 0; r < read_len; r += sizeof(uint32_t)) {
|
||||||
|
int r_w = r / sizeof(uint32_t); // index in words (r is index in bytes)
|
||||||
|
|
||||||
|
uint32_t expected = src_addr[i_w + r_w] & before_buf[r_w];
|
||||||
|
uint32_t actual = after_buf[r_w];
|
||||||
|
if (expected != actual) {
|
||||||
|
#ifdef CONFIG_SPI_FLASH_LOG_FAILED_WRITE
|
||||||
|
spi_flash_guard_end();
|
||||||
|
ESP_LOGE(TAG, "Bad write at offset 0x%x expected 0x%08x readback 0x%08x", target + i + r, expected, actual);
|
||||||
|
spi_flash_guard_start();
|
||||||
|
#endif
|
||||||
|
res = ESP_ROM_SPIFLASH_RESULT_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
remaining -= read_len;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
#endif // CONFIG_SPI_FLASH_VERIFY_WRITE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
||||||
{
|
{
|
||||||
CHECK_WRITE_ADDRESS(dst, size);
|
CHECK_WRITE_ADDRESS(dst, size);
|
||||||
@ -269,7 +330,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
|||||||
uint32_t t = 0xffffffff;
|
uint32_t t = 0xffffffff;
|
||||||
memcpy(((uint8_t *) &t) + (dst - left_off), srcc, left_size);
|
memcpy(((uint8_t *) &t) + (dst - left_off), srcc, left_size);
|
||||||
spi_flash_guard_start();
|
spi_flash_guard_start();
|
||||||
rc = esp_rom_spiflash_write(left_off, &t, 4);
|
rc = spi_flash_write_inner(left_off, &t, 4);
|
||||||
spi_flash_guard_end();
|
spi_flash_guard_end();
|
||||||
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
|
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||||
goto out;
|
goto out;
|
||||||
@ -296,7 +357,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
|||||||
write_src = (const uint8_t *)write_buf;
|
write_src = (const uint8_t *)write_buf;
|
||||||
}
|
}
|
||||||
spi_flash_guard_start();
|
spi_flash_guard_start();
|
||||||
rc = esp_rom_spiflash_write(dst + mid_off, (const uint32_t *) write_src, write_size);
|
rc = spi_flash_write_inner(dst + mid_off, (const uint32_t *) write_src, write_size);
|
||||||
spi_flash_guard_end();
|
spi_flash_guard_end();
|
||||||
COUNTER_ADD_BYTES(write, write_size);
|
COUNTER_ADD_BYTES(write, write_size);
|
||||||
mid_size -= write_size;
|
mid_size -= write_size;
|
||||||
@ -311,7 +372,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
|||||||
uint32_t t = 0xffffffff;
|
uint32_t t = 0xffffffff;
|
||||||
memcpy(&t, srcc + right_off, right_size);
|
memcpy(&t, srcc + right_off, right_size);
|
||||||
spi_flash_guard_start();
|
spi_flash_guard_start();
|
||||||
rc = esp_rom_spiflash_write(dst + right_off, &t, 4);
|
rc = spi_flash_write_inner(dst + right_off, &t, 4);
|
||||||
spi_flash_guard_end();
|
spi_flash_guard_end();
|
||||||
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
|
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||||
goto out;
|
goto out;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user