Stores data on the flash memory of stm32f4xx
Revision 0:4cb438b58dc2, committed 2016-11-18
- Comitter:
- hendreh
- Date:
- Fri Nov 18 14:37:15 2016 +0000
- Commit message:
- working
Changed in this revision
diff -r 000000000000 -r 4cb438b58dc2 SOFBlock.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SOFBlock.cpp Fri Nov 18 14:37:15 2016 +0000 @@ -0,0 +1,153 @@ +/* +* @file SOFBlock.cpp +* @author hillkim7@gmail.com +* +* @brief Simple storage implementation on internal MCU flash memory. +* +*/ + +#include "SOFBlock.h" +#include <string.h> +#include <stdlib.h> + + +SOFBlock::SOFBlock() + : hblock_(NULL) +{ +} + +SOFBlock::~SOFBlock() +{ + close(); +} + +void SOFBlock::close() +{ + if (hblock_ != NULL) { + SOF_block_close(hblock_); + hblock_ = NULL; + } +} + +bool SOFBlock::format( uint8_t sector_index ) +{ + return SOF_block_format(sector_index); +} + +bool SOFBlock::get_stat( uint8_t sector_index, SOF_Statics_t &statics ) +{ + return SOF_block_get_statics(sector_index, &statics) == kSOF_ErrNone; +} + +SOFWriter::SOFWriter() +{ + +} + +SOFWriter::~SOFWriter() +{ + +} + +SOF_Error_t SOFWriter::open( uint8_t sector_index ) +{ + if (is_open()) { + return kSOF_ErrBusyBlock; + } + + SOF_Error_t err; + + hblock_ = SOF_block_create_storage(sector_index, &err); + + return err; +} + +bool SOFWriter::write_byte_data( uint8_t c ) +{ + if (!is_open()) { + return false; + } + + return SOF_block_putc(hblock_, c); +} + +size_t SOFWriter::write_data( const uint8_t *p, size_t p_size ) +{ + if (!is_open()) { + return false; + } + + return SOF_block_write(hblock_, p, p_size); +} + +size_t SOFWriter::get_free_size() +{ + if (!is_open()) { + return 0; + } + + return SOF_block_get_free_size(hblock_); +} + + +SOFReader::SOFReader() +{ + +} + +SOFReader::~SOFReader() +{ + +} + +SOF_Error_t SOFReader::open( uint8_t sector_index ) +{ + if (is_open()) { + return kSOF_ErrBusyBlock; + } + + SOF_Error_t err; + + hblock_ = SOF_block_open_storage(sector_index, &err); + + return err; +} + +uint8_t * SOFReader::get_physical_data_addr() +{ + if (!is_open()) { + return NULL; + } + + return SOF_block_base_addr(hblock_); +} + +size_t SOFReader::get_data_size() +{ + if (!is_open()) { + return 0; + } + + return SOF_block_storage_size(hblock_); +} + +bool SOFReader::read_byte_data( uint8_t *c ) +{ + if (!is_open()) { + return false; + } + + return SOF_block_getc(hblock_, c); +} + +size_t SOFReader::read_data( uint8_t *p, size_t p_size ) +{ + if (!is_open()) { + return 0; + } + + return SOF_block_read(hblock_, p, p_size); +} + + +
diff -r 000000000000 -r 4cb438b58dc2 SOFBlock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SOFBlock.h Fri Nov 18 14:37:15 2016 +0000 @@ -0,0 +1,184 @@ +/** + * @file SOFBlock.h + * + * @author hillkim7@gmail.com + * @brief Simple storage implementation on internal MCU flash memory. + * + * The SOF in SOFBlock is abbreviation of "Storage On Flash". + * The purpose of SOFBlock class is to provide a way to write data on flash memory + * in the same way of file handling class in the file system. + * It manages a chunk of data on the Flash memory efficiently by minimizing flash erase operation as little as possible. + * Note: Currently it only supports STM32F4xx series platforms. + * - NUCLEO-F401RE, NUCLEO-F411RE, Seeed Arch Max + * The STM32 F4xx series from ST have plenty of internal Flash memory inside MCU core. + * For example STM32 401RE has 512Kbyts Flash. + * Typical size of firmware file is less than 256KB, so remaining area is free to use. + * The simplest way of flash utilization as data storage is to use a chunk of Flash area as an unit of storage. + * A block of flash is called sector in STM32F4xx domain. It requires to erase a sector before update bits in flash. + * + * Conceptually it is quite simple. + * Here is typical write operation: + * 1) Erase sector #n + * 2) Write data to sector #n + * Read operation: + * 1) Just read physical memory address of sector #n + * The base physical address of STM32 flash is 0x08000000. + * + * There may be inefficiency in this flash usage scenario when size of data is too small compared with sector size. + * The size of sectors from #5 to #7 of STM32-F4xx Flash is 128KB. For example, if I only need to maintain 1KB data, + * whenever I need to update data I need to erase whole 128KB of sector. + * This produces two problems. + * One is time consumption of the erase operation. The operation of ERASE128KB takes 1~4 seconds long. + * The other is related to lifetime of Flash memory. + * More you erase and write and lifetime of flash is shorter. + * + * To overcome such problems, here simple flash management algorithm is used for. + * By tracking data offset and size it can hold multiple data in a sector. + * Bear in mind that is impossible rewriting data on Flash. + * Keeping tracking data along with data itself without frequent erase operation is crucial. + * To do this, data itself is growing from low address. + * On the other hand tracking data is growing down from high address. + * Let's assume the size of data is 1KB and store it in sector #6 which address range is from 0x08040000 to 0x0805ffff. + * +-------------+----------------------------------------------------------------------+-----+ + * <data> <tracking data> + * +-------------+----------------------------------------------------------------------+-----+ + * data grows -> <- tracking data grows + * Writing data will be placed at the end of data always and reading data will pick the last data. + * It is like simple file system that only keep a file only. + * + * Unlike file manipulation operation, there is caution you need to check if write operation fails + * or need to check free size before you start to write data. + * It is required to format flash sector when there is no more free space. + */ + +#pragma once + +#include "SOF_dev.h" + +/** SOF(Storage On Flash) usage example + * + * Example: + * @code + * #include "mbed.h" + * #include "SOFBlock.h" + * + * int main() + * { + * const uint8_t sector_index = 7; + * SOFBlock::format(sector_index); // Erase flash sector 7 and make structure for storage. + * + * SOFWriter writer; + * SOFReader reader; + * + * writer.open(sector_index); + * writer.write_data((uint8_t*)"First Data", 10); + * writer.close(); + * + * reader.open(sector_index); + * printf("data %d bytes at %p :\r\n", reader.get_data_size(), reader.get_physical_base_addr()); + * printf("%.*s\r\n", reader.get_data_size(), reader.get_physical_base_addr()); + * // "First Data" printed + * reader.close(); + * + * SOF_Statics_t statics; + * if (!SOFBlock(sector_index, statics) || statics.free_size < 11) { // check available byte + * SOFBlock::format(sector_index); + * } + * writer.open(sector_index); + * // Overwrite previous data without erasing flash. + * writer.write_data((uint8_t*)"Second Data", 11); + * writer.close(); + * + * reader.open(sector_index); + * printf("data %d bytes at %p :\r\n", reader.get_data_size(), reader.get_physical_base_addr()); + * printf("%.*s\r\n", reader.get_data_size(), reader.get_physical_base_addr()); + * // "Second Data" printed + * reader.close(); + * } + */ + +/** + * Base class of SOF(Storage On Flash) + */ +class SOFBlock +{ +public: + SOFBlock(); + + virtual ~SOFBlock(); + + void close(); + +public: + /*** Returns whether instance of SOFBlock is currently associated to flash storage. */ + bool is_open() const { + return hblock_ != NULL; + } + +public: + /*** Erase flash sector and put signature to setup file system struct */ + static bool format(uint8_t sector_index); + + /*** Get statistics of storage */ + static bool get_stat(uint8_t sector_index, SOF_Statics_t &statics); + +protected: + SOF_BlockHandle_t hblock_; +}; + + +/** + * It provides interface for writing data to flash memory. + */ +class SOFWriter : public SOFBlock +{ +public: + SOFWriter(); + virtual ~SOFWriter(); + + /*** Open for writing mode */ + SOF_Error_t open(uint8_t sector_index); + + /*** Return max available for writing */ + size_t get_free_size(); + + /*** Write one byte of data. + * Note: in case of storage full, it can't write data any more. + * It is required to format sector and write it again. + */ + bool write_byte_data(uint8_t c); + + /*** Write n bytes of data */ + size_t write_data(const uint8_t *p, size_t p_size); +}; + + +/** +* It provides interface for reading data from flash memory. +* It can read data directly by accessing physical flash address or +* calling function like traditional file API style. +*/ +class SOFReader : public SOFBlock +{ +public: + SOFReader(); + virtual ~SOFReader(); + + /*** Open for read mode */ + SOF_Error_t open(uint8_t sector_index); + + /*** Return flash physical address of data for direct access */ + uint8_t *get_physical_data_addr(); + + /*** Return data size */ + size_t get_data_size(); + + /*** Return one byte of data */ + bool read_byte_data(uint8_t *c); + + /*** Return n bytes of data */ + size_t read_data( uint8_t *p, size_t p_size); +}; + + +
diff -r 000000000000 -r 4cb438b58dc2 SOF_block.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SOF_block.cpp Fri Nov 18 14:37:15 2016 +0000 @@ -0,0 +1,523 @@ +/* +* @file SOF_block.cpp +* +* @brief MTD device handling of STM32 internal flash memory. +* +* +* History: +*/ + +#include <stdio.h> +#include <assert.h> +#include "SOF_dev.h" +#include <string.h> + +#define LOCAL_DEBUG 0 // turn on local debug + +#define DCRLF "\r\n" + +#if LOCAL_DEBUG +#define DPRINTF printf +#define EPRINTF printf +#define DUMP_BLOCK dump_block +#define DASSERT assert +#else +#define DPRINTF(...) +#define EPRINTF(...) +#define DUMP_BLOCK(...) +#define DASSERT(...) +#endif + +static uint16_t checksum(const uint8_t* data, int count); + +#define SYNC_MARK_BYTE_IN_LEN 0x07 // signature mark for upper byte in the storage_len + +#define RESERVED_BLOCK_INFO_SIZE sizeof(BlockInfo_t) + +typedef struct { + uint16_t for_storage; + uint16_t for_info; +} BlockChecksum_t; + +typedef struct { + BlockChecksum_t csum; + uint32_t storage_len; +} BlockInfo_t; + +typedef struct { + uint32_t begin_offset; + uint32_t len; + uint16_t storage_csum; +} StorageInfo_t; + +class SOF_BlockHandle +{ +public: + SOF_BlockHandle() + : write_mode_(false) + , cur_pos_(0) + , hdev_(SOF_INVALID_HANDLE) + , storage_max_offset_(0) + , storage_begin_offset_(0) + , storage_end_offset_(0) { + } + + bool is_writable() const { + return write_mode_; + } + + uint32_t total_physical_block_size() const { + return SOF_dev_info(hdev_)->sec_size; + } + +public: + bool write_mode_; + size_t cur_pos_; + SOF_DevHandle_t hdev_; + uint32_t storage_max_offset_; + uint32_t storage_begin_offset_; + uint32_t storage_end_offset_; +}; + + +static bool get_block_info(const SOF_BlockHandle_t handle, size_t seq, BlockInfo_t *info, uint32_t *loc_offset) +{ + uint32_t check_pos = ((seq+1) * sizeof(BlockInfo_t)); + uint32_t info_pos; + + DASSERT(check_pos < handle->total_physical_block_size()); + if (check_pos >= handle->total_physical_block_size()) + return false; + + *loc_offset = info_pos = handle->total_physical_block_size() - check_pos; + + // checksum in the first word + *((uint32_t*)&info->csum) = SOF_dev_read_word(handle->hdev_, info_pos); + // storage len in the next word + info->storage_len = SOF_dev_read_word(handle->hdev_, info_pos + 4); + + return true; +} + +static bool is_empty_block_info(BlockInfo_t *info) +{ + uint8_t *p = (uint8_t*)info; + + for (size_t i = 0; i < sizeof(BlockInfo_t); ++i) + if (p[i] != SOF_ERASED_BYTE_VALUE) + return false; + + return true; +} + +static bool is_valid_block_info(BlockInfo_t *info) +{ + uint16_t csum = checksum((uint8_t*)&info->storage_len, 4); + + if (SYNC_MARK_BYTE_IN_LEN != (info->storage_len >> 24)) { + EPRINTF("no sync mark in storage_len=%#x"DCRLF,info->storage_len); + return false; + } + + if (csum != info->csum.for_info) { + EPRINTF("CSUM mismatch %#x %#x"DCRLF,csum, info->csum.for_info); + return false; + } + + return true; +} + +static bool get_empty_info_location(const SOF_BlockHandle_t handle, uint32_t *loc_offset) +{ + BlockInfo_t info; + uint32_t pos; + + for (size_t seq = 0; get_block_info(handle, seq, &info, &pos); ++seq) { + //DPRINTF("[%u] len=%#x pos=%u"DCRLF,seq, info.storage_len, pos); + if (is_empty_block_info(&info)) { + *loc_offset = pos; + return true; + } + } + + return false; +} + +static SOF_Error_t probe_active_storage_info(const SOF_BlockHandle_t handle, StorageInfo_t *storage_info) +{ + BlockInfo_t info, last_info; + uint32_t pos; + uint32_t storage_len_sum = 0; + + for (size_t seq = 0; get_block_info(handle, seq, &info, &pos); ++seq) { + if (is_empty_block_info(&info)) { + if (seq == 0) + return kSOF_ErrNoInfo; + break; + } + if (!is_valid_block_info(&info)) { + if (storage_info->begin_offset + storage_info->len == pos) { + DPRINTF("data is full: %u"DCRLF,storage_info->begin_offset + storage_info->len); + break; + } + + EPRINTF("invalid block at %u"DCRLF,pos); + return kSOF_ErrBadBlock; + } + + storage_len_sum += info.storage_len & 0x00FFFFFF; + last_info = info; + } + + uint32_t storage_len = last_info.storage_len & 0x00FFFFFF; + + storage_info->begin_offset = storage_len_sum - storage_len; + storage_info->len = storage_len; + storage_info->storage_csum = last_info.csum.for_storage; + + return kSOF_ErrNone; +} + + +#if LOCAL_DEBUG +static void dump_block(SOF_BlockHandle_t handle) +{ + DPRINTF("sector(%u)"DCRLF, SOF_dev_info(handle->hdev_)->sec_no); + DPRINTF(" offset =%u"DCRLF, handle->cur_pos_); + DPRINTF(" writemode =%d"DCRLF, handle->write_mode_); + DPRINTF(" storage_max_offset =%u"DCRLF, handle->storage_max_offset_); + DPRINTF(" storage_begin_offset =%u"DCRLF, handle->storage_begin_offset_); + DPRINTF(" storage_end_offset =%u"DCRLF, handle->storage_end_offset_); + DPRINTF(" free=%u total=%u"DCRLF,SOF_block_get_free_size(handle), handle->total_physical_block_size()); +} +#endif + +size_t SOF_block_get_free_size(SOF_BlockHandle_t handle) +{ + DASSERT(handle != NULL); + if (handle->storage_end_offset_ <= handle->storage_max_offset_-RESERVED_BLOCK_INFO_SIZE) + return (handle->storage_max_offset_- RESERVED_BLOCK_INFO_SIZE) - handle->storage_end_offset_; + else { + return 0; + } +} + +uint32_t SOF_block_storage_size(SOF_BlockHandle_t handle) +{ + DASSERT(handle != NULL); + return handle->storage_end_offset_ - handle->storage_begin_offset_; +} + +static uint16_t checksum(const uint8_t* data, int count) +{ + // Fletcher's checksum algorithm + uint16_t sum1 = 0; + uint16_t sum2 = 0; + int index; + + for( index = 0; index < count; ++index ) { + sum1 = (sum1 + data[index]) % 255; + sum2 = (sum2 + sum1) % 255; + } + + return (sum2 << 8) | sum1; +} + +static uint16_t compute_storage_checksum(SOF_BlockHandle_t handle) +{ + uint8_t *addr = SOF_dev_get_hw_addr(handle->hdev_); + + return checksum(addr+handle->storage_begin_offset_, SOF_block_storage_size(handle)); +} + +static bool write_storage_info(SOF_BlockHandle_t handle) +{ + BlockInfo_t cs; + + cs.storage_len = (SYNC_MARK_BYTE_IN_LEN << 24) | SOF_block_storage_size(handle); + cs.csum.for_info = checksum((uint8_t*)&cs.storage_len, 4); + cs.csum.for_storage = compute_storage_checksum(handle); + + DPRINTF("write %#x at %#x"DCRLF,*((uint32_t*)&cs.csum), handle->storage_max_offset_); + if (SOF_dev_write_word(handle->hdev_, handle->storage_max_offset_, *((uint32_t*)&cs.csum)) < 0) + return false; + + if (SOF_dev_write_word(handle->hdev_, handle->storage_max_offset_+4, *((uint32_t*)&cs.storage_len)) < 0) + return false; + + return true; +} + +static bool create_empty_storage(SOF_DevHandle_t hdev, uint8_t sector_index) +{ + SOF_BlockHandle handle_data; + + handle_data.hdev_ = hdev; + + uint32_t info_begin_offset; + + if (!get_empty_info_location(&handle_data, &info_begin_offset)) { + EPRINTF("no info"DCRLF); + SOF_block_close(&handle_data); + return false; + } + + handle_data.storage_max_offset_ = info_begin_offset; + handle_data.storage_begin_offset_ = 0; + handle_data.storage_end_offset_ = handle_data.storage_begin_offset_; + handle_data.cur_pos_ = handle_data.storage_begin_offset_; + + DPRINTF("storage created: begin=%d end=%d free=%d"DCRLF, + handle_data.storage_begin_offset_, handle_data.storage_end_offset_, SOF_block_get_free_size(&handle_data)); + + write_storage_info(&handle_data); + + return true; +} + + +bool SOF_block_format(uint8_t sector_index) +{ + if (!SOF_dev_is_valid_sector(sector_index)) { + DPRINTF("invalid sector_index=%d"DCRLF, sector_index); + return false; + } + + SOF_DevHandle_t hdev = SOF_dev_open(sector_index); + + if (hdev == SOF_INVALID_HANDLE) { + DPRINTF("SOF_dev_open(%d) failed"DCRLF, sector_index); + return false; + } + + DPRINTF("Flash erase %d"DCRLF, sector_index); + SOF_dev_erase(hdev); + create_empty_storage(hdev, sector_index); + SOF_dev_close(hdev); + + return true; +} + +SOF_BlockHandle_t SOF_block_open_storage(uint8_t sector_index, SOF_Error_t *err) +{ + if (!SOF_dev_is_valid_sector(sector_index)) { + DPRINTF("invalid sector_index=%d"DCRLF, sector_index); + return false; + } + + SOF_DevHandle_t hdev = SOF_dev_open(sector_index); + + if (hdev == SOF_INVALID_HANDLE) { + DPRINTF("SOF_dev_open(%d) failed"DCRLF, sector_index); + return false; + } + + SOF_BlockHandle_t handle = new SOF_BlockHandle(); + + handle->hdev_ = hdev; + + StorageInfo_t storage_info; + + if ((*err=probe_active_storage_info(handle, &storage_info)) != kSOF_ErrNone) { + delete handle; + return NULL; + } + + uint32_t info_begin_offset; + + if (!get_empty_info_location(handle, &info_begin_offset)) { + *err = kSOF_ErrBadBlock; + delete handle; + return NULL; + } + + // set max offset that storage grows. + handle->storage_max_offset_ = info_begin_offset; + + handle->storage_begin_offset_ = storage_info.begin_offset; + handle->storage_end_offset_ = storage_info.begin_offset + storage_info.len; + + handle->cur_pos_ = handle->storage_begin_offset_; + + DPRINTF("open for read: begin=%d end=%d len=%d free=%d"DCRLF, + handle->storage_begin_offset_, handle->storage_end_offset_, storage_info.len, + SOF_block_get_free_size(handle)); + if (compute_storage_checksum(handle) != storage_info.storage_csum) { + EPRINTF("checksum error %#x != %#x"DCRLF, compute_storage_checksum(handle), storage_info.storage_csum); + *err = kSOF_ErrDataCurrupted; + delete handle; + return NULL; + } + + DUMP_BLOCK(handle); + *err = kSOF_ErrNone; + + return handle; +} + +SOF_BlockHandle_t SOF_block_create_storage(uint8_t sector_index, SOF_Error_t *err) +{ + if (!SOF_dev_is_valid_sector(sector_index)) { + DPRINTF("invalid sector_index=%d"DCRLF, sector_index); + return false; + } + + SOF_DevHandle_t hdev = SOF_dev_open(sector_index); + + if (hdev == SOF_INVALID_HANDLE) { + DPRINTF("SOF_dev_open(%d) failed"DCRLF, sector_index); + return false; + } + + SOF_BlockHandle_t handle = new SOF_BlockHandle(); + + handle->hdev_ = hdev; + + StorageInfo_t storage_info; + + if ((*err=probe_active_storage_info(handle, &storage_info)) != kSOF_ErrNone) { + delete handle; + return NULL; + } + + uint32_t info_begin_offset; + + if (!get_empty_info_location(handle, &info_begin_offset)) { + *err = kSOF_ErrBadBlock; + delete handle; + return NULL; + } + + // set max offset that storage grows. + handle->storage_max_offset_ = info_begin_offset; + + // writing position is just after previous storage + handle->storage_begin_offset_ = storage_info.begin_offset + storage_info.len; + handle->storage_end_offset_ = handle->storage_begin_offset_; + + handle->cur_pos_ = handle->storage_begin_offset_; + handle->write_mode_ = true; + DPRINTF("open for write: begin=%d end=%d free=%d"DCRLF, + handle->storage_begin_offset_, handle->storage_end_offset_, SOF_block_get_free_size(handle)); + + DUMP_BLOCK(handle); + *err = kSOF_ErrNone; + + return handle; +} + +bool SOF_block_close(SOF_BlockHandle_t handle) +{ + bool r = true; + + DASSERT(handle != NULL); + if (handle->write_mode_) + r = (bool)write_storage_info(handle); + SOF_dev_close(handle->hdev_); + delete handle; + + return r; +} + +uint8_t *SOF_block_base_addr(SOF_BlockHandle_t handle) +{ + DASSERT(handle != NULL); + return SOF_dev_get_hw_addr(handle->hdev_) + handle->cur_pos_; +} + +bool SOF_block_putc(SOF_BlockHandle_t handle, uint8_t c) +{ + DASSERT(handle != NULL); + DASSERT(handle->is_writable()); + + if (SOF_block_get_free_size(handle) == 0) { + DPRINTF("no free space"DCRLF); + DUMP_BLOCK(handle); + + return false; + } + + bool b = SOF_dev_write_byte(handle->hdev_, handle->cur_pos_, c) != -1; + if (b) { + handle->cur_pos_++; + handle->storage_end_offset_++; + } + + return b; +} + +size_t SOF_block_write(SOF_BlockHandle_t handle, const uint8_t *p, size_t p_size) +{ + size_t i; + + for (i = 0; i < p_size; ++i) + if (SOF_block_putc(handle, *p++) != true) + return i; + + return i; +} + +bool SOF_block_getc(SOF_BlockHandle_t handle, uint8_t *c) +{ + DASSERT(handle != NULL); + DASSERT(handle->is_writable()); + + if (handle->cur_pos_ >= handle->storage_end_offset_) { + DPRINTF("end of data\n"DCRLF); + DUMP_BLOCK(handle); + + return false; + } + + *c = SOF_dev_read_byte(handle->hdev_, handle->cur_pos_++); + + return true; +} + +size_t SOF_block_read(SOF_BlockHandle_t handle, uint8_t *p, size_t p_size) +{ + size_t i; + + for (i = 0; i < p_size; ++i) + if (!SOF_block_getc(handle, p++)) + break; + + return i; +} + +SOF_Error_t SOF_block_get_statics(uint8_t sector_index, SOF_Statics_t *stat) +{ + if (!SOF_dev_is_valid_sector(sector_index)) { + DPRINTF("invalid sector_index=%d"DCRLF, sector_index); + return kSOF_ErrParam; + } + + SOF_Error_t err; + SOF_BlockHandle_t hblk = SOF_block_open_storage(sector_index, &err); + + if (hblk == NULL) { + DPRINTF("SOF_block_open_storage(%d) failed"DCRLF, sector_index); + return err; + } + + stat->data_addr = SOF_block_base_addr(hblk); + stat->data_size = SOF_block_storage_size(hblk); + stat->free_size = SOF_block_get_free_size(hblk); + + SOF_block_close(hblk); + + return kSOF_ErrNone; +} + +const SOF_SectorSpec_t *SOF_block_get_info(uint8_t sector_index) +{ + if (!SOF_dev_is_valid_sector(sector_index)) { + DPRINTF("invalid sector_index=%d"DCRLF, sector_index); + return NULL; + } + + return SOF_dev_info_by_index(sector_index); +} + + +
diff -r 000000000000 -r 4cb438b58dc2 SOF_dev.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SOF_dev.h Fri Nov 18 14:37:15 2016 +0000 @@ -0,0 +1,82 @@ +/** +* @file SOF_dev.c +* +* @author hillkim7@gmail.com +* @brief Storage On Flash device interface +* +*/ + +#pragma once + +#include <stdint.h> +#include <stddef.h> + +/** The default value of erased flash memory */ +#define SOF_ERASED_BYTE_VALUE 0xFF + +#define SOF_INVALID_HANDLE 0xFFFFFFFF + +/** Error code definition */ +typedef enum { + kSOF_ErrNone = 0, + kSOF_ErrParam, + kSOF_ErrNoInfo, + kSOF_ErrBusyBlock, + kSOF_ErrBadBlock, + kSOF_ErrDataCurrupted, + kSOF_ErrFatal, +} SOF_Error_t;; + +/** Flash sector specification */ +typedef struct { + uint32_t sec_no; + uint32_t sec_addr; + uint32_t sec_size; +} SOF_SectorSpec_t; + +/** statics of SOF block */ +typedef struct { + uint8_t *data_addr; + uint32_t data_size; + uint32_t free_size; +} SOF_Statics_t; + +typedef uint32_t SOF_DevHandle_t; + +class SOF_BlockHandle; +typedef SOF_BlockHandle* SOF_BlockHandle_t; + +/*-----------------------------------------------------------------------------------------------------*/ +/* Flash device interface */ +/*-----------------------------------------------------------------------------------------------------*/ +int SOF_dev_is_valid_sector(uint8_t sector_index); +const SOF_SectorSpec_t *SOF_dev_info(SOF_DevHandle_t hdev); +const SOF_SectorSpec_t *SOF_dev_info_by_index(uint8_t sector_index); +SOF_DevHandle_t SOF_dev_open(uint8_t sector_index); +void SOF_dev_close(SOF_DevHandle_t hdev); +uint8_t *SOF_dev_get_hw_addr(SOF_DevHandle_t hdev); +void SOF_dev_erase(SOF_DevHandle_t handle); +int SOF_dev_write_word(SOF_DevHandle_t handle, uint32_t offset_addr, uint32_t data); +uint32_t SOF_dev_read_word(SOF_DevHandle_t handle, uint32_t offset_addr); +int SOF_dev_write_byte(SOF_DevHandle_t handle, uint32_t offset_addr, uint8_t data); +uint8_t SOF_dev_read_byte(SOF_DevHandle_t handle, uint32_t offset_addr); + +/*-----------------------------------------------------------------------------------------------------*/ +/* Flash block device interface */ +/*-----------------------------------------------------------------------------------------------------*/ +bool SOF_block_format(uint8_t sector_index); +SOF_BlockHandle_t SOF_block_open_storage(uint8_t sector_index, SOF_Error_t *err); +SOF_BlockHandle_t SOF_block_create_storage(uint8_t sector_index, SOF_Error_t *err); +bool SOF_block_close(SOF_BlockHandle_t handle); +uint8_t *SOF_block_base_addr(SOF_BlockHandle_t handle); +bool SOF_block_putc(SOF_BlockHandle_t handle, uint8_t c); +size_t SOF_block_write(SOF_BlockHandle_t handle, const uint8_t *p, size_t p_size); +bool SOF_block_getc(SOF_BlockHandle_t handle, uint8_t *c); +size_t SOF_block_read(SOF_BlockHandle_t handle, uint8_t *p, size_t p_size); +size_t SOF_block_get_free_size(SOF_BlockHandle_t handle); +uint32_t SOF_block_storage_size(SOF_BlockHandle_t handle); +SOF_Error_t SOF_block_get_statics(uint8_t sector_index, SOF_Statics_t *stat); +const SOF_SectorSpec_t *SOF_block_get_info(uint8_t sector_index); + + +
diff -r 000000000000 -r 4cb438b58dc2 SOF_dev_stm32_f4xx.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SOF_dev_stm32_f4xx.cpp Fri Nov 18 14:37:15 2016 +0000 @@ -0,0 +1,186 @@ +/** +* @file SOF_dev_stm32.c +* +* @brief Flash device access interface for STM32 F4xx series +* +* +* History: +*/ + +#include <stdio.h> +#include "SOF_dev.h" +#include <string.h> + +#include "mbed.h" +#include "stm32f4xx_hal_flash.h" + +#define DCRLF "\r\n" + +#if 0 +#define DPRINTF printf +#define DASSERT(cond) \ + if (!(cond)) { \ + printf("%s:%d assertion failed! '%s\r\n"\ + , __FILE__, __LINE__, #cond); \ + } +#else +#define DPRINTF(...) +#define DASSERT(...) +#endif + + +#if defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F407xx) +static const SOF_SectorSpec_t _sec_spec[] = { + {FLASH_SECTOR_0, 0x08000000, 16*1024}, + {FLASH_SECTOR_1, 0x08004000, 16*1024}, + {FLASH_SECTOR_2, 0x08008000, 16*1024}, + {FLASH_SECTOR_3, 0x0800C000, 16*1024}, + {FLASH_SECTOR_4, 0x08010000, 64*1024}, + {FLASH_SECTOR_5, 0x08020000, 128*1024}, + {FLASH_SECTOR_6, 0x08040000, 128*1024}, + {FLASH_SECTOR_7, 0x08060000, 128*1024}, +}; +#else +#error "Not supported device" +#endif + +#define N_SECTOR_SPEC (sizeof(_sec_spec)/sizeof(_sec_spec[0])) + +#define SECTOR_NO(sector) _sec_spec[sector].sec_no +#define SECTOR_ADDR(sector) _sec_spec[sector].sec_addr +#define SECTOR_SIZE(sector) _sec_spec[sector].sec_size + + +static inline size_t handle_to_sector_index(SOF_DevHandle_t hdev) +{ + DASSERT(hdev < N_SECTOR_SPEC); + return hdev; +} + +const SOF_SectorSpec_t *SOF_dev_info(uint8_t sector_index) +{ + DASSERT(sector_index < N_SECTOR_SPEC); + return &_sec_spec[sector_index]; +} + +int SOF_dev_is_valid_sector(uint8_t sector_index) +{ + return sector_index < N_SECTOR_SPEC; +} + +const SOF_SectorSpec_t *SOF_dev_info_by_index(uint8_t sector_index) +{ + DASSERT(SOF_dev_is_valid_sector(sector_index)); + return &_sec_spec[sector_index]; +} + +const SOF_SectorSpec_t *SOF_dev_info(SOF_DevHandle_t hdev) +{ + uint8_t sector_index = handle_to_sector_index(hdev); + + return SOF_dev_info_by_index(sector_index); +} + +SOF_DevHandle_t SOF_dev_open(uint8_t sector_index) +{ + DASSERT(sector_index < N_SECTOR_SPEC); + return (SOF_DevHandle_t)sector_index; +} + +void SOF_dev_close(SOF_DevHandle_t hdev) +{ +} + +uint8_t *SOF_dev_get_hw_addr(SOF_DevHandle_t hdev) +{ + uint8_t sector_index = handle_to_sector_index(hdev); + + return (uint8_t *)SECTOR_ADDR(sector_index); +} + + +void SOF_dev_erase(SOF_DevHandle_t hdev) +{ + uint8_t sector_index = handle_to_sector_index(hdev); + FLASH_EraseInitTypeDef ei; + uint32_t error = 0; + + DPRINTF("FLASH_Erase_Sector %d"DCRLF, SECTOR_NO(sector_index)); + HAL_FLASH_Unlock(); + + ei.TypeErase = TYPEERASE_SECTORS; + ei.Sector = SECTOR_NO(sector_index); + ei.NbSectors = 1; + ei.Banks = 0; + ei.VoltageRange = VOLTAGE_RANGE_3; + HAL_FLASHEx_Erase(&ei, &error); + HAL_FLASH_Lock(); + DPRINTF("FLASH_Erase_Sector ok"DCRLF); +} + + +int SOF_dev_write_word(SOF_DevHandle_t hdev, uint32_t offset_addr, uint32_t data) +{ + uint8_t sector_index = handle_to_sector_index(hdev); + uint32_t dst = SECTOR_ADDR(sector_index) + offset_addr; + + DASSERT((offset_addr%sizeof(uint32_t)) == 0); + HAL_FLASH_Unlock(); + if (HAL_FLASH_Program(TYPEPROGRAM_WORD, dst, data) != HAL_OK) { + DPRINTF("FLASH_ProgramWord failed: %#x"DCRLF, dst); + HAL_FLASH_Lock(); + return -1; + } + + HAL_FLASH_Lock(); + + if (data != SOF_dev_read_word(hdev, offset_addr)) { + DPRINTF("addr=%x %#04x %#04x"DCRLF, dst, data, SOF_dev_read_word(hdev, offset_addr)); + return -1; + } + + return 0; +} + +uint32_t SOF_dev_read_word(SOF_DevHandle_t hdev, uint32_t offset_addr) +{ + uint8_t sector_index = handle_to_sector_index(hdev); + uint32_t src = SECTOR_ADDR(sector_index) + offset_addr; + + DASSERT((offset_addr%sizeof(uint32_t)) == 0); + + return *(volatile uint32_t*)src; +} + +int SOF_dev_write_byte(SOF_DevHandle_t hdev, uint32_t offset_addr, uint8_t data) +{ + uint8_t sector_index = handle_to_sector_index(hdev); + uint32_t dst = SECTOR_ADDR(sector_index) + offset_addr; + + HAL_FLASH_Unlock(); + if (HAL_FLASH_Program(TYPEPROGRAM_BYTE, dst, data) != HAL_OK) { + DPRINTF("FLASH_ProgramWord failed: %#x"DCRLF, dst); + HAL_FLASH_Lock(); + return -1; + } + + HAL_FLASH_Lock(); + + if (data != SOF_dev_read_byte(hdev, offset_addr)) { + DPRINTF("addr=%x %#02x %#02x"DCRLF, dst, data, SOF_dev_read_byte(hdev, offset_addr)); + return -1; + } + + return 0; +} + +uint8_t SOF_dev_read_byte(SOF_DevHandle_t hdev, uint32_t offset_addr) +{ + uint8_t sector_index = handle_to_sector_index(hdev); + uint32_t src = SECTOR_ADDR(sector_index) + offset_addr; + + return *(volatile uint8_t*)src; +} + + +