Safely storing application settings in the flash

Designing hardware and software for systems that use the VS1010 MP3 Audio DSP Microcontroller.
Post Reply
User avatar
Panu
VSDSP Expert
Posts: 2829
Joined: Tue 2010-06-22 13:43

Safely storing application settings in the flash

Post 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) {
	Disable();	
	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.	
	Enable();
	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
	Disable();
	BlockRead(&spiBus, 120, buf); //read one disk sector to buffer
	memcpy (myAppSettings, buf, 33); //copy 33 words to the console data area
	Enable();
}
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>savesettings

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

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

VS1010>loadsettings

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

VS1010>
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.
Attachments
loadsettings.dlx
Safely loads user settings from the flash. VS1010 VSOS DLX executable.
(486 Bytes) Downloaded 221 times
savesettings.dlx
Safely saves user settings to the flash. VS1010 VSOS DLX executable.
(474 Bytes) Downloaded 219 times
arch-loadsettings-2021-02-23-09-40-RC1.zip
Source code, VSIDE solution
(20.17 KiB) Downloaded 225 times
arch-savesettings-2021-02-23-09-40-RC1.zip
Source code, VSIDE solution
(20.25 KiB) Downloaded 219 times
kenc
User
Posts: 11
Joined: Tue 2021-02-09 3:41
Location: Ontario, Canada

Re: Safely storing application settings in the flash

Post by kenc »

This is fantastic Panu, thank you for this!

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

Cheers,
Ken
Decko
User
Posts: 2
Joined: Tue 2022-09-20 12:38

Re: Safely storing application settings in the flash

Post by Decko »

Hi. How can i extend this to write an array of u_int16 values to sector 120?

I want to use this method to store my "marked tracks", so that they dont get played when they are marked.

At the moment i have a u_int16 value and each bit represents a track marking.
"tracks_marked = 0b0000000000001100;"
In this example the track 3 and 4 doesnt get played.

So for now this only can save the marking of 16Tracks, but i need this for like 512Tracks (Bits).

How can i read / write / delete the complete sector with an array? not only the first 16bits?
Image

This is my shortened code so far:
1. LoadMarking will be executed at the beginning and SaveMarking just before PowerOff
2. MarkTrack gets called by a ButtonHandler
3. ResetTrackMarking gets called by a ButtonHandler

Code: Select all

void LoadMarking(){
	printf("\n -> Load-Marked-Tracks <-\n");
	Disable();
	// Make sure SPI bus pins are in the correct state as we're calling low level functions directly
	GpioSetAsPeripheral(0x11); //MISO0
	GpioSetAsPeripheral(0x10); //MOSI0
	GpioSetAsPeripheral(0x12); //SCK0
	GpioSetPin(0x13, 1); //XCS0
	BlockRead(&spiBus, 120, buf); //Read one spi disk sector(120) to buffer 
	printf("Loaded: %b\n",*buf);
	tracks_marked = *buf;
	Enable();
}

void SaveMarking(){ // Store markings in Sectors 120..127 in SPI Flash Memory (512 bytes each sector) 
	printf("\n -> Save-Marked-Tracks <-\n");
	Disable();
	// Make sure SPI bus pins are in the correct state as we're calling low level functions directly
	GpioSetAsPeripheral(0x11); //MISO0
	GpioSetAsPeripheral(0x10); //MOSI0
	GpioSetAsPeripheral(0x12); //SCK0
	GpioSetPin(0x13, 1); //XCS0
	Erase4K (&spiBus, 120); // Use 4K block at 60K..63K (sectors 120..127), FAT starts at 64K (physical sector 128)
	*buf = tracks_marked;
	printf("Saved: %b\n",*buf);
	Program4K(&spiBus, 120, buf); //Write Buffer to spi disk sector(120)	
	Enable();
}

void MarkTrack(void){ 
	tracks_marked |= (1<<track);
	printf("\n->Mark-Track Nr.: %d \n", track);
	printf("Tracks_Marked: %b \n", tracks_marked);
}

void ResetTrackMarking(void){  // reset all marked tracks
	tracks_marked = 0xEEEE; // EEEE just an example to show area in memory
}

ioresult main(char *params){
        ...
	while(keepPlaying){ //player loop
		...	
		while(track_ok == 0){
			if(tracks_marked & (1<<nextTrack)){ 
				nextTrack++;
				printf("Track_is_Marked -> next is: %d \n", nextTrack);
			}else{
				track_ok = 1;
				printf("Track: %d ok to play \n ", track);
			}
		}
	}
	return S_OK;
	...
}
Can somebody help me or give me a hint how to extend this?

Cheers,
Decko
Last edited by Decko on Wed 2022-09-21 15:08, edited 1 time in total.
User avatar
pasi
VLSI Staff
Posts: 2102
Joined: Thu 2010-07-15 16:04

Re: Safely storing application settings in the flash

Post by pasi »

The code provided by Panu already writes and reads whole blocks, but your tracks_marked variable is just one word in the buffer saved/restored.

You need to extend your tracks_marked to be an array instead of a single variable, then copy the whole array when saving and restoring.

Something like the below primitives should get you forward.

Code: Select all

	u_int16 tracks_marked[512/16];
	#define SET_TRACK(a) tracks_marked[(a)/16] |= (1<<((a)&15))
	#define CLEAR_TRACK(a) tracks_marked[(a)/16] &= ~(1<<((a)&15))
	#define IS_TRACK(a) (tracks_marked[(a)/16] & (1<<((a)&15)))
	memset(tracks_marked, 0, sizeof(tracks_marked)); //all not marked
	memcpy(buf, tracks_marked, sizeof(tracks_marked)); //copy to buf
	memcpy(tracks_marked, buf, sizeof(tracks_marked)); //copy from buf to tracks_marked
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
Decko
User
Posts: 2
Joined: Tue 2022-09-20 12:38

Re: Safely storing application settings in the flash

Post by Decko »

Hi pasi,

thank you very much for the quick response and elegant solution.
You helped me a lot!

Best Greetings
Post Reply