Reinitializing Audio Library after Snooze

YasarYY

Active member
Hi.

I use Snooze v6.3.9 library to snooze Teensy 4.1 with deepSleep() method. Snoozing and waking work as expected, but audio library doesn't function after waking up, i.e. doesn't play wav files via AudioPlayMemory. (I have a speaker connected to MQS output.)

I know Snooze library is old and not maintained anymore, but I cannot find an alternative either. I tried reallocating memory by AudioMemory() after wake, disabling/enabling audio interrupts before/after snooze by AudioNoInterrupts()/AudioInterrupts(), but the issue persisted. Many other chip-level suggestions are for the chip of Teensy 3.

Can anyone recommend a method on how the audio library can be revived, through reinitializing it or by any other means?

If this issue turns out not solvable, then I'll switch to hibernate() method that restarts on wake, which is not my first choice but is a solution.

Here is a minimum code with comments describing the issue, if anyone wants to have a look:

C++:
#include <Snooze.h>
#include <SnoozeBlock.h>
#include <Bounce.h>
#include "AudioSampleBird.h"  // sound sample created by wav2sketch

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlayMemory playMem1;  //xy=588,313
AudioAmplifier amp1;       //xy=744,313
AudioOutputMQS mqs1;       //xy=895,313
AudioConnection patchCord1(playMem1, amp1);
AudioConnection patchCord2(amp1, 0, mqs1, 0);
// GUItool: end automatically generated code

SnoozeTimer snoozeTimer;
SnoozeUSBSerial snoozeUsb;
SnoozeSPI snoozeSpi;
SnoozeBlock sbTimer(snoozeTimer, snoozeUsb, snoozeSpi);
bool slept = false;
const uint8_t pinButton = 28;
Bounce button = Bounce(pinButton, 50);

void setup() {
  Serial.begin(9600);
  pinMode(pinButton, INPUT_PULLUP);
  // init audio library
  AudioMemory(20);
  amp1.gain(2.0f);
  // start playing sample sound
  playMem1.play(AudioSampleBird);  // PLAYS
  Serial.println("*** setup is completed ***");
  // set snooze timer
  snoozeTimer.setTimer(5);
}

void loop() {
  // play sound if the button is pressed
  button.update();
  if (button.fallingEdge()) {
    Serial.println("starting play");
    playMem1.play(AudioSampleBird);  // DOESN'T play after snooze but hangs for several seconds and restarts
  }
  // print current millis
  Serial.printf("millis = %u", millis());
  Serial.println(playMem1.isPlaying() ? " playing" : "");
  // sleep when some seconds passed after startup
  if (!slept && millis() > 10000) {
    slept = true;
    Serial.println("going to snooze...");
    // request and wait for sending buffered serial data
    Serial.send_now();
    delay(10);
    Snooze.deepSleep(sbTimer);
    // wait for serial to reinitialize
    delay(250);
    Serial.println("awakened!");
  }
  delay(100);
}
 
It seemed (to me at least) quite complicated, if not impossible, to revive Audio Library after wake up from Snooze.deepSleep(). So a restart seems mandatory in this case. At this point I wanted to consider using Snooze.hibernate() method which already makes a restart at wake and saves a bit more milliampers.

But, it turned out that Snooze.hibernate() method cannot be used together with Teensy Audio Library on Teensy 4, because Snooze Library doesn't play nice with the Audio Library (missing SnoozeAudio driver at T4) and just causes the program to hang at method call (following with a CPU Lockup restart after several seconds). I made some attempts to solve this but I couldn't make them work together. On the other hand, I need to be able to get the wake source anyway.

So, Instead of Snooze.hibernate(), I decided to switch back to Snooze.deepSleep() method, with a software restart upon waking up. I used SRC_SRSR (Reset Status Register) and SRC_GPR5 (General Purpose Register 5) registers, to carry reset state and wake source over restarts.

For the sake of completeness, here is the relevant pseudo-code, which is like a diff w.r.t. the code at my previous post.

C++:
...
SnoozeDigital snoozeDigital;
SnoozeTimer snoozeTimer;
SnoozeUSBSerial snoozeUsb;
SnoozeSPI snoozeSpi;
SnoozeBlock sbTimer(snoozeDigital, snoozeTimer, snoozeUsb, snoozeSpi);
...
// last reset's status
uint32_t lastResetStatus;

void SoftwareReset() {
  // Write the mandatory VECTKEY and SYSRESETREQ bit to the AIRCR register
  SCB_AIRCR = 0x05FA0004;
  // Clear the instruction and data pipelines
  __asm__ volatile("dsb");
  // Block execution until the reset completes
  while (true) {};
}

void setup() {
  // get "Reset Status Register"
  lastResetStatus = SRC_SRSR;
  ...
  // define digital pin for waking the teensy up
  snoozeDigital.pinMode(28, INPUT_PULLUP, FALLING);
  ...
  // if this is a software reset after snooze, print the wake source
  if (lastResetStatus & SRC_SRSR_LOCKUP_SYSRESETREQ && SRC_GPR5 != 0) {
    Serial.print(">>> the wake source is ");
    if (SRC_GPR5 == COMPARE_WAKE) Serial.println("COMPARE");
    else if (SRC_GPR5 == ALARM_WAKE) Serial.println("ALARM");
    else if (SRC_GPR5 == TIMER_WAKE) Serial.println("TIMER");
    else if (SRC_GPR5 == TOUCH_WAKE) Serial.println("TOUCH");
    else Serial.printf("PIN %u\n", SRC_GPR5);
  }
  // clear "General Purpose Register 5"
  SRC_GPR5 = 0;
}

void loop() {
  ...
  if (resetCondition) {
    // snooze and write the wake source to "General Purpose Register 5" to be able to know it at the subsequent startup
    SRC_GPR5 = Snooze.deepSleep(sbTimer);
    // restart to make the audio library work again
    SoftwareReset();
  }
}
 
Hi Yasar,

I am having the same problem as you: Teensy 4.1 + deepSleep results in Audio stopping to function after the first wakeup.

I am using the Audio shield Rev D, for reference.

No input, no output, nothing.

What I have found out so far:
  • Adding the SnoozeAudio driver does not compile in Teensyduino with "Compilation error: 'SnoozeAudio' does not name a type"
  • Using sleep() instead of deepSleep() works fine and does not break the Audio library
My suspicion is that for Teensy 4.1 Audio and deepSleep() SnoozeAudio is needed.
  1. Can anyone confirm this?
  2. Can anyone with the required coding skills add the SnoozeAudio driver for Teensy 4.1?
 
I tried making a MWE to reproduce this. I made a very simple Audio System using the Audio system design tool where I can listen live to the Mic input over the headphone out. When not in snooze mode, mic input should be audible, while in snooze mode not.

This works if using sleep() (using line 65)

It does not work if using deepSleep() (using line 66), at least not as expected: Surprisingly, the Teensy resets at each wakeup. (I can see this from how I have programmed the onboard LED.

Code:
// Barebones test to check whether deepSleep breaks Teensy 4.1 audio

// outputting the mic input to the headphone jack

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Snooze.h>

// Snooze drivers
  SnoozeTimer snooze_timer; //for timed snooze
  // SnoozeAudio snooze_audio; --> does not compile if using this

  // install Snooze drivers to a SnoozeBlock
  SnoozeBlock snooze_config(snooze_timer);


// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=285,246
AudioOutputI2S           i2s2;           //xy=652,231
AudioConnection          patchCord1(i2s1, 0, i2s2, 0);
AudioConnection          patchCord2(i2s1, 0, i2s2, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=581,567
// GUItool: end automatically generated code


const unsigned long ON_DURATION = 1000; //[ms] how often a recording starts
const unsigned long OFF_DURATION = 1000; //[ms] how long each recording should be
const uint8_t LED_PIN = 13; //inbuilt
const int AUDIO_IN_SELECT = AUDIO_INPUT_MIC;

unsigned long snooze_duration = OFF_DURATION/1000; //Teensy 4.1 snooze timer is in seconds!

bool gone_to_sleep = false;

elapsedMillis sinceStartOn;

 void setup()
 {
  pinMode(LED_PIN, OUTPUT);

  // initialize audio
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(AUDIO_IN_SELECT);
  sgtl5000_1.volume(0.5);

  // low power timer for snooze
  snooze_timer.setTimer(snooze_duration);// milliseconds
  sinceStartOn = 0;
  digitalWrite(LED_PIN, LOW);

}

void loop()
{

 
  if (sinceStartOn>ON_DURATION)
  {
    gone_to_sleep = true;
    digitalWrite(LED_PIN, LOW);
    // Snooze.sleep(snooze_config);
    Snooze.deepSleep(snooze_config);
  }

  if (gone_to_sleep)
  {
    //only executes after wakeup
    gone_to_sleep = false;
    digitalWrite(LED_PIN, HIGH);
    sinceStartOn = 0;
  }

}
 
My suspicion is that for Teensy 4.1 Audio and deepSleep() SnoozeAudio is needed.
  1. Can anyone confirm this?
It seems so, since SnoozeAudio is missing for T4 while it's present for other Teensy versions.
(https://github.com/PaulStoffregen/Snooze/tree/examples_build/src/hal/TEENSY_40)
Audio Library Driver for Teensy 3 states that its purpose is "Teensy 3.x Audio Library Driver Snooze compatibility".
(https://github.com/PaulStoffregen/Snooze/blob/examples_build/src/hal/TEENSY_36/SnoozeAudio.h#L26)

Can anyone with the required coding skills add the SnoozeAudio driver for Teensy 4.1?
I can't add it 😅 When I take a look at SnoozeAudio code for Teensy 3, I see that I don't have the necessary low-level chip knowledge.
(https://github.com/PaulStoffregen/Snooze/blob/examples_build/src/hal/TEENSY_36/SnoozeAudio.cpp)
 
It does not work if using deepSleep() (using line 66), at least not as expected: Surprisingly, the Teensy resets at each wakeup. (I can see this from how I have programmed the onboard LED.

deepSleep() with only SnoozeTimer restarts immediately at snooze method call, even before waiting timer sleep duration. (You may not notice it since you sleep for only 1 second.)
To mitigate this, SnoozeUSBSerial and SnoozeSPI must be used as well.

Instead of:
C++:
SnoozeTimer snooze_timer;
SnoozeBlock snooze_config(snooze_timer);
Snooze.deepSleep(snooze_config);

Try this:
C++:
SnoozeTimer snooze_timer;
SnoozeUSBSerial snooze_usb;
SnoozeSPI snooze_spi;
SnoozeBlock snooze_config_plus(snooze_timer, snooze_usb, snooze_spi);
Snooze.deepSleep(snooze_config_plus);
 
To mitigate this, SnoozeUSBSerial and SnoozeSPI must be used as well.
Thanks, I missed that. I actually didn't realize that that's the behaviour with snooze_timer only.

With your additions, the deepSleep() version of my previous code breaks "as expected". You hear the mic passthrough once, before going to sleep the first time and then never again, as the Audio library is broken after the first wakeup.

C++:
// Barebones test to check whether deepSleep breaks Teensy 4.1 audio

// outputting the mic input to the headphone jack

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Snooze.h>

// Snooze drivers
  SnoozeTimer snooze_timer; //for timed snooze
  // SnoozeAudio snooze_audio; --> does not compile if using this
  SnoozeSPI snooze_spi;
  SnoozeUSBSerial snooze_usb;

  // install Snooze drivers to a SnoozeBlock
  SnoozeBlock snooze_config(snooze_timer, snooze_spi, snooze_usb);


// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=285,246
AudioOutputI2S           i2s2;           //xy=652,231
AudioConnection          patchCord1(i2s1, 0, i2s2, 0);
AudioConnection          patchCord2(i2s1, 0, i2s2, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=581,567
// GUItool: end automatically generated code


const unsigned long ON_DURATION = 1000; //[ms] how often a recording starts
const unsigned long OFF_DURATION = 1000; //[ms] how long each recording should be
const uint8_t LED_PIN = 13; //inbuilt
const int AUDIO_IN_SELECT = AUDIO_INPUT_MIC;

unsigned long snooze_duration = OFF_DURATION/1000; //Teensy 4.1 snooze timer is in seconds!

bool gone_to_sleep = false;

elapsedMillis sinceStartOn;

 void setup()
 {
  pinMode(LED_PIN, OUTPUT);

  // initialize audio
  AudioMemory(60);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(AUDIO_IN_SELECT);
  sgtl5000_1.volume(0.5);

  // low power timer for snooze
  snooze_timer.setTimer(snooze_duration);// milliseconds
  sinceStartOn = 0;
  digitalWrite(LED_PIN, LOW);

}

void loop()
{

 
  if (sinceStartOn>ON_DURATION)
  {
    gone_to_sleep = true;
    digitalWrite(LED_PIN, LOW);
    // Snooze.sleep(snooze_config);
    Snooze.deepSleep(snooze_config);
  }

  if (gone_to_sleep)
  {
    //only executes after wakeup
    gone_to_sleep = false;
    digitalWrite(LED_PIN, HIGH);
    sinceStartOn = 0;
  }

}
 
Back
Top