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.

Committer:
hillkim7
Date:
Wed Mar 25 05:46:25 2015 +0000
Revision:
3:2bb58064d0a2
Parent:
2:e79a9cb05801
Fix comment.

Who changed what in which revision?

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