Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 63 additions & 6 deletions FlashIAPBlockDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifdef DEVICE_FLASH

#include "FlashIAPBlockDevice.h"
#include "mbed_critical.h"

#include "mbed.h"

Expand All @@ -35,23 +36,67 @@
#define DEBUG_PRINTF(...)
#endif

FlashIAPBlockDevice::FlashIAPBlockDevice(uint32_t address, uint32_t size)
: _flash(), _base(address), _size(size)
FlashIAPBlockDevice::FlashIAPBlockDevice()
: _flash(), _base(0), _size(0), _is_initialized(false), _init_ref_count(0)
{
DEBUG_PRINTF("FlashIAPBlockDevice: %" PRIX32 " %" PRIX32 "\r\n", address, size);
}

FlashIAPBlockDevice::FlashIAPBlockDevice(uint32_t address, uint32_t)
: _flash(), _base(0), _size(0), _is_initialized(false), _init_ref_count(0)
{

}

FlashIAPBlockDevice::~FlashIAPBlockDevice()
{
deinit();
}

int FlashIAPBlockDevice::init()
{
DEBUG_PRINTF("init\r\n");

return _flash.init();
if (!_is_initialized) {
_init_ref_count = 0;
}

uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);

if (val != 1) {
return BD_ERROR_OK;
}

int ret = _flash.init();

if (ret) {
return ret;
}

_base = _flash.get_flash_start();
_size = _flash.get_flash_size();

_is_initialized = true;
return ret;
}

int FlashIAPBlockDevice::deinit()
{
DEBUG_PRINTF("deinit\r\n");

if (!_is_initialized) {
_init_ref_count = 0;
return 0;
}

uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1);

if (val) {
return 0;
}

_is_initialized = false;

return _flash.deinit();
}

Expand All @@ -65,7 +110,7 @@ int FlashIAPBlockDevice::read(void *buffer,
int result = BD_ERROR_DEVICE_ERROR;

/* Check that the address and size are properly aligned and fit. */
if (is_valid_read(virtual_address, size)) {
if (_is_initialized && is_valid_read(virtual_address, size)) {

/* Convert virtual address to the physical address for the device. */
bd_addr_t physical_address = _base + virtual_address;
Expand All @@ -89,7 +134,7 @@ int FlashIAPBlockDevice::program(const void *buffer,
int result = BD_ERROR_DEVICE_ERROR;

/* Check that the address and size are properly aligned and fit. */
if (is_valid_program(virtual_address, size)) {
if (_is_initialized && is_valid_program(virtual_address, size)) {

/* Convert virtual address to the physical address for the device. */
bd_addr_t physical_address = _base + virtual_address;
Expand All @@ -114,7 +159,7 @@ int FlashIAPBlockDevice::erase(bd_addr_t virtual_address,
int result = BD_ERROR_DEVICE_ERROR;

/* Check that the address and size are properly aligned and fit. */
if (is_valid_erase(virtual_address, size)) {
if (_is_initialized && is_valid_erase(virtual_address, size)) {

/* Convert virtual address to the physical address for the device. */
bd_addr_t physical_address = _base + virtual_address;
Expand All @@ -135,6 +180,10 @@ bd_size_t FlashIAPBlockDevice::get_read_size() const

bd_size_t FlashIAPBlockDevice::get_program_size() const
{
if (!_is_initialized) {
return 0;
}

uint32_t page_size = _flash.get_page_size();

DEBUG_PRINTF("get_program_size: %" PRIX32 "\r\n", page_size);
Expand All @@ -144,6 +193,10 @@ bd_size_t FlashIAPBlockDevice::get_program_size() const

bd_size_t FlashIAPBlockDevice::get_erase_size() const
{
if (!_is_initialized) {
return 0;
}

uint32_t erase_size = _flash.get_sector_size(_base);

DEBUG_PRINTF("get_erase_size: %" PRIX32 "\r\n", erase_size);
Expand All @@ -153,6 +206,10 @@ bd_size_t FlashIAPBlockDevice::get_erase_size() const

bd_size_t FlashIAPBlockDevice::get_erase_size(bd_addr_t addr) const
{
if (!_is_initialized) {
return 0;
}

uint32_t erase_size = _flash.get_sector_size(_base + addr);

DEBUG_PRINTF("get_erase_size: %" PRIX32 "\r\n", erase_size);
Expand Down
25 changes: 9 additions & 16 deletions FlashIAPBlockDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@
#include "BlockDevice.h"
#include <mbed.h>

#ifndef MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS
#error flashiap-block-device.base-address not set
#endif

#ifndef MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE
#error flashiap-block-device.size not set
#endif

/** BlockDevice using the FlashIAP API
*
* @code
Expand All @@ -39,14 +31,13 @@
*/
class FlashIAPBlockDevice : public BlockDevice {
public:
/** Creates a FlashIAPBlockDevice, starting at the given address and
* with a certain size.
*
* @param address Starting address for the BlockDevice
* @param size Maximum size allocated to this BlockDevice
*/
FlashIAPBlockDevice(uint32_t address = MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS,
uint32_t size = MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE);
/** Creates a FlashIAPBlockDevice **/
FlashIAPBlockDevice();

MBED_DEPRECATED("Please use default constructor instead")
FlashIAPBlockDevice(uint32_t address, uint32_t size = 0);

virtual ~FlashIAPBlockDevice();

/** Initialize a block device
*
Expand Down Expand Up @@ -129,6 +120,8 @@ class FlashIAPBlockDevice : public BlockDevice {
FlashIAP _flash;
bd_addr_t _base;
bd_size_t _size;
bool _is_initialized;
uint32_t _init_ref_count;
};

#endif /* DEVICE_FLASH */
Expand Down
18 changes: 2 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,13 @@ This driver is **EXPERIMENTAL** and improper usage could kill your board's flash
This driver should only be used on platforms where the FlashIAP implementation is using external flash or in conjunction with a filesystem with wear leveling, that can operate on a page size granularity.

Additional concerns:
- The BlockDevice API assumes a uniform erase size so the underlying flash must also have uniform sectors.
- The FlashIAP may freeze code execution for a long period of time while writing to flash. Not even high-priority irqs will be allowed to run, which may interrupt background processes.


## Configuration

The driver must be configured with the starting address for the internal flash area reserved for the block device and it's size in bytes. In the application's `mbed_app.json`, add the following lines:

```json
{
"target_overrides": {
"K64F": {
"flashiap-block-device.base-address": "<internal flash address where the block device starts>",
"flashiap-block-device.size": "<number of bytes allocated to the internal flash block device>"
}
}
}
```

None.

## Tested on

* Realtek RTL8195AM
* K82F
* K64F
60 changes: 38 additions & 22 deletions TESTS/filesystem/basic/basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@
*/

#include "mbed.h"
#include "mbed_config.h"
#include "FATFileSystem.h"
#include "LittleFileSystem.h"
#include "test_env.h"
#include "fsfat_debug.h"
#include "fsfat_test.h"
Expand Down Expand Up @@ -94,9 +93,11 @@ using namespace utest::v1;
//SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);

#include "FlashIAPBlockDevice.h"
#include "SlicingBlockDevice.h"

FlashIAPBlockDevice sd;
FATFileSystem fs("sd", &sd);
FlashIAPBlockDevice *flash;
SlicingBlockDevice *slice;
LittleFileSystem fs("sd");

#define FSFAT_BASIC_TEST_ fsfat_basic_test_
#define FSFAT_BASIC_TEST_00 fsfat_basic_test_00
Expand All @@ -118,7 +119,8 @@ static const char *sd_file_path = "/sd/out.txt";
static const int FSFAT_BASIC_DATA_SIZE = 256;
static char fsfat_basic_msg_g[FSFAT_BASIC_MSG_BUF_SIZE];
static char fsfat_basic_buffer[1024];
static const int FSFAT_BASIC_KIB_RW = 128;
static const int FSFAT_BASIC_KIB_RW = 16;
static const int MAX_TEST_SIZE = FSFAT_BASIC_KIB_RW * 1024 * 2;
static Timer fsfat_basic_timer;
static const char *fsfat_basic_bin_filename = "/sd/testfile.bin";
static const char *fsfat_basic_bin_filename_test_08 = "testfile.bin";
Expand All @@ -141,12 +143,26 @@ control_t fsfat_basic_test_(const size_t call_count)
(void) call_count;
int32_t ret = -1;

/* the allocation_unit of 0 means chanFS will use the default for the card (varies according to capacity). */
fs.unmount();
ret = fs.format(&sd);
FSFAT_TEST_UTEST_MESSAGE(fsfat_basic_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret);
flash = new FlashIAPBlockDevice();
ret = flash->init();
TEST_ASSERT_EQUAL(0, ret);

// Use slice of last sectors
bd_addr_t slice_addr = flash->size();
bd_size_t slice_size = 0;
while (slice_size < MAX_TEST_SIZE) {
bd_size_t unit_size = flash->get_erase_size(slice_addr - 1);
slice_addr -= unit_size;
slice_size += unit_size;
}
slice = new SlicingBlockDevice(flash, slice_addr);
slice->init();

ret = fs.reformat(slice);
FSFAT_TEST_UTEST_MESSAGE(fsfat_basic_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to format device (ret=%d)\n", __func__, (int) ret);
TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g);
fs.mount(&sd);
fs.mount(slice);

return CaseNext;
}

Expand Down Expand Up @@ -803,23 +819,23 @@ static control_t fsfat_basic_test_09()

bool fsfat_basic_test_file_write_fatfs(const char *filename, const int kib_rw)
{
FIL file;
FRESULT res = f_open(&file, filename, FA_WRITE | FA_CREATE_ALWAYS);
File file;
int res = file.open(&fs, filename, O_CREAT | O_WRONLY);

FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g);
TEST_ASSERT_MESSAGE(res == 0, fsfat_basic_msg_g);

int byte_write = 0;
unsigned int bytes = 0;
fsfat_basic_timer.start();
for (int i = 0; i < kib_rw; i++) {
res = f_write(&file, fsfat_basic_buffer, sizeof(fsfat_basic_buffer), &bytes);
bytes = file.write(fsfat_basic_buffer, sizeof(fsfat_basic_buffer));
FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to write to file.\n", __func__);
TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g);
TEST_ASSERT_MESSAGE(res == 0, fsfat_basic_msg_g);
byte_write++;
}
fsfat_basic_timer.stop();
f_close(&file);
file.close();
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
Expand All @@ -831,21 +847,21 @@ bool fsfat_basic_test_file_write_fatfs(const char *filename, const int kib_rw)

bool fsfat_basic_test_file_read_fatfs(const char *filename, const int kib_rw)
{
FIL file;
FRESULT res = f_open(&file, filename, FA_READ | FA_OPEN_EXISTING);
File file;
int res = file.open(&fs, filename, O_RDONLY);

FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__);
TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g);
TEST_ASSERT_MESSAGE(res == 0, fsfat_basic_msg_g);

fsfat_basic_timer.start();
int byte_read = 0;
unsigned int bytes = 0;
do {
res = f_read(&file, fsfat_basic_buffer, sizeof(fsfat_basic_buffer), &bytes);
bytes = file.read(fsfat_basic_buffer, sizeof(fsfat_basic_buffer));
byte_read++;
} while (res == FR_OK && bytes == sizeof(fsfat_basic_buffer));
} while (res == 0 && bytes == sizeof(fsfat_basic_buffer));
fsfat_basic_timer.stop();
f_close(&file);
file.close();
#ifdef FSFAT_DEBUG
double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0;
double speed = kib_rw / test_time_sec;
Expand Down
Loading