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

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

Open
VK2BEA opened this issue Jul 9, 2022 · 21 comments
Open

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

VK2BEA opened this issue Jul 9, 2022 · 21 comments
Assignees
Labels
Status: Opened Issue is new

Comments

@VK2BEA
Copy link

VK2BEA commented Jul 9, 2022

Environment

  • Development Kit: ESP32-Wrover-Kit
  • Kit version : ESP32-D0WDQ6 (revision 1)
  • Module or chip used: ESP32-WROOM-32
  • IDF version: v4.4.1
  • Build System: CMake
  • Compiler version : 8.4.0
  • Operating System: Linux
  • Using an IDE?: Yes, Eclipse
  • Power Supply: USB

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

@espressif-bot espressif-bot added the Status: Opened Issue is new label Jul 9, 2022
@github-actions github-actions bot changed the title Internal DAC glitches using I2C ".use_apll = true" Internal DAC glitches using I2C ".use_apll = true" (IDFGH-7784) Jul 9, 2022
@suda-morris suda-morris changed the title Internal DAC glitches using I2C ".use_apll = true" (IDFGH-7784) Internal DAC glitches using I2S ".use_apll = true" (IDFGH-7784) Jul 11, 2022
@VK2BEA
Copy link
Author

VK2BEA commented Aug 25, 2022

Is anything happening on this problem?

@L-KAYA
Copy link
Collaborator

L-KAYA commented Aug 26, 2022

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

@L-KAYA
Copy link
Collaborator

L-KAYA commented Aug 26, 2022

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
Copy link
Author

VK2BEA commented Aug 28, 2022

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

@L-KAYA
Copy link
Collaborator

L-KAYA commented Aug 29, 2022

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;
}

@espressif-bot espressif-bot added the Awaiting Response awaiting a response from the author label Aug 29, 2022
@VK2BEA
Copy link
Author

VK2BEA commented Aug 31, 2022

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.

@Alvin1Zhang Alvin1Zhang removed the Awaiting Response awaiting a response from the author label Sep 1, 2022
@L-KAYA
Copy link
Collaborator

L-KAYA commented Sep 1, 2022

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
Copy link
Author

VK2BEA commented Sep 1, 2022

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
Copy link
Collaborator

L-KAYA commented Sep 2, 2022

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
Copy link
Author

VK2BEA commented Sep 2, 2022

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
Copy link
Collaborator

L-KAYA commented Sep 5, 2022

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
Copy link
Author

VK2BEA commented Sep 6, 2022

the lowest is 67 Hz the highest 254 Hz.

@L-KAYA
Copy link
Collaborator

L-KAYA commented Sep 7, 2022

the lowest is 67 Hz the highest 254 Hz.

Is this a sine wave frequency or DAC conversion rate of each data?
- If it is the sine wave rate, I think we can generate more sampling point for a sine wave, like 300 points in a 67Hz sine wave, which requires a 20100Hz conversion rate. Then we can use PLL.
- If it is the DAC conversion rate, as it's a relative low rate, instead of using DAC DMA, we can set the DAC voltage directly in a timer interrupt. In this case, you need a gptimer to generate the interrupt at your specific frequency.

@JoseEnriqueFA
Copy link

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
Copy link

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
Copy link
Author

VK2BEA commented Oct 8, 2022

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
Copy link

JoseEnriqueFA commented Oct 8, 2022 via email

@JoseEnriqueFA
Copy link

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
Copy link

JoseEnriqueFA commented Oct 26, 2022 via email

@joshwwest
Copy link

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
Copy link

FedericoBusero commented Apr 3, 2023

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

  • .communication_format
    changed in 4.2.0
  • .mclk_multiple
    changed in 4.4.0
  • .bits_per_chan
    changed in 4.4.0

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
      };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Opened Issue is new
Projects
None yet
Development

No branches or pull requests

7 participants