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:27:59 2015 +0000
Revision:
2:e79a9cb05801
Parent:
1:33afe074c8f8
Child:
3:2bb58064d0a2
Support Seeed Arch Max platform; Modified to comply with mbed coding standard.

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 2:e79a9cb05801 28 * The size of sectors from #5 to #7 of STM32 401RE Flash 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 2:e79a9cb05801 36 * 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 2:e79a9cb05801 37 * Keeping tracking data along with data itself is crucial without frequent erase operation.
hillkim7 2:e79a9cb05801 38 * To do this, data itself is growing from low address. On the other hand tracking data is growing down from high address.
hillkim7 2:e79a9cb05801 39 * 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 40 * +-------------+----------------------------------------------------------------------+-----+
hillkim7 2:e79a9cb05801 41 * <data> <tracking data>
hillkim7 2:e79a9cb05801 42 * +-------------+----------------------------------------------------------------------+-----+
hillkim7 2:e79a9cb05801 43 * data grows -> <- tracking data grows
hillkim7 2:e79a9cb05801 44 * Writing data will be placed at the end of data always and reading data will pick the last data.
hillkim7 2:e79a9cb05801 45 * It is like simple file system that only keep a file only.
hillkim7 2:e79a9cb05801 46 *
hillkim7 2:e79a9cb05801 47 * Unlike file manipulation operation, there is caution you need to check if write operation fails
hillkim7 2:e79a9cb05801 48 * or need to check free size before you start to write data.
hillkim7 2:e79a9cb05801 49 * It is required to format flash sector when there is no more free space.
hillkim7 2:e79a9cb05801 50 */
hillkim7 0:7f4bc855cb46 51
hillkim7 0:7f4bc855cb46 52 #pragma once
hillkim7 0:7f4bc855cb46 53
hillkim7 0:7f4bc855cb46 54 #include "SOF_dev.h"
hillkim7 0:7f4bc855cb46 55
hillkim7 0:7f4bc855cb46 56 /** SOF(Storage On Flash) usage example
hillkim7 0:7f4bc855cb46 57 *
hillkim7 0:7f4bc855cb46 58 * Example:
hillkim7 0:7f4bc855cb46 59 * @code
hillkim7 2:e79a9cb05801 60 * #include "mbed.h"
hillkim7 2:e79a9cb05801 61 * #include "SOFBlock.h"
hillkim7 2:e79a9cb05801 62 *
hillkim7 2:e79a9cb05801 63 * int main()
hillkim7 2:e79a9cb05801 64 * {
hillkim7 2:e79a9cb05801 65 * const uint8_t sector_index = 7;
hillkim7 2:e79a9cb05801 66 * SOFBlock::format(sector_index); // Erase flash sector 7 and make structure for storage.
hillkim7 2:e79a9cb05801 67 *
hillkim7 2:e79a9cb05801 68 * SOFWriter writer;
hillkim7 2:e79a9cb05801 69 * SOFReader reader;
hillkim7 2:e79a9cb05801 70 *
hillkim7 2:e79a9cb05801 71 * writer.open(sector_index);
hillkim7 2:e79a9cb05801 72 * writer.write_data((uint8_t*)"First Data", 10);
hillkim7 2:e79a9cb05801 73 * writer.close();
hillkim7 2:e79a9cb05801 74 *
hillkim7 2:e79a9cb05801 75 * reader.open(sector_index);
hillkim7 2:e79a9cb05801 76 * printf("data %d bytes at %p :\r\n", reader.get_data_size(), reader.get_physical_base_addr());
hillkim7 2:e79a9cb05801 77 * printf("%.*s\r\n", reader.get_data_size(), reader.get_physical_base_addr());
hillkim7 2:e79a9cb05801 78 * // "First Data" printed
hillkim7 2:e79a9cb05801 79 * reader.close();
hillkim7 2:e79a9cb05801 80 *
hillkim7 2:e79a9cb05801 81 * SOF_Statics_t statics;
hillkim7 2:e79a9cb05801 82 * if (!SOFBlock(sector_index, statics) || statics.free_size < 11) { // check available byte
hillkim7 2:e79a9cb05801 83 * SOFBlock::format(sector_index);
hillkim7 2:e79a9cb05801 84 * }
hillkim7 2:e79a9cb05801 85 * writer.open(sector_index);
hillkim7 2:e79a9cb05801 86 * // Overwrite previous data without erasing flash.
hillkim7 2:e79a9cb05801 87 * writer.write_data((uint8_t*)"Second Data", 11);
hillkim7 2:e79a9cb05801 88 * writer.close();
hillkim7 2:e79a9cb05801 89 *
hillkim7 2:e79a9cb05801 90 * reader.open(sector_index);
hillkim7 2:e79a9cb05801 91 * printf("data %d bytes at %p :\r\n", reader.get_data_size(), reader.get_physical_base_addr());
hillkim7 2:e79a9cb05801 92 * printf("%.*s\r\n", reader.get_data_size(), reader.get_physical_base_addr());
hillkim7 2:e79a9cb05801 93 * // "Second Data" printed
hillkim7 2:e79a9cb05801 94 * reader.close();
hillkim7 2:e79a9cb05801 95 * }
hillkim7 2:e79a9cb05801 96 */
hillkim7 0:7f4bc855cb46 97
hillkim7 0:7f4bc855cb46 98 /**
hillkim7 2:e79a9cb05801 99 * Base class of SOF(Storage On Flash)
hillkim7 2:e79a9cb05801 100 */
hillkim7 0:7f4bc855cb46 101 class SOFBlock
hillkim7 0:7f4bc855cb46 102 {
hillkim7 0:7f4bc855cb46 103 public:
hillkim7 2:e79a9cb05801 104 SOFBlock();
hillkim7 0:7f4bc855cb46 105
hillkim7 2:e79a9cb05801 106 virtual ~SOFBlock();
hillkim7 0:7f4bc855cb46 107
hillkim7 2:e79a9cb05801 108 void close();
hillkim7 0:7f4bc855cb46 109
hillkim7 0:7f4bc855cb46 110 public:
hillkim7 2:e79a9cb05801 111 /*** Returns whether instance of SOFBlock is currently associated to flash storage. */
hillkim7 2:e79a9cb05801 112 bool is_open() const {
hillkim7 2:e79a9cb05801 113 return hblock_ != NULL;
hillkim7 2:e79a9cb05801 114 }
hillkim7 0:7f4bc855cb46 115
hillkim7 0:7f4bc855cb46 116 public:
hillkim7 2:e79a9cb05801 117 /*** Erase flash sector and put signature to setup file system struct */
hillkim7 2:e79a9cb05801 118 static bool format(uint8_t sector_index);
hillkim7 2:e79a9cb05801 119
hillkim7 2:e79a9cb05801 120 /*** Get statistics of storage */
hillkim7 2:e79a9cb05801 121 static bool get_stat(uint8_t sector_index, SOF_Statics_t &statics);
hillkim7 2:e79a9cb05801 122
hillkim7 0:7f4bc855cb46 123 protected:
hillkim7 2:e79a9cb05801 124 SOF_BlockHandle_t hblock_;
hillkim7 0:7f4bc855cb46 125 };
hillkim7 0:7f4bc855cb46 126
hillkim7 0:7f4bc855cb46 127
hillkim7 0:7f4bc855cb46 128 /**
hillkim7 2:e79a9cb05801 129 * It provides interface for writing data to flash memory.
hillkim7 2:e79a9cb05801 130 */
hillkim7 0:7f4bc855cb46 131 class SOFWriter : public SOFBlock
hillkim7 0:7f4bc855cb46 132 {
hillkim7 0:7f4bc855cb46 133 public:
hillkim7 2:e79a9cb05801 134 SOFWriter();
hillkim7 2:e79a9cb05801 135 virtual ~SOFWriter();
hillkim7 0:7f4bc855cb46 136
hillkim7 2:e79a9cb05801 137 /*** Open for writing mode */
hillkim7 2:e79a9cb05801 138 SOF_Error_t open(uint8_t sector_index);
hillkim7 2:e79a9cb05801 139
hillkim7 2:e79a9cb05801 140 /*** Return max available for writing */
hillkim7 2:e79a9cb05801 141 size_t get_free_size();
hillkim7 0:7f4bc855cb46 142
hillkim7 2:e79a9cb05801 143 /*** Write one byte of data.
hillkim7 2:e79a9cb05801 144 * Note: in case of storage full, it can't write data any more.
hillkim7 2:e79a9cb05801 145 * It is required to format sector and write it again.
hillkim7 2:e79a9cb05801 146 */
hillkim7 2:e79a9cb05801 147 bool write_byte_data(uint8_t c);
hillkim7 0:7f4bc855cb46 148
hillkim7 2:e79a9cb05801 149 /*** Write n bytes of data */
hillkim7 2:e79a9cb05801 150 size_t write_data(const uint8_t *p, size_t p_size);
hillkim7 0:7f4bc855cb46 151 };
hillkim7 0:7f4bc855cb46 152
hillkim7 0:7f4bc855cb46 153
hillkim7 0:7f4bc855cb46 154 /**
hillkim7 0:7f4bc855cb46 155 * It provides interface for reading data from flash memory.
hillkim7 0:7f4bc855cb46 156 * It can read data directly by accessing physical flash address or
hillkim7 0:7f4bc855cb46 157 * calling function like traditional file API style.
hillkim7 0:7f4bc855cb46 158 */
hillkim7 0:7f4bc855cb46 159 class SOFReader : public SOFBlock
hillkim7 0:7f4bc855cb46 160 {
hillkim7 0:7f4bc855cb46 161 public:
hillkim7 2:e79a9cb05801 162 SOFReader();
hillkim7 2:e79a9cb05801 163 virtual ~SOFReader();
hillkim7 0:7f4bc855cb46 164
hillkim7 2:e79a9cb05801 165 /*** Open for read mode */
hillkim7 2:e79a9cb05801 166 SOF_Error_t open(uint8_t sector_index);
hillkim7 0:7f4bc855cb46 167
hillkim7 2:e79a9cb05801 168 /*** Return flash physical address of data for direct access */
hillkim7 2:e79a9cb05801 169 uint8_t *get_physical_data_addr();
hillkim7 0:7f4bc855cb46 170
hillkim7 2:e79a9cb05801 171 /*** Return data size */
hillkim7 2:e79a9cb05801 172 size_t get_data_size();
hillkim7 0:7f4bc855cb46 173
hillkim7 2:e79a9cb05801 174 /*** Return one byte of data */
hillkim7 2:e79a9cb05801 175 bool read_byte_data(uint8_t *c);
hillkim7 0:7f4bc855cb46 176
hillkim7 2:e79a9cb05801 177 /*** Return n bytes of data */
hillkim7 2:e79a9cb05801 178 size_t read_data( uint8_t *p, size_t p_size);
hillkim7 0:7f4bc855cb46 179 };
hillkim7 0:7f4bc855cb46 180
hillkim7 2:e79a9cb05801 181