Feather M4 (SAMD51) Disable/Re-Enable I2S

Hey Guys,

Having a bit of trouble using I2S on a SAMD51 and then disabling I2S, sleeping and then re-enabling and using I2S again.

I’m using a modified version of the WavFilePlayer example from the Adafruit fork of the Audio library (GitHub - adafruit/Audio: Teensy Audio Library). I’ve been struggling a bit trying to figure out how to re-initialize I2S after going into a low-power sleep mode. It would be useful to look at the code I am using to give you guys an idea of what I am talking about. Here is what I am using, basically as I said a modified version of the WavFilePlayer example, with sleep integrated into it:

#include <Audio.h>[color=#2e8b57][/color]
#include <SdFat.h>[color=#2e8b57][/color]
#include <Adafruit_SPIFlash.h>[color=#2e8b57][/color]
#include <play_fs_wav.h>[color=#2e8b57][/color]
#include <Adafruit_SleepyDog.h>[color=#2e8b57][/color]
[color=#2e8b57][/color]
AudioPlayFSWav           playFSWav;[color=#2e8b57][/color]
AudioOutputI2S           audioOutput;[color=#2e8b57][/color]
AudioConnection          patchCord1(playFSWav, 0, audioOutput, 1);[color=#2e8b57][/color]
AudioConnection          patchCord2(playFSWav, 1, audioOutput, 0);[color=#2e8b57][/color]
[color=#2e8b57][/color]
Adafruit_FlashTransport_QSPI flashTransport(PIN_QSPI_SCK, PIN_QSPI_CS, PIN_QSPI_IO0, PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3);[color=#2e8b57][/color]
[color=#2e8b57][/color]
Adafruit_SPIFlash flash(&flashTransport);[color=#2e8b57][/color]
FatFileSystem QSPIFS;[color=#2e8b57][/color]
SdFat SD;[color=#2e8b57][/color]
bool QSPIOK = false;[color=#2e8b57][/color]
[color=#2e8b57][/color]
int pin_i2s_power = 6;[color=#2e8b57][/color]
int pin_i2s_din = 11;[color=#2e8b57][/color]
int pin_i2s_lrclk = 10;[color=#2e8b57][/color]
int pin_i2s_tx_d1 = 1;[color=#2e8b57][/color]
[color=#2e8b57][/color]
void setup() {[color=#2e8b57][/color]
  pinMode(6, OUTPUT);[color=#2e8b57][/color]
  digitalWrite(6, HIGH);[color=#2e8b57][/color]
[color=#2e8b57][/color]
  AudioMemory(8);[color=#2e8b57][/color]
[color=#2e8b57][/color]
  QSPIOK = false;[color=#2e8b57][/color]
  if (!flash.begin()) {[color=#2e8b57][/color]
    Serial.println("Error, failed to initialize flash chip!");[color=#2e8b57][/color]
  } else if (!QSPIFS.begin(&flash)) {[color=#2e8b57][/color]
    Serial.println("Failed to mount QSPI filesystem!");[color=#2e8b57][/color]
    Serial.println("Was CircuitPython loaded on the board first to create the filesystem?");[color=#2e8b57][/color]
  } else {[color=#2e8b57][/color]
    Serial.println("QSPI OK!");[color=#2e8b57][/color]
    QSPIOK = true;[color=#2e8b57][/color]
  }[color=#2e8b57][/color]
   playFSWav.changeVolume(1.0);[color=#2e8b57][/color]
}[color=#2e8b57][/color]
[color=#2e8b57][/color]
void playFile(const char *filename)[color=#2e8b57][/color]
{[color=#2e8b57][/color]
  File f = QSPIFS.open(filename);[color=#2e8b57][/color]
 [color=#2e8b57][/color]
  if (!playFSWav.play(f)) {[color=#2e8b57][/color]
    Serial.println("Failed to play");[color=#2e8b57][/color]
    return;[color=#2e8b57][/color]
  }[color=#2e8b57][/color]
  Serial.println("QSPI OK!");[color=#2e8b57][/color]
}[color=#2e8b57][/color]
[color=#2e8b57][/color]
[color=#2e8b57][/color]
void loop() {[color=#2e8b57][/color]
 [color=#2e8b57][/color]
    digitalWrite(6, HIGH);[color=#2e8b57][/color]
[color=#2e8b57][/color]
    playFile("battery.wav");[color=#2e8b57][/color]
    delay(6);[color=#2e8b57][/color]
    while(playFSWav.isPlaying()) delay(1);[color=#2e8b57][/color]
[color=#2e8b57][/color]
    enterLowPowerState();[color=#2e8b57][/color]
    Watchdog.sleep(2000);[color=#2e8b57][/color]
   [color=#2e8b57][/color]
}[color=#2e8b57][/color]
[color=#2e8b57][/color]
void enterLowPowerState() {[color=#2e8b57][/color]
[color=#2e8b57][/color]
  if (!playFSWav.isPlaying()) {[color=#2e8b57][/color]
    digitalWrite(pin_i2s_power, LOW);[color=#2e8b57][/color]
    I2S->CTRLA.bit.ENABLE=0;//THIS ACHIEVES HUGE POWER SAVINGS, BUT I DON'T KNOW HOW TO TURN IT BACK ON[color=#2e8b57][/color]
  }[color=#2e8b57][/color]
[color=#2e8b57][/color]
}

You can see where I turn off “I2S->CTRLA.bit.ENABLE=0;” and it achieves amazing power savings, but I can’t figure out how to reinitialize and make it work. How do I get out of sleep and play another WAV file? I thought it would be something simple like I2S->CTRLA.bit.ENABLE=1; … any ideas on why that wouldn’t work or other solutions? Could one simply shut off the clocks to I2S? I couldn’t figure out how to do that. Thanks guys!

Hi Casey10110,

Although it might not be the problem, it is however necessary to wait for the I2S's CTRLA register to synchronize, when setting or clearing the ENABLE bit:

I2S->CTRLA.bit.ENABLE = 0;  // Disable the I2S peripheral
while (I2S->SYNCBUSY.bit.ENABLE);  // Wait for synchronization

This will ensure that the I2S module has indeed been disabled, before putting the microcontroller to sleep.

For sure, thanks Martin. Unfortunately that isn't the issue. I think there must be some more things that get "uninitialized" when disabling the I2S and I'm trying to figure out how to reconfigure ...