Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not work on ESP32 #89

Open
jenschr opened this issue May 2, 2023 · 7 comments
Open

Does not work on ESP32 #89

jenschr opened this issue May 2, 2023 · 7 comments
Assignees

Comments

@jenschr
Copy link

jenschr commented May 2, 2023

The VS1053 library does not work with ESP32's.

Steps to reproduce:

  • Open the "player_simple.ino" example after installing the library
  • Set pins for BREAKOUT_RESET 9, BREAKOUT_CS 10, BREAKOUT_CS 6, CARDCS 4, DREQ 3
  • Connect according to the above
  • Compile & upload

This will cause a hardware crash on the ESP32, causing it to reboot at a regular interval. Changing from this constructor:

Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);

... to the software SPI version:

Adafruit_VS1053_FilePlayer(MOSI, MISO, SCK, BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);

... does stop the crashing, but the device still does not play audio files. Printing out MOSI, MISO and SCK lists the correct pins (35, 37, 36) so it does not make much sense that calling this makes a difference (but it does).

This library contains working code (as a workaround), but I'd at least update the Adafruit guide for the VS1053 products and point out that this library does not work with ESP32 for now..

@jenschr
Copy link
Author

jenschr commented May 2, 2023

It looks like this issue has been raised in issue #45 but it was closed as a "cannot reproduce". Trying the sample file with an ESP32 S3 with no psram will make it 100% reproducible.

The approach in the @eziya fork is to essentially not use interrupts

@caternuson
Copy link
Contributor

The issue is with interrupt playback. That currently is not working for ESP32 platforms. In the player_simple.ino example, comment out this line:

  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int

and then it should work for the non-interrupt playback call to:

  musicPlayer.playFullFile("/track001.mp3");

The subsequent interrupt based playback call(s) will not work however:

  musicPlayer.startPlayingFile("/track002.mp3");

Do not have the breakout version of this to test. However, using a Feather ESP32-S3 (PID 5323) and commenting out the DREQ setup in feather_player.ino works.

@jenschr
Copy link
Author

jenschr commented May 3, 2023

I can confirm that removing the interrupt does work. As suggested, playFullFile does play the full file. Using startPlayingFile also works if you make sure to fill the buffer in your loop:

void loop() {
  musicPlayer.feedBuffer();
  // more stuff here
}

This works as long as the loop time is less than 150ms so the buffer stays full. It would be quite easy to add a timer that can just keep the buffer filled. I might make use this approach. I can do a PR on this if it's useful?

@TheNitek
Copy link
Contributor

TheNitek commented May 4, 2023

I dont think a timer will work, because thise time depends in the bitrate of the file and probably even more factors. DREQ pin is specifically there to tell you when it is time to send more data, so „watching“ it, with or without interrupt, is the best approach here.

@jenschr
Copy link
Author

jenschr commented May 4, 2023

Spent some more time on this. What is crashing is reading from SD inside an interrupt. If I just set a flag in the interrupt and then check this flag in the loop, it works fine. Here's an example that is using interrupts, but just not to fill the buffer: https://pastebin.com/qwcJVs8E

It is basically the same as calling the feedBuffer routine from the main loop, but it will only do it when required. I would like to get this to work with interrupts, but I'm unsure where to go next. Any hints helpful!

sidenote: I've tried using the SDFat option present in the library, but it looks like that's not been maintained in a while? Setting PREFER_SDFAT_LIBRARY yields compilation errors. Tried using adafruit/SdFat - Adafruit Fork@^1.5.1 as well as 2.2.1. Slightly different output

@jenschr
Copy link
Author

jenschr commented Jun 12, 2023

Turns out that it's not hard to get this working by using FreeRtos Functions. Adding the following code to Adafruit_VS1053.cpp will use a FreeRTOS Task to poll the feedBuffer routine.

I can deliver a PR if you think this is a good way to solve it. I can also test it. My current fork of the library allows me to play files directly from SPIFFS or any other files system.

static void feedEsp32( void * pvParameters ){
  for(;;){
    myself->feedBuffer();
    delay(10);
  } 
}

boolean Adafruit_VS1053_FilePlayer::useInterrupt(uint8_t type) {
  myself = this; // oy vey

  if (type == VS1053_FILEPLAYER_TIMER0_INT) {
#if defined(ARDUINO_ARCH_AVR)
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    return true;
#elif defined(ESP32)
    TaskHandle_t Task1;
    xTaskCreatePinnedToCore(
                  feedEsp32,   /* Task function. */
                  "Task1",     /* name of task. */
                  10000,       /* Stack size of task */
                  NULL,        /* parameter of the task */
                  1,           /* priority of the task */
                  &Task1,      /* Task handle to keep track of created task */
                  0);          /* pin task to core 0 */  
#elif defined(__arm__) && defined(CORE_TEENSY)

Here's my current code master...jenschr:Adafruit_VS1053_Library:master

I don't think it's possible to get the non-timer method to ever work on ESP32 (ref: Calling long ISR's will crash ), so in my codebase, I'm printing out a warning on Serial if this is used.

@Broker89
Copy link

Thanks a lot @jenschr that fixed it for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants