admin管理员组文章数量:1187337
I have built an internet radio with an ESP32 and with a MAX98357A I2S amplifier, but I get this error about every minute and my ESP32 keeps rebooting:
CORRUPT HEAP: Bad head at 0x3ffe854c. Expected 0xabba1234 got 0xa40c84d1
assert failed: multi_heap_free multi_heap_poisoning.c:279 (head != NULL)
I'm using an ESP-Wroom-32 without PSRAM and the partition scheme is set to "Huge APP" in the Arduino IDE. Any suggestions?
My code:
#include <WiFi.h>
#include <Audio.h> //
#include <AiEsp32RotaryEncoder.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define I2S_DOUT 25 // din
#define I2S_BCLK 26 // bclk
#define I2S_LRC 27 // lrc
#define VOLUME_PIN 34
#define ROTARY_ENCODER_A_PIN 32 // clk
#define ROTARY_ENCODER_B_PIN 33 // dt
#define ROTARY_ENCODER_BUTTON_PIN 35 // sw
#define ROTARY_ENCODER_STEPS 4
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
#define I2C_SDA 21
#define I2C_SCL 22
AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, -1, ROTARY_ENCODER_STEPS);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Audio audio;
const char* ssid = "xxx";
const char* password = "xxx";
const char* stations[] = {
".mp3",
".mp3",
".mp3",
":7813/slagerfm128.mp3",
":8443/sc_gyor1",
".mp3",
":8000/fun128.mp3",
".mp3",
".mp3",
".mp3",
".mp3"
};
const char* stationNames[] = {
"Retro Radio",
"Petofi Radio",
"Radio 1",
"Slager FM",
"Gyor Plusz Radio",
"Radio Expres",
"Fun Radio",
"Radio Jemne",
"Europa 2",
"Radio Rock",
"Radio Vlna"
};
const int NUM_STATIONS = sizeof(stations) / sizeof(stations[0]);
int currentStation = 0;
char streamTitle[64] = "";
// Volume control variables
const int SAMPLES = 5;
int volumeReadings[SAMPLES];
int readIndex = 0;
int total = 0;
int average = 0;
unsigned long lastVolumeCheck = 0;
const unsigned long VOLUME_CHECK_INTERVAL = 10;
bool isWiFiConnected = false;
bool isDisplayInitialized = false;
bool isAudioInitialized = false;
void IRAM_ATTR readEncoderISR() {
rotaryEncoder.readEncoder_ISR();
}
void setup() {
delay(1000);
Serial.begin(115200);
while(!Serial) { delay(10); }
pinMode(VOLUME_PIN, INPUT);
rotaryEncoder.begin();
rotaryEncoder.setup(readEncoderISR);
rotaryEncoder.setBoundaries(0, NUM_STATIONS - 1, true);
rotaryEncoder.setAcceleration(0);
Wire.begin(I2C_SDA, I2C_SCL);
for (int i = 0; i < SAMPLES; i++) {
volumeReadings[i] = 0;
}
}
void loop() {
static unsigned long lastInitAttempt = 0;
const unsigned long initInterval = 1000;
if (!isDisplayInitialized && millis() - lastInitAttempt > initInterval) {
initializeDisplay();
lastInitAttempt = millis();
}
if (!isWiFiConnected && millis() - lastInitAttempt > initInterval) {
connectToWiFi();
lastInitAttempt = millis();
}
if (isWiFiConnected && !isAudioInitialized && millis() - lastInitAttempt > initInterval) {
initializeAudio();
lastInitAttempt = millis();
}
if (isDisplayInitialized && isWiFiConnected && isAudioInitialized) {
audio.loop();
checkEncoder();
checkVolumeControl();
}
}
void initializeDisplay() {
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
return;
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.display();
isDisplayInitialized = true;
}
void connectToWiFi() {
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
isWiFiConnected = true;
if (isDisplayInitialized) {
display.clearDisplay();
display.setCursor(0,0);
display.display();
}
}
}
void initializeAudio() {
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
connectToStation(currentStation);
isAudioInitialized = true;
}
void checkEncoder() {
if (rotaryEncoder.encoderChanged()) {
currentStation = rotaryEncoder.readEncoder();
connectToStation(currentStation);
}
if (rotaryEncoder.isEncoderButtonClicked()) {
// empty
}
}
void connectToStation(int stationIndex) {
audio.stopSong();
audio.connecttohost(stations[stationIndex]);
updateDisplay();
}
void checkVolumeControl() {
unsigned long currentMillis = millis();
if (currentMillis - lastVolumeCheck >= VOLUME_CHECK_INTERVAL) {
lastVolumeCheck = currentMillis;
total = total - volumeReadings[readIndex];
volumeReadings[readIndex] = analogRead(VOLUME_PIN);
total = total + volumeReadings[readIndex];
readIndex = (readIndex + 1) % SAMPLES;
average = total / SAMPLES;
int volume = map(average, 0, 4095, 0, 15);
static int lastVolume = -1;
if (volume != lastVolume) {
audio.setVolume(volume);
lastVolume = volume;
updateDisplay();
}
}
}
void updateDisplay() {
if (!isDisplayInitialized) return;
display.clearDisplay();
display.setCursor(0,0);
display.println(String(stationNames[currentStation]));
display.println();
display.println(String(streamTitle));
display.display();
}
void audio_showstreamtitle(const char *info) {
Serial.print("streamtitle: "); Serial.println(info);
strncpy(streamTitle, info, sizeof(streamTitle) - 1);
streamTitle[sizeof(streamTitle) - 1] = '\0'; // Ensure null-termination
updateDisplay();
}
I have built an internet radio with an ESP32 and with a MAX98357A I2S amplifier, but I get this error about every minute and my ESP32 keeps rebooting:
CORRUPT HEAP: Bad head at 0x3ffe854c. Expected 0xabba1234 got 0xa40c84d1
assert failed: multi_heap_free multi_heap_poisoning.c:279 (head != NULL)
I'm using an ESP-Wroom-32 without PSRAM and the partition scheme is set to "Huge APP" in the Arduino IDE. Any suggestions?
My code:
#include <WiFi.h>
#include <Audio.h> // https://github.com/schreibfaul1/ESP32-audioI2S
#include <AiEsp32RotaryEncoder.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define I2S_DOUT 25 // din
#define I2S_BCLK 26 // bclk
#define I2S_LRC 27 // lrc
#define VOLUME_PIN 34
#define ROTARY_ENCODER_A_PIN 32 // clk
#define ROTARY_ENCODER_B_PIN 33 // dt
#define ROTARY_ENCODER_BUTTON_PIN 35 // sw
#define ROTARY_ENCODER_STEPS 4
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
#define I2C_SDA 21
#define I2C_SCL 22
AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, -1, ROTARY_ENCODER_STEPS);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Audio audio;
const char* ssid = "xxx";
const char* password = "xxx";
const char* stations[] = {
"https://icast.connectmedia.hu/5001/live.mp3",
"https://icast.connectmedia.hu/4738/mr2.mp3",
"https://icast.connectmedia.hu/5223/live.mp3",
"https://slagerfm.netregator.hu:7813/slagerfm128.mp3",
"https://stream.42netmedia.com:8443/sc_gyor1",
"https://stream.bauermedia.sk/128.mp3",
"https://stream.funradio.sk:8000/fun128.mp3",
"https://stream.bauermedia.sk/melody-hi.mp3",
"https://stream.bauermedia.sk/europa2.mp3",
"https://stream.bauermedia.sk/rock-hi.mp3",
"https://stream.radiovlna.sk/vlna-hi.mp3"
};
const char* stationNames[] = {
"Retro Radio",
"Petofi Radio",
"Radio 1",
"Slager FM",
"Gyor Plusz Radio",
"Radio Expres",
"Fun Radio",
"Radio Jemne",
"Europa 2",
"Radio Rock",
"Radio Vlna"
};
const int NUM_STATIONS = sizeof(stations) / sizeof(stations[0]);
int currentStation = 0;
char streamTitle[64] = "";
// Volume control variables
const int SAMPLES = 5;
int volumeReadings[SAMPLES];
int readIndex = 0;
int total = 0;
int average = 0;
unsigned long lastVolumeCheck = 0;
const unsigned long VOLUME_CHECK_INTERVAL = 10;
bool isWiFiConnected = false;
bool isDisplayInitialized = false;
bool isAudioInitialized = false;
void IRAM_ATTR readEncoderISR() {
rotaryEncoder.readEncoder_ISR();
}
void setup() {
delay(1000);
Serial.begin(115200);
while(!Serial) { delay(10); }
pinMode(VOLUME_PIN, INPUT);
rotaryEncoder.begin();
rotaryEncoder.setup(readEncoderISR);
rotaryEncoder.setBoundaries(0, NUM_STATIONS - 1, true);
rotaryEncoder.setAcceleration(0);
Wire.begin(I2C_SDA, I2C_SCL);
for (int i = 0; i < SAMPLES; i++) {
volumeReadings[i] = 0;
}
}
void loop() {
static unsigned long lastInitAttempt = 0;
const unsigned long initInterval = 1000;
if (!isDisplayInitialized && millis() - lastInitAttempt > initInterval) {
initializeDisplay();
lastInitAttempt = millis();
}
if (!isWiFiConnected && millis() - lastInitAttempt > initInterval) {
connectToWiFi();
lastInitAttempt = millis();
}
if (isWiFiConnected && !isAudioInitialized && millis() - lastInitAttempt > initInterval) {
initializeAudio();
lastInitAttempt = millis();
}
if (isDisplayInitialized && isWiFiConnected && isAudioInitialized) {
audio.loop();
checkEncoder();
checkVolumeControl();
}
}
void initializeDisplay() {
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
return;
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.display();
isDisplayInitialized = true;
}
void connectToWiFi() {
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
isWiFiConnected = true;
if (isDisplayInitialized) {
display.clearDisplay();
display.setCursor(0,0);
display.display();
}
}
}
void initializeAudio() {
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
connectToStation(currentStation);
isAudioInitialized = true;
}
void checkEncoder() {
if (rotaryEncoder.encoderChanged()) {
currentStation = rotaryEncoder.readEncoder();
connectToStation(currentStation);
}
if (rotaryEncoder.isEncoderButtonClicked()) {
// empty
}
}
void connectToStation(int stationIndex) {
audio.stopSong();
audio.connecttohost(stations[stationIndex]);
updateDisplay();
}
void checkVolumeControl() {
unsigned long currentMillis = millis();
if (currentMillis - lastVolumeCheck >= VOLUME_CHECK_INTERVAL) {
lastVolumeCheck = currentMillis;
total = total - volumeReadings[readIndex];
volumeReadings[readIndex] = analogRead(VOLUME_PIN);
total = total + volumeReadings[readIndex];
readIndex = (readIndex + 1) % SAMPLES;
average = total / SAMPLES;
int volume = map(average, 0, 4095, 0, 15);
static int lastVolume = -1;
if (volume != lastVolume) {
audio.setVolume(volume);
lastVolume = volume;
updateDisplay();
}
}
}
void updateDisplay() {
if (!isDisplayInitialized) return;
display.clearDisplay();
display.setCursor(0,0);
display.println(String(stationNames[currentStation]));
display.println();
display.println(String(streamTitle));
display.display();
}
void audio_showstreamtitle(const char *info) {
Serial.print("streamtitle: "); Serial.println(info);
strncpy(streamTitle, info, sizeof(streamTitle) - 1);
streamTitle[sizeof(streamTitle) - 1] = '\0'; // Ensure null-termination
updateDisplay();
}
Share
Improve this question
asked Jan 25 at 14:20
Tamás CsibaTamás Csiba
13 bronze badges
1 Answer
Reset to default 0You should try running the code under a debugger or at least displaying it through something that will decode that stream of numbers under the "GURU MEDITATION" that's displayed after that. It may not show you the culprit, but it might offer hints.
In PlatformIO, that's just running it under the monitor https://docs.platformio.org/en/stable/tutorials/espressif32/arduino_debugging_unit_testing.html once configured as a filter Arduino has something similar. All of those tools are wrappers around Espressif's own stack decoder that they provide separately and as part of ESP-IDF.
Now, the mystery is why might the crash not be the actual offender? The error you're getting shows that SOMETHING was able to determine that the heap - the big chunk of memory where all allocations (malloc, calloc, operator new, etc) come from, where they live while they're in use, and the pool of memory that hasn't been allocated yet or that's been used and then returned. It's like a big bookshelf and as books get checked out, it's not like everything else gets pushed together. Eventually, something is determining that, for example, there's more space between books on the shelf than the shelf is long. That's "obviously" a crazy thing that should never happen, but if someone was a bad citizen and damaged the storage by scribbling into memory after it was freed (and possibly resused!) or trying to return (free) memory twice, that would also trigger as corruption.
Unfortunately, sometimes you don't get the error when that person returns the book twice; you get the error later. This is why this kind of crash can be tricky to track down.
There's a lot going on in this system, with network requests flying around, I2S buffers getting filled and emptied, SSD1306 updates happening, knobs getting checked and probably more.
I see three arrays in your code, but they're all in the .data section, not the heap, and just from inspection, I don't see any obvious overwrites in them. volumeReadings, numStations, and streamTitle don't seem to have any obvious overwrites. (I could be wrong.) The "hard" part of all this doesn't seem to be in your code at all.
I'd move some of that startup stuff outside of loop() and into setup(). Just for simplicity in debugging, I assume that display, Wifi, and audio each need to be initialized only and exactly once. I'd move them to setup.
Then I'd simplify the loop runner to just call audio.loop and leave the display and audio out of it. That at least gets you a simpler system to debug. If the problem remains, go back to the sample code from whereever your audio library came and see if it works. If so, compare the remaining source. If the problem goes into remission, add volume and screen handling back individually. Again, it may not be 100% their fault, but it at least lets you divide and conquer. Their https://github.com/schreibfaul1/ESP32-audioI2S/blob/master/examples/I2Saudio/I2Saudio.ino example may provide inspiration on a super minimalistic implementation.
Those are the tricks and tools I'd use to chase this down. Good luck!
本文标签: mp3ESP32 heap corruption with internet radioStack Overflow
版权声明:本文标题:mp3 - ESP32 heap corruption with internet radio - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738356164a2079872.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论