From 9c37fbf40a13feb6c2a38a1871aa2c045dd812f3 Mon Sep 17 00:00:00 2001 From: Brian Juel Folkmann Date: Tue, 10 Jan 2023 09:21:23 +0100 Subject: [PATCH 1/2] drivers: flash: bug fix stm32 ospi flash erase This commit fixes a bug in the STM32 ospi flash driver when attempting to erase an area that spans more than one erase sector. Without this fix, only the first sector is actually erased, the rest silently fails the erase. Issue is that the write enable latch command is only sent for the first erase command. Signed-off-by: Brian Juel Folkmann --- drivers/flash/flash_stm32_ospi.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 02a520dcdd164..0106ab4a54bd2 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -931,16 +931,11 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, if (stm32_ospi_mem_ready(&dev_data->hospi, dev_cfg->data_mode, dev_cfg->data_rate) != 0) { + ospi_unlock_thread(dev); LOG_ERR("Erase failed : flash busy"); return -EBUSY; } - if (stm32_ospi_write_enable(&dev_data->hospi, - dev_cfg->data_mode, dev_cfg->data_rate) != 0) { - LOG_ERR("Erase failed : write enable"); - return -EIO; - } - cmd_erase.InstructionMode = (dev_cfg->data_mode == OSPI_OPI_MODE) ? HAL_OSPI_INSTRUCTION_8_LINES : HAL_OSPI_INSTRUCTION_1_LINE; @@ -952,6 +947,14 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, : HAL_OSPI_INSTRUCTION_8_BITS; while ((size > 0) && (ret == 0)) { + + ret = stm32_ospi_write_enable(&dev_data->hospi, + dev_cfg->data_mode, dev_cfg->data_rate); + if (ret != 0) { + LOG_ERR("Erase failed : write enable"); + break; + } + if (size == dev_cfg->flash_size) { /* Chip erase */ LOG_DBG("Chip Erase"); @@ -966,6 +969,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, } else { /* Sector erase */ LOG_DBG("Sector Erase"); + cmd_erase.Address = addr; const struct jesd216_erase_type *erase_types = dev_data->erase_types; @@ -1002,6 +1006,10 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, ? stm32_ospi_hal_address_size(dev) : HAL_OSPI_ADDRESS_24_BITS; cmd_erase.Address = addr; + /* Avoid using wrong erase type, + * if zero entries are found in erase_types + */ + bet = NULL; } } @@ -1180,6 +1188,7 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, ret = stm32_ospi_mem_ready(&dev_data->hospi, dev_cfg->data_mode, dev_cfg->data_rate); if (ret != 0) { + ospi_unlock_thread(dev); LOG_ERR("OSPI: write not ready"); return -EIO; } From c6e50ed7db492fdbeb24e51607bdaa3d65239e24 Mon Sep 17 00:00:00 2001 From: Brian Juel Folkmann Date: Tue, 10 Jan 2023 09:40:01 +0100 Subject: [PATCH 2/2] samples: spi_flash: Add option to test multiple sectors Add tests for erase of multiple consequtive sectors. Signed-off-by: Brian Juel Folkmann --- samples/drivers/spi_flash/src/main.c | 122 ++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 13 deletions(-) diff --git a/samples/drivers/spi_flash/src/main.c b/samples/drivers/spi_flash/src/main.c index 381e3971a6eb2..177cd953b964a 100644 --- a/samples/drivers/spi_flash/src/main.c +++ b/samples/drivers/spi_flash/src/main.c @@ -26,25 +26,18 @@ #endif #define SPI_FLASH_SECTOR_SIZE 4096 -void main(void) +#if defined CONFIG_FLASH_STM32_OSPI +#define SPI_FLASH_MULTI_SECTOR_TEST +#endif + +void single_sector_test(const struct device *flash_dev) { const uint8_t expected[] = { 0x55, 0xaa, 0x66, 0x99 }; const size_t len = sizeof(expected); uint8_t buf[sizeof(expected)]; - const struct device *flash_dev; int rc; - flash_dev = DEVICE_DT_GET(DT_ALIAS(spi_flash0)); - - if (!device_is_ready(flash_dev)) { - printk("%s: device not ready.\n", flash_dev->name); - return; - } - - printf("\n%s SPI flash testing\n", flash_dev->name); - printf("==========================\n"); - - + printf("\nPerform test on single sector"); /* Write protection needs to be disabled before each write or * erase, since the flash component turns on write protection * automatically after completion of write and erase @@ -96,3 +89,106 @@ void main(void) } } } + +#if defined SPI_FLASH_MULTI_SECTOR_TEST +void multi_sector_test(const struct device *flash_dev) +{ + const uint8_t expected[] = { 0x55, 0xaa, 0x66, 0x99 }; + const size_t len = sizeof(expected); + uint8_t buf[sizeof(expected)]; + int rc; + + printf("\nPerform test on multiple consequtive sectors"); + + /* Write protection needs to be disabled before each write or + * erase, since the flash component turns on write protection + * automatically after completion of write and erase + * operations. + */ + printf("\nTest 1: Flash erase\n"); + + /* Full flash erase if SPI_FLASH_TEST_REGION_OFFSET = 0 and + * SPI_FLASH_SECTOR_SIZE = flash size + * Erase 2 sectors for check for erase of consequtive sectors + */ + rc = flash_erase(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, SPI_FLASH_SECTOR_SIZE * 2); + if (rc != 0) { + printf("Flash erase failed! %d\n", rc); + } else { + /* Read the content and check for erased */ + memset(buf, 0, len); + size_t offs = SPI_FLASH_TEST_REGION_OFFSET; + + while (offs < SPI_FLASH_TEST_REGION_OFFSET + 2 * SPI_FLASH_SECTOR_SIZE) { + rc = flash_read(flash_dev, offs, buf, len); + if (rc != 0) { + printf("Flash read failed! %d\n", rc); + return; + } + if (buf[0] != 0xff) { + printf("Flash erase failed at offset 0x%x got 0x%x\n", + offs, buf[0]); + return; + } + offs += SPI_FLASH_SECTOR_SIZE; + } + printf("Flash erase succeeded!\n"); + } + + printf("\nTest 2: Flash write\n"); + + size_t offs = SPI_FLASH_TEST_REGION_OFFSET; + + while (offs < SPI_FLASH_TEST_REGION_OFFSET + 2 * SPI_FLASH_SECTOR_SIZE) { + printf("Attempting to write %zu bytes at offset 0x%x\n", len, offs); + rc = flash_write(flash_dev, offs, expected, len); + if (rc != 0) { + printf("Flash write failed! %d\n", rc); + return; + } + + memset(buf, 0, len); + rc = flash_read(flash_dev, offs, buf, len); + if (rc != 0) { + printf("Flash read failed! %d\n", rc); + return; + } + + if (memcmp(expected, buf, len) == 0) { + printf("Data read matches data written. Good!!\n"); + } else { + const uint8_t *wp = expected; + const uint8_t *rp = buf; + const uint8_t *rpe = rp + len; + + printf("Data read does not match data written!!\n"); + while (rp < rpe) { + printf("%08x wrote %02x read %02x %s\n", + (uint32_t)(offs + (rp - buf)), + *wp, *rp, (*rp == *wp) ? "match" : "MISMATCH"); + ++rp; + ++wp; + } + } + offs += SPI_FLASH_SECTOR_SIZE; + } +} +#endif + +void main(void) +{ + const struct device *flash_dev = DEVICE_DT_GET(DT_ALIAS(spi_flash0)); + + if (!device_is_ready(flash_dev)) { + printk("%s: device not ready.\n", flash_dev->name); + return; + } + + printf("\n%s SPI flash testing\n", flash_dev->name); + printf("==========================\n"); + + single_sector_test(flash_dev); +#if defined SPI_FLASH_MULTI_SECTOR_TEST + multi_sector_test(flash_dev); +#endif +}