Problem with volume control using MAX98357A and I2S on an ESP32

billys7
Posts: 5
Joined: Tue Feb 22, 2022 4:00 pm

Problem with volume control using MAX98357A and I2S on an ESP32

Postby billys7 » Tue Feb 22, 2022 4:31 pm

I use the following code to reproduce an audio file with ESP32 --> I2S --> MAX98357A with success.

I want to add a software volume, so i add the code in comments. When i uncomment this part of the code the result is very noisy.
Do you have any suggestions ?

Code: Untitled.cpp Select all


#include "driver/i2s.h"
#include "freertos/queue.h"
#include <pgmspace.h>

#include "soundsample.h"

uint16_t readData1, readData2;
uint32_t readData, counter;

//i2s configuration
const int i2s_num = 0;

i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 16000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 1024,
.use_apll = 0,
.tx_desc_auto_clear = true
};


i2s_pin_config_t pin_config = {
.bck_io_num = 26, //this is BCK pin
.ws_io_num = 25, // this is LRCK pin
.data_out_num = 22, // this is DATA output pin
.data_in_num = I2S_PIN_NO_CHANGE
// .data_in_num = -1 //Not used
};

int i2s_write_sample_nb(uint32_t sample)
{
size_t bytes_written;
i2s_write((i2s_port_t)i2s_num, (const char*)&sample, sizeof(uint32_t), &bytes_written, 100);
return bytes_written;
}

//Main function to play samples from PROGMEM
void playPROGMEMsample(const uint32_t* audioSample)
{
i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL); //initialize i2s with configurations above
i2s_set_pin((i2s_port_t)i2s_num, &pin_config); //initialize i2s with configurations above
i2s_set_sample_rates((i2s_port_t)i2s_num, 16000); //set sample rates of i2s to sample rate of wav file

while (audioSample)
{
readData = pgm_read_dword(&audioSample[counter++]);

readData = ((readData>>24)&0xff) | // move byte 3 to byte 0 // Convert big endian to little endian in C
((readData<<8)&0xff0000) | // move byte 1 to byte 2
((readData>>8)&0xff00) | // move byte 2 to byte 1
((readData<<24)&0xff000000); // byte 0 to byte 3

/* Code for volume test
readData1 = uint16_t(readData>>16);
readData1 = readData1 /3;
readData2 = uint16_t(readData);
readData2 = readData2 /3;
readData = uint32_t (readData1 << 16)+ readData2;
*/

i2s_write_sample_nb(readData);
if(counter > 125252) break;
}
counter = 0;
readData = 0;
i2s_driver_uninstall((i2s_port_t)i2s_num); //stop & destroy i2s driver
}

void setup()
{
Serial.begin(115200);
Serial.println("Serial connection OK");
playPROGMEMsample(sample1);
Serial.println("End");
}

void loop()
{

}
Attachments
soundsample.h
(1.43 MiB) Downloaded 298 times

imanpakii
Posts: 3
Joined: Fri Jan 29, 2021 2:42 am

Re: Problem with volume control using MAX98357A and I2S on an ESP32

Postby imanpakii » Thu Mar 17, 2022 2:41 pm

Hello,

Did you Fix the problem?
I'm using driver/i2s.h and I would like to change the sound volume also.
Please give me your solution if you have it.

Thank you
Iman

billys7
Posts: 5
Joined: Tue Feb 22, 2022 4:00 pm

Re: Problem with volume control using MAX98357A and I2S on an ESP32

Postby billys7 » Tue Mar 22, 2022 10:45 pm

I have no solution yet. I think that i must include the i2s_write function in an interrupt - task, so i can use it, only when the buffer will be empty. I read in this forum that i can trigger an event when the buffer is empty but i couldn't understand it. i want to learn more about the function :

"i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);"

i2s_num I2S device number
i2s_config I2S configurations - see i2s_config_t struct
queue_size I2S event queue size/depth. (what does that mean ? How can i know the value ?)
i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue. (When the event will happend ?)

and especially about the last 2 parameters, and the way that i will do the interrupt - task.

Also, in the technical reference, i found the I2S_TX_REMPTY_INT interrupt. It is triggered when the transmit FIFO is empty. I think that this is what i am looking for, but i don't know how can i trigger it.

Unfortunately it is very difficult to find a guide, and the infos are limited.

Who is online

Users browsing this forum: PetalBot, Semrush [Bot] and 4 guests