1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "esp_spi_flash.h"
6 #include "esp_partition.h"
7 #include "wear_levelling.h"
8 #include "WL_Flash.h"
9 #include "SpiFlash.h"
10 
11 #include "catch.hpp"
12 
13 #include "sdkconfig.h"
14 
15 extern "C" void _spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
16 extern SpiFlash spiflash;
17 
18 #define TEST_COUNT_MAX 100
19 
20 TEST_CASE("write and read back data", "[wear_levelling]")
21 {
22     _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
23 
24     esp_err_t result;
25     wl_handle_t wl_handle;
26 
27     int flash_handle;
28     const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
29 
30     // Mount wear-levelled partition
31     result = wl_mount(partition, &wl_handle);
32     REQUIRE(result == ESP_OK);
33 
34     // Get the sector size
35     uint32_t sector_size = wl_sector_size(wl_handle);
36     REQUIRE(sector_size == CONFIG_WL_SECTOR_SIZE);
37 
38     uint8_t* data = (uint8_t*) malloc(partition->size);
39     uint8_t* read = (uint8_t*) malloc(partition->size);
40 
41     uint32_t sectors = partition->size / sector_size;
42 
43     // Generate data
44     for(uint32_t sector = 0; sector < sectors; sector++)
45     {
46         uint32_t sector_address = sector * sector_size;
47 
48         for(uint32_t i = 0; i < sector_size / sizeof(i); i++)
49         {
50             ((uint32_t*) data)[i] = sector_address + i;
51         }
52     }
53 
54     // Write data
55     result = wl_write(wl_handle, 0, data, partition->size);
56     REQUIRE(result == ESP_OK);
57 
58     // Read data
59     result = wl_read(wl_handle, 0, read, partition->size);
60     REQUIRE(result == ESP_OK);
61 
62     // Verify that written and read data match
63     REQUIRE(memcmp(data, read, partition->size));
64 
65     // Erase some ranges
66     result = wl_erase_range(wl_handle, 0, sector_size);
67     REQUIRE(result == ESP_OK);
68     result = wl_erase_range(wl_handle, 12288, sector_size * 2);
69     REQUIRE(result == ESP_OK);
70     result = wl_erase_range(wl_handle, 28672, sector_size * 3);
71     REQUIRE(result == ESP_OK);
72 
73     // Expected data after erasure
74     memset(data + 0, 0xFF, sector_size);
75     memset(data + 12288, 0xFF, sector_size * 2);
76     memset(data + 28672, 0xFF, sector_size * 3);
77 
78     // Read again, with erased ranges
79     result = wl_read(wl_handle, 0, read, partition->size);
80     REQUIRE(result == ESP_OK);
81 
82     // Verify that written and read data match
83     REQUIRE(memcmp(data, read, partition->size));
84 
85     // Unmount
86     result = wl_unmount(wl_handle);
87     REQUIRE(result == ESP_OK);
88 
89     free(data);
90     free(read);
91 }
92 
93 TEST_CASE("power down test", "[wear_levelling]")
94 {
95     _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
96 
97     esp_err_t result;
98     wl_handle_t wl_handle;
99 
100     int flash_handle;
101     const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
102 
103     // Mount wear-levelled partition
104     result = wl_mount(partition, &wl_handle);
105     REQUIRE(result == ESP_OK);
106 
107     // Get wl partition information
108     size_t sector_size = wl_sector_size(wl_handle);
109     int32_t sectors_count = wl_size(wl_handle) / sector_size;
110 
111     uint32_t add_const = 0;
112     uint32_t *sector_data = new uint32_t[sector_size / sizeof(uint32_t)];
113 
114     // Fill partition with check data
115     for (int32_t i = 0; i < sectors_count; i++) {
116         REQUIRE(wl_erase_range(wl_handle, i * sector_size, sector_size) == ESP_OK);
117         for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
118             uint32_t temp_data = i * sector_size + add_const + m;
119             sector_data[m] = temp_data;
120         }
121         REQUIRE(wl_write(wl_handle, i * sector_size, sector_data, sector_size) == ESP_OK);
122     }
123 
124     for (int32_t i = 0; i < sectors_count; i++) {
125         result |= wl_read(wl_handle, i * sector_size, sector_data, sector_size);
126         for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
127             uint32_t temp_data = i * sector_size + add_const + m;
128             REQUIRE(temp_data == sector_data[m]);
129             if (temp_data != sector_data[m]) {
130                 printf("Error - read: %08x, expected %08x\n", sector_data[m], temp_data);
131             }
132         }
133     }
134 
135     // Perform test
136     int32_t max_count = 100;
137     int32_t max_check_count = TEST_COUNT_MAX;
138 
139     printf("used_sectors_count=%d\n", max_check_count);
140 
141     for (int32_t k = 0; k < max_check_count; k++) {
142 
143         spiflash.set_total_erase_cycles_limit(max_count);
144 
145         int32_t err_sector = -1;
146         for (int32_t i = 0; i < sectors_count; i++) {
147             result = ESP_OK;
148             result = wl_erase_range(wl_handle, i * sector_size, sector_size);
149             if (result != ESP_OK) {
150                 err_sector = i;
151                 break;
152             }
153             for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
154                 uint32_t temp_data = i * sector_size + add_const + m;
155                 sector_data[m] = temp_data;
156             }
157             result = wl_write(wl_handle, i * sector_size, sector_data, sector_size);
158             if (result != ESP_OK) {
159                 err_sector = i;
160                 break;
161             }
162         }
163 
164         if (err_sector >= 0) {
165             max_count++;
166         } else {
167             max_count = 0;
168         }
169 
170         spiflash.set_total_erase_cycles_limit(0);
171 
172         result = wl_unmount(wl_handle);
173         REQUIRE(result == ESP_OK);
174 
175         result = wl_mount(partition, &wl_handle);
176         REQUIRE(result == ESP_OK);
177 
178         for (int32_t i = 0; i < sectors_count; i++) {
179             if (i != err_sector) {
180                 result |= wl_read(wl_handle, i * sector_size, sector_data, sector_size);
181                 for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
182                     uint32_t temp_data = i * sector_size + add_const + m;
183                     REQUIRE(temp_data == sector_data[m]);
184                     if (temp_data != sector_data[m]) {
185                         printf("Error - read: %08x, expected %08x, m=%i, sector=%i\n", sector_data[m], temp_data, m, i);
186                     }
187                 }
188             }
189         }
190 
191         if (err_sector != -1) {
192             result |= wl_erase_range(wl_handle, err_sector * sector_size, sector_size);
193             for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
194                 uint32_t temp_data = err_sector * sector_size + add_const + m;
195                 sector_data[m] = temp_data;
196             }
197             result |= wl_write(wl_handle, err_sector * sector_size, sector_data, sector_size);
198         }
199 
200         spiflash.reset_total_erase_cycles();
201 
202         printf("[%3.f%%] err_sector=%i\n", (float)k / ((float)max_check_count) * 100.0f, err_sector);
203     }
204 
205     delete[] sector_data;
206 
207     // Unmount
208     result = wl_unmount(wl_handle);
209     REQUIRE(result == ESP_OK);
210 }
211