Skip to content

Commit 0aeeece

Browse files
author
David Saada
committed
FlashIAP driver modifications:
- Support programming across sectors. - Support program size not aligned to page size. - Fix validations on sector erase.
1 parent 24a3acd commit 0aeeece

File tree

3 files changed

+101
-23
lines changed

3 files changed

+101
-23
lines changed

TESTS/mbed_drivers/flashiap/main.cpp

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,56 @@ void flashiap_program_test()
8181
TEST_ASSERT_EQUAL_INT32(0, ret);
8282
}
8383

84+
void flashiap_cross_sector_program_test()
85+
{
86+
FlashIAP flash_device;
87+
uint32_t ret = flash_device.init();
88+
TEST_ASSERT_EQUAL_INT32(0, ret);
89+
90+
uint32_t page_size = flash_device.get_page_size();
91+
92+
// Erase last two sectors
93+
uint32_t address = flash_device.get_flash_start() + flash_device.get_flash_size();
94+
uint32_t sector_size, agg_size = 0;
95+
for (uint32_t i = 0; i < 2; i++) {
96+
sector_size = flash_device.get_sector_size(address - 1UL);
97+
TEST_ASSERT_NOT_EQUAL(0, sector_size);
98+
TEST_ASSERT_TRUE(sector_size % page_size == 0);
99+
agg_size += sector_size;
100+
address -= sector_size;
101+
}
102+
ret = flash_device.erase(address, agg_size);
103+
TEST_ASSERT_EQUAL_INT32(0, ret);
104+
105+
address += sector_size - page_size;
106+
uint32_t aligned_prog_size = 2 * page_size;
107+
uint32_t prog_size = aligned_prog_size;
108+
if (page_size > 1) {
109+
prog_size--;
110+
}
111+
uint8_t *data = new uint8_t[aligned_prog_size];
112+
for (uint32_t i = 0; i < prog_size; i++) {
113+
data[i] = rand() % 256;
114+
}
115+
for (uint32_t i = prog_size; i < aligned_prog_size; i++) {
116+
data[i] = 0xFF;
117+
}
118+
119+
ret = flash_device.program(data, address, prog_size);
120+
TEST_ASSERT_EQUAL_INT32(0, ret);
121+
122+
uint8_t *data_flashed = new uint8_t[aligned_prog_size];
123+
ret = flash_device.read(data_flashed, address, aligned_prog_size);
124+
TEST_ASSERT_EQUAL_INT32(0, ret);
125+
TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, aligned_prog_size);
126+
127+
delete[] data;
128+
delete[] data_flashed;
129+
130+
ret = flash_device.deinit();
131+
TEST_ASSERT_EQUAL_INT32(0, ret);
132+
}
133+
84134
void flashiap_program_error_test()
85135
{
86136
FlashIAP flash_device;
@@ -111,12 +161,6 @@ void flashiap_program_error_test()
111161
TEST_ASSERT_EQUAL_INT32(-1, ret);
112162
}
113163

114-
if (flash_device.get_page_size() > 1) {
115-
// unaligned page size
116-
ret = flash_device.program(data, address, page_size + 1);
117-
TEST_ASSERT_EQUAL_INT32(-1, ret);
118-
}
119-
120164
delete[] data;
121165

122166
ret = flash_device.deinit();
@@ -126,6 +170,7 @@ void flashiap_program_error_test()
126170
Case cases[] = {
127171
Case("FlashIAP - init", flashiap_init_test),
128172
Case("FlashIAP - program", flashiap_program_test),
173+
Case("FlashIAP - program across sectors", flashiap_cross_sector_program_test),
129174
Case("FlashIAP - program errors", flashiap_program_error_test),
130175
};
131176

drivers/FlashIAP.cpp

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
* SOFTWARE.
2121
*/
2222

23+
#include <stdio.h>
2324
#include <string.h>
25+
#include <algorithm>
2426
#include "FlashIAP.h"
2527
#include "mbed_assert.h"
2628

@@ -57,6 +59,9 @@ int FlashIAP::init()
5759
if (flash_init(&_flash)) {
5860
ret = -1;
5961
}
62+
uint32_t page_size = get_page_size();
63+
_page_buf = new uint8_t[page_size];
64+
6065
_mutex->unlock();
6166
return ret;
6267
}
@@ -68,6 +73,7 @@ int FlashIAP::deinit()
6873
if (flash_free(&_flash)) {
6974
ret = -1;
7075
}
76+
delete[] _page_buf;
7177
_mutex->unlock();
7278
return ret;
7379
}
@@ -85,22 +91,43 @@ int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size)
8591
int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size)
8692
{
8793
uint32_t page_size = get_page_size();
88-
uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
89-
// addr and size should be aligned to page size, and multiple of page size
90-
// page program should not cross sector boundaries
91-
if (!is_aligned(addr, page_size) ||
92-
!is_aligned(size, page_size) ||
93-
(size < page_size) ||
94-
(((addr % current_sector_size) + size) > current_sector_size)) {
94+
uint32_t flash_size = flash_get_size(&_flash);
95+
uint32_t flash_start_addr = flash_get_start_address(&_flash);
96+
uint32_t chunk, prog_size;
97+
const uint8_t *buf = (uint8_t *) buffer;
98+
const uint8_t *prog_buf;
99+
100+
// addr should be aligned to page size
101+
if (!is_aligned(addr, page_size) || (!buffer) ||
102+
((addr + size) > (flash_start_addr + flash_size))) {
95103
return -1;
96104
}
97105

98106
int ret = 0;
99107
_mutex->lock();
100-
if (flash_program_page(&_flash, addr, (const uint8_t *)buffer, size)) {
101-
ret = -1;
108+
while (size) {
109+
uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
110+
chunk = std::min(current_sector_size - (addr % current_sector_size), size);
111+
if (chunk < page_size) {
112+
memcpy(_page_buf, buf, chunk);
113+
memset(_page_buf + chunk, 0xFF, page_size - chunk);
114+
prog_buf = _page_buf;
115+
prog_size = page_size;
116+
} else {
117+
chunk = chunk / page_size * page_size;
118+
prog_buf = buf;
119+
prog_size = chunk;
120+
}
121+
if (flash_program_page(&_flash, addr, prog_buf, prog_size)) {
122+
ret = -1;
123+
break;
124+
}
125+
size -= chunk;
126+
addr += chunk;
127+
buf += chunk;
102128
}
103129
_mutex->unlock();
130+
104131
return ret;
105132
}
106133

@@ -117,10 +144,19 @@ bool FlashIAP::is_aligned_to_sector(uint32_t addr, uint32_t size)
117144

118145
int FlashIAP::erase(uint32_t addr, uint32_t size)
119146
{
120-
uint32_t current_sector_size = 0UL;
147+
uint32_t current_sector_size;
148+
uint32_t flash_size = flash_get_size(&_flash);
149+
uint32_t flash_start_addr = flash_get_start_address(&_flash);
150+
uint32_t flash_end_addr = flash_start_addr + flash_size;
151+
uint32_t erase_end_addr = addr + size;
121152

122-
if (!is_aligned_to_sector(addr, size)) {
153+
if (erase_end_addr > flash_end_addr) {
123154
return -1;
155+
} else if (erase_end_addr < flash_end_addr){
156+
uint32_t following_sector_size = flash_get_sector_size(&_flash, erase_end_addr);
157+
if (!is_aligned(erase_end_addr, following_sector_size)) {
158+
return -1;
159+
}
124160
}
125161

126162
int32_t ret = 0;
@@ -132,10 +168,6 @@ int FlashIAP::erase(uint32_t addr, uint32_t size)
132168
break;
133169
}
134170
current_sector_size = flash_get_sector_size(&_flash, addr);
135-
if (!is_aligned_to_sector(addr, size)) {
136-
ret = -1;
137-
break;
138-
}
139171
size -= current_sector_size;
140172
addr += current_sector_size;
141173
}

drivers/FlashIAP.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ class FlashIAP : private NonCopyable<FlashIAP> {
7272
* The sectors must have been erased prior to being programmed
7373
*
7474
* @param buffer Buffer of data to be written
75-
* @param addr Address of a page to begin writing to, must be a multiple of program and sector sizes
76-
* @param size Size to write in bytes, must be a multiple of program and sector sizes
75+
* @param addr Address of a page to begin writing to
76+
* @param size Size to write in bytes, must be a multiple of program size
7777
* @return 0 on success, negative error code on failure
7878
*/
7979
int program(const void *buffer, uint32_t addr, uint32_t size);
@@ -128,6 +128,7 @@ class FlashIAP : private NonCopyable<FlashIAP> {
128128
bool is_aligned_to_sector(uint32_t addr, uint32_t size);
129129

130130
flash_t _flash;
131+
uint8_t *_page_buf;
131132
static SingletonPtr<PlatformMutex> _mutex;
132133
};
133134

0 commit comments

Comments
 (0)