mirror of https://github.com/ARMmbed/mbed-os.git
FlashIAP driver modifications:
- Support programming across sectors. - Support program size not aligned to page size. - Fix validations on sector erase.pull/6140/head
parent
24a3acd647
commit
0aeeece97d
|
@ -81,6 +81,56 @@ void flashiap_program_test()
|
|||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
}
|
||||
|
||||
void flashiap_cross_sector_program_test()
|
||||
{
|
||||
FlashIAP flash_device;
|
||||
uint32_t ret = flash_device.init();
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
|
||||
uint32_t page_size = flash_device.get_page_size();
|
||||
|
||||
// Erase last two sectors
|
||||
uint32_t address = flash_device.get_flash_start() + flash_device.get_flash_size();
|
||||
uint32_t sector_size, agg_size = 0;
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
sector_size = flash_device.get_sector_size(address - 1UL);
|
||||
TEST_ASSERT_NOT_EQUAL(0, sector_size);
|
||||
TEST_ASSERT_TRUE(sector_size % page_size == 0);
|
||||
agg_size += sector_size;
|
||||
address -= sector_size;
|
||||
}
|
||||
ret = flash_device.erase(address, agg_size);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
|
||||
address += sector_size - page_size;
|
||||
uint32_t aligned_prog_size = 2 * page_size;
|
||||
uint32_t prog_size = aligned_prog_size;
|
||||
if (page_size > 1) {
|
||||
prog_size--;
|
||||
}
|
||||
uint8_t *data = new uint8_t[aligned_prog_size];
|
||||
for (uint32_t i = 0; i < prog_size; i++) {
|
||||
data[i] = rand() % 256;
|
||||
}
|
||||
for (uint32_t i = prog_size; i < aligned_prog_size; i++) {
|
||||
data[i] = 0xFF;
|
||||
}
|
||||
|
||||
ret = flash_device.program(data, address, prog_size);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
|
||||
uint8_t *data_flashed = new uint8_t[aligned_prog_size];
|
||||
ret = flash_device.read(data_flashed, address, aligned_prog_size);
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, aligned_prog_size);
|
||||
|
||||
delete[] data;
|
||||
delete[] data_flashed;
|
||||
|
||||
ret = flash_device.deinit();
|
||||
TEST_ASSERT_EQUAL_INT32(0, ret);
|
||||
}
|
||||
|
||||
void flashiap_program_error_test()
|
||||
{
|
||||
FlashIAP flash_device;
|
||||
|
@ -111,12 +161,6 @@ void flashiap_program_error_test()
|
|||
TEST_ASSERT_EQUAL_INT32(-1, ret);
|
||||
}
|
||||
|
||||
if (flash_device.get_page_size() > 1) {
|
||||
// unaligned page size
|
||||
ret = flash_device.program(data, address, page_size + 1);
|
||||
TEST_ASSERT_EQUAL_INT32(-1, ret);
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
|
||||
ret = flash_device.deinit();
|
||||
|
@ -126,6 +170,7 @@ void flashiap_program_error_test()
|
|||
Case cases[] = {
|
||||
Case("FlashIAP - init", flashiap_init_test),
|
||||
Case("FlashIAP - program", flashiap_program_test),
|
||||
Case("FlashIAP - program across sectors", flashiap_cross_sector_program_test),
|
||||
Case("FlashIAP - program errors", flashiap_program_error_test),
|
||||
};
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include "FlashIAP.h"
|
||||
#include "mbed_assert.h"
|
||||
|
||||
|
@ -57,6 +59,9 @@ int FlashIAP::init()
|
|||
if (flash_init(&_flash)) {
|
||||
ret = -1;
|
||||
}
|
||||
uint32_t page_size = get_page_size();
|
||||
_page_buf = new uint8_t[page_size];
|
||||
|
||||
_mutex->unlock();
|
||||
return ret;
|
||||
}
|
||||
|
@ -68,6 +73,7 @@ int FlashIAP::deinit()
|
|||
if (flash_free(&_flash)) {
|
||||
ret = -1;
|
||||
}
|
||||
delete[] _page_buf;
|
||||
_mutex->unlock();
|
||||
return ret;
|
||||
}
|
||||
|
@ -85,22 +91,43 @@ int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size)
|
|||
int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size)
|
||||
{
|
||||
uint32_t page_size = get_page_size();
|
||||
uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
|
||||
// addr and size should be aligned to page size, and multiple of page size
|
||||
// page program should not cross sector boundaries
|
||||
if (!is_aligned(addr, page_size) ||
|
||||
!is_aligned(size, page_size) ||
|
||||
(size < page_size) ||
|
||||
(((addr % current_sector_size) + size) > current_sector_size)) {
|
||||
uint32_t flash_size = flash_get_size(&_flash);
|
||||
uint32_t flash_start_addr = flash_get_start_address(&_flash);
|
||||
uint32_t chunk, prog_size;
|
||||
const uint8_t *buf = (uint8_t *) buffer;
|
||||
const uint8_t *prog_buf;
|
||||
|
||||
// addr should be aligned to page size
|
||||
if (!is_aligned(addr, page_size) || (!buffer) ||
|
||||
((addr + size) > (flash_start_addr + flash_size))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
_mutex->lock();
|
||||
if (flash_program_page(&_flash, addr, (const uint8_t *)buffer, size)) {
|
||||
ret = -1;
|
||||
while (size) {
|
||||
uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
|
||||
chunk = std::min(current_sector_size - (addr % current_sector_size), size);
|
||||
if (chunk < page_size) {
|
||||
memcpy(_page_buf, buf, chunk);
|
||||
memset(_page_buf + chunk, 0xFF, page_size - chunk);
|
||||
prog_buf = _page_buf;
|
||||
prog_size = page_size;
|
||||
} else {
|
||||
chunk = chunk / page_size * page_size;
|
||||
prog_buf = buf;
|
||||
prog_size = chunk;
|
||||
}
|
||||
if (flash_program_page(&_flash, addr, prog_buf, prog_size)) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
size -= chunk;
|
||||
addr += chunk;
|
||||
buf += chunk;
|
||||
}
|
||||
_mutex->unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -117,10 +144,19 @@ bool FlashIAP::is_aligned_to_sector(uint32_t addr, uint32_t size)
|
|||
|
||||
int FlashIAP::erase(uint32_t addr, uint32_t size)
|
||||
{
|
||||
uint32_t current_sector_size = 0UL;
|
||||
uint32_t current_sector_size;
|
||||
uint32_t flash_size = flash_get_size(&_flash);
|
||||
uint32_t flash_start_addr = flash_get_start_address(&_flash);
|
||||
uint32_t flash_end_addr = flash_start_addr + flash_size;
|
||||
uint32_t erase_end_addr = addr + size;
|
||||
|
||||
if (!is_aligned_to_sector(addr, size)) {
|
||||
if (erase_end_addr > flash_end_addr) {
|
||||
return -1;
|
||||
} else if (erase_end_addr < flash_end_addr){
|
||||
uint32_t following_sector_size = flash_get_sector_size(&_flash, erase_end_addr);
|
||||
if (!is_aligned(erase_end_addr, following_sector_size)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ret = 0;
|
||||
|
@ -132,10 +168,6 @@ int FlashIAP::erase(uint32_t addr, uint32_t size)
|
|||
break;
|
||||
}
|
||||
current_sector_size = flash_get_sector_size(&_flash, addr);
|
||||
if (!is_aligned_to_sector(addr, size)) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
size -= current_sector_size;
|
||||
addr += current_sector_size;
|
||||
}
|
||||
|
|
|
@ -72,8 +72,8 @@ public:
|
|||
* The sectors must have been erased prior to being programmed
|
||||
*
|
||||
* @param buffer Buffer of data to be written
|
||||
* @param addr Address of a page to begin writing to, must be a multiple of program and sector sizes
|
||||
* @param size Size to write in bytes, must be a multiple of program and sector sizes
|
||||
* @param addr Address of a page to begin writing to
|
||||
* @param size Size to write in bytes, must be a multiple of program size
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int program(const void *buffer, uint32_t addr, uint32_t size);
|
||||
|
@ -128,6 +128,7 @@ private:
|
|||
bool is_aligned_to_sector(uint32_t addr, uint32_t size);
|
||||
|
||||
flash_t _flash;
|
||||
uint8_t *_page_buf;
|
||||
static SingletonPtr<PlatformMutex> _mutex;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue