espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.78k stars 7.44k forks source link

The esp32 i2s internal DAC output is not working with the release 2.0.1 #5938

Closed cicciocb closed 2 years ago

cicciocb commented 3 years ago

The audio output using I2S works both with an external DAC or in PDM mode but not using the internal DAC. This seems to be related to the ESP-IDF https://github.com/espressif/esp-idf/issues/7684

VojtechBartoska commented 3 years ago

PTAL, @PilnyTomas.

relates to: https://github.com/espressif/esp-idf/issues/7684

FedericoBusero commented 2 years ago

It did work until V2.0.0-rc2

Jason2866 commented 2 years ago

Do you have news for this @PilnyTomas ?

PilnyTomas commented 2 years ago

Hi, sorry for the late response - I was working on other tasks. I can confirm that in version 2.0.1 and newer it doesn't work and that version 2.0.0. does work. I will investigate to pinpoint the breaking commit and find the reason for this issue.

PilnyTomas commented 2 years ago

I found the braking commit, from Oct 1, 2021: 00214d5c2a1c2b1904f2caf6f0d5ddfe952331ff

VojtechBartoska commented 2 years ago

We are now discussing the issue with ESP-IDF team, we will let you know about the update.

Jason2866 commented 2 years ago

Maybe this https://www.esp32.com/viewtopic.php?t=6025

s-hadinger commented 2 years ago

I did some more tests, on ESP32 Rev1 and Pico D4. Actually the DAC output works, but the speed is 11x more than real time. I.e. I sent PCM at 16K samples/s, and it was played at ~176K samples/s.

Original waveform is 660ms long Orig

The signal recorded on GPIO26 is playing in 60ms DAC

cicciocb commented 2 years ago

Maybe this could be related to ? https://github.com/espressif/esp-idf/commit/1d02e638bd05b80d6fd648d51c14a8ecd6c2dbdc

s-hadinger commented 2 years ago

I doubt. I did some detour on i2s_hal_tx_clock_config() to check what clock values were calculated, and force-injected some different clock values until the sound was good again. I will work backwards to see why these values are wrong in the first place.

cicciocb commented 2 years ago

@s-hadinger What is the version of the arduino core that you are using?

s-hadinger commented 2 years ago

I use 2.0.2 with IDF 4.4. I believe the problem is in idf, not Arduino Core.

One highly possible cause is that the calculated mclk_div is 1250 when using 16000Hz audio on DAC. I'm not sure yet what are the values of a and b divider, but I realize now that mclk_div is 8-bit long. 1250 is clearly an overflow.

Values calculated by IDF 4.4 for 16000Hz audio, DAC, 2 channels sclk=160000000 mclk=128000 bclk=64000 mclk_div=1250 bclk_div=2

Hardware registers:

    union {
        struct {
            uint32_t clkm_div_num: 8;
            uint32_t clkm_div_b:   6;
            uint32_t clkm_div_a:   6;
            uint32_t clk_en:       1;
            uint32_t clka_en:      1;
            uint32_t reserved22:  10;
        };
        uint32_t val;
    } clkm_conf;

The overflow may explain why I got random results, and why I only could get something to work by increasing bclk_div

Edit: for information, bclk_div uses 6 bits

            uint32_t tx_bck_div_num: 6;
            uint32_t rx_bck_div_num: 6;

Edit2: 1250 (0x4E2) would be truncated to 226 (0xE2) which could explain why the playback was 11x times the normal rate.

s-hadinger commented 2 years ago

I have now confirmation. For 16000Hz, 2 channels, internal DAC is 8 bits.

Knowing that the sclk is 160MHz esp-idf set the following mclk_div=1250 and bclk_div=2 which makes an overall divider around at 1250*2 = 2500, i.e. a bit frequency of 160000000/2500 = 64000 bps. But the problem is that mclk is overflowing the 8 bits.

My working version sets: mclk_div=156, bclk_div=32, so the overall divider is 15632 = 4992. So the bit frequency is 160000000/4992 = 32051 bps, which is in line with 16000 2 (for 2 channels).

I'm still unclear whether a and b factors have an influence.

s-hadinger commented 2 years ago

I opened a new issue with these information https://github.com/espressif/esp-idf/issues/8326

s-hadinger commented 2 years ago

Recompiling esp-idf with the fix above(thanks @Jason2866) makes Audio DAC working again.

Here are the new values computed: sclk=160000000 mclk=1024000 bclk=32000 mclk_div=156 bclk_div=32

Jason2866 commented 2 years ago

The framework with the idf i2s fix is here if anyone wants to try. There are some different sdkconfig settings choosen to optimize for our needs. The build can directly used with platformio using platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip

cicciocb commented 2 years ago

@Jason2866 Thanks for your framework but what is exactly the fix done inside the idf? Thanks

s-hadinger commented 2 years ago

Not sure to understand your question. The proposed fixed was shared with idf team yesterday. Jason backported this fix into a custom version of IDF4.4.

This is the one we're using in Tasmota and proved to fix the Audio DAC issue described earlier.

cicciocb commented 2 years ago

@s-hadinger Thanks for your answer, I found the fix that is here https://github.com/espressif/esp-idf/pull/8327/files

cicciocb commented 2 years ago

@Jason2866 I tried but I still have the same issue, works well with external DAC or PDM but not with the internal DAC @s-hadinger Could you publish the source code that you are using for the test?

Jason2866 commented 2 years ago

@cicciocb Used with Tasmota ;-) Are you sure you have used latest version? To be sure you have to delete the hidden folder .platformio

cicciocb commented 2 years ago

@Jason2866 Yes, unfortunately I'm sure, it works rolling back to a previous version. Could you just publish your test case?

Jason2866 commented 2 years ago

@cicciocb You can use this setup https://github.com/arendst/Tasmota/pull/12795

cicciocb commented 2 years ago

@Jason2866 Still not working, at least for me. Maybe someone else could confirm if working or not

Jason2866 commented 2 years ago

@cicciocb Can you publish your test case?

VojtechBartoska commented 2 years ago

Fixed, will be available in 2.0.3 release. Related fix https://github.com/espressif/esp-idf/issues/8326.

VojtechBartoska commented 2 years ago

@cicciocb Wil you be able to retest this with v2.0.3-RC1? It should be already fixed :) Thank you.

VojtechBartoska commented 2 years ago

Closing as solved, if you still face problems, please reopen this.

pjmi1 commented 2 years ago

This is still broken (I2S using I2S_MODE_DAC_BUILT_IN) - it still does not work for Arduino ESP32 core v. 2.0.3

PilnyTomas commented 2 years ago

This is still broken (I2S using I2S_MODE_DAC_BUILT_IN) - it still does not work for Arduino ESP32 core v. 2.0.3

@pjmi1 Please open a new issue with specifications for your problem. Please include a complete sketch that demonstrates the issue.

ifrew commented 2 years ago

I can confirm this is still broken in Arduino 2.0.4, IDF 4.4.1

Not sure why we need to open a new bug for this @PilnyTomas?

Here is the sketch I used. If I change from internal DAC to PDM it works although really noisy.

// Arduino Zero / Feather M0 I2S audio tone generation example.
// Author: Tony DiCola
//
// Connect an I2S DAC or amp (like the UDA1334A) to the Arduino Zero
// and play back simple sine, sawtooth, triangle, and square waves.
// Makes your Zero sound like a NES!
//
// NOTE: The I2S signal generated by the Zero does NOT have a MCLK /
// master clock signal.  You must use an I2S receiver that can operate
// without a MCLK signal (like the UDA1334A).
//
// For an Arduino Zero / Feather M0 connect it to you I2S hardware as follows:
// - Digital 0 -> I2S LRCLK / FS (left/right / frame select clock)
// - Digital 1 -> I2S BCLK / SCLK (bit / serial clock)
// - Digital 9 -> I2S DIN / SD (data output)
// - Ground
//
// Released under a MIT license: https://opensource.org/licenses/MIT

//modified for M5Stack Gray Core

#include <M5Stack.h>
#include <driver/i2s.h>

#define SPEAKER_I2S_NUMBER I2S_NUM_0

#define SAMPLERATE_HZ 44100  // The sample rate of the audio.  Higher sample rates have better fidelity,
                             // but these tones are so simple it won't make a difference.  44.1khz is
                             // standard CD quality sound.

#define AMPLITUDE     ((1<<31)-1)   // Set the amplitude of generated waveforms.  This controls how loud
                             // the signals are, and can be any value from 0 to 2**31 - 1.  Start with
                             // a low value to prevent damaging speakers!

#define WAV_SIZE      256    // The size of each generated waveform.  The larger the size the higher
                             // quality the signal.  A size of 256 is more than enough for these simple
                             // waveforms.

// Define the frequency of music notes (from http://www.phy.mtu.edu/~suits/notefreqs.html):
#define C4_HZ      261.63
#define D4_HZ      293.66
#define E4_HZ      329.63
#define F4_HZ      349.23
#define G4_HZ      392.00
#define A4_HZ      440.00
#define B4_HZ      493.88

// Define a C-major scale to play all the notes up and down.
float scale[] = { C4_HZ, D4_HZ, E4_HZ, F4_HZ, G4_HZ, A4_HZ, B4_HZ, A4_HZ, G4_HZ, F4_HZ, E4_HZ, D4_HZ, C4_HZ };

// Store basic waveforms in memory.
int32_t sine[WAV_SIZE]     = {0};
int32_t sawtooth[WAV_SIZE] = {0};
int32_t triangle[WAV_SIZE] = {0};
int32_t square[WAV_SIZE]   = {0};
size_t writeSize;

// Create I2S audio transmitter object.
//Adafruit_ZeroI2S i2s;

#define Serial Serial

void generateSine(int32_t amplitude, int32_t* buffer, uint16_t length) {
  // Generate a sine wave signal with the provided amplitude and store it in
  // the provided buffer of size length.
  for (int i=0; i<length; ++i) {
    buffer[i] = int32_t(float(amplitude)*sin(2.0*PI*(1.0/length)*i));
  }
}
void generateSawtooth(int32_t amplitude, int32_t* buffer, uint16_t length) {
  // Generate a sawtooth signal that goes from -amplitude/2 to amplitude/2
  // and store it in the provided buffer of size length.
  float delta = float(amplitude)/float(length);
  for (int i=0; i<length; ++i) {
    buffer[i] = -(amplitude/2)+delta*i;
  }
}

void generateTriangle(int32_t amplitude, int32_t* buffer, uint16_t length) {
  // Generate a triangle wave signal with the provided amplitude and store it in
  // the provided buffer of size length.
  float delta = float(amplitude)/float(length);
  for (int i=0; i<length/2; ++i) {
    buffer[i] = -(amplitude/2)+delta*i;
  }
    for (int i=length/2; i<length; ++i) {
    buffer[i] = (amplitude/2)-delta*(i-length/2);
  }
}

void generateSquare(int32_t amplitude, int32_t* buffer, uint16_t length) {
  // Generate a square wave signal with the provided amplitude and store it in
  // the provided buffer of size length.
  for (int i=0; i<length/2; ++i) {
    buffer[i] = -(amplitude/2);
  }
    for (int i=length/2; i<length; ++i) {
    buffer[i] = (amplitude/2);
  }
}

void playWave(int32_t* buffer, uint16_t length, float frequency, float seconds) {
  // Play back the provided waveform buffer for the specified
  // amount of seconds.
  // First calculate how many samples need to play back to run
  // for the desired amount of seconds.
  uint32_t iterations = seconds*SAMPLERATE_HZ;
  // Then calculate the 'speed' at which we move through the wave
  // buffer based on the frequency of the tone being played.
  float delta = (frequency*length)/float(SAMPLERATE_HZ);
  // Now loop through all the samples and play them, calculating the
  // position within the wave buffer for each moment in time.
  for (uint32_t i=0; i<iterations; ++i) {
    uint16_t pos = uint32_t(i*delta) % length;
    int32_t sample = buffer[pos];
    // Duplicate the sample so it's sent to both the left and right channel.
    // It appears the order is right channel, left channel if you want to write
    // stereo sound.
    i2s_write(SPEAKER_I2S_NUMBER, &sample, sizeof(sample), &writeSize, portMAX_DELAY);
  }
}

void setup() {
  // Configure serial port.
  Serial.begin(115200);

  Serial.printf("ESP-IDF Version %d.%d.%d \r\n", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR, ESP_IDF_VERSION_PATCH);
  Serial.printf("Ardunio Version %d.%d.%d \r\n", ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH);

  M5.begin(true, true, true, true);

  Serial.println("Audio Tone Generator");

  // Initialize the I2S transmitter.
  esp_err_t err = ESP_OK;

  //i2s_driver_uninstall(SPEAKER_I2S_NUMBER);
  i2s_config_t i2s_config = {
      .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
      .sample_rate = SAMPLERATE_HZ ,
      .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
      .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
      .communication_format = I2S_COMM_FORMAT_I2S,
      .intr_alloc_flags = 0,
      .dma_buf_count = 2,
      .dma_buf_len = 256
  };

  i2s_config.use_apll = false;
  i2s_config.tx_desc_auto_clear = true;

  err += i2s_driver_install(SPEAKER_I2S_NUMBER, &i2s_config, 0, NULL);
  i2s_pin_config_t tx_pin_config;

  tx_pin_config.mck_io_num = 0;
  tx_pin_config.bck_io_num = 12;
  tx_pin_config.ws_io_num = 13;
  tx_pin_config.data_out_num = 15;
  tx_pin_config.data_in_num = 34;

  err += i2s_set_pin(SPEAKER_I2S_NUMBER, NULL);

  err += i2s_set_clk(SPEAKER_I2S_NUMBER, SAMPLERATE_HZ, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);

  // Generate waveforms.
  generateSine(AMPLITUDE, sine, WAV_SIZE);
  generateSawtooth(AMPLITUDE, sawtooth, WAV_SIZE);
  generateTriangle(AMPLITUDE, triangle, WAV_SIZE);
  generateSquare(AMPLITUDE, square, WAV_SIZE);
}

void loop() {
  Serial.println("Sine wave");
  for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
    // Play the note for a quarter of a second.
    playWave(sine, WAV_SIZE, scale[i], 0.25);
    // Pause for a tenth of a second between notes.
    delay(100);
  }
  Serial.println("Sawtooth wave");
  for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
    // Play the note for a quarter of a second.
    playWave(sawtooth, WAV_SIZE, scale[i], 0.25);
    // Pause for a tenth of a second between notes.
    delay(100);
  }
  Serial.println("Triangle wave");
  for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
    // Play the note for a quarter of a second.
    playWave(triangle, WAV_SIZE, scale[i], 0.25);
    // Pause for a tenth of a second between notes.
    delay(100);
  }
  Serial.println("Square wave");
  for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
    // Play the note for a quarter of a second.
    playWave(square, WAV_SIZE, scale[i], 1.0);
    // Pause for a tenth of a second between notes.
    //delay(1);
    delay(100);
  }
}
PilnyTomas commented 2 years ago

Hi @ifrew I tried your code and it takes 110 seconds to generate that 0.25sec tone. Please try improving tone generation.

ifrew commented 2 years ago

@PilnyTomas It isn't actually my code, I was just using an example I found to show the potential issue. However, I did find the issue in the example. as I stated in #6856. Thanks for getting back though.

PilnyTomas commented 2 years ago

I have tried IDF example and the output is very laggy, so I opened an issue for the IDF team https://github.com/espressif/esp-idf/issues/9389

JoseEnriqueFA commented 2 years ago

The esp32 I2s internal DAC output is NOT working with the release 2.0.5

I tested yesterday the last Board Manager release 2.0.5 and a sketch to generate a sinus signal with I2S and the internal DAC output. Same result: Not Working!

HW: Adafruit ESP32 feather and an oscilloscope

With the Board Manager 2.0.0 the sketch works but all the Board Manager > 2.0.0 have same bug

Is there any work around?

Note: I discovered the bug trying to evaluate the Adafruit ESP32 feather V2. You need to upgrade the Board Manager to 2.0.4 Same issue is shown in both boards Adafruit ESP32 feather and Adafruit ESP32 feather V2

PilnyTomas commented 2 years ago

@cicciocb, @ifrew, @pjmi1, can you please try this sketch if it works for you? It does for me.

JoseEnriqueFA commented 2 years ago

this sketch https://github.com/PilnyTomas/issues/blob/4b5315b5547165c9f080fd3e993dce24bf0fe7bf/issue_7252B/issue_7252B.ino is also working for me

But:

    .use_apll = 1

   produces sporadic glitches with the Arduino  Board Manager  2.0.5   .   See:    https://github.com/espressif/esp-idf/issues/9321

  Alternatives:  

                  .use_apll = 0        (For my application  is fine)

  or

                 Arduino  Board Manager  1.0.6    .use_apll = 1    does not produce glitches

Best whishes

De: Tomáš Pilný @.*** Enviado el: lunes, 17 de octubre de 2022 17:12 Para: espressif/arduino-esp32 CC: JoseEnriqueFA; Comment Asunto: Re: [espressif/arduino-esp32] The esp32 i2s internal DAC output is not working with the release 2.0.1 (Issue #5938)

Can you please try this sketch https://github.com/PilnyTomas/issues/blob/4b5315b5547165c9f080fd3e993dce24bf0fe7bf/issue_7252B/issue_7252B.ino if it works for you? It does for me.

— Reply to this email directly, view it on GitHub https://github.com/espressif/arduino-esp32/issues/5938#issuecomment-1281027915 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AML3OVBGNJP7I5XPRQY2PR3WDVUFBANCNFSM5I5BQEUQ . You are receiving this because you commented. https://github.com/notifications/beacon/AML3OVDEOLFN733AH3RD6MTWDVUFBA5CNFSM5I5BQEU2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOJRNO6SY.gif Message ID: @.***>

PilnyTomas commented 2 years ago

The topic seems to be dead, so I am closing it.

McMornan commented 2 years ago

Hi, I ran into this issue yesterday. Took me hours of testing different boards and max chips, checking wiring and pin layout etc. to finally come to the conclusion that the only difference of my hitherto working code vs. non working code and device was 1.0.6 vs 2.0.6 esp32 framework.

Arduino 1.8.6, esp32 2.0.6 framework, esp32 dev board, max dac chip.

Downgraded to 1.0.6, dac works again immediately.

JoseEnriqueFA commented 2 years ago

Hi, After many hours used in this issue .... You have to init I2S depending the Board Manager you are using, see my code bellow In summary with Adafruit feather I follow using B.M. 1.0.6 with Adafruit feather v2 I use B.M. 2.0.4 Nevertheless take care of 1- if you change use_apll = false, to true with B.M. 2.0.4 you will get glitches It does not happen with B.M. 1.0.6 2- In my application I cannot use B.M. 2.0.5 because there are other issues related SPIFFS ... I should investigate .... 3- I have not tested B.M. 2.0.6 Good luck

//////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////

ifdef B_Manager_1_0_6

void i2sInit() { i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), .sample_rate = I2S_SAMPLE_RATE_LOW, // The format of the signal using ADC_BUILT_IN .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8, .dma_buf_len = 64, .use_apll = false, .tx_desc_auto_clear = false,
.fixed_mclk = 0
}; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); //install and start i2s driver i2s_set_pin(I2S_NUM_0, NULL); //for internal DAC, this will enable both of the internal channels }

endif

//////////////////////////////////////////////////////////////////////////////////////////////////// // Board Manager superior a 2.0.4 needs for ADAFRUIT ESP32 feather V2 ///////////////////////////////////////////////////////////////////////////////////////////////////

ifdef BManager>_2_0_4

void i2sInit() { i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), .sample_rate = I2S_SAMPLE_RATE_LOW, // The format of the signal using ADC_BUILT_IN .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_MSB, // B.M. 2.0.4 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8, .dma_buf_len = 64, .use_apll = false, .tx_desc_auto_clear = false,
.fixed_mclk = 0
}; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); //install and start i2s driver i2s_set_pin(I2S_NUM_0, NULL); //for internal DAC, this will enable both of the internal channels }

endif

De: McMornan @.*** Enviado el: miércoles, 09 de noviembre de 2022 18:13 Para: espressif/arduino-esp32 CC: JoseEnriqueFA; Comment Asunto: Re: [espressif/arduino-esp32] The esp32 i2s internal DAC output is not working with the release 2.0.1 (Issue #5938)

Hi, I ran into this issue yesterday. Took me hours of testing different boards and max chips, checking wiring and pin layout etc. to finally come to the conclusion that the only difference of my hitherto working code vs. non working code and device was 1.0.6 vs 2.0.6 esp32 framework.

Arduino 1.8.6, esp32 2.0.6 framework, esp32 dev board, max dac chip.

Downgraded to 1.0.6, dac works again immediately.

— Reply to this email directly, view it on GitHub https://github.com/espressif/arduino-esp32/issues/5938#issuecomment-1309077652 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AML3OVE75QDJFXPZNP6GKUDWHPLRRANCNFSM5I5BQEUQ . You are receiving this because you commented. https://github.com/notifications/beacon/AML3OVHCU7WC7XW4GQXHGLLWHPLRRA5CNFSM5I5BQEU2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOJYDPBFA.gif Message ID: @.***>

PilnyTomas commented 2 years ago

Please understand the difference between IDF and arduino-esp32. The function i2s_driver_install is IDF (please read the documentation) - if something doesn't work, please report it to IDF repository

From version 2.0.3 of arduino-esp32 there is I2S library using Arduino API (Arduino Documentation) I am currently working on some fixes and updates for this library - you can follow them in PR #7117

Arduino-esp32 is based on IDF so you can always use IDF functions and combine them with Arduino API. We pull updates done in IDF from time to time, which could cause breaking changes or introduce bugs, but most of the time they are fixing previous bugs.