Preset not surviving power cycle

sorry, this code is very messy as I have not yet learned how to work with classes.

the problem is, I have 10 presets, and they work fine within a power cycle.
all my changes are saved and loaded correctly.

however, if I reboot the daisy, presets are empty.

thanks in advance, this mistake must be very small,
I have a version of this with a single preset which is saved with a button and loads when the device starts up, and it works absolutely perfect :wink:

#include "daisysp.h"
#include <stdio.h>
#include <string.h>
#include "daisy_seed.h"
#include "dev/oled_ssd130x.h"
#include "dev/mpr121.h"
#include "Utility/dsp.h"

using namespace daisysp;
using namespace daisy;

using MyOledDisplay = OledDisplay<SSD130xI2c128x64Driver>;

dsy_gpio ledR_1_pin, ledG_1_pin, ledB_1_pin;

dsy_gpio muxpin, muxbpin, muxcpin;


uint16_t currTouched;
uint16_t lastTouched;


DaisySeed         hw;
MyOledDisplay     display;
Mpr121I2C         mpr121;

Encoder encoder;
Switch  button;
Switch  buttonP;
Switch  buttonsave;

// Define display dimensions
const int DISPLAY_WIDTH = 128;
const int DISPLAY_HEIGHT = 64;

// Define display buffer size
const int DISPLAY_BUFFER_SIZE = (DISPLAY_WIDTH * DISPLAY_HEIGHT) / 8;

// Define display buffer
uint8_t displayBuffer[DISPLAY_BUFFER_SIZE];

// Number of presets
const int NUM_PRESETS = 10;

    //Setting Struct containing parameters we want to save to flash
    struct Settings {
    int p1[8]; // Sequence Pitch
    int p2[8]; // Beat
    int p3[8]; // Sequence Pitch
    int p4[8]; // Beat
    int p5; //lfoFenv
    int p6; //lfoFamt
    int p7; //lfoAenv
    int p8; //lfoAamt
    int p9; //osc2pv
    int p10; //scale


	//Overloading the != operator
    //This is necessary as this operator is used in the PersistentStorage source code
    bool operator!=(const Settings& a) const {
    for (int i = 0; i < 8; ++i) {
        if (p1[i] != a.p1[i] || p2[i] != a.p2[i] || p3[i] != a.p3[i] || p4[i] != a.p4[i]) {
            return true;
        }
    }
    return p5 != a.p5 || p6 != a.p6 || p7 != a.p7 || p8 != a.p8 || p9 != a.p9 || p10 != a.p10;
}
};


Settings presets[NUM_PRESETS];
int current_preset = 0;

static Oscillator osc;
static Oscillator osc2;
static Oscillator lfo;
static Svf        filt;
static Metro      clock;
static Adsr       env;
static Adsr       envM;
float             osc2F=24;
float             gate;
float             envout;
float             oscF=24;
int               seqF;
float             Dseq;
float             trig;
float             sig;
int               decO=0;
int               trigo = 0;
float             keyF=0;
int               ctfO=0;
int               beat[8] {1, 1, 1, 1, 1, 1, 1, 1};
int               beato[8] {0, 0, 0, 0, 0 ,0 ,0 ,0};
int               seqP[8] {0, 0, 0, 0, 0, 0, 0, 0};
float             seqD[8] {0, 0, 0, 0, 0, 0, 0, 0};
float             seDc[8] {0, 0, 0, 0, 0, 0, 0, 0};
int               Pval=0;//enc parameter select
int               Pval2=0;
int               step = 0;
int               cnt = 0;
int               stepped = 0;
int               steppedO = 0;
int               oct=0;
int               seqlen = 8;
float             sDec = 0;
int               pg=0;
int               pgtrig=0;
int               pgtrigO=0;
int               lfoFenv=0;
int               lfoAenv=0;
int               lfoFamt=0;
int               lfoAamt=0;
int               osc2seq=0;
int               subP=0;
float             lfo_=0;
float             lfoF_=0;
float             lfoA_=0;
int               osc2pv=0;
int               scale=0;
int               sub2=0;
int               output_value = 0;


// Buffer to store the previous state of the display
uint8_t prevDisplayBuffer[128 * 64 / 8];
uint8_t currentDisplayBuffer[128 * 64 / 8];

// Function to update only the changed pixels
void updateDisplay(uint8_t* currentBuffer) {
    // Compare the current buffer with the previous buffer
    for (int i = 0; i < 128 * 64 / 8; i++) {
        if (currentBuffer[i] != prevDisplayBuffer[i]) {
            // Calculate the x, y position of the changed pixel
            int x = (i % 128);
            int y = (i / 128);

            // Update the pixel on the display
            display.DrawPixel(x, y, currentBuffer[i]);

            // Update the corresponding pixel in the previous buffer
            prevDisplayBuffer[i] = currentBuffer[i];
        }
    }

    // Send the updated pixels to the display
    display.Update();
}
    //Persistent Storage Declaration. Using type Settings and passed the devices qspi handle
    
// Erstelle eine Instanz der PersistentStorage-Klasse fĂźr deine Presets
daisy::PersistentStorage<Settings> SavedSettings(hw.qspi);
    // Create an array of settings to hold multiple presets
    
    bool use_preset = false;
    bool trigger_save = false;
    

   
void LoadPreset(int preset_index) {
    // Ensure SavedSettings.Init() has been called before Load()
    if (preset_index < 0 || preset_index >= NUM_PRESETS) return; // Invalid preset index

    const Settings& preset = presets[preset_index];
    for (int i = 0; i < 8; i++) {
        seqP[i] = preset.p1[i];
        beat[i] = preset.p2[i];
        seqD[i] = preset.p3[i];
        seDc[i] = preset.p4[i];
    }
    lfoFenv = preset.p5;
    lfoFamt = preset.p6;
    lfoAenv = preset.p7;
    lfoAamt = preset.p8;
    osc2pv = preset.p9;
    scale = preset.p10;
}

void SavePreset(int preset_index) {
    if (preset_index < 0 || preset_index >= NUM_PRESETS) return; // Invalid preset index

    Settings& preset = presets[preset_index];
    for (int i = 0; i < 8; i++) {
        preset.p1[i] = seqP[i];
        preset.p2[i] = beat[i];
        preset.p3[i] = seqD[i];
        preset.p4[i] = seDc[i];
    }
    preset.p5 = lfoFenv;
    preset.p6 = lfoFamt;
    preset.p7 = lfoAenv;
    preset.p8 = lfoAamt;
    preset.p9 = osc2pv;
    preset.p10 = scale;
    
    trigger_save = true;
}
// P R E S E T
    
    void ProcessControls() {
    int increment3 = encoder.Increment();
    buttonsave.Debounce();
    buttonP.Debounce();

        
        if(buttonP.RisingEdge() && pg==0)
        {
            output_value += 1;
            output_value %= 8;
        }
        if(buttonP.RisingEdge() && pg==1)
            {
            subP += 1;
            subP %= 2;
            
            }

        if(buttonP.RisingEdge() && pg==2)
            {
            sub2 += 1;
            sub2 %= 2;
            }

    if (pg == 2) {
        if (increment3 > 0) {
            current_preset = (current_preset + 1) % NUM_PRESETS;
        } else if (increment3 < 0) {
            current_preset = (current_preset - 1 + NUM_PRESETS) % NUM_PRESETS;
        }
    
        if (encoder.RisingEdge()) {
            if(sub2==0){
            LoadPreset(current_preset);
            display.Fill(false);
            display.SetCursor(38, 24);
            display.WriteString("Loaded", Font_11x18, true);
            updateDisplay(currentDisplayBuffer);
            }
            else if(sub2==1){
                SavePreset(current_preset);
                display.Fill(false);
                display.SetCursor(38, 24);
                display.WriteString("Saved", Font_11x18, true);
                updateDisplay(currentDisplayBuffer);
            }
        }
        
        
        
        
    }
     if(encoder.FallingEdge() || encoder.Increment() || button.FallingEdge()|| buttonP.FallingEdge() || 
        (encoder.TimeHeldMs() > 200) || hw.adc.GetFloat(4)> 0.5)
        {
            if(pg==0){
        display.Fill(false);
        //display.SetCursor(2, 0);
        //display.WriteString("Gate & P & Mod-Dec", Font_7x10, true);
        display.DrawCircle(10, 56, beat[0] *2+1, true);
        display.DrawCircle(25, 56, beat[1] *2+1, true);
        display.DrawCircle(40, 56, beat[2] *2+1, true);
        display.DrawCircle(55, 56, beat[3] *2+1, true);
        display.DrawCircle(70, 56, beat[4] *2+1, true);
        display.DrawCircle(85, 56, beat[5] *2+1, true);
        display.DrawCircle(100, 56, beat[6] *2+1, true);
        display.DrawCircle(115, 56, beat[7] *2+1, true);

        display.DrawLine(128, 36-Pval*18, 128, 36-Pval*18+12, true);

        display.DrawLine(output_value*15 + 4, 63, output_value*15+16, 63, true);

        display.DrawArc(10, 42, 6, 90, seqP[0]*-14, true);
        display.DrawArc(25, 42, 6, 90, seqP[1]*-14, true);
        display.DrawArc(40, 42, 6, 90, seqP[2]*-14, true);
        display.DrawArc(55, 42, 6, 90, seqP[3]*-14, true);
        display.DrawArc(70, 42, 6, 90, seqP[4]*-14, true);
        display.DrawArc(85, 42, 6, 90, seqP[5]*-14, true);
        display.DrawArc(100, 42, 6, 90, seqP[6]*-14, true);
        display.DrawArc(115, 42, 6, 90, seqP[7]*-14, true);

        display.DrawArc(10, 24, 6, 90, seqD[0]*-12, true);
        display.DrawArc(25, 24, 6, 90, seqD[1]*-12, true);
        display.DrawArc(40, 24, 6, 90, seqD[2]*-12, true);
        display.DrawArc(55, 24, 6, 90, seqD[3]*-12, true);
        display.DrawArc(70, 24, 6, 90, seqD[4]*-12, true);
        display.DrawArc(85, 24, 6, 90, seqD[5]*-12, true);
        display.DrawArc(100, 24, 6, 90, seqD[6]*-12, true);
        display.DrawArc(115, 24, 6, 90, seqD[7]*-12, true);

        display.DrawArc(10, 6, 6, 90, seDc[0]*-12, true);
        display.DrawArc(25, 6, 6, 90, seDc[1]*-12, true);
        display.DrawArc(40, 6, 6, 90, seDc[2]*-12, true);
        display.DrawArc(55, 6, 6, 90, seDc[3]*-12, true);
        display.DrawArc(70, 6, 6, 90, seDc[4]*-12, true);
        display.DrawArc(85, 6, 6, 90, seDc[5]*-12, true);
        display.DrawArc(100, 6, 6, 90, seDc[6]*-12, true);
        display.DrawArc(115, 6, 6, 90, seDc[7]*-12, true);
        }

        else if (pg==1){
        display.Fill(false);
        display.DrawLine(128, Pval2*16, 128, Pval2*16+14, true);
        display.DrawLine(subP*36 + 54, 63, subP*36 + 54 + 32, 63, true);

        display.SetCursor(2, 4);
        display.WriteString("LFO F", Font_7x10, true);
        display.DrawArc(114, 8, 6, 90, lfoFamt*-12, true);
        switch(lfoFenv){
        case  0: display.SetCursor(54, 4);
        display.WriteString("Off", Font_7x10, true); break;
        case 1: display.SetCursor(54, 4);
        display.WriteString("Env 1", Font_7x10, true); break;
        case 2: display.SetCursor(54, 4);
        display.WriteString("Env 2", Font_7x10, true); break;
        default: 0; break;
        }
        display.SetCursor(2, 20);
        display.WriteString("LFO A", Font_7x10, true);
        display.DrawArc(114, 24, 6, 90, lfoAamt*-12, true);
        switch(lfoAenv){
        case  0: display.SetCursor(54, 20);
        display.WriteString("Off", Font_7x10, true); break;
        case 1: display.SetCursor(54, 20);
        display.WriteString("Env 1", Font_7x10, true); break;
        case 2: display.SetCursor(54, 20);
        display.WriteString("Env 2", Font_7x10, true); break;
        default: 0; break;
        }
        display.SetCursor(2, 36);
        display.WriteString("Osc2 F", Font_7x10, true);
        display.DrawArc(114, 40, 1, 90, 360, true);
        switch(osc2pv){
        case  0: display.SetCursor(54, 36);
        display.WriteString("Key+Seq", Font_7x10, true); break;
        case 1: display.SetCursor(54, 36);
        display.WriteString("Key Only", Font_7x10, true); break;
        case 2: display.SetCursor(54, 36);
        display.WriteString("None", Font_7x10, true); break;
        default: 0; break;
        }
        display.SetCursor(2, 52);
        display.WriteString("Scale", Font_7x10, true);
        display.DrawArc(114, 56, 1, 90, 360, true);
        switch(scale){
        case  0: display.SetCursor(54, 52);
        display.WriteString("Chroma", Font_7x10, true); break;
        case 1: display.SetCursor(54, 52);
        display.WriteString("Major", Font_7x10, true); break;
        case 2: display.SetCursor(54, 52);
        display.WriteString("Minor", Font_7x10, true); break;
        case 3: display.SetCursor(54, 52);
        display.WriteString("Penta", Font_7x10, true); break;
        default: 0; break;
        }
        }
        if(pg==2){
        display.Fill(false);
        display.SetCursor(40, 2);
        display.WriteString("Preset", Font_7x10, true);
        display.SetCursor(50, 22);
        FixedCapStr<16> str("");
        str.AppendInt(current_preset);
        display.WriteString(str, Font_11x18, true);
        display.SetCursor(20, 50);
        display.WriteString("Load", Font_7x10, true);
        display.SetCursor(80, 50);
        display.WriteString("Save", Font_7x10, true);
        display.DrawLine(sub2*36 + 20, 63, sub2*36 + 20 + 40, 63, true);
        }
        
        
        // Update only the changed pixels
        updateDisplay(currentDisplayBuffer);
        //display.Update();
//System :: Delay(1);
        
        }
}

static void AudioCallback(AudioHandle::InterleavingInputBuffer  in,
                          AudioHandle::InterleavingOutputBuffer out,
                          size_t                                size)

{
    
    for(size_t i = 0; i < size; i += 2)
    {
        
        // Use envelope to control the amplitude of the oscillator.
        envout = env.Process(trig && gate);
        osc.SetAmp(envout*.5);
        osc2.SetAmp(envout*.5);
        
        sig = osc.Process() + osc2.Process();

        filt.Process(sig);


        // left out
        out[i] = filt.Low();

        // right out
        out[i + 1] = filt.Low();
    }
}

int main(void)
{
    
    // Initialize the previous display buffer to all zeros
    memset(prevDisplayBuffer, 0, sizeof(prevDisplayBuffer));
    // initialize seed hardware and oscillator daisysp module
    float sample_rate = 96000;
    
    hw.Configure();
    hw.Init();
    hw.SetAudioBlockSize(2);
    hw.SetAudioSampleRate(SaiHandle::Config::SampleRate::SAI_96KHZ);
    sample_rate = hw.AudioSampleRate();

     // Initialize PersistentStorage with default settings
    Settings DefaultSettings = {{12, 24, 48, 24, 12, 0, 0, 0}, {0, 1, 0, 1, 0, 1, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0},0,0,0,0,0,0};
    SavedSettings.Init(DefaultSettings);

   

    // Load settings on boot
    LoadPreset(0);

    //Set button to pin 28, to be updated at a 1kHz  samplerate
    button.Init(hw.GetPin(9), 100);
    buttonP.Init(hw.GetPin(10), 100);
    buttonsave.Init(hw.GetPin(26), 100);

    osc.Init(sample_rate);
    osc2.Init(sample_rate);
    lfo.Init(sample_rate);

    //init metro object
    clock.Init(2, sample_rate);
    clock.SetFreq (200);

    //Set envelope parameters
    env.Init(sample_rate);
    env.SetTime(ADSR_SEG_ATTACK, .1);
    env.SetTime(ADSR_SEG_DECAY, .5);
    env.SetTime(ADSR_SEG_RELEASE, .5);  
    env.SetSustainLevel(.5);

    //Mod>Env Init
    envM.Init(sample_rate);
    envM.SetTime(ADSR_SEG_ATTACK, .1);
    envM.SetTime(ADSR_SEG_DECAY, .5);
    envM.SetTime(ADSR_SEG_RELEASE, .5);  
    envM.SetSustainLevel(.5);

    // Set parameters for oscillator
    osc.SetWaveform(4);
    osc.SetFreq(220);
    osc.SetAmp(0.5);

    // Set parameters for oscillator
    osc2.SetWaveform(4);
    osc2.SetFreq(220);
    osc2.SetAmp(0.5);
    
    lfo.SetWaveform(0);
    lfo.SetFreq(.5);

    // Initialize Filter, and set parameters.
    filt.Init(sample_rate);
    filt.SetFreq(500.0);
    filt.SetRes(0.85);
    filt.SetDrive(0.8);
    
    
    // R 1 on pin 27
    ledR_1_pin.pin = hw.GetPin(28);
    ledR_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    ledR_1_pin.pull = DSY_GPIO_NOPULL;
    dsy_gpio_init(&ledR_1_pin);
    dsy_gpio_write(&ledR_1_pin, true);

    // R 1 on pin 27
    ledG_1_pin.pin = hw.GetPin(29);
    ledG_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    ledG_1_pin.pull = DSY_GPIO_NOPULL;
    dsy_gpio_init(&ledG_1_pin);
    dsy_gpio_write(&ledG_1_pin, true);

    // R 1 on pin 27
    ledB_1_pin.pin = hw.GetPin(30);
    ledB_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    ledB_1_pin.pull = DSY_GPIO_NOPULL;
    dsy_gpio_init(&ledB_1_pin);
    dsy_gpio_write(&ledB_1_pin, true);

    // muxing out
    muxpin.pin = hw.GetPin(13);
    muxpin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    muxpin.pull = DSY_GPIO_NOPULL;
    dsy_gpio_init(&muxpin);
    dsy_gpio_write(&muxpin, false);

    muxbpin.pin = hw.GetPin(14);
    muxbpin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    muxbpin.pull = DSY_GPIO_NOPULL;
    dsy_gpio_init(&muxbpin);
    dsy_gpio_write(&muxbpin, false);

    muxcpin.pin = hw.GetPin(27);
    muxcpin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    muxcpin.pull = DSY_GPIO_NOPULL;
    dsy_gpio_init(&muxcpin);
    dsy_gpio_write(&muxcpin, false);

    
    //Configure pin 21 as an ADC input. This is where we'll read the knob.
   // Create an array of two AdcChannelConfig objects
    const int num_adc_channels = 11;
    AdcChannelConfig my_adc_config[num_adc_channels];
    
    // Initialize the first one connected to A0
    my_adc_config[0].InitSingle(hw.GetPin(21));
    my_adc_config[1].InitSingle(hw.GetPin(20));
    my_adc_config[2].InitSingle(hw.GetPin(19));
    my_adc_config[3].InitSingle(hw.GetPin(18));
    my_adc_config[4].InitSingle(hw.GetPin(17));
    my_adc_config[5].InitSingle(hw.GetPin(16));
    my_adc_config[6].InitSingle(hw.GetPin(22));
    my_adc_config[7].InitSingle(hw.GetPin(23));
    my_adc_config[8].InitSingle(hw.GetPin(24));
    my_adc_config[9].InitMux(hw.GetPin(15), 8, seed::D3, seed::D4, seed::D5);
    my_adc_config[10].InitMux(hw.GetPin(25), 8, seed::D0, seed::D1, seed::D2);
    
  

    //Initialize the adc with the config we just made
    
    hw.adc.Init(my_adc_config, num_adc_channels);
    
    
    
    //Start reading values
    hw.adc.Start();

    /** Initialize our Encoder */
    encoder.Init(seed::D6, seed::D7, seed::D8);
    
    
    // start callback
    hw.StartAudio(AudioCallback);

    // touch works
    // Initialize MPR121 with I2C configuration
    Mpr121I2C::Config mprConfig;
    mprConfig.transport_config.periph = I2CHandle::Config::Peripheral::I2C_1;
    mprConfig.transport_config.speed = I2CHandle::Config::Speed::I2C_400KHZ;
    mprConfig.transport_config.mode  = I2CHandle::Config::Mode::I2C_MASTER;
    mprConfig.transport_config.scl = Pin(PORTB,8);  // Replace with your SCL pin
    mprConfig.transport_config.sda = Pin(PORTB,9);  // Replace with your SDA pin

	// Set additional MPR121 configuration if needed
    mprConfig.touch_threshold = 12;
    mprConfig.release_threshold = 6;

    if(mpr121.Init(mprConfig) != Mpr121I2C::OK)
    {
        // Handle initialization error
        while(1)
        {
            // Error handling code (blinking LED, etc.)
        }
    }
	// Setup to print 
	hw.StartLog();
    /** Create a variable to store the value we'll print out to USB */
    
    // oled
    // Configure the Display 
    MyOledDisplay::Config disp_cfg;
    disp_cfg.driver_config.transport_config.i2c_address               = 0x3C;
    disp_cfg.driver_config.transport_config.i2c_config.periph         = I2CHandle::Config::Peripheral::I2C_1;
    disp_cfg.driver_config.transport_config.i2c_config.speed          = I2CHandle::Config::Speed::I2C_1MHZ;
    disp_cfg.driver_config.transport_config.i2c_config.mode           = I2CHandle::Config::Mode::I2C_MASTER;
    disp_cfg.driver_config.transport_config.i2c_config.pin_config.scl = {DSY_GPIOB, 8};    
    disp_cfg.driver_config.transport_config.i2c_config.pin_config.sda = {DSY_GPIOB, 9};
    // And Initialize
        display.Init(disp_cfg);
        display.Fill(false);
        display.SetCursor(20, 10);
        display.WriteString("MONOFONK", Font_11x18, true);
        display.SetCursor(2, 42);
        display.WriteString("Pointless Innovations", Font_6x8, true);
        display.Update();



    while(1) {
        	if(trigger_save) {
            SavedSettings.Save(); // Writing locally stored settings to the external flash
            trigger_save = false;
            }
            ProcessControls();

//E N C O D E R 
        encoder.Debounce();
        
        
        //Pager
		if(hw.adc.GetFloat(4) > .5f)
        {  
        hw.SetLed(true);
        pgtrig=1;
            if(pgtrigO!=pgtrig){
            
            pg++;
            pg %= 3;
            
            }
        }
        else {pgtrig=0;}
        pgtrigO=pgtrig;
        
	
       if(pg ==0){
        if(encoder.FallingEdge() && pg==0){Pval++;
        if (Pval>2) {Pval=0;}}

        int increment = encoder.Increment();
        
        
        
        button.Debounce();
        if(button.RisingEdge() && pg==0){
        if (beat[output_value] == 1)
            {
            beat[output_value] = 0;
            }
            else 
            {
            beat[output_value] = 1;
            }
            }

        if((Pval==0) && (increment > 0) && pg==0)
        
        {
            seqP[output_value] += 1;
            hw.PrintLine("Pitch:\t%d", seqP[output_value]);
            
        }
        else if((Pval==0) && (increment < 0))
        {
            seqP[output_value] -= 1;
            hw.PrintLine("Pitch:\t%d", seqP[output_value]);     
        }
        if((Pval==1) && (increment > 0) && pg==0)
        {
            seqD[output_value] += 1;
        }
        else if((Pval==1) && (increment < 0) && pg==0)
        {
            seqD[output_value] -= 1;    
        }
        if((Pval==2) && (increment > 0) && pg==0)
        {
            seDc[output_value] += 1;
        }
        else if((Pval==2) && (increment < 0) && pg==0)
        {
            seDc[output_value] -= 1;    
        }
        if ((encoder.TimeHeldMs() > 200) && pg==0)
             {
            seqP[output_value] = 0;
            seqD[output_value] = 0;
            beat[output_value] = 1;
            seDc[output_value] = 0;
        }
        }
// PAGE 1
        if(pg == 1){
        
        if(encoder.FallingEdge()) {Pval2++; Pval2 %= 4;}

        int increment2 = encoder.Increment();
        if((subP==0) && (Pval2==0)&&(increment2 > 0) )
        {
            lfoFenv += 1;
            lfoFenv %= 3;
        }
        else if((subP==0) && (Pval2==0) && (increment2 < 0))
        {
            lfoFenv -= 1;
            if(lfoFenv < 0){lfoFenv = 2;}    
        }
        if((subP==1) && (Pval2==0) && (increment2 > 0) )
        {
            lfoFamt += 1;
        }
        else if((subP==1) && (Pval2==0) && (increment2 < 0) )
        {
            lfoFamt -= 1;    
        }
        if((subP==0) && (Pval2==1) && (increment2 > 0) )
        {
            lfoAenv += 1;
            lfoAenv %= 3;
        }
        else if((subP==0) && (Pval2==1) && (increment2 < 0) )
        {
            lfoAenv -= 1;
            if(lfoAenv < 0){lfoAenv = 2;}    
        }
        if((subP==1) && (Pval2==1) && (increment2 > 0) )
        {
            lfoAamt += 1;
        }
        else if((subP==1) && (Pval2==1) && (increment2 < 0) )
        {
            lfoAamt -= 1;    
        }
        if((subP==0) && (Pval2==2) && (increment2 > 0) )
        {
            osc2pv += 1;
            osc2pv %= 3;
        }
        else if((subP==0) && (Pval2==2) && (increment2 < 0) )
        {
            osc2pv -= 1;
            if(osc2pv < 0){osc2pv = 2;}    
        }
        if((subP==0) && (Pval2==3) && (increment2 > 0) )
        {
            scale += 1;
            scale %= 4;
        }
        else if((subP==0) && (Pval2==3) && (increment2 < 0) )
        {
            scale -= 1;
            if(scale < 0){scale = 3;}    
        }
        
        }
        
        // Read touch status
        currTouched = mpr121.Touched();

        // Process the touch status as needed
        for(int i = 0; i < 12; i++)
        {
            if((currTouched & (1 << i)) && !(lastTouched& (1 << i)))
            {
                // Channel i is touched, print the channel number
                hw.PrintLine("Channel %d touched", i);
                keyF = i;
                trig = 1;
                
            }
            if(!(currTouched & (1 << i)) && (lastTouched& (1 << i)))
            {
                // Channel i is released, print the channel number
                hw.PrintLine("Channel %d released", i);
                trig = 0;
            }
        }

        lastTouched = currTouched;
       
//Sequencer
        if (hw.adc.GetFloat(6) > 0)
        {
        if (trig != trigo){
            step=0 ;
            cnt=0;
            clock.Reset();
            }
        if (trig > 0){
            clock.SetFreq(hw.adc.GetFloat(5) * 400);

        if (clock.Process()){
            cnt++;
            cnt %= 4;
            
            if(cnt == 0) {
                gate = 1;
                step++;
                step %= 8;
                }
                
            } else if(cnt == 3) {
                gate = 0;
            }
            
            if(beat[step] > 0)
            { 
                stepped = step;}

                else{stepped = steppedO;}
                
            steppedO=stepped;
        
        trigo=trig;
        }
        
            gate = beat[step] * gate;
            seqF = seqP[stepped];
            Dseq = seqD[stepped];
            sDec = seDc[stepped];
            int muxa = (step) % 2;
            int muxb = (int) (.5f * step)  % 2;
            int muxc = (int) (.25f * step)  % 2;
            dsy_gpio_write(&muxpin,  muxa);
            dsy_gpio_write(&muxbpin,  muxb);
            dsy_gpio_write(&muxcpin,  muxc);
        }
        else 
        {
            gate = 1;
            seqF = 0;
            Dseq = 0;
            sDec = 0;
            dsy_gpio_write(&muxpin,  false);
            dsy_gpio_write(&muxbpin,  false);
            dsy_gpio_write(&muxcpin,  false);
        }
        
         
        float lfoF = hw.adc.GetMuxFloat(9, 0);
        switch(lfoFenv){
            case 0: lfoF_=(lfoF * lfoF * 299.99  + .01); break;
            case 1: lfoF_=(lfoF * lfoF * 299.99  + .01)*env.Process(trig&&gate)*(1-lfoFamt)/24; break;
            case 2: lfoF_=(lfoF * lfoF * 299.99  + .01)*envM.Process(trig&&gate)*(1-lfoFamt)/24; break;
            default: 0; break;
        }
        lfo.SetFreq(lfoF_);
        
        switch(lfoAenv){
            case 0: lfoA_= lfo.Process(); break;
            case 1: lfoA_= lfo.Process() * env.Process(trig && gate) * (1-lfoAamt)/24; break;
            case 2: lfoA_= lfo.Process() * envM.Process(trig && gate) * (1-lfoAamt)/24; break;
            default: 0; break;
        }
        float Menv = envM.Process(trig && gate);
        float peak = (hw.adc.GetMuxFloat(10, 5) * 96 + Dseq*2) * Menv;
        float Cut = hw.adc.GetMuxFloat(10, 4) * 127;
        
        float lfoamt = lfoA_ * hw.adc.GetMuxFloat(9, 1) * 60;
        filt.SetFreq(mtof(Cut + peak+ lfoamt + 27));
        filt.SetRes(hw.adc.GetMuxFloat(10, 6) * 1.1f);

        int rawct=0;
        rawct=hw.adc.GetFloat(2) * 4 - 2;
        oct = rawct * 12;

        int owav = (static_cast<int>(hw.adc.GetMuxFloat(10, 7) * 3 + .7));
        switch (owav)
        {
        case 0: osc.SetWaveform(0); osc2.SetWaveform(0); break;
        case 1: osc.SetWaveform(5); osc2.SetWaveform(5); break;
        case 2: osc.SetWaveform(6); osc2.SetWaveform(6); break;
        case 3: osc.SetWaveform(7); osc2.SetWaveform(7); break;
        default: osc.SetWaveform(0); osc2.SetWaveform(0); break; 
        }

        oscF= hw.adc.GetFloat(0) * 96 + 24;
        osc2F = hw.adc.GetFloat(1) * 96 + 24;
        
        float lfopamt = lfoA_ * hw.adc.GetMuxFloat(9, 2) * 48;
        float Menvpamt = Menv * hw.adc.GetMuxFloat(9, 7) * 60;
        float lfopwamt(lfoA_ * hw.adc.GetFloat(7) * .5);

//Scale
        int Major[7]{0,2,4,5,7,9,11};
        int Minor[7]{0,2,3,5,8,9,10};
        int Penta[5]{0,3,5,8,10};
        int keyFsc=0;
        int keysc=0;
        int scoct=0;
         

        switch(scale)
        {
        case 0: keysc=keyF+seqF;  break;
        case 1: keyFsc= static_cast<int>(keyF + seqF) % 7;
        scoct = static_cast<int>((keyF + seqF)/7)*12;
        keysc = Major[keyFsc] + scoct; break;
        case 2: keyFsc= static_cast<int>(keyF + seqF) % 7;
        scoct = static_cast<int>((keyF + seqF)/7)*12;
        keysc= Minor[keyFsc] + scoct; break;
        case 3: keyFsc= static_cast<int>(keyF + seqF) % 5;
        scoct = static_cast<int>((keyF + seqF)/5)*12;
        keysc = Penta[keyFsc] + scoct; break;
        default: 0; break;
        }
        osc.SetFreq(mtof(Menvpamt + lfopamt + keysc + oscF + oct));
        
        float pwm = hw.adc.GetFloat(8) * .9 + lfopwamt;
        if (pwm > .99){pwm = .99;}
        else if (pwm < .01){pwm = .01;}
        osc.SetPw(pwm);

        if(osc2pv==0){
        osc2.SetFreq((mtof(Menvpamt + lfopamt + keysc + osc2F + oct)));
        }
        else if(osc2pv==1){
            switch(scale)
        {
        case 0: keysc=keyF;  break;
        case 1: keyFsc= static_cast<int>(keyF) % 7;
        scoct = static_cast<int>(keyF/7)*12;
        keysc = Major[keyFsc] + scoct; break;
        case 2: keyFsc= static_cast<int>(keyF) % 7;
        scoct = static_cast<int>(keyF/7)*12;
        keysc= Minor[keyFsc] + scoct; break;
        case 3: keyFsc= static_cast<int>(keyF) % 5;
        scoct = static_cast<int>(keyF/5)*12;
        keysc = Penta[keyFsc] + scoct; break;
        default: 0; break;
        }
        osc2.SetFreq((mtof(Menvpamt + lfopamt + keysc + osc2F + oct)));
        }
        else if(osc2pv==2){
        osc2.SetFreq((mtof(Menvpamt + lfopamt + osc2F + oct)));
        }

        osc2.SetPw(pwm);

        clock.SetFreq(4 * (hw.adc.GetFloat(6) * 1.9f + .1f));

         //Set envelope parameters
        env.SetTime(ADSR_SEG_ATTACK, hw.adc.GetMuxFloat(10, 0));
        float dec = hw.adc.GetMuxFloat(10, 1);
        env.SetTime(ADSR_SEG_DECAY, (dec * dec) + (sDec/256));
        env.SetTime(ADSR_SEG_RELEASE, hw.adc.GetMuxFloat(10, 3));
        env.SetSustainLevel(trig * hw.adc.GetMuxFloat(10, 2));

         //Set Mod envelope parameters
        envM.SetTime(ADSR_SEG_ATTACK, hw.adc.GetMuxFloat(9, 3));
        float decM = hw.adc.GetMuxFloat(9, 4);
        envM.SetTime(ADSR_SEG_DECAY, (decM * decM) + (sDec/256));
        envM.SetTime(ADSR_SEG_RELEASE, hw.adc.GetMuxFloat(9, 6));
        envM.SetSustainLevel(trig * hw.adc.GetMuxFloat(9, 5));

        //OlED Stuff
        /*fonepole(Cutfone, Cut, .000001);
        int newcut = Cutfone * 10000000;
        if (newcut != ctfO){
        
        display.SetCursor(40, 2);
        
        display.WriteString("Cutoff", Font_6x8, true);
        
        display.SetCursor(50, 22);

        /
        FixedCapStr<16> str("");
        str.AppendInt(newcut);
        
        display.WriteString(str, Font_11x18, true);

        display.Update();
        
        }*/
        
//false is true
        if ((Pval==0) && (cnt < 3)  && (hw.adc.GetFloat(6) > 0)){
                dsy_gpio_write(&ledR_1_pin, false );
                dsy_gpio_write(&ledG_1_pin, false );
                dsy_gpio_write(&ledB_1_pin, true );
                }
        else if ((Pval==1) && (cnt < 3) && (hw.adc.GetFloat(6) > 0)){
                dsy_gpio_write(&ledR_1_pin, false );
                dsy_gpio_write(&ledG_1_pin, true );
                dsy_gpio_write(&ledB_1_pin, false );
                }
        else if ((Pval==2) && (cnt < 3) && (hw.adc.GetFloat(6) > 0)){
                dsy_gpio_write(&ledR_1_pin, true );
                dsy_gpio_write(&ledG_1_pin, false );
                dsy_gpio_write(&ledB_1_pin, false );
                }
        else if (trig>0 && (hw.adc.GetFloat(6) < .5))
                {dsy_gpio_write(&ledR_1_pin, false );
                dsy_gpio_write(&ledG_1_pin, false );
                dsy_gpio_write(&ledB_1_pin, false );}
        else
                {dsy_gpio_write(&ledR_1_pin, true );
                dsy_gpio_write(&ledG_1_pin, true );
                dsy_gpio_write(&ledB_1_pin, true );}
        
        
        
        
       
         
        
        
        //decO = newdec;
        //ctfO = newcut;
        
        
        
        
        

    }
}

You probably need to call this somewhere:

SavedSettings.GetSettings();

I have seen this in a black shepherd project,
where he had it in place of my = presets[preset_index].
I tried it and it didn’t work, also I assumed that the array address [preset index] is responsible for the preset number I want to load/save. However, I am going to try again. thanks!

(but on the other hand, GetSettings() was not used in my earlier state of the project, and it worked fine)

I am facing a similar problem. I defined the following struct, based on this example https://forum.electro-smith.com/t/saving-values-to-flash-memory-using-persistentstorage-class-on-daisy-pod/4306/10:

struct Settings {
	int p1; 
	int p2; 
	Applet::appletParam *ParamArray;
	Applet::appletParam testParam;
	
	//Overloading the != operator
	//This is necessary as this operator is used in the PersistentStorage source code
	bool operator!=(const Settings& a) const {
        return !(a.p1==p1 && a.p2==p2);
		
    }
};
Applet::appletParam DSY_SDRAM_BSS appletParamArray[6400];
PersistentStorage<Settings> storage(patch.qspi);

*ParamArray points to an array of structs (Applet::appletParam) in SDRAM. When I update the parameters and save to QSPI with storage.Save() everything is correctly updated. After a reboot, the paramters in the *ParamArray are reset to the default values. All the other ones like testParam are reloaded correctly.
I am sure it is not related to the overloaded operator, since it is working fine for the variable testParam.
The problem seems to be somehow related to the pointer to the array. The thing is, I can’t define an array, since it is too big to fit into DTCMRAM (I am using the bootloader mode).

Thanks for your help.

PersistentStorage works by writing the binary contents of the struct into QSPI flash. If you have a pointer in your struct, it will write the value of the pointer - i.e. the 32-bit memory address it’s pointing to - not the data at that address.

The reason it disappears after reboot is because you’re just writing a pointer to an SDRAM address into your Settings data in QSPI flash. When you reboot, the data pointed to by that pointer - data in the SDRAM - will have been cleared out, since it’s volatile memory. testParam is a value type in the struct which is why that one works correctly.

You need to actually store the data in ParamArray inside your Settings struct for this to work correctly, something like this:

struct Settings {
	int p1; 
	int p2; 
	Applet::appletParam ParamArray[32]; // replace 32 with the max possible length of this array
	Applet::appletParam testParam;
};

If the param array really needs to live in SDRAM, you’ll need to copy it out of there and into the save struct first.

If the length of ParamArray is variable, you should also add a variable to the struct representing its length.

2 Likes

Thanks a lot for your great explanation, infrasonicaudio :slight_smile:

This is exactly my problem. I have now idea how to achive this :frowning: How can I “tell” the struct to set aside a block of memory for the array without initializing it in DTCMRAM ?
A statement like:

struct Settings {
Applet::appletParam DSY_SDRAM_BSS ParamArray[32];
}

does not work. Do you have any ideas? I think there must be a way. Otherwise the
PersistentStorage struct could never be larger than the amount of available SRAM/DTCMRAM.

The array length is fixed, so no problem here.

Thanks again

Correct, the approach used by PersistentStorage assumes the storage struct fits comfortably into working memory. You might be able to allocate the PersistentStorage class instance itself into SDRAM via placement new (since it has an explicit non-default constructor, makes this a little trickier) but you’ll still have to be careful about copying your storage struct by value if it’s really big.

My 2 cents though: if you’re trying to store dozens or hundreds of kilobytes (or more) in QSPI flash you’ll need to implement your own buffered read/write strategy using the QSPI handle directly. I’m not sure it’s worth trying to fight with PersistentStorage for that use case.

Thanks again! That’s unfortunate :frowning: It least it worked partialy.

I remember when I tried the QSPI.cpp of the seed examples, nothing worked at all, or I got pretty strange results. Once I wrote to QSPI, I could not reboot my patch_sm board. I had to flash the firmware again. I guess this is related to the fact, the bootloader temporarily uses QSPI to store the firmware image. It might be solved by setting the start offset of the QSPI memory, but I could find neither the offset nor a way to set it.

All in all it is a pretty frustrating experience. I think I move on to using a SD-card and read my configs from there. Although from what I read using SD-Cards with the bootloader is not straight forward too.