Skip to content

Commit c337a07

Browse files
committed
bd: Added block randomizations and some more helpful checks to testing
1 parent 9cdd9f4 commit c337a07

File tree

3 files changed

+134
-66
lines changed

3 files changed

+134
-66
lines changed

features/filesystem/spif/SPIFBlockDevice.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#define SPIF_TIMEOUT 10000
2525

2626
// Debug available
27-
#define SPIF_DEBUG true
27+
#define SPIF_DEBUG 0
2828

2929
// MX25R Series Register Command Table.
3030
enum ops {
@@ -51,20 +51,22 @@ SPIFBlockDevice::SPIFBlockDevice(
5151
PinName mosi, PinName miso, PinName sclk, PinName cs, int freq)
5252
: _spi(mosi, miso, sclk), _cs(cs), _size(0)
5353
{
54+
_cs = 1;
5455
_spi.frequency(freq);
5556
}
5657

5758
bd_error_t SPIFBlockDevice::init()
5859
{
5960
// Check for vendor specific hacks, these should move into more general
6061
// handling when possible. RDID is not used to verify a device is attached.
61-
uint8_t id;
62-
_cmdread(SPIF_RDID, 0, 1, 0x0, &id);
62+
uint8_t id[3];
63+
_cmdread(SPIF_RDID, 0, 3, 0x0, id);
6364

64-
switch (id) {
65+
switch (id[0]) {
6566
case 0xbf:
6667
// SST devices come preset with block protection
6768
// enabled for some regions, issue gbpu instruction to clear
69+
_wren();
6870
_cmdwrite(0x98, 0, 0, 0x0, NULL);
6971
break;
7072
}
@@ -82,13 +84,13 @@ bd_error_t SPIFBlockDevice::init()
8284

8385
// Verify SFDP signature for sanity
8486
// Also check that major/minor version is acceptable
85-
if (!(memcmp(&header[0], "SFDP", 4) == 0 && header[4+1] == 1 && header[4+0] >= 6)) {
87+
if (!(memcmp(&header[0], "SFDP", 4) == 0 && header[5] == 1)) {
8688
return BD_ERROR_DEVICE_ERROR;
8789
}
8890

8991
// The SFDP spec indicates the standard table is always at offset 0
9092
// in the parameter headers, we check just to be safe
91-
if (!(header[8] == 0 && header[9+1] == 1 && header[9+0] >= 6)) {
93+
if (!(header[8] == 0 && header[10] == 1)) {
9294
return BD_ERROR_DEVICE_ERROR;
9395
}
9496

@@ -152,17 +154,15 @@ void SPIFBlockDevice::_cmdread(
152154
_cs = 1;
153155

154156
if (SPIF_DEBUG) {
155-
printf("spif %02x", op);
156-
for (uint32_t i = 0; i < 4; i++) {
157+
printf("spif <- %02x", op);
158+
for (uint32_t i = 0; i < addrc; i++) {
157159
if (i < addrc) {
158160
printf("%02lx", 0xff & (addr >> 8*(addrc-1 - i)));
159161
} else {
160162
printf(" ");
161163
}
162164
}
163-
if (retc > 0) {
164-
printf(" <- ");
165-
}
165+
printf(" ");
166166
for (uint32_t i = 0; i < 16 && i < retc; i++) {
167167
printf("%02x", rets[i]);
168168
}
@@ -190,17 +190,15 @@ void SPIFBlockDevice::_cmdwrite(
190190
_cs = 1;
191191

192192
if (SPIF_DEBUG) {
193-
printf("spif %02x", op);
194-
for (uint32_t i = 0; i < 4 || i < addrc; i++) {
193+
printf("spif -> %02x", op);
194+
for (uint32_t i = 0; i < addrc; i++) {
195195
if (i < addrc) {
196196
printf("%02lx", 0xff & (addr >> 8*(addrc-1 - i)));
197197
} else {
198198
printf(" ");
199199
}
200200
}
201-
if (argc > 0) {
202-
printf(" -> ");
203-
}
201+
printf(" ");
204202
for (uint32_t i = 0; i < 16 && i < argc; i++) {
205203
printf("%02x", args[i]);
206204
}
@@ -274,12 +272,16 @@ bd_error_t SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_
274272
}
275273

276274
// Write up to 256 bytes a page
277-
uint32_t chunk = (size < 256) ? size : 256;
275+
// TODO handle unaligned programs
276+
uint32_t off = addr % 256;
277+
uint32_t chunk = (off + size < 256) ? size : (256-off);
278278
_cmdwrite(SPIF_PROG, 3, chunk, addr, static_cast<const uint8_t *>(buffer));
279279
buffer = static_cast<const uint8_t*>(buffer) + chunk;
280280
addr += chunk;
281281
size -= chunk;
282282

283+
wait_ms(1);
284+
283285
err = _sync();
284286
if (err) {
285287
return err;
@@ -318,17 +320,17 @@ bd_error_t SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t size)
318320
return 0;
319321
}
320322

321-
bd_size_t SPIFBlockDevice::read_size()
323+
bd_size_t SPIFBlockDevice::get_read_size()
322324
{
323325
return SPIF_READ_SIZE;
324326
}
325327

326-
bd_size_t SPIFBlockDevice::program_size()
328+
bd_size_t SPIFBlockDevice::get_program_size()
327329
{
328330
return SPIF_PROG_SIZE;
329331
}
330332

331-
bd_size_t SPIFBlockDevice::erase_size()
333+
bd_size_t SPIFBlockDevice::get_erase_size()
332334
{
333335
return SPIF_SE_SIZE;
334336
}

features/filesystem/spif/SPIFBlockDevice.h

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
#include "BlockDevice.h"
2424

2525

26-
/** BlockDevice for the SPIF series of spi-based flash chips
26+
/** BlockDevice for SPI based flash devices
27+
* such as the MX25R or SST26F016B
2728
*
2829
* @code
2930
* #include "mbed.h"
@@ -36,15 +37,15 @@
3637
* printf("mx25r test\n");
3738
* mx52r.init();
3839
* printf("mx25r size: %llu\n", mx25r.size());
39-
* printf("mx25r read size: %llu\n", mx25r.read_size());
40-
* printf("mx25r program size: %llu\n", mx25r.program_size());
41-
* printf("mx25r erase size: %llu\n", mx25r.erase_size());
40+
* printf("mx25r read size: %llu\n", mx25r.get_read_size());
41+
* printf("mx25r program size: %llu\n", mx25r.get_program_size());
42+
* printf("mx25r erase size: %llu\n", mx25r.get_erase_size());
4243
*
43-
* uint8_t *buffer = malloc(mx25r.erase_size());
44+
* uint8_t *buffer = malloc(mx25r.get_erase_size());
4445
* sprintf(buffer, "Hello World!\n");
45-
* mx25r.erase(0, mx25r.erase_size());
46-
* mx25r.write(buffer, 0, mx25r.erase_size());
47-
* mx25r.read(buffer, 0, mx25r.erase_size());
46+
* mx25r.erase(0, mx25r.get_erase_size());
47+
* mx25r.write(buffer, 0, mx25r.get_erase_size());
48+
* mx25r.read(buffer, 0, mx25r.get_erase_size());
4849
* printf("%s", buffer);
4950
*
5051
* mx25r.deinit();
@@ -58,9 +59,9 @@ class SPIFBlockDevice : public BlockDevice {
5859
* @param miso SPI master in, slave out pin
5960
* @param sclk SPI clock pin
6061
* @param csel SPI chip select pin
61-
* @param freq Clock speed of the SPI bus (defaults to 50MHz)
62+
* @param freq Clock speed of the SPI bus (defaults to 40MHz)
6263
*/
63-
SPIFBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq=50000000);
64+
SPIFBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq=4000000);
6465

6566
/** Initialize a block device
6667
*
@@ -108,21 +109,21 @@ class SPIFBlockDevice : public BlockDevice {
108109
*
109110
* @return Size of a readable block in bytes
110111
*/
111-
virtual bd_size_t read_size();
112+
virtual bd_size_t get_read_size();
112113

113114
/** Get the size of a programable block
114115
*
115116
* @return Size of a programable block in bytes
116117
* @note Must be a multiple of the read size
117118
*/
118-
virtual bd_size_t program_size();
119+
virtual bd_size_t get_program_size();
119120

120121
/** Get the size of a eraseable block
121122
*
122123
* @return Size of a eraseable block in bytes
123124
* @note Must be a multiple of the program size
124125
*/
125-
virtual bd_size_t erase_size();
126+
virtual bd_size_t get_erase_size();
126127

127128
/** Get the total size of the underlying device
128129
*

features/filesystem/spif/TESTS/block_device/spif/main.cpp

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,111 @@ using namespace utest::v1;
1616
//#error [NOT_SUPPORTED] SPIF Required
1717
//#endif
1818

19-
#define BLOCK_SIZE 4096
20-
uint8_t write_block[BLOCK_SIZE];
21-
uint8_t read_block[BLOCK_SIZE];
19+
#if defined(TARGET_K82F)
20+
#define TEST_PINS PTE2, PTE4, PTE1, PTE5
21+
#define TEST_FREQ 40000000
22+
#else
23+
#define TEST_PINS D11, D12, D13, D10
24+
#define TEST_FREQ 1000000
25+
#endif
26+
27+
#define TEST_BLOCK_COUNT 10
28+
#define TEST_ERROR_MASK 16
29+
30+
const struct {
31+
const char *name;
32+
bd_size_t (BlockDevice::*method)();
33+
} ATTRS[] = {
34+
{"read size", &BlockDevice::get_read_size},
35+
{"program size", &BlockDevice::get_program_size},
36+
{"erase size", &BlockDevice::get_erase_size},
37+
{"total size", &BlockDevice::size},
38+
};
2239

2340

2441
void test_read_write() {
25-
//SPIFBlockDevice bd(PTE2, PTE4, PTE1, PTE5);
26-
SPIFBlockDevice bd(D11, D12, D13, D10);
42+
SPIFBlockDevice bd(TEST_PINS, TEST_FREQ);
2743

2844
int err = bd.init();
2945
TEST_ASSERT_EQUAL(0, err);
3046

31-
printf("read size: %llu\r\n", bd.read_size());
32-
printf("program size: %llu\r\n", bd.program_size());
33-
printf("erase size: %llu\r\n", bd.erase_size());
34-
35-
// Fill with random sequence
36-
srand(1);
37-
for (int i = 0; i < BLOCK_SIZE; i++) {
38-
write_block[i] = 0xff & rand();
47+
for (unsigned a = 0; a < sizeof(ATTRS)/sizeof(ATTRS[0]); a++) {
48+
static const char *prefixes[] = {"", "k", "M", "G"};
49+
for (int i = 3; i >= 0; i--) {
50+
bd_size_t size = (bd.*ATTRS[a].method)();
51+
if (size >= (1ULL << 10*i)) {
52+
printf("%s: %llu%sbytes (%llubytes)\n",
53+
ATTRS[a].name, size >> 10*i, prefixes[i], size);
54+
break;
55+
}
56+
}
3957
}
4058

41-
// Write, sync, and read the block
42-
err = bd.write(write_block, 0, BLOCK_SIZE);
43-
TEST_ASSERT_EQUAL(0, err);
44-
45-
err = bd.read(read_block, 0, BLOCK_SIZE);
46-
TEST_ASSERT_EQUAL(0, err);
47-
48-
// Check that the data was unmodified
49-
printf("w (0x%02x%02x%02x%02x)\n",
50-
write_block[0], write_block[1], write_block[2], write_block[3],
51-
write_block[4], write_block[5], write_block[6], write_block[7]);
52-
printf("r (0x%02x%02x%02x%02x)\n",
53-
read_block[0], read_block[1], read_block[2], read_block[3],
54-
read_block[4], read_block[5], read_block[6], read_block[7]);
55-
56-
srand(1);
57-
for (int i = 0; i < BLOCK_SIZE; i++) {
58-
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
59+
bd_size_t block_size = bd.get_erase_size();
60+
uint8_t *write_block = new uint8_t[block_size];
61+
uint8_t *read_block = new uint8_t[block_size];
62+
uint8_t *error_mask = new uint8_t[TEST_ERROR_MASK];
63+
unsigned addrwidth = ceil(log(bd.size()-1) / log(16))+1;
64+
65+
for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
66+
// Find a random block
67+
bd_addr_t block = (rand()*block_size) % bd.size();
68+
69+
// Use next random number as temporary seed to keep
70+
// the address progressing in the pseudorandom sequence
71+
unsigned seed = rand();
72+
73+
// Fill with random sequence
74+
srand(seed);
75+
for (bd_size_t i = 0; i < block_size; i++) {
76+
write_block[i] = 0xff & rand();
77+
}
78+
79+
// Write, sync, and read the block
80+
printf("test %0*llx:%llu...\n", addrwidth, block, block_size);
81+
82+
err = bd.write(write_block, block, block_size);
83+
TEST_ASSERT_EQUAL(0, err);
84+
85+
printf("write %0*llx:%llu ", addrwidth, block, block_size);
86+
for (int i = 0; i < 16; i++) {
87+
printf("%02x", write_block[i]);
88+
}
89+
printf("...\n");
90+
91+
err = bd.read(read_block, block, block_size);
92+
TEST_ASSERT_EQUAL(0, err);
93+
94+
printf("read %0*llx:%llu ", addrwidth, block, block_size);
95+
for (int i = 0; i < 16; i++) {
96+
printf("%02x", read_block[i]);
97+
}
98+
printf("...\n");
99+
100+
// Find error mask for debugging
101+
memset(error_mask, 0, TEST_ERROR_MASK);
102+
bd_size_t error_scale = block_size / (TEST_ERROR_MASK*8);
103+
104+
srand(seed);
105+
for (bd_size_t i = 0; i < TEST_ERROR_MASK*8; i++) {
106+
for (bd_size_t j = 0; j < error_scale; j++) {
107+
if ((0xff & rand()) != read_block[i*error_scale + j]) {
108+
error_mask[i/8] |= 1 << (i%8);
109+
}
110+
}
111+
}
112+
113+
printf("error %0*llx:%llu ", addrwidth, block, block_size);
114+
for (int i = 0; i < 16; i++) {
115+
printf("%02x", error_mask[i]);
116+
}
117+
printf("\n");
118+
119+
// Check that the data was unmodified
120+
srand(seed);
121+
for (bd_size_t i = 0; i < block_size; i++) {
122+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
123+
}
59124
}
60125

61126
err = bd.deinit();
@@ -65,12 +130,12 @@ void test_read_write() {
65130

66131
// Test setup
67132
utest::v1::status_t test_setup(const size_t number_of_cases) {
68-
GREENTEA_SETUP(10*1000*1000, "default_auto");
133+
GREENTEA_SETUP(30, "default_auto");
69134
return verbose_test_setup_handler(number_of_cases);
70135
}
71136

72137
Case cases[] = {
73-
Case("Testing read write of a block", test_read_write),
138+
Case("Testing read write random blocks", test_read_write),
74139
};
75140

76141
Specification specification(test_setup, cases);

0 commit comments

Comments
 (0)