From d1b5c5e995cdbb4003f7cb42ab1282d47a64ad86 Mon Sep 17 00:00:00 2001 From: David Saada Date: Sun, 5 Aug 2018 19:29:22 +0300 Subject: [PATCH 1/2] Change driver initialization behavior: - Remove configuration file (base and size taken from driver). - Add initializtion variables (is initialized and rinit ref count). - Add destructor. --- FlashIAPBlockDevice.cpp | 69 +++++++++++++++++++++++++++++++++++++---- FlashIAPBlockDevice.h | 25 ++++++--------- README.md | 18 ++--------- mbed_lib.json | 19 ------------ 4 files changed, 74 insertions(+), 57 deletions(-) delete mode 100644 mbed_lib.json diff --git a/FlashIAPBlockDevice.cpp b/FlashIAPBlockDevice.cpp index 51fb3f4..a79f57f 100644 --- a/FlashIAPBlockDevice.cpp +++ b/FlashIAPBlockDevice.cpp @@ -17,6 +17,7 @@ #ifdef DEVICE_FLASH #include "FlashIAPBlockDevice.h" +#include "mbed_critical.h" #include "mbed.h" @@ -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(); } @@ -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; @@ -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; @@ -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; @@ -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); @@ -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); @@ -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); diff --git a/FlashIAPBlockDevice.h b/FlashIAPBlockDevice.h index 39ede5f..54c1a8a 100644 --- a/FlashIAPBlockDevice.h +++ b/FlashIAPBlockDevice.h @@ -22,14 +22,6 @@ #include "BlockDevice.h" #include -#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 @@ -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 * @@ -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 */ diff --git a/README.md b/README.md index 998f1eb..54165e0 100644 --- a/README.md +++ b/README.md @@ -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": "", - "flashiap-block-device.size": "" - } - } -} -``` - +None. ## Tested on -* Realtek RTL8195AM +* K82F * K64F diff --git a/mbed_lib.json b/mbed_lib.json deleted file mode 100644 index 49b4cdb..0000000 --- a/mbed_lib.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "flashiap-block-device", - "config": { - "base-address": { - "help": "Base address for the block device on the external flash.", - "value": "0xFFFFFFFF" - }, - "size": { - "help": "Memory allocated for block device.", - "value": "0" - } - }, - "target_overrides": { - "REALTEK_RTL8195AM": { - "base-address": "0x1C0000", - "size": "0x40000" - } - } -} From e3b7cacd123814b2d64f3a414b2d9e2788b74f9c Mon Sep 17 00:00:00 2001 From: David Saada Date: Tue, 7 Aug 2018 16:58:31 +0300 Subject: [PATCH 2/2] Modify file system tests: - Use LittleFS instead of FAT (more appropriate in Flash). - Use slice to limit block device. --- TESTS/filesystem/basic/basic.cpp | 60 ++++++++++++++++++++------------ TESTS/filesystem/fopen/fopen.cpp | 35 ++++++++++++++----- 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/TESTS/filesystem/basic/basic.cpp b/TESTS/filesystem/basic/basic.cpp index 6391322..a7697d1 100644 --- a/TESTS/filesystem/basic/basic.cpp +++ b/TESTS/filesystem/basic/basic.cpp @@ -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" @@ -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 @@ -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"; @@ -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; } @@ -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; @@ -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; diff --git a/TESTS/filesystem/fopen/fopen.cpp b/TESTS/filesystem/fopen/fopen.cpp index 6d2a6ae..550c48d 100644 --- a/TESTS/filesystem/fopen/fopen.cpp +++ b/TESTS/filesystem/fopen/fopen.cpp @@ -22,8 +22,7 @@ */ #include "mbed.h" -#include "mbed_config.h" -#include "FATFileSystem.h" +#include "LittleFileSystem.h" #include "fsfat_debug.h" #include "fsfat_test.h" #include "utest/utest.h" @@ -76,15 +75,18 @@ using namespace utest::v1; */ #include "FlashIAPBlockDevice.h" +#include "SlicingBlockDevice.h" -FlashIAPBlockDevice sd; -FATFileSystem fs("sd", &sd); +FlashIAPBlockDevice *flash; +SlicingBlockDevice *slice; +LittleFileSystem fs("sd"); static char fsfat_fopen_utest_msg_g[FSFAT_UTEST_MSG_BUF_SIZE]; #define FSFAT_FOPEN_TEST_MOUNT_PT_NAME "sd" #define FSFAT_FOPEN_TEST_MOUNT_PT_PATH "/"FSFAT_FOPEN_TEST_MOUNT_PT_NAME #define FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1 64 #define FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH 20 +static const int MAX_TEST_SIZE = 256 * 1024 * 2; static const char *sd_badfile_path = "/sd/badfile.txt"; static const char *sd_testfile_path = "/sd/test.txt"; @@ -705,6 +707,8 @@ static const char fsfat_fopen_ascii_illegal_buf_g[] = "\"�'*+,./:;<=>?[\\]|"; */ control_t fsfat_fopen_test_06(const size_t call_count) { +// legal in LittleFS +#if 0 const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH; const char *extname = "txt"; const size_t filename_len = strlen(mnt_pt)+FSFAT_MAX_FILE_BASENAME+strlen(extname)+2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */ @@ -737,6 +741,7 @@ control_t fsfat_fopen_test_06(const size_t call_count) FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: created file when filename contains invalid characters (filename=%s, ret=%d).\n", __func__, filename, (int) ret); TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g); } +#endif return CaseNext; } @@ -1267,12 +1272,26 @@ control_t fsfat_fopen_test_00(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); + 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_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret); TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); - fs.mount(&sd); + fs.mount(slice); + return CaseNext; }