adafruit / Adafruit_VS1053_Library

This is a Arduino library for the Adafruit VS1053 Codec Breakout and Music Maker Shields
https://www.adafruit.com/products/1381
135 stars 113 forks source link

Crashes on ESP32 when using interrupts #45

Closed danclarke closed 2 years ago

danclarke commented 6 years ago

The interrupt-based playback does not work on ESP32, calling the SD library from within an interrupt handler seems to cause an almost immediate crash. The exception stack trace is as follows:

0x400812f5: lock_acquire_generic at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/newlib/./locks.c line 141
0x40087754: invoke_abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/./panic.c line 648
0x4008792f: abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/./panic.c line 648
0x400812f5: lock_acquire_generic at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/newlib/./locks.c line 141
0x40081415: _lock_acquire_recursive at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/newlib/./locks.c line 169
0x400da302: _fread_r at /Users/ivan/e/newlib_xtensa-2.2.0-bin/newlib_xtensa-2.2.0/xtensa-esp32-elf/newlib/libc/stdio/../../../.././newlib/libc/stdio/fread.c line 194 (discriminator 2)
0x400da3c9: fread at /Users/ivan/e/newlib_xtensa-2.2.0-bin/newlib_xtensa-2.2.0/xtensa-esp32-elf/newlib/libc/stdio/../../../.././newlib/libc/stdio/fread.c line 301
0x400d280b: VFSFileImpl::read(unsigned char*, unsigned int) at c:\users\dancl\documents\arduino\hardware\espressif\esp32\tools\xtensa-esp32-elf\xtensa-esp32-elf\include\c++\5.2.0\bits/shared_ptr_base.h line 127 (discriminator 1)
0x400ec6e7: fs::File::read(unsigned char*, unsigned int) at C:\Users\dancl\Documents\Arduino\hardware\espressif\esp32\libraries\FS\src/FS.cpp line 258
0x400d1314: Adafruit_VS1053_FilePlayer::feedBuffer_noLock() at C:\Users\dancl\Documents\Arduino\libraries\Adafruit_VS1053_Library/Adafruit_VS1053.cpp line 737 (discriminator 1)
0x400d1355: Adafruit_VS1053_FilePlayer::feedBuffer() at C:\Users\dancl\Documents\Arduino\libraries\Adafruit_VS1053_Library/Adafruit_VS1053.cpp line 737 (discriminator 1)
0x400d1368: feeder() at C:\Users\dancl\Documents\Arduino\libraries\Adafruit_VS1053_Library/Adafruit_VS1053.cpp line 737 (discriminator 1)
0x40080ddd: __onPinInterrupt at C:\Users\dancl\Documents\Arduino\hardware\espressif\esp32\cores\esp32/esp32-hal-gpio.c line 211
0x400817d9: _xt_lowint1 at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/./xtensa_vectors.S line 1105
0x400dbc63: esp_vApplicationIdleHook at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/./freertos_hooks.c line 85

I've done a quick test where the interrupt handler sets a flag, letting the main loop know to populate the buffer and that works fine. I'm pretty sure I can set up a solution using a separate task to just feed the buffer as and when with maybe a larger memory buffer to cater for the extra latency. Of course this will be super ESP32 specific and couldn't be integrated back into the library.

danclarke commented 6 years ago

Small update - I got it working with some very small amends to the library, the task can be created transparently within the library itself. I'll continue testing and create a PR if I'm happy with how it works.

brandondixon commented 6 years ago

@danclarke I was about to dive into this problem. Do you have any working code? I would love to help test/debug.

danclarke commented 6 years ago

@brandondixon I do, I've put a fork up here: https://github.com/danclarke/Adafruit_VS1053_Library

In my specific application I was getting some odd behaviour, but it could be power related. I've tried with some much more advanced workarounds and changes, and they seem to get progressively worse than the simple code I've uploaded. Sadly I haven't had the time to fully investigate.

TheNitek commented 6 years ago

Why do you want to use interrupts when you have to feed the buffer in the main loop anyway?

Something like

void loop() {
  if (musicPlayer.playingMusic) {
    musicPlayer.feedBuffer();
  }
}

will do fine without any interrupts.

The main Problem is that the ESP8266 and ESP32 do not support this function: https://www.arduino.cc/en/Reference/SPIusingInterrupt This makes SPI communication and interrupts a hassle.

brandondixon commented 6 years ago

I'm stuck using an ESP32 :(

TheNitek commented 6 years ago

There's nothing wrong using an ESP32, IMHO it's just easier not to use this library with interrupts on it, but with manual buffer feeding as shown in my previous post

danclarke commented 6 years ago

@TheNitek It's so that you can play audio in the background while performing other tasks without having to worry about keeping the buffer fed manually.

Interestingly I created a task where the sole purpose is to call the feed method, and I still get the same audio corruption in the same place. I'm thinking it's due to how I'm using the audio files specifically so more investigation required. On the plus side, it behaved in an identical manner to my interrupt workaround.

danclarke commented 6 years ago

Well I found the source of the audio corruption, seems my SD card was slowly getting more and more corrupted. Also I found wav files I was using to play very slightly less reliably than mp3. I don't think it's due to insufficient feeding of the buffer, but I don't know enought to say for certain. It was a slight lack of dynamic range rather than static.

Anyway if the workaround for the interrupt / SPI access works OK for others, I'll submit a PR.

NitramLegov commented 6 years ago

It works for me using the devkit1 board. I would love to see this in the official library!

paulmand3l commented 5 years ago

Works for me on the Huzzah Esp32 feather. Thanks!

eziya commented 5 years ago

Hello, I'm adding my modification link for who might run into same issue like me https://github.com/eziya/ESP32_ADAFRUIT_VS1053

bentwookie commented 2 years ago

Is this going to be addressed? The stock sample code fails for me on a stock HUZZAH32 without the forked library.

caternuson commented 2 years ago

The base issue here is in the ESP32 BSP. See here: https://github.com/espressif/arduino-esp32/issues/7211

The lack of ability to disable interrupts, combined with the DREQ pin behavior of the VS1053, ends up causing grief when trying to use interrupt based playback. The DREQ pin toggles for other reasons and fires the ISR when not expected. This eventually leads to a WDT reset or other behavior.

The approach in the @eziya fork is to essentially not use interrupts and rely on feeding the buffer in the sketch's loop().

MarcHagen commented 2 years ago

Yes @eziya fork works fine, but the main loop freezes at feedBuffer() . So in my example button inputs are not working until the song is done playing (using startPlayingFile).

Also the sounds seems to pop from time to time :(

Anyone suggestions?

caternuson commented 2 years ago

Try updating to the 2.0.5 release of the ESP32 BSP: https://github.com/espressif/arduino-esp32/releases

The addition of support for noInterrupt() and interrupt() fixed interrupt based playback on ESP32 in our testing using this library and the feather_player example.

MarcHagen commented 2 years ago

@caternuson it seems im unable to get a stable output from the HUZZAH32 + VS1053 feather, nor the HUZZAH + VS1053 feather. It jitters and pops. Both instances give me jitter sounds. File is a WAV 44100Hz at 16bit PCM. Even with the feather_player example

caternuson commented 2 years ago

Is that happening if the WAV file is played back with both playFullFile() and startPlayingFile()? Or is it just with startPlayingFile()?

MarcHagen commented 2 years ago

It seems to be both do the same. You almost say it the module or something but I’ve 3 audio feathers all with the same issue 😅

caternuson commented 2 years ago

If it is also happening with playFullFile(), then it is unrelated to interrupt playback. Please open a new issue.

Closing this one for now since interrupt playback with startPlayingFile() is working in local testing with on ESP32.