乐鑫技术交流
直播中

张鑫

8年用户 1131经验值
私信 关注
[问答]

为什么我的ADC通道在通过I2S读取时会加倍或跳过通道呢?

我正在尝试使用 I2S 直接来自 ADC 的功能,以立体声方式运行。我正在使用在 Ubuntu 18.04 上开发的 Wemos Lolin D32,它使用 ESP32-WROOM-32。
我的 IDF 版本是 v3.3-beta2,但它需要对 IDF 进行一些修改才能公开必要的功能(我也通过直接操作寄存器尝试过);我将在下面详细说明。
我的问题是,无论我做什么,我都会看到 ADC 数据加倍或跳过通道。我有从 I2S 读取的 ADC 数据中提取通道的代码,如下所示:
代码:
static void show_some_data(uint16_t * data)
{
    const unsigned rows = 8;
    for (unsigned row = 0; row < rows; row++)
    {
        ESP_LOGI(
            TAG,
            "CH: %d %d %d %d %d %d %d %d",
            (data[8*row + 0] & 0xF000) >> 12,
            (data[8*row + 1] & 0xF000) >> 12,
            (data[8*row + 2] & 0xF000) >> 12,
            (data[8*row + 3] & 0xF000) >> 12,
            (data[8*row + 4] & 0xF000) >> 12,
            (data[8*row + 5] & 0xF000) >> 12,
            (data[8*row + 6] & 0xF000) >> 12,
            (data[8*row + 7] & 0xF000) >> 12
        );
    }
}
我在串行日志中看到的结果是:
代码:
I (324) I2S: PLL_D2: Req RATE: 24000, real rate: 1515.000, BITS: 16, CLKM: 55, BCK: 60, MCLK: 55.556, SCLK: 48480.000000, diva: 64, divb: 35
I (334) i2s-test: CH: 6 6 6 6 6 6 0 0
I (334) i2s-test: CH: 0 0 0 0 0 0 0 0
I (344) i2s-test: CH: 0 0 0 0 0 0 0 0
I (344) i2s-test: CH: 0 0 0 0 0 0 0 0
I (354) i2s-test: CH: 0 0 0 0 0 0 0 0
I (354) i2s-test: CH: 0 0 0 0 0 0 0 0
I (364) i2s-test: CH: 0 0 0 0 0 0 0 0
I (364) i2s-test: CH: 0 0 0 0 0 0 0 0
I (364) i2s-test: CH: 5 5 6 6 5 5 6 6
I (374) i2s-test: CH: 5 5 6 6 5 5 6 6
I (374) i2s-test: CH: 5 5 6 6 5 5 6 6
I (384) i2s-test: CH: 5 5 6 6 5 5 6 6
I (384) i2s-test: CH: 5 5 6 6 5 5 6 6
I (394) i2s-test: CH: 5 5 6 6 5 5 6 6
I (394) i2s-test: CH: 5 5 6 6 5 5 6 6
I (394) i2s-test: CH: 5 5 6 6 5 5 6 6
I (404) i2s-test: CH: 6 6 5 5 6 6 5 5
配置相当简单:
代码:
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
        .sample_rate =  SAMPLE_RATE, // 24kHz
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .communication_format = I2S_COMM_FORMAT_I2S,
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 2,
        .dma_buf_len = NUM_SAMPLES, // 64
        .use_apll = 0,
        .fixed_mclk = 0
    };
   
    i2s_driver_install(i2s_num, &i2s_config, 4, i2s_queue);
    i2s_set_clk(i2s_num, SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_STEREO);
    i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_6);

    adc_set_i2s_data_pattern(ADC_UNIT_1, 0, ADC_CHANNEL_6, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11);
    adc_set_i2s_data_pattern(ADC_UNIT_1, 1, ADC_CHANNEL_5, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11);
    adc_set_i2s_data_len(ADC_UNIT_1, 2);
正如我提到的,我必须对 IDF 进行一些更改才能使用 ADC 模式表:公开函数 adc_set_i2s_data_len() 和 adc_set_i2s_data_pattern() 并注释掉 i2s_adc_enable() 中的 _i2s_adc_mode_recover() 调用。生成的代码在 我的 fork 中可用。
它可以通过检查并执行“idf.py build”来构建。
我完全无法弄清楚出了什么问题。我检查了我的代码和 IDF 库以确保正确设置了寄存器。我已经从头到尾阅读了技术参考手册。我已经尝试过使用和不使用队列,使用和不使用 DMA 清除。我已经使用示波器来验证 WS 信号确实以 24kHz 的频率运行(尽管这不应该影响通道顺序)。
即使只是让其他人尝试我的示例项目并告诉我他们是否在他们的硬件上看到相同的东西,这对我来说也是一个巨大的帮助。但是,如果您看到我在这里犯的一个错误,或者对更多调试有任何想法,请告诉我。


回帖(1)

李阳

2023-3-1 17:11:30
你可以试试...
代码:
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT

#include
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_spi_flash.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_partition.h"
#include "driver/i2s.h"
#include "driver/adc.h"
#include "driver/gpio.h"
#include "esp_adc_cal.h"
#include "esp_rom_sys.h"
#include

static const char* TAG = "adc";

//i2s number
#define EXAMPLE_I2S_NUM           (0)
//i2s sample rate
#define EXAMPLE_I2S_SAMPLE_RATE   (17000)
//i2s data bits
#define EXAMPLE_I2S_SAMPLE_BITS   (16)
//I2S read buffer length
#define EXAMPLE_I2S_READ_LEN      (1700 * 4)
//I2S built-in ADC unit
#define I2S_ADC_UNIT              ADC_UNIT_1


void example_i2s_init(void)
{
      

        i2s_config_t i2s_config = {
                .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
                // I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN
                 .sample_rate = EXAMPLE_I2S_SAMPLE_RATE * 2,
                .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS,
                .communication_format = I2S_COMM_FORMAT_STAND_MSB,
                .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
                .intr_alloc_flags = 0,
                .dma_buf_count = 4,
                .dma_buf_len = 1024,
                .use_apll = true,
        };
        //install and start i2s driver
        i2s_driver_install(EXAMPLE_I2S_NUM, &i2s_config, 0, NULL);
        ESP_ERROR_CHECK(i2s_set_adc_mode(I2S_ADC_UNIT, ADC1_CHANNEL_6));
        ESP_ERROR_CHECK(i2s_set_adc_mode(I2S_ADC_UNIT, ADC1_CHANNEL_7));
      
        SYSCON.saradc_ctrl2.max_meas_num = 255;
        SYSCON.saradc_ctrl2.meas_num_limit = 1;


}
void example_i2s_adc_dac(void)
{
        size_t bytes_read; //, bytes_written;
        //I2S_EVENT_RX_Q_OVF
        char* i2s_read_buff = (char*) calloc(EXAMPLE_I2S_READ_LEN, sizeof(char));
        //i2s_event_t evt;
        while (1)
        {
                vTaskDelay(100);
               
                ESP_LOGI(TAG, "Starting");
               
                i2s_adc_enable(EXAMPLE_I2S_NUM);
               
                // Overwrite oattern register to get 2 channels scanning
                SYSCON.saradc_sar1_patt_tab[0] = 0x07F6F0F0F;
                SYSCON.saradc_ctrl.sar1_patt_len = 1;

                //rstb_wait: 8 sample_cycle: 2 standby_wait: 100 start_wait: 16
                //ESP_LOGI(TAG, " rstb_wait: %u sample_cycle: %u standby_wait: %u start_wait: %u", SYSCON.saradc_fsm.rstb_wait, SYSCON.saradc_fsm.sample_cycle, SYSCON.saradc_fsm.standby_wait, SYSCON.saradc_fsm.start_wait);
               
                //read data from I2S bus, in this case, from ADC.
                i2s_read(EXAMPLE_I2S_NUM, (void*) i2s_read_buff, EXAMPLE_I2S_READ_LEN, &bytes_read, portMAX_DELAY);

                ESP_LOGI(TAG, "Stopping");

                i2s_adc_disable(EXAMPLE_I2S_NUM);

                vTaskDelay(100);

                for (size_t i = 0; i < EXAMPLE_I2S_READ_LEN; i += 2)
                {
                        ESP_LOGI(TAG, " %1x  %u", ((i2s_read_buff[i + 1] & 0xf0) >> 4), (i2s_read_buff | ((i2s_read_buff[i + 1] & 0x0f) << 8)));
                }
        }
}

esp_err_t app_main(void)
{
                example_i2s_init();
    esp_log_level_set("I2S", ESP_LOG_INFO);
                example_i2s_adc_dac();

    return ESP_OK;
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分