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

Faulty clock output in I2S PDM TX DAC mode on ESP32-S3 (IDFGH-9010) #10420

Closed
thebender7 opened this issue Dec 21, 2022 · 7 comments
Closed

Faulty clock output in I2S PDM TX DAC mode on ESP32-S3 (IDFGH-9010) #10420

thebender7 opened this issue Dec 21, 2022 · 7 comments
Assignees
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally

Comments

@thebender7
Copy link

Hello Team,

i am having troubles operating the I2S0 in PDM TX DAC Stereo Mode at high sample rates (>75kHz) on a ESP32-S3.

First there is a little bug in the driver file i2s_pdm.c (ln 38):
clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * pdm_tx_clk->up_sample_fp / pdm_tx_clk->up_sample_fs;
this expression leads to an overflow for large sampling rates as bckl is only 32bit. This can be easily overcome by adding brackets:
clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * (pdm_tx_clk->up_sample_fp / pdm_tx_clk->up_sample_fs);

Furthermore for achieving high sample rates also the default value for the bitclock divider needs to be reduced(ln 39):
clk_info->bclk_div = 4;
Target sample rate is 156250 Hz which should be met with a mclk divider of 2.
When doing so however i get a faulty clock manifesting in interruptions of the clock at the period of the sample rate such that the last 10% of the sample time the clock signal drops to zero and begins again with the next sample.
It seems that for bckl_div < 8 the bit clock is not working properly. In the technical reference manual i could not find any restrictions for bclk_div for PDM TX applications. Is this expected behaviour?

Another way of reaching 156250 Hz while keeping bclk_div = 8 seems to set the oversampling ratio to 64 e.g. OSR2 = 1.
When doing so by setting in i2s_pdm.h f_p = f_s such that OSR2 = f_p / f_s =1 i get no clock output at all, only glitches at the rate of the sample rate. From documentation the actual meaning of f_p and f_s and their connection to the sample rate stay quite unclear to me. Is an OSR2 of 1 not forseen or am i missing something?

Thank you everybody for any hints to understand the behaviour.
Best,
Helmar

@espressif-bot espressif-bot added the Status: Opened Issue is new label Dec 21, 2022
@github-actions github-actions bot changed the title Faulty clock output in I2S PDM TX DAC mode on ESP32-S3 Faulty clock output in I2S PDM TX DAC mode on ESP32-S3 (IDFGH-9010) Dec 21, 2022
@L-KAYA
Copy link
Collaborator

L-KAYA commented Dec 22, 2022

Hi @thebender7 , many thanks for your bug report!

  • For the bclk calculation, it's indeed a careless bug, we will fix it soon
  • As for the limitation of bclk_div, it's a limitation of hardware, not only PDM, but also other modes have some requirements to the bclk_div. For PDM mode, 8 should be the most appropriate value that can make the clock work correctly meanwhile ensuring the supported sampling frequency as higher as possible.
  • And the fp, fs you asked, they determines the Over Sampling Multiple, which equals to (fp / fs) * 64, but actually the Over Sampling Multiple can only be 64 or 128, therefore, the default configuration fp=960, fs=480 is recommended, that is to say, the sample rate is fs * 100 = 48K, and the highest Over Sampling Rate is 128 * 48K.

To sum up, PDM TX can only support up to 48K sample rate. Sorry for the lack of documents, we will update it as well.

@thebender7
Copy link
Author

Hi @L-KAYA thank's a lot for your answer!

i wonder what are the correct settings in order to get an oversampling of 64? I tried different values for fp = fs but even for sampling rates < 48kHz i was not able to get a clock.
On the other hand i achieved a sample rate of 78,125 kHz (mckl_div = 2, bckl_div = 8) with 128 oversampling (fp=960, fs=480).
if i change the values of fp and fs, this seems to have no effect as long as i keep the ratio fp/fs = 2. I was hoping that if i could manage to reduce the osr to 64 in this configuration the sample rate should be doubled and thus fullfill my needs.
The fs * 100 = 48K statement confuses me. The sample rate is fs = f_bckl * oversampling ratio (= 64 or 128) so how could both statements be true at all times? But even then, could the max sampling rate not be doubled by setting fs = 960 ?

Many thanks for your help!

@L-KAYA
Copy link
Collaborator

L-KAYA commented Dec 26, 2022

Hi @thebender7 ,

  • Currently OSR2 is set to fp / fs in lower layer, but seems it better to be able to config separately regardless fp and fs. For now, if you only want to set the an oversampling of 64, you may have to operate the register directly, like:
    #include "hal/i2s_ll.h"
    ......
    // Set the OSR2 to 1 additionally after 'i2s_channel_init_pdm_tx_mode' and before 'i2s_channel_enable'
    I2S0.tx_pcm2pdm_conf.tx_sinc_osr2 = 1;
  • 48KHz is the frequency that I get from my digital colleague, seems it's not a definite limitation. I guess the audio that adopts the sample_rate that exceed 48kHz might have more glitches or noise.
  • fs reflects the actual audio sample rate, but as it's a waste to store the whole value in the reg, it is divided 100 to save bits. And the output clock, which equals to sample_rate * oversampling ratio is the frequency of PDM sampling clock.
  • Another thing is that, if you are using DAC mode, normally the clock line is not required, it only requires a low-pass filter between data line and the amplifier. You can refer to the note that in pdm-tx-usage section.

Thank you for your question, please let me know if there are still something not clear.

@espressif-bot espressif-bot added Status: Reviewing Issue is being reviewed and removed Status: Opened Issue is new labels Dec 26, 2022
@thebender7
Copy link
Author

Hi @L-KAYA,

thank you for the clarifications!

I tried to set the osr2 = 1 directly as you suggested (while keeping fp = 960, fs = 480), however the setting has no effect on the sample rate e.g. the oversampling is still 128.
If i set fp = fs = 480 (the configuration with a faulty output) i can make it work again by directly setting osr2 = 2 so the register write is working obviously.

From my experience so far, as long as fp/fs = 2 the sample rate is not connected to fs but is sample_rate = bckl / 128.
For any other ratio of the two i could net get a valid output, also not if i set fs to the required sample_rate / 100.

Sorry for not mentioning this before but not only the clock output is faulty but also the data output shows the same corruption.

Thank you!

@L-KAYA
Copy link
Collaborator

L-KAYA commented Dec 29, 2022

May I ask what's your expected clock frequency and data wave?
And could you offer your I2S initialization code if possible?
Thanks!

@espressif-bot espressif-bot added Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Resolution: Done Issue is done internally and removed Status: Reviewing Issue is being reviewed Resolution: NA Issue resolution is unavailable labels Dec 30, 2022
@thebender7
Copy link
Author

thebender7 commented Dec 31, 2022

Hi @L-KAYA ,

our application uses ultrasonic, sine shaped pulses in the frequency range 20 - 70 kHz. We therefore aim at a sample rate of 156250 Hz. For an oversampling ratio of 128 however due to the limitation that bckl_div >= 8 the maximum possible sample rate is 156250 / 2 for bckl_div = 8. The bckl_freq is than 160MHz/2/8 = 10 MHz and sample rate = 10 MHz / 128. If for these clock settings the oversampling could be reduced to 64 than we would end up at the required sample rate.

The initialization code is taken from the I2S_PDM_TX example of IDE 5.0 but slightly adapted in order to get a 2 line dac signal on two seperate gpios:

#define EXAMPLE_PDM_TX_CLK_IO           GPIO_NUM_39      // I2S PDM TX clock io number
#define EXAMPLE_PDM_TX_DOUT_IO          GPIO_NUM_40      // I2S PDM TX data out io number
#define EXAMPLE_PDM_TX_DOUT2_IO          GPIO_NUM_41      // I2S PDM TX data out 2 io number

#define EXAMPLE_PDM_TX_FREQ_HZ          (156250 / 2)        // I2S PDM TX frequency
#define SOC_I2S_SUPPORTS_PDM_TX         1
#define SOC_I2S_HW_VERSION_2            1


static TaskHandle_t s_task_handle;
static const char *TAG = "EXAMPLE";

static i2s_chan_handle_t i2s_example_init_pdm_tx(void)
{
    i2s_chan_handle_t tx_chan;        // I2S tx channel handler
    /* Setp 1: Determine the I2S channel configuration and allocate TX channel only
     * The default configuration can be generated by the helper macro,
     * it only requires the I2S controller id and I2S role,
     * but note that PDM channel can only be registered on I2S_NUM_0 */
    i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
    tx_chan_cfg.auto_clear = true;
    ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_chan, NULL));

    /* Step 2: Setting the configurations of PDM TX mode and initialize the TX channel
     * The slot configuration and clock configuration can be generated by the macros
     * These two helper macros is defined in 'i2s_pdm.h' which can only be used in PDM TX mode.
     * They can help to specify the slot and clock configurations for initialization or re-configuring */
    i2s_pdm_tx_config_t pdm_tx_cfg = {
        .clk_cfg = I2S_PDM_TX_CLK_DEFAULT_CONFIG(EXAMPLE_PDM_TX_FREQ_HZ),
        //.clk_cfg.clk_src = 2,//I2S_CLK_SRC_PLL_160M,
        /* The data bit-width of PDM mode is fixed to 16 */
        .slot_cfg = I2S_PDM_TX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
        .slot_cfg.line_mode = I2S_PDM_TX_TWO_LINE_DAC,
        .gpio_cfg = {
            .clk = EXAMPLE_PDM_TX_CLK_IO,
            .dout = EXAMPLE_PDM_TX_DOUT_IO,
            .dout2 = EXAMPLE_PDM_TX_DOUT2_IO,
            .invert_flags = {
                .clk_inv = false,
            },
        },
    };
    ESP_ERROR_CHECK(i2s_channel_init_pdm_tx_mode(tx_chan, &pdm_tx_cfg));

    //I2S0.tx_pcm2pdm_conf.tx_sinc_osr2 = 1;
    
    /* Step 3: Enable the tx channel before writing data */
    ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));

    return tx_chan;
}

@L-KAYA
Copy link
Collaborator

L-KAYA commented Jan 3, 2023

I see, so you want to generate a 20 - 70 kHz sine wave by PDM right? According to my test, it's not possible to reach 70kHz, the maximum frequency of the sine wave is near 30kHz. If you only need to generate a sine wave likewise, there are several other ways you can have a try:

  1. Use LEDC or MCPWM peripheral to generate a square wave with 50% duty, and then filter the square wave with an external filter;
  2. Use sigma-delta modulation to output the wave (refer to the sdm example), it's the most similar way comparing to PDM, but limited by its division factor, it can only support the frequency low to 80MHz / 256 / 4 = 78.125 kHz

espressif-bot pushed a commit that referenced this issue Mar 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally
Projects
None yet
Development

No branches or pull requests

3 participants