The Flash Safe package provides a robust and simple mechanism for storing data in flash memory. It is intended for relatively small quantities of data such as configuration and customization data. For larger amounts of data, the JFFS2 flash filesystem is available.
The Flash Safe operates by dividing a region of the flash into a number of equal sized blocks. Each block is given a sequence number and is checksummed. A header containing these is stored at the start and end of each block. At startup the Flash Safe searches the available blocks for one with the latest sequence number and a valid checksum. The application can now retrieve data stored in the Flash Safe against a numeric key.
To store new data, the application opens a block, which will cause the block with the oldest sequence number to be erased and prepared for writing. Data can now be written to the block with a numeric key identifying each write. When all the data has been written, the block is committed, which will cause the headers to be written with valid checksums. This block now becomes the source of all subsequent data retrieval, freeing the original valid block for reuse.
This approach provides a simple transactional mechanism for storing data across power failures and crashes. At any time at least one committed block is valid and is released only after a new valid block has been committed to replace it. Any interruption during the creation of a new block will leave it invalid and data retrieval will fall back to the last committed block. The use of keys to identify data makes retrieval independent of the order in which the items are stored, of any change in size of the data and of any alignment requirements of the underlying flash device and driver.
The Flash Safe needs a minimum of two blocks to be defined, which must each be a multiple of the block size of the underlying flash device. A single Flash Safe block per flash device block would be the normal approach. More Flash Safe blocks may be used to implement a crude wear levelling mechanism, since under normal circumstances the Flash Safe will use the blocks in a round-robin manner.
The flashsafe is mostly configured at runtime. The following CDL configuration options are present:
This option defines the size of the buffer that the flashsafe uses to store data prior to writing it to disk. Different flash devices have different alignment and minimum sizes for writes to the flash. This buffer collects data items into segments that can be written in single operations.
A flashsafe block can be viewed as an array of segments of CYGNUM_FLASHSAFE_BUFFER_SIZE bytes each. The first and last segments are reserved for the flashsafe system's use, and the rest are available for data storage. So the buffer size may be at most one third the size of the block. The buffer size should also be chosen to be an integer fraction of the block size. It is not possible to change the buffer size once a flashsafe has been initialized, since it plays a part in defining the format of the stored data.
This lists the set of test programs. At present there is only one test, which runs on the synthetic target.
Interaction with RedBoot
The Flash Safe is mainly targetted at small systems where a FIS directory or JFFS2 would not be appropriate. Consequently it does not try to look up a named entry in the FIS or work via the flash IO device. Instead it uses raw flash block addresses. The flashsafe parameters can be set up at runtime by the application querying the RedBoot FIS interface, and the flash subsystem. The following code extract demonstrates how this might be done.
cyg_flashsafe flashsafe; cyg_flash_info_t flashinfo; cyg_uint32 size; int err; // Initialize flash system err = cyg_flash_init(diag_printf); if( err != CYG_FLASH_ERR_OK ) ... // Fetch flashsafe region base and size from FIS directory. err = CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, "flashsafe", &flashsafe.base); if( err == 0 ) ... err = CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, "flashsafe", &size); if( err == 0 ) ... // Fetch flash device info from flash system err = cyg_flash_get_info_addr( flashsafe.base, &flashinfo ); if( err != CYG_FLASH_ERR_OK ) ... // Calculate block number and size. flashsafe.block_size = flashinfo.block_info.block_size; flashsafe.block_count = size/flashsafe.block_size; err = cyg_flashsafe_init( &flashsafe ); if(err != CYG_FLASHSAFE_ERR_OK) ...