Tiny storage(file) system on MCU internal flash memory for Nucleo F4xx. 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.
Dependents: storage_on_flash_demo mbed_controller_demo mbed-os-example-blinky-2
March 26, 2015
Seeed Arch Max platform which is based on STM32-F407 is supported.
SOFBlock.h@0:7f4bc855cb46, 2015-01-19 (annotated)
- Committer:
- hillkim7
- Date:
- Mon Jan 19 12:57:44 2015 +0000
- Revision:
- 0:7f4bc855cb46
- Child:
- 1:33afe074c8f8
Tiny storage(file) system on MCU internal flash for Nucleo F4xx.; 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.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hillkim7 | 0:7f4bc855cb46 | 1 | /** |
hillkim7 | 0:7f4bc855cb46 | 2 | * @file SOFBlock.h |
hillkim7 | 0:7f4bc855cb46 | 3 | * |
hillkim7 | 0:7f4bc855cb46 | 4 | * @author hillkim7@gmail.com |
hillkim7 | 0:7f4bc855cb46 | 5 | * @brief Simple storage implementation on internal MCU flash memory. |
hillkim7 | 0:7f4bc855cb46 | 6 | |
hillkim7 | 0:7f4bc855cb46 | 7 | The SOF in SOFBlock is abbreviation of "Storage On Flash". |
hillkim7 | 0:7f4bc855cb46 | 8 | The purpose of SOFBlock class is to provide a way to write data on flash memory |
hillkim7 | 0:7f4bc855cb46 | 9 | in the same way of file handling class in the file system. |
hillkim7 | 0:7f4bc855cb46 | 10 | It manages a chunk of data on the Flash memory efficiently by minimizing flash erase operation as little as possible. |
hillkim7 | 0:7f4bc855cb46 | 11 | Note: Currently I only support STM32F4xx series platforms. |
hillkim7 | 0:7f4bc855cb46 | 12 | |
hillkim7 | 0:7f4bc855cb46 | 13 | The STM32 F4xx series from ST have plenty of internal Flash memory inside MCU core. |
hillkim7 | 0:7f4bc855cb46 | 14 | For example STM32 401RE has 512Kbyts Flash. |
hillkim7 | 0:7f4bc855cb46 | 15 | Typical size of firmware file is less than 256KB, so remaining area is free to use. |
hillkim7 | 0:7f4bc855cb46 | 16 | The simplest way of flash utilization as data storage is to use a chunk of Flash area as an unit of storage. |
hillkim7 | 0:7f4bc855cb46 | 17 | A block of Flash is called sector in STM32 domain. It requires to erase a sector before update bits in Flash. |
hillkim7 | 0:7f4bc855cb46 | 18 | |
hillkim7 | 0:7f4bc855cb46 | 19 | Conceptually it is quite simple. |
hillkim7 | 0:7f4bc855cb46 | 20 | Here is write operation: |
hillkim7 | 0:7f4bc855cb46 | 21 | 1) Erase sector #n |
hillkim7 | 0:7f4bc855cb46 | 22 | 2) Write data to sector #n |
hillkim7 | 0:7f4bc855cb46 | 23 | Read operation: |
hillkim7 | 0:7f4bc855cb46 | 24 | 1) Just read physical memory address of sector #n |
hillkim7 | 0:7f4bc855cb46 | 25 | The base address of STM32 Flash is 0x00000000. |
hillkim7 | 0:7f4bc855cb46 | 26 | |
hillkim7 | 0:7f4bc855cb46 | 27 | There may be inefficiency in this Flash usage scenario when size of data is too small compared with sector size. |
hillkim7 | 0:7f4bc855cb46 | 28 | The size of sectors from #5 to #7 of STM32 401RE Flash 128KB. If I only need to maintain 1KB data, |
hillkim7 | 0:7f4bc855cb46 | 29 | whenever I need to update data I need to erase whole 128KB of sector. |
hillkim7 | 0:7f4bc855cb46 | 30 | This produces two problems. |
hillkim7 | 0:7f4bc855cb46 | 31 | One is time consumption of erase operation. The operation of ERASE128KB takes 1~4 seconds long. |
hillkim7 | 0:7f4bc855cb46 | 32 | The other is lifetime of Flash memory. More you erase and write and lifetime of Flash is shorter. |
hillkim7 | 0:7f4bc855cb46 | 33 | |
hillkim7 | 0:7f4bc855cb46 | 34 | To overcome such problem, here simple flash management algorithm is used for. |
hillkim7 | 0:7f4bc855cb46 | 35 | By tracking data offset and size it can hold multiple data in a sector. Bear in mind that is impossible rewriting data on Flash. |
hillkim7 | 0:7f4bc855cb46 | 36 | Keeping tracking data along with data itself is crucial. |
hillkim7 | 0:7f4bc855cb46 | 37 | Data itself is growing from low address. On the other hand tracking data is growing down from high address. |
hillkim7 | 0:7f4bc855cb46 | 38 | Let's assume the size of data is 1KB and store it in sector #6 which address range is from 0x08040000 to 0x0805ffff. |
hillkim7 | 0:7f4bc855cb46 | 39 | +-------------+----------------------------------------------------------------------+-----+ |
hillkim7 | 0:7f4bc855cb46 | 40 | <data> <tracking data> |
hillkim7 | 0:7f4bc855cb46 | 41 | +-------------+----------------------------------------------------------------------+-----+ |
hillkim7 | 0:7f4bc855cb46 | 42 | data grows -> <- tracking data grows |
hillkim7 | 0:7f4bc855cb46 | 43 | Writing data will be placed at the end of data always and reading data will pick the last data. |
hillkim7 | 0:7f4bc855cb46 | 44 | It is like simple file system that only keep a file only. |
hillkim7 | 0:7f4bc855cb46 | 45 | */ |
hillkim7 | 0:7f4bc855cb46 | 46 | |
hillkim7 | 0:7f4bc855cb46 | 47 | #pragma once |
hillkim7 | 0:7f4bc855cb46 | 48 | |
hillkim7 | 0:7f4bc855cb46 | 49 | #include "SOF_dev.h" |
hillkim7 | 0:7f4bc855cb46 | 50 | |
hillkim7 | 0:7f4bc855cb46 | 51 | /** SOF(Storage On Flash) usage example |
hillkim7 | 0:7f4bc855cb46 | 52 | * |
hillkim7 | 0:7f4bc855cb46 | 53 | * Example: |
hillkim7 | 0:7f4bc855cb46 | 54 | * @code |
hillkim7 | 0:7f4bc855cb46 | 55 | #include "mbed.h" |
hillkim7 | 0:7f4bc855cb46 | 56 | #include "SOFBlock.h" |
hillkim7 | 0:7f4bc855cb46 | 57 | |
hillkim7 | 0:7f4bc855cb46 | 58 | int main() |
hillkim7 | 0:7f4bc855cb46 | 59 | { |
hillkim7 | 0:7f4bc855cb46 | 60 | const uint8_t sector_index = 7; |
hillkim7 | 0:7f4bc855cb46 | 61 | SOFBlock::format(sector_index); // Erase flash sector 7 and make structure for storage. |
hillkim7 | 0:7f4bc855cb46 | 62 | |
hillkim7 | 0:7f4bc855cb46 | 63 | SOFWriter writer; |
hillkim7 | 0:7f4bc855cb46 | 64 | SOFReader reader; |
hillkim7 | 0:7f4bc855cb46 | 65 | |
hillkim7 | 0:7f4bc855cb46 | 66 | writer.open(sector_index) ; |
hillkim7 | 0:7f4bc855cb46 | 67 | writer.write_data((uint8_t*)"First Data", 10); |
hillkim7 | 0:7f4bc855cb46 | 68 | writer.close(); |
hillkim7 | 0:7f4bc855cb46 | 69 | |
hillkim7 | 0:7f4bc855cb46 | 70 | reader.open(sector_index); |
hillkim7 | 0:7f4bc855cb46 | 71 | printf("data %d bytes at %p :\r\n", reader.get_data_size(), reader.get_physical_base_addr()); |
hillkim7 | 0:7f4bc855cb46 | 72 | printf("%.*s\r\n", reader.get_data_size(), reader.get_physical_base_addr()); |
hillkim7 | 0:7f4bc855cb46 | 73 | // "First Data" printed |
hillkim7 | 0:7f4bc855cb46 | 74 | reader.close(); |
hillkim7 | 0:7f4bc855cb46 | 75 | |
hillkim7 | 0:7f4bc855cb46 | 76 | writer.open(sector_index) ; |
hillkim7 | 0:7f4bc855cb46 | 77 | // Overwrite previous data without erasing flash. |
hillkim7 | 0:7f4bc855cb46 | 78 | writer.write_data((uint8_t*)"Second Data", 11); |
hillkim7 | 0:7f4bc855cb46 | 79 | writer.close(); |
hillkim7 | 0:7f4bc855cb46 | 80 | |
hillkim7 | 0:7f4bc855cb46 | 81 | reader.open(sector_index); |
hillkim7 | 0:7f4bc855cb46 | 82 | printf("data %d bytes at %p :\r\n", reader.get_data_size(), reader.get_physical_base_addr()); |
hillkim7 | 0:7f4bc855cb46 | 83 | printf("%.*s\r\n", reader.get_data_size(), reader.get_physical_base_addr()); |
hillkim7 | 0:7f4bc855cb46 | 84 | // "Second Data" printed |
hillkim7 | 0:7f4bc855cb46 | 85 | reader.close(); |
hillkim7 | 0:7f4bc855cb46 | 86 | } |
hillkim7 | 0:7f4bc855cb46 | 87 | |
hillkim7 | 0:7f4bc855cb46 | 88 | */ |
hillkim7 | 0:7f4bc855cb46 | 89 | |
hillkim7 | 0:7f4bc855cb46 | 90 | /** |
hillkim7 | 0:7f4bc855cb46 | 91 | * Base class of SOF(Storage On Flash) |
hillkim7 | 0:7f4bc855cb46 | 92 | */ |
hillkim7 | 0:7f4bc855cb46 | 93 | class SOFBlock |
hillkim7 | 0:7f4bc855cb46 | 94 | { |
hillkim7 | 0:7f4bc855cb46 | 95 | public: |
hillkim7 | 0:7f4bc855cb46 | 96 | SOFBlock(); |
hillkim7 | 0:7f4bc855cb46 | 97 | |
hillkim7 | 0:7f4bc855cb46 | 98 | virtual ~SOFBlock(); |
hillkim7 | 0:7f4bc855cb46 | 99 | |
hillkim7 | 0:7f4bc855cb46 | 100 | void close(); |
hillkim7 | 0:7f4bc855cb46 | 101 | |
hillkim7 | 0:7f4bc855cb46 | 102 | public: |
hillkim7 | 0:7f4bc855cb46 | 103 | bool is_open() const { return hblock_ != NULL; } |
hillkim7 | 0:7f4bc855cb46 | 104 | |
hillkim7 | 0:7f4bc855cb46 | 105 | public: |
hillkim7 | 0:7f4bc855cb46 | 106 | /*** erase flash sector and put signature to setup struct */ |
hillkim7 | 0:7f4bc855cb46 | 107 | static bool format(uint8_t sector_index); |
hillkim7 | 0:7f4bc855cb46 | 108 | |
hillkim7 | 0:7f4bc855cb46 | 109 | protected: |
hillkim7 | 0:7f4bc855cb46 | 110 | SOF_BlockHandle_t hblock_; |
hillkim7 | 0:7f4bc855cb46 | 111 | }; |
hillkim7 | 0:7f4bc855cb46 | 112 | |
hillkim7 | 0:7f4bc855cb46 | 113 | |
hillkim7 | 0:7f4bc855cb46 | 114 | /** |
hillkim7 | 0:7f4bc855cb46 | 115 | * It provides interface for writing data to flash memory. |
hillkim7 | 0:7f4bc855cb46 | 116 | */ |
hillkim7 | 0:7f4bc855cb46 | 117 | class SOFWriter : public SOFBlock |
hillkim7 | 0:7f4bc855cb46 | 118 | { |
hillkim7 | 0:7f4bc855cb46 | 119 | public: |
hillkim7 | 0:7f4bc855cb46 | 120 | SOFWriter(); |
hillkim7 | 0:7f4bc855cb46 | 121 | virtual ~SOFWriter(); |
hillkim7 | 0:7f4bc855cb46 | 122 | |
hillkim7 | 0:7f4bc855cb46 | 123 | /*** Open for writing mode */ |
hillkim7 | 0:7f4bc855cb46 | 124 | SOF_Error_t open(uint8_t sector_index); |
hillkim7 | 0:7f4bc855cb46 | 125 | |
hillkim7 | 0:7f4bc855cb46 | 126 | /*** Return max available for writing */ |
hillkim7 | 0:7f4bc855cb46 | 127 | size_t get_free_size(); |
hillkim7 | 0:7f4bc855cb46 | 128 | |
hillkim7 | 0:7f4bc855cb46 | 129 | /*** Write one byte of data */ |
hillkim7 | 0:7f4bc855cb46 | 130 | bool write_byte_data(uint8_t c); |
hillkim7 | 0:7f4bc855cb46 | 131 | |
hillkim7 | 0:7f4bc855cb46 | 132 | /*** Write n bytes of data */ |
hillkim7 | 0:7f4bc855cb46 | 133 | size_t write_data(const uint8_t *p, size_t p_size); |
hillkim7 | 0:7f4bc855cb46 | 134 | }; |
hillkim7 | 0:7f4bc855cb46 | 135 | |
hillkim7 | 0:7f4bc855cb46 | 136 | |
hillkim7 | 0:7f4bc855cb46 | 137 | /** |
hillkim7 | 0:7f4bc855cb46 | 138 | * It provides interface for reading data from flash memory. |
hillkim7 | 0:7f4bc855cb46 | 139 | * It can read data directly by accessing physical flash address or |
hillkim7 | 0:7f4bc855cb46 | 140 | * calling function like traditional file API style. |
hillkim7 | 0:7f4bc855cb46 | 141 | */ |
hillkim7 | 0:7f4bc855cb46 | 142 | class SOFReader : public SOFBlock |
hillkim7 | 0:7f4bc855cb46 | 143 | { |
hillkim7 | 0:7f4bc855cb46 | 144 | public: |
hillkim7 | 0:7f4bc855cb46 | 145 | SOFReader(); |
hillkim7 | 0:7f4bc855cb46 | 146 | virtual ~SOFReader(); |
hillkim7 | 0:7f4bc855cb46 | 147 | |
hillkim7 | 0:7f4bc855cb46 | 148 | /*** Open for read mode */ |
hillkim7 | 0:7f4bc855cb46 | 149 | SOF_Error_t open(uint8_t sector_index); |
hillkim7 | 0:7f4bc855cb46 | 150 | |
hillkim7 | 0:7f4bc855cb46 | 151 | /*** Return flash physical address of data for direct access */ |
hillkim7 | 0:7f4bc855cb46 | 152 | uint8_t *get_physical_base_addr(); |
hillkim7 | 0:7f4bc855cb46 | 153 | |
hillkim7 | 0:7f4bc855cb46 | 154 | /*** Return data size */ |
hillkim7 | 0:7f4bc855cb46 | 155 | size_t get_data_size(); |
hillkim7 | 0:7f4bc855cb46 | 156 | |
hillkim7 | 0:7f4bc855cb46 | 157 | /*** Return one byte of data */ |
hillkim7 | 0:7f4bc855cb46 | 158 | bool read_byte_data(uint8_t *c); |
hillkim7 | 0:7f4bc855cb46 | 159 | |
hillkim7 | 0:7f4bc855cb46 | 160 | /*** Return n bytes of data */ |
hillkim7 | 0:7f4bc855cb46 | 161 | size_t read_data( uint8_t *p, size_t p_size); |
hillkim7 | 0:7f4bc855cb46 | 162 | }; |
hillkim7 | 0:7f4bc855cb46 | 163 |