Need Help: Audio Playback from SD Card through MAX98357A on nRF52832

Hello everyone,

I'm currently working on a project involving the nRF52832 microcontroller and the MAX98357A amplifier for audio playback from an SD card. However, I'm encountering issues with the I2S initialization in my code.

Here are the details of my setup:

  • Microcontroller: nRF52832
  • Amplifier: MAX98357A
  • I2S Pin Configuration:
    • LRC: GPIO 31
    • BCLK: GPIO 30
    • DIN: GPIO 27
  • SD Card Pin Configuration:
    • MISO: GPIO 14
    • MOSI: GPIO 13
    • SCK: GPIO 12
    • CS: GPIO 11
  • WAV File Sample Rate: 16000 Hz, 8 bit

Issue:

While probing the DIN pin with a logic analyzer, I observed that it is always low, whereas the LRC and BCLK pins are functioning correctly. This suggests that the data might not be getting sent to the amplifier.

Code:
#include <Arduino.h>
#include <SD.h>
#include <SPI.h>
#include <nrf_i2s.h>

#define SD_CS_PIN 11 // Chip Select pin for SD card
#define I2S_BCK_PIN 30 // Bit clock pin
#define I2S_LRCLK_PIN 31 // Word select pin
#define I2S_DATA_PIN 27 // Data pin
#define I2S_BUFFER_SIZE 512// Buffer size for I2S

int8_t i2s_tx_buffer[I2S_BUFFER_SIZE] = {0}; // Buffers for TX data (8-bit)
File audioFile; // File for reading audio data
#define WAV_HEADER_SIZE 44 // WAV file header size
uint8_t volume =100; // Default volume is 100%

bool initSD() {
    if (!SD.begin(SD_CS_PIN)) {
        Serial.println("SD card initialization failed!");
        return false;
    }
    Serial.println("SD card initialized.");
    return true;
}

bool readWAVHeader(const char *filename) {
    Serial.print("Checking for file: ");
    Serial.println(filename);
    if (!SD.exists(filename)) {
        Serial.println("Sample WAV file does not exist!");
        return false;
    }
    audioFile = SD.open(filename, FILE_READ);
    if (!audioFile) {
        Serial.println("Failed to open WAV file!");
        return false;
    }
    byte header[WAV_HEADER_SIZE];
    audioFile.read(header, WAV_HEADER_SIZE);
    if (header[0] != 'R' || header[1] != 'I' || header[2] != 'F' || header[3] != 'F') {
        Serial.println("Not a valid WAV file.");
        audioFile.close();
        return false;
    }
    uint32_t sampleRate = *(uint32_t*)&header[24];
    uint16_t bitsPerSample = *(uint16_t*)&header[34];
    Serial.println("WAV File Format:");
    Serial.print("Sample Rate: ");
    Serial.println(sampleRate);
    Serial.print("Bits per Sample: ");
    Serial.println(bitsPerSample);
    if (sampleRate != 16000) {
        Serial.print("Warning: Sample rate is ");
        Serial.println(sampleRate);
    }
    audioFile.seek(WAV_HEADER_SIZE);
    Serial.println("WAV header read and skipped.");
    return true;
}

void i2s_init() {
    NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master;   // Set as master
    NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left;
    NRF_I2S->CONFIG.RXEN = I2S_CONFIG_RXEN_RXEN_Disabled; // Disable RX
    NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_Enabled;  // Enable TX
    NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S; // Set to I2S format
    NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_Enabled; // Enable MCK if needed
    NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV10;
    NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_192X;     // Set ratio to 128x
    NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_8Bit;
    NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_LEFT;
    //CONFIG_CHANNELS_CHANNELS_Left;

    NRF_I2S->PSEL.LRCK = (I2S_LRCLK_PIN << I2S_PSEL_LRCK_PIN_Pos);
    NRF_I2S->PSEL.SCK = (I2S_BCK_PIN << I2S_PSEL_SCK_PIN_Pos);
     NRF_I2S->PSEL.SDOUT = (I2S_DATA_PIN << I2S_PSEL_SDOUT_PIN_Pos);
    // NRF_I2S->PSEL.SDIN = (I2S_DATA_PIN << I2S_PSEL_SDIN_PIN_Pos);
    NRF_I2S->TXD.PTR = (uint32_t)i2s_tx_buffer;
    NRF_I2S->ENABLE = I2S_ENABLE_ENABLE_Enabled;
    Serial.println("I2S setup finished.");

}

void i2s_start() {
    NRF_I2S->TASKS_START = 1;
}

void playWAVData() {
    if (audioFile) {

        // int bytesRead = audioFile.read(i2s_tx_buffer, sizeof(i2s_tx_buffer));
        //  Serial.print("Raw sample: ");
        //          Serial.println(bytesRead);

        for (int i = 0; i < I2S_BUFFER_SIZE; i++) {
            int8_t sample = 0;
            int bytesRead = audioFile.read(&sample, sizeof(sample)); // Read 8-bit PCM sample
            if (bytesRead > 0) {
                // Serial.print("Raw sample: ");
                //  Serial.println(sample);
                //   Serial.println(bytesRead);

                // Scale sample by volume (0-100) and center around zero
            //   Scale sample by volume (0-100) and center around zero
                int8_t scaledSample = (int8_t)((sample - 128) * (volume / 100.0)); // Center and scale

                i2s_tx_buffer[i] =sample;// scaledSample + 128; // Shift to positive range (0 to 255)
                i2s_start();
                // Serial.print("Buffered sample: ");
                // Serial.println(i2s_tx_buffer[i]);
            }// else {
            //     audioFile.close();
            //     Serial.println("Audio playback finished.");
            //     return;
            // }
        }
        // i2s_start();
    }
}


void setup() {
    Serial.begin(115200);
    if (!initSD()) {
        while (1); // Stop if SD card fails to initialize
    }
    if (!readWAVHeader("sample.wav")) {
        while (1); // Stop if WAV header fails to read
    }
    i2s_init();
}

void loop() {
    playWAVData();
}


If anyone has experience with I2S audio playback, SD card integration, or has encountered similar issues, I would greatly appreciate your insights or suggestions on how to resolve this.

Thank you,

Parents Reply Children
No Data
Related