paul-szczepanek-arm 2018-02-23 14:03:10 +00:00
commit 41ee797d7f
3 changed files with 101 additions and 23 deletions
TESTS/mbed_drivers/flashiap

View File

@ -81,6 +81,56 @@ void flashiap_program_test()
TEST_ASSERT_EQUAL_INT32(0, ret); 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() void flashiap_program_error_test()
{ {
FlashIAP flash_device; FlashIAP flash_device;
@ -111,12 +161,6 @@ void flashiap_program_error_test()
TEST_ASSERT_EQUAL_INT32(-1, ret); 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; delete[] data;
ret = flash_device.deinit(); ret = flash_device.deinit();
@ -126,6 +170,7 @@ void flashiap_program_error_test()
Case cases[] = { Case cases[] = {
Case("FlashIAP - init", flashiap_init_test), Case("FlashIAP - init", flashiap_init_test),
Case("FlashIAP - program", flashiap_program_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), Case("FlashIAP - program errors", flashiap_program_error_test),
}; };

View File

@ -20,7 +20,9 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <stdio.h>
#include <string.h> #include <string.h>
#include <algorithm>
#include "FlashIAP.h" #include "FlashIAP.h"
#include "mbed_assert.h" #include "mbed_assert.h"
@ -57,6 +59,9 @@ int FlashIAP::init()
if (flash_init(&_flash)) { if (flash_init(&_flash)) {
ret = -1; ret = -1;
} }
uint32_t page_size = get_page_size();
_page_buf = new uint8_t[page_size];
_mutex->unlock(); _mutex->unlock();
return ret; return ret;
} }
@ -68,6 +73,7 @@ int FlashIAP::deinit()
if (flash_free(&_flash)) { if (flash_free(&_flash)) {
ret = -1; ret = -1;
} }
delete[] _page_buf;
_mutex->unlock(); _mutex->unlock();
return ret; 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) int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size)
{ {
uint32_t page_size = get_page_size(); uint32_t page_size = get_page_size();
uint32_t current_sector_size = flash_get_sector_size(&_flash, addr); uint32_t flash_size = flash_get_size(&_flash);
// addr and size should be aligned to page size, and multiple of page size uint32_t flash_start_addr = flash_get_start_address(&_flash);
// page program should not cross sector boundaries uint32_t chunk, prog_size;
if (!is_aligned(addr, page_size) || const uint8_t *buf = (uint8_t *) buffer;
!is_aligned(size, page_size) || const uint8_t *prog_buf;
(size < page_size) ||
(((addr % current_sector_size) + size) > current_sector_size)) { // addr should be aligned to page size
if (!is_aligned(addr, page_size) || (!buffer) ||
((addr + size) > (flash_start_addr + flash_size))) {
return -1; return -1;
} }
int ret = 0; int ret = 0;
_mutex->lock(); _mutex->lock();
if (flash_program_page(&_flash, addr, (const uint8_t *)buffer, size)) { while (size) {
ret = -1; 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(); _mutex->unlock();
return ret; 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) 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; 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; int32_t ret = 0;
@ -132,10 +168,6 @@ int FlashIAP::erase(uint32_t addr, uint32_t size)
break; break;
} }
current_sector_size = flash_get_sector_size(&_flash, addr); current_sector_size = flash_get_sector_size(&_flash, addr);
if (!is_aligned_to_sector(addr, size)) {
ret = -1;
break;
}
size -= current_sector_size; size -= current_sector_size;
addr += current_sector_size; addr += current_sector_size;
} }

View File

@ -72,8 +72,8 @@ public:
* The sectors must have been erased prior to being programmed * The sectors must have been erased prior to being programmed
* *
* @param buffer Buffer of data to be written * @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 addr Address of a page to begin writing to
* @param size Size to write in bytes, must be a multiple of program and sector sizes * @param size Size to write in bytes, must be a multiple of program size
* @return 0 on success, negative error code on failure * @return 0 on success, negative error code on failure
*/ */
int program(const void *buffer, uint32_t addr, uint32_t size); 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); bool is_aligned_to_sector(uint32_t addr, uint32_t size);
flash_t _flash; flash_t _flash;
uint8_t *_page_buf;
static SingletonPtr<PlatformMutex> _mutex; static SingletonPtr<PlatformMutex> _mutex;
}; };