audio library wakes up teensy from hibernate

Both would have to be set after I2S was started but before going to sleep.
For the transmitter : I2S0_TCSR |= I2S_TCSR_STOPE which keeps it running even in STOP mode
For the receiver : I2S0_RCSR |= I2S_RCSR_STOPE which keeps it running even in STOP mode

Another method to give a try would be forcing the I2S enable after waking up, which should also relaunch the clock generation.
For the transmitter : I2S0_TCSR |= I2S_TCSR_TE
For the receiver : I2S0_RCSR |= I2S_RCSR_RE

More info in Chapter 48, page 1297 of the MK20DX256 reference manual.
 
Both would have to be set after I2S was started but before going to sleep.
For the transmitter : I2S0_TCSR |= I2S_TCSR_STOPE which keeps it running even in STOP mode
For the receiver : I2S0_RCSR |= I2S_RCSR_STOPE which keeps it running even in STOP mode

Another method to give a try would be forcing the I2S enable after waking up, which should also relaunch the clock generation.
For the transmitter : I2S0_TCSR |= I2S_TCSR_TE
For the receiver : I2S0_RCSR |= I2S_RCSR_RE

More info in Chapter 48, page 1297 of the MK20DX256 reference manual.

Is this meant to be used in addition to turning off the I2S clock gate or instead?
 
In addition. Just try it out.

Versuch macht kluch, as the Germans say... ;)

The SIM handles the clock and the activation of the I2S module. My additional "tweaks" affect a different thing, the clock generated by the I2S module afterwards. IMHO it is not an optimal idea to deactivate the I2S fully via the SIM, especially that the I2S module has support for low power and stop modes.

Study the reference manual for better understanding.
 
Last edited:
I tried both your suggestions, with and without shutting down the I2S clock via SIM and also some other configurations that I thought were clever :p Neither worked as expected.
Not of the configurations resulted in empty files, others produced the beeping sound again :confused:

Versuch macht kluch, as the Germans say...
Didn't work out for now :D
 
Both would have to be set after I2S was started but before going to sleep.
For the transmitter : I2S0_TCSR |= I2S_TCSR_STOPE which keeps it running even in STOP mode
For the receiver : I2S0_RCSR |= I2S_RCSR_STOPE which keeps it running even in STOP mode
The K66/K20 manuals says: Configures receiver operation in Stop mode. This bit is ignored and the receiver is disabled in all low- leakage stop modes


and also from the manuals:
61.1.3.2 Low-leakage modes
When entering low-leakage modes, the Stop Enable (TCSR[STOPE] and RCSR[STOPE]) bits are ignored and the SAI is disabled after completing the current transmit and receive Frames. Entry into stop mode is prevented (not acknowledged) while waiting for the transmitter and receiver to be disabled at the end of the current frame.

'deepSleep' and 'hibernate' are low-leakage modes so that clock cannot remain active. You might have to monitor the I2S Transmitter and Receiver for them to be officially disabled before going into low power mode i.e. 'deepSleep', 'hibernate'
 
Great, it's working! Thank you WMXZ and duff.

You have to enable the I2S-clock after the wake up:
Code:
SIM_SCGC6 |= SIM_SCGC6_I2S;
worked for me!

What file is this code being added to and which line? I am using a teensy 4.0 and the corresponding Audio Adapter Board. When I searched "SIM_SCGC6" in Duff's github, I see that it's used in the SnoozeAlarm.cpp for other teensy models, but it is not in the code for the teensy 4.0. Was hoping to find it in used in there for context clues.

Background on my issue:
I'm trying to integrate two pieces of code: 1) The first is the code Duff provided here (link 1 below) which enables you to schedule snooze functionality. The second is Arduino's example file (examples>Audio>WavFilePlayer). Perhaps somewhat obviously, the aim is to play audio on a schedule and have the teensy go into low power mode when the audio isn't playing.

link 1: https://forum.pjrc.com/threads/60695-Teensy-3-6-RTC-not-continues-time-in-hibernation

I've pasted my code below. After incorporating the code under the "Teensy Audio Setup" heading, my teensy no longer wakes up from hibernate. In the name of isolating the problem for more efficient debugging, I've commented out all lines following these ones that have to do with the audio player. I think my problem is caused by issue noted in this thread, but I do not know where to insert that line of code in the header files. Including these other details in case my thinking is mistaken and the problem lies elsewhere. Thanks so much for your help in advance!

Code:
//This code combines Duff's code for scheduled teensy sleep with the WAV File player example

#include <Snooze.h>
#include <TimeLib.h>
#include <TimeAlarms.h>

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
//---------------------------------------------------------------------------
// Load drivers
SnoozeAlarm alarm;
// SnoozeUSBSerial driver does what Serial does like "print", -
// "println", "prinf", etc and also handles the effects of using -
// the Arduino Serial monitor and sleeping. Use it when you -
// want to print to serial monitor for sleeping applications.
SnoozeUSBSerial usb;
//---------------------------------------------------------------------------
// install drivers to a SnoozeBlock
SnoozeBlock config_teensy36(usb, alarm);
//---------------------------------------------------------------------------
// Teensy Audio Setup

//Going sequentially from the top, commenting out all audio stuff, this is where I hit issues
//once these lines are uncommented, the teensy does not wake up as instructed
AudioPlaySdWav           playWav1;
AudioOutputI2S           audioOutput;
AudioConnection          patchCord1(playWav1, 0, audioOutput, 0);
AudioConnection          patchCord2(playWav1, 1, audioOutput, 1);
AudioControlSGTL5000     sgtl5000_1;

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

//---------------------------------------------------------------------------
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWriteFast(LED_BUILTIN, HIGH); //turn the LED on
  
  // Set RtcTimer for test mode (Teensy should wake up in 10 seconds)
  alarm.setRtcTimer(0, 0, 10);// hour, min, sec
  // set the Time library to use Teensy 3.6's RTC to keep time
  setSyncProvider(getTeensy3Time);
  
  while (!usb);  // Wait for Arduino Serial Monitor to open
  delay(100);
  if (timeStatus() != timeSet) {
    usb.println("Unable to sync with the RTC");
  } else {
    usb.println("RTC has set the system time");
  }
  
  // Set timer for test mode
  Alarm.timerRepeat(10, GoToSleep); //go to sleep 10 sec after power on
  // Set timer For productive mode
  //Alarm.alarmRepeat(22,00,00,GoToSleep);

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  /*
  AudioMemory(8);
  
  // Comment these out if not using the audio adaptor board.
  // This may wait forever if the SDA & SCL pins lack
  // pullup resistors
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    // stop here, but print a message repetitively
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  */
}
//---------------------------------------------------------------------------
void loop() {
  if (usb.available()) {
    time_t t = processSyncMessage();
    if (t != 0) {
      Teensy3Clock.set(t); // set the RTC
      setTime(t);
    }
  }
  digitalClockDisplay();
  Alarm.delay(1000);
}
//---------------------------------------------------------------------------
void GoToSleep() {
  // Set RtcTimer for productive mode (Teensy should wake up at 7:00am )
  //alarm.setRtcTimer(9, 0, 0);// hour, min, sec
  usb.println("Going to hibernate Sleep now");
  delay(5);
  digitalWriteFast(LED_BUILTIN, LOW);
  Snooze.hibernate( config_teensy36 );
  digitalWriteFast(LED_BUILTIN, HIGH);
  setSyncProvider(getTeensy3Time);
  //usb.println("Playing Audio");
  //delay(5);
  //playFile("BACH.WAV");  // filenames are always uppercase 8.3 format
}
//---------------------------------------------------------------------------
time_t getTeensy3Time() {
  return Teensy3Clock.get();
}
//---------------------------------------------------------------------------
void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(year());
  Serial.print("-");
  Serial.print(month());
  Serial.print("-");
  Serial.print(day());
  Serial.println();
}
//---------------------------------------------------------------------------
/*  code to process time sync messages from the serial port   */
#define TIME_HEADER  "T"   // Header tag for serial time sync message
unsigned long processSyncMessage() {
  unsigned long pctime = 0L;
  const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013
  if (Serial.find(TIME_HEADER)) {
    pctime = usb.parseInt();
    return pctime;
    // check the value is a valid time (greater than Jan 1 2013)
    if ( pctime < DEFAULT_TIME) {
      // return 0 to indicate that the time is not valid
      pctime = 0L; 
    }
  }
  return pctime;
}
//---------------------------------------------------------------------------
void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  usb.print(":");
  if (digits < 10)
    usb.print('0');
  usb.print(digits);
}
//---------------------------------------------------------------------------
/*
void playFile(const char *filename)
{
  Serial.print("Playing file: ");
  Serial.println(filename);

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playWav1.play(filename);

  // A brief delay for the library read WAV info
  delay(25);

  // Simply wait for the file to finish playing.
  while (playWav1.isPlaying()) {
    // uncomment these lines if you audio shield
    // has the optional volume pot soldered
    //float vol = analogRead(15);
    //vol = vol / 1024;
    // sgtl5000_1.volume(vol);
  }
}
  */
  //---------------------------------------------------------------------------
 
Hello, I have the same issue with teensy 4.0.
Sleep work but not hibernate or deepsleep.

Does someone manage to correct the issue? Or have a solution to reduce the power consomption without the usage of Snooze?

Thanks
Pierre
 
I have used it in the past to wake up from deepsleep using a change in pin status.
Hello Bricomp, thank you for your response.

When you mention a change in pin status, do you mean a change in the I2S pin or the wakeup pin?
Currently, I'm using the basic code from the Snooze example, but with the audio.h library. I would be infinitely grateful if you could provide the necessary changes to implement this on the pin.

Here's the basic code I'm using:

Code:
//*****************************LIBRARY
#include <Snooze.h>
#include <Audio.h>


//*****************************AUDIO SETTINGS
AudioControlSGTL5000 sgtl5000_1;
AudioOutputI2S i2s2;



//*****************************Variables

//low power
SnoozeUSBSerial usb;
SnoozeDigital digital;
SnoozeBlock config_teensy40(usb, digital);



void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digital.pinMode(15, INPUT_PULLUP, FALLING);  //pin, mode, type

  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

void loop() {
  Snooze.hibernate(config_teensy40);  // return module that woke processor
}
 
Below is something I wrote a long time ago for testing Snooze.

It will come live from Sleep by applying 3.3V on either pins 0 or 9.
Give it a try.
Caveat: I have NOT used this for a very large time.

Code:
#include <Snooze.h>

// Load drivers
SnoozeDigital digital;
SnoozeTimer timer;
SnoozeUSBSerial usb;
//SnoozeBlock config_teensy(usb, timer);
SnoozeBlock config_teensy(usb, timer, digital);    ///*** REB ADDED / CHANGED
const int maxHistorySize = 40;                      //**** REB ADDED 3333

struct hData                                        //**** REB ADDED 3333
{                                                   //**** REB ADDED 3333
    char text[25];                                  //**** REB ADDED 3333
    unsigned long time;                             //**** REB ADDED 3333
};                                                  //**** REB ADDED 3333
hData history[maxHistorySize];                                 //**** REB ADDED 3333
int idx = 0;                                        //**** REB ADDED 3333

// set pin numbers:
const int button1Pin = 0;   // sw1
const int button2Pin = 9;   // sw2
const int led1Pin =  21;    // led1
const int led2Pin =  20;    // led2

void setup() {
  Serial.begin(115200);
  while (!usb){};
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);

  digital.pinMode(button1Pin, INPUT_PULLUP, FALLING);//pin, mode, type
  digital.pinMode(button2Pin, INPUT_PULLUP, FALLING);//pin, mode, type

  timer.setTimer(5000);// milliseconds
//  usb.println("Setup Done");
}
  bool done1=false;           //**** REB ADDED 2222
  bool done2=false;           //**** REB ADDED 2222
  bool done3=false;           //**** REB ADDED 2222


void loop() {
 
  int who;
  static elapsedMillis clock;
  uint32_t iWokeUpAt;        //**** REB ADDED ****
  uint32_t usbWokeUpAt;      //**** REB ADDED ****
 
    if ((done3==false) && (clock >= 1000)) {                 //**** REB ALTERED 2222
        done3=true;
        strncpy(history[idx].text, "three", 10);            //**** REB ADDED 3333
        history[idx].time = millis();                       //**** REB ADDED 3333
        ++idx;                                              //**** REB ADDED 3333
        usb.println("three");
        digitalWrite(led2Pin, HIGH);
        delay(200);
        digitalWrite(led2Pin, LOW);
    } else if ((done2==false) && (clock >= 2000)) {          //**** REB ALTERED 2222
      done2=true;
        strncpy(history[idx].text, "two", 10);                //**** REB ADDED 3333
        history[idx].time = millis();                         //**** REB ADDED 3333
        ++idx;                                                //**** REB ADDED 3333
        usb.println("two");
        digitalWrite(led2Pin, HIGH);
        delay(200);
        digitalWrite(led2Pin, LOW);
  } else if ((done1==false) && (clock >= 3000)) {          //**** REB ALTERED 2222
        done1=true;
        strncpy(history[idx].text, "one", 10);                //**** REB ADDED 3333
        history[idx].time = millis();                         //**** REB ADDED 3333
        ++idx;                                                //**** REB ADDED 3333
        usb.println("one");
        digitalWrite(led2Pin, HIGH);
        delay(200);
        digitalWrite(led2Pin, LOW);
  } else if (clock > 4000){
        strncpy(history[idx].text, "zzz", 10);                //**** REB ADDED 3333
        history[idx].time = millis();                         //**** REB ADDED 3333
        ++idx;                                                //**** REB ADDED 3333
        usb.println("zzz");
        done1=false;                          //**** REB ADDED 2222
        done2=false;                          //**** REB ADDED 2222
        done3=false;                          //**** REB ADDED 2222
 

        delay(10);
    
    /********************************************************
      feed the sleep function its wakeup parameters. Then go
      to deepSleep.
    ********************************************************/

        usb.flush(); 
        delay(500);
//      config_teensy += digital;                   //**** REB REMOVED ****
        who = Snooze.deepSleep( config_teensy );// return module that woke processor
//      config_teensy -= digital;                   //**** REB REMOVED ****
        iWokeUpAt = millis();                           //**** REB ADDED ****
    
        while (!usb && (millis() < iWokeUpAt + 8000));  //**** REB ADDED ****
        usbWokeUpAt = millis();                         //**** REB ADDED ****

        delay(500);

        strncpy(history[idx].text, "Good morning", 25);       //**** REB ADDED 3333
        history[idx].time = millis();                         //**** REB ADDED 3333
        ++idx;                                                //**** REB ADDED 3333
        usb.println("Good morning");
        usb.print("who="); usb.println(who);            //**** REB ADDED ****
        usb.print("Time to wake up usb=");              //**** REB ADDED ****
        usb.print(usbWokeUpAt - iWokeUpAt);             //**** REB ADDED ****
        usb.println("ms");                              //**** REB ADDED ****

        if (who == button1Pin) { // pin wakeup source is its pin value
            for (int i = 0; i < 1; i++) {
                digitalWrite(led1Pin, HIGH);
                delay(200);
                digitalWrite(led1Pin, LOW);
                delay(200);
            }
        }

        if (who == button2Pin) { // pin wakeup source is its pin value
            for (int i = 0; i < 2; i++) {
                digitalWrite(led1Pin, HIGH);
                delay(200);
                digitalWrite(led1Pin, LOW);
                delay(200);
            }
        }

        if (who == 34) { // compare wakeup value
            for (int i = 0; i < 3; i++) {
                digitalWrite(led1Pin, HIGH);
                delay(200);
                digitalWrite(led1Pin, LOW);
                delay(200);
            }
        }

        if (who == 35) { // rtc wakeup value
            for (int i = 0; i < 4; i++) {
                digitalWrite(led1Pin, HIGH);
                delay(200);
                digitalWrite(led1Pin, LOW);
                delay(200);
            }
        }

        if (who == 36) { // lptmr wakeup value
            for (int i = 0; i < 5; i++) {
                digitalWrite(led1Pin, HIGH);
                delay(200);
                digitalWrite(led1Pin, LOW);
                delay(200);
            }
        }

        if (who == 37) { // tsi wakeup value
            for (int i = 0; i < 6; i++) {
                digitalWrite(led1Pin, HIGH);
                delay(200);
                digitalWrite(led1Pin, LOW);
                delay(200);
            }
        }
        clock = 0;
    }
    if (idx >= maxHistorySize-2)                                                //**** REB ADDED 3333
    {
        usb.println("------------- HISTORY --------------------");              //**** REB ADDED 3333

        for (int n = 0; n < idx; ++n)                                           //**** REB ADDED 3333
        {                                                                       //**** REB ADDED 3333
            usb.print(history[n].time);                                         //**** REB ADDED 3333
            usb.print(" - ");                                                   //**** REB ADDED 3333
            usb.println(history[n].text);                                       //**** REB ADDED 3333
        }                                                                       //**** REB ADDED 3333
        usb.println(idx);                                                       //**** REB ADDED 3333
        usb.println("---------- END OF HISTORY ----------------");              //**** REB ADDED 3333
        idx = 0;                                                                //**** REB ADDED 3333
        while (1);                                                              //**** REB ADDED 3333
    }
}
 
I try your code, but sadly it's the same problem once I add I2S...

Actually I don't have any problem to go in deepsleep, even in hibernate. The problem is the combinaison with I2S:
If I comment these line from my previous code:

Code:
//AudioControlSGTL5000 sgtl5000_1;
//AudioOutputI2S i2s2;

I go fom 30mA to ~3mA. Sadly when these line are uncommented, the teensy never go to hibernate and continously reset.
 
It would appear that the Teensy is crashing.
You can add crash report to the beginning of your program to see what is causing it.
I am replying on my phone at the moment so can't give you much pointers at the moment.
Search the forum for crash report
 
It seem that there are no crash detected, but it look like that sleep mode cannot be monitoring :

Code:
No Crash Data To Report
  Hopefully all is well, but certain types of crashes can't be reported:
    stuck in an infinite loop (technically, hardware still running properly)
    remaining in a low power sleep mode
    access to certain peripherals without their clock enabled (eg, FlexIO)
    change of CPU or bus clock speed without use of glitchless mux

I'm not sure there is a crash, I think that the I2S use disable the low power mode, and as teensy 4 reset when it quit low power mode it can be normal that it reset in loop ..
 
Ah, I seem to remember that a wake up from Hibernate results in a re-boot, whereas a deepsleep wakeup carries on from where the snooze took place.
 
Hum, I try several technique to disable I2S or even DMA but I still have no result... I'm quitte a newbie on software but may anyone have some knowledge on that?
 
Sadly the snooze isn't fully supported in T4 IMO, not sure if it would be there later, or does anyone had a solution?
 
Sadly the snooze isn't fully supported in T4 IMO, not sure if it would be there later, or does anyone had a solution?
If you wanted true hibernate with wake-up by RTC alarm, here is what I'm using
Code:
#if defined (__IMXRT1062__)
  #define SNVS_LPCR_LPTA_EN_MASK          (0x2U)    ///< mask to put MCU to hibernate

  // see also https://forum.pjrc.com/threads/58484-issue-to-reporogram-T4-0?highlight=hibernate
  /**
   * @brief Set the Wakeup Call object
   *
   * @param nsec number of seconds to sleep
   */
  void setWakeupCall(uint32_t nsec)
  {
    uint32_t tmp = SNVS_LPCR; // save control register

    SNVS_LPSR |= 1;

    // disable alarm
    SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
    while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK);

    __disable_irq();

    //get Time:
    uint32_t lsb, msb;
    do {
      msb = SNVS_LPSRTCMR;
      lsb = SNVS_LPSRTCLR;
    } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) );
    uint32_t secs = (msb << 17) | (lsb >> 15);

    //set alarm
    secs += nsec;
    SNVS_LPTAR = secs;
    while (SNVS_LPTAR != secs);

    // restore control register and set alarm
    SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK;
    while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));

    __enable_irq();
  }

  /**
   * @brief Shut down Tessnsy
   *
   */
  void powerDown(void)
  {
    SNVS_LPCR |= (1 << 6); // turn off power
    while (1) asm("wfi");     
  }

  /**
   * @brief Set the Wakeup Call and Sleep object
   *
   * @param nsec number of seconds to sleep
   */
  void setWakeupCallandSleep(uint32_t nsec)
  {
    setWakeupCall(nsec);
    powerDown();
  }

 #endif
 
If you wanted true hibernate with wake-up by RTC alarm, here is what I'm using
Code:
#if defined (__IMXRT1062__)
  #define SNVS_LPCR_LPTA_EN_MASK          (0x2U)    ///< mask to put MCU to hibernate

  // see also https://forum.pjrc.com/threads/58484-issue-to-reporogram-T4-0?highlight=hibernate
  /**
   * @brief Set the Wakeup Call object
   *
   * @param nsec number of seconds to sleep
   */
  void setWakeupCall(uint32_t nsec)
  {
    uint32_t tmp = SNVS_LPCR; // save control register

    SNVS_LPSR |= 1;

    // disable alarm
    SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
    while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK);

    __disable_irq();

    //get Time:
    uint32_t lsb, msb;
    do {
      msb = SNVS_LPSRTCMR;
      lsb = SNVS_LPSRTCLR;
    } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) );
    uint32_t secs = (msb << 17) | (lsb >> 15);

    //set alarm
    secs += nsec;
    SNVS_LPTAR = secs;
    while (SNVS_LPTAR != secs);

    // restore control register and set alarm
    SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK;
    while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));

    __enable_irq();
  }

  /**
   * @brief Shut down Tessnsy
   *
   */
  void powerDown(void)
  {
    SNVS_LPCR |= (1 << 6); // turn off power
    while (1) asm("wfi");    
  }

  /**
   * @brief Set the Wakeup Call and Sleep object
   *
   * @param nsec number of seconds to sleep
   */
  void setWakeupCallandSleep(uint32_t nsec)
  {
    setWakeupCall(nsec);
    powerDown();
  }

 #endif
With this code, it go in hibernate even with I2S (it seem that the power is even lower than with the snooze function) !
By any chance, do you have a code with the digital interrupt?
 
Back
Top