BUG: PlaySdRaw on Teensy 3.6 -- crashes

gruvin

Member
BUG: Teensyduino v1.3.1-beta3 :: PlaySdRaw on Teensy 3.6 crashes

Howdy

Background
I recently backed the Teensy 3.5/6 campaign, as my first foray into the Teensy world. I have 2x Teensy 3.6 boards and later, a Teensy 3.2. All very cool, especially the great library code! A great deal of work must have gone in to all this. Wow! Loving it.

Today, I've been playing around with the audio library, following the video tutorial (more or less) though using DAC outputs on the '3.6, instead of the codec chip on the shield I don't have.

BUG REPORT

Context
OS X Mavericks, Arduino IDE 1.6.12, Teensyduino v1.3.1-beta3

Discovery
Everything worked amazingly well (it's super cool :) ... up until I got to playSdRaw() (not part of the tutorial). (playSdWav() works fine, though it's a little slower.) OK, so details ...

First, here's the sketch source I'm working with ...

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <CapacitiveSensor.h>

// GUItool: begin automatically generated code
AudioPlaySdRaw           playSdRaw4;     //xy=183,336
AudioPlaySdRaw           playSdRaw3;     //xy=184,287
AudioPlaySdRaw           playSdRaw1;     //xy=185,196
AudioPlaySdRaw           playSdRaw2;     //xy=185,243
AudioPlaySdRaw           playSdRaw7;     //xy=187,502
AudioPlaySdRaw           playSdRaw6;     //xy=188,452
AudioPlaySdRaw           playSdRaw5;     //xy=196,400
AudioPlaySdRaw           playSdRaw8;     //xy=203,562
AudioMixer4              mixer1;         //xy=353,268
AudioMixer4              mixer2;         //xy=360,449
AudioMixer4              mixer3;         //xy=546,359
AudioOutputAnalogStereo  dacs1;          //xy=702,359
AudioConnection          patchCord1(playSdRaw4, 0, mixer1, 3);
AudioConnection          patchCord2(playSdRaw3, 0, mixer1, 2);
AudioConnection          patchCord3(playSdRaw1, 0, mixer1, 0);
AudioConnection          patchCord4(playSdRaw2, 0, mixer1, 1);
AudioConnection          patchCord5(playSdRaw7, 0, mixer2, 2);
AudioConnection          patchCord6(playSdRaw6, 0, mixer2, 1);
AudioConnection          patchCord7(playSdRaw5, 0, mixer2, 0);
AudioConnection          patchCord8(playSdRaw8, 0, mixer2, 3);
AudioConnection          patchCord9(mixer1, 0, mixer3, 0);
AudioConnection          patchCord10(mixer2, 0, mixer3, 1);
AudioConnection          patchCord11(mixer3, 0, dacs1, 0);
AudioConnection          patchCord12(mixer3, 0, dacs1, 1);
// GUItool: end automatically generated code

#define NUM_TOUCHES 5
#define DEBOUNCE_COUNT 5
#define TOUCH_THRESHOLD 2500
typedef enum
{
  TS_IDLE,
  TS_DEBOUNCE,
  TS_OFF_WAIT
} Touch_State_TypeDef;
Touch_State_TypeDef touchState[NUM_TOUCHES];
int touchCounter[NUM_TOUCHES];

void setup() {
  Serial.begin(9600);
  AudioMemory(10);

  // Configure SPI for the audio shield pins
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  if (!SD.begin(BUILTIN_SDCARD))
  {
    while (1)
    {
      Serial.println("No SD card access!");
      delay(500);
    }
  }
  mixer1.gain(0, 0.25);
  mixer1.gain(1, 0.25);
  mixer1.gain(2, 0.25);
  mixer1.gain(3, 0.25);
  mixer2.gain(0, 0.25);
  mixer2.gain(1, 0.25);
  mixer2.gain(2, 0.25);
  mixer2.gain(3, 0.25);
  mixer3.gain(0, 0.4);
  mixer3.gain(1, 0.4);
  mixer3.gain(2, 0.4);
  mixer3.gain(3, 0.4);
}

void loop() {

  for (int i=0; i<NUM_TOUCHES; i++)
  {
    switch (touchState[i])
    {
      case TS_IDLE:
        touchCounter[i] = DEBOUNCE_COUNT;
        touchState[i] = TS_DEBOUNCE;
        break;

      case TS_DEBOUNCE:
        if (touchRead(15+i) > TOUCH_THRESHOLD)
        {
          touchCounter[i]--;
          if (touchCounter[i] == 0)
          {
            switch (i)
            {
              case 0:
                playSdRaw1.play("SNARE.RAW");
                break;
                
              case 1:
                playSdRaw2.play("KICK.RAW");
                break;
      
              case 2:
                playSdRaw3.play("TOM1.RAW");
                break;
      
              case 3:
                playSdRaw4.play("TOM2.RAW");
                break;

              case 4:
                playSdRaw5.play("TOM3.RAW");
                break;
            }
            touchState[i] = TS_OFF_WAIT;
          }
        }
        else
        {
          touchCounter[i] = DEBOUNCE_COUNT;
          touchState[i] = TS_IDLE;
        }
        break;

        case TS_OFF_WAIT:
          if (touchRead(15+i) < TOUCH_THRESHOLD)
            touchState[i] = TS_IDLE;
          break;

        default:
          touchState[i] = TS_IDLE;
          break;
          
    } // switch (touchState[i])
  } // for
} // loop

Sketch Notes
As the source suggests, the wiring set-up is pretty straight forward. I have the Teensy 3.6 connected to a USB port. I have wires with touch plates connected to pins 15 through (15+NUM_TOUCHES), inclusive. These are read using readTouch(). The for loop etc is simply a roll-my-own debounce and single-shot (non-repeating if touch pad continuously touched). All of that was working fine with playMem() and playSdWav().

The Bug
Using playSdRawN(), I can tap away on any single pad and everything seems fine. However, if I tap any other pad before the previous pad's sample has fully completed playing, CRASH.

In other words, if say, playSdRaw1() is playing and I trigger playSdRaw2() before playSdRaw1()'s sample completes, then the system hangs, some time soon after (inside one second or so) yet not immediately. If I had to guess, I would say that an in-progress DMA operation completes, generates an interrupt and right about then is when the crash occurs.

Estimated Repeatability Factor: 98.8% :p

Sample files used in the above sketch are attached. These were created using SoX, as in: sox Kick.wav -e signed -b 16 Kick.raw

Oh -- the MMC card is a, "SanDisk Ultra 8GB Class 10".

Thanks a bunch.

Bryan
New Zealand.
 

Attachments

  • samples.zip
    664.5 KB · Views: 434
Last edited:
Played around with this some more. Can't seem to find any way around it. Is there anything I can do to help find or procure a fix? Thanks.
 
Have you installed the latest TeensyDuino 1.32? There were some updates to "#include <SD.h>" that might be involved.

It may be some other conflict with the Audio library - not that up on that - but there is a sample in the Audio Tutorial that should let you show what you see - if it repro's - or show what is wrong if not.

These files are preloaded in EXAMPLES - maybe look at this or another one :: Part 2-2 Mixers & Playing Two Files
 
Have you installed the latest TeensyDuino 1.32? There were some updates to "#include <SD.h>" that might be involved.

Thanks for the reply!

I didn't know there had been an update since 1.3.1-beta. I must need to subscribe to something somewhere? I'll check it out today and update this thread with my findings.

EDIT: Have now tested with Teensyduino 3.2. No change. Same bug.

The SD library itself (with SDIO) appears to be working fine. I rather suspect the bug is in the playSdRaw1 code somewhere, being as playSdWav will go all day without a hitch. [EDIT: See post below for example sketches.]

Yes, I've been through most of the examples, learning the ropes and all. It's a pretty cool thing to have such tools for a micro-controller. Though I've wanted to play around with audio for some time, I could never find the motivation to write the low level code to make it happen. So this is great! :)
 
Last edited:
If you provide a short sketch that works with minimum-hardware (means: without touch) and shows the problem, i can look..
 
If you provide a short sketch that works with minimum-hardware (means: without touch) and shows the problem, i can look..

Thanks for the offer.

Here is a minimal test sketch, which can be used to produce the crash without any external input ...

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <CapacitiveSensor.h>

// GUItool: begin automatically generated code
AudioPlaySdRaw           playSdRaw1;     //xy=185,196
AudioPlaySdRaw           playSdRaw2;     //xy=185,243
AudioMixer4              mixer1;         //xy=353,268
AudioOutputAnalogStereo  dacs1;          //xy=702,359
AudioConnection          patchCord3(playSdRaw1, 0, mixer1, 0);
AudioConnection          patchCord4(playSdRaw2, 0, mixer1, 1);
AudioConnection          patchCord11(mixer1, 0, dacs1, 0);
AudioConnection          patchCord12(mixer1, 0, dacs1, 1);
// GUItool: end automatically generated code

void setup() {
  Serial.begin(9600);
  AudioMemory(10);

  // Configure SPI for the audio shield pins
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  if (!SD.begin(BUILTIN_SDCARD))
  {
    while (1)
    {
      Serial.println("No SD card access!");
      delay(500);
    }
  }
  mixer1.gain(0, 0.4);
}

#define DELAY_MS 5000
void loop() {
    playSdRaw1.play("TOM1.RAW");
    delay(DELAY_MS);
    playSdRaw2.play("TOM2.RAW");
    delay(DELAY_MS);    
} // loop

As given above, there should be no crash, because the next playSdRaw does not occur before the first has fully completed playing. Changing DELAY_MS from 5000 to 1000 will cause the crash.

If you change the set-up to use playSdWav, it will not crash ...
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <CapacitiveSensor.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;     //xy=185,196
AudioPlaySdWav           playSdWav2;     //xy=185,243
AudioMixer4              mixer1;         //xy=353,268
AudioOutputAnalogStereo  dacs1;          //xy=702,359
AudioConnection          patchCord3(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord4(playSdWav2, 0, mixer1, 1);
AudioConnection          patchCord11(mixer1, 0, dacs1, 0);
AudioConnection          patchCord12(mixer1, 0, dacs1, 1);
// GUItool: end automatically generated code

void setup() {
  Serial.begin(9600);
  AudioMemory(10);

  // Configure SPI for the audio shield pins
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  if (!SD.begin(BUILTIN_SDCARD))
  {
    while (1)
    {
      Serial.println("No SD card access!");
      delay(500);
    }
  }
  mixer1.gain(0, 0.4);
}

#define DELAY_MS 1000
void loop() {
    playSdWav1.play("TOM1.WAV");
    delay(DELAY_MS);
    playSdWav2.play("TOM2.WAV");
    delay(DELAY_MS);    
} // loop

I have attached the WAV versions of the samples, herein.

Thanks again.

View attachment samples_wav.zip
 
Last edited:
Gday,

I use a test for is playing to avoid the clash.

Code:
if (playSdWav1.isPlaying() == false) {
    playSdWav1.play("SDTEST5.WAV");
    delay(10); // wait for library to parse WAV info
  }

I do not set the SPI pins to play from the audio. SPI.setMOSI and SPI.setSCK could be removed.

I do use them to setup a tft but as I do not use the audio shield they are not needed for the builtin-sd, and they may be getting in the way. It looks like you are using onboard DACs, so you can probably do without them.

I recommend you update to the latest teensyduino. Frank and Paul put in fixes for the SD to independent of SPI in 1.32 beta 1.

It got me going!

1.32 is up and out of beta.
 
The code I indicated seems a good looking sample :: // Part 2-2: Mixers & Playing Multiple Sounds


Code:
void loop() {
  if (playSdWav1.isPlaying() == false) {
    Serial.println("Start playing 1");
    playSdWav1.play("SDTEST1.WAV");
    delay(10); // wait for library to parse WAV info
  }
  if (playSdWav2.isPlaying() == false) {
    Serial.println("Start playing 2");
    playSdWav2.play("SDTEST4.WAV");
    delay(10); // wait for library to parse WAV info
  }
 
Yes, but the play_sd_raw was indeed a bit buggy :)
btw, it has a spi-fix, too (but not related to the bug which caused the crash here)
See post #9 for a fixed file.
 
Thanks for the reply! This is great.

The code I indicated seems a good looking sample :: // Part 2-2: Mixers & Playing Multiple Sounds
Code:
void loop() {
...
  }

Well yes ... except that is, a) using sdPlayWav (not buggy in the first place) *and* the sound libraries are designed to allow calling playSd* without waiting for the previous sound to finish. The currently playing sound is simply stopped and the new one started. This is *essential* for my purposes.

I cannot be having any delay calls for this project, either. Speed is of the essence. ;-)
 
I'm glad it works for you.

Edit:
I hope it will be in the next beta of Teensyduino.
 
Last edited:
Back
Top