Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems using I2S to output #3932

Closed
JeanRenier opened this issue Apr 23, 2020 · 2 comments
Closed

Problems using I2S to output #3932

JeanRenier opened this issue Apr 23, 2020 · 2 comments

Comments

@JeanRenier
Copy link

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

@lbernstone
Copy link
Contributor

This issue is more appropriate for the esp-idf issues or esp32.com forum. This is not an issue with arduino-esp32.

@JeanRenier
Copy link
Author

Ok, sorry about the inconvenience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants