×Закрыть

Проблема з I2S ADC на ESP32

Доброго дня!
Спроба зняття сигналу з АЦП через інтерфейс I2S зазнала невдачі.
Cхоже я не отримую бажану частоту дискретизації (10000 Гц)

 // Initialization of I2S buffer
	uint16_t* i2sReadBuffer = (uint16_t*)calloc(DMA_BUFFER_LEN, sizeof(uint16_t));
	size_t bytesRead;

	while (1) {

		// Read data in the buffer till its not full
		i2s_read(ADC_I2S_NUM, (void*)i2sReadBuffer, DMA_BUFFER_LEN * sizeof(uint16_t), &bytesRead, portMAX_DELAY);

		for (size_t i = 0; i < DMA_BUFFER_LEN; i++) {
			uint16_t value = i2sReadBuffer[i];
            printf("%d\n", value);
		}
	}

Сигнал через UART я отримав і відфільтрував.
Але фільтр адекватно працює тільки з коефіцієнтами, що були задані для частоти дискретизації 1кГц.

Посилання на результат

MatLab код для обробки сигналу:

xlsFile = 'ecg_data.xlsx';

[num, txt, raw] = xlsread(xlsFile);

input = cell2mat(raw);

a = fir1(100, [0.06 0.14], 'stop'); % BandStop фільтр

in = input(:, 2);

filtered = filter(a, 1, in);

y = fft(filtered);

N = length(y);                   % Довжина вектора

f = (0:N - 1 ) * 100 / N;        % Частотний вектор

m = abs(y);                      % Амплітуда
% y(m<1e-6) = 0;
p = unwrap(angle(y));            % Фаза

X_vector = (1:3:N) / ((N - 1) * 1e-3);

title('Частотний аналіз')

subplot(2,2,1)
plot(f,m)
title('АЧХ')
ax = gca;
ax.XTick = X_vector;

subplot(2,2,2)
plot(f,p*180/pi)
title('ФЧХ')
ax = gca;
ax.XTick = X_vector;

subplot(2,2,3)
plot(in)
title('Вхідний сигнал')
xlabel('msec')
ax = gca;

subplot(2,2,4)
plot(filtered)
title('Відфільтрований сигнал')
ax = gca;

Конфігурація I2S

#define SAMPLING_FREQ 10000
#define ADC_CHANNEL ADC1_CHANNEL_4
#define ADC_UNIT ADC_UNIT_1
#define DMA_BUFFER_LEN 1024
#define ADC_I2S_NUM I2S_NUM_0

static void init_i2s_adc(void) {
    i2s_config_t i2s_config = 
    {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
        .sample_rate = SAMPLING_FREQ,                                            
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,                            
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,                              
        .communication_format = I2S_COMM_FORMAT_STAND_MSB, 
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,                                                 
        .dma_buf_count = 8,                                                    
        .dma_buf_len = DMA_BUFFER_LEN,
        .tx_desc_auto_clear = 1,                                            
        .use_apll = 0,                                                       
    };
    adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN_11db);
    adc1_config_width(ADC_WIDTH_12Bit);
    i2s_driver_install(ADC_I2S_NUM, &i2s_config, 0, NULL);

    i2s_set_clk(ADC_I2S_NUM, SAMPLING_FREQ, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
    i2s_set_adc_mode(ADC_UNIT, ADC_CHANNEL);
    i2s_adc_enable(ADC_I2S_NUM);
}

Чи не означає це те що реально частота дискретизації 1кГц?
Хтось може допомогти виправити цю проблему?

👍НравитсяПонравилось0
В избранноеВ избранном0
LinkedIn

Похожие топики

Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Я не працював з ESP32, але з мого досвіду — реальна частота може суттєво відрізнятися від тієї, що в коді бо комбінація частот генератора і значень поділювача просто не може надати потрібне значення. Судячи з гуглу там мають бути логи які показують реально встановлену частоту — ви перевіряли чи реальні значення співпадають з очікуваними?

Також не перевіряється значення, яке повертає i2s_set_clk — не факт, що виклик був успішний.

i2s_read(ADC_I2S_NUM, (void*)i2sReadBuffer, DMA_BUFFER_LEN * sizeof(uint16_t), &bytesRead, portMAX_DELAY);

		for (size_t i = 0; i < DMA_BUFFER_LEN; i++) {
Це може працювати а може закінчитись кількома годинами пошуку джерела сміття у вашому сигналі. Краще переписати цикл використовуючи bytesRead замість DMA_BUFFER_LEN. Гігієна коду.

1. Додав перевірку на виклик i2s_set_clk — все гаразд.
2. Переписав цикл відносно значення bytesRead, дякую за зауваження
3. Я гадки не маю як отримати реально встановлену частоту дискретизації. Ви б не могли підсказати як її отримати?

Я гадки не маю як отримати реально встановлену частоту дискретизації. Ви б не могли підсказати як її отримати?

Судячи з документації:
1. Використовуючи i2s_get_clk (docs.espressif.com/...​11i2s_get_clk10i2s_port_t)
2. Встановивши log level на INFO для тегу «I2S» і перевіривши що там після виклику i2s_set_clk. Якщо вірити гуглу там має бути щось на зразок:

I (640) I2S: PLL_D2: Req RATE: 44100, real rate: 2777.000, BITS: 16, CLKM: 30, BCK: 60, MCLK: 30.234, SCLK: 88864.000000, diva: 64, divb: 14

Це все в теорії, у мене немає заліза перевірити як це працює насправді.

Тепер все зрозуміло. Реальна частота була в 16 разів менша.
При такому значенні MATLAB фільтрував частоти 40-80 Гц, що не спотворило криву ЕКГ і при цьому дозволило усунути шум 50-60 Гц.
Красно дякую вам!

Чогось я тут не розумію, передивись цю строчку

f = (0:N — 1 ) * 100 / N;

Це відноситься до перетворення Фур’є. Мене скоріше цікавить чого фільтр працює з параметрами 0.06 — 0.14.

А є можливість увійти в debug mode?

насчет фильтра не понял вопроса. он аппаратный?
но сам код с i2c_read() не имеет смысла, поскольку ты не смотришь на значение

bytesRead

1. Ні, цифровий (50-60 Гц).
2. Якщо передати portMAX_DELAY останнім аргументом, то жодного timeout не буде. Відповідно bytesRead = DMA_BUFFER_LEN.

Подписаться на комментарии