pschatzmann / arduino-audio-tools

Arduino Audio Tools (a powerful Audio library not only for Arduino)
GNU General Public License v3.0
1.46k stars 227 forks source link

SPDIFStream/SPDIFOutput #1010

Closed mrx23dot closed 1 year ago

mrx23dot commented 1 year ago

Problem Description

Adding this line makes my black ESP32 WROOM 32 constantly rebooting

SPDIFStream spdif; or SPDIFOutput spdif;

output

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:13260
load:0x40080400,len:3028
entry 0x400805e4
ets Jul 29 2019 12:21:46

rst:0x3 (SW_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:13260
load:0x40080400,len:3028
entry 0x400805e4
ets Jul 29 2019 12:21:46

rst:0x3 (SW_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:13260
load:0x40080400,len:3028
entry 0x400805e4

Device Description

black ESP32 WROOM 32

Sketch

#include "AudioConfigLocal.h"
#include "BluetoothA2DPSink.h"
#include "AudioTools.h"

BluetoothA2DPSink a2dp_sink;
SPDIFStream spdif;

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

void loop() {
   delay(100);
  //rtc_wdt_feed();
}


### Other Steps to Reproduce

_No response_

### What is your development environment

_No response_

### I have checked existing issues, discussions and online documentation

- [X] I confirm I have checked existing issues, discussions and online documentation
pschatzmann commented 1 year ago

A2DP needs a lot of flash memory: Are you sure that you are not just running out of flash memory ? Did you try to compile with the Partition Scheme Huge App ?

mrx23dot commented 1 year ago

Well it compiles and burns in fine. As you see I'm only using these 2 libs BluetoothA2DPSink, SPDIFStream. And it should have 2/4MB flash.

If it failed then it would fail like:

Sketch uses 2529577 bytes (192%) of program storage space. Maximum is 1310720 bytes.
Sketch too big;

I tried mass erasing and let arduino do its thing.

Weird because the same code worked fine moths ago on same board. Blink code still works. So I think something in SPDIFStream constructor might changed, I need to check out older version.

pschatzmann commented 1 year ago

Nop, no change none of the constructors actually do anything!

I could reproduce your issue and with the correct partition scheme it was resolved! Please note that with each new ESP32 Arduino version there is the risk that A2DP needs more memory...

ps. I initially answer was almost that you must be creazy: You sketch is not doing anything except calling constructors which also do nothing: so the issue can't definitly not be in my libraries...

mrx23dot commented 12 months ago

I stripped it down to one line to find the root cause, and it was that line.

I went back in time to

  https://github.com/pschatzmann/arduino-audio-tools
    ab732d6abfd83163318e82f855142a90c4794fc5
  https://github.com/pschatzmann/ESP32-A2DP
    a75ff1f968c46b64488c641a5b4487b572a22e38

And these seem to work, shows up connectable, I just don't have my scope near by to test the spdif. So what's different?

pschatzmann commented 12 months ago

What line caused the issue ? Did you try the corrected sketch ?

If you are still using the old sketch which takes the sample rate from a2dp, you will need to wait until is_connected() returns true before reading the sample rate.

mrx23dot commented 12 months ago

As I mentioned in the first post, after checking out head, and including either these lines it gone into a constant reboot cycle:

SPDIFStream spdif;
SPDIFOutput spdif;

the example located at https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-basic-api/basic-a2dp-spdif/basic-a2dp-spdif.ino

starts almost identically:

#include "AudioConfigLocal.h"
#include "BluetoothA2DPSink.h"
#include "AudioTools.h"

AudioInfo info(44100, 2, 16);
BluetoothA2DPSink a2dp_sink;
SPDIFOutput spdif;

true I don't have AudioInfo line, but I don't think it will get through SPDIFOutput.

I don't know if Partition Scheme Huge App is enabled or not, I'm using out of the box environment. (in fact I tried with an older arduino first, then upgraded to latest to see if it fixed it) Although older checkpoint did work, so it must fit.

It didn't get through the constructor so guess is_connected() wouldn't play yet. I will do some more testing tomorrow. Thank you though

pschatzmann commented 12 months ago

I am pretty confident that if you select a partition size with a decent APP size, the issue will go away...

mrx23dot commented 12 months ago

I checked, this is what's in my boards.txt

esp32s3.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
esp32s3.menu.PartitionScheme.huge_app.build.partitions=huge_app
esp32s3.menu.PartitionScheme.huge_app.upload.maximum_size=3145728

looks like it already has huge enabled,

according to this https://arduino.stackexchange.com/questions/81895/no-huge-app-partition-scheme-esp32 it would fail as:

Sketch uses 2529577 bytes (192%) of program storage space. Maximum is 1310720 bytes.
Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.

my output on head:

Writing at 0x0014bdf9... (100 %)
Wrote 1315408 bytes (785065 compressed) at 0x00010000 in 11.8 seconds (effective 888.4 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

then it constantly reboots, tested again, used unmodified example https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-basic-api/basic-a2dp-spdif/basic-a2dp-spdif.ino

pschatzmann commented 12 months ago

I was testing with the Arduino ESP32 version 2.0.14 and 3.0.0-alpha1 with a ESP-WROOM and an AudioKit. What version are you using ?

For me the following is giving your error: Sketch uses 1308777 bytes (99%) of program storage space. Maximum is 1310720 bytes. So even it reports to fit, it does not!

I suggest to activate the standard ESP32 logging and the AudioTools logging. Maybe this gives some more clues...

mrx23dot commented 12 months ago

17bed089e946386c7cec0779f8e55ebfe1c7bcc4 works, there are only few changes in AudioSPDIF.h after that which could cause the reboot cycle with same compiler/env.

the working one outputs

Sketch uses 1099621 bytes (83%) of program storage space. Maximum is 1310720 bytes.
Global variables use 40828 bytes (12%) of dynamic memory, leaving 286852 bytes for local variables. Maximum is 327680 bytes.
Chip is ESP32-D0WD-V3 (revision v3.0)

First I thought it was a heap issue but there is 280KB left, not sure if assertion/exception is printed in arduino.

image

no idea where arduino hides the actual gcc compiler. But I had the same issue with 1year old compiler in the first place.

As I saw AudioTools logging is activated in setup(), but it fails before it gets to it. Unfortunately I don't have more time to debug, I've got a working version, thank you for it.

I wanted to try more advanced HD codecs with BLE to swap out QCC3031, but looks like I'm better off with SBC.

pschatzmann commented 12 months ago

If it would be a heap issue you should see any debug entries if you set the log level to debug or if you add a print statement in the setup. The needed heap is mainly driven by the i2s buffer settings in AudioConfigLocal.h

I think the situation is really strange: if we use the same software versions and settings and it is not working, the only conclusion left, is that it must be the hardware. Maybe because the size was increasing, you are hitting some bad memory adresses now.

Did you try with another device ?

i was also wondering why your sketch is so much bigger then mine.

mrx23dot commented 12 months ago

This is the only ESP32 board I have.

Yeah could be a size issue, I guess the example outgrew the board. this is what I get with head:

Sketch uses 1309105 bytes (99%) of program storage space. Maximum is 1310720 bytes.
Global variables use 47964 bytes (14%) of dynamic memory, leaving 279716 bytes for local variables. Maximum is 327680 bytes.

So that's 1 full MB of code, is everything included needed? The example only includes these:

#include "AudioConfigLocal.h"
#include "BluetoothA2DPSink.h"
#include "AudioTools.h"

I guess it optimizes out the remaining, but with c++ who knows.

blink costs 231KB

Sketch uses 237117 bytes (18%) of program storage space. Maximum is 1310720 bytes.
Global variables use 21048 bytes (6%) of dynamic memory, leaving 306632 bytes for local variables. Maximum is 327680 bytes.
mrx23dot commented 12 months ago

It should be possible to generate a .map file telling what takes up space, not optimized out https://everythingesp.com/esp32-arduino-creating-a-memory-map-file/

you know better what's needed.

mrx23dot commented 10 months ago

I integrated the ESP32 into the hifi system and noticed the gain is lot lower than USB spdif, even when I max BT volume out on phone.

Phone is loud when I use it with Sony BT heapdhones. My guess is volume scaling is not reaching 100% with this lib. (I was using example code)

unpapardo commented 4 months ago

I want to add that using the latest libraries for audio-tools and A2DP, and ESP 2.0.16, the A2DP to SPDIF example still crashes at runtime, probably because of a lack of heap memory. A2DP and SPDIF by themselves work, but not both at the same time, even if I decrease the buffer count and samples to a minimum (2x128 buffer).

I already forgot some of the things I tried, but it either crashed with phy_init: failed to allocate memory for RF calibration data or it ran the a2dp_sink.start("a2dp-spdif"); line indefinitely. Enlarging the nvs partition (where the phy RF calibration data supposedly resides) didn't fix the issue.

I reckon this is more of a problem of the audio-tools library than the A2DP one, but it wasn't possible for me to mix and match an old audio-tools version with a new A2DP one, I guess some type definition chaged between the BluetoothA2DPSink a2dp_sink; (old) and BluetoothA2DPSink a2dp_sink(spdif) (new) declarations along the way or something

As suggested by mrx23dot

I stripped it down to one line to find the root cause, and it was that line.

I went back in time to

  https://github.com/pschatzmann/arduino-audio-tools
    ab732d6abfd83163318e82f855142a90c4794fc5
  https://github.com/pschatzmann/ESP32-A2DP
    a75ff1f968c46b64488c641a5b4487b572a22e38

And these seem to work, shows up connectable, I just don't have my scope near by to test the spdif. So what's different?

These versions seem to work fine as well for me, or at least they don't crash at runtime (I have to check the SPDIF output with my cheapo DAC)

pschatzmann commented 4 months ago

Did you really try with the latest versions of the libraries ? What is the output if you set the log level to Info ? Do you see the expected i2s buffer sizes ? During some time the buffer sizes did not get passed to I2S and the defaults were much too high, but this has been fixed a long time ago

unpapardo commented 4 months ago

Audio-tools v0.9.8, A2DP v1.8.1, ESP32 v2.0.16, Arduino IDE v1.8.15 (I used v2 with the same result) Straight from the example sketch:

ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
ets Jul 29 2019 12:21:46

rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
[    20][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
[    38][V][esp32-hal-uart.c:330] uartBegin(): UART0 baud(115200) Mode(800001c) rxPin(3) txPin(1)
[    47][V][esp32-hal-uart.c:416] uartBegin(): UART0 not installed. Starting installation
[    57][V][esp32-hal-uart.c:463] uartBegin(): UART0 initialization done.
[    75][D][BluetoothA2DPSink.cpp:89] start(): [BT_AV] start
[    81][I][BluetoothA2DPCommon.cpp:246] log_free_heap(): [BT_AV] Available Heap: 22972
[    89][I][BluetoothA2DPSink.cpp:101] start(): [BT_AV] Device name will be set to 'a2dp-spdif'
[    97][D][BluetoothA2DPSink.cpp:1042] init_nvs(): [BT_AV] init_nvs
[   104][D][BluetoothA2DPCommon.cpp:152] get_last_connection(): [BT_AV] get_last_connection
[   112][D][BluetoothA2DPCommon.cpp:175] get_last_connection(): [BT_AV] => 38:e3:9f:98:1c:66
[   121][I][BluetoothA2DPSink.cpp:164] init_i2s(): [BT_AV] init_i2s
[   127][I][BluetoothA2DPOutput.cpp:199] begin(): [BT_AV] begin
[   136][D][BluetoothA2DPSink.cpp:185] init_bluetooth(): [BT_AV] init_bluetooth
E (127) phy_init: failed to allocate memory for RF calibration data

abort() was called at PC 0x40180a19 on core 1

Backtrace: 0x400839ad:0x3ffcc0b0 0x40095001:0x3ffcc0d0 0x4009a781:0x3ffcc0f0 0x40180a19:0x3ffcc170 0x40180b01:0x3ffcc1a0 0x400ebc2d:0x3ffcc1c0 0x400d9804:0x3ffcc1e0 0x400d8e42:0x3ffcc230 0x400d7a3b:0x3ffcc270 0x400d42a1:0x3ffcc2d0 0x400da6c6:0x3ffcc340

ELF file SHA256: d66db5f8fd6587e0

Rebooting...

Backtrace decoded:

0x400839ad: panic_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_system/panic.c line 408
0x40095001: esp_system_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_system/esp_system.c line 137
0x4009a781: abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/newlib/abort.c line 46
0x40180a19: esp_phy_load_cal_and_init at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_phy/src/phy_init.c line 695
0x40180b01: esp_phy_enable at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_phy/src/phy_init.c line 241
0x400ebc2d: esp_bt_controller_enable at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/bt/controller/esp32/bt.c line 1722
0x400d9804: btStart at C:\Users\MPardo\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.16\cores\esp32\esp32-hal-bt.c line 50
0x400d8e42: BluetoothA2DPSink::init_bluetooth() at C:\Users\MPardo\Documents\Arduino\libraries\ESP32-A2DP-v.1.8.1\src\BluetoothA2DPSink.cpp line 186
0x400d7a3b: BluetoothA2DPSink::start(char const*) at C:\Users\MPardo\Documents\Arduino\libraries\ESP32-A2DP-v.1.8.1\src\BluetoothA2DPSink.cpp line 128
0x400d42a1: setup() at C:\Users\MPardo\Documents\Arduino\libraries\arduino-audio-tools-0.9.8\examples\examples-communication\a2dp\basic-a2dp-spdif/basic-a2dp-spdif.ino line 28
0x400da6c6: loopTask(void*) at C:\Users\MPardo\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.16\cores\esp32\main.cpp line 42

If I try with

  cfg.buffer_size = 128;
  cfg.buffer_count = 2;

If fails just the same but with [ 79][I][BluetoothA2DPCommon.cpp:246] log_free_heap(): [BT_AV] Available Heap: 206332

pschatzmann commented 4 months ago

You need to set the log level to info for the AudioTools to see the relevant information! AudioLogger::instance().begin(Serial, AudioLogger::Info);

There you can compare the reported sizes with the ones you were setting... Did you eventually forgot to set the Partition Size ?

unpapardo commented 4 months ago
[    20][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
[    38][V][esp32-hal-uart.c:330] uartBegin(): UART0 baud(115200) Mode(800001c) rxPin(3) txPin(1)
[    47][V][esp32-hal-uart.c:416] uartBegin(): UART0 not installed. Starting installation
[    57][V][esp32-hal-uart.c:463] uartBegin(): UART0 initialization done.
[I] AudioTypes.h : 127 - in: sample_rate: 88200 / channels: 2 / bits_per_sample: 32
[I] AudioTypes.h : 127 - out: sample_rate: 88200 / channels: 2 / bits_per_sample: 32
[I] AudioTypes.h : 127 -  sample_rate: 88200 / channels: 2 / bits_per_sample: 32
[I] I2SConfigESP32.h : 80 - rx/tx mode: RXTX_MODE
[I] I2SConfigESP32.h : 81 - port_no: 0
[I] I2SConfigESP32.h : 82 - is_master: Master
[I] I2SConfigESP32.h : 83 - sample rate: 88200
[I] I2SConfigESP32.h : 84 - bits per sample: 32
[I] I2SConfigESP32.h : 85 - number of channels: 2
[I] I2SConfigESP32.h : 86 - signal_type: Digital
[I] I2SConfigESP32.h : 88 - i2s_format: I2S_STD_FORMAT
[I] I2SConfigESP32.h : 90 - auto_clear: true
[I] I2SConfigESP32.h : 92 - use_apll: true
[I] I2SConfigESP32.h : 95 - fixed_mclk: 22579200
[I] I2SConfigESP32.h : 97 - buffer_count:2
[I] I2SConfigESP32.h : 98 - buffer_size:128
[I] I2SConfigESP32.h : 107 - pin_data: 23
[   148][D][BluetoothA2DPSink.cpp:89] start(): [BT_AV] start
[   157][I][BluetoothA2DPCommon.cpp:246] log_free_heap(): [BT_AV] Available Heap: 206332
[   165][I][BluetoothA2DPSink.cpp:101] start(): [BT_AV] Device name will be set to 'a2dp-spdif'
[   174][D][BluetoothA2DPSink.cpp:1042] init_nvs(): [BT_AV] init_nvs
[   180][D][BluetoothA2DPCommon.cpp:152] get_last_connection(): [BT_AV] get_last_connection
[   189][D][BluetoothA2DPCommon.cpp:175] get_last_connection(): [BT_AV] => 38:e3:9f:98:1c:66
[   197][I][BluetoothA2DPSink.cpp:164] init_i2s(): [BT_AV] init_i2s
[   203][I][BluetoothA2DPOutput.cpp:199] begin(): [BT_AV] begin
[I] AudioTypes.h : 127 - out: sample_rate: 88200 / channels: 2 / bits_per_sample: 32
[I] AudioTypes.h : 127 -  sample_rate: 88200 / channels: 2 / bits_per_sample: 32
[I] I2SConfigESP32.h : 80 - rx/tx mode: RXTX_MODE
[I] I2SConfigESP32.h : 81 - port_no: 0
[I] I2SConfigESP32.h : 82 - is_master: Master
[I] I2SConfigESP32.h : 83 - sample rate: 88200
[I] I2SConfigESP32.h : 84 - bits per sample: 32
[I] I2SConfigESP32.h : 85 - number of channels: 2
[I] I2SConfigESP32.h : 86 - signal_type: Digital
[I] I2SConfigESP32.h : 88 - i2s_format: I2S_STD_FORMAT
[I] I2SConfigESP32.h : 90 - auto_clear: true
[I] I2SConfigESP32.h : 92 - use_apll: true
[I] I2SConfigESP32.h : 95 - fixed_mclk: 22579200
[I] I2SConfigESP32.h : 97 - buffer_count:30
[I] I2SConfigESP32.h : 98 - buffer_size:384
[I] I2SConfigESP32.h : 107 - pin_data: 23
[   276][D][BluetoothA2DPSink.cpp:185] init_bluetooth(): [BT_AV] init_bluetooth
E (273) phy_init: failed to allocate memory for RF calibration data

abort() was called at PC 0x40180a21 on core 1

I see that there's still a big buffer being allocated by default. Could an AudioConfigLocal.h file fix that?

pschatzmann commented 4 months ago

Why don't you just install the version (the main branch) where the issue has been corrected ?

unpapardo commented 4 months ago

Huh, I guess you meant "latest" as in "latest commits", not "latest release".

I can confirm that it is indeed working as expected, finally. (Other than some pesky ground loops and the occasional crackle) I want to thank you for the huge effort put into this library and the A2DP one, I'm retrofitting BT audio into an old car radio and you just saved me a few bucks and probably several hours not spent on more chips, datasheets and debugging.

As a closing question, what would be the easiest way to incorpore status beeps into the SPDIF output? Can you have both a BluetoothA2DPSink and a StreamCopy streaming onto the same output? Not necessarily at the same time anyways

pschatzmann commented 4 months ago

This should be quite easy. I would suggest the following:

  1. Make sure that A2DP stops any output (if necessary)
    • call avrc pause()
    • set the output to a NullStream
  2. copy the status beep signal to the SPDIFOutput. You can e.g. use a SineGenerator for this.
  3. Resume A2DP Playback
    • set output back to the SPDIFOutput
    • call avrc resume()

Alternatively you can use an approach using the callback method, where you can add some status variable to manage if you want to output the received signal or your own generated one