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