Page 1 of 1

Safely storing application settings in the flash

Posted: Tue 2021-02-23 12:47
by Panu
Saving application settings in the flash across power off conditions is a common need in VS1010 applications. There are two questions involved in implementing this functionality: 1) where to store the application settings in the RAM and 2) how to safely load and store that application state persistently.

To answer question 1, there's a fixed location in the X data memory of all VS1010 versions, that holds 33 16-bit words of free memory that your applications can use, share, save and restore. It's declared as struct device_descriptor console for reasons that are no longer relevant, and any ROM version in use today doesn't need it for anything (its original function has been superseded by the abstract FILE consoleFile in VSOS4 of the VS1010). You're entirely free to use it for storing some application data in a fixed location, namely addresses 111..134 in X data memory, which turns out to be very convenient.

The easiest way to use that memory area is to declare an array or a struct in a fixed location using LINK_ABS linker directive:

Code: Select all

LINK_ABS(myAppSettings,111) extern u_int16 myAppSettings[sizeof(console)]; //33 words
Since the location is fixed, the data is not lost when an executable terminates and thus the data can be shared between different DLX executables, which is a great way to extend the limited program memory of the VS1010. You can split a large application into several DLX executables and include a similar declaration in each executable. Each separate executable can then hold some key information such as a song number or position, volume settings, etc., without them being overwritten when the running application changes.

Saving to flash

The second question is how to save and restore this information across power-off cycles. Saving it to a settings file in the SPI flash using fwrite is possible, but not recommended, because fwriting to the flash during device's normal operation is inherently unsafe and can cause catastrophic firmware corruption if the power is lost during FAT directory updates, for instance.

Instead, the method presented here uses a fixed location in the flash, outside the S: system disk, to save the data. This way the S: partition in the flash is not touched at all and there's very little chance of it being corrupted.

The SPI flash layout in VS1010 is quite simple. The first 64 kilobytes are reserved for booting and usually are not used at all in VS1010 products. The rest of the SPI flash is either empty or contains a FAT partition that can be used as the S: system disk or for general storage.

The VS1010 normally detects the SPI flash automatically and can access the FAT partition and boot directly from there. Boot records at the very beginning of the SPI flash are only needed if the SPI flash cannot be accessed using normal methods and a custom flash storage driver needs to be loaded into RAM before booting.

The VS1010 treats the first 64 kilobytes of the SPI flash as 128 sectors of 512 bytes each. Generally, the SPI flash can be erased in groups of 8 sectors or 4 kilobytes at a time. This software uses the last 4 kilobytes before the beginning of the FAT partition (sectors 120..127) to store the user's application settings.

Here's the function that saves the application settings from the console data area to the flash:

Code: Select all

LINK_ABS(myAppSettings,111) extern u_int16 myAppSettings[33]; 

ioresult SaveSettings (char *params) {
	Erase4K (&spiBus, 120); // Use 4K block at 60K..63K (sectors 120..127), FAT starts at 64K (physical sector 128)
	Program4K(&spiBus, 120, myAppSettings); //Write application settings to flash.	
	return S_OK;
And here's the function for loading the application settings from the flash:

Code: Select all

LINK_ABS(myAppSettings,111) extern u_int16 myAppSettings[33];

ioresult LoadSettings (char *params) {
	u_int16 buf[256]; // allocate space for one sector buffer from stack
	BlockRead(&spiBus, 120, buf); //read one disk sector to buffer
	memcpy (myAppSettings, buf, 33); //copy 33 words to the console data area
For the full source code, please see downloads below.

For your convenience, I have written two programs, savesettings.dlx and loadsettings.dlx that you can use to save and load the area. Here's an example where the first word of the application settings, located in X memory addres 111 decimal, is first changed to 5, then saved, then changed to 8, then loaded, and finally checked that it's 5 again, after being read back from the flash.
VS1010>poke x:111,5
:0x006f: 0x0000->0x0005

VS1010>peek 111
0x006f X=0x0005 Y=0035


VS1010>poke x:111,8
:0x006f: 0x0005->0x0008

VS1010>peek 111
0x006f X=0x0008 Y=0008


VS1010>peek 111
0x006f X=0x0005 Y=0069

Using the flash this way is as safe as it can be in a VS1010 product. The ROM functions which are used in this code are those functions that the ROM's SPI flash driver uses itself to handle the S: FAT device. The S: device itself is not used, only the SPI bus, and this can be important in some cases. While you could use the S: device to read and write the data by giving a negative sector number to S: disk's methods BlockRead and BlockWrite, any writing using those methods writes the data through X: addresses 0x3000..0x3fff, which are typically used by the MP3 decoder. This code doesn't need any extra memory for writing, which increases its applicability.

Re: Safely storing application settings in the flash

Posted: Tue 2021-02-23 21:35
by kenc
This is fantastic Panu, thank you for this!

I think you're reading my mind sometimes, exactly what I was looking for :)