electro-smith / DaisyDuino

Arduino Support for the Daisy Audio Platform.
https://www.electro-smith.com/daisy
MIT License
92 stars 20 forks source link

PersistentStorage, QSPI external flash, CpuLoadMeter support & ReverbSc extras #56

Closed snail23 closed 1 year ago

snail23 commented 1 year ago

Implementation of daisy::PersistentStorage and QSPIHandle, a single channel ReverbSc::Process, CpuLoadMeter and related functions from the latest master branch of libDaisy. So far so good while testing my Terrarium/Seed build. Quick example of use:

Initializing QSPI

// QSPI pin configuration for the Daisy Seed

#define PIN_QSPI_CLK dsy_pin(DSY_GPIOF, 10)
#define PIN_QSPI_IO0 dsy_pin(DSY_GPIOF, 8)
#define PIN_QSPI_IO1 dsy_pin(DSY_GPIOF, 9)
#define PIN_QSPI_IO2 dsy_pin(DSY_GPIOF, 7)
#define PIN_QSPI_IO3 dsy_pin(DSY_GPIOF, 6)
#define PIN_QSPI_NCS dsy_pin(DSY_GPIOG, 6)

// Init QSPI
QSPIHandle::Config qspiConfig;

qspiConfig.device = QSPIHandle::Config::IS25LP064A;
qspiConfig.mode = QSPIHandle::Config::MEMORY_MAPPED;

qspiConfig.pin_config.clk = PIN_QSPI_CLK;
qspiConfig.pin_config.io0 = PIN_QSPI_IO0;
qspiConfig.pin_config.io1 = PIN_QSPI_IO1;
qspiConfig.pin_config.io2 = PIN_QSPI_IO2;
qspiConfig.pin_config.io3 = PIN_QSPI_IO3;
qspiConfig.pin_config.ncs = PIN_QSPI_NCS;

QSPIHandle qspi;
qspi.Init(qspiConfig);

daisy::PersistentStorage usage

struct StorageData {
  int value;

  bool operator==(StorageData &rhs) {
    return this->value== rhs.value;
  }

  bool operator!=(StorageData &rhs) {
    return !this->operator==(rhs);
  }
};

PersistentStorage<StorageData> storage(qspi);
storage.Init({});

// Save current data from QSPI external flash as the default content (we're backing it up)
storage.GetDefaultSettings() = storage.GetSettings();

// Change value in internal ram buffer
storage.GetSettings().a = 1;

// Write the change to QSPI external flash
storage.Save();

// Restore previous value from QSPI external flash
storage.RestoreDefaults();

// Write the original data to QSPI external flash
storage.Save();
beserge commented 1 year ago

Tested on the Daisy Pod. I was getting an error when compiling.

In file included from C:\Users\Ben\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.5.0\libraries\SrcWrapper\src\LL\stm32yyxx_ll_delayblock.c:6:
C:\Users\Ben\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.5.0\system/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_delayblock.c: In function 'DelayBlock_Enable':
C:\Users\Ben\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.5.0\system/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_delayblock.c:113:40: error: 'DLYB_MAX_SELECT' undeclared (first use in this function)
  113 |   for (sel_current = 0U; sel_current < DLYB_MAX_SELECT; sel_current++)
      |                                        ^~~~~~~~~~~~~~~
C:\Users\Ben\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.5.0\system/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_delayblock.c:113:40: note: each undeclared identifier is reported only once for each function it appears in
C:\Users\Ben\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.5.0\system/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_ll_delayblock.c:118:44: error: 'DLYB_MAX_UNIT' undeclared (first use in this function); did you mean 'DLYB_CFGR_UNIT'?
  118 |     for (unit_current = 0U; unit_current < DLYB_MAX_UNIT; unit_current++)
      |                                            ^~~~~~~~~~~~~
      |                                            DLYB_CFGR_UNIT

This error went away when I switched to the generic STM32H750 device. I was able to fix it by adding #define HAL_SD_MODULE_ENABLED to line 7 of hal_conf_extra.h

Then, I wrote this arduino code to test audio and qspi at the same time. It basically loads the last saved note, then after 5 seconds saves a new one and updates the oscillator. You can hit reset / power cycle the device and the oscillator climbs up the scale.

#include "DaisyDuino.h"

// QSPI pin configuration for the Daisy Seed
#define PIN_QSPI_CLK dsy_pin(DSY_GPIOF, 10)
#define PIN_QSPI_IO0 dsy_pin(DSY_GPIOF, 8)
#define PIN_QSPI_IO1 dsy_pin(DSY_GPIOF, 9)
#define PIN_QSPI_IO2 dsy_pin(DSY_GPIOF, 7)
#define PIN_QSPI_IO3 dsy_pin(DSY_GPIOF, 6)
#define PIN_QSPI_NCS dsy_pin(DSY_GPIOG, 6)

DaisyHardware hw;
QSPIHandle::Config qspiConfig;
QSPIHandle qspi;
static Oscillator osc_sine;

struct StorageData {
  int value;

  bool operator==(StorageData &rhs) {
    return this->value== rhs.value;
  }

  bool operator!=(StorageData &rhs) {
    return !this->operator==(rhs);
  }
};

float num_channels;
void MyCallback(float **in, float **out, size_t size)
{
  for (size_t i = 0; i < size; i++)
  {
    float sine = osc_sine.Process();

    for (size_t chn = 0; chn < num_channels; chn++)
    {
      out[chn][i] = sine;
    }
  }
}

void setup() {
  // set up qspi and persistent storage
  qspiConfig.device = QSPIHandle::Config::IS25LP064A;
  qspiConfig.mode = QSPIHandle::Config::MEMORY_MAPPED;

  qspiConfig.pin_config.clk = PIN_QSPI_CLK;
  qspiConfig.pin_config.io0 = PIN_QSPI_IO0;
  qspiConfig.pin_config.io1 = PIN_QSPI_IO1;
  qspiConfig.pin_config.io2 = PIN_QSPI_IO2;
  qspiConfig.pin_config.io3 = PIN_QSPI_IO3;
  qspiConfig.pin_config.ncs = PIN_QSPI_NCS;

  qspi.Init(qspiConfig);

  PersistentStorage<StorageData> storage(qspi);
  storage.Init({});

  // Save current data from QSPI external flash as the default content (we're backing it up)
  storage.GetDefaultSettings() = storage.GetSettings();

  // Restore previous value from QSPI external flash
  storage.RestoreDefaults();

  // set up hardware and audio
  hw = DAISY.init(DAISY_SEED, AUDIO_SR_48K);
  num_channels = hw.num_channels;
  float sample_rate = DAISY.get_samplerate();

  // init and set to last saved frequency
  osc_sine.Init(sample_rate);
  int freq = storage.GetSettings().value;
  osc_sine.SetFreq(freq + 100);
  osc_sine.SetAmp(1.0);
  osc_sine.SetWaveform(0);

  DAISY.begin(MyCallback);

  // after 5 seconds, change to a random frequency and save to qspi
  delay(5000);
  freq = (freq + 100) % 1000;
  storage.GetSettings().value = freq;
  storage.Save();

  osc_sine.SetFreq(freq + 100);
}

// loop forever
void loop() {}

After that: