Uncorrect ADC iniziatization with I2S

Gianluca.Loi
Posts: 19
Joined: Mon Jun 03, 2019 3:46 pm

Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Mon Aug 26, 2019 7:28 am

Hello,

I'm new in this forum so please forgive me if I'm making any mistake creating this post.

I'm developing a system on ESP32 in order to sample a signal and I need an high sample rate (around 51200Hz). Fort this reason I'm using the I2S-ADC mode.
The input signal is composed by a dc value that is generated by an ESP's dac pin and an ac signal from outside.
So, at the adc pin, at least is possible to measure the dc value due to the dac pin.

Sometimes, when the board start for the first time and I initialize the I2S - ADC section, I'm not able to read the data from the dma. To be more specific, I read a zero value buffer.
When I have this problem, I try a re-init of I2S-ADC section but I continue to see this problem. The only solution is to turn off the board, wait some seconds and the turn on. This solution, clearly, is not acceptable.

Somebody know where is the problem and how to solve it?

Some code:

Code: Select all

static void adc_i2s_init(void)
{
	esp_err_t ret = ESP_OK;

	i2s_config_t adc_i2s_config =
	{
			.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
			.sample_rate = SAMPLE_RATE,
			.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
			.communication_format = I2S_COMM_FORMAT_I2S_MSB,
			.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,					// one channel
			.intr_alloc_flags = 0,//ESP_INTR_FLAG_LEVEL1,
			.dma_buf_count = DMA_BUF_COUNT,									
			.dma_buf_len = DMA_BUF_LEN,										
			.use_apll = false,
			.tx_desc_auto_clear = true										
	};

	//install and start i2s driver
	ret = i2s_driver_install(I2S_UNIT, &adc_i2s_config, 1, &adc_i2s_event_queue);
	if (ret  != ESP_OK)
	{
		ESP_LOGE(TAG, "i2s_driver_install operation error = %i", ret);
	}

	//init ADC pad
#if ADC_DUAL_CHANNEL
	adc_gpio_init(ADC_UNIT, ADC_VOLTAGE_CHANNEL);
	adc_gpio_init(ADC_UNIT, ADC_CURRENT_CHANNEL);
	ret = i2s_set_adc_mode_custom(ADC_UNIT, ADC_VOLTAGE_CHANNEL, ADC_VOLTAGE_WIDTH, ADC_VOLTAGE_ATTEN_DB, ADC_DATA_INV);
#elif VOLTAGE_CHANNEL_EN
	ret = i2s_set_adc_mode_custom(ADC_UNIT, ADC_VOLTAGE_CHANNEL, ADC_VOLTAGE_WIDTH, ADC_VOLTAGE_ATTEN_DB, ADC_DATA_INV);
#elif CURRENT_CHANNEL_EN
	ret = i2s_set_adc_mode_custom(ADC_UNIT, ADC_CURRENT_CHANNEL, ADC_CURRENT_WIDTH, ADC_CURRENT_ATTEN_DB, ADC_DATA_INV);
#else
	ESP_LOGE(TAG,"NO CHANNEL SELECTED");
#endif

	if (ret  != ESP_OK)
	{
		ESP_LOGE(TAG, "i2s_set_adc_mode_custom operation error = %i", ret);
	}

	vTaskDelay(2000);
}

static void adc_i2s_enable(void)
{
	esp_err_t ret = ESP_OK;

#if ADC_DUAL_CHANNEL
	ret = i2s_adc_enable_custom(I2S_UNIT, ADC_VOLTAGE_CHANNEL, ADC_VOLTAGE_WIDTH, ADC_VOLTAGE_ATTEN_DB, ADC_DATA_INV);
	//Enable Multipattern scanning
	SYSCON.saradc_ctrl.sar1_patt_len = 3;
	SYSCON.saradc_sar1_patt_tab[0] = ADC_DUAL_CHANNEL_PATTERN_TABLE;
	//		SYSCON.saradc_sar1_patt_tab[0] = 0x7F6F7F6F;							// Vref 3.6V
#elif VOLTAGE_CHANNEL_EN
	ret = i2s_adc_enable_custom(I2S_UNIT, ADC_VOLTAGE_CHANNEL, ADC_VOLTAGE_WIDTH, ADC_VOLTAGE_ATTEN_DB, ADC_DATA_INV);
#elif CURRENT_CHANNEL_EN
	ret = i2s_adc_enable_custom(I2S_UNIT, ADC_CURRENT_CHANNEL, ADC_CURRENT_WIDTH, ADC_CURRENT_ATTEN_DB, ADC_DATA_INV);
#else
	ESP_LOGE(TAG,"NO CHANNEL SELECTED");
#endif

	if (ret  != ESP_OK)
	{
		ESP_LOGE(TAG, "i2s_adc_enable_custom operation error = %i", ret);
	}
}

static void adc_i2s_disable(void)
{
	i2s_adc_disable(I2S_UNIT);
}

static void adc_i2s_restore_sampling(void)
{
	adc_i2s_disable();
	adc_disable_function();
	vTaskDelay(100);
	adc_power_on();
	adc_i2s_init();
	adc_i2s_enable();
}

static void adc_task(void *pvParameter)
{
	esp_err_t ret = ESP_OK;
	i2s_event_t adc_i2s_evt;
	size_t bytes_read;

	/* Reset ADC */
	adc_disable_function();
	/*********************/

	adc_i2s_init();
	adc_i2s_enable();

	while ( 1 )
	{
		if(xQueueReceive(adc_i2s_event_queue, (void * )&adc_i2s_evt, (portTickType)portMAX_DELAY))
		{
			if(adc_i2s_evt.type == I2S_EVENT_RX_DONE)
			{
				/*
				 * Read data from I2S bus, in this case, from ADC.
				 * With DMA_BUF_LEN = 1024, DMA_BUF_COUNT = 2 and NUM_SAMPLES = 1024 it takes 2887 cycles to complete the operation.
				 */
				ret = i2s_read_custom(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES*2, &bytes_read, portMAX_DELAY);
				if (ret  != ESP_OK)
				{
					ESP_LOGE(TAG, "i2s_read operation error = %i", ret);
				}

				if(((adc_data_buf[0]) == 0) && ((adc_data_buf[1]) == 0) && ((adc_data_buf[2]) == 0))
				{
					// If the adc reads zero values, it means it hasn't been started correctly. Restart it again to fix this problem.
					adc_i2s_restore_sampling();
				}
				else
				{
					// Do Something
				}
			}
		}
	}
	adc_i2s_disable(); // Unreachable
}
Last edited by Gianluca.Loi on Wed Aug 28, 2019 8:55 am, edited 1 time in total.

Gianluca.Loi
Posts: 19
Joined: Mon Jun 03, 2019 3:46 pm

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Tue Aug 27, 2019 9:07 am

Hello,

Any solution or idea?
If further information are needed please ask me.

Gianluca

Gianluca.Loi
Posts: 19
Joined: Mon Jun 03, 2019 3:46 pm

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Wed Aug 28, 2019 9:04 am

Further information:
I put some logs after the i2s_read.

Code: Select all

				ret = i2s_read_custom(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES*2, &bytes_read, portMAX_DELAY);
				if (ret  != ESP_OK)
				{
					ESP_LOGE(TAG, "i2s_read operation error = %i", ret);
				}

				if(((adc_data_buf[0]) == 0) && ((adc_data_buf[1]) == 0) && ((adc_data_buf[2]) == 0))
				{
					printf("adc_data_buf[0] = %d adc_data_buf[1] = %d adc_data_buf[2] = %d\n",adc_data_buf[0],adc_data_buf[1],adc_data_buf[2]);
					// If the adc reads zero values, it means it hasn't been started correctly. Restart it again to fix this problem.
					adc_i2s_restore_sampling();
				}
				else
				{
					printf("adc_data_buf[0] = %d adc_data_buf[1] = %d adc_data_buf[2] = %d\n",adc_data_buf[0],adc_data_buf[1],adc_data_buf[2]);
					ESP_LOGW(TAG, "RESTARTING");
					vTaskDelay(1000);
					// Restart is done to reproduce this problem
					esp_restart();
				}
When it works correctly I read:
I (247) I2S: DMA Malloc info, datalen=blocksize=2048, dma_buf_count=2
I (248) I2S: PLL_D2: Req RATE: 51600, real rate: 3333.000, BITS: 16, CLKM: 25, BCK: 60, MCLK: 25.840, SCLK: 106656.000000, diva: 64, divb: 53
I (2249) I2S: PLL_D2: Req RATE: 51600, real rate: 3333.000, BITS: 16, CLKM: 25, BCK: 60, MCLK: 25.840, SCLK: 106656.000000, diva: 64, divb: 53
adc_data_buf[0] = 30847 adc_data_buf[1] = 30861 adc_data_buf[2] = 30871
W (2250) ADC_TASK: RESTARTING

Instead, in wrong case:
I (247) I2S: queue free spaces: 1
I (247) I2S: DMA Malloc info, datalen=blocksize=2048, dma_buf_count=2
I (248) I2S: PLL_D2: Req RATE: 51600, real rate: 3333.000, BITS: 16, CLKM: 25, BCK: 60, MCLK: 25.840, SCLK: 106656.000000, diva: 64, divb: 53
I (2249) I2S: PLL_D2: Req RATE: 51600, real rate: 3333.000, BITS: 16, CLKM: 25, BCK: 60, MCLK: 25.840, SCLK: 106656.000000, diva: 64, divb: 53
adc_data_buf[0] = 0 adc_data_buf[1] = 0 adc_data_buf[2] = 0

bitsmith
Posts: 4
Joined: Mon Nov 23, 2020 4:31 am

Re: Uncorrect ADC iniziatization with I2S

Postby bitsmith » Mon Nov 23, 2020 4:48 am

Hi Guys,
This problem is doing my head in. I've been scouring the net trying to find documentation or running code. I have Arduino version of code that runs. But not esp-idf. I'm having the same problem. The documents from espressif are not the expressive and very light on specifics or working code.
There seems to be a number of bug fixes related to this topic, but these don't seem to help with our esp-idf i2s_adc configuration problems.
The Hardware and peripheral descriptions need a lot more detail.
I know what we want to do is possible and with rates much higher than the audio we are playing with. I have had code working, but randomly. Sometimes it works, sometimes it has the wrong pin or attenuation, but mostly I get 0000 or 4096.
The last code that was place here when connected to a 8khz sinewave with a low of 100mv to a high of 1.2v shouldn't give me either 0000 or 4096. Sometimes it has a number of lines of 4096 then 0000 there after.
I'm still looking thanks for the incites in the topic, hope fully we can find the root cause.

Gianluca.Loi
Posts: 19
Joined: Mon Jun 03, 2019 3:46 pm

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Mon Nov 23, 2020 7:52 am

bitsmith wrote:
Mon Nov 23, 2020 4:48 am
Hi Guys,
This problem is doing my head in. I've been scouring the net trying to find documentation or running code. I have Arduino version of code that runs. But not esp-idf. I'm having the same problem. The documents from espressif are not the expressive and very light on specifics or working code.
There seems to be a number of bug fixes related to this topic, but these don't seem to help with our esp-idf i2s_adc configuration problems.
The Hardware and peripheral descriptions need a lot more detail.
I know what we want to do is possible and with rates much higher than the audio we are playing with. I have had code working, but randomly. Sometimes it works, sometimes it has the wrong pin or attenuation, but mostly I get 0000 or 4096.
The last code that was place here when connected to a 8khz sinewave with a low of 100mv to a high of 1.2v shouldn't give me either 0000 or 4096. Sometimes it has a number of lines of 4096 then 0000 there after.
I'm still looking thanks for the incites in the topic, hope fully we can find the root cause.
Hello bitsmith,

The fix for this problem was:

Code: Select all

void bootloader_random_disable(void)
{
    /* Reset some i2s configuration (possibly redundant as we reset entire
       I2S peripheral further down). */
    CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_CAMERA_EN);
    CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_LCD_EN);
    CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE_TEST_EN);
    CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE);
    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_START);
    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET);
    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET);

    /* Disable i2s clock */
    DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);

    /* Restore SYSCON mode registers */
    CLEAR_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DIG_FORCE);
    CLEAR_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DIG_FORCE);

    /* Restore SAR ADC mode */
    CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_SAR2_EN_TEST);
    CLEAR_PERI_REG_MASK(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR2_MUX
                        | SYSCON_SARADC_SAR_SEL | SYSCON_SARADC_DATA_TO_I2S);
    SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
    SET_PERI_REG_BITS(SYSCON_SARADC_FSM_REG, SYSCON_SARADC_START_WAIT, 8, SYSCON_SARADC_START_WAIT_S);

    /* Reset i2s peripheral */
    DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
    DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);

    /* Disable pull supply voltage to SAR ADC */
    CLEAR_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC);
    SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 0, RTC_CNTL_DTEST_RTC_S); }
   
I would like also to highlight that I changed a lot of i2s' idf function to allow me to set correctly all attributes for each pin.
Which IDF version are you using? Have you made any changes in the idf for the i2s?

Regards,
Gianluca.

bitsmith
Posts: 4
Joined: Mon Nov 23, 2020 4:31 am

Re: Uncorrect ADC iniziatization with I2S

Postby bitsmith » Mon Nov 23, 2020 7:29 pm

Hi Gianluca,
Thanks for the quick response.

I'm using the stable(?) idf version 4.1. this seems to be the latest release bar the development version.
I haven't changed any of the core idf code, thinking that the examples that are included with the version would have been tested on the version they were released with. It must be my changes/config/hardware.
Also, I don't understand enough about the low level hal drivers and hardware on this device to go messing about in there yet. This is a problem due to the lack of information in the hardware and peripherals configuration etc.....
(I've been writing low level drivers for AVR, STM32 etc for 20+ years and some linux serial drivers).
This is my first platformio / idf project and I'm on a steep learning curve, with non-working examples.

If you have a basic working example of i2s_adc, I would be most grateful if I could get a copy.
I noticed the code that you have placed in the reply.
What changes did you need to make to the idf? and are they being rolled into the development version?

What documents were you using to make the changes to the idf?

Many thanks in advance,
BitSmith.

Gianluca.Loi
Posts: 19
Joined: Mon Jun 03, 2019 3:46 pm

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Tue Nov 24, 2020 8:14 am

bitsmith wrote:
Mon Nov 23, 2020 7:29 pm
Hi Gianluca,
Thanks for the quick response.

I'm using the stable(?) idf version 4.1. this seems to be the latest release bar the development version.
I haven't changed any of the core idf code, thinking that the examples that are included with the version would have been tested on the version they were released with. It must be my changes/config/hardware.
Also, I don't understand enough about the low level hal drivers and hardware on this device to go messing about in there yet. This is a problem due to the lack of information in the hardware and peripherals configuration etc.....
(I've been writing low level drivers for AVR, STM32 etc for 20+ years and some linux serial drivers).
This is my first platformio / idf project and I'm on a steep learning curve, with non-working examples.

If you have a basic working example of i2s_adc, I would be most grateful if I could get a copy.
I noticed the code that you have placed in the reply.
What changes did you need to make to the idf? and are they being rolled into the development version?

What documents were you using to make the changes to the idf?

Many thanks in advance,
BitSmith.

Hello BitSmith,

When I developed the i2s_adc module, I was using the ESP-IDF v3.3. So I'm not sure it's the same developing process but to start, I used the i2s_adc_dac example. After that I started to modify it and the related libraries (I'm a FW developer). I did this modification because I needed to customize my i2s working mode and I have them in local.
I didn't use any document for my modification, I just only read the code, understand how it works with some test and reading some post online, and then I changed it.

What is your need from the i2s? If you could be more specific I could try to help you.
I put some code that works in v3.3. The functions with name that ends with "_custom" are the ones which I had changed but you could try to use, as the first step, the original ones.

Code: Select all

static void adc_i2s_init(void)
{
	esp_err_t ret = ESP_OK;

	i2s_config_t adc_i2s_config =
	{
			.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
			.sample_rate = SAMPLE_RATE,
			.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
			.communication_format = I2S_COMM_FORMAT_I2S_MSB,
			.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,					// one channel
			.intr_alloc_flags = 0,//ESP_INTR_FLAG_LEVEL1,
			.dma_buf_count = DMA_BUF_COUNT,									// dma_buf_count * dma_buf_len = NUM_SAMPLES
			.dma_buf_len = DMA_BUF_LEN,										// dma_buf_len is not bytes, but samples!
			.use_apll = false,
			.tx_desc_auto_clear = true										// I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability)
	};

	//install and start i2s driver
	ret = i2s_driver_install(I2S_UNIT, &adc_i2s_config, 1, &adc_i2s_event_queue);
	if (ret  != ESP_OK)
	{
		ESP_LOGE(TAG, "i2s_driver_install operation error = %i", ret);
	}
	//init ADC pad
	ret = i2s_set_adc_mode_custom(ADC_UNIT, ADC_VOLTAGE_CHANNEL, ADC_VOLTAGE_WIDTH, ADC_VOLTAGE_ATTEN_DB, ADC_DATA_INV);

	if (ret  != ESP_OK)
	{
		ESP_LOGE(TAG, "i2s_set_adc_mode_custom operation error = %i", ret);
	}

	vTaskDelay(1000);

	adc_i2s_enable();

}

static void adc_i2s_enable(void)
{
	esp_err_t ret = ESP_OK;

	ret = i2s_adc_enable_custom(I2S_UNIT, ADC_VOLTAGE_CHANNEL, ADC_VOLTAGE_WIDTH, ADC_VOLTAGE_ATTEN_DB, ADC_DATA_INV);

	if (ret  != ESP_OK)
	{
		ESP_LOGE(TAG, "i2s_adc_enable_custom operation error = %i", ret);
	}
}

static void adc_i2s_running_function(void)
{
	esp_err_t ret = ESP_OK;
	i2s_event_t adc_i2s_evt;
	size_t bytes_read;

	while(1)
	{
		if(xQueueReceive(adc_i2s_event_queue, (void * )&adc_i2s_evt, (portTickType)portMAX_DELAY))
		{
			if(adc_i2s_evt.type == I2S_EVENT_RX_DONE)
			{
				/*
				 * Read data from I2S bus, in this case, from ADC.
				 * With DMA_BUF_LEN = 1024, DMA_BUF_COUNT = 2 and NUM_SAMPLES = 1024 it takes 2887 cycles to complete the operation.
				 */
				ret = i2s_read_custom(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES*2, &bytes_read, portMAX_DELAY);
				if (ret  != ESP_OK)
				{
					ESP_LOGE(TAG, "i2s_read operation error = %i", ret);
				}

				// DO THINGS....
			}
		}
	}
}
Regards,
Gianluca.

bitsmith
Posts: 4
Joined: Mon Nov 23, 2020 4:31 am

Re: Uncorrect ADC iniziatization with I2S

Postby bitsmith » Tue Nov 24, 2020 5:57 pm

Hi Gianluca,
Thanks for the code.
I want to record one audio channel, and send it to a web page. That is all I need at the moment. The web page side works.
It is the sampling that doesn't work. I have an Arduino version of the code running on the same hardware as the idf attempts.
The example i2s_adc_dac doesn't work for me. That is where I started from. When it does get samples they are from the VP pin, not the ADC_Channel_7 and the attenuation is has not changed to the correct level.
Here is the (hacked about) code that sometimes works, but mostly the samples are 0000. It is scaled down example I2S_ADC_DAC.

Code: Select all

#include <stdio.h>
#include <string.h>
#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 "audio_example_file.h"
#include "esp_adc_cal.h"
#include "soc/adc_channel.h"


#define ADC1_TEST_CHANNEL (ADC1_CHANNEL_7)
#define EXAMPLE_I2S_NUM           (0)
#define EXAMPLE_I2S_SAMPLE_RATE   (16000)
#define EXAMPLE_I2S_SAMPLE_BITS   (16)
#define EXAMPLE_I2S_READ_LEN      (4 * 1024)
#define EXAMPLE_I2S_FORMAT        (I2S_CHANNEL_FMT_RIGHT_LEFT)
#define EXAMPLE_I2S_CHANNEL_NUM   ((EXAMPLE_I2S_FORMAT < I2S_CHANNEL_FMT_ONLY_RIGHT) ? (2) : (1))
#define I2S_ADC_UNIT              ADC_UNIT_1
#define I2S_ADC_CHANNEL           ADC1_CHANNEL_7

uint16_t gAdcBuffer[1024];
void example_i2s_init(void)
{
	 int i2s_num = EXAMPLE_I2S_NUM;
	 i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,  /*!< I2S work mode*/
        .sample_rate =  EXAMPLE_I2S_SAMPLE_RATE,                        /*!< I2S sample rate*/
        .bits_per_sample = EXAMPLE_I2S_SAMPLE_BITS,                     /*!< I2S bits per sample*/
	.communication_format = I2S_COMM_FORMAT_I2S_MSB,                /*!< I2S channel format */
	.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,                    /*!< I2S communication format */
	.intr_alloc_flags = 0,                                          /*!< Flags used to allocate the interrupt. */
	    .dma_buf_count = 2,                                             /*!< I2S DMA Buffer Count */
	    .dma_buf_len = 1024,                                            /*!< I2S DMA Buffer Length */
	    .use_apll = 1,                                                  /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
        //.tx_desc_auto_clear = 0,                                      /*!< I2S auto clear tx descriptor if there is underflow condition */
        .fixed_mclk = 16000,                                            /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0 */
	 }; 
    ESP_ERROR_CHECK(i2s_driver_install(i2s_num, &i2s_config, 0, NULL));
    ESP_ERROR_CHECK(i2s_set_adc_mode(I2S_ADC_UNIT, I2S_ADC_CHANNEL));
    ESP_ERROR_CHECK(adc1_config_channel_atten(I2S_ADC_CHANNEL, ADC_ATTEN_DB_11));
}
void example_disp_buf(uint8_t* buf, int length)
{
    int Av,Min,Max,AvCnt;
    Av = Min = Max = AvCnt = 0 ;
    for (int i = 0; i < length; i +=2 )  
    {
        uint16_t sample = buf[i+1];
        sample *= 0x100;
        sample += buf[i];
        if(i < 16)
        {
            printf("%04X ", sample);
            if ((i  % 16 ) == 0)   printf("\n");
        }    
        if(AvCnt == 0)           Av = Min = Max = sample;
        else   {
            Av+=sample;
            if(sample < Min) Min = sample;
            if(sample > Max) Max = sample;
        }
        AvCnt++;
    }
    printf("Cnt:%u, Min:%u, Max:%u, Av:%u \n",length,Min,Max,Av/AvCnt);
}

void example_i2s_adc_dac(void*arg)
{
    while(1)
    {
    vTaskDelay(100/portTICK_PERIOD_MS);
    int i2s_read_len = EXAMPLE_I2S_READ_LEN;
    int flash_wr_size = 0;
    size_t bytes_read;

        char* i2s_read_buff = (char*) calloc(i2s_read_len, sizeof(char));
        uint8_t* flash_write_buff = (uint8_t*) calloc(i2s_read_len, sizeof(char));
       
        i2s_adc_enable(EXAMPLE_I2S_NUM);
        while(1)
        {
            //read data from I2S bus, in this case, from ADC.
            i2s_read(EXAMPLE_I2S_NUM, (void*) i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);
            example_disp_buf((uint8_t*) i2s_read_buff, bytes_read);
        }
        memcpy(gAdcBuffer,i2s_read_buff,1024);
        i2s_adc_disable(EXAMPLE_I2S_NUM);
        free(i2s_read_buff);
        i2s_read_buff = NULL;
        free(flash_write_buff);
        flash_write_buff = NULL;
   }
   vTaskDelay(200 / portTICK_RATE_MS);
   vTaskDelete(NULL);  
}

esp_err_t app_main(void)
{
    example_i2s_init();
    esp_log_level_set("I2S", ESP_LOG_INFO);
    xTaskCreate(example_i2s_adc_dac, "example_i2s_adc_dac", 1024 * 2, NULL, 5, NULL);
    return ESP_OK;
}

Gianluca.Loi
Posts: 19
Joined: Mon Jun 03, 2019 3:46 pm

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Wed Nov 25, 2020 8:16 am

Hello BitSmith,

Before changing the IDF, I suggest you to manage the read from the dma's buffers using "I2S_EVENT_RX_DONE" event.
You will find the code below.

Let me know if you are able to see something different with this modifications.

Regards,

Gianluca.

Code: Select all

// ...
QueueHandle_t adc_i2s_event_queue;
uint8_t adc_i2s_event_queue_size = 1;
ret = i2s_driver_install(i2s_num, &i2s_config, adc_i2s_event_queue_size , &adc_i2s_event_queue);
// ...
i2s_event_t adc_i2s_evt;
while(1)
{
		if(xQueueReceive(adc_i2s_event_queue, (void * )&adc_i2s_evt, (portTickType)portMAX_DELAY))
		{
			if(adc_i2s_evt.type == I2S_EVENT_RX_DONE)
			{
				ret = i2s_read(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES*2, &bytes_read, portMAX_DELAY);
				if (ret  != ESP_OK)
				{
					ESP_LOGE(TAG, "i2s_read operation error = %i", ret);
				}
			}
		}
}
// ...

klaetze
Posts: 13
Joined: Tue Dec 29, 2020 6:45 pm

Re: Uncorrect ADC iniziatization with I2S

Postby klaetze » Wed Apr 21, 2021 9:00 pm

Hi,

i'm facing a quit similar problem.
I try to take adc measuremets with the maximum possible sample rate. In the Documentation I read something of about 2 Msps.
However, I can't get the i2s_adc_dac- example to work. When i read from the DMA buffer i always get zeros. I also tried your Example @Gianluca.Loi but with the same result.

Can you tell me, how or when do you use the "bootloader_random_disable()" function?

Kind Regards
Kletze

Who is online

Users browsing this forum: No registered users and 116 guests