Skip to content

Repeatedly starting/ending I2S crashes? #1162

@jfrey-xx

Description

@jfrey-xx

Hello,

A bit of context: I am trying to implement audio output using both I2S and PWM Audio (an I2S chip is connected to a speaker and I'm using the PWM output as a cheap way to connect headphones when needed). Alas, when PWM is enabled, the sound via the I2S becomes corrputed (e.g. pops occurring). That even when I don't write anymore to I2S (hence the output should defaul to 0s on the I2S I believe). I don't have an oscilloscope to check what is going on with the output. That could be a separate bug report, since this is not what I am after here.

To mitigate the issue I am now trying to start/step completely each output when I want to swich back and forth between speaker and headphones. That works, if I call end() on the PWM side the I2S works properly, and when I2S is ended the speaker becomes silent. But after switching a couple times, the pico crashes (does not respond to anything, reset required). And this is the topic of this bug report.

After narrowing-down the problem it seems that just calling repeapitidely begin() / end() on the I2S causes the crash. I supected at first a memory issue, but checking the heap size with the SDK functions does not seem to indicate a leak (nor did I found one after a quick inspection of the code). The problems occurs more quickly if I output something on the Serial port. Or when I initialisie some variable (I had at first some audio buffer, global scope fixed size arrays, the reason why ), and immediately if I try to reset I2S (end/begin) too fast (twice within a second). Maybe there is something going on with the PIO and the FIFO? Before spending more time digging the code I thought it could be worth to ask if this use-case is even supported.

Here is a minimal code to reproduce the issue (tested with 2.7.1, no optimization for the compilation, with and without TinyUSB stack); sine at fixed frequency, timer to reset periosically I2S.

#define TIME_uS                     time_us_32()
#define fTime                       (TIME_uS/1000000.0)

#include <I2S.h>
I2S i2s(OUTPUT);

#define pBCLK 20
#define pWS (pBCLK+1)
#define pDOUT 22

const int sampleRate = 16000;
unsigned long timer0 = 0;
bool PWMon = true;

void setup()
{
  Serial.begin(115200);

  i2s.setBCLK(pBCLK);
  i2s.setDATA(pDOUT);
  i2s.setBitsPerSample(16);

  delay(100);
  timer0 = millis();
}

void loop()
{
  if (millis() > 3000) 
  {
    float fAmp = 50.0 * sin(2.0 * PI * fTime * 440.0);
    short amp = (short)fAmp;

    if (!PWMon) i2s.write16(amp, amp);


    if (millis() - timer0 >= 10000)
    {
      timer0 = millis();

      if (PWMon)    Serial.println("Before I2S begin : ");
      else          Serial.println("Before I2S end : ");

      if (!PWMon)    i2s.end();
      else          i2s.begin(sampleRate);

      if (PWMon)    Serial.println("After I2S begin : ");
      else          Serial.println("After I2S end : ");

      PWMon = !PWMon;
    }
  }
}

Is there something wrong with the code above, that I missed?

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions