espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.48k stars 7.26k forks source link

Internal DAC glitches using I2S ".use_apll = true" (IDFGH-7784) #9321

Open VK2BEA opened 2 years ago

VK2BEA commented 2 years ago

Environment

Problem Description

The output of the DAC is glitchy when the "use_apll" is set TRUE. It is very clean when the PLL is off (use_apll set to off). For my application I must use the PLL. Without the PLL, the correct sampling frequency cannot be generated.

See the attached pictures. The glitches are random (non synchronous to the waveform and vary).

In the sample code I am generating two quadrature sinewaves at 100 Hz.

Expected Behavior

Clean signals generated at the DAC outputs corresponding to the digital values set

Actual Behavior

Random noise on DAC outputs

Steps to reproduce

  1. run code
  2. observe output on oscilloscope
  3. see glitches
  4. set ".use_apll = false"
  5. observe that the outout is clean (but the frequency is not 100Hz as needed)

Code to reproduce this issue

#include "freertos/FreeRTOS.h"
#include "esp_system.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "driver/gpio.h"

#include "driver/dac.h"
#include "driver/i2s.h"
#include <math.h>

#define I2S_NUM (i2s_port_t)0

#define NUM_CTCSS_TONES 39
float CTCSS[NUM_CTCSS_TONES] = {
        199.5,  67.0,  71.9,  74.4,  77.0,  79.7,  82.5,  85.4,  88.5,  91.5,
         94.8,  97.4, 100.0, 103.5, 107.2, 110.9, 114.8, 118.8, 123.0, 127.3,
        131.8, 136.5, 141.3, 146.2, 151.4, 156.7, 162.2, 167.9, 173.8, 179.9,
        186.2, 192.8, 203.5, 210.7, 218.1, 225.7, 233.6, 241.8, 250.3
};

#define NOofSAMPLESperSINE  100

// One cycle of quadrature sinewave
// With the internal DAC, only the upper 8 bits are used for each 16bit sample
// The channels are interleaved
const uint32_t sineBuffer[ NOofSAMPLESperSINE ] = {
        0x8000ff00,0x8800ff00,0x9000fe00,0x9700fd00,0x9f00fb00,0xa700f900,0xaf00f700,0xb600f300,0xbd00f000,0xc400ec00,
        0xcb00e700,0xd100e200,0xd700dd00,0xdd00d700,0xe200d100,0xe700cb00,0xec00c400,0xf000bd00,0xf300b600,0xf700af00,
        0xf900a700,0xfb009f00,0xfd009700,0xfe009000,0xff008800,0xff008000,0xff007700,0xfe006f00,0xfd006800,0xfb006000,
        0xf9005800,0xf7005000,0xf3004900,0xf0004200,0xec003b00,0xe7003400,0xe2002e00,0xdd002800,0xd7002200,0xd1001d00,
        0xcb001800,0xc4001300,0xbd000f00,0xb6000c00,0xaf000800,0xa7000600,0x9f000400,0x97000200,0x90000100,0x88000000,
        0x80000000,0x77000000,0x6f000100,0x68000200,0x60000400,0x58000600,0x50000800,0x49000c00,0x42000f00,0x3b001300,
        0x34001800,0x2e001d00,0x28002200,0x22002800,0x1d002e00,0x18003400,0x13003b00,0x0f004200,0x0c004900,0x08005000,
        0x06005800,0x04006000,0x02006800,0x01006f00,0x00007700,0x00007f00,0x00008800,0x01009000,0x02009700,0x04009f00,
        0x0600a700,0x0800af00,0x0c00b600,0x0f00bd00,0x1300c400,0x1800cb00,0x1d00d100,0x2200d700,0x2800dd00,0x2e00e200,
        0x3400e700,0x3b00ec00,0x4200f000,0x4900f300,0x5000f700,0x5800f900,0x6000fb00,0x6800fd00,0x6f00fe00,0x7700ff00
};

//Configuration for the I2S bus
i2s_config_t i2s_config = {
  .mode                 = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), //Mode
  .sample_rate          = 0, //set below
  .bits_per_sample      = I2S_BITS_PER_SAMPLE_16BIT, // the DAC uses only top 8 bits of the MSB
  .channel_format       = I2S_CHANNEL_FMT_RIGHT_LEFT, // Channel format ESP32 supports stereo only
  .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, //Standard format for I2S
  .intr_alloc_flags     = 0,   // Standard Interrupt
  .dma_buf_count        = 2,   // Number of FIFO buffers
  .dma_buf_len          = 100, // Size of FIFO buffers
  .use_apll             = true,
  .fixed_mclk           = 0
};

void app_main(void)
{
    nvs_flash_init();

    // CTCSS 100Hz
    i2s_config.sample_rate = (uint32_t)round( CTCSS[ 12 ] * (double)NOofSAMPLESperSINE );

    ESP_ERROR_CHECK( dac_i2s_enable() );
    ESP_ERROR_CHECK( i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL) );
    ESP_ERROR_CHECK( i2s_set_pin(I2S_NUM, NULL) );
    ESP_ERROR_CHECK( i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN) );

    // Fill buffers with once cycle of quadrature sinewave
    int buffers = 0;
    do {
        size_t bytesWritten;
        i2s_write(I2S_NUM, (const char *)sineBuffer, NOofSAMPLESperSINE * sizeof(uint32_t),
                &bytesWritten, NOofSAMPLESperSINE);
    } while (++buffers < 2);
    i2s_set_sample_rates(I2S_NUM, i2s_config.sample_rate);

    while (true) {
        vTaskDelay( 500 / portTICK_PERIOD_MS );
    }

}

Here is a trace showing the glitches are random (non-periodic) Here is a trace showing a close up of the glitches

again, the gliches to not occur if the clock is not using the PLL (indicating the code is good)

Michael

VK2BEA commented 2 years ago

Is anything happening on this problem?

L-KAYA commented 2 years ago

Is the issue exists on other released branch? I didn't catch any clue where the glitches might come from 😟

L-KAYA commented 2 years ago

It seems not a software issue,I monitored the clock of APLL, it looks pretty well, and it's totally same with the PLL clock. I used two DMA strategies to transport the data, not work, it's not likely a DMA problem as well.

The most possible reason I guess is these two clock domain (APLL for I2S DMA and RTC for DAC) are affected by each other. Due to the APLL generated a good clock, I doubt RTC is interfered by something that introduced by the APLL

VK2BEA commented 2 years ago

It happens on all the branches / releases I've tried and on several hardware platforms.

L-KAYA commented 2 years ago

I tried again with the data that calculated by sin and found the glitches are gone

uint8_t w_buf[800] = {0};
for (int i = 0; i < 800; i+=2) {
    uint8_t val = (uint8_t)((sin(2 * 3.1416 * ((float)i / 800.0)) + 1) * 127);
    w_buf[i + 1] = val;
}
VK2BEA commented 2 years ago

No this does not fix the problem. What you have done is to create two in phase sine waves. It does seem that the problem is LESS visible when the data from both DACs is the same but the problem IS still there. My example has two sine waves in quadrature (90 degrees out of phase). The problem is more evident / reproducible there.

L-KAYA commented 2 years ago

Yeah, you're right! Seems the phase shift between the two channels will indeed bring more glitches.

I tested the case on the new driver-NG of DAC (not merged yet), the glitches are still there, but they don't show up on ESP32-S2 under same conditions.

And I checked the sent data as well, at least the data is correct after they are transmitted by DMA, the only possible point that breaks the data should between DMA and DAC converter. Which might be a hardware bug, sadly I'm not sure if there will be a solution for this issue. I'll report the issue to the hardware designer.

VK2BEA commented 2 years ago

Thanks, I was concerned that it may be hardware related. Do you know if it is also OK on the S3 (I need the dual core)? -- edit ... never mind, I see the S3 doesn't have a DAC 8-( Does this mean that the on-board DAC is broken and cannot be used reliably? Are there settings where it doesn't glitch (i.e. can I find a work-around)?

L-KAYA commented 2 years ago

I haven't received any comments from hardware team yet, seems it's an unknown bug, probably no work-around for this. If you only need to generated a sine wave from DAC module, is it possible to use the DAC cosine wave generator?

You can have a try using the patch of the DAC driver-ng preview (based on master)

dac_ng_preview_patch.zip

You can check the dac examples in the patch to learn how to use it.

VK2BEA commented 2 years ago

Alas, no I cannot use the cosine generator. I'm generating low frequency tones of very precise frequencies .. https://en.wikipedia.org/wiki/Continuous_Tone-Coded_Squelch_System#List_of_tones The cosine generator does not have the resolution needed to generate the exact frequencies.

L-KAYA commented 2 years ago

Sounds like DAC DMA is the only solution, may I ask how low the frequency might be? According to my test, PLL can support down to 20KHz converting rate on ESP32, if it's not low enough, the one work-around could be duplicating the data meanwhile double the converting rate.

VK2BEA commented 2 years ago

the lowest is 67 Hz the highest 254 Hz.

L-KAYA commented 2 years ago

the lowest is 67 Hz the highest 254 Hz.

Is this a sine wave frequency or DAC conversion rate of each data?

JoseEnriqueFA commented 2 years ago

As far as I know, I am afraid the only possibility is to use an older version of idf.

I am using Arduino as IDE. With the latest version if .use_apll = 1 the glitches appear. In this version of IDF .use_apll = false, no glitches appear. However with an older version of IDF and .use_apll = 1 these glitches do not appear.

JoseEnriqueFA commented 2 years ago

Additional information if you are not familiar with ESP32 and IDE Aduino

When in Preferences del Arduino IDE you write (This is declared as the latest estable release) https://dl.espressif.com/dl/package_esp32_index.json Then in the Board Manager ESP32 you can load the Board Manager 1.0.6 and later choose your board Then with .use_apll = 1 these glitches do not appear.

In case you need new ESP boards (i.e. ESP32 Adafruit feather V2) then you need to include in preferences Arduino IDE https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json (information you can get i.e. in Adafruit WEB) After that you can use the Board Manager up 2.0.5 in the Arduino IDE Advantage: you can choose as board the Adafruit ESP32 feather V2 Disadvantage: if .use_apll = 1 the glitches appear

To be change in the Sketch with Board Manager 1.0.6
//Configuration for the I2S bus .communication_format = I2S_COMM_FORMAT_I2S_MSB,

with Board Manager 2.0.5 //Configuration for the I2S bus .communication_format = I2S_COMM_FORMAT_STAND_MSB,

Good Luck!

VK2BEA commented 2 years ago

As far as I know, I am afraid the only possibility is to use an older version of idf.

I am using Arduino as IDE. With the latest version if .use_apll = 1 the glitches appear. In this version of IDF .use_apll = false, no glitches appear. However with an older version of IDF and .use_apll = 1 these glitches do not appear.

How old ? (what version works?) This is good news and means that it is not a hardware issue. I'm not using Arduino but straight C (as demonstrated in the example above)

Michael

JoseEnriqueFA commented 2 years ago

Dear Michael,

"How old ? (what version works?)" I cannot give you a precise answer.

I have been working the last two years with the so call IDF stable version (in Preferences) and the Board Manager 1.0.6 (captures attached) Board Adafruit Feather ESP32

Only when about two months ago I realized about the Board Adafruit Feather ESP32 V2 I bought this board for evaluation then I had to upgrade to the Development release and Board Manager 2.0.5

with this upgrade the behavior of my old Board Adafruit Feather ESP32 is not the same when using DMA DAC.

Good luck!

https://dl.espressif.com/dl/package_esp32_index.json

https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#windows-manual-installation

https://learn.adafruit.com/adafruit-esp32-feather-v2/arduino-ide-setup

De: Michael G. Katzmann @.*** Enviado el: sábado, 08 de octubre de 2022 4:12 Para: espressif/esp-idf CC: JoseEnriqueFA; Comment Asunto: Re: [espressif/esp-idf] Internal DAC glitches using I2S ".use_apll = true" (IDFGH-7784) (Issue #9321)

As far as I know, I am afraid the only possibility is to use an older version of idf.

I am using Arduino as IDE. With the latest version if .use_apll = 1 the glitches appear. In this version of IDF .use_apll = false, no glitches appear. However with an older version of IDF and .use_apll = 1 these glitches do not appear.

How old ? (what version works?) This is good news and means that it is not a hardware issue. I'm not using Arduino but straight C (as demonstrated in the example above)

Michael

— Reply to this email directly, view it on GitHub https://github.com/espressif/esp-idf/issues/9321#issuecomment-1272197615 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AML3OVAEM7QSTLBKEDCFQJTWCDJ6VANCNFSM53DUPZDA . You are receiving this because you commented. https://github.com/notifications/beacon/AML3OVCETNKRONNFYIASRKDWCDJ6VA5CNFSM53DUPZDKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOJPKDD3Y.gif Message ID: @.***>

JoseEnriqueFA commented 1 year ago

I have found this URL https://github.com/espressif/arduino-esp32/releases?page=1 ** where you can read "[ESP32 Arduino Release 1.0.6 based on ESP-IDF v3.3.5] (https://github.com/espressif/arduino-esp32/releases/tag/1.0.6)"

When I use the "Release 1.0.6" in Arduino IDE I can use_"apll = 1" glitches free

Best whishes José

**PD : Only FYI, I was looking for information in the WEB. In the latest version ESP32 Arduino 2.0.5 based on ESP-IDF 4.4.2 I have identified two problems, I am investigating ...

JoseEnriqueFA commented 1 year ago

HI,

I have found this URL https://github.com/espressif/arduino-esp32/releases?page=1 **

where you can read " https://github.com/espressif/arduino-esp32/releases/tag/1.0.6 ESP32 Arduino Release 1.0.6 based on ESP-IDF v3.3.5"

When I use the "Release 1.0.6" in Arduino IDE I can use_"apll = 1" glitches free

Best whishes

José

**PD : Only FYI, I was looking for information in the WEB.

          In the latest version   ESP32 Arduino 2.0.5 based on ESP-IDF 4.4.2

          I have identified two problems, I am investigating ...

De: Michael G. Katzmann @.*** Enviado el: sábado, 08 de octubre de 2022 4:12 Para: espressif/esp-idf CC: JoseEnriqueFA; Comment Asunto: Re: [espressif/esp-idf] Internal DAC glitches using I2S ".use_apll = true" (IDFGH-7784) (Issue #9321)

As far as I know, I am afraid the only possibility is to use an older version of idf.

I am using Arduino as IDE. With the latest version if .use_apll = 1 the glitches appear. In this version of IDF .use_apll = false, no glitches appear. However with an older version of IDF and .use_apll = 1 these glitches do not appear.

How old ? (what version works?) This is good news and means that it is not a hardware issue. I'm not using Arduino but straight C (as demonstrated in the example above)

Michael

— Reply to this email directly, view it on GitHub https://github.com/espressif/esp-idf/issues/9321#issuecomment-1272197615 , or unsubscribe https://github.com/notifications/unsubscribe-auth/AML3OVAEM7QSTLBKEDCFQJTWCDJ6VANCNFSM53DUPZDA . You are receiving this because you commented. https://github.com/notifications/beacon/AML3OVCETNKRONNFYIASRKDWCDJ6VA5CNFSM53DUPZDKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOJPKDD3Y.gif Message ID: @.***>

joshwwest commented 1 year ago

I am having a similar issue, where the I2S/DAC is now generating very noisy audio. I use the I2S to feed 8bit 22050Hz data to the DAC. On IDF version 4.2.2 this worked fine, but in 4.4.3 the sound quality is very bad. This would seem to indicate it is not a hardware issue, or if it is, some configuration in the IDF must have made it worse. Has any progress been made to identify the problem and come up with some work-arounds?

FedericoBusero commented 1 year ago

When it has changed in a certain IDF version, you need to check that all parameters are being initialised correctly:

As an example of code that works, have a look at https://raw.githubusercontent.com/earlephilhower/ESP8266Audio/master/src/AudioOutputI2S.cpp more specifically, following lines of code are relevant

      if (output_mode == INTERNAL_DAC)
      {
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
        comm_fmt = (i2s_comm_format_t) I2S_COMM_FORMAT_STAND_MSB;
#else
        comm_fmt = (i2s_comm_format_t) I2S_COMM_FORMAT_I2S_MSB;
#endif
      }

....

      i2s_config_t i2s_config_dac = {
          .mode = mode,
          .sample_rate = 44100,
          .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
          .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
          .communication_format = comm_fmt,
          .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // lowest interrupt priority
          .dma_buf_count = dma_buf_count,
          .dma_buf_len = 128,
          .use_apll = use_apll, // Use audio PLL
          .tx_desc_auto_clear = true, // Silence on underflow
          .fixed_mclk = use_mclk, // Unused
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
          .mclk_multiple = I2S_MCLK_MULTIPLE_256, // Unused
          .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample
#endif
      };