You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi,
My project involves the bidirectional transmission of audio signals between two ESP32 modules over WiFi and the internet using UDP.
On both sides a ESP32-WROOM-32D module is used in conjunction with a WM8731A codec.
The sketch was developed on the Arduino IDE 1.8.12 and the ESP32 libraries 1.0.4 on a Ubuntu 18.04 system. Upload speed: 921600, Flash: 80MHz/QIO/4MB, CPUs: 240MHz.
Everything works fine, simultaneous 16bit sound in and 16bit sound out on both sides (sampling rate is 8kHz), running at 25 packets /s in both directions, a 16.75 KByte/s net data rate (sound + control signal).
I however notices a periodic rattling at some 4Hz in the sound outputs. In order to eliminate all other variables (a.o. packet loss, lack of synchronicity, ...), I made a simple sketch (see further) just to push a sine wave (785Hz) to the DAC. The rattle is present most of the time but disappears for about 12s seconds every 30s or so.
On the oscilloscope the rattle is uneasy to catch, but appears to be a superfluous/duplicated sample, i.e. the DAC output remains constant for a single sample period. As far as I could determine, this duplicate value fault is repeated every 256ms, or 2048 samples, being by no coincidence (?) "dma_buf_count = 8" times "dma_buf_len = 256". The MCLK, BCLK & FCLK signals were fine on the scope, i.e. no missing cycles.
The Debug level was set to "debug", no messages were generated though.
I am a bit stuck here, any suggestion ?
Also, I understand that the hit and miss method with the "i2s_push_sample" function is probably not the most efficient way to handle the I2S. Can any of you point me towards a good example of a sketch to drive an audio codec with the I2S interface simultaneously for in and out.
// *********************************************************************************************
// Setting up the environment
// *********************************************************************************************
void setup() {
uint16_t i, j, err = 0;
pinMode (R_LED, OUTPUT );
digitalWrite(R_LED, HIGH);
pinMode (G_LED, OUTPUT );
digitalWrite(G_LED, HIGH);
// starting the serial ports
Wire.begin(I2C_SDA, I2C_SCL, 100000); // creating a I2C port
Serial.begin(115200); // uart connection used for debugging
// initialize WM8731 codec
for (i = 0; i < 12; i++) {
Wire.beginTransmission(codec);
Wire.write(wm8731_regs[i][0]);
Wire.write(wm8731_regs[i][1]);
err += Wire.endTransmission();
delay(1);
}
if (err == 0) Serial.println("codec initialized");
else Serial.println("codec initialization failed");
// start I2S hardware & driver
i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL); // no events used
i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
// this is to output a 2048 kHz (8kHz*256) clock aka the MCLK on GPIO0
REG_WRITE(PIN_CTRL, 0b111111110000);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
Serial.println("I2S configured @ 8kHz");
delay(10);
// run audio task in dedicated task on cpu core 1
xTaskCreatePinnedToCore(audioTask, "audioTask", 10000, NULL, 10, NULL, 1);
} // end setup
// ********************************************************************************************
// Dedicated audio task, this is in effect a 2nd "loop"
// ********************************************************************************************
void audioTask(void *) {
uint8_t byte_num;
Serial.println("dedicated audio task created");
while (true) { // audio task will never end
// output a synthesized signal as a debug feature
byte_num = 2;
while (byte_num != 0) {
byte_num = i2s_push_sample((i2s_port_t)i2s_num, (uint8_t *)&synth[0], 1); // push sample left & right
byte_num = i2s_push_sample((i2s_port_t)i2s_num, (uint8_t *)&synth[0], 1);
if (byte_num != 0) { // generating a continuous single tone of 785Hz
accu += adder;
synth[0] = sine[(accu >> 8)];
}
}
delay(1);
}
vTaskDelete(NULL);
}
// ********************************************************************************************
// Recurrent part of the program
// ********************************************************************************************
void loop() {
delay(1);
} // end loop
The text was updated successfully, but these errors were encountered:
Hi,
My project involves the bidirectional transmission of audio signals between two ESP32 modules over WiFi and the internet using UDP.
On both sides a ESP32-WROOM-32D module is used in conjunction with a WM8731A codec.
The sketch was developed on the Arduino IDE 1.8.12 and the ESP32 libraries 1.0.4 on a Ubuntu 18.04 system. Upload speed: 921600, Flash: 80MHz/QIO/4MB, CPUs: 240MHz.
Everything works fine, simultaneous 16bit sound in and 16bit sound out on both sides (sampling rate is 8kHz), running at 25 packets /s in both directions, a 16.75 KByte/s net data rate (sound + control signal).
I however notices a periodic rattling at some 4Hz in the sound outputs. In order to eliminate all other variables (a.o. packet loss, lack of synchronicity, ...), I made a simple sketch (see further) just to push a sine wave (785Hz) to the DAC. The rattle is present most of the time but disappears for about 12s seconds every 30s or so.
On the oscilloscope the rattle is uneasy to catch, but appears to be a superfluous/duplicated sample, i.e. the DAC output remains constant for a single sample period. As far as I could determine, this duplicate value fault is repeated every 256ms, or 2048 samples, being by no coincidence (?) "dma_buf_count = 8" times "dma_buf_len = 256". The MCLK, BCLK & FCLK signals were fine on the scope, i.e. no missing cycles.
The Debug level was set to "debug", no messages were generated though.
I am a bit stuck here, any suggestion ?
Also, I understand that the hit and miss method with the "i2s_push_sample" function is probably not the most efficient way to handle the I2S. Can any of you point me towards a good example of a sketch to drive an audio codec with the I2S interface simultaneously for in and out.
Many thanks and all the best,
Jean.
#include <Arduino.h>
#include "driver/i2s.h"
#include <Wire.h>
#include "freertos/queue.h"
// Pin definitions:
#define I2C_SDA 15 // I2C for WM8731
#define I2C_SCL 14
#define I2S_DOUT 21 // I2S for WM8731
#define I2S_DIN 22
#define I2S_FCLK 26
#define I2S_BCLK 25
#define I2S_MCLK 0
#define G_LED 18 // debug leds
#define R_LED 19
// other defines
#define SAMPLERATE 8000l
//i2s configuration
int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
.sample_rate = SAMPLERATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority, interrupt level 1
.dma_buf_count = 8,
.dma_buf_len = 256,
.use_apll = true
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_BCLK,
.ws_io_num = I2S_FCLK,
.data_out_num = I2S_DOUT,
.data_in_num = I2S_DIN
};
#define codec 0x1a // I2C address of WM8731 codec
#define hifreq 6431 // 785Hz adder for 8000kHz sampling rate & 16bit accumulator
uint16_t accu = 0, adder = hifreq;
int16_t synth[] = { 0x0000, 0x0000, 0x0000, 0x0000};
const uint8_t wm8731_regs[12][2] = { // WM8731 initialization
{ 0x1e, 0x00 }, // reset
{ 0x0c, 0x10 }, // power control: all on except output
{ 0x0e, 0x01 }, // data format: slave mode, 16bit, MSB-First, left justified
{ 0x00, 0x17 }, // lin vol: 0dB
{ 0x02, 0x17 }, // rin vol: 0dB
{ 0x04, 0x79 }, // lhp vol: 0dB
{ 0x06, 0x79 }, // rhp vol: 0dB
{ 0x08, 0x10 }, // ana conf: DAC select & line in select
{ 0x0a, 0x00 }, // dig conf: normal
{ 0x10, 0x00 }, // sample rate: normal, 48ks/s @ 12288kHz MCLK yields 8ks/s @ 2048kHz
{ 0x12, 0x01 }, // enable: interface active
{ 0x0c, 0x00 } // power control, all on incl. output
};
const int16_t sine[256] = { 0, 736, 1472, 2207, 2941, 3672, 4402, 5129, 5853, 6573, 7289, 8001, 8709, 9410, 10107, 10797,
11481, 12157, 12827, 13488, 14142, 14787, 15423, 16050, 16667, 17274, 17871, 18457, 19032, 19595, 20147, 20686,
21213, 21727, 22229, 22716, 23190, 23650, 24096, 24528, 24944, 25346, 25732, 26103, 26458, 26797, 27120, 27426,
27716, 27990, 28246, 28486, 28708, 28913, 29101, 29271, 29424, 29558, 29675, 29774, 29856, 29919, 29964, 29991,
30000, 29991, 29964, 29919, 29856, 29774, 29675, 29558, 29424, 29271, 29101, 28913, 28708, 28486, 28246, 27990,
27716, 27426, 27120, 26797, 26458, 26103, 25732, 25346, 24944, 24528, 24096, 23650, 23190, 22716, 22229, 21727,
21213, 20686, 20147, 19595, 19032, 18457, 17871, 17274, 16667, 16050, 15423, 14787, 14142, 13488, 12827, 12157,
11481, 10797, 10107, 9410, 8709, 8001, 7289, 6573, 5853, 5129, 4402, 3672, 2941, 2207, 1472, 736,
0, -736, -1472, -2207, -2941, -3672, -4402, -5129, -5853, -6573, -7289, -8001, -8709, -9410,-10107,-10797,
-11481,-12157,-12827,-13488,-14142,-14787,-15423,-16050,-16667,-17274,-17871,-18457,-19032,-19595,-20147,-20686,
-21213,-21727,-22229,-22716,-23190,-23650,-24096,-24528,-24944,-25346,-25732,-26103,-26458,-26797,-27120,-27426,
-27716,-27990,-28246,-28486,-28708,-28913,-29101,-29271,-29424,-29558,-29675,-29774,-29856,-29919,-29964,-29991,
-30000,-29991,-29964,-29919,-29856,-29774,-29675,-29558,-29424,-29271,-29101,-28913,-28708,-28486,-28246,-27990,
-27716,-27426,-27120,-26797,-26458,-26103,-25732,-25346,-24944,-24528,-24096,-23650,-23190,-22716,-22229,-21727,
-21213,-20686,-20147,-19595,-19032,-18457,-17871,-17274,-16667,-16050,-15423,-14787,-14142,-13488,-12827,-12157,
-11481,-10797,-10107, -9410, -8709, -8001, -7289, -6573, -5853, -5129, -4402, -3672, -2941, -2207, -1472, -736
}; // equates to 880mVeff at the output
// *********************************************************************************************
// Setting up the environment
// *********************************************************************************************
void setup() {
uint16_t i, j, err = 0;
pinMode (R_LED, OUTPUT );
digitalWrite(R_LED, HIGH);
pinMode (G_LED, OUTPUT );
digitalWrite(G_LED, HIGH);
// starting the serial ports
Wire.begin(I2C_SDA, I2C_SCL, 100000); // creating a I2C port
Serial.begin(115200); // uart connection used for debugging
// initialize WM8731 codec
for (i = 0; i < 12; i++) {
Wire.beginTransmission(codec);
Wire.write(wm8731_regs[i][0]);
Wire.write(wm8731_regs[i][1]);
err += Wire.endTransmission();
delay(1);
}
if (err == 0) Serial.println("codec initialized");
else Serial.println("codec initialization failed");
// start I2S hardware & driver
i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL); // no events used
i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
// this is to output a 2048 kHz (8kHz*256) clock aka the MCLK on GPIO0
REG_WRITE(PIN_CTRL, 0b111111110000);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
Serial.println("I2S configured @ 8kHz");
delay(10);
// run audio task in dedicated task on cpu core 1
xTaskCreatePinnedToCore(audioTask, "audioTask", 10000, NULL, 10, NULL, 1);
} // end setup
// ********************************************************************************************
// Dedicated audio task, this is in effect a 2nd "loop"
// ********************************************************************************************
void audioTask(void *) {
uint8_t byte_num;
Serial.println("dedicated audio task created");
while (true) { // audio task will never end
// output a synthesized signal as a debug feature
byte_num = 2;
while (byte_num != 0) {
byte_num = i2s_push_sample((i2s_port_t)i2s_num, (uint8_t *)&synth[0], 1); // push sample left & right
byte_num = i2s_push_sample((i2s_port_t)i2s_num, (uint8_t *)&synth[0], 1);
if (byte_num != 0) { // generating a continuous single tone of 785Hz
accu += adder;
synth[0] = sine[(accu >> 8)];
}
}
delay(1);
}
vTaskDelete(NULL);
}
// ********************************************************************************************
// Recurrent part of the program
// ********************************************************************************************
void loop() {
delay(1);
} // end loop
The text was updated successfully, but these errors were encountered: