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