I’m struggling with an ESP32 library.
As premise, the ESP32 module I’m using has a 2 MB PSRAM on-board.
I wrote a test code to verify it’s working:
void setup()
{
Serial.begin(115200);
while (!Serial);
log_i("Available PSRAM: %lu bytes", (long unsigned int)ESP.getFreePsram());
uint8_t *b = (uint8_t*)ps_calloc(655350, sizeof(uint8_t));
log_i("Available PSRAM: %lu bytes, %p", (long unsigned int)ESP.getFreePsram(), b);
}
this is the output:
[ 314][I][main.cpp:98] setup(): Available PSRAM: 2095103 bytes
[ 365][I][main.cpp:100] setup(): Available PSRAM: 1439735 bytes, 0x3f800800
the memory is then allocated (even with 18 bytes more, I guess for some overhead).
In the library there is the very same code, line #43:
size_t AudioBuffer::init() {
if(m_buffer) free(m_buffer);
m_buffer = NULL;
if(psramInit() && m_buffSizePSRAM > 0) { // PSRAM found, AudioBuffer will be allocated in PSRAM
m_f_psram = true;
m_buffSize = m_buffSizePSRAM;
m_buffer = (uint8_t*)ps_calloc(m_buffSize, sizeof(uint8_t));
m_buffSize = m_buffSizePSRAM - m_resBuffSizePSRAM;
}
if(m_buffer == NULL) { // PSRAM not found, not configured or not enough available
m_f_psram = false;
m_buffer = (uint8_t*)heap_caps_calloc(m_buffSizeRAM, sizeof(uint8_t), MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
m_buffSize = m_buffSizeRAM - m_resBuffSizeRAM;
}
if(!m_buffer) return 0;
m_f_init = true;
resetBuffer();
return m_buffSize;
}
where m_buffSize
is actually 655350 (I checked it out at runtime).
I slightly changed the code as follow:
if(psramInit() && m_buffSizePSRAM > 0) { // PSRAM found, AudioBuffer will be allocated in PSRAM
m_f_psram = true;
m_buffSize = m_buffSizePSRAM;
log_i("Available PSRAM: %lu bytes", (long unsigned int)ESP.getFreePsram());
m_buffer = (uint8_t*)ps_calloc(m_buffSize, sizeof(uint8_t));
log_i("Available PSRAM: %lu bytes %p", (long unsigned int)ESP.getFreePsram(), m_buffer);
m_buffSize = m_buffSizePSRAM - m_resBuffSizePSRAM;
}
and this is the output:
[ 343][I][Audio.cpp:43] init(): Available PSRAM: 2040835 bytes
[ 351][I][Audio.cpp:45] init(): Available PSRAM: 0 bytes 0x3f80dbfc
I also tried to use malloc
instead of calloc
so the allocated area is not zero-ed. In that case it returns the correct available size, but of course the code won’t work anymore. If I zero the memory after:
m_buffer = (uint8_t*)ps_malloc(m_buffSize);
memset(m_buffer, 0, m_buffSize);
log_i("Available PSRAM: %lu bytes, %p", (long unsigned int)ESP.getFreePsram(), m_buffer);
it comes back to the previous behavior:
[ 351][I][Audio.cpp:45] init(): Available PSRAM: 0 bytes 0x3f80dbfc
My development environment is:
- Ubuntu 24.10
- Visual Studio Code 1.95.3
- PlatformIO 6.1.16
- Espressif 32 (6.9.0)
- Hardware: DFRobot Firebeetle 2 ESP32-E N16R2
- Compiler: toolchain-xtensa-esp32 8.4.0
What can cause such an odd behavior?
Here my complete test code:
#include <Arduino.h>
#include <FS.h>
#include <SD.h>
#include <SPI.h>
#include "Audio.h"
#define PIN_SPI_SCK 18
#define PIN_SPI_MISO 19
#define PIN_SPI_MOSI 23
#define PIN_SD_CS 2
#define PIN_I2S_BCLK 25
#define PIN_I2S_LRC 26
#define PIN_I2S_DOUT 9
Audio audio;
void audio_process_i2s(int16_t *outBuff, uint16_t validSamples, uint8_t bitsPerSample, uint8_t channels, bool *continueI2S)
{
log_i("%d", validSamples);
*continueI2S = false;
}
void audio_info(const char *info)
{
log_i("%s", info);
}
void setup()
{
Serial.begin(115200);
while (!Serial);
uint32_t flashSize = ESP.getFlashChipSize();
Serial.printf("Flash Size: %u bytesn", flashSize);
uint32_t psramSize = ESP.getPsramSize();
Serial.printf("PSRAM Size: %u bytesn", psramSize);
uint32_t freeMemory = ESP.getFreeHeap();
Serial.printf("Free Memory: %u bytesn", freeMemory);
uint32_t Totalheap = ESP.getHeapSize();
Serial.printf("Total heap: %u bytesn", Totalheap);
uint32_t FreePSRAM = ESP.getFreePsram();
Serial.printf("Free PSRAM: %u bytesn", FreePSRAM);
SPI.setFrequency(1000000);
SPI.begin(PIN_SPI_SCK, PIN_SPI_MISO, PIN_SPI_MOSI, PIN_SD_CS);
if (SD.begin(PIN_SD_CS)) Serial.println("SD card mounted!");
else Serial.println("Failed to mount SD card");
File root = SD.open("/");
audio.setPinout(PIN_I2S_BCLK, PIN_I2S_LRC, PIN_I2S_DOUT);
audio.setVolume(15);
audio.connecttoFS(SD, "songs/bach.mp3");
}
void loop()
{
audio.loop();
vTaskDelay(1);
}