espressif / esp-idf

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

ESP32 I2S ADC only returns 0s when use_apll = true (IDFGH-4228) #6086

Open oliverjrose99 opened 4 years ago

oliverjrose99 commented 4 years ago

Environment

Problem Description

When use_apll = true in the i2s config, i2s_read() only returns 0s. When use_apll = false, the returned data is correct but the rate (as reported by the serial monitor) is not. I am trying to sample a 3.5mm audio jack (with the correct circuit) so a sample rate of 44.1kH is required.

Note: sample rate requested is double as the real rate reported is half, this code is not mine and is mostly taken from phonec

My guess to fix this is that the apll clock need to be routed to the ADC by setting a register but but i cant find anything and dont know if that is correct. Please help, ive spent so long on this.

Code to reproduce this issue

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "driver/i2s.h"
#include "driver/adc.h"
#include "soc/syscon_reg.h"
#include "esp_log.h"
#include "esp_event.h"

static QueueHandle_t i2s_event_queue;

void app_main()
{
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
        .sample_rate = 44100 * 2,
        .bits_per_sample = 16,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 2,
        .dma_buf_len = 1024,
        .use_apll = 1,
    };

    i2s_driver_install(I2S_NUM_0, &i2s_config, 1, &i2s_event_queue);
    i2s_set_adc_mode(I2S_NUM_0, ADC1_CHANNEL_0);

    SET_PERI_REG_BITS(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR1_PATT_LEN, 1, SYSCON_SARADC_SAR1_PATT_LEN_S);
    WRITE_PERI_REG(SYSCON_SARADC_SAR1_PATT_TAB1_REG, 0b00001111000011110000111100001111);
    SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);

    vTaskDelay(5000/portTICK_RATE_MS);

    i2s_adc_enable(I2S_NUM_0);

    int i2s_read_len = 1024 * 2;
    uint16_t* i2s_read_buff = (uint16_t*) calloc(2048, sizeof(uint16_t));
    size_t bytes_read;

    while(1) {
        system_event_t evt;
        if (xQueueReceive(i2s_event_queue, &evt, portMAX_DELAY) == pdPASS) {
            if (evt.event_id==2) {
                i2s_read(I2S_NUM_0, (void*)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);
                ESP_LOG_BUFFER_HEX("i2s_read_buff", i2s_read_buff, 16);
            }
        }
    }
}

Debug Logs

I havent included all of the boot log, i can add it if needed.

use_apll = true

I (334) I2S: queue free spaces: 1
I (334) I2S: DMA Malloc info, datalen=blocksize=2048, dma_buf_count=2
I (364) I2S: APLL: Req RATE: 88200, real rate: 44099.988, BITS: 16, CLKM: 1, BCK_M: 8, MCLK: 11289597.000, SCLK: 1411199.625000, diva: 1, divb: 0
I (5374) I2S: APLL: Req RATE: 88200, real rate: 44099.988, BITS: 16, CLKM: 1, BCK_M: 8, MCLK: 11289597.000, SCLK: 1411199.625000, diva: 1, divb: 0
I (5374) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I (5384) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I (5394) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I (5394) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I (5404) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I (5414) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I (5424) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I (5424) i2s_read_buff: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

use_apll = false

I (334) I2S: queue free spaces: 1
I (334) I2S: DMA Malloc info, datalen=blocksize=2048, dma_buf_count=2
I (344) I2S: PLL_D2: Req RATE: 88200, real rate: 5555.000, BITS: 16, CLKM: 15, BCK: 60, MCLK: 15.117, SCLK: 177760.000000, diva: 64, divb: 7
I (5354) I2S: PLL_D2: Req RATE: 88200, real rate: 5555.000, BITS: 16, CLKM: 15, BCK: 60, MCLK: 15.117, SCLK: 177760.000000, diva: 64, divb: 7
I (5354) i2s_read_buff: ff 0f ff 0f ff 0f ff 0f ff 0f ff 0f ff 0f ff 0f
I (5364) i2s_read_buff: 06 07 08 07 0d 07 06 07 07 07 09 07 07 07 07 07
I (5374) i2s_read_buff: 07 07 04 07 06 07 07 07 07 07 09 07 0b 07 10 07
I (5384) i2s_read_buff: 05 07 07 07 0a 07 10 07 0d 07 06 07 0a 07 09 07
I (5394) i2s_read_buff: 09 07 06 07 09 07 05 07 0f 07 07 07 0b 07 0b 07
I (5414) i2s_read_buff: 07 07 09 07 09 07 07 07 0e 07 0b 07 0e 07 0a 07
I (5424) i2s_read_buff: 09 07 07 07 09 07 05 07 0b 07 0b 07 0d 07 0a 07
I (5434) i2s_read_buff: 07 07 09 07 09 07 07 07 10 07 09 07 0b 07 09 07
I (5444) i2s_read_buff: 07 07 07 07 08 07 07 07 0b 07 0c 07 0a 07 0b 07
I (5454) i2s_read_buff: 09 07 06 07 06 07 08 07 0e 07 0a 07 0b 07 10 07
I (5464) i2s_read_buff: 05 07 09 07 07 07 05 07 0d 07 05 07 0b 07 0c 07
I (5484) i2s_read_buff: 09 07 06 07 07 07 07 07 10 07 0a 07 0a 07 0f 07
oliverjrose99 commented 4 years ago

I have fixed my issue and possibly revealed a bug. powering down the apll / plla before all of the config functions and then powering it up seems to have fixed it.

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "driver/i2s.h"
#include "driver/adc.h"
#include "soc/i2s_reg.h"
#include "soc/syscon_reg.h"
#include "soc/syscon_struct.h"
#include "soc/sens_reg.h"
#include "soc/sens_periph.h"
#include "soc/sens_struct.h"
#include "esp_log.h"

#define SAMPLES 1024
#define SAMPLING_FREQ 44100

static const char* TAG = "MAIN";

void init_i2s_adc()
{
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
        .sample_rate = 44100,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
        .intr_alloc_flags = 0,
        .dma_buf_count = 2,
        .dma_buf_len = 1024,
        .use_apll = 1,
    };

    // powerdown APLL/PLLA
    SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD_M);
    CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU_M);

    // config adc atten and width
    adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_11db);
    adc1_config_width(ADC_WIDTH_12Bit);

    // set pattern tbl and invert, might not need, double check
    SYSCON.saradc_ctrl.sar1_patt_len = 1;
    SYSCON.saradc_sar1_patt_tab[0] = 0b00001111000011110000111100001111;
    SYSCON.saradc_ctrl2.sar1_inv = 1;

    //install and start i2s driver
    i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
    i2s_set_adc_mode(I2S_NUM_0, ADC1_CHANNEL_0);

    // delay and enable
    vTaskDelay(3000 / portTICK_RATE_MS);
    i2s_adc_enable(I2S_NUM_0);

    // powerup APLL/PLLA
    SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU_M);
    CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD_M);
}

void app_main()
{
    init_i2s_adc();

    int read_len = 1024 * 2;
    uint16_t* read_buff = (uint16_t*) calloc(read_len, sizeof(uint16_t));
    size_t bytes_read;

    while(1) {
        i2s_read(I2S_NUM_0, (void*) read_buff, read_len, &bytes_read, portMAX_DELAY);

        for (int i = 0; i < 64; i++) {
            printf("%hu ", read_buff[i]);
            if (i % 8 == 0) printf("\n");
        }

    }
}
varioscientist commented 11 months ago

I had same issue, with output to another i2s channel: apll does produce zeros values. This is fixed by install sar adr driver last over initializing i2s out (first). This work well without patch above (but, i'm think that is helpfull too). Keep in mind, that sar i2c input will come with first values of dma vector filled with acdual adc values, then last will be a noised values. Another words, in 1024 values single channel adc will produce [0..511] adc values and [512..1023] some randoms, so for listening it needs "interlace" with normal stereo i2s values.

I'm think that is very serious issue because with no apll adc produce some audible aliasing artifacts.

-- V.V.