Uncorrect ADC iniziatization with I2S

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

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Thu Apr 22, 2021 7:04 am

Hello klaetze,

Which IDF are you using? Before pointing to 2Msps, did you try with slower sampling rate?
Could you show me some of your code?

I don't call bootloader_random_disable() function because it is called by the fw start-up routine.

Gianluca.

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

Re: Uncorrect ADC iniziatization with I2S

Postby klaetze » Thu Apr 22, 2021 9:24 am

Hi Gianluca,

thanks for your reply,

I tried several sampling rates from 3 kHz to 100 kHz but it didn't work for any of them.

I am using the esp-idf version 4.1.

Here is the code that I used. I reused quite a lot of Your code.

Code: Select all

#define TAG                         "I2S"

#define SAMPLE_RATE                 5000
#define I2S_UNIT			(0)
#define DMA_BUF_COUNT               4
#define DMA_BUF_LEN                 1024
#define ADC_UNIT                    1
#define ADC_CHANNEL         		0
#define NUM_SAMPLES                 1024

xQueueHandle adc_i2s_event_queue;
uint8_t adc_i2s_event_queue_size = 1;
// ...
i2s_event_t adc_i2s_evt;

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_LEFT,					
			.intr_alloc_flags = 0,
			.dma_buf_count = DMA_BUF_COUNT,									
			.dma_buf_len = DMA_BUF_LEN,										
			.use_apll = 1,//false,
			.tx_desc_auto_clear = true										
	};

	static const i2s_pin_config_t pin_config = {
		.bck_io_num = 32,							// Sample f(Hz) (= sample f * 2)  on this pin (optional).
		.ws_io_num = 33,							// Left/Right   (= sample f)      on this pin (optional).
		.data_out_num = I2S_PIN_NO_CHANGE,
		.data_in_num = I2S_PIN_NO_CHANGE
	};

	//install and start i2s driver
    ret = i2s_driver_install(I2S_UNIT, &adc_i2s_config, adc_i2s_event_queue_size , &adc_i2s_event_queue);

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

	// Output sample clock & left/right signals to measure with oscilloscope (optional).
	i2s_set_pin(I2S_UNIT, &pin_config);

	//init ADC pad
	ret = i2s_set_adc_mode(ADC_UNIT, ADC_CHANNEL);
	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;

	ESP_ERROR_CHECK(i2s_zero_dma_buffer(I2S_UNIT));

	ret = i2s_adc_enable(I2S_UNIT);
	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();
	vTaskDelay(100);
	adc_power_on();
	adc_i2s_init();
	adc_i2s_enable();
}

#define I2S_MAX_CHANNELS 1
// Convert DMA 16bit (Chan 4b + ADC 12b) => 12bit, and print them in the same order each time.
void i2s_print_adc_data(uint8_t* s_buff, uint32_t len)
{
	uint16_t dac_value[] = 		// Max 8 ADC1 input channels/pins.
		{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
	int chan = 0;
	
	printf( "\tChan[n] : ADC raw\t");
	for (int i = 0; i < len; i += (I2S_MAX_CHANNELS * 2)) {
		for (int j = 0; j < (I2S_MAX_CHANNELS * 2); j += 2) {
			chan = s_buff[i + j + 1] >> 4;				// Cannel nbr is in bit 7:4.
			dac_value[chan] = (((s_buff[i + j + 1] & 0x0F) << 8) | s_buff[i + j + 0 ]);
		}
		for (int j = 0; j < 8; j ++) {
			if(dac_value[j] != 0xFFFF)
				printf( "\t[%d] : %04x", j, dac_value[j]);
		}
	}
	printf("\n\n");
}

static void adc_task(void *pvParameter)
{
	esp_err_t ret = ESP_OK;
	i2s_event_t adc_i2s_evt;
	size_t bytes_read;
    uint8_t* adc_data_buf = (uint8_t*) calloc(NUM_SAMPLES, sizeof(char));


	adc_i2s_init();
	vTaskDelay(5000 / portTICK_PERIOD_MS);
	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)
			{
                //vTaskDelay(3000 / portTICK_PERIOD_MS);
				ret = i2s_read(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES, &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();
				}
			}
		}
	}
	adc_i2s_disable(); // Unreachable
}

esp_err_t app_main()
{
	esp_log_level_set("I2S", ESP_LOG_INFO);
	xTaskCreate( adc_task, "example_i2s_adc_dac", 4096, NULL, 5, NULL);
	while(1)
	{
		vTaskDelay(5000 / portTICK_PERIOD_MS);
	}
	return ESP_OK;
}

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

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Thu Apr 22, 2021 10:16 am

hello klaetze,

Giving a quick view of your code I noticed some point.

In your configuration, you set ".bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,", so, when you make a calloc you will need:

Code: Select all

uint16_t* adc_data_buf = (uint16_t*) calloc(NUM_SAMPLES, sizeof(uint16_t));
And so, in your read:

Code: Select all

ret = i2s_read(I2S_UNIT, (char*)adc_data_buf, NUM_SAMPLES*2, &bytes_read, portMAX_DELAY);
because you are casting adc_data_buf as a (char*)

Also, try to print the raw value by:

Code: Select all

for(int i = 0; i < NUM_SAMPLES; i++)
{
    ets_printf("%d ", adc_data_buf[i]);
}
before any calculation on it.

Let me know if you will have any progress.

Regards,

Gianluca.

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

Re: Uncorrect ADC iniziatization with I2S

Postby klaetze » Thu Apr 22, 2021 11:23 am

Hi Gianluca,

You are right that doesn't make sense in my code. I changed it according to your suggestions.

The problem unfortunately remains the same.

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

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Thu Apr 22, 2021 12:07 pm

Hello klaetze,

try to put ".use_apll = false," and also, which kind of values are you supposed to read?
To do some test, you can try to set up a DAC output and bring it (by a wire for example) to che ADC pin and try to read it in order to have a specific value.

Regars,

Gianluca.

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

Re: Uncorrect ADC iniziatization with I2S

Postby klaetze » Thu Apr 22, 2021 1:37 pm

I have already tried both .apll=true, and apll=false, without any difference.
As input I use a cosine wave with a frequency of about 400Hz for testing purposes. I have also used constant values of 2.0V, but the adc display remains zero. :|

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

Re: Uncorrect ADC iniziatization with I2S

Postby klaetze » Thu Apr 22, 2021 6:42 pm

With the following code (quite messy) I am able to get realistic adc readings up to a frequency of 10 ksps however as soon as i increase the sampling rate over 10 ksps the adc-readings are all zeros again.

Code: Select all

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "driver/i2s.h"
#include "soc/syscon_reg.h"
#include "driver/adc.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "driver/dac.h"

#define TAG "adc_i2s"

xQueueHandle i2s_event_queue;
uint8_t adc_i2s_event_queue_size = 1;
i2s_event_t evt;
static EventGroupHandle_t wifi_event_group;

static esp_err_t event_handler(void *ctx, system_event_t *event)
{
    switch(event->event_id) {
        case SYSTEM_EVENT_STA_START:
            esp_wifi_connect();
            break;
        case SYSTEM_EVENT_STA_GOT_IP:
            break;
        case SYSTEM_EVENT_STA_DISCONNECTED:
            break;
        default:
            break;
    }
    return ESP_OK;
}


#define COSINE
static void dac_task()
{
	#ifdef COSINE
		esp_err_t ret = ESP_OK;
		dac_cw_config_t cosine = {
			.en_ch = DAC_CHANNEL_1,			// output on pin 25
			.scale = 0x0,
			.phase = 0x2,
			.freq = 500,
			.offset = 1
		};
			
		ret = dac_cw_generator_config(&cosine);
		if (ret  != ESP_OK)
			{
				ESP_LOGE(TAG, "dac config error = %i", ret);
			}
		else
		{
			printf("config succesful\n");
		}

		ret = dac_cw_generator_enable();
		if (ret  != ESP_OK)
			{
				ESP_LOGE(TAG, "dac enable error = %i", ret);
			}
		else
		{
				printf("enable succesful\n");
			}
		dac_output_enable( DAC_CHANNEL_1);
	#else
		dac_output_enable(DAC_CHANNEL_1);
		dac_output_voltage(DAC_CHANNEL_1, 150);
	#endif

    while(1)
    {
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }

	//dac_output_enable(DAC_CHANNEL_1)
}


void adc_task()
{
// initialization
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
        .sample_rate =  100000,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .communication_format = I2S_COMM_FORMAT_I2S,//I2S_COMM_FORMAT_I2S_MSB,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 2,
        .dma_buf_len = 1024,
        .use_apll = true,
    };

static const i2s_pin_config_t pin_config = {
		.bck_io_num = 32,							// Sample f(Hz) (= sample f * 2)  on this pin (optional).
		.ws_io_num = 33,							// Left/Right   (= sample f)      on this pin (optional).
		.data_out_num = I2S_PIN_NO_CHANGE,
		.data_in_num = I2S_PIN_NO_CHANGE
	};


    printf("after config struct\n");
    i2s_driver_install(I2S_NUM_0, &i2s_config, adc_i2s_event_queue_size , &i2s_event_queue);
    printf("driver installed\n");
    
    // Output sample clock & left/right signals to measure with oscilloscope (optional).
	i2s_set_pin(I2S_NUM_0, &pin_config);


    //******************************************************//
    ESP_ERROR_CHECK(i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_0));
    ESP_ERROR_CHECK(i2s_adc_enable(I2S_NUM_0));

    // workaround
    vTaskDelay(10 / portTICK_PERIOD_MS);

    // enable continuous adc sampling
    SYSCON.saradc_ctrl2.meas_num_limit = 0;

    // channel, attenation, bit width
    SYSCON.saradc_sar1_patt_tab[0] = ((ADC1_CHANNEL_0 << 4) | (ADC_WIDTH_BIT_12 << 2) | ADC_ATTEN_DB_11) << 24;
    //************************************************************************//

    // After running WiFi on esp_wifi_set_mode(), the ADC-I2S scanning is stops. 
    // init_wifi();
    //dac_task();
    // Read DMA event queue as ADC scanning result
    printf("test\n");
    int i2s_read_len = 1024 * 2;
    size_t bytes_read = 0;
    uint16_t i2s_read_buff[1024];
    
    printf("while\n");
    while(1) {
        printf("in while\n");
        if (xQueueReceive(i2s_event_queue,(void *)&evt, (portTickType)portMAX_DELAY)) {
            printf("first if\n");
            if (evt.type==2) {
                printf("second if\n");
                i2s_read(I2S_NUM_0, (char*)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY);
                ESP_LOG_BUFFER_HEX("i2s_read_buff", i2s_read_buff, 16);
            }
        }
    }
}




void app_main()
{
    xTaskCreate(dac_task, "DAC_TASK", 4096, NULL, 5, NULL);   
    xTaskCreate(adc_task, "ADC TASK", 8192, NULL, 5, NULL);
	
    while(1)
    {
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }

}

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

Re: Uncorrect ADC iniziatization with I2S

Postby klaetze » Mon Apr 26, 2021 1:46 pm

Hi Guys,
i had to update from esp-idf version 4.1 to 4.2. Now everything is working as it should.
For further questions check out this post: https://github.com/espressif/esp-idf/pull/1991

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

Re: Uncorrect ADC iniziatization with I2S

Postby Gianluca.Loi » Mon Apr 26, 2021 1:49 pm

Hello Klaetze,

Great!
I haven't answer you yet because I haven't any time to test your fw. I'm glad you solved your problem.
Did you reach 2Msps?

Regards,

Gianluca.

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

Re: Uncorrect ADC iniziatization with I2S

Postby klaetze » Mon Apr 26, 2021 7:51 pm

Hi Gianluca,
i measured the Sampling frequency with an oscilloscope and its indeed 2 Msps.

I also made a measurement with a pwm signal of 120 kHz and a duty cycle of 90%. As you can see on the picture it is pretty much 2 Msps.
Attachments
2MSPS.jpg
2MSPS.jpg (21.94 KiB) Viewed 6891 times

Who is online

Users browsing this forum: Bing [Bot] and 230 guests