From 9eb1c910938c8149250680ba92d4783a29ad101a Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 3 Jan 2015 22:03:07 +0100 Subject: [PATCH 01/17] Flash interface for native CPU --- boards/native/Makefile.features | 2 + boards/pca10000/Makefile.features | 2 + boards/pca10005/Makefile.features | 2 + boards/yunjia-nrf51822/Makefile.features | 2 + cpu/native/include/cpu-conf.h | 12 + cpu/native/periph/flash.c | 305 +++++++++++++++++++++++ cpu/native/startup.c | 18 ++ cpu/nrf51822/include/cpu-conf.h | 15 ++ drivers/include/periph/flash.h | 207 +++++++++++++++ tests/periph_flash/Makefile | 6 + tests/periph_flash/README.md | 4 + tests/periph_flash/main.c | 92 +++++++ 12 files changed, 667 insertions(+) create mode 100644 cpu/native/periph/flash.c create mode 100644 drivers/include/periph/flash.h create mode 100644 tests/periph_flash/Makefile create mode 100644 tests/periph_flash/README.md create mode 100644 tests/periph_flash/main.c diff --git a/boards/native/Makefile.features b/boards/native/Makefile.features index 4ad14738b855..3aeab9864980 100644 --- a/boards/native/Makefile.features +++ b/boards/native/Makefile.features @@ -1,3 +1,5 @@ FEATURES_PROVIDED += transceiver periph_cpuid config cpp FEATURES_PROVIDED += periph_random FEATURES_PROVIDED += periph_rtc +FEATURES_PROVIDED += periph_flash + diff --git a/boards/pca10000/Makefile.features b/boards/pca10000/Makefile.features index 498e6d7eeb20..f4e4c3625fb2 100644 --- a/boards/pca10000/Makefile.features +++ b/boards/pca10000/Makefile.features @@ -1,2 +1,4 @@ FEATURES_PROVIDED += cpp FEATURES_PROVIDED += periph_uart periph_gpio periph_random periph_rtt periph_cpuid +FEATURES_PROVIDED += periph_flash + diff --git a/boards/pca10005/Makefile.features b/boards/pca10005/Makefile.features index 498e6d7eeb20..f4e4c3625fb2 100644 --- a/boards/pca10005/Makefile.features +++ b/boards/pca10005/Makefile.features @@ -1,2 +1,4 @@ FEATURES_PROVIDED += cpp FEATURES_PROVIDED += periph_uart periph_gpio periph_random periph_rtt periph_cpuid +FEATURES_PROVIDED += periph_flash + diff --git a/boards/yunjia-nrf51822/Makefile.features b/boards/yunjia-nrf51822/Makefile.features index 498e6d7eeb20..f4e4c3625fb2 100644 --- a/boards/yunjia-nrf51822/Makefile.features +++ b/boards/yunjia-nrf51822/Makefile.features @@ -1,2 +1,4 @@ FEATURES_PROVIDED += cpp FEATURES_PROVIDED += periph_uart periph_gpio periph_random periph_rtt periph_cpuid +FEATURES_PROVIDED += periph_flash + diff --git a/cpu/native/include/cpu-conf.h b/cpu/native/include/cpu-conf.h index 3cf26d05e66c..67ae5b2ded60 100644 --- a/cpu/native/include/cpu-conf.h +++ b/cpu/native/include/cpu-conf.h @@ -68,6 +68,18 @@ extern "C" { #define CPUID_ID_LEN (4) #endif +/** + * @name CPU Flash configuration (file simulation) + * @{ + */ +#define FLASH_PAGE_SIZE (1024) /**< Page size of flash memory */ +#define FLASH_NUM_PAGES (256) /**< Number of flash pages */ +#define FLASH_START_ADDRESS (0x0) /**< Starting address to calculate end of flash */ +#define FLASH_WRITE_ALIGN (4) /**< number of bytes must be written at once */ +#define FLASH_WRITES_PER_WORD (2) /**< how often a word can overwritten without flash erase */ +#define FLASH_ERASE_CYCLES (20000) /**< Flash erase cycles descibed in datasheet */ +#define FLASH_ERASED_BIT_VALUE (0) /**< Value of erased bits 0|1 */ + #ifdef __cplusplus } #endif diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c new file mode 100644 index 000000000000..56766644f0a3 --- /dev/null +++ b/cpu/native/periph/flash.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2014 Frank Holtz + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * Native CPU periph/flash.h implementation + * + * The implementation emulates flash ROM by allocating RAM + * By using "-F" argument flash content is stored in given file. + * + * @author Frank Holtz + * + * @ingroup _native_cpu + * @defgroup _native_flash + * @file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu-conf.h" +#include "periph/flash.h" + +#include "native_internal.h" + +#define ENABLE_DEBUG (1) +#include "debug.h" + +#define FLASH_ERROR_SIMULATION (1) + +static int _native_flash_initialized = 0; +static int _native_flash_fd; // file descriptor for flash content in file system +static uint8_t _native_flash_content[FLASH_NUM_PAGES * FLASH_PAGE_SIZE]; // simulated flash +extern const char *_native_flash_emulation_file_path; // file path parameter startup.c + +/** + * @brief Check if given address in valid range + * + * @return Error code FLASH_ERROR_SUCCESS or FLASH_ERROR_ADDR_RANGE + */ +static uint8_t flash_check_address(void *address) +{ + if ((address < (void *)&_native_flash_content) + || ((address > (void *)&_native_flash_content[(FLASH_NUM_PAGES * FLASH_PAGE_SIZE) - 1]))) { + return FLASH_ERROR_ADDR_RANGE; + } + + return FLASH_ERROR_SUCCESS; +} + +/** + * @brief store simulated flash content in file + * + * @param[in] page Page number + * + * @return Error code FLASH_ERROR_SUCCESS or FLASH_ERROR_VERIFY + */ +static uint8_t flash_write_page_to_file(flash_page_number_t page, flash_page_number_t num) +{ + // Check range + if (page + num > FLASH_NUM_PAGES) { + DEBUG("Write overrides array boundary\n"); + return FLASH_ERROR_VERIFY; + } + + if (_native_flash_fd >= 0) { + ssize_t numbytes = 0; + + if (lseek(_native_flash_fd, 0, SEEK_END) < page * FLASH_PAGE_SIZE) { + // Write complete array + lseek(_native_flash_fd, 0, SEEK_SET); + numbytes = write(_native_flash_fd, &_native_flash_content[0], FLASH_NUM_PAGES * FLASH_PAGE_SIZE); + } + else { + // Write block + size_t pos = lseek(_native_flash_fd, page * FLASH_PAGE_SIZE, SEEK_SET); + + if (pos == page * FLASH_PAGE_SIZE) { + numbytes = write(_native_flash_fd, &_native_flash_content[FLASH_PAGE_SIZE * page], + num * FLASH_PAGE_SIZE); + } + } + + DEBUG("Write %d bytes to %s\n", numbytes, _native_flash_emulation_file_path); + } + + return FLASH_ERROR_SUCCESS; +} + +uint8_t flash_init(void) +{ + DEBUG("flash_init\n"); + _native_flash_fd = -1; + + // Format flash + for (flash_page_number_t i = 0; i < FLASH_NUM_PAGES; i++) { + flash_erase_page(i); + } + + if (_native_flash_emulation_file_path != NULL) { + _native_flash_fd = open(_native_flash_emulation_file_path, O_RDWR | O_CREAT, 0600); + + if (_native_flash_fd >= 0) { + lseek(_native_flash_fd, 0, SEEK_SET); + ssize_t numbytes = 0; + numbytes = read(_native_flash_fd, _native_flash_content, sizeof(_native_flash_content)); + DEBUG("Read %d bytes from %s\n", numbytes, _native_flash_emulation_file_path); + } + } + + _native_flash_initialized = 1; + DEBUG("Flash emulation initialized.\n"); + return FLASH_ERROR_SUCCESS; +} + +/** + * @brief Translates an address to page number + * + * This function is needed to calculate the page number + * for erase operation + * + * @param[in] address Pointer/Memory address + * @param[out] offset Address location in page + * + * @return Flash page number + */ +flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page_offset) +{ + flash_page_number_t page_number = (flash_page_number_t)(((uint8_t *)address - + &_native_flash_content[0]) / FLASH_PAGE_SIZE); + + if (page_offset != NULL) { + *page_offset = (flash_page_number_t)(((uint8_t *)address - &_native_flash_content[0]) % + FLASH_PAGE_SIZE); + } + + return page_number; +} + +/** + * @brief Translates an page number to pointer + * + * This function is needed to calculate the memory address + * of an flash page + * + * @param[in] page Page number + * + * @return Pointer to page or NULL + */ +void *flash_get_address(flash_page_number_t page) +{ + return (void *)&_native_flash_content[page * FLASH_PAGE_SIZE]; +} + +/** + * @brief Write data to flash + * + * This function works like memcpy. It can be used to write + * a part of a flash page or an single flash page or multiple + * flash pages at once. Written data are reread to check if + * data are stored correctly. + * + * The return code should by checked to handle errors. + * + * @param[in] dest Address of flash memory page + * @param[in] src Address of source data + * @param[in] n Number of bytes to write + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ALIGNMENT + * @return FLASH_ERROR_VERIFY + * @return FLASH_ERROR_ADDR_RANGE + */ +uint8_t flash_memcpy(void *dest, const void *src, size_t n) +{ + // Check alignment +#if FLASH_WRITE_ALIGN > 1 + flash_page_size_t page_offset; + flash_get_page_number(dest, &page_offset); + + if ((n % FLASH_WRITE_ALIGN != 0) || (page_offset % FLASH_WRITE_ALIGN != 0)) { + DEBUG("Unaligned access n=%d offset=%d\n", n, page_offset); + return FLASH_ERROR_ALIGNMENT; + } + +#endif + + uint8_t ret = flash_memcpy_fast(dest, src, n); + return (ret); +} + +/** + * @brief Write data to flash without checks + * + * This function works like memcpy. It can be used to write + * a part of a flash page or an single flash page or multiple + * flash pages at once. + * + * The return code should by checked to handle errors. + * + * @param[in] dest Address of flash memory page + * @param[in] src Address of source data + * @param[in] n Number of bytes to write + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ALIGNMENT + * @return FLASH_ERROR_ADDR_RANGE + */ +uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) +{ + // Check memory range + if ((flash_check_address(dest) > FLASH_ERROR_SUCCESS) + || (flash_check_address((void *)((uint8_t *)dest + n)) > FLASH_ERROR_SUCCESS)) { + return FLASH_ERROR_ADDR_RANGE; + } + + memcpy(dest, src, n); + + // Write to disk + flash_page_size_t page_offset = 0; + flash_page_number_t page_num = flash_get_page_number(dest, &page_offset); + flash_page_number_t num_pages = n / FLASH_PAGE_SIZE; + + if (n % FLASH_PAGE_SIZE > 0) { + num_pages++; + } + + return flash_write_page_to_file(page_num, num_pages); +} + + +/** + * @brief Erase an flash page by page number + * + * @param[in] page Page number + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ADDR_RANGE + */ +uint8_t flash_erase_page(flash_page_number_t page) +{ + // check argument + if (page > FLASH_NUM_PAGES) { + return FLASH_ERROR_ADDR_RANGE; + } + + // erase content + DEBUG("Erase page %d\n", page); + + for (ssize_t i = page * FLASH_PAGE_SIZE; i < ((page + 1) * FLASH_PAGE_SIZE); i++) { +#if FLASH_ERASED_BIT_VALUE == 0 + _native_flash_content[i] = 0; +#else + _native_flash_content[i] = 0xff; +#endif + } + + return (flash_write_page_to_file(page, 1)); +} + +/** + * @brief Erase an flash page by address + * + * @param[in] address Page address + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ADDR_RANGE + */ +uint8_t flash_erase_page_by_address(void *address) +{ + if (flash_check_address(address) > FLASH_ERROR_SUCCESS) { + return FLASH_ERROR_ADDR_RANGE; + } + + flash_page_size_t page_offset; + return (flash_erase_page(flash_get_page_number(address, &page_offset))); +} diff --git a/cpu/native/startup.c b/cpu/native/startup.c index 0d5137a6afcb..df7aa03bdfc4 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -44,6 +44,7 @@ char **_native_argv; pid_t _native_pid; pid_t _native_id; const char *_native_unix_socket_path = NULL; +const char *_native_flash_emulation_file_path = NULL; /** * initialize _native_null_in_pipe to allow for reading from stdin @@ -200,6 +201,12 @@ void usage_exit(void) -r replay missed output when (re-)attaching to socket\n\ (implies -o)\n"); #endif + +#ifdef FEATURE_PERIPH_FLASH + real_printf("\ +-F Path to a file where simulated flash are stored permantenty\n"); +#endif + real_printf("\ -i specify instance id (set by config module)\n\ -d daemonize\n\ @@ -316,6 +323,17 @@ __attribute__((constructor)) static void startup(int argc, char **argv) _native_unix_socket_path = argv[++argp]; } } +#endif +#ifdef FEATURE_PERIPH_FLASH + else if (strcmp("-F", arg) == 0) { + /* parse optional path */ + if ((argp + 1 < argc) && (argv[argp + 1][0] != '-')) { + _native_flash_emulation_file_path = argv[++argp]; + } + else { + usage_exit(); + } + } #endif else { usage_exit(); diff --git a/cpu/nrf51822/include/cpu-conf.h b/cpu/nrf51822/include/cpu-conf.h index 51cbd3bbbd62..d2b4cc2af71d 100644 --- a/cpu/nrf51822/include/cpu-conf.h +++ b/cpu/nrf51822/include/cpu-conf.h @@ -55,6 +55,21 @@ extern "C" { */ #define CPUID_ID_LEN (8) +/** + * @name CPU Flash configuration + * @{ + */ +#define FLASH_PAGE_SIZE (1024) /**< Page size of flash memory */ +#define FLASH_NUM_PAGES (256) /**< Number of flash pages */ +#define FLASH_START_ADDRESS (0x0) /**< Starting address to calculate end of flash */ +#define FLASH_WRITE_ALIGN (4) /**< number of bytes must be written at once */ +#define FLASH_WRITES_PER_WORD (2) /**< how often a word can overwritten without flash erase */ +#define FLASH_ERASE_CYCLES (20000) /**< Flash erase cycles descibed in datasheet */ +#define FLASH_ERASED_BIT_VALUE (1) /**< Value of erased bits 0|1 */ + +/** @} */ + + #ifdef __cplusplus } #endif diff --git a/drivers/include/periph/flash.h b/drivers/include/periph/flash.h new file mode 100644 index 000000000000..344795ec934d --- /dev/null +++ b/drivers/include/periph/flash.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2014 Frank Holtz + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup driver_periph_flash Flash interface + * @ingroup driver_periph + * @brief Low-level access to internal flash + * + * @{ + * @file + * @brief Low-level access to internal flash + * + * @author Frank Holtz + */ + +#ifndef __FLASH_H +#define __FLASH_H + +#include +#include "cpu-conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Available error codes + * + */ +enum flash_errors { + FLASH_ERROR_SUCCESS = 0, /**< Success */ + FLASH_ERROR_BROWNOUT = 1, /**< Voltage to low */ + FLASH_ERROR_FB_CONFIG = 2, /**< Forbidden by MCU configuration/flags */ + FLASH_ERROR_LOCKED = 3, /**< Page or flash is locked by other operation */ + FLASH_ERROR_TIMEOUT = 4, /**< Timeout */ + FLASH_ERROR_ALIGNMENT = 5, /**< Misalligned access */ + FLASH_ERROR_VERIFY = 6, /**< Data not written correctly */ + FLASH_ERROR_ADDR_RANGE = 7, /**< Address out of flash area */ +}; + +/** + * @brief Type definition for page size + * + * This allows page sizes >64k in the future + * + */ +#ifndef FLASH_PAGE_SIZE +#error Flash is not suppored or not implemented for this CPU +#elif FLASH_PAGE_SIZE>=256 +typedef uint16_t flash_page_size_t; +#else +typedef uint8_t flash_page_size_t; +#endif + +/** + * @brief Type definition for page number + * + * This allows more then 64k pages in the future + * + */ +#if FLASH_NUM_PAGES>=256 +typedef uint16_t flash_page_number_t; +#else +typedef uint8_t flash_page_number_t; +#endif + +/** + * @brief Type definition for data word for alignment + */ +#if FLASH_WRITE_ALIGN == 1 +typedef uint8_t flash_data_word_t; +#elif FLASH_WRITE_ALIGN == 2 +typedef uint16_t flash_data_word_t; +#elif FLASH_WRITE_ALIGN == 4 +typedef uint32_t flash_data_word_t; +#elif FLASH_WRITE_ALIGN == 8 +typedef uint64_t flash_data_word_t; +#endif + +/** + * @brief Initialize flash memory access + * + * If needed flash memory initialization can be performed. + * In native mode a file is loaded into memory to simulate + * flash. + * + * @return Error Code + */ +uint8_t flash_init(void); + +/** + * @brief Translates an address to page number + * + * This function is needed to calculate the page number + * for erase operation + * + * @param[in] address Pointer/Memory address + * @param[out] offset Address location in page or NULL + * + * @return Flash page number + */ +flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page_offset); + +/** + * @brief Translates an page number to pointer + * + * This function is needed to calculate the memory address + * of an flash page + * + * @param[in] page Page number + * + * @return Pointer to page or NULL + */ +void *flash_get_address(flash_page_number_t page); + +/** + * @brief Write data to flash + * + * This function works like memcpy. It can be used to write + * a part of a flash page or an single flash page or multiple + * flash pages at once. Written data are reread to check if + * data are stored correctly. Optionally a written word can + * modified to set only changed bits to reach more write cycles. + * + * The return code should by checked to handle errors. + * + * @param[in] dest Address of flash memory page + * @param[in] src Address of source data + * @param[in] n Number of bytes to write + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ALIGNMENT + * @return FLASH_ERROR_VERIFY + * @return FLASH_ERROR_ADDR_RANGE + */ +uint8_t flash_memcpy(void *dest, const void *src, size_t n); + +/** + * @brief Write data to flash without checks + * + * This function works like memcpy. It can be used to write + * a part of a flash page or an single flash page or multiple + * flash pages at once. There are no alignment, address or correct + * write checks, so write to protected flash regions or unaligned + * writes are possible. To support all plattforms do an alignment + * and address check by your application + * This function is used by tests/periph_flash to check if + * alignment is configurd correctly + * + * The return code should by checked to handle errors. + * + * @param[in] dest Address of flash memory page + * @param[in] src Address of source data + * @param[in] n Number of bytes to write + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + */ +uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n); + + +/** + * @brief Erase an flash page by page number + * + * @param[in] page Page number + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ADDR_RANGE + */ +uint8_t flash_erase_page(flash_page_number_t page); + +/** + * @brief Erase an flash page by address + * + * @param[in] address Page address + * + * @return FLASH_ERROR_SUCCESS + * @return FLASH_ERROR_BROWNOUT + * @return FLASH_ERROR_FB_CONFIG + * @return FLASH_ERROR_LOCKED + * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ADDR_RANGE + */ +uint8_t flash_erase_page_by_address(void *address); + +#ifdef __cplusplus +} +#endif + +#endif /* __FLASH_H */ +/** @} */ diff --git a/tests/periph_flash/Makefile b/tests/periph_flash/Makefile new file mode 100644 index 000000000000..8b285d792b73 --- /dev/null +++ b/tests/periph_flash/Makefile @@ -0,0 +1,6 @@ +export APPLICATION = periph_flash +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_flash + +include $(RIOTBASE)/Makefile.include diff --git a/tests/periph_flash/README.md b/tests/periph_flash/README.md new file mode 100644 index 000000000000..a8f93b3161c1 --- /dev/null +++ b/tests/periph_flash/README.md @@ -0,0 +1,4 @@ +Expected result +=============== +This test should be run without errors. With second start "Compare signate with flash OK (0)" must be print out. + diff --git a/tests/periph_flash/main.c b/tests/periph_flash/main.c new file mode 100644 index 000000000000..02a48e6a91c5 --- /dev/null +++ b/tests/periph_flash/main.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 Frank Holtz + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Flash interface test + * + * @author Frank Holtz + * + * @} + */ + +#include +#include + +#include "periph/flash.h" + +uint8_t print_test(char *text, uint32_t return_code, uint32_t error_code) +{ + if ((return_code == error_code) || (error_code == 65535)) { + printf("%s\tOK (%d)\n", text, return_code); + return 0; + } + else { + printf("%s\tError (%d)\n", text, return_code); + return 1; + } +} + +int main(void) +{ + // Signature with space for alignment + char *testsignature = "RIOT-FLASH-TEST\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + int errors = 0, testsignaturelen = strlen(testsignature), counter = 0; + uint8_t *flashpage = flash_get_address(FLASH_NUM_PAGES - 1); + + printf("\nFlash interface test...\nTest\t\t\t\t\tResult (RC)\n---------------------------------------------------\n"); + + errors = errors + print_test("Initializing flash interface\t", flash_init(), FLASH_ERROR_SUCCESS); + errors = errors + print_test("Compare signate with flash\t", memcmp(flashpage, testsignature, + strlen(testsignature)), 65535); + errors = errors + print_test("Erase last flash page\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), + FLASH_ERROR_SUCCESS); + + counter = 0; + + for (flash_page_size_t i = 0; i < FLASH_PAGE_SIZE; i++) { +#if FLASH_ERASED_BIT_VALUE==0 + + if (flashpage[i] == 0x00) { +#else + + if (flashpage[i] == 0xff) { +#endif + counter++; + } + } + + errors = errors + print_test("Number of erased bytes\t\t", counter, FLASH_PAGE_SIZE); + + +#if FLASH_NUM_PAGES != 256 && FLASH_NUM_PAGES != 65536 + errors = errors + print_test("Erase flash page outside\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), + FLASH_ERROR_ADDR_RANGE); +#endif +#if FLASH_WRITE_ALIGN > 1 + + // align len + while (testsignaturelen % FLASH_WRITE_ALIGN > 0) { + testsignaturelen++; + } + + errors = errors + print_test("Write test signature unaligned\t", flash_memcpy(flashpage, + testsignature, testsignaturelen - 1), FLASH_ERROR_ALIGNMENT); +#endif + errors = errors + print_test("Write test signature aligned\t", flash_memcpy(flashpage, + testsignature, testsignaturelen), FLASH_ERROR_SUCCESS); + errors = errors + print_test("Compare signate with flash\t", memcmp(flashpage, testsignature, + testsignaturelen), 0); + + printf("\nDone with %d errors.\n", errors); + + return 0; +} From 6a66b55d0c8ca81751c1fa8c87bb6a4d54225af5 Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sun, 4 Jan 2015 09:28:50 +0100 Subject: [PATCH 02/17] fix doxygen error --- drivers/include/periph/flash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/include/periph/flash.h b/drivers/include/periph/flash.h index 344795ec934d..534ec8c393ac 100644 --- a/drivers/include/periph/flash.h +++ b/drivers/include/periph/flash.h @@ -100,7 +100,7 @@ uint8_t flash_init(void); * for erase operation * * @param[in] address Pointer/Memory address - * @param[out] offset Address location in page or NULL + * @param[out] page_offset Address location in page or NULL * * @return Flash page number */ From ca618f42a6de7b8c89f977729bf2415414ea0cfb Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann Date: Sun, 4 Jan 2015 12:01:23 +0100 Subject: [PATCH 03/17] general review of native parts missing bits and pieces, spelling, etc --- cpu/native/include/cpu-conf.h | 15 +++--- cpu/native/include/native_internal.h | 3 ++ cpu/native/native_cpu.c | 5 ++ cpu/native/periph/flash.c | 73 +++++++++++++++++----------- cpu/native/startup.c | 4 +- cpu/native/syscalls.c | 2 + 6 files changed, 64 insertions(+), 38 deletions(-) diff --git a/cpu/native/include/cpu-conf.h b/cpu/native/include/cpu-conf.h index 67ae5b2ded60..994bd95338a9 100644 --- a/cpu/native/include/cpu-conf.h +++ b/cpu/native/include/cpu-conf.h @@ -72,13 +72,14 @@ extern "C" { * @name CPU Flash configuration (file simulation) * @{ */ -#define FLASH_PAGE_SIZE (1024) /**< Page size of flash memory */ -#define FLASH_NUM_PAGES (256) /**< Number of flash pages */ -#define FLASH_START_ADDRESS (0x0) /**< Starting address to calculate end of flash */ -#define FLASH_WRITE_ALIGN (4) /**< number of bytes must be written at once */ -#define FLASH_WRITES_PER_WORD (2) /**< how often a word can overwritten without flash erase */ -#define FLASH_ERASE_CYCLES (20000) /**< Flash erase cycles descibed in datasheet */ -#define FLASH_ERASED_BIT_VALUE (0) /**< Value of erased bits 0|1 */ +#define FLASH_PAGE_SIZE (1024) /**< Page size of flash memory */ +#define FLASH_NUM_PAGES (256) /**< Number of flash pages */ +#define FLASH_START_ADDRESS (0x0) /**< Starting address to calculate end of flash */ +#define FLASH_WRITE_ALIGN (4) /**< number of bytes must be written at once */ +#define FLASH_WRITES_PER_WORD (2) /**< how often a word can overwritten without flash erase */ +#define FLASH_ERASE_CYCLES (20000) /**< Flash erase cycles described in datasheet */ +#define FLASH_ERASED_BIT_VALUE (0) /**< Value of erased bits 0|1 */ +/* @} */ #ifdef __cplusplus } diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h index b784de8b26ae..72f49b0a4ced 100644 --- a/cpu/native/include/native_internal.h +++ b/cpu/native/include/native_internal.h @@ -119,6 +119,7 @@ extern int (*real_unlink)(const char *); extern long int (*real_random)(void); extern const char* (*real_gai_strerror)(int errcode); extern FILE* (*real_fopen)(const char *path, const char *mode); +extern off_t (*real_lseek)(int fd, off_t offset, int whence); #ifdef __MACH__ #else @@ -146,6 +147,8 @@ extern char **_native_argv; extern pid_t _native_pid; extern pid_t _native_id; extern const char *_native_unix_socket_path; +extern const char *_native_flash_emulation_file_path; +extern int _native_flash_fd; #ifdef MODULE_UART0 #include diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c index 5548f0af1579..e6ab07d7c5ce 100644 --- a/cpu/native/native_cpu.c +++ b/cpu/native/native_cpu.c @@ -77,6 +77,11 @@ int reboot_arch(int mode) real_close(_native_tap_fd); } #endif +#ifdef FEATURE_PERIPH_FLASH + if (_native_flash_fd != -1) { + real_close(_native_flash_fd); + } +#endif if (real_execve(_native_argv[0], _native_argv, NULL) == -1) { err(EXIT_FAILURE, "reboot: execve"); diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c index 56766644f0a3..1a0af5c04490 100644 --- a/cpu/native/periph/flash.c +++ b/cpu/native/periph/flash.c @@ -9,8 +9,9 @@ /** * Native CPU periph/flash.h implementation * - * The implementation emulates flash ROM by allocating RAM - * By using "-F" argument flash content is stored in given file. + * The implementation emulates flash ROM by allocating RAM. + * When using the "-f" argument, flash contents are synchronized to a + * given file. * * @author Frank Holtz * @@ -35,15 +36,16 @@ #include "native_internal.h" -#define ENABLE_DEBUG (1) +#define ENABLE_DEBUG (0) #include "debug.h" #define FLASH_ERROR_SIMULATION (1) static int _native_flash_initialized = 0; -static int _native_flash_fd; // file descriptor for flash content in file system -static uint8_t _native_flash_content[FLASH_NUM_PAGES * FLASH_PAGE_SIZE]; // simulated flash -extern const char *_native_flash_emulation_file_path; // file path parameter startup.c +/* file descriptor for flash content in file system */ +int _native_flash_fd; +/* simulated flash */ +static uint8_t _native_flash_content[FLASH_NUM_PAGES * FLASH_PAGE_SIZE]; /** * @brief Check if given address in valid range @@ -69,7 +71,7 @@ static uint8_t flash_check_address(void *address) */ static uint8_t flash_write_page_to_file(flash_page_number_t page, flash_page_number_t num) { - // Check range + /* Check range */ if (page + num > FLASH_NUM_PAGES) { DEBUG("Write overrides array boundary\n"); return FLASH_ERROR_VERIFY; @@ -78,21 +80,29 @@ static uint8_t flash_write_page_to_file(flash_page_number_t page, flash_page_num if (_native_flash_fd >= 0) { ssize_t numbytes = 0; - if (lseek(_native_flash_fd, 0, SEEK_END) < page * FLASH_PAGE_SIZE) { - // Write complete array - lseek(_native_flash_fd, 0, SEEK_SET); - numbytes = write(_native_flash_fd, &_native_flash_content[0], FLASH_NUM_PAGES * FLASH_PAGE_SIZE); + _native_syscall_enter(); + + if (real_lseek(_native_flash_fd, 0, SEEK_END) < page * FLASH_PAGE_SIZE) { + /* Write complete array */ + real_lseek(_native_flash_fd, 0, SEEK_SET); + numbytes = real_write(_native_flash_fd, + &_native_flash_content[0], + FLASH_NUM_PAGES * FLASH_PAGE_SIZE); } else { - // Write block - size_t pos = lseek(_native_flash_fd, page * FLASH_PAGE_SIZE, SEEK_SET); + /* Write block */ + size_t pos = real_lseek(_native_flash_fd, + page * FLASH_PAGE_SIZE, SEEK_SET); if (pos == page * FLASH_PAGE_SIZE) { - numbytes = write(_native_flash_fd, &_native_flash_content[FLASH_PAGE_SIZE * page], - num * FLASH_PAGE_SIZE); + numbytes = real_write(_native_flash_fd, + &_native_flash_content[FLASH_PAGE_SIZE * page], + num * FLASH_PAGE_SIZE); } } + _native_syscall_leave(); + DEBUG("Write %d bytes to %s\n", numbytes, _native_flash_emulation_file_path); } @@ -104,20 +114,26 @@ uint8_t flash_init(void) DEBUG("flash_init\n"); _native_flash_fd = -1; - // Format flash + /* Format flash */ + /* TODO: move below to else in case no file is associated */ for (flash_page_number_t i = 0; i < FLASH_NUM_PAGES; i++) { flash_erase_page(i); } if (_native_flash_emulation_file_path != NULL) { - _native_flash_fd = open(_native_flash_emulation_file_path, O_RDWR | O_CREAT, 0600); + + _native_syscall_enter(); + _native_flash_fd = real_open(_native_flash_emulation_file_path, O_RDWR | O_CREAT, 0600); if (_native_flash_fd >= 0) { - lseek(_native_flash_fd, 0, SEEK_SET); - ssize_t numbytes = 0; - numbytes = read(_native_flash_fd, _native_flash_content, sizeof(_native_flash_content)); + real_lseek(_native_flash_fd, 0, SEEK_SET); + /* TODO: check numbytes, could be lower than requested */ + ssize_t numbytes = real_read(_native_flash_fd, _native_flash_content, + sizeof(_native_flash_content)); DEBUG("Read %d bytes from %s\n", numbytes, _native_flash_emulation_file_path); } + + _native_syscall_leave(); } _native_flash_initialized = 1; @@ -142,8 +158,9 @@ flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page &_native_flash_content[0]) / FLASH_PAGE_SIZE); if (page_offset != NULL) { - *page_offset = (flash_page_number_t)(((uint8_t *)address - &_native_flash_content[0]) % - FLASH_PAGE_SIZE); + *page_offset = (flash_page_number_t) ( + ((uint8_t *)address - &_native_flash_content[0]) + % FLASH_PAGE_SIZE); } return page_number; @@ -189,7 +206,7 @@ void *flash_get_address(flash_page_number_t page) */ uint8_t flash_memcpy(void *dest, const void *src, size_t n) { - // Check alignment + /* Check alignment */ #if FLASH_WRITE_ALIGN > 1 flash_page_size_t page_offset; flash_get_page_number(dest, &page_offset); @@ -198,7 +215,6 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) DEBUG("Unaligned access n=%d offset=%d\n", n, page_offset); return FLASH_ERROR_ALIGNMENT; } - #endif uint8_t ret = flash_memcpy_fast(dest, src, n); @@ -228,7 +244,7 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) */ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) { - // Check memory range + /* Check memory range */ if ((flash_check_address(dest) > FLASH_ERROR_SUCCESS) || (flash_check_address((void *)((uint8_t *)dest + n)) > FLASH_ERROR_SUCCESS)) { return FLASH_ERROR_ADDR_RANGE; @@ -236,7 +252,7 @@ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) memcpy(dest, src, n); - // Write to disk + /* Write to disk */ flash_page_size_t page_offset = 0; flash_page_number_t page_num = flash_get_page_number(dest, &page_offset); flash_page_number_t num_pages = n / FLASH_PAGE_SIZE; @@ -248,7 +264,6 @@ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) return flash_write_page_to_file(page_num, num_pages); } - /** * @brief Erase an flash page by page number * @@ -263,12 +278,12 @@ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) */ uint8_t flash_erase_page(flash_page_number_t page) { - // check argument + /* check argument */ if (page > FLASH_NUM_PAGES) { return FLASH_ERROR_ADDR_RANGE; } - // erase content + /* erase content */ DEBUG("Erase page %d\n", page); for (ssize_t i = page * FLASH_PAGE_SIZE; i < ((page + 1) * FLASH_PAGE_SIZE); i++) { diff --git a/cpu/native/startup.c b/cpu/native/startup.c index df7aa03bdfc4..98fc6d357254 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -204,7 +204,7 @@ void usage_exit(void) #ifdef FEATURE_PERIPH_FLASH real_printf("\ --F Path to a file where simulated flash are stored permantenty\n"); +-f Path to a file where simulated flash is stored permanently\n"); #endif real_printf("\ @@ -325,7 +325,7 @@ __attribute__((constructor)) static void startup(int argc, char **argv) } #endif #ifdef FEATURE_PERIPH_FLASH - else if (strcmp("-F", arg) == 0) { + else if (strcmp("-f", arg) == 0) { /* parse optional path */ if ((argp + 1 < argc) && (argv[argp + 1][0] != '-')) { _native_flash_emulation_file_path = argv[++argp]; diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c index f0587ce15055..b8d72374d6a8 100644 --- a/cpu/native/syscalls.c +++ b/cpu/native/syscalls.c @@ -87,6 +87,7 @@ int (*real_unlink)(const char *); long int (*real_random)(void); const char* (*real_gai_strerror)(int errcode); FILE* (*real_fopen)(const char *path, const char *mode); +off_t (*real_lseek)(int fd, off_t offset, int whence); #ifdef __MACH__ #else @@ -412,6 +413,7 @@ void _native_init_syscalls(void) *(void **)(&real_feof) = dlsym(RTLD_NEXT, "feof"); *(void **)(&real_ferror) = dlsym(RTLD_NEXT, "ferror"); *(void **)(&real_clearerr) = dlsym(RTLD_NEXT, "clearerr"); + *(void **)(&real_lseek) = dlsym(RTLD_NEXT, "lseek"); #ifdef __MACH__ #else *(void **)(&real_clock_gettime) = dlsym(RTLD_NEXT, "clock_gettime"); From 0068cb27cb0d1a1877b7f724d95927222ffdc75b Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann Date: Sun, 4 Jan 2015 12:07:14 +0100 Subject: [PATCH 04/17] native/flash: remove duplicated API --- cpu/native/periph/flash.c | 89 --------------------------------------- 1 file changed, 89 deletions(-) diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c index 1a0af5c04490..1d32c16cb7ec 100644 --- a/cpu/native/periph/flash.c +++ b/cpu/native/periph/flash.c @@ -141,17 +141,6 @@ uint8_t flash_init(void) return FLASH_ERROR_SUCCESS; } -/** - * @brief Translates an address to page number - * - * This function is needed to calculate the page number - * for erase operation - * - * @param[in] address Pointer/Memory address - * @param[out] offset Address location in page - * - * @return Flash page number - */ flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page_offset) { flash_page_number_t page_number = (flash_page_number_t)(((uint8_t *)address - @@ -166,44 +155,11 @@ flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page return page_number; } -/** - * @brief Translates an page number to pointer - * - * This function is needed to calculate the memory address - * of an flash page - * - * @param[in] page Page number - * - * @return Pointer to page or NULL - */ void *flash_get_address(flash_page_number_t page) { return (void *)&_native_flash_content[page * FLASH_PAGE_SIZE]; } -/** - * @brief Write data to flash - * - * This function works like memcpy. It can be used to write - * a part of a flash page or an single flash page or multiple - * flash pages at once. Written data are reread to check if - * data are stored correctly. - * - * The return code should by checked to handle errors. - * - * @param[in] dest Address of flash memory page - * @param[in] src Address of source data - * @param[in] n Number of bytes to write - * - * @return FLASH_ERROR_SUCCESS - * @return FLASH_ERROR_BROWNOUT - * @return FLASH_ERROR_FB_CONFIG - * @return FLASH_ERROR_LOCKED - * @return FLASH_ERROR_TIMEOUT - * @return FLASH_ERROR_ALIGNMENT - * @return FLASH_ERROR_VERIFY - * @return FLASH_ERROR_ADDR_RANGE - */ uint8_t flash_memcpy(void *dest, const void *src, size_t n) { /* Check alignment */ @@ -221,27 +177,6 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) return (ret); } -/** - * @brief Write data to flash without checks - * - * This function works like memcpy. It can be used to write - * a part of a flash page or an single flash page or multiple - * flash pages at once. - * - * The return code should by checked to handle errors. - * - * @param[in] dest Address of flash memory page - * @param[in] src Address of source data - * @param[in] n Number of bytes to write - * - * @return FLASH_ERROR_SUCCESS - * @return FLASH_ERROR_BROWNOUT - * @return FLASH_ERROR_FB_CONFIG - * @return FLASH_ERROR_LOCKED - * @return FLASH_ERROR_TIMEOUT - * @return FLASH_ERROR_ALIGNMENT - * @return FLASH_ERROR_ADDR_RANGE - */ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) { /* Check memory range */ @@ -264,18 +199,6 @@ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) return flash_write_page_to_file(page_num, num_pages); } -/** - * @brief Erase an flash page by page number - * - * @param[in] page Page number - * - * @return FLASH_ERROR_SUCCESS - * @return FLASH_ERROR_BROWNOUT - * @return FLASH_ERROR_FB_CONFIG - * @return FLASH_ERROR_LOCKED - * @return FLASH_ERROR_TIMEOUT - * @return FLASH_ERROR_ADDR_RANGE - */ uint8_t flash_erase_page(flash_page_number_t page) { /* check argument */ @@ -297,18 +220,6 @@ uint8_t flash_erase_page(flash_page_number_t page) return (flash_write_page_to_file(page, 1)); } -/** - * @brief Erase an flash page by address - * - * @param[in] address Page address - * - * @return FLASH_ERROR_SUCCESS - * @return FLASH_ERROR_BROWNOUT - * @return FLASH_ERROR_FB_CONFIG - * @return FLASH_ERROR_LOCKED - * @return FLASH_ERROR_TIMEOUT - * @return FLASH_ERROR_ADDR_RANGE - */ uint8_t flash_erase_page_by_address(void *address) { if (flash_check_address(address) > FLASH_ERROR_SUCCESS) { From 5e0e305485a560b9af52d4e17163f56d28086115 Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann Date: Sun, 4 Jan 2015 18:16:57 +0100 Subject: [PATCH 05/17] cpu/native: use mmap for periph/flash --- cpu/native/include/native_internal.h | 9 +- cpu/native/lpm_cpu.c | 10 ++ cpu/native/native_cpu.c | 2 + cpu/native/periph/flash.c | 214 ++++++++++++++------------- cpu/native/startup.c | 7 +- cpu/native/syscalls.c | 5 + 6 files changed, 141 insertions(+), 106 deletions(-) diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h index 72f49b0a4ced..30b70323c3b6 100644 --- a/cpu/native/include/native_internal.h +++ b/cpu/native/include/native_internal.h @@ -64,6 +64,7 @@ typedef void (*_native_callback_t)(void); void native_cpu_init(void); void native_interrupt_init(void); extern void native_hwtimer_pre_init(void); +void _native_flash_init(void); void native_irq_handler(void); extern void _native_sig_leave_tramp(void); @@ -84,6 +85,8 @@ extern void (*real_free)(void *ptr); extern void* (*real_calloc)(size_t nmemb, size_t size); extern void* (*real_malloc)(size_t size); extern void* (*real_realloc)(void *ptr, size_t size); +extern void* (*real_mmap)(void *addr, size_t length, int prot, int flags, + int fd, off_t offset); extern void (*real_freeaddrinfo)(struct addrinfo *res); extern void (*real_freeifaddrs)(struct ifaddrs *ifa); extern void (*real_srandom)(unsigned int seed); @@ -105,6 +108,7 @@ extern int (*real_getifaddrs)(struct ifaddrs **ifap); extern int (*real_getpid)(void); extern int (*real_ioctl)(int fildes, int request, ...); extern int (*real_listen)(int socket, int backlog); +extern int (*real_munmap)(void *addr, size_t length); extern int (*real_open)(const char *path, int oflag, ...); extern int (*real_pause)(void); extern int (*real_pipe)(int[2]); @@ -147,8 +151,11 @@ extern char **_native_argv; extern pid_t _native_pid; extern pid_t _native_id; extern const char *_native_unix_socket_path; -extern const char *_native_flash_emulation_file_path; + +extern const char *_native_flash_path; +extern uint8_t *_native_flash_memory; extern int _native_flash_fd; +extern size_t _native_flash_size; #ifdef MODULE_UART0 #include diff --git a/cpu/native/lpm_cpu.c b/cpu/native/lpm_cpu.c index 3ac45213aa27..fdd43b501d23 100644 --- a/cpu/native/lpm_cpu.c +++ b/cpu/native/lpm_cpu.c @@ -24,6 +24,9 @@ #include #endif #include +#ifdef FEATURE_PERIPH_FLASH +#include +#endif #include "lpm.h" #include "debug.h" @@ -129,6 +132,13 @@ enum lpm_mode lpm_set(enum lpm_mode target) case LPM_OFF: printf("lpm_set(): exit()\n"); +#ifdef FEATURE_PERIPH_FLASH + if (_native_flash_fd != -1) { + /* casting to discard volatile */ + real_munmap((void *)_native_flash_memory, _native_flash_size); + real_close(_native_flash_fd); + } +#endif real_exit(EXIT_SUCCESS); default: diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c index e6ab07d7c5ce..e98824fe3e22 100644 --- a/cpu/native/native_cpu.c +++ b/cpu/native/native_cpu.c @@ -40,6 +40,7 @@ #endif #include +#include #include "kernel_internal.h" #include "kernel.h" @@ -79,6 +80,7 @@ int reboot_arch(int mode) #endif #ifdef FEATURE_PERIPH_FLASH if (_native_flash_fd != -1) { + real_munmap(_native_flash_memory, _native_flash_size); real_close(_native_flash_fd); } #endif diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c index 1d32c16cb7ec..1a06beb12cc4 100644 --- a/cpu/native/periph/flash.c +++ b/cpu/native/periph/flash.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Frank Holtz + * Copyright (C) 2014 Ludwig Ortmann * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -14,6 +15,7 @@ * given file. * * @author Frank Holtz + * @author Ludwig Ortmann * * @ingroup _native_cpu * @defgroup _native_flash @@ -25,11 +27,11 @@ #include #include #include -#include #include #include -#include #include +#include +#include #include "cpu-conf.h" #include "periph/flash.h" @@ -39,116 +41,48 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#define FLASH_ERROR_SIMULATION (1) +int _native_flash_fd = -1; +uint8_t *_native_flash_memory = NULL; +size_t _native_flash_size = (FLASH_NUM_PAGES * FLASH_PAGE_SIZE); + -static int _native_flash_initialized = 0; -/* file descriptor for flash content in file system */ -int _native_flash_fd; -/* simulated flash */ -static uint8_t _native_flash_content[FLASH_NUM_PAGES * FLASH_PAGE_SIZE]; +/************************************************************************/ +/* internal API *********************************************************/ +/************************************************************************/ /** * @brief Check if given address in valid range * - * @return Error code FLASH_ERROR_SUCCESS or FLASH_ERROR_ADDR_RANGE + * @return Error code FLASH_ERROR_SUCCESS or FLASH_ERROR_ADDR_RANGE */ -static uint8_t flash_check_address(void *address) +static uint8_t flash_check_address(uint8_t *address) { - if ((address < (void *)&_native_flash_content) - || ((address > (void *)&_native_flash_content[(FLASH_NUM_PAGES * FLASH_PAGE_SIZE) - 1]))) { + if ((address < _native_flash_memory) + || ((address >= _native_flash_memory+_native_flash_size))) { return FLASH_ERROR_ADDR_RANGE; } return FLASH_ERROR_SUCCESS; } -/** - * @brief store simulated flash content in file - * - * @param[in] page Page number - * - * @return Error code FLASH_ERROR_SUCCESS or FLASH_ERROR_VERIFY - */ -static uint8_t flash_write_page_to_file(flash_page_number_t page, flash_page_number_t num) -{ - /* Check range */ - if (page + num > FLASH_NUM_PAGES) { - DEBUG("Write overrides array boundary\n"); - return FLASH_ERROR_VERIFY; - } - - if (_native_flash_fd >= 0) { - ssize_t numbytes = 0; - - _native_syscall_enter(); - - if (real_lseek(_native_flash_fd, 0, SEEK_END) < page * FLASH_PAGE_SIZE) { - /* Write complete array */ - real_lseek(_native_flash_fd, 0, SEEK_SET); - numbytes = real_write(_native_flash_fd, - &_native_flash_content[0], - FLASH_NUM_PAGES * FLASH_PAGE_SIZE); - } - else { - /* Write block */ - size_t pos = real_lseek(_native_flash_fd, - page * FLASH_PAGE_SIZE, SEEK_SET); - - if (pos == page * FLASH_PAGE_SIZE) { - numbytes = real_write(_native_flash_fd, - &_native_flash_content[FLASH_PAGE_SIZE * page], - num * FLASH_PAGE_SIZE); - } - } - - _native_syscall_leave(); - - DEBUG("Write %d bytes to %s\n", numbytes, _native_flash_emulation_file_path); - } - - return FLASH_ERROR_SUCCESS; -} +/************************************************************************/ +/* periph/flash.h *******************************************************/ +/************************************************************************/ uint8_t flash_init(void) { - DEBUG("flash_init\n"); - _native_flash_fd = -1; - - /* Format flash */ - /* TODO: move below to else in case no file is associated */ - for (flash_page_number_t i = 0; i < FLASH_NUM_PAGES; i++) { - flash_erase_page(i); - } - - if (_native_flash_emulation_file_path != NULL) { - - _native_syscall_enter(); - _native_flash_fd = real_open(_native_flash_emulation_file_path, O_RDWR | O_CREAT, 0600); - - if (_native_flash_fd >= 0) { - real_lseek(_native_flash_fd, 0, SEEK_SET); - /* TODO: check numbytes, could be lower than requested */ - ssize_t numbytes = real_read(_native_flash_fd, _native_flash_content, - sizeof(_native_flash_content)); - DEBUG("Read %d bytes from %s\n", numbytes, _native_flash_emulation_file_path); - } - - _native_syscall_leave(); - } - - _native_flash_initialized = 1; - DEBUG("Flash emulation initialized.\n"); + DEBUG("flash initialized\n"); return FLASH_ERROR_SUCCESS; } flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page_offset) { flash_page_number_t page_number = (flash_page_number_t)(((uint8_t *)address - - &_native_flash_content[0]) / FLASH_PAGE_SIZE); + &_native_flash_memory[0]) / FLASH_PAGE_SIZE); if (page_offset != NULL) { *page_offset = (flash_page_number_t) ( - ((uint8_t *)address - &_native_flash_content[0]) + ((uint8_t *)address - &_native_flash_memory[0]) % FLASH_PAGE_SIZE); } @@ -157,7 +91,7 @@ flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page void *flash_get_address(flash_page_number_t page) { - return (void *)&_native_flash_content[page * FLASH_PAGE_SIZE]; + return ((void *) (_native_flash_memory + (page * FLASH_PAGE_SIZE))); } uint8_t flash_memcpy(void *dest, const void *src, size_t n) @@ -180,23 +114,18 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) { /* Check memory range */ - if ((flash_check_address(dest) > FLASH_ERROR_SUCCESS) - || (flash_check_address((void *)((uint8_t *)dest + n)) > FLASH_ERROR_SUCCESS)) { + if (flash_check_address((uint8_t *) dest) > FLASH_ERROR_SUCCESS) { + DEBUG("attempted to write below first address\n"); + return FLASH_ERROR_ADDR_RANGE; + } + if (flash_check_address((((uint8_t *) dest) + n)) > FLASH_ERROR_SUCCESS) { + DEBUG("attemted to write beyond last address\n"); return FLASH_ERROR_ADDR_RANGE; } memcpy(dest, src, n); - /* Write to disk */ - flash_page_size_t page_offset = 0; - flash_page_number_t page_num = flash_get_page_number(dest, &page_offset); - flash_page_number_t num_pages = n / FLASH_PAGE_SIZE; - - if (n % FLASH_PAGE_SIZE > 0) { - num_pages++; - } - - return flash_write_page_to_file(page_num, num_pages); + return FLASH_ERROR_SUCCESS; } uint8_t flash_erase_page(flash_page_number_t page) @@ -211,13 +140,13 @@ uint8_t flash_erase_page(flash_page_number_t page) for (ssize_t i = page * FLASH_PAGE_SIZE; i < ((page + 1) * FLASH_PAGE_SIZE); i++) { #if FLASH_ERASED_BIT_VALUE == 0 - _native_flash_content[i] = 0; + _native_flash_memory[i] = 0; #else - _native_flash_content[i] = 0xff; + _native_flash_memory[i] = 0xff; #endif } - return (flash_write_page_to_file(page, 1)); + return FLASH_ERROR_SUCCESS; } uint8_t flash_erase_page_by_address(void *address) @@ -229,3 +158,82 @@ uint8_t flash_erase_page_by_address(void *address) flash_page_size_t page_offset; return (flash_erase_page(flash_get_page_number(address, &page_offset))); } + +/************************************************************************/ +/* native internal API **************************************************/ +/************************************************************************/ + +void _native_flash_init(void) +{ + DEBUG("_native_flash_init\n"); + off_t init_start = 0, init_length = _native_flash_size; + + /* open and mmap file to memory if path given, malloc otherwise */ + if (_native_flash_path != NULL) { + DEBUG("_native_flash_init: opening file\n"); + _native_syscall_enter(); + + /* try to open [existing] file */ + if ((_native_flash_fd = real_open(_native_flash_path, + O_RDWR | O_CREAT, 0600)) == -1) { + err(EXIT_FAILURE, "_native_flash_init: open"); + } + + /* make sure the file is large enough and adjust boundaries + * for initialization */ + size_t size = 0; + char buf[100]; + int ret; + + for (ret = 0; (ret = read(_native_flash_fd, buf, sizeof(buf))) > 0;) { + size += ret; + } + + if (ret == -1) { + err(EXIT_FAILURE, "_native_flash_init: read"); + } + + init_start = size; + if (size < _native_flash_size) { + init_length = _native_flash_size - size; + if (real_lseek(_native_flash_fd, _native_flash_size - 1, + SEEK_SET) == -1) { + err(EXIT_FAILURE, "_native_flash_init: lseek"); + } + + if (real_write(_native_flash_fd, "", 1) != 1) { + err(EXIT_FAILURE, "_native_flash_init: write"); + } + } + else { + init_length = 0; + } + + /* try to map file into memory */ + if ((_native_flash_memory = real_mmap(NULL, _native_flash_size, + PROT_READ|PROT_WRITE, MAP_SHARED, _native_flash_fd, 0) + ) == MAP_FAILED) { + err(EXIT_FAILURE, "_native_flash_init: mmap"); + } + + DEBUG("_native_flash_init: using file %s\n", _native_flash_path); + + _native_syscall_leave(); + } + else { + DEBUG("_native_flash_init: allocating memory\n"); + _native_syscall_enter(); + + /* try and allocate memory */ + if ((_native_flash_memory = real_malloc(_native_flash_size)) == NULL) { + err(EXIT_FAILURE, "_native_flash_init: malloc"); + } + + _native_syscall_leave(); + DEBUG("_native_flash_init: using memory %p\n", _native_flash_memory); + } + + /* initialize [remaining] memory area */ + memset((void *)(_native_flash_memory + init_start), FLASH_ERASED_BIT_VALUE, + init_length); +} diff --git a/cpu/native/startup.c b/cpu/native/startup.c index 98fc6d357254..b9a0cedaf78b 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -44,7 +44,7 @@ char **_native_argv; pid_t _native_pid; pid_t _native_id; const char *_native_unix_socket_path = NULL; -const char *_native_flash_emulation_file_path = NULL; +const char *_native_flash_path = NULL; /** * initialize _native_null_in_pipe to allow for reading from stdin @@ -328,7 +328,7 @@ __attribute__((constructor)) static void startup(int argc, char **argv) else if (strcmp("-f", arg) == 0) { /* parse optional path */ if ((argp + 1 < argc) && (argv[argp + 1][0] != '-')) { - _native_flash_emulation_file_path = argv[++argp]; + _native_flash_path = argv[++argp]; } else { usage_exit(); @@ -358,6 +358,9 @@ __attribute__((constructor)) static void startup(int argc, char **argv) #ifdef MODULE_NATIVENET tap_init(argv[1]); #endif +#ifdef FEATURE_PERIPH_FLASH + _native_flash_init(); +#endif board_init(); diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c index b8d72374d6a8..f524875682cd 100644 --- a/cpu/native/syscalls.c +++ b/cpu/native/syscalls.c @@ -57,6 +57,8 @@ void (*real_free)(void *ptr); void* (*real_malloc)(size_t size); void* (*real_calloc)(size_t nmemb, size_t size); void* (*real_realloc)(void *ptr, size_t size); +void* (*real_mmap)(void *addr, size_t length, int prot, int flags, + int fd, off_t offset); void (*real_freeaddrinfo)(struct addrinfo *res); void (*real_freeifaddrs)(struct ifaddrs *ifa); void (*real_srandom)(unsigned int seed); @@ -75,6 +77,7 @@ int (*real_feof)(FILE *stream); int (*real_ferror)(FILE *stream); int (*real_listen)(int socket, int backlog); int (*real_ioctl)(int fildes, int request, ...); +int (*real_munmap)(void *addr, size_t length); int (*real_open)(const char *path, int oflag, ...); int (*real_pause)(void); int (*real_pipe)(int[2]); @@ -406,6 +409,8 @@ void _native_init_syscalls(void) *(void **)(&real_execve) = dlsym(RTLD_NEXT, "execve"); *(void **)(&real_ioctl) = dlsym(RTLD_NEXT, "ioctl"); *(void **)(&real_listen) = dlsym(RTLD_NEXT, "listen"); + *(void **)(&real_mmap) = dlsym(RTLD_NEXT, "mmap"); + *(void **)(&real_munmap) = dlsym(RTLD_NEXT, "munmap"); *(void **)(&real_open) = dlsym(RTLD_NEXT, "open"); *(void **)(&real_pause) = dlsym(RTLD_NEXT, "pause"); *(void **)(&real_fopen) = dlsym(RTLD_NEXT, "fopen"); From 08d5847dc1b5045120dc650c25f1113b306e6c03 Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann Date: Sun, 4 Jan 2015 18:53:19 +0100 Subject: [PATCH 06/17] cpu/native: make flash volatile --- cpu/native/include/native_internal.h | 2 +- cpu/native/native_cpu.c | 3 ++- cpu/native/periph/flash.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h index 30b70323c3b6..1fbdeb0056fc 100644 --- a/cpu/native/include/native_internal.h +++ b/cpu/native/include/native_internal.h @@ -153,7 +153,7 @@ extern pid_t _native_id; extern const char *_native_unix_socket_path; extern const char *_native_flash_path; -extern uint8_t *_native_flash_memory; +extern volatile uint8_t *_native_flash_memory; extern int _native_flash_fd; extern size_t _native_flash_size; diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c index e98824fe3e22..ba197986fcfc 100644 --- a/cpu/native/native_cpu.c +++ b/cpu/native/native_cpu.c @@ -80,7 +80,8 @@ int reboot_arch(int mode) #endif #ifdef FEATURE_PERIPH_FLASH if (_native_flash_fd != -1) { - real_munmap(_native_flash_memory, _native_flash_size); + /* casting to discard volatile */ + real_munmap((void *)_native_flash_memory, _native_flash_size); real_close(_native_flash_fd); } #endif diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c index 1a06beb12cc4..7177706aad74 100644 --- a/cpu/native/periph/flash.c +++ b/cpu/native/periph/flash.c @@ -42,7 +42,7 @@ #include "debug.h" int _native_flash_fd = -1; -uint8_t *_native_flash_memory = NULL; +volatile uint8_t *_native_flash_memory = NULL; size_t _native_flash_size = (FLASH_NUM_PAGES * FLASH_PAGE_SIZE); From 9706d25bdd7888cec8d7b2f53e0630e99b324e47 Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann Date: Sun, 4 Jan 2015 21:16:08 +0100 Subject: [PATCH 07/17] cpu/native: clean up flash macro definitions --- cpu/native/include/cpu-conf.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/cpu/native/include/cpu-conf.h b/cpu/native/include/cpu-conf.h index 994bd95338a9..295474a59b96 100644 --- a/cpu/native/include/cpu-conf.h +++ b/cpu/native/include/cpu-conf.h @@ -69,16 +69,13 @@ extern "C" { #endif /** - * @name CPU Flash configuration (file simulation) + * @name CPU Flash configuration * @{ */ -#define FLASH_PAGE_SIZE (1024) /**< Page size of flash memory */ -#define FLASH_NUM_PAGES (256) /**< Number of flash pages */ -#define FLASH_START_ADDRESS (0x0) /**< Starting address to calculate end of flash */ -#define FLASH_WRITE_ALIGN (4) /**< number of bytes must be written at once */ -#define FLASH_WRITES_PER_WORD (2) /**< how often a word can overwritten without flash erase */ -#define FLASH_ERASE_CYCLES (20000) /**< Flash erase cycles described in datasheet */ -#define FLASH_ERASED_BIT_VALUE (0) /**< Value of erased bits 0|1 */ +#define FLASH_PAGE_SIZE (1024) /**< page size of flash memory */ +#define FLASH_NUM_PAGES (256) /**< number of flash pages */ +#define FLASH_WRITE_ALIGN (4) /**< number of bytes which must be written at once */ +#define FLASH_ERASED_BIT_VALUE (0x00) /**< value of erased bits */ /* @} */ #ifdef __cplusplus From 6c7c5bb668f09aa143fd911abf1cc77a2f93d19c Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Mon, 5 Jan 2015 19:08:21 +0100 Subject: [PATCH 08/17] ERASED_BIT_VALUE -> ERASED_WORD_VALUE --- cpu/native/include/cpu-conf.h | 2 +- cpu/native/periph/flash.c | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cpu/native/include/cpu-conf.h b/cpu/native/include/cpu-conf.h index 295474a59b96..fcdf311b8263 100644 --- a/cpu/native/include/cpu-conf.h +++ b/cpu/native/include/cpu-conf.h @@ -75,7 +75,7 @@ extern "C" { #define FLASH_PAGE_SIZE (1024) /**< page size of flash memory */ #define FLASH_NUM_PAGES (256) /**< number of flash pages */ #define FLASH_WRITE_ALIGN (4) /**< number of bytes which must be written at once */ -#define FLASH_ERASED_BIT_VALUE (0x00) /**< value of erased bits */ +#define FLASH_ERASED_WORD_VALUE (0x00) /**< value of erased data words */ /* @} */ #ifdef __cplusplus diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c index 7177706aad74..25ce60570515 100644 --- a/cpu/native/periph/flash.c +++ b/cpu/native/periph/flash.c @@ -139,11 +139,7 @@ uint8_t flash_erase_page(flash_page_number_t page) DEBUG("Erase page %d\n", page); for (ssize_t i = page * FLASH_PAGE_SIZE; i < ((page + 1) * FLASH_PAGE_SIZE); i++) { -#if FLASH_ERASED_BIT_VALUE == 0 - _native_flash_memory[i] = 0; -#else - _native_flash_memory[i] = 0xff; -#endif + _native_flash_memory[i] = FLASH_ERASED_WORD_VALUE; } return FLASH_ERROR_SUCCESS; @@ -234,6 +230,6 @@ void _native_flash_init(void) } /* initialize [remaining] memory area */ - memset((void *)(_native_flash_memory + init_start), FLASH_ERASED_BIT_VALUE, + memset((void *)(_native_flash_memory + init_start), FLASH_ERASED_WORD_VALUE, init_length); } From 0199abcd920f36c599ae5c231a6e767a85c1c47b Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Mon, 5 Jan 2015 19:24:55 +0100 Subject: [PATCH 09/17] FLASH_ERASED_WORD_VALUE in tests/periph_flash --- tests/periph_flash/main.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/periph_flash/main.c b/tests/periph_flash/main.c index 02a48e6a91c5..c0fa89771a0d 100644 --- a/tests/periph_flash/main.c +++ b/tests/periph_flash/main.c @@ -53,13 +53,7 @@ int main(void) counter = 0; for (flash_page_size_t i = 0; i < FLASH_PAGE_SIZE; i++) { -#if FLASH_ERASED_BIT_VALUE==0 - - if (flashpage[i] == 0x00) { -#else - - if (flashpage[i] == 0xff) { -#endif + if (flashpage[i] == FLASH_ERASED_WORD_VALUE) { counter++; } } From 35592e53b0bf6364f4c64aab320bec5ac9233fdb Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Mon, 5 Jan 2015 19:59:14 +0100 Subject: [PATCH 10/17] PR comments (tab stops, comments) --- drivers/include/periph/flash.h | 16 +++++++--------- tests/periph_flash/main.c | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/include/periph/flash.h b/drivers/include/periph/flash.h index 534ec8c393ac..6e508f02eeb2 100644 --- a/drivers/include/periph/flash.h +++ b/drivers/include/periph/flash.h @@ -33,14 +33,14 @@ extern "C" { * */ enum flash_errors { - FLASH_ERROR_SUCCESS = 0, /**< Success */ - FLASH_ERROR_BROWNOUT = 1, /**< Voltage to low */ - FLASH_ERROR_FB_CONFIG = 2, /**< Forbidden by MCU configuration/flags */ - FLASH_ERROR_LOCKED = 3, /**< Page or flash is locked by other operation */ - FLASH_ERROR_TIMEOUT = 4, /**< Timeout */ + FLASH_ERROR_SUCCESS = 0, /**< Success */ + FLASH_ERROR_BROWNOUT = 1, /**< Voltage to low */ + FLASH_ERROR_FB_CONFIG = 2, /**< Forbidden by MCU configuration/flags */ + FLASH_ERROR_LOCKED = 3, /**< Page or flash is locked by other operation */ + FLASH_ERROR_TIMEOUT = 4, /**< Timeout */ FLASH_ERROR_ALIGNMENT = 5, /**< Misalligned access */ - FLASH_ERROR_VERIFY = 6, /**< Data not written correctly */ - FLASH_ERROR_ADDR_RANGE = 7, /**< Address out of flash area */ + FLASH_ERROR_VERIFY = 6, /**< Data not written correctly */ + FLASH_ERROR_ADDR_RANGE = 7, /**< Address out of flash area */ }; /** @@ -86,8 +86,6 @@ typedef uint64_t flash_data_word_t; * @brief Initialize flash memory access * * If needed flash memory initialization can be performed. - * In native mode a file is loaded into memory to simulate - * flash. * * @return Error Code */ diff --git a/tests/periph_flash/main.c b/tests/periph_flash/main.c index c0fa89771a0d..96b8deb9c008 100644 --- a/tests/periph_flash/main.c +++ b/tests/periph_flash/main.c @@ -37,47 +37,47 @@ uint8_t print_test(char *text, uint32_t return_code, uint32_t error_code) int main(void) { - // Signature with space for alignment + /* Signature with space for alignment */ char *testsignature = "RIOT-FLASH-TEST\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; int errors = 0, testsignaturelen = strlen(testsignature), counter = 0; uint8_t *flashpage = flash_get_address(FLASH_NUM_PAGES - 1); - printf("\nFlash interface test...\nTest\t\t\t\t\tResult (RC)\n---------------------------------------------------\n"); + printf("\nFlash interface test...\n" + "Test\t\t\t\t\tResult (RC)\n" + "---------------------------------------------------\n"); - errors = errors + print_test("Initializing flash interface\t", flash_init(), FLASH_ERROR_SUCCESS); - errors = errors + print_test("Compare signate with flash\t", memcmp(flashpage, testsignature, - strlen(testsignature)), 65535); - errors = errors + print_test("Erase last flash page\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), + errors += print_test("Initializing flash interface\t", flash_init(), FLASH_ERROR_SUCCESS); + errors += print_test("Compare signature with flash\t", memcmp(flashpage, testsignature, + testsignaturelen), 65535); + errors += print_test("Erase last flash page\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), FLASH_ERROR_SUCCESS); - counter = 0; - for (flash_page_size_t i = 0; i < FLASH_PAGE_SIZE; i++) { if (flashpage[i] == FLASH_ERASED_WORD_VALUE) { counter++; } } - errors = errors + print_test("Number of erased bytes\t\t", counter, FLASH_PAGE_SIZE); + errors += print_test("Number of erased bytes\t\t", counter, FLASH_PAGE_SIZE); #if FLASH_NUM_PAGES != 256 && FLASH_NUM_PAGES != 65536 - errors = errors + print_test("Erase flash page outside\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), + errors += print_test("Erase flash page outside\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), FLASH_ERROR_ADDR_RANGE); #endif #if FLASH_WRITE_ALIGN > 1 - // align len + /* align len */ while (testsignaturelen % FLASH_WRITE_ALIGN > 0) { testsignaturelen++; } - errors = errors + print_test("Write test signature unaligned\t", flash_memcpy(flashpage, + errors += print_test("Write test signature unaligned\t", flash_memcpy(flashpage, testsignature, testsignaturelen - 1), FLASH_ERROR_ALIGNMENT); #endif - errors = errors + print_test("Write test signature aligned\t", flash_memcpy(flashpage, + errors += print_test("Write test signature aligned\t", flash_memcpy(flashpage, testsignature, testsignaturelen), FLASH_ERROR_SUCCESS); - errors = errors + print_test("Compare signate with flash\t", memcmp(flashpage, testsignature, + errors += print_test("Compare signature with flash\t", memcmp(flashpage, testsignature, testsignaturelen), 0); printf("\nDone with %d errors.\n", errors); From b7a5cdc0fc86453aaf99c5d25cb312d39ce2f177 Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 10 Jan 2015 21:47:40 +0100 Subject: [PATCH 11/17] Extend with hexdump. Small fixes --- tests/periph_flash/main.c | 48 ++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/tests/periph_flash/main.c b/tests/periph_flash/main.c index 96b8deb9c008..0259215a4547 100644 --- a/tests/periph_flash/main.c +++ b/tests/periph_flash/main.c @@ -26,15 +26,35 @@ uint8_t print_test(char *text, uint32_t return_code, uint32_t error_code) { if ((return_code == error_code) || (error_code == 65535)) { - printf("%s\tOK (%d)\n", text, return_code); + printf("%s\tOK (%d)\n", text, (int)return_code); return 0; } else { - printf("%s\tError (%d)\n", text, return_code); + printf("%s\tError (%d)\n", text, (int)return_code); return 1; } } +void dump_line(uint8_t *address) +{ + printf("%08x ", (size_t)address); + + for (uint8_t i = 0; i < 16; i++) { + printf("%02x ", address[i]); + } + + for (uint8_t i = 0; i < 16; i++) { + if ((address[i] > 31) && (address[i] < 127)) { + printf("%c", address[i]); + } + else { + printf("."); + } + } + + printf("\n"); +} + int main(void) { /* Signature with space for alignment */ @@ -48,12 +68,12 @@ int main(void) errors += print_test("Initializing flash interface\t", flash_init(), FLASH_ERROR_SUCCESS); errors += print_test("Compare signature with flash\t", memcmp(flashpage, testsignature, - testsignaturelen), 65535); + testsignaturelen), 65535); errors += print_test("Erase last flash page\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), - FLASH_ERROR_SUCCESS); + FLASH_ERROR_SUCCESS); for (flash_page_size_t i = 0; i < FLASH_PAGE_SIZE; i++) { - if (flashpage[i] == FLASH_ERASED_WORD_VALUE) { + if (flashpage[i] == (FLASH_ERASED_WORD_VALUE & 0xff)) { counter++; } } @@ -62,8 +82,8 @@ int main(void) #if FLASH_NUM_PAGES != 256 && FLASH_NUM_PAGES != 65536 - errors += print_test("Erase flash page outside\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), - FLASH_ERROR_ADDR_RANGE); + errors += print_test("Erase flash page outside\t\t", flash_erase_page(FLASH_NUM_PAGES + 1), + FLASH_ERROR_ADDR_RANGE); #endif #if FLASH_WRITE_ALIGN > 1 @@ -73,14 +93,20 @@ int main(void) } errors += print_test("Write test signature unaligned\t", flash_memcpy(flashpage, - testsignature, testsignaturelen - 1), FLASH_ERROR_ALIGNMENT); + testsignature, testsignaturelen - 1), FLASH_ERROR_ALIGNMENT); #endif errors += print_test("Write test signature aligned\t", flash_memcpy(flashpage, - testsignature, testsignaturelen), FLASH_ERROR_SUCCESS); + testsignature, testsignaturelen), FLASH_ERROR_SUCCESS); errors += print_test("Compare signature with flash\t", memcmp(flashpage, testsignature, - testsignaturelen), 0); + testsignaturelen), 0); - printf("\nDone with %d errors.\n", errors); + printf("\nDone with %d errors.\n\n", errors); + + printf("Dump of last flash page:\n"); + + for (flash_page_size_t i = 0; i < FLASH_PAGE_SIZE; i += 16) { + dump_line(flashpage + i); + } return 0; } From 552afe8199598125c7baab6c552ad2d4c71a7fb0 Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 10 Jan 2015 22:01:19 +0100 Subject: [PATCH 12/17] nRF51 Support (buggy) flash_memcpy dies with hard_fault when source is char *. When source is a flashpage it seems to work. --- cpu/nrf51822/include/cpu-conf.h | 12 +- cpu/nrf51822/periph/flash.c | 203 ++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 8 deletions(-) create mode 100644 cpu/nrf51822/periph/flash.c diff --git a/cpu/nrf51822/include/cpu-conf.h b/cpu/nrf51822/include/cpu-conf.h index d2b4cc2af71d..a11f18da1d5a 100644 --- a/cpu/nrf51822/include/cpu-conf.h +++ b/cpu/nrf51822/include/cpu-conf.h @@ -59,17 +59,13 @@ extern "C" { * @name CPU Flash configuration * @{ */ -#define FLASH_PAGE_SIZE (1024) /**< Page size of flash memory */ -#define FLASH_NUM_PAGES (256) /**< Number of flash pages */ -#define FLASH_START_ADDRESS (0x0) /**< Starting address to calculate end of flash */ -#define FLASH_WRITE_ALIGN (4) /**< number of bytes must be written at once */ -#define FLASH_WRITES_PER_WORD (2) /**< how often a word can overwritten without flash erase */ -#define FLASH_ERASE_CYCLES (20000) /**< Flash erase cycles descibed in datasheet */ -#define FLASH_ERASED_BIT_VALUE (1) /**< Value of erased bits 0|1 */ +#define FLASH_PAGE_SIZE (1024) /**< Page size of flash memory */ +#define FLASH_NUM_PAGES (256) /**< Number of flash pages */ +#define FLASH_WRITE_ALIGN (4) /**< number of bytes must be written at once */ +#define FLASH_ERASED_WORD_VALUE (0xffffffff) /**< value of erased data words */ /** @} */ - #ifdef __cplusplus } #endif diff --git a/cpu/nrf51822/periph/flash.c b/cpu/nrf51822/periph/flash.c new file mode 100644 index 000000000000..ab1d7cc5cfdf --- /dev/null +++ b/cpu/nrf51822/periph/flash.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2015 Frank Holtz + * Copyright (C) 2015 Ludwig Ortmann + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * NRF51 periph/flash.h implementation + * + * @author Frank Holtz + * @author Ludwig Ortmann + * + * @ingroup cpu_nrf51822 + * @defgroup cpu_nrf51822_flash + * @file + */ + +#include + +#include "cpu-conf.h" +#include "periph/flash.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Size of available flash memory */ +static size_t _nrf51_flash_size = (FLASH_NUM_PAGES *FLASH_PAGE_SIZE); + +/************************************************************************/ +/* internal API *********************************************************/ +/************************************************************************/ + +/** + * @brief Check if given address in valid range + * + * @return Error code FLASH_ERROR_SUCCESS or FLASH_ERROR_ADDR_RANGE + * TODO: Implement code region 0|1 check and return FLASH_ERROR_FB_CONFIG + * NRF_FICR->CLENR0 + PPFC + */ +static uint8_t flash_check_address(void *address) +{ + if (((size_t)address < 0) || ((size_t)address >= _nrf51_flash_size)) { + return FLASH_ERROR_ADDR_RANGE; + } + + return FLASH_ERROR_SUCCESS; +} + + + +/************************************************************************/ +/* periph/flash.h *******************************************************/ +/************************************************************************/ + +uint8_t flash_init(void) +{ + DEBUG("flash initialized\n"); + return FLASH_ERROR_SUCCESS; +} + +flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page_offset) +{ + flash_page_number_t page_number = (flash_page_number_t)( + (size_t)address / FLASH_PAGE_SIZE); + + if (page_offset != NULL) { + *page_offset = (flash_page_number_t)( + (size_t)address % FLASH_PAGE_SIZE); + } + + return page_number; +} + +void *flash_get_address(flash_page_number_t page) +{ + return ((void *)(page * FLASH_PAGE_SIZE)); +} + +uint8_t flash_memcpy(void *dest, const void *src, size_t n) +{ + /* Check alignment */ + flash_page_size_t page_offset; + flash_get_page_number(dest, &page_offset); + + if ((n % FLASH_WRITE_ALIGN != 0) || (page_offset % FLASH_WRITE_ALIGN != 0)) { + DEBUG("Unaligned access n=%d offset=%d\n", n, page_offset); + return FLASH_ERROR_ALIGNMENT; + } + + /* write data to flash */ + uint8_t ret = flash_memcpy_fast(dest, src, n); + + /* verify written data if write was successfull */ + if (ret == FLASH_ERROR_SUCCESS) { + while (n > 0) { + if (*((flash_data_word_t *) dest) != *((flash_data_word_t *) src)) { + return FLASH_ERROR_VERIFY; + } + + dest += FLASH_WRITE_ALIGN; + src += FLASH_WRITE_ALIGN; + n -= FLASH_WRITE_ALIGN; + } + } + + return (ret); +} + +/* TODO: Fix it. Jumps into Hard Fault when src is Pointer to char* */ +uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) +{ + /* Check memory range */ + uint8_t ret = flash_check_address((uint8_t *) dest); + + if (ret > FLASH_ERROR_SUCCESS) { + DEBUG("attempted to write below first address\n"); + return ret; + } + + ret = flash_check_address((((uint8_t *) dest) + n)); + + if (ret > FLASH_ERROR_SUCCESS) { + DEBUG("attemted to write beyond last address\n"); + return ret; + } + + flash_data_word_t *mydst = (flash_data_word_t *)dest; + flash_data_word_t *mysrc = (flash_data_word_t *)src; + + /* Enable writing to flash */ + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; + + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + /* Write data to flash */ + n = n / FLASH_WRITE_ALIGN; + + while (n--) { + *mydst = *mysrc; + mydst += FLASH_WRITE_ALIGN; + mysrc += FLASH_WRITE_ALIGN; + + /* wait until write operation is completed */ + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + } + + /* Disable writing to flash */ + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; + + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + + return FLASH_ERROR_SUCCESS; +} + +uint8_t flash_erase_page(flash_page_number_t page) +{ + /* check argument */ + if (page > FLASH_NUM_PAGES) { + return FLASH_ERROR_ADDR_RANGE; + } + + /* erase page by address */ + return flash_erase_page_by_address((void *)(page * FLASH_PAGE_SIZE)); +} + +uint8_t flash_erase_page_by_address(void *address) +{ + /* TODO: check code 0|1 region */ + uint8_t ret = flash_check_address(address); + + if (ret > FLASH_ERROR_SUCCESS) { + return ret; + } + + /* Check alignment */ + if ((size_t)address % FLASH_PAGE_SIZE != 0) { + return FLASH_ERROR_ALIGNMENT; + } + + /* Enable erasing flash */ + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos; + + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + + /* Erase page in region 1*/ + NRF_NVMC->ERASEPAGE = (size_t)address; + + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + /* Disable writing to flash */ + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; + + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + return FLASH_ERROR_SUCCESS; +} + From 2d194e72f539a21e8927d7247f14b2d6b801e188 Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 17 Jan 2015 16:36:07 +0100 Subject: [PATCH 13/17] Flash API change to support unaligned writes --- drivers/include/periph/flash.h | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/include/periph/flash.h b/drivers/include/periph/flash.h index 6e508f02eeb2..070811884190 100644 --- a/drivers/include/periph/flash.h +++ b/drivers/include/periph/flash.h @@ -38,7 +38,7 @@ enum flash_errors { FLASH_ERROR_FB_CONFIG = 2, /**< Forbidden by MCU configuration/flags */ FLASH_ERROR_LOCKED = 3, /**< Page or flash is locked by other operation */ FLASH_ERROR_TIMEOUT = 4, /**< Timeout */ - FLASH_ERROR_ALIGNMENT = 5, /**< Misalligned access */ + FLASH_ERROR_ALIGNMENT = 5, /**< Misalligned access */ FLASH_ERROR_VERIFY = 6, /**< Data not written correctly */ FLASH_ERROR_ADDR_RANGE = 7, /**< Address out of flash area */ }; @@ -124,6 +124,8 @@ void *flash_get_address(flash_page_number_t page); * flash pages at once. Written data are reread to check if * data are stored correctly. Optionally a written word can * modified to set only changed bits to reach more write cycles. + * + * This function can be used with aligned and unaligned addresses. * * The return code should by checked to handle errors. * @@ -136,7 +138,6 @@ void *flash_get_address(flash_page_number_t page); * @return FLASH_ERROR_FB_CONFIG * @return FLASH_ERROR_LOCKED * @return FLASH_ERROR_TIMEOUT - * @return FLASH_ERROR_ALIGNMENT * @return FLASH_ERROR_VERIFY * @return FLASH_ERROR_ADDR_RANGE */ @@ -147,24 +148,26 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n); * * This function works like memcpy. It can be used to write * a part of a flash page or an single flash page or multiple - * flash pages at once. There are no alignment, address or correct - * write checks, so write to protected flash regions or unaligned - * writes are possible. To support all plattforms do an alignment - * and address check by your application + * flash pages at once. There are no address or correct write checks, + * so write to protected flash regions are possible. + * + * To support all plattforms do an alignment of src and dest addresses. + * * This function is used by tests/periph_flash to check if - * alignment is configurd correctly + * alignment check is implemented correctly * * The return code should by checked to handle errors. * - * @param[in] dest Address of flash memory page - * @param[in] src Address of source data - * @param[in] n Number of bytes to write + * @param[in] dest Aligned address of flash memory page + * @param[in] src Aligned address of source data + * @param[in] n Aligned number of bytes to write * * @return FLASH_ERROR_SUCCESS * @return FLASH_ERROR_BROWNOUT * @return FLASH_ERROR_FB_CONFIG * @return FLASH_ERROR_LOCKED * @return FLASH_ERROR_TIMEOUT + * @return FLASH_ERROR_ALIGNMENT */ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n); From ecd9f31f7a7e62ce344d6e32dd0b580c559b6b35 Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 17 Jan 2015 16:36:38 +0100 Subject: [PATCH 14/17] Flash API change, more tests --- cpu/native/periph/flash.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c index 25ce60570515..275ef2bee787 100644 --- a/cpu/native/periph/flash.c +++ b/cpu/native/periph/flash.c @@ -96,23 +96,33 @@ void *flash_get_address(flash_page_number_t page) uint8_t flash_memcpy(void *dest, const void *src, size_t n) { - /* Check alignment */ -#if FLASH_WRITE_ALIGN > 1 - flash_page_size_t page_offset; - flash_get_page_number(dest, &page_offset); - - if ((n % FLASH_WRITE_ALIGN != 0) || (page_offset % FLASH_WRITE_ALIGN != 0)) { - DEBUG("Unaligned access n=%d offset=%d\n", n, page_offset); - return FLASH_ERROR_ALIGNMENT; + /* Check memory range */ + if (flash_check_address((uint8_t *) dest) > FLASH_ERROR_SUCCESS) { + DEBUG("attempted to write below first address\n"); + return FLASH_ERROR_ADDR_RANGE; + } + if (flash_check_address((((uint8_t *) dest) + n)) > FLASH_ERROR_SUCCESS) { + DEBUG("attemted to write beyond last address\n"); + return FLASH_ERROR_ADDR_RANGE; } -#endif - uint8_t ret = flash_memcpy_fast(dest, src, n); - return (ret); + memcpy(dest, src, n); + + return (FLASH_ERROR_SUCCESS); } uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) { + /* Check alignment */ + #if FLASH_WRITE_ALIGN>1 + if ((n % FLASH_WRITE_ALIGN != 0) || + ((size_t)src % FLASH_WRITE_ALIGN != 0) || + ((size_t)dest % FLASH_WRITE_ALIGN != 0)) { + DEBUG("Unaligned access dest=%d, src=%d, n=%d\n", (size_t)mydst, (size_t)mysrc, n); + return FLASH_ERROR_ALIGNMENT; + } + #endif + /* Check memory range */ if (flash_check_address((uint8_t *) dest) > FLASH_ERROR_SUCCESS) { DEBUG("attempted to write below first address\n"); From bab248b8a892da7a3ac960aa5e761efa0552d42c Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 17 Jan 2015 16:36:52 +0100 Subject: [PATCH 15/17] more tests --- tests/periph_flash/main.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/tests/periph_flash/main.c b/tests/periph_flash/main.c index 0259215a4547..55afaf70c500 100644 --- a/tests/periph_flash/main.c +++ b/tests/periph_flash/main.c @@ -58,7 +58,8 @@ void dump_line(uint8_t *address) int main(void) { /* Signature with space for alignment */ - char *testsignature = "RIOT-FLASH-TEST\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + char *testsignature = "RIOTOS-FLASH-TEST\0XXXXXXX"; + char *teststring = "01234"; int errors = 0, testsignaturelen = strlen(testsignature), counter = 0; uint8_t *flashpage = flash_get_address(FLASH_NUM_PAGES - 1); @@ -67,7 +68,7 @@ int main(void) "---------------------------------------------------\n"); errors += print_test("Initializing flash interface\t", flash_init(), FLASH_ERROR_SUCCESS); - errors += print_test("Compare signature with flash\t", memcmp(flashpage, testsignature, + errors += print_test("Compare signature with flash\t", memcmp(flashpage+1, testsignature, testsignaturelen), 65535); errors += print_test("Erase last flash page\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), FLASH_ERROR_SUCCESS); @@ -86,25 +87,33 @@ int main(void) FLASH_ERROR_ADDR_RANGE); #endif #if FLASH_WRITE_ALIGN > 1 - - /* align len */ - while (testsignaturelen % FLASH_WRITE_ALIGN > 0) { - testsignaturelen++; - } - - errors += print_test("Write test signature unaligned\t", flash_memcpy(flashpage, - testsignature, testsignaturelen - 1), FLASH_ERROR_ALIGNMENT); + errors += print_test("Write test signature unaligned\t", flash_memcpy_fast(flashpage+1, + testsignature, testsignaturelen), FLASH_ERROR_ALIGNMENT); #endif - errors += print_test("Write test signature aligned\t", flash_memcpy(flashpage, + errors += print_test("Write test signature flash_memcpy", flash_memcpy(flashpage+1, testsignature, testsignaturelen), FLASH_ERROR_SUCCESS); - errors += print_test("Compare signature with flash\t", memcmp(flashpage, testsignature, + errors += print_test("Compare signature with flash\t", memcmp(flashpage+1, testsignature, testsignaturelen), 0); + errors += print_test("Write 1 byte flash_memcpy\t", + flash_memcpy(flashpage+testsignaturelen+2, + teststring, 1), FLASH_ERROR_SUCCESS); + errors += print_test("Compare 1 byte with flash\t", + memcmp(flashpage+testsignaturelen+2, teststring, 1), 0); + + errors += print_test("Overwrite with flash_memcpy\t", + flash_memcpy(flashpage+testsignaturelen+2, + teststring, strlen(teststring)), FLASH_ERROR_SUCCESS); + errors += print_test("Compare bytes with flash\t", + memcmp(flashpage+testsignaturelen+2, teststring, + strlen(teststring)), 0); + + printf("\nDone with %d errors.\n\n", errors); - printf("Dump of last flash page:\n"); + printf("Dump top of last flash page:\n"); - for (flash_page_size_t i = 0; i < FLASH_PAGE_SIZE; i += 16) { + for (flash_page_size_t i = 0; i < 16*5; i += 16) { dump_line(flashpage + i); } From e6c21e2fad21103ca4b3e1cb585892f907575b9d Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 17 Jan 2015 16:37:09 +0100 Subject: [PATCH 16/17] nRF51 support --- cpu/nrf51822/periph/flash.c | 154 +++++++++++++++++++++++++++--------- 1 file changed, 116 insertions(+), 38 deletions(-) diff --git a/cpu/nrf51822/periph/flash.c b/cpu/nrf51822/periph/flash.c index ab1d7cc5cfdf..dc37f95295c5 100644 --- a/cpu/nrf51822/periph/flash.c +++ b/cpu/nrf51822/periph/flash.c @@ -49,8 +49,6 @@ static uint8_t flash_check_address(void *address) return FLASH_ERROR_SUCCESS; } - - /************************************************************************/ /* periph/flash.h *******************************************************/ /************************************************************************/ @@ -81,55 +79,134 @@ void *flash_get_address(flash_page_number_t page) uint8_t flash_memcpy(void *dest, const void *src, size_t n) { - /* Check alignment */ - flash_page_size_t page_offset; - flash_get_page_number(dest, &page_offset); + DEBUG("flash_memcpy dest=%d, src=%d, n=%d\n", (size_t)dest, (size_t)src, n); + + /* Variables */ - if ((n % FLASH_WRITE_ALIGN != 0) || (page_offset % FLASH_WRITE_ALIGN != 0)) { - DEBUG("Unaligned access n=%d offset=%d\n", n, page_offset); - return FLASH_ERROR_ALIGNMENT; - } + /* temp */ + uint8_t temp; - /* write data to flash */ - uint8_t ret = flash_memcpy_fast(dest, src, n); + /* Flag is switched on verify error */ + bool writeverify = true; - /* verify written data if write was successfull */ - if (ret == FLASH_ERROR_SUCCESS) { - while (n > 0) { - if (*((flash_data_word_t *) dest) != *((flash_data_word_t *) src)) { - return FLASH_ERROR_VERIFY; - } + /* Buffer for unaligned access*/ + flash_data_word_t dstbuffer; - dest += FLASH_WRITE_ALIGN; - src += FLASH_WRITE_ALIGN; - n -= FLASH_WRITE_ALIGN; - } - } + /* Align dest */ + flash_data_word_t *mydst_start = + (flash_data_word_t *)((size_t)dest & (FLASH_ERASED_WORD_VALUE - FLASH_WRITE_ALIGN + 1)); + flash_data_word_t *mydst_end = + (flash_data_word_t *)((size_t)(dest + n) & + (FLASH_ERASED_WORD_VALUE - FLASH_WRITE_ALIGN +1)); - return (ret); -} + /* prepare src to read bytewise */ + uint8_t *mysrc = (uint8_t *)src; -/* TODO: Fix it. Jumps into Hard Fault when src is Pointer to char* */ -uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) -{ - /* Check memory range */ - uint8_t ret = flash_check_address((uint8_t *) dest); + /* Nothing to do */ + if (n == 0) { + return (FLASH_ERROR_SUCCESS); + } - if (ret > FLASH_ERROR_SUCCESS) { + /* Check destination memory range: start */ + temp = flash_check_address((uint8_t *) mydst_start); + + if (temp > FLASH_ERROR_SUCCESS) { DEBUG("attempted to write below first address\n"); - return ret; + return temp; } - ret = flash_check_address((((uint8_t *) dest) + n)); + /* Check destination memory range: end */ + temp = flash_check_address((uint8_t *) mydst_end-1); - if (ret > FLASH_ERROR_SUCCESS) { + if (temp > FLASH_ERROR_SUCCESS) { DEBUG("attemted to write beyond last address\n"); - return ret; + return temp; + } + + /* Enable writing to flash */ + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; + + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + /* move mysrc down to count of unaligned dst bytes */ + mysrc -= (uint8_t *)dest - (uint8_t *)mydst_start; + + for (flash_data_word_t *i = mydst_start; i <= mydst_end && n > 0; i++) { + dstbuffer = FLASH_ERASED_WORD_VALUE; + + /* copy data into dstbuffer */ + for (temp = 0; temp < FLASH_WRITE_ALIGN; temp++) { + /* check address range */ + if ((mysrc >= (uint8_t *)src) && (n > 0)) { + n--; + /* for every data word byte (little endian)*/ + switch (temp) { + case 0: + *((uint8_t *)&dstbuffer) = *mysrc; + break; + + case 1: + *((uint8_t *)&dstbuffer + 1) = *mysrc; + break; + + case 2: + *((uint8_t *)&dstbuffer + 2) = *mysrc; + break; + + default: + *((uint8_t *)&dstbuffer + 3) = *mysrc; + break; + } + } + mysrc++; + } + + /* new data -> write + * change & to | when erased bit value is 0 */ + if ( *i != (dstbuffer & *i)) { + /* write data */ + *i = dstbuffer; + + /* wait until write operation is completed */ + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + /* verify data */ + if (*i != dstbuffer) { + /* set error flag */ + writeverify = false; + } + } } + /* Disable writing to flash */ + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; + + while (NRF_NVMC->READY == NVMC_READY_READY_Busy); + + if (writeverify) { + return (FLASH_ERROR_SUCCESS); + } + else { + return (FLASH_ERROR_VERIFY); + } +} + +uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) +{ flash_data_word_t *mydst = (flash_data_word_t *)dest; flash_data_word_t *mysrc = (flash_data_word_t *)src; + /* Prevent hard fault: Is src and dst aligned ? */ + /* Check alignment */ + if ((n % FLASH_WRITE_ALIGN != 0) || + ((size_t)mysrc % FLASH_WRITE_ALIGN != 0) || + ((size_t)mydst % FLASH_WRITE_ALIGN != 0)) { + DEBUG("Unaligned access dest=%d, src=%d, n=%d\n", (size_t)mydst, (size_t)mysrc, n); + return FLASH_ERROR_ALIGNMENT; + } + + return (0); + /* Enable writing to flash */ NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; @@ -139,13 +216,15 @@ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) n = n / FLASH_WRITE_ALIGN; while (n--) { + /* write data */ *mydst = *mysrc; - mydst += FLASH_WRITE_ALIGN; - mysrc += FLASH_WRITE_ALIGN; + + /* increment pointer by 4 on Cortex-M0 */ + mydst++; + mysrc++; /* wait until write operation is completed */ while (NRF_NVMC->READY == NVMC_READY_READY_Busy); - } /* Disable writing to flash */ @@ -153,7 +232,6 @@ uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) while (NRF_NVMC->READY == NVMC_READY_READY_Busy); - return FLASH_ERROR_SUCCESS; } From b343ef8b6ed1236022e367a3b3a75acca4472bdd Mon Sep 17 00:00:00 2001 From: Frank Holtz Date: Sat, 17 Jan 2015 16:47:24 +0100 Subject: [PATCH 17/17] Flash-Interface fix cppcheck; astyle --- cpu/native/periph/flash.c | 33 +++++++++++++++++++-------------- cpu/nrf51822/periph/flash.c | 12 +++++++----- tests/periph_flash/main.c | 24 ++++++++++++------------ 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/cpu/native/periph/flash.c b/cpu/native/periph/flash.c index 275ef2bee787..2bdf85bbf4a7 100644 --- a/cpu/native/periph/flash.c +++ b/cpu/native/periph/flash.c @@ -43,7 +43,7 @@ int _native_flash_fd = -1; volatile uint8_t *_native_flash_memory = NULL; -size_t _native_flash_size = (FLASH_NUM_PAGES * FLASH_PAGE_SIZE); +size_t _native_flash_size = (FLASH_NUM_PAGES *FLASH_PAGE_SIZE); /************************************************************************/ @@ -58,7 +58,7 @@ size_t _native_flash_size = (FLASH_NUM_PAGES * FLASH_PAGE_SIZE); static uint8_t flash_check_address(uint8_t *address) { if ((address < _native_flash_memory) - || ((address >= _native_flash_memory+_native_flash_size))) { + || ((address >= _native_flash_memory + _native_flash_size))) { return FLASH_ERROR_ADDR_RANGE; } @@ -81,9 +81,9 @@ flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page &_native_flash_memory[0]) / FLASH_PAGE_SIZE); if (page_offset != NULL) { - *page_offset = (flash_page_number_t) ( - ((uint8_t *)address - &_native_flash_memory[0]) - % FLASH_PAGE_SIZE); + *page_offset = (flash_page_number_t)( + ((uint8_t *)address - &_native_flash_memory[0]) + % FLASH_PAGE_SIZE); } return page_number; @@ -91,7 +91,7 @@ flash_page_number_t flash_get_page_number(void *address, flash_page_size_t *page void *flash_get_address(flash_page_number_t page) { - return ((void *) (_native_flash_memory + (page * FLASH_PAGE_SIZE))); + return ((void *)(_native_flash_memory + (page * FLASH_PAGE_SIZE))); } uint8_t flash_memcpy(void *dest, const void *src, size_t n) @@ -101,33 +101,36 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) DEBUG("attempted to write below first address\n"); return FLASH_ERROR_ADDR_RANGE; } + if (flash_check_address((((uint8_t *) dest) + n)) > FLASH_ERROR_SUCCESS) { DEBUG("attemted to write beyond last address\n"); return FLASH_ERROR_ADDR_RANGE; } memcpy(dest, src, n); - + return (FLASH_ERROR_SUCCESS); } uint8_t flash_memcpy_fast(void *dest, const void *src, size_t n) { /* Check alignment */ - #if FLASH_WRITE_ALIGN>1 +#if FLASH_WRITE_ALIGN>1 if ((n % FLASH_WRITE_ALIGN != 0) || ((size_t)src % FLASH_WRITE_ALIGN != 0) || ((size_t)dest % FLASH_WRITE_ALIGN != 0)) { DEBUG("Unaligned access dest=%d, src=%d, n=%d\n", (size_t)mydst, (size_t)mysrc, n); return FLASH_ERROR_ALIGNMENT; } - #endif + +#endif /* Check memory range */ if (flash_check_address((uint8_t *) dest) > FLASH_ERROR_SUCCESS) { DEBUG("attempted to write below first address\n"); return FLASH_ERROR_ADDR_RANGE; } + if (flash_check_address((((uint8_t *) dest) + n)) > FLASH_ERROR_SUCCESS) { DEBUG("attemted to write beyond last address\n"); return FLASH_ERROR_ADDR_RANGE; @@ -181,7 +184,7 @@ void _native_flash_init(void) /* try to open [existing] file */ if ((_native_flash_fd = real_open(_native_flash_path, - O_RDWR | O_CREAT, 0600)) == -1) { + O_RDWR | O_CREAT, 0600)) == -1) { err(EXIT_FAILURE, "_native_flash_init: open"); } @@ -200,10 +203,12 @@ void _native_flash_init(void) } init_start = size; + if (size < _native_flash_size) { init_length = _native_flash_size - size; + if (real_lseek(_native_flash_fd, _native_flash_size - 1, - SEEK_SET) == -1) { + SEEK_SET) == -1) { err(EXIT_FAILURE, "_native_flash_init: lseek"); } @@ -217,8 +222,8 @@ void _native_flash_init(void) /* try to map file into memory */ if ((_native_flash_memory = real_mmap(NULL, _native_flash_size, - PROT_READ|PROT_WRITE, MAP_SHARED, _native_flash_fd, 0) - ) == MAP_FAILED) { + PROT_READ | PROT_WRITE, MAP_SHARED, _native_flash_fd, 0) + ) == MAP_FAILED) { err(EXIT_FAILURE, "_native_flash_init: mmap"); } @@ -241,5 +246,5 @@ void _native_flash_init(void) /* initialize [remaining] memory area */ memset((void *)(_native_flash_memory + init_start), FLASH_ERASED_WORD_VALUE, - init_length); + init_length); } diff --git a/cpu/nrf51822/periph/flash.c b/cpu/nrf51822/periph/flash.c index dc37f95295c5..dba540b379e1 100644 --- a/cpu/nrf51822/periph/flash.c +++ b/cpu/nrf51822/periph/flash.c @@ -80,7 +80,7 @@ void *flash_get_address(flash_page_number_t page) uint8_t flash_memcpy(void *dest, const void *src, size_t n) { DEBUG("flash_memcpy dest=%d, src=%d, n=%d\n", (size_t)dest, (size_t)src, n); - + /* Variables */ /* temp */ @@ -96,8 +96,8 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) flash_data_word_t *mydst_start = (flash_data_word_t *)((size_t)dest & (FLASH_ERASED_WORD_VALUE - FLASH_WRITE_ALIGN + 1)); flash_data_word_t *mydst_end = - (flash_data_word_t *)((size_t)(dest + n) & - (FLASH_ERASED_WORD_VALUE - FLASH_WRITE_ALIGN +1)); + (flash_data_word_t *)((size_t)((size_t)dest + n) & + (FLASH_ERASED_WORD_VALUE - FLASH_WRITE_ALIGN + 1)); /* prepare src to read bytewise */ uint8_t *mysrc = (uint8_t *)src; @@ -116,7 +116,7 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) } /* Check destination memory range: end */ - temp = flash_check_address((uint8_t *) mydst_end-1); + temp = flash_check_address((uint8_t *) mydst_end - 1); if (temp > FLASH_ERROR_SUCCESS) { DEBUG("attemted to write beyond last address\n"); @@ -139,6 +139,7 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) /* check address range */ if ((mysrc >= (uint8_t *)src) && (n > 0)) { n--; + /* for every data word byte (little endian)*/ switch (temp) { case 0: @@ -158,12 +159,13 @@ uint8_t flash_memcpy(void *dest, const void *src, size_t n) break; } } + mysrc++; } /* new data -> write * change & to | when erased bit value is 0 */ - if ( *i != (dstbuffer & *i)) { + if (*i != (dstbuffer & *i)) { /* write data */ *i = dstbuffer; diff --git a/tests/periph_flash/main.c b/tests/periph_flash/main.c index 55afaf70c500..fc935a74191a 100644 --- a/tests/periph_flash/main.c +++ b/tests/periph_flash/main.c @@ -68,7 +68,7 @@ int main(void) "---------------------------------------------------\n"); errors += print_test("Initializing flash interface\t", flash_init(), FLASH_ERROR_SUCCESS); - errors += print_test("Compare signature with flash\t", memcmp(flashpage+1, testsignature, + errors += print_test("Compare signature with flash\t", memcmp(flashpage + 1, testsignature, testsignaturelen), 65535); errors += print_test("Erase last flash page\t\t", flash_erase_page(FLASH_NUM_PAGES - 1), FLASH_ERROR_SUCCESS); @@ -87,33 +87,33 @@ int main(void) FLASH_ERROR_ADDR_RANGE); #endif #if FLASH_WRITE_ALIGN > 1 - errors += print_test("Write test signature unaligned\t", flash_memcpy_fast(flashpage+1, + errors += print_test("Write test signature unaligned\t", flash_memcpy_fast(flashpage + 1, testsignature, testsignaturelen), FLASH_ERROR_ALIGNMENT); #endif - errors += print_test("Write test signature flash_memcpy", flash_memcpy(flashpage+1, + errors += print_test("Write test signature flash_memcpy", flash_memcpy(flashpage + 1, testsignature, testsignaturelen), FLASH_ERROR_SUCCESS); - errors += print_test("Compare signature with flash\t", memcmp(flashpage+1, testsignature, + errors += print_test("Compare signature with flash\t", memcmp(flashpage + 1, testsignature, testsignaturelen), 0); errors += print_test("Write 1 byte flash_memcpy\t", - flash_memcpy(flashpage+testsignaturelen+2, - teststring, 1), FLASH_ERROR_SUCCESS); + flash_memcpy(flashpage + testsignaturelen + 2, + teststring, 1), FLASH_ERROR_SUCCESS); errors += print_test("Compare 1 byte with flash\t", - memcmp(flashpage+testsignaturelen+2, teststring, 1), 0); + memcmp(flashpage + testsignaturelen + 2, teststring, 1), 0); errors += print_test("Overwrite with flash_memcpy\t", - flash_memcpy(flashpage+testsignaturelen+2, - teststring, strlen(teststring)), FLASH_ERROR_SUCCESS); + flash_memcpy(flashpage + testsignaturelen + 2, + teststring, strlen(teststring)), FLASH_ERROR_SUCCESS); errors += print_test("Compare bytes with flash\t", - memcmp(flashpage+testsignaturelen+2, teststring, - strlen(teststring)), 0); + memcmp(flashpage + testsignaturelen + 2, teststring, + strlen(teststring)), 0); printf("\nDone with %d errors.\n\n", errors); printf("Dump top of last flash page:\n"); - for (flash_page_size_t i = 0; i < 16*5; i += 16) { + for (flash_page_size_t i = 0; i < 16 * 5; i += 16) { dump_line(flashpage + i); }