1 #include <stdio.h>
2 #include <string.h>
3 #include <freertos/FreeRTOS.h>
4 #include <freertos/task.h>
5 #include <freertos/semphr.h>
6 
7 #include <unity.h>
8 #include "esp_flash.h"
9 #include "driver/spi_common_internal.h"
10 #include "esp_flash_spi_init.h"
11 #include "memspi_host_driver.h"
12 #include <esp_attr.h>
13 #include "esp_log.h"
14 
15 #include <test_utils.h>
16 
17 #include "unity.h"
18 #include "driver/gpio.h"
19 #include "soc/io_mux_reg.h"
20 #include "sdkconfig.h"
21 
22 #include "ccomp_timer.h"
23 #include "esp_rom_gpio.h"
24 #include "esp_rom_sys.h"
25 #include "esp_timer.h"
26 
27 #if CONFIG_IDF_TARGET_ESP32S2
28 #include "esp32s2/rom/cache.h"
29 #elif CONFIG_IDF_TARGET_ESP32S3
30 #include "esp32s3/rom/cache.h"
31 #elif CONFIG_IDF_TARGET_ESP32C3
32 #include "esp32c3/rom/cache.h"
33 #endif
34 
35 #define FUNC_SPI    1
36 
37 static uint8_t sector_buf[4096];
38 
39 #define MAX_ADDR_24BIT      0x1000000
40 #define TEST_SPI_SPEED      ESP_FLASH_10MHZ
41 #define TEST_SPI_READ_MODE  SPI_FLASH_FASTRD
42 // #define FORCE_GPIO_MATRIX
43 
44 #if CONFIG_IDF_TARGET_ESP32
45 #define EXTRA_SPI1_CLK_IO   17  //the pin which is usually used by the PSRAM clk
46 #define SPI1_CS_IO          16  //the pin which is usually used by the PSRAM cs
47 
48 #define HSPI_PIN_NUM_MOSI   HSPI_IOMUX_PIN_NUM_MOSI
49 #define HSPI_PIN_NUM_MISO   HSPI_IOMUX_PIN_NUM_MISO
50 #define HSPI_PIN_NUM_CLK    HSPI_IOMUX_PIN_NUM_CLK
51 #define HSPI_PIN_NUM_HD     HSPI_IOMUX_PIN_NUM_HD
52 #define HSPI_PIN_NUM_WP     HSPI_IOMUX_PIN_NUM_WP
53 #define HSPI_PIN_NUM_CS     HSPI_IOMUX_PIN_NUM_CS
54 
55 #define VSPI_PIN_NUM_MOSI   VSPI_IOMUX_PIN_NUM_MOSI
56 #define VSPI_PIN_NUM_MISO   VSPI_IOMUX_PIN_NUM_MISO
57 #define VSPI_PIN_NUM_CLK    VSPI_IOMUX_PIN_NUM_CLK
58 #define VSPI_PIN_NUM_HD     VSPI_IOMUX_PIN_NUM_HD
59 #define VSPI_PIN_NUM_WP     VSPI_IOMUX_PIN_NUM_WP
60 #define VSPI_PIN_NUM_CS     VSPI_IOMUX_PIN_NUM_CS
61 
62 #elif CONFIG_IDF_TARGET_ESP32S2
63 #define SPI1_CS_IO          26  //the pin which is usually used by the PSRAM cs
64 #define SPI1_HD_IO          27  //the pin which is usually used by the PSRAM hd
65 #define SPI1_WP_IO          28  //the pin which is usually used by the PSRAM wp
66 
67 #define FSPI_PIN_NUM_MOSI   35
68 #define FSPI_PIN_NUM_MISO   37
69 #define FSPI_PIN_NUM_CLK    36
70 #define FSPI_PIN_NUM_HD     33
71 #define FSPI_PIN_NUM_WP     38
72 #define FSPI_PIN_NUM_CS     34
73 
74 // Just use the same pins for HSPI
75 #define HSPI_PIN_NUM_MOSI   FSPI_PIN_NUM_MOSI
76 #define HSPI_PIN_NUM_MISO   FSPI_PIN_NUM_MISO
77 #define HSPI_PIN_NUM_CLK    FSPI_PIN_NUM_CLK
78 #define HSPI_PIN_NUM_HD     FSPI_PIN_NUM_HD
79 #define HSPI_PIN_NUM_WP     FSPI_PIN_NUM_WP
80 #define HSPI_PIN_NUM_CS     FSPI_PIN_NUM_CS
81 
82 #elif CONFIG_IDF_TARGET_ESP32S3
83 #define SPI1_CS_IO          26  //the pin which is usually used by the PSRAM cs
84 #define SPI1_HD_IO          27  //the pin which is usually used by the PSRAM hd
85 #define SPI1_WP_IO          28  //the pin which is usually used by the PSRAM wp
86 
87 #define FSPI_PIN_NUM_MOSI   35
88 #define FSPI_PIN_NUM_MISO   37
89 #define FSPI_PIN_NUM_CLK    36
90 #define FSPI_PIN_NUM_HD     33
91 #define FSPI_PIN_NUM_WP     38
92 #define FSPI_PIN_NUM_CS     34
93 
94 // Just use the same pins for HSPI
95 #define HSPI_PIN_NUM_MOSI   FSPI_PIN_NUM_MOSI
96 #define HSPI_PIN_NUM_MISO   FSPI_PIN_NUM_MISO
97 #define HSPI_PIN_NUM_CLK    FSPI_PIN_NUM_CLK
98 #define HSPI_PIN_NUM_HD     FSPI_PIN_NUM_HD
99 #define HSPI_PIN_NUM_WP     FSPI_PIN_NUM_WP
100 #define HSPI_PIN_NUM_CS     FSPI_PIN_NUM_CS
101 
102 #elif CONFIG_IDF_TARGET_ESP32C3
103 #define SPI1_CS_IO          26  //the pin which is usually used by the PSRAM cs
104 #define SPI1_HD_IO          27  //the pin which is usually used by the PSRAM hd
105 #define SPI1_WP_IO          28  //the pin which is usually used by the PSRAM wp
106 
107 #define FSPI_PIN_NUM_MOSI   7
108 #define FSPI_PIN_NUM_MISO   2
109 #define FSPI_PIN_NUM_CLK    6
110 #define FSPI_PIN_NUM_HD     4
111 #define FSPI_PIN_NUM_WP     5
112 #define FSPI_PIN_NUM_CS     10
113 
114 // Just use the same pins for HSPI
115 #define HSPI_PIN_NUM_MOSI   FSPI_PIN_NUM_MOSI
116 #define HSPI_PIN_NUM_MISO   FSPI_PIN_NUM_MISO
117 #define HSPI_PIN_NUM_CLK    FSPI_PIN_NUM_CLK
118 #define HSPI_PIN_NUM_HD     FSPI_PIN_NUM_HD
119 #define HSPI_PIN_NUM_WP     FSPI_PIN_NUM_WP
120 #define HSPI_PIN_NUM_CS     FSPI_PIN_NUM_CS
121 #endif
122 
123 #define TEST_CONFIG_NUM (sizeof(config_list)/sizeof(flashtest_config_t))
124 
125 typedef void (*flash_test_func_t)(const esp_partition_t *part);
126 
127 /* Use FLASH_TEST_CASE for SPI flash tests that only use the main SPI flash chip
128 */
129 #define FLASH_TEST_CASE(STR, FUNC_TO_RUN) \
130     TEST_CASE(STR, "[esp_flash]") {flash_test_func(FUNC_TO_RUN, 1 /* first index reserved for main flash */ );}
131 
132 #define FLASH_TEST_CASE_IGNORE(STR, FUNC_TO_RUN) \
133     TEST_CASE(STR, "[esp_flash][ignore]") {flash_test_func(FUNC_TO_RUN, 1 /* first index reserved for main flash */ );}
134 
135 /* Use FLASH_TEST_CASE_3 for tests which also run on external flash, which sits in the place of PSRAM
136    (these tests are incompatible with PSRAM)
137 
138    These tests run for all the flash chip configs shown in config_list, below (internal and external).
139  */
140 #if defined(CONFIG_SPIRAM)
141 
142 #define FLASH_TEST_CASE_3(STR, FUNCT_TO_RUN)
143 #define FLASH_TEST_CASE_3_IGNORE(STR, FUNCT_TO_RUN)
144 #else //CONFIG_SPIRAM
145 #if !CONFIG_IDF_TARGET_ESP32C3
146 #define FLASH_TEST_CASE_3(STR, FUNC_TO_RUN) \
147     TEST_CASE(STR", 3 chips", "[esp_flash_3][test_env=UT_T1_ESP_FLASH]") {flash_test_func(FUNC_TO_RUN, TEST_CONFIG_NUM);}
148 
149 #define FLASH_TEST_CASE_3_IGNORE(STR, FUNC_TO_RUN) \
150     TEST_CASE(STR", 3 chips", "[esp_flash_3][test_env=UT_T1_ESP_FLASH][ignore]") {flash_test_func(FUNC_TO_RUN, TEST_CONFIG_NUM);}
151 #else //CONFIG_IDF_TARGET_ESP32C3
152 #define FLASH_TEST_CASE_3(STR, FUNC_TO_RUN) \
153     TEST_CASE(STR", 2 chips", "[esp_flash_2][test_env=UT_T1_ESP_FLASH]") {flash_test_func(FUNC_TO_RUN, TEST_CONFIG_NUM);}
154 
155 #define FLASH_TEST_CASE_3_IGNORE(STR, FUNC_TO_RUN) \
156     TEST_CASE(STR", 2 chips", "[esp_flash_2][test_env=UT_T1_ESP_FLASH][ignore]") {flash_test_func(FUNC_TO_RUN, TEST_CONFIG_NUM);}
157 #endif // !CONFIG_IDF_TARGET_ESP32C3
158 #endif //CONFIG_SPIRAM
159 
160 //currently all the configs are the same with esp_flash_spi_device_config_t, no more information required
161 typedef esp_flash_spi_device_config_t flashtest_config_t;
162 
163 static const char TAG[] = "test_esp_flash";
164 
165 #define FLASHTEST_CONFIG_COMMON     \
166     /* 0 always reserved for main flash */ \
167     { \
168         /* no need to init */ \
169         .host_id = -1, \
170     } \
171     , \
172     { \
173         .io_mode = TEST_SPI_READ_MODE,\
174         .speed = TEST_SPI_SPEED, \
175         .host_id = SPI1_HOST, \
176         .cs_id = 1, \
177         /* the pin which is usually used by the PSRAM */ \
178         .cs_io_num = SPI1_CS_IO, \
179         .input_delay_ns = 0, \
180     }
181 
182 #if CONFIG_IDF_TARGET_ESP32
183 flashtest_config_t config_list[] = {
184     FLASHTEST_CONFIG_COMMON,
185     /* current runner doesn't have a flash on HSPI */
186     // {
187     //     .io_mode = TEST_SPI_READ_MODE,
188     //     .speed = TEST_SPI_SPEED,
189     //     .host_id = HSPI_HOST,
190     //     .cs_id = 0,
191     //     // uses GPIO matrix on esp32s2 regardless if FORCE_GPIO_MATRIX
192     //     .cs_io_num = HSPI_PIN_NUM_CS,
193     //     .input_delay_ns = 20,
194     // },
195     {
196         .io_mode = TEST_SPI_READ_MODE,
197         .speed = TEST_SPI_SPEED,
198         .host_id = VSPI_HOST,
199         .cs_id = 0,
200         .cs_io_num = VSPI_PIN_NUM_CS,
201         .input_delay_ns = 0,
202     },
203 };
204 #elif CONFIG_IDF_TARGET_ESP32S2
205 flashtest_config_t config_list[] = {
206     FLASHTEST_CONFIG_COMMON,
207     {
208         .io_mode = TEST_SPI_READ_MODE,
209         .speed = TEST_SPI_SPEED,
210         .host_id = FSPI_HOST,
211         .cs_id = 0,
212         .cs_io_num = FSPI_PIN_NUM_CS,
213         .input_delay_ns = 0,
214     },
215     {
216         .io_mode = TEST_SPI_READ_MODE,
217         .speed = TEST_SPI_SPEED,
218         .host_id = HSPI_HOST,
219         .cs_id = 0,
220         // uses GPIO matrix on esp32s2 regardless of FORCE_GPIO_MATRIX
221         .cs_io_num = HSPI_PIN_NUM_CS,
222         .input_delay_ns = 0,
223     },
224 };
225 #elif CONFIG_IDF_TARGET_ESP32S3
226 flashtest_config_t config_list[] = {
227     FLASHTEST_CONFIG_COMMON,
228     /* No runners for esp32s3 for these config yet */
229     {
230         .io_mode = TEST_SPI_READ_MODE,
231         .speed = TEST_SPI_SPEED,
232         .host_id = SPI2_HOST,
233         .cs_id = 0,
234         .cs_io_num = FSPI_PIN_NUM_CS,
235         .input_delay_ns = 0,
236     },
237 };
238 #elif CONFIG_IDF_TARGET_ESP32C3
239 flashtest_config_t config_list[] = {
240     /* No SPI1 CS1 flash on esp32c3 test */
241     {
242         /* no need to init */
243         .host_id = -1,
244     },
245     {
246         .io_mode = TEST_SPI_READ_MODE,
247         .speed = TEST_SPI_SPEED,
248         .host_id = SPI2_HOST,
249         .cs_id = 0,
250         .cs_io_num = FSPI_PIN_NUM_CS,
251         .input_delay_ns = 0,
252     },
253 };
254 #endif
255 
get_chip_host(esp_flash_t * chip,spi_host_device_t * out_host_id,int * out_cs_id)256 static void get_chip_host(esp_flash_t* chip, spi_host_device_t* out_host_id, int* out_cs_id)
257 {
258     spi_host_device_t host_id;
259     int cs_id;
260     if (chip == NULL) {
261         host_id = SPI1_HOST;
262         cs_id = 0;
263     } else {
264         spi_flash_hal_context_t* host_data = (spi_flash_hal_context_t*)chip->host;
265         host_id = spi_flash_ll_hw_get_id(host_data->spi);
266         cs_id = host_data->cs_num;
267     }
268     if (out_host_id) {
269         *out_host_id = host_id;
270     }
271     if (out_cs_id) {
272         *out_cs_id = cs_id;
273     }
274 }
275 
276 #if CONFIG_IDF_TARGET_ESP32
setup_bus(spi_host_device_t host_id)277 static void setup_bus(spi_host_device_t host_id)
278 {
279     if (host_id == SPI1_HOST) {
280         ESP_LOGI(TAG, "setup flash on SPI1 CS1...\n");
281         //no need to initialize the bus, however the CLK may need one more output if it's on the usual place of PSRAM
282         esp_rom_gpio_connect_out_signal(EXTRA_SPI1_CLK_IO, SPICLK_OUT_IDX, 0, 0);
283         //currently the SPI bus for main flash chip is initialized through GPIO matrix
284     } else if (host_id == SPI2_HOST) {
285         ESP_LOGI(TAG, "setup flash on SPI%d (HSPI) CS0...\n", host_id + 1);
286         spi_bus_config_t hspi_bus_cfg = {
287             .mosi_io_num = HSPI_PIN_NUM_MOSI,
288             .miso_io_num = HSPI_PIN_NUM_MISO,
289             .sclk_io_num = HSPI_PIN_NUM_CLK,
290             .quadhd_io_num = HSPI_PIN_NUM_HD,
291             .quadwp_io_num = HSPI_PIN_NUM_WP,
292             .max_transfer_sz = 64,
293         };
294         esp_err_t ret = spi_bus_initialize(host_id, &hspi_bus_cfg, 0);
295         TEST_ESP_OK(ret);
296     } else if (host_id == SPI3_HOST) {
297         ESP_LOGI(TAG, "setup flash on SPI%d (VSPI) CS0...\n", host_id + 1);
298         spi_bus_config_t vspi_bus_cfg = {
299             .mosi_io_num = VSPI_PIN_NUM_MOSI,
300             .miso_io_num = VSPI_PIN_NUM_MISO,
301             .sclk_io_num = VSPI_PIN_NUM_CLK,
302             .quadhd_io_num = VSPI_PIN_NUM_HD,
303             .quadwp_io_num = VSPI_PIN_NUM_WP,
304             .max_transfer_sz = 64,
305         };
306         esp_err_t ret = spi_bus_initialize(host_id, &vspi_bus_cfg, 0);
307         TEST_ESP_OK(ret);
308     } else {
309         ESP_LOGE(TAG, "invalid bus");
310     }
311 }
312 #else // FOR ESP32-S2, ESP32-S3, ESP32-C3
setup_bus(spi_host_device_t host_id)313 static void setup_bus(spi_host_device_t host_id)
314 {
315     if (host_id == SPI1_HOST) {
316         ESP_LOGI(TAG, "setup flash on SPI1 CS1...\n");
317 #if !CONFIG_ESPTOOLPY_FLASHMODE_QIO && !CONFIG_ESPTOOLPY_FLASHMODE_QOUT
318         //Initialize the WP and HD pins, which are not automatically initialized on ESP32-S2.
319         int wp_pin = spi_periph_signal[host_id].spiwp_iomux_pin;
320         int hd_pin = spi_periph_signal[host_id].spihd_iomux_pin;
321         gpio_iomux_in(wp_pin, spi_periph_signal[host_id].spiwp_in);
322         gpio_iomux_out(wp_pin, spi_periph_signal[host_id].func, false);
323         gpio_iomux_in(hd_pin, spi_periph_signal[host_id].spihd_in);
324         gpio_iomux_out(hd_pin, spi_periph_signal[host_id].func, false);
325 #endif //CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
326         //currently the SPI bus for main flash chip is initialized through GPIO matrix
327     } else if (host_id == SPI2_HOST) {
328         ESP_LOGI(TAG, "setup flash on SPI%d (FSPI) CS0...\n", host_id + 1);
329         spi_bus_config_t fspi_bus_cfg = {
330             .mosi_io_num = FSPI_PIN_NUM_MOSI,
331             .miso_io_num = FSPI_PIN_NUM_MISO,
332             .sclk_io_num = FSPI_PIN_NUM_CLK,
333             .quadhd_io_num = FSPI_PIN_NUM_HD,
334             .quadwp_io_num = FSPI_PIN_NUM_WP,
335             .max_transfer_sz = 64,
336         };
337         esp_err_t ret = spi_bus_initialize(host_id, &fspi_bus_cfg, 0);
338         TEST_ESP_OK(ret);
339     } else if (host_id == SPI3_HOST) {
340         ESP_LOGI(TAG, "setup flash on SPI%d (HSPI) CS0...\n", host_id + 1);
341         spi_bus_config_t hspi_bus_cfg = {
342             .mosi_io_num = HSPI_PIN_NUM_MOSI,
343             .miso_io_num = HSPI_PIN_NUM_MISO,
344             .sclk_io_num = HSPI_PIN_NUM_CLK,
345             .quadhd_io_num = HSPI_PIN_NUM_HD,
346             .quadwp_io_num = HSPI_PIN_NUM_WP,
347             .max_transfer_sz = 64,
348         };
349         esp_err_t ret = spi_bus_initialize(host_id, &hspi_bus_cfg, 0);
350         TEST_ESP_OK(ret);
351 
352         // HSPI have no multiline mode, use GPIO to pull those pins up
353         gpio_set_direction(HSPI_PIN_NUM_HD, GPIO_MODE_OUTPUT);
354         gpio_set_level(HSPI_PIN_NUM_HD, 1);
355 
356         gpio_set_direction(HSPI_PIN_NUM_WP, GPIO_MODE_OUTPUT);
357         gpio_set_level(HSPI_PIN_NUM_WP, 1);
358     } else {
359         ESP_LOGE(TAG, "invalid bus");
360     }
361 }
362 #endif // CONFIG_IDF_TARGET_ESP32
363 
release_bus(int host_id)364 static void release_bus(int host_id)
365 {
366     //SPI1 bus can't be deinitialized
367     if (host_id == SPI2_HOST || host_id == SPI3_HOST) {
368         spi_bus_free(host_id);
369     }
370 }
371 
setup_new_chip(const flashtest_config_t * test_cfg,esp_flash_t ** out_chip)372 static void setup_new_chip(const flashtest_config_t* test_cfg, esp_flash_t** out_chip)
373 {
374     //the bus should be initialized before the flash is attached to the bus
375     if (test_cfg->host_id == -1) {
376         *out_chip = NULL;
377         return;
378     }
379     setup_bus(test_cfg->host_id);
380 
381     esp_flash_spi_device_config_t dev_cfg = {
382         .host_id = test_cfg->host_id,
383         .io_mode = test_cfg->io_mode,
384         .speed = test_cfg->speed,
385         .cs_id = test_cfg->cs_id,
386         .cs_io_num = test_cfg->cs_io_num,
387         .input_delay_ns = test_cfg->input_delay_ns,
388     };
389     esp_flash_t* init_chip;
390     esp_err_t err = spi_bus_add_flash_device(&init_chip, &dev_cfg);
391     TEST_ESP_OK(err);
392     err = esp_flash_init(init_chip);
393     TEST_ESP_OK(err);
394     *out_chip = init_chip;
395 }
396 
teardown_test_chip(esp_flash_t * chip)397 static void teardown_test_chip(esp_flash_t* chip)
398 {
399     spi_host_device_t host_id;
400     get_chip_host(chip, &host_id, NULL);
401     //happen to work when chip==NULL
402     spi_bus_remove_flash_device(chip);
403     release_bus(host_id);
404 }
405 
flash_test_core(flash_test_func_t func,const flashtest_config_t * config)406 static void flash_test_core(flash_test_func_t func, const flashtest_config_t* config)
407 {
408     esp_flash_t* chip;
409     setup_new_chip(config, &chip);
410 
411     uint32_t size;
412     esp_err_t err = esp_flash_get_size(chip, &size);
413     TEST_ESP_OK(err);
414     ESP_LOGI(TAG, "Flash size: 0x%08X", size);
415 
416     const esp_partition_t* test_part = get_test_data_partition();
417     TEST_ASSERT_NOT_EQUAL(NULL, test_part->flash_chip);
418 
419     esp_partition_t part = *test_part;
420     part.flash_chip = chip;
421 
422     ESP_LOGI(TAG, "Testing chip %p, address 0x%08X...", part.flash_chip, part.address);
423     (*func)(&part);
424 
425     // For flash with size over 16MB, add one extra round of test for the 32-bit address area
426     if (size > MAX_ADDR_24BIT) {
427         part.address = 0x1030000;
428         part.size = 0x0010000;
429         ESP_LOGI(TAG, "Testing chip %p, address 0x%08X...", part.flash_chip, part.address);
430         (*func)(&part);
431     }
432 
433     teardown_test_chip(chip);
434 }
435 
flash_test_func(flash_test_func_t func,int test_num)436 static void flash_test_func(flash_test_func_t func, int test_num)
437 {
438     esp_log_level_set("gpio", ESP_LOG_NONE);
439     for (int i = 0; i < test_num; i++) {
440         ESP_LOGI(TAG, "Testing config %d/%d", i+1, test_num);
441         flash_test_core(func, &config_list[i]);
442     }
443     ESP_LOGI(TAG, "Completed %d configs", test_num);
444 }
445 
446 /* ---------- Test code start ------------*/
447 
test_metadata(const esp_partition_t * part)448 static void test_metadata(const esp_partition_t* part)
449 {
450     esp_flash_t* chip = part->flash_chip;
451     uint32_t id, size;
452     TEST_ESP_OK(esp_flash_read_id(chip, &id));
453     TEST_ESP_OK(esp_flash_get_size(chip, &size));
454     printf("Flash ID %08x detected size %d bytes\n", id, size);
455 }
456 
457 FLASH_TEST_CASE("SPI flash metadata functions", test_metadata);
458 FLASH_TEST_CASE_3("SPI flash metadata functions", test_metadata);
459 
erase_test_region(const esp_partition_t * part,int num_sectors)460 static uint32_t erase_test_region(const esp_partition_t *part, int num_sectors)
461 {
462     esp_flash_t* chip = part->flash_chip;
463     uint32_t offs = part->address;
464 
465     /* chip should be initialised */
466     TEST_ASSERT(esp_flash_default_chip != NULL
467                 && esp_flash_chip_driver_initialized(esp_flash_default_chip));
468 
469     TEST_ASSERT(num_sectors * 4096 <= part->size);
470 
471     bzero(sector_buf, sizeof(sector_buf));
472 
473     printf("Erase @ 0x%x...\n", offs);
474     TEST_ASSERT_EQUAL_HEX32(ESP_OK, esp_flash_erase_region(chip, offs, num_sectors * 4096) );
475 
476     printf("Verify erased...\n");
477     for (int i = 0; i < num_sectors; i++) {
478         TEST_ASSERT_EQUAL_HEX32(ESP_OK, esp_flash_read(chip, sector_buf, offs + i * 4096, sizeof(sector_buf)));
479 
480         printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]);
481         for (int i = 0; i < sizeof(sector_buf); i++) {
482             TEST_ASSERT_EQUAL_HEX8(0xFF, sector_buf[i]);
483         }
484     }
485 
486     return offs;
487 }
488 
test_simple_read_write(const esp_partition_t * part)489 void test_simple_read_write(const esp_partition_t* part)
490 {
491     esp_flash_t* chip = part->flash_chip;
492     uint32_t offs = erase_test_region(part, 1);
493 
494     const int test_seed = 778;
495     srand(test_seed);
496     for (int i = 0 ; i < sizeof(sector_buf); i++) {
497         sector_buf[i] = rand();
498     }
499 
500     printf("Write %p...\n", (void *)offs);
501     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, sector_buf, offs, sizeof(sector_buf)) );
502 
503     bzero(sector_buf, sizeof(sector_buf));
504 
505     printf("Read back...\n");
506     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, sector_buf, offs, sizeof(sector_buf)) );
507 
508     printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]);
509 
510     srand(test_seed);
511     for (int i = 0; i < sizeof(sector_buf); i++) {
512         uint8_t data = rand();
513         TEST_ASSERT_EQUAL_HEX8(data, sector_buf[i]);
514     }
515 }
516 
517 FLASH_TEST_CASE("SPI flash simple read/write", test_simple_read_write);
518 FLASH_TEST_CASE_3("SPI flash simple read/write", test_simple_read_write);
519 
test_unaligned_read_write(const esp_partition_t * part)520 void test_unaligned_read_write(const esp_partition_t* part)
521 {
522     esp_flash_t* chip = part->flash_chip;
523     uint32_t offs = erase_test_region(part, 2);
524 
525     const char *msg = "i am a message";
526     TEST_ASSERT(strlen(msg) + 1 % 4 != 0);
527     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, msg, offs + 1, strlen(msg) + 1) );
528 
529     char buf[strlen(msg) + 1];
530 
531     memset(buf, 0xEE, sizeof(buf));
532 
533     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, buf, offs + 1, strlen(msg) + 1) );
534     TEST_ASSERT_EQUAL_STRING_LEN(msg, buf, strlen(msg));
535     TEST_ASSERT(memcmp(buf, msg, strlen(msg) + 1) == 0);
536 }
537 
538 FLASH_TEST_CASE("SPI flash unaligned read/write", test_unaligned_read_write);
539 FLASH_TEST_CASE_3("SPI flash unaligned read/write", test_unaligned_read_write);
540 
test_single_read_write(const esp_partition_t * part)541 void test_single_read_write(const esp_partition_t* part)
542 {
543     esp_flash_t* chip = part->flash_chip;
544     uint32_t offs = erase_test_region(part, 2);
545 
546     const int seed = 699;
547     srand(seed);
548     for (unsigned v = 0; v < 512; v++) {
549         uint32_t data = rand();
550         TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_write(chip, &data, offs + v, 1) );
551     }
552 
553     srand(seed);
554     for (unsigned v = 0; v < 512; v++) {
555         uint8_t readback;
556         uint32_t data = rand();
557         TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_read(chip, &readback, offs + v, 1) );
558         TEST_ASSERT_EQUAL_HEX8(data, readback);
559     }
560 }
561 
562 FLASH_TEST_CASE("SPI flash single byte reads/writes", test_single_read_write);
563 FLASH_TEST_CASE_3("SPI flash single byte reads/writes", test_single_read_write);
564 
565 
566 /* this test is notable because it generates a lot of unaligned reads/writes,
567    and also reads/writes across both a sector boundary & many page boundaries.
568 */
test_three_byte_read_write(const esp_partition_t * part)569 void test_three_byte_read_write(const esp_partition_t* part)
570 {
571     esp_flash_t* chip = part->flash_chip;
572     uint32_t offs = erase_test_region(part, 2);
573 
574     const int seed = 700;
575     esp_rom_printf("offs:%X\n", offs);
576 
577     srand(seed);
578     for (uint32_t v = 0; v < 86; v++) {
579         uint32_t data = rand();
580         TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, &data, offs + 3 * v, 3) );
581     }
582 
583     srand(seed);
584     for (uint32_t v = 0; v < 1; v++) {
585         uint32_t readback;
586         uint32_t data = rand();
587         TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, offs + 3 * v, 3) );
588         TEST_ASSERT_EQUAL_HEX32(data & 0xFFFFFF, readback & 0xFFFFFF);
589     }
590 }
591 
592 FLASH_TEST_CASE("SPI flash three byte reads/writes", test_three_byte_read_write);
593 FLASH_TEST_CASE_3("SPI flash three byte reads/writes", test_three_byte_read_write);
594 
test_erase_large_region(const esp_partition_t * part)595 void test_erase_large_region(const esp_partition_t *part)
596 {
597     esp_flash_t* chip = part->flash_chip;
598 
599     /* Write some noise at the start and the end of the region */
600     const char *ohai = "OHAI";
601     uint32_t readback;
602     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, ohai, part->address, 5));
603     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, ohai, part->address + part->size - 5, 5));
604 
605     /* sanity check what we just wrote. since the partition may haven't been erased, we only check the part which is written to 0. */
606     uint32_t written_data = *((const uint32_t *)ohai);
607     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address + part->size - 5, 4));
608     TEST_ASSERT_EQUAL_HEX32(0, readback & (~written_data));
609     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address, 4));
610     TEST_ASSERT_EQUAL_HEX32(0, readback & (~written_data));
611 
612     /* Erase whole region */
613     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_erase_region(chip, part->address, part->size));
614 
615     /* ensure both areas we wrote are now all-FFs */
616     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address, 4));
617     TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback);
618 
619     TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, part->address + part->size - 5, 4));
620     TEST_ASSERT_EQUAL_HEX32(0xFFFFFFFF, readback);
621 }
622 
623 FLASH_TEST_CASE("SPI flash erase large region", test_erase_large_region);
624 FLASH_TEST_CASE_3("SPI flash erase large region", test_erase_large_region);
625 
626 #if CONFIG_SPI_FLASH_AUTO_SUSPEND
esp_test_for_suspend(void)627 void esp_test_for_suspend(void)
628 {
629     /*clear content in cache*/
630 #if !CONFIG_IDF_TARGET_ESP32C3
631     Cache_Invalidate_DCache_All();
632 #endif
633     Cache_Invalidate_ICache_All();
634     ESP_LOGI(TAG, "suspend test begins:");
635     printf("run into test suspend function\n");
636     printf("print something when flash is erasing:\n");
637     printf("aaaaa bbbbb zzzzz fffff qqqqq ccccc\n");
638 }
639 
640 static volatile bool task_erase_end, task_suspend_end = false;
task_erase_large_region(void * arg)641 void task_erase_large_region(void *arg)
642 {
643     esp_partition_t *part = (esp_partition_t *)arg;
644     test_erase_large_region(part);
645     task_erase_end = true;
646     vTaskDelete(NULL);
647 }
648 
task_request_suspend(void * arg)649 void task_request_suspend(void *arg)
650 {
651     vTaskDelay(2);
652     ESP_LOGI(TAG, "flash go into suspend");
653     esp_test_for_suspend();
654     task_suspend_end = true;
655     vTaskDelete(NULL);
656 }
657 
test_flash_suspend_resume(const esp_partition_t * part)658 static void test_flash_suspend_resume(const esp_partition_t* part)
659 {
660     xTaskCreatePinnedToCore(task_request_suspend, "suspend", 2048, (void *)"test_for_suspend", UNITY_FREERTOS_PRIORITY + 3, NULL, 0);
661     xTaskCreatePinnedToCore(task_erase_large_region, "test", 2048, (void *)part, UNITY_FREERTOS_PRIORITY + 2, NULL, 0);
662     while (!task_erase_end || !task_suspend_end) {
663     }
664     vTaskDelay(200);
665 }
666 
667 FLASH_TEST_CASE("SPI flash suspend and resume test", test_flash_suspend_resume);
668 #endif //CONFIG_SPI_FLASH_AUTO_SUSPEND
669 
test_write_protection(const esp_partition_t * part)670 static void test_write_protection(const esp_partition_t* part)
671 {
672     esp_flash_t* chip = part->flash_chip;
673 
674     bool wp = true;
675     esp_err_t ret = ESP_OK;
676     ret = esp_flash_get_chip_write_protect(chip, &wp);
677     TEST_ESP_OK(ret);
678 
679     for (int i = 0; i < 4; i ++) {
680         bool wp_write = !wp;
681         ret = esp_flash_set_chip_write_protect(chip, wp_write);
682         TEST_ESP_OK(ret);
683 
684         bool wp_read;
685         ret = esp_flash_get_chip_write_protect(chip, &wp_read);
686         TEST_ESP_OK(ret);
687         TEST_ASSERT(wp_read == wp_write);
688         wp = wp_read;
689     }
690 }
691 
692 FLASH_TEST_CASE("Test esp_flash can enable/disable write protetion", test_write_protection);
693 FLASH_TEST_CASE_3("Test esp_flash can enable/disable write protetion", test_write_protection);
694 
695 static const uint8_t large_const_buffer[16400] = {
696     203, // first byte
697     1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
698     21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
699     [50 ... 99] = 2,
700     [1600 ... 2000] = 3,
701     [8000 ... 9000] = 77,
702     [15000 ... 16398] = 8,
703     43 // last byte
704 };
705 
706 static void test_write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length);
707 static void write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length);
708 static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length);
709 
710 // Internal functions for testing, from esp_flash_api.c
711 esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe);
712 esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe);
713 esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
714 esp_err_t spi_flash_chip_mxic_probe(esp_flash_t *chip, uint32_t flash_id);
715 
is_winbond_chip(esp_flash_t * chip)716 static bool is_winbond_chip(esp_flash_t* chip)
717 {
718     uint32_t flash_id;
719     esp_err_t ret = esp_flash_read_chip_id(chip, &flash_id);
720     TEST_ESP_OK(ret);
721     if ((flash_id >> 16) == 0xEF) {
722         return true;
723     } else {
724         return false;
725     }
726 }
727 
is_mxic_chip(esp_flash_t * chip)728 static bool is_mxic_chip(esp_flash_t* chip)
729 {
730     uint32_t flash_id;
731     esp_err_t ret = esp_flash_read_chip_id(chip, &flash_id);
732     TEST_ESP_OK(ret);
733     return (spi_flash_chip_mxic_probe(chip, flash_id)==ESP_OK);
734 }
735 
test_toggle_qe(const esp_partition_t * part)736 IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(const esp_partition_t* part)
737 {
738     esp_flash_t* chip = part->flash_chip;
739 
740     bool qe;
741     if (chip == NULL) {
742         chip = esp_flash_default_chip;
743     }
744     esp_flash_io_mode_t io_mode_before = chip->read_mode;
745     esp_err_t ret = esp_flash_get_io_mode(chip, &qe);
746     TEST_ESP_OK(ret);
747 
748     bool allow_failure = is_winbond_chip(chip) || is_mxic_chip(chip);
749 
750     for (int i = 0; i < 4; i ++) {
751         esp_rom_printf(DRAM_STR("write qe: %d->%d\n"), qe, !qe);
752         qe = !qe;
753         chip->read_mode = qe? SPI_FLASH_QOUT: SPI_FLASH_SLOWRD;
754         ret = esp_flash_set_io_mode(chip, qe);
755         if (allow_failure && !qe && ret == ESP_ERR_FLASH_NO_RESPONSE) {
756             //allows clear qe failure for Winbond chips
757             ret = ESP_OK;
758         }
759         TEST_ESP_OK(ret);
760 
761         bool qe_read;
762         ret = esp_flash_get_io_mode(chip, &qe_read);
763         TEST_ESP_OK(ret);
764         ESP_LOGD(TAG, "qe read: %d", qe_read);
765         if (!qe && qe_read) {
766             if (allow_failure) {
767                 ESP_LOGW(TAG, "cannot clear QE bit for known permanent QE (Winbond or MXIC) chips.");
768             } else {
769                 ESP_LOGE(TAG, "cannot clear QE bit, please make sure force clearing QE option is enabled in `spi_flash_common_set_io_mode`, and this chip is not a permanent QE one.");
770             }
771             chip->read_mode = io_mode_before;
772             return;
773         }
774         TEST_ASSERT_EQUAL(qe, qe_read);
775     }
776     //restore the io_mode after test
777     chip->read_mode = io_mode_before;
778 }
779 
780 // These tests show whether the QE is permanent or not for the chip tested.
781 // To test the behaviour of a new SPI flash chip, enable force_check flag in generic driver
782 // `spi_flash_common_set_io_mode` and then run this test.
783 FLASH_TEST_CASE_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
784 FLASH_TEST_CASE_3_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
785 
test_permutations_part(const flashtest_config_t * config,esp_partition_t * part,void * source_buf,size_t length)786 void test_permutations_part(const flashtest_config_t* config, esp_partition_t* part, void* source_buf, size_t length)
787 {
788     if (config->host_id != -1) {
789         esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN;
790         while (speed != ESP_FLASH_SPEED_MAX) {
791             //test io_mode in the inner loop to test QE set/clear function, since
792             //the io mode will switch frequently.
793             esp_flash_io_mode_t io_mode = SPI_FLASH_READ_MODE_MIN;
794             while (io_mode != SPI_FLASH_READ_MODE_MAX) {
795                 if (io_mode > SPI_FLASH_FASTRD &&
796                     !SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(config->host_id)) {
797                     io_mode++;
798                     continue;
799                 }
800 
801                 esp_flash_t* chip;
802                 flashtest_config_t temp_config = *config;
803                 temp_config.io_mode = io_mode;
804                 temp_config.speed = speed;
805                 setup_new_chip(&temp_config, &chip);
806                 ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed);
807 
808                 part->flash_chip = chip;
809                 read_and_check(part, source_buf, length);
810                 teardown_test_chip(chip);
811 
812                 io_mode++;
813             }
814             speed++;
815         }
816     } else {
817         //test main flash
818         part->flash_chip = NULL;
819         read_and_check(part, source_buf, length);
820     }
821 }
822 
test_permutations_chip(const flashtest_config_t * config)823 void test_permutations_chip(const flashtest_config_t* config)
824 {
825     esp_log_level_set("gpio", ESP_LOG_NONE);
826     esp_flash_t* chip;
827     flashtest_config_t temp_config = *config;
828     // Use the lowest speed to read configs, data and write data to make sure success
829     temp_config.io_mode = SPI_FLASH_READ_MODE_MIN;
830     temp_config.speed = ESP_FLASH_SPEED_MIN;
831     setup_new_chip(&temp_config, &chip);
832 
833     //Get size to determine whether to test one extra partition
834     uint32_t size;
835     esp_err_t err = esp_flash_get_size(chip, &size);
836     TEST_ESP_OK(err);
837     ESP_LOGI(TAG, "Flash size: 0x%08X", size);
838     bool addr_32bit = (size > MAX_ADDR_24BIT);
839 
840     // Get test partition, and locate temporary partitions according to the default one
841     const esp_partition_t* test_part = get_test_data_partition();
842     const int length = sizeof(large_const_buffer);
843     TEST_ASSERT(test_part->size > length + 2 + SPI_FLASH_SEC_SIZE);
844 
845     esp_partition_t part[2] = {};
846     part[0] = *test_part;
847     part[0].flash_chip = chip;
848     // For flash with size over 16MB, add one extra round of test for the 32-bit address area
849     if (addr_32bit) {
850         part[1] = *test_part;
851         part[1].flash_chip = chip;
852         part[1].address = 0x1030000;
853         part[1].size = 0x0010000;
854     } else {
855         part[1].size = 0;
856     }
857 
858     // Prepare test data and write to the specified region
859     uint8_t *source_buf = malloc(length);
860     TEST_ASSERT_NOT_NULL(source_buf);
861     srand(778);
862     for (int i = 0; i < length; i++) {
863         source_buf[i] = rand();
864     }
865 
866     for (int i = 0; i < 2; i++) {
867         if (part[i].size == 0) continue;
868         write_large_buffer(&part[i], source_buf, length);
869     }
870 
871     teardown_test_chip(chip);
872 
873     for (int i = 0; i < 2; i++) {
874         if (part[i].size == 0) continue;
875 
876         part[i].flash_chip = (esp_flash_t*)-1;
877         ESP_LOGI(TAG, "Testing address 0x%08X...", part[i].address);
878         test_permutations_part(config, &part[i], source_buf, length);
879     }
880 
881     free(source_buf);
882 }
883 
884 TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash]")
885 {
886     test_permutations_chip(&config_list[0]);
887 }
888 
889 #ifndef CONFIG_SPIRAM
890 TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash_3][test_env=UT_T1_ESP_FLASH]")
891 {
892     for (int i = 0; i < TEST_CONFIG_NUM; i++) {
893         test_permutations_chip(&config_list[i]);
894     }
895 }
896 #endif
897 
898 
test_write_large_const_buffer(const esp_partition_t * part)899 static void test_write_large_const_buffer(const esp_partition_t* part)
900 {
901     test_write_large_buffer(part, large_const_buffer, sizeof(large_const_buffer));
902 }
903 
904 FLASH_TEST_CASE("Test esp_flash_write large const buffer", test_write_large_const_buffer);
905 FLASH_TEST_CASE_3("Test esp_flash_write large const buffer", test_write_large_const_buffer);
906 
test_write_large_ram_buffer(const esp_partition_t * part)907 static void test_write_large_ram_buffer(const esp_partition_t* part)
908 {
909     // buffer in RAM
910     uint8_t *source_buf = malloc(sizeof(large_const_buffer));
911     TEST_ASSERT_NOT_NULL(source_buf);
912     memcpy(source_buf, large_const_buffer, sizeof(large_const_buffer));
913     test_write_large_buffer(part, source_buf, sizeof(large_const_buffer));
914     free(source_buf);
915 }
916 
917 FLASH_TEST_CASE("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer);
918 FLASH_TEST_CASE_3("Test esp_flash_write large RAM buffer", test_write_large_ram_buffer);
919 
write_large_buffer(const esp_partition_t * part,const uint8_t * source,size_t length)920 static void write_large_buffer(const esp_partition_t *part, const uint8_t *source, size_t length)
921 {
922     esp_flash_t* chip = part->flash_chip;
923     printf("Writing chip %p %p, %d bytes from source %p\n", chip, (void*)part->address, length, source);
924 
925     ESP_ERROR_CHECK( esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)) );
926 
927     // note writing to unaligned address
928     ESP_ERROR_CHECK( esp_flash_write(chip, source, part->address + 1, length) );
929 }
930 
read_and_check(const esp_partition_t * part,const uint8_t * source,size_t length)931 static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length)
932 {
933     esp_flash_t* chip = part->flash_chip;
934     printf("Checking chip %p 0x%08X, %d bytes\n", chip, part->address, length);
935     uint8_t *buf = malloc(length);
936     TEST_ASSERT_NOT_NULL(buf);
937     ESP_ERROR_CHECK( esp_flash_read(chip, buf, part->address + 1, length) );
938     TEST_ASSERT_EQUAL_HEX8_ARRAY(source, buf, length);
939     free(buf);
940 
941     // check nothing was written at beginning or end
942     uint8_t ends[8];
943 
944     ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address, sizeof(ends)) );
945     TEST_ASSERT_EQUAL_HEX8(0xFF, ends[0]);
946     TEST_ASSERT_EQUAL_HEX8(source[0], ends[1]);
947 
948     ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address + length, sizeof(ends)) );
949 
950     TEST_ASSERT_EQUAL_HEX8(source[length - 1], ends[0]);
951     TEST_ASSERT_EQUAL_HEX8(0xFF, ends[1]);
952     TEST_ASSERT_EQUAL_HEX8(0xFF, ends[2]);
953     TEST_ASSERT_EQUAL_HEX8(0xFF, ends[3]);
954 }
955 
test_write_large_buffer(const esp_partition_t * part,const uint8_t * source,size_t length)956 static void test_write_large_buffer(const esp_partition_t* part, const uint8_t *source, size_t length)
957 {
958     TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE);
959 
960     write_large_buffer(part, source, length);
961     read_and_check(part, source, length);
962 }
963 
964 #if !CONFIG_SPIRAM
965 
966 typedef struct {
967     uint32_t us_start;
968     size_t len;
969     const char* name;
970 } time_meas_ctx_t;
971 
time_measure_start(time_meas_ctx_t * ctx)972 static void time_measure_start(time_meas_ctx_t* ctx)
973 {
974     ctx->us_start = esp_timer_get_time();
975     ccomp_timer_start();
976 }
977 
time_measure_end(time_meas_ctx_t * ctx)978 static uint32_t time_measure_end(time_meas_ctx_t* ctx)
979 {
980     uint32_t c_time_us = ccomp_timer_stop();
981     uint32_t time_us = esp_timer_get_time() - ctx->us_start;
982 
983     ESP_LOGI(TAG, "%s: compensated: %.2lf kB/s, typical: %.2lf kB/s", ctx->name, ctx->len / (c_time_us / 1000.), ctx->len / (time_us/1000.));
984     return ctx->len * 1000 / (c_time_us / 1000);
985 }
986 
987 #define TEST_TIMES      20
988 #define TEST_SECTORS    4
989 
measure_erase(const esp_partition_t * part)990 static uint32_t measure_erase(const esp_partition_t* part)
991 {
992     const int total_len = SPI_FLASH_SEC_SIZE * TEST_SECTORS;
993     time_meas_ctx_t time_ctx = {.name = "erase", .len = total_len};
994 
995     time_measure_start(&time_ctx);
996     esp_err_t err = esp_flash_erase_region(part->flash_chip, part->address, total_len);
997     TEST_ESP_OK(err);
998     return time_measure_end(&time_ctx);
999 }
1000 
1001 // should called after measure_erase
measure_write(const char * name,const esp_partition_t * part,const uint8_t * data_to_write,int seg_len)1002 static uint32_t measure_write(const char* name, const esp_partition_t* part, const uint8_t* data_to_write, int seg_len)
1003 {
1004     const int total_len = SPI_FLASH_SEC_SIZE;
1005     time_meas_ctx_t time_ctx = {.name = name, .len = total_len * TEST_TIMES};
1006 
1007     time_measure_start(&time_ctx);
1008     for (int i = 0; i < TEST_TIMES; i ++) {
1009         // Erase one time, but write 100 times the same data
1010         size_t len = total_len;
1011         int offset = 0;
1012 
1013         while (len) {
1014             int len_write = MIN(seg_len, len);
1015             esp_err_t err = esp_flash_write(part->flash_chip, data_to_write + offset, part->address + offset, len_write);
1016             TEST_ESP_OK(err);
1017 
1018             offset += len_write;
1019             len -= len_write;
1020         }
1021     }
1022     return time_measure_end(&time_ctx);
1023 }
1024 
measure_read(const char * name,const esp_partition_t * part,uint8_t * data_read,int seg_len)1025 static uint32_t measure_read(const char* name, const esp_partition_t* part, uint8_t* data_read, int seg_len)
1026 {
1027     const int total_len = SPI_FLASH_SEC_SIZE;
1028     time_meas_ctx_t time_ctx = {.name = name, .len = total_len * TEST_TIMES};
1029 
1030     time_measure_start(&time_ctx);
1031     for (int i = 0; i < TEST_TIMES; i ++) {
1032         size_t len = total_len;
1033         int offset = 0;
1034 
1035         while (len) {
1036             int len_read = MIN(seg_len, len);
1037             esp_err_t err = esp_flash_read(part->flash_chip, data_read + offset, part->address + offset, len_read);
1038             TEST_ESP_OK(err);
1039 
1040             offset += len_read;
1041             len -= len_read;
1042         }
1043     }
1044     return time_measure_end(&time_ctx);
1045 }
1046 
1047 #define MEAS_WRITE(n)   (measure_write("write in "#n"-byte chunks", part, data_to_write, n))
1048 #define MEAS_READ(n)    (measure_read("read in "#n"-byte chunks", part, data_read, n))
1049 
test_flash_read_write_performance(const esp_partition_t * part)1050 static void test_flash_read_write_performance(const esp_partition_t *part)
1051 {
1052     esp_flash_t* chip = part->flash_chip;
1053     const int total_len = SPI_FLASH_SEC_SIZE;
1054     uint8_t *data_to_write = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
1055     uint8_t *data_read = heap_caps_malloc(total_len, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
1056 
1057     srand(777);
1058     for (int i = 0; i < total_len; i++) {
1059         data_to_write[i] = rand();
1060     }
1061 
1062     uint32_t erase_1 = measure_erase(part);
1063     uint32_t speed_WR_4B = MEAS_WRITE(4);
1064     uint32_t speed_RD_4B = MEAS_READ(4);
1065     uint32_t erase_2 = measure_erase(part);
1066     uint32_t speed_WR_2KB = MEAS_WRITE(2048);
1067     uint32_t speed_RD_2KB = MEAS_READ(2048);
1068 
1069     TEST_ASSERT_EQUAL_HEX8_ARRAY(data_to_write, data_read, total_len);
1070 
1071 #if !CONFIG_SPIRAM && !CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE
1072 #  define CHECK_DATA(bus, suffix) TEST_PERFORMANCE_CCOMP_GREATER_THAN(FLASH_SPEED_BYTE_PER_SEC_##bus##suffix, "%d", speed_##suffix)
1073 #  define CHECK_ERASE(bus, var) TEST_PERFORMANCE_CCOMP_GREATER_THAN(FLASH_SPEED_BYTE_PER_SEC_##bus##ERASE, "%d", var)
1074 #else
1075 #  define CHECK_DATA(bus, suffix) ((void)speed_##suffix)
1076 #  define CHECK_ERASE(bus, var)   ((void)var)
1077 #endif
1078 
1079 // Erase time may vary a lot, can increase threshold if this fails with a reasonable speed
1080 #define CHECK_PERFORMANCE(bus) do {\
1081             CHECK_DATA(bus, WR_4B); \
1082             CHECK_DATA(bus, RD_4B); \
1083             CHECK_DATA(bus, WR_2KB); \
1084             CHECK_DATA(bus, RD_2KB); \
1085             CHECK_ERASE(bus, erase_1); \
1086             CHECK_ERASE(bus, erase_2); \
1087         } while (0)
1088 
1089     spi_host_device_t host_id;
1090     int cs_id;
1091 
1092     get_chip_host(chip, &host_id, &cs_id);
1093     if (host_id != SPI1_HOST) {
1094         // Chips on other SPI buses
1095         CHECK_PERFORMANCE(EXT_);
1096     } else if (cs_id == 0) {
1097         // Main flash
1098         CHECK_PERFORMANCE();
1099     } else {
1100         // Other cs pins on SPI1
1101         CHECK_PERFORMANCE(SPI1_);
1102     }
1103     free(data_to_write);
1104     free(data_read);
1105 }
1106 
1107 TEST_CASE("Test esp_flash read/write performance", "[esp_flash][test_env=UT_T1_ESP_FLASH]") {flash_test_func(test_flash_read_write_performance, 1);}
1108 #endif // !CONFIG_SPIRAM
1109 FLASH_TEST_CASE_3("Test esp_flash read/write performance"", 3 chips", test_flash_read_write_performance);
1110 
1111 #ifdef CONFIG_SPIRAM_USE_MALLOC
1112 
1113 /* Utility: Read into a small internal RAM buffer using esp_flash_read() and compare what
1114    we read with 'buffer' */
s_test_compare_flash_contents_small_reads(esp_flash_t * chip,const uint8_t * buffer,size_t offs,size_t len)1115 static void s_test_compare_flash_contents_small_reads(esp_flash_t *chip, const uint8_t *buffer, size_t offs, size_t len)
1116 {
1117     const size_t INTERNAL_BUF_SZ = 1024; // Should fit in internal RAM
1118     uint8_t *ibuf = heap_caps_malloc(INTERNAL_BUF_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
1119     TEST_ASSERT_NOT_NULL(ibuf);
1120 
1121     for (int i = 0; i < len; i += INTERNAL_BUF_SZ) {
1122         size_t to_read = MIN(INTERNAL_BUF_SZ, len - i);
1123         ESP_ERROR_CHECK( esp_flash_read(chip, ibuf, offs + i, to_read) );
1124         TEST_ASSERT_EQUAL_HEX8_ARRAY(buffer + i, ibuf, to_read);
1125     }
1126 
1127     free(ibuf);
1128 }
1129 
test_flash_read_large_psram_buffer(const esp_partition_t * part)1130 static void test_flash_read_large_psram_buffer(const esp_partition_t *part)
1131 {
1132     esp_flash_t* chip = part->flash_chip;
1133     const size_t BUF_SZ = 256 * 1024;    // Too large for internal RAM
1134     const size_t TEST_OFFS = 0x1000; // Can be any offset, really
1135 
1136     uint8_t *buf = heap_caps_malloc(BUF_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_SPIRAM);
1137     TEST_ASSERT_NOT_NULL(buf);
1138 
1139     ESP_ERROR_CHECK( esp_flash_read(chip, buf, TEST_OFFS, BUF_SZ) );
1140 
1141     // Read back the same into smaller internal memory buffer and check it all matches
1142     s_test_compare_flash_contents_small_reads(chip, buf, TEST_OFFS, BUF_SZ);
1143 
1144     free(buf);
1145 }
1146 
1147 FLASH_TEST_CASE("esp_flash_read large PSRAM buffer", test_flash_read_large_psram_buffer);
1148 
1149 
1150 /* similar to above test, but perform it under memory pressure */
test_flash_read_large_psram_buffer_low_internal_mem(const esp_partition_t * part)1151 static void test_flash_read_large_psram_buffer_low_internal_mem(const esp_partition_t *part)
1152 {
1153     esp_flash_t* chip = part->flash_chip;
1154     const size_t BUF_SZ = 256 * 1024;    // Too large for internal RAM
1155     const size_t REMAINING_INTERNAL = 1024; // Exhaust internal memory until maximum free block is less than this
1156     const size_t TEST_OFFS = 0x8000;
1157 
1158     /* Exhaust the available free internal memory */
1159     test_utils_exhaust_memory_rec erec = test_utils_exhaust_memory(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT, REMAINING_INTERNAL);
1160 
1161     uint8_t *buf = heap_caps_malloc(BUF_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_SPIRAM);
1162     TEST_ASSERT_NOT_NULL(buf);
1163 
1164     /* Calling esp_flash_read() here will need to allocate a small internal buffer,
1165        so check it works. */
1166     ESP_ERROR_CHECK( esp_flash_read(chip, buf, TEST_OFFS, BUF_SZ) );
1167 
1168     test_utils_free_exhausted_memory(erec);
1169 
1170     // Read back the same into smaller internal memory buffer and check it all matches
1171     s_test_compare_flash_contents_small_reads(chip, buf, TEST_OFFS, BUF_SZ);
1172 
1173     free(buf);
1174 }
1175 
1176 FLASH_TEST_CASE("esp_flash_read large PSRAM buffer low memory", test_flash_read_large_psram_buffer_low_internal_mem);
1177 
1178 
1179 #endif
1180