Convert WAV file and Play audio via I2S MAX9835

Hi

I tried to play an audio convert file by NRF52840 via I2S, but the sound output was like noise (incorrect):

This is my config I2S:

    // Enable transmission
    NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos);

    // Enable MCK generator
    NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_ENABLE << I2S_CONFIG_MCKEN_MCKEN_Pos);

    // MCKFREQ = 4 MHz
    NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV11 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;

    // Ratio = 64
    NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_128X << I2S_CONFIG_RATIO_RATIO_Pos;

    // Master mode, 16Bit, left aligned
    NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_MASTER << I2S_CONFIG_MODE_MODE_Pos;
    NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16BIT << I2S_CONFIG_SWIDTH_SWIDTH_Pos;
    NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_LEFT << I2S_CONFIG_ALIGN_ALIGN_Pos;

    // Format = I2S
    NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos;

    // Use stereo
    NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_STEREO << I2S_CONFIG_CHANNELS_CHANNELS_Pos;

    // Configure pins
    // NRF_I2S->PSEL.MCK = (PIN_MCK << I2S_PSEL_MCK_PIN_Pos);
    NRF_I2S->PSEL.SCK = (PIN_SCK << I2S_PSEL_SCK_PIN_Pos);
    NRF_I2S->PSEL.LRCK = (PIN_LRCK << I2S_PSEL_LRCK_PIN_Pos);
    NRF_I2S->PSEL.SDOUT = (PIN_SDOUT << I2S_PSEL_SDOUT_PIN_Pos);

    NRF_I2S->ENABLE = (I2S_ENABLE_ENABLE_Enabled << I2S_ENABLE_ENABLE_Pos);

    // Configure data pointer
    NRF_I2S->TXD.PTR = (uint32_t)&audio_table[0];
    NRF_I2S->RXTXD.MAXCNT = sizeof(audio_table) / sizeof(unsigned const char);

    // Start transmitting I2S data
    NRF_I2S->EVENTS_TXPTRUPD = 0;
    NRF_I2S->ENABLE = 1;
    NRF_I2S->TASKS_START = 1;
The audio file I am using "Audacity" audio tool converts with parameters like this

audio convert

and use Python code to convert to a .h file

from __future__ import print_function

import os
import struct
import wave
from builtins import range

try:
    from typing import List
except ImportError:
    pass


def get_wave_array_str(filename, target_bits):  # type: (str, int) -> str
    try:
        wave_read = wave.open(filename, 'r')
    except wave.Error as e:
        print(f"Error processing {filename}: {e}")
        return ''

    array_str = ''
    nchannels, sampwidth, framerate, nframes, comptype, compname = wave_read.getparams()
    sampwidth *= 8
    scale_val = (1 << target_bits) - 1
    cur_lim = (1 << sampwidth) - 1
    for i in range(wave_read.getnframes()):
        frame_data = wave_read.readframes(1)
        if sampwidth == 8:
            val = struct.unpack('<B', frame_data[:1])[0]  # 8-bit is unsigned char
        elif sampwidth == 16:
            val = struct.unpack('<H', frame_data[:2])[0]  # 16-bit is unsigned short
        elif sampwidth == 24:
            val = struct.unpack('<I', frame_data[:3] + b'\x00')[0]  # 24-bit is unsigned int (little-endian)
        else:
            raise ValueError("Unsupported sample width: {}".format(sampwidth))
        
        # scale current data to target bits
        val = val * scale_val / cur_lim
        val = int(val + ((scale_val + 1) // 2)) & scale_val
        array_str += '0x%x, ' % (val)
        if (i + 1) % 16 == 0:
            array_str += '\n'
    wave_read.close()
    return array_str


def gen_wave_table(wav_file_list, target_file_name, scale_bits=8):  # type: (List[str], str, int) -> None
    with open(target_file_name, 'w') as audio_table:
        print('#include <stdio.h>', file=audio_table)
        print('const unsigned char audio_table[] = {', file=audio_table)
        for wav in wav_file_list:
            print('processing: {}'.format(wav))
            wave_data_str = get_wave_array_str(filename=wav, target_bits=scale_bits)
            if wave_data_str:  # Only print non-empty strings
                print(wave_data_str, file=audio_table)
        print('};\n', file=audio_table)
    print('Done...')


if __name__ == '__main__':
    print('Generating audio array...')

    wav_file = input("Enter the name of the WAV file you want to convert: ")
    if not os.path.exists(wav_file):
        print(f"File {wav_file} does not exist.")
    else:
        output_file = os.path.splitext(wav_file)[0] + '.h'
        try:
            with wave.open(wav_file, 'r') as wave_read:
                _, sampwidth, _, _, _, _ = wave_read.getparams()
                sampwidth_bits = sampwidth * 8
        except wave.Error as e:
            print(f"Error processing {wav_file}: {e}")
            exit(1)
        
        gen_wave_table(wav_file_list=[wav_file], target_file_name=output_file, scale_bits=sampwidth_bits)

I used "a logic analyzer" to measure the output signal
audio signal

 Sometimes I use this tool the "DOUT" is empty!!!!

Related