Skip to content

Commit 665152d

Browse files
committed
test: add flash functional tests for flash HAL
Add tests to verify the hal port of the flash_api.
1 parent dc85a8b commit 665152d

File tree

1 file changed

+249
-0
lines changed
  • TESTS/mbed_hal/flash/functional_tests

1 file changed

+249
-0
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2016 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#if !DEVICE_FLASH
18+
#error [NOT_SUPPORTED] Flash API not supported for this target
19+
#endif
20+
21+
#include "utest/utest.h"
22+
#include "unity/unity.h"
23+
#include "greentea-client/test_env.h"
24+
25+
#include "mbed.h"
26+
#include "flash_api.h"
27+
#include "flash_data.h"
28+
29+
using namespace utest::v1;
30+
31+
#define TEST_CYCLES 1000000
32+
#define ALLOWED_DRIFT_PPM 1000 //0.1%
33+
34+
/*
35+
return values to be checked are documented at:
36+
http://arm-software.github.io/CMSIS_5/Pack/html/algorithmFunc.html#Verify
37+
*/
38+
39+
#ifndef ALIGN_DOWN
40+
#define ALIGN_DOWN(x, a) ((x)& ~((a) - 1))
41+
#endif
42+
43+
static int timer_diff_start;
44+
45+
static void erase_range(flash_t *flash, uint32_t addr, uint32_t size)
46+
{
47+
while (size > 0) {
48+
uint32_t sector_size = flash_get_sector_size(flash, addr);
49+
TEST_ASSERT_NOT_EQUAL(0, sector_size);
50+
int32_t ret = flash_erase_sector(flash, addr);
51+
TEST_ASSERT_EQUAL_INT32(0, ret);
52+
size = size > sector_size ? size - sector_size : 0;
53+
}
54+
}
55+
56+
static int time_cpu_cycles(uint32_t cycles)
57+
{
58+
Timer timer;
59+
timer.start();
60+
61+
int timer_start = timer.read_us();
62+
63+
volatile uint32_t delay = (volatile uint32_t)cycles;
64+
while (delay--);
65+
66+
int timer_end = timer.read_us();
67+
68+
timer.stop();
69+
return timer_end - timer_start;
70+
}
71+
72+
void flash_init_test()
73+
{
74+
timer_diff_start = time_cpu_cycles(TEST_CYCLES);
75+
76+
flash_t test_flash;
77+
int32_t ret = flash_init(&test_flash);
78+
TEST_ASSERT_EQUAL_INT32(0, ret);
79+
ret = flash_free(&test_flash);
80+
TEST_ASSERT_EQUAL_INT32(0, ret);
81+
}
82+
83+
void flash_mapping_alignment_test()
84+
{
85+
flash_t test_flash;
86+
int32_t ret = flash_init(&test_flash);
87+
TEST_ASSERT_EQUAL_INT32(0, ret);
88+
89+
const uint32_t page_size = flash_get_page_size(&test_flash);
90+
const uint32_t flash_start = flash_get_start_address(&test_flash);
91+
const uint32_t flash_size = flash_get_size(&test_flash);
92+
TEST_ASSERT_TRUE(page_size != 0UL);
93+
94+
uint32_t sector_size = flash_get_sector_size(&test_flash, flash_start);
95+
for (uint32_t offset = 0; offset < flash_size; offset += sector_size) {
96+
const uint32_t sector_start = flash_start + offset;
97+
sector_size = flash_get_sector_size(&test_flash, sector_start);
98+
const uint32_t sector_end = sector_start + sector_size - 1;
99+
const uint32_t end_sector_size = flash_get_sector_size(&test_flash, sector_end);
100+
101+
// Sector size must be a valid value
102+
TEST_ASSERT_NOT_EQUAL(MBED_FLASH_INVALID_SIZE, sector_size);
103+
// Sector size must be greater than zero
104+
TEST_ASSERT_NOT_EQUAL(0, sector_size);
105+
// All flash sectors must be a multiple of page size
106+
TEST_ASSERT_EQUAL(0, sector_size % page_size);
107+
// Sector address must be a multiple of sector size
108+
TEST_ASSERT_EQUAL(0, sector_start % sector_size);
109+
// All address in a sector must return the same sector size
110+
TEST_ASSERT_EQUAL(sector_size, end_sector_size);
111+
112+
}
113+
114+
// Make sure unmapped flash is reported correctly
115+
TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start - 1));
116+
TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start + flash_size));
117+
118+
ret = flash_free(&test_flash);
119+
TEST_ASSERT_EQUAL_INT32(0, ret);
120+
}
121+
122+
void flash_erase_sector_test()
123+
{
124+
flash_t test_flash;
125+
int32_t ret = flash_init(&test_flash);
126+
TEST_ASSERT_EQUAL_INT32(0, ret);
127+
128+
uint32_t addr_after_last = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
129+
uint32_t last_sector_size = flash_get_sector_size(&test_flash, addr_after_last - 1);
130+
uint32_t last_sector = addr_after_last - last_sector_size;
131+
TEST_ASSERT_EQUAL_INT32(0, last_sector % last_sector_size);
132+
ret = flash_erase_sector(&test_flash, last_sector);
133+
TEST_ASSERT_EQUAL_INT32(0, ret);
134+
135+
ret = flash_free(&test_flash);
136+
TEST_ASSERT_EQUAL_INT32(0, ret);
137+
}
138+
139+
// Erase sector, write one page, erase sector and write new data
140+
void flash_program_page_test()
141+
{
142+
flash_t test_flash;
143+
int32_t ret = flash_init(&test_flash);
144+
TEST_ASSERT_EQUAL_INT32(0, ret);
145+
146+
uint32_t test_size = flash_get_page_size(&test_flash);
147+
uint8_t *data = new uint8_t[test_size];
148+
for (uint32_t i = 0; i < test_size; i++) {
149+
data[i] = 0xCE;
150+
}
151+
152+
// the one before the last page in the system
153+
uint32_t address = flash_get_start_address(&test_flash) + flash_get_size(&test_flash) - (2*test_size);
154+
155+
// sector size might not be same as page size
156+
uint32_t erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
157+
ret = flash_erase_sector(&test_flash, erase_sector_boundary);
158+
TEST_ASSERT_EQUAL_INT32(0, ret);
159+
160+
ret = flash_program_page(&test_flash, address, data, test_size);
161+
TEST_ASSERT_EQUAL_INT32(0, ret);
162+
uint8_t *data_flashed = (uint8_t *)address;
163+
TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);
164+
165+
// sector size might not be same as page size
166+
erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
167+
ret = flash_erase_sector(&test_flash, erase_sector_boundary);
168+
TEST_ASSERT_EQUAL_INT32(0, ret);
169+
170+
// write another data to be certain we are re-flashing
171+
for (uint32_t i = 0; i < test_size; i++) {
172+
data[i] = 0xAC;
173+
}
174+
ret = flash_program_page(&test_flash, address, data, test_size);
175+
TEST_ASSERT_EQUAL_INT32(0, ret);
176+
TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);
177+
178+
ret = flash_free(&test_flash);
179+
TEST_ASSERT_EQUAL_INT32(0, ret);
180+
delete[] data;
181+
}
182+
183+
// make sure programming works with an unaligned data buffer
184+
void flash_buffer_alignment_test()
185+
{
186+
flash_t test_flash;
187+
int32_t ret = flash_init(&test_flash);
188+
TEST_ASSERT_EQUAL_INT32(0, ret);
189+
190+
const uint32_t page_size = flash_get_page_size(&test_flash);
191+
const uint32_t buf_size = page_size + 4;
192+
uint8_t *data = new uint8_t[buf_size];
193+
for (uint32_t i = 0; i < buf_size; i++) {
194+
data[i] = i & 0xFF;
195+
}
196+
197+
// use the last four pages for the alignment test
198+
const uint32_t flash_end = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
199+
const uint32_t test_addr = flash_end - page_size * 4;
200+
const uint32_t erase_sector_boundary = ALIGN_DOWN(test_addr, flash_get_sector_size(&test_flash, test_addr));
201+
erase_range(&test_flash, erase_sector_boundary, flash_end - erase_sector_boundary);
202+
203+
// make sure page program works with an unaligned data buffer
204+
for (uint32_t i = 0; i < 4; i++) {
205+
const uint32_t addr = test_addr + i * page_size;
206+
ret = flash_program_page(&test_flash, addr, data + i, page_size);
207+
TEST_ASSERT_EQUAL_INT32(0, ret);
208+
uint8_t *data_flashed = (uint8_t *)addr;
209+
TEST_ASSERT_EQUAL_UINT8_ARRAY(data + i, data_flashed, page_size);
210+
}
211+
212+
ret = flash_free(&test_flash);
213+
TEST_ASSERT_EQUAL_INT32(0, ret);
214+
delete[] data;
215+
}
216+
217+
// check the execution speed at the start and end of the test to make sure
218+
// cache settings weren't changed
219+
void flash_clock_and_cache_test()
220+
{
221+
const int timer_diff_end = time_cpu_cycles(TEST_CYCLES);
222+
const int acceptable_range = timer_diff_start / (1000000 / ALLOWED_DRIFT_PPM);
223+
TEST_ASSERT_UINT32_WITHIN(acceptable_range, timer_diff_start, timer_diff_end);
224+
}
225+
226+
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason) {
227+
greentea_case_failure_abort_handler(source, reason);
228+
return STATUS_CONTINUE;
229+
}
230+
231+
Case cases[] = {
232+
Case("Flash - init", flash_init_test, greentea_failure_handler),
233+
Case("Flash - mapping alignment", flash_mapping_alignment_test, greentea_failure_handler),
234+
Case("Flash - erase sector", flash_erase_sector_test, greentea_failure_handler),
235+
Case("Flash - program page", flash_program_page_test, greentea_failure_handler),
236+
Case("Flash - buffer alignment test", flash_buffer_alignment_test, greentea_failure_handler),
237+
Case("Flash - clock and cache test", flash_clock_and_cache_test, greentea_failure_handler),
238+
};
239+
240+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
241+
GREENTEA_SETUP(20, "default_auto");
242+
return greentea_test_setup_handler(number_of_cases);
243+
}
244+
245+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
246+
247+
int main() {
248+
Harness::run(specification);
249+
}

0 commit comments

Comments
 (0)