Skip to content

Commit 355f69a

Browse files
authored
Merge pull request #3802 from ARMmbed/feature-flash-api
Merge the feature-flash-api branch into master
2 parents 5491ccc + 0712354 commit 355f69a

File tree

14 files changed

+1484
-16
lines changed

14 files changed

+1484
-16
lines changed

TESTS/mbed_drivers/flashiap/main.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
2+
/* mbed Microcontroller Library
3+
* Copyright (c) 2017 ARM Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#if !DEVICE_FLASH
19+
#error [NOT_SUPPORTED] Flash API not supported for this target
20+
#endif
21+
22+
#include "utest/utest.h"
23+
#include "unity/unity.h"
24+
#include "greentea-client/test_env.h"
25+
26+
#include "mbed.h"
27+
28+
using namespace utest::v1;
29+
30+
void flashiap_init_test()
31+
{
32+
FlashIAP flash_device;
33+
uint32_t ret = flash_device.init();
34+
TEST_ASSERT_EQUAL_INT32(0, ret);
35+
ret = flash_device.deinit();
36+
TEST_ASSERT_EQUAL_INT32(0, ret);
37+
}
38+
39+
void flashiap_program_test()
40+
{
41+
FlashIAP flash_device;
42+
uint32_t ret = flash_device.init();
43+
TEST_ASSERT_EQUAL_INT32(0, ret);
44+
45+
// get the last sector size (flash size - 1)
46+
uint32_t sector_size = flash_device.get_sector_size(flash_device.get_flash_start() + flash_device.get_flash_size() - 1UL);
47+
uint32_t page_size = flash_device.get_page_size();
48+
TEST_ASSERT_NOT_EQUAL(0, sector_size);
49+
TEST_ASSERT_NOT_EQUAL(0, page_size);
50+
TEST_ASSERT_TRUE(sector_size % page_size == 0);
51+
const uint8_t test_value = 0xCE;
52+
uint8_t *data = new uint8_t[page_size];
53+
for (uint32_t i = 0; i < page_size; i++) {
54+
data[i] = test_value;
55+
}
56+
57+
// the one before the last sector in the system
58+
uint32_t address = (flash_device.get_flash_start() + flash_device.get_flash_size()) - (sector_size);
59+
TEST_ASSERT_TRUE(address != 0UL);
60+
ret = flash_device.erase(address, sector_size);
61+
TEST_ASSERT_EQUAL_INT32(0, ret);
62+
63+
64+
for (uint32_t i = 0; i < sector_size / page_size; i++) {
65+
uint32_t page_addr = address + i * page_size;
66+
ret = flash_device.program(data, page_addr, page_size);
67+
TEST_ASSERT_EQUAL_INT32(0, ret);
68+
}
69+
70+
uint8_t *data_flashed = new uint8_t[page_size];
71+
for (uint32_t i = 0; i < sector_size / page_size; i++) {
72+
uint32_t page_addr = address + i * page_size;
73+
ret = flash_device.read(data_flashed, page_addr, page_size);
74+
TEST_ASSERT_EQUAL_INT32(0, ret);
75+
TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, page_size);
76+
}
77+
delete[] data;
78+
delete[] data_flashed;
79+
80+
ret = flash_device.deinit();
81+
TEST_ASSERT_EQUAL_INT32(0, ret);
82+
}
83+
84+
void flashiap_program_error_test()
85+
{
86+
FlashIAP flash_device;
87+
uint32_t ret = flash_device.init();
88+
TEST_ASSERT_EQUAL_INT32(0, ret);
89+
90+
// get the last sector size (flash size - 1)
91+
uint32_t sector_size = flash_device.get_sector_size(flash_device.get_flash_start() + flash_device.get_flash_size() - 1UL);
92+
uint32_t page_size = flash_device.get_page_size();
93+
TEST_ASSERT_NOT_EQUAL(0, sector_size);
94+
TEST_ASSERT_NOT_EQUAL(0, page_size);
95+
TEST_ASSERT_TRUE(sector_size % page_size == 0);
96+
const uint8_t test_value = 0xCE;
97+
uint8_t *data = new uint8_t[page_size];
98+
for (uint32_t i = 0; i < page_size; i++) {
99+
data[i] = test_value;
100+
}
101+
102+
// the one before the last page in the system
103+
uint32_t address = (flash_device.get_flash_start() + flash_device.get_flash_size()) - (sector_size);
104+
TEST_ASSERT_TRUE(address != 0UL);
105+
106+
// unaligned address
107+
ret = flash_device.erase(address + 1, sector_size);
108+
TEST_ASSERT_EQUAL_INT32(-1, ret);
109+
ret = flash_device.program(data, address + 1, page_size);
110+
TEST_ASSERT_EQUAL_INT32(-1, ret);
111+
112+
// unaligned page size
113+
ret = flash_device.program(data, address, page_size + 1);
114+
TEST_ASSERT_EQUAL_INT32(-1, ret);
115+
116+
delete[] data;
117+
118+
ret = flash_device.deinit();
119+
TEST_ASSERT_EQUAL_INT32(0, ret);
120+
}
121+
122+
Case cases[] = {
123+
Case("FlashIAP - init", flashiap_init_test),
124+
Case("FlashIAP - program", flashiap_program_test),
125+
Case("FlashIAP - program errors", flashiap_program_error_test),
126+
};
127+
128+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
129+
GREENTEA_SETUP(20, "default_auto");
130+
return greentea_test_setup_handler(number_of_cases);
131+
}
132+
133+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
134+
135+
int main() {
136+
Harness::run(specification);
137+
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 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+
Case cases[] = {
227+
Case("Flash - init", flash_init_test),
228+
Case("Flash - mapping alignment", flash_mapping_alignment_test),
229+
Case("Flash - erase sector", flash_erase_sector_test),
230+
Case("Flash - program page", flash_program_page_test),
231+
Case("Flash - buffer alignment test", flash_buffer_alignment_test),
232+
Case("Flash - clock and cache test", flash_clock_and_cache_test),
233+
};
234+
235+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
236+
GREENTEA_SETUP(20, "default_auto");
237+
return greentea_test_setup_handler(number_of_cases);
238+
}
239+
240+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
241+
242+
int main() {
243+
Harness::run(specification);
244+
}

0 commit comments

Comments
 (0)