Persisting data to (from) Flash

Just looking at the flash load/save functions, they seem complicated to me! :slight_smile: I don’t currently have a MUX, but saving/loading from flash don’t disturb my analog reads.

This is how I do it, maybe this will help.

static OpdFlashConfig DSY_QSPI_BSS flashConfigLoad;

void UtilFlashSave()
{
uint32_t base = 0x90000000;
OpdFlashConfig flashConfigSave;

// copy data to flashConfigSave struct

flashConfigSave.configVersion = FLASH_CONFIG_VERSION;
memcpy(&flashConfigSave.mixSynth, &mixSynth, sizeof(mixSynth));
flashConfigSave.mixDrum = mixDrum;

memcpy(&flashConfigSave.synthSettings, &synthSettings, sizeof(synthSettings));
flashConfigSave.drumSettings = drumSettings;

memcpy(&flashConfigSave.songStep, &songStep, sizeof(songStep));
flashConfigSave.seqSongLen = seqSongLen;

memcpy(&flashConfigSave.seqBass, &seqBass, sizeof(seqBass));
memcpy(&flashConfigSave.seqLead, &seqLead, sizeof(seqLead));
memcpy(&flashConfigSave.seqLeadLen, &seqLeadLen, sizeof(seqLeadLen));
memcpy(&flashConfigSave.seqDrum, &seqDrum, sizeof(seqDrum));

//memcpy(&flashConfigSave.lfo, &lfo, sizeof(lfo));
flashConfigSave.fxSettings = fxSettings;
memcpy(&flashConfigSave.seqBassGateTime, &seqBassGateTime, sizeof(seqBassGateTime));
memcpy(&flashConfigSave.seqVoiceOn, &seqVoiceOn, sizeof(seqVoiceOn));
flashConfigSave.sysTickBPM = sysTickBPM;

// init and set mode

hardware.qspi_handle.mode = DSY_QSPI_MODE_INDIRECT_POLLING;
dsy_qspi_init(&hardware.qspi_handle);

// erase

dsy_qspi_erase(base, base + sizeof(flashConfigSave));

// write

dsy_qspi_write(base, sizeof(flashConfigSave), (uint8_t*)&flashConfigSave);

// de-init

dsy_qspi_deinit();

}

void UtilFlashLoad()
{

// init and set mode

hardware.qspi_handle.mode = DSY_QSPI_MODE_DSY_MEMORY_MAPPED;
dsy_qspi_init(&hardware.qspi_handle);

// Flash is memory mapped so no need to read

// copy data from opdLoadConfig struct to data

if (flashConfigLoad.configVersion == FLASH_CONFIG_VERSION)
{
memcpy(&mixSynth, &flashConfigLoad.mixSynth, sizeof(mixSynth));
mixDrum = flashConfigLoad.mixDrum;

  memcpy(&synthSettings, &flashConfigLoad.synthSettings, sizeof(synthSettings));
  drumSettings = flashConfigLoad.drumSettings;

  memcpy(&songStep, &flashConfigLoad.songStep, sizeof(songStep));
  seqSongLen = flashConfigLoad.seqSongLen;

  memcpy(&seqBass, &flashConfigLoad.seqBass, sizeof(seqBass));
  memcpy(&seqLead, &flashConfigLoad.seqLead, sizeof(seqLead));
  memcpy(&seqLeadLen, &flashConfigLoad.seqLeadLen, sizeof(seqLeadLen));
  memcpy(&seqDrum, &flashConfigLoad.seqDrum, sizeof(seqDrum));

  //memcpy(&lfo, &flashConfigLoad.lfo, sizeof(lfo));
  fxSettings = flashConfigLoad.fxSettings;
  memcpy(&seqBassGateTime, &flashConfigLoad.seqBassGateTime, sizeof(seqBassGateTime));
  memcpy(&seqVoiceOn, &flashConfigLoad.seqVoiceOn, sizeof(seqVoiceOn));
  sysTickBPM = flashConfigLoad.sysTickBPM;

}

// de-init

dsy_qspi_deinit();

}

Notice the

dsy_qspi_deinit();

at the end.

You are also polling your hardware extremely often in the for(;;)-loop in main(). Maybe try using a small delay in the loop, eg

System::Delay(25);

and see if this helps?

1 Like

Thanks for your reply Staffan. I think our save and load functions look quite similar from first glance. I believe I had to split my 32bit float values into 4 bytes to get it to work - what kind of data are you saving?

Also to be clear my normal ADC channels aren’t impacted, it’s only the muxed ones. Additionally in my full module code the ADC’s are polled at regular intervals, one channel per AudioCallback call, but that is exhibiting the same problem.

I’ll have to look into what the dsy_qspi_deinit() does exactly, but no harm in testing it out.

1 Like

Consider switching QSPI to memory mapped mode or deiinitialziing in the end of save procedure. It doesn’t feel right to leave it in polling mode. And also it looks like you would be switching it from polling to polling now (there’s no load calls made between them), I think it might not work correctly (vaguely recall having something like that not working in code from Daisy).

2 Likes

I have everything from float’s to structs in my struct. It is just a big chunk of memory. Why did you get a problem with the floats?

And sorry, can’t try your code as I don’t have a mux. I hope somebody else can help you!

@adam_f thanks for sharing, I don’t have a ton of bandwidth this week, but I can take a look sometime within the next few days/week and see if I see anything.

I should be able to run it (or something similar) on my Field to I can see if I can replicate the “mux-death” you’re seeing on your end.

I’ll chime back in as soon as I have some time to look it over.

@shensley ok thanks, whenever you get a chance. Just an update - I tried putting dsy_qspi_deinit() at the end of the SaveSettings and LoadSettings functions. This makes the example ‘MuxTest’ program work correctly…however it still does not work in my full module code! This is going to make it much harder to debug :sob:

There’s a lot more going on in my full module code, but I’m still calling the SaveSettings function from main() as per the example program. I tried both reading the ADCs from main() and from the AudioCallback but it still has the same result. All I can think of is that something else happening in my AudioCallback that is somehow interrupting the save? And that is having a knock-on impact on the synchronization of the mux somehow?! I’m really clutching at straws now! Thanks in advance for any help!

In these cases, if you got a working simple example, and a larger non-working, my method is usually to
a) either start with the simple and add things until it stops working, or
b) go from the larger and remove things until it starts working.

1 Like

Just for the archives, since things have change with libdaisy v2.0, I had to update my functions.
So, I now have this, and it works :

void save_config(uint32_t slot) {
uint32_t base = 0x90000000;
base += slot4096; // works only because sizeof(CONFIGURATION) < 4096
hw.seed.qspi.Erase(base, base + sizeof(CONFIGURATION));
hw.seed.qspi.Write(base, sizeof(CONFIGURATION), (uint8_t
)&curent_config);
}

void load_config(uint32_t slot)
{
memcpy(&curent_config, reinterpret_cast<void*>(0x90000000 + (slot * 4096)), sizeof(CONFIGURATION));
}

2 Likes