Skip to content

Commit ebef79a

Browse files
author
Jaakko Korhonen
committed
Add generic BlockDevice test for contiguous erase/write/read.
1 parent b1904a5 commit ebef79a

File tree

1 file changed

+137
-1
lines changed
  • features/storage/TESTS/blockdevice/general_block_device

1 file changed

+137
-1
lines changed

features/storage/TESTS/blockdevice/general_block_device/main.cpp

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
#ifndef __STDC_FORMAT_MACROS
17+
#define __STDC_FORMAT_MACROS //Required for PRIu64
18+
#endif
1619

1720
#include "mbed.h"
1821
#include "greentea-client/test_env.h"
1922
#include "unity.h"
2023
#include "utest.h"
2124
#include "mbed_trace.h"
25+
#include <inttypes.h>
2226
#include <stdlib.h>
2327

2428
using namespace utest::v1;
@@ -209,6 +213,137 @@ void test_multi_threads()
209213
TEST_ASSERT_EQUAL(0, err);
210214
}
211215

216+
void test_contiguous_erase_write_read()
217+
{
218+
utest_printf("\nTest Contiguous Erase/Program/Read Starts..\n");
219+
220+
// Test flow:
221+
// 1. Erase whole test area
222+
// - Tests contiguous erase
223+
// 2. Write smaller memory area
224+
// - Tests contiguous sector writes
225+
// 3. Rerun step 2 for whole erase region
226+
227+
BlockDevice *block_device = BlockDevice::get_default_instance();
228+
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "\nno block device found.\n");
229+
230+
// Initialize BlockDevice
231+
int err = block_device->init();
232+
TEST_ASSERT_EQUAL(0, err);
233+
234+
// Test parameters
235+
bd_size_t erase_size = block_device->get_erase_size();
236+
TEST_ASSERT(erase_size > 0);
237+
bd_size_t program_size = block_device->get_program_size();
238+
TEST_ASSERT(program_size > 0);
239+
utest_printf("\nerase_size=%d", erase_size);
240+
utest_printf("\nprogram_size=%d", program_size);
241+
utest_printf("\nblock_device->size()=%" PRId64, block_device->size());
242+
243+
// Determine write/read buffer size
244+
// start write_read_buf_size from 1% block_device->size()
245+
bd_size_t write_read_buf_size = block_device->size() / 100; // 1%, 10k=100, 100k=1k, 1MB=10k, 32MB=32k
246+
// try to limit write_read_buf_size to 10k. If program_size*2 is larger than 10k, that will be used instead.
247+
if (write_read_buf_size > 10000) {
248+
write_read_buf_size = 10000;
249+
}
250+
// 2 program_size blocks is minimum for contiguous write/read test
251+
if (write_read_buf_size < program_size*2) {
252+
write_read_buf_size = program_size*2; // going over 10k
253+
}
254+
bd_size_t contiguous_write_read_blocks_per_region = write_read_buf_size / program_size; // 2 is minimum to test contiguous write
255+
write_read_buf_size = contiguous_write_read_blocks_per_region * program_size;
256+
utest_printf("\ncontiguous_write_read_blocks_per_region=%" PRIu64, contiguous_write_read_blocks_per_region);
257+
utest_printf("\nwrite_read_buf_size=%" PRIu64, write_read_buf_size);
258+
259+
// Determine test region count
260+
int contiguous_write_read_regions = TEST_BLOCK_COUNT;
261+
utest_printf("\ncontiguous_write_read_regions=%d", contiguous_write_read_regions);
262+
263+
// Determine whole erase size
264+
bd_size_t contiguous_erase_size = write_read_buf_size * contiguous_write_read_regions;
265+
contiguous_erase_size -= contiguous_erase_size % erase_size; // aligned to erase_size
266+
contiguous_erase_size += erase_size; // but larger than write/read size * regions
267+
utest_printf("\ncontiguous_erase_size=%" PRIu64, contiguous_erase_size);
268+
269+
// Determine starting address
270+
bd_addr_t start_address = rand(); // low 32 bytes
271+
start_address += (uint64_t)rand() << 32; // high 32 bytes
272+
start_address %= block_device->size() - contiguous_erase_size - erase_size; // fit all data + alignment reserve
273+
start_address += erase_size; // add alignment reserve
274+
start_address -= start_address % erase_size; // align with erase_block
275+
bd_addr_t stop_address = start_address + write_read_buf_size * contiguous_write_read_regions;
276+
utest_printf("\nstart_address=0x%016" PRIx64, start_address);
277+
utest_printf("\nstop_address=0x%016" PRIx64, stop_address);
278+
279+
// Allocate write/read buffer
280+
uint8_t *write_read_buf = (uint8_t*)malloc(write_read_buf_size);
281+
if (write_read_buf == NULL) {
282+
block_device->deinit();
283+
TEST_SKIP_MESSAGE("\nnot enough memory for test");
284+
}
285+
utest_printf("\nwrite_read_buf_size=%" PRIu64 "", (uint64_t)write_read_buf_size);
286+
287+
// Pre-fill the to-be-erased region. By pre-filling the region,
288+
// we can be sure the test will not pass if the erase doesn't work.
289+
for (bd_size_t offset=0; start_address+offset < stop_address; offset+=write_read_buf_size) {
290+
for (size_t i=0; i<write_read_buf_size; i++) {
291+
write_read_buf[i] = (uint8_t)rand();
292+
}
293+
utest_printf("\npre-filling memory, from 0x%" PRIx64 " of size 0x%" PRIx64, start_address+offset, write_read_buf_size);
294+
err = block_device->program((const void*)write_read_buf, start_address+offset, write_read_buf_size);
295+
TEST_ASSERT_EQUAL(0, err);
296+
}
297+
298+
// Erase the whole region first
299+
utest_printf("\nerasing memory, from 0x%" PRIx64 " of size 0x%" PRIx64, start_address, contiguous_erase_size);
300+
err = block_device->erase(start_address, contiguous_erase_size);
301+
TEST_ASSERT_EQUAL(0, err);
302+
303+
// Loop through all write/read regions
304+
int region = 0;
305+
for (; start_address < stop_address; start_address+=write_read_buf_size) {
306+
utest_printf("\n\nregion #%d start_address=0x%016" PRIx64, region++, start_address);
307+
308+
// Generate test data
309+
unsigned int seed = rand();
310+
utest_printf("\ngenerating test data, seed=%u", seed);
311+
srand(seed);
312+
for (size_t i=0; i<write_read_buf_size; i++) {
313+
write_read_buf[i] = (uint8_t)rand();
314+
}
315+
316+
// Write test data
317+
utest_printf("\nwriting test data");
318+
err = block_device->program((const void*)write_read_buf, start_address, write_read_buf_size);
319+
TEST_ASSERT_EQUAL(0, err);
320+
321+
// Read test data
322+
memset(write_read_buf, 0, (size_t)write_read_buf_size);
323+
utest_printf("\nreading test data");
324+
err = block_device->read(write_read_buf, start_address, write_read_buf_size);
325+
TEST_ASSERT_EQUAL(0, err);
326+
327+
// Verify read data
328+
utest_printf("\nverifying test data");
329+
srand(seed);
330+
for (size_t i=0; i<write_read_buf_size; i++) {
331+
uint8_t expected_value = (uint8_t)rand();
332+
if (write_read_buf[i] != expected_value) {
333+
utest_printf("\ndata verify failed, write_read_buf[%d]=%" PRIu8 " and not %" PRIu8 "\n",
334+
i, write_read_buf[i], expected_value);
335+
}
336+
TEST_ASSERT_EQUAL(write_read_buf[i], expected_value);
337+
}
338+
utest_printf("\nverify OK");
339+
}
340+
341+
free(write_read_buf);
342+
343+
// BlockDevice deinitialization
344+
err = block_device->deinit();
345+
TEST_ASSERT_EQUAL(0, err);
346+
}
212347

213348
// Test setup
214349
utest::v1::status_t test_setup(const size_t number_of_cases)
@@ -219,7 +354,8 @@ utest::v1::status_t test_setup(const size_t number_of_cases)
219354

220355
Case cases[] = {
221356
Case("Testing read write random blocks", test_random_program_read_erase),
222-
Case("Testing Multi Threads Erase Program Read", test_multi_threads)
357+
Case("Testing Multi Threads Erase Program Read", test_multi_threads),
358+
Case("Testing contiguous erase, write and read", test_contiguous_erase_write_read)
223359
};
224360

225361
Specification specification(test_setup, cases);

0 commit comments

Comments
 (0)