ADC glitchs - I2S - ESP32

DylanR0
Posts: 12
Joined: Mon Aug 06, 2018 2:42 pm

ADC glitchs - I2S - ESP32

Postby DylanR0 » Mon Aug 06, 2018 2:57 pm

Hello :)

I'm working on a project with the ESP32.
I have to send data by wifi using TCP/IP protocol.
I tested with simple signal but I have a problem, they're noisy with inexplicable glitchs.

Tested with 40KHz sampling rate. Wanted to work fine even at 100Hz but problem with clkmdiv is too large, don't know how to solve this... (Sorry I'm a frenchy :D )

Code: Select all

 
 
 #include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "nvs.h"
#include "nvs_flash.h"

#include "driver/i2s.h"
#include "soc/syscon_reg.h"
#include "driver/adc.h"
#include "esp_event_loop.h"
#define BUF_LEN 512
#define TAG1 "bytes read"
#define SSID "PCDylanR" 
#define PASSPHARSE "motdepasse" 
#define TCPServerIP "192.168.137.1" 
//#define SAMPLERATE 40000 
//PORT3010

static QueueHandle_t i2s_event_queue;

static EventGroupHandle_t wifi_event_group;
const int CONNECTED_BIT = BIT0;

static const char *TAG="tcp_client";


void wifi_connect(){
    wifi_config_t cfg = {
        .sta = {
            .ssid = SSID,
            .password = PASSPHARSE,
        },
    };
    ESP_ERROR_CHECK( esp_wifi_disconnect() );
    ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &cfg) );
    ESP_ERROR_CHECK( esp_wifi_connect() );
}


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


static void initialise_wifi(void)
{
    esp_log_level_set("wifi", ESP_LOG_NONE); 
    tcpip_adapter_init();                   
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}


void app_main()
{
    
    ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
    wifi_event_group = xEventGroupCreate();
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { 
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK( ret );

    
    initialise_wifi();
   
    // Configuration de l'I2S
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,          
        .sample_rate = 40000,                                                  
        .bits_per_sample = 16,                                                 
        .use_apll = true,                                                         
        .communication_format = I2S_COMM_FORMAT_I2S_MSB, 
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,               
        .intr_alloc_flags =0,                               
        .dma_buf_count =2,                                                      
        .dma_buf_len = BUF_LEN                                                      

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


    i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_0);
    
    i2s_set_sample_rates(I2S_NUM_0, 40000); //test utilité


    SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);
    
    adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_DB_11);

 
    vTaskDelay(5000/portTICK_RATE_MS);


    i2s_adc_enable(I2S_NUM_0);   

    ESP_LOGI(TAG,"démarage du mode TCP \n");
    struct sockaddr_in tcpServerAddr;
    tcpServerAddr.sin_addr.s_addr = inet_addr(TCPServerIP);
    tcpServerAddr.sin_family = AF_INET;
    tcpServerAddr.sin_port = htons( 3010 ); //Port sur lequel le serveur écoute

    int s;
    int i2s_read_len = BUF_LEN*2; 
    size_t bytes_read;
    char* i2s_read_buff = (char*) calloc(i2s_read_len,sizeof(char));
    i2s_event_t evt;
     
    
    while(1){
        xEventGroupWaitBits(wifi_event_group,CONNECTED_BIT,false,true,portMAX_DELAY); 
        s=socket(AF_INET, SOCK_STREAM, 0);                                     
        if (xQueueReceive(i2s_event_queue, &evt, portMAX_DELAY) == pdPASS) 
        { 
            if (evt.type==I2S_EVENT_RX_DONE) 
            {
                i2s_read(I2S_NUM_0, (void*)i2s_read_buff, i2s_read_len,&bytes_read, portMAX_DELAY);
                if(s < 0) 
                {
                    ESP_LOGE(TAG, "... Impossible d'alouer un socket.\n");
                    vTaskDelay(2000 / portTICK_PERIOD_MS);
                    continue;
                }
                //ESP_LOGI(TAG, "... socket alloué\n");
                if(connect(s, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr)) != 0) 
                {
                    ESP_LOGE(TAG, "... problème de connexion errno=%d \n", errno);
                    close(s);
                    vTaskDelay(4000 / portTICK_PERIOD_MS);
                    continue;
                }
                ESP_LOGI(TAG, "... connecté \n");
                if( send(s , i2s_read_buff , i2s_read_len,0) < 0)
                {
                    ESP_LOGE(TAG, "... Send failed \n");
                    close(s);
                    vTaskDelay(4000 / portTICK_PERIOD_MS);
                    continue;
                }
                //ESP_LOGI(TAG, "... paquet envoyé");   
                //ESP_LOGI(TAG1,"%d \n", bytes_read);
                ESP_LOG_BUFFER_HEX("i2s_read_buff", i2s_read_buff, 16); 
                close(s);
            }
        }
    }
}
 
Do you have any idea ? I think about a problem with the ADC like in other forums but I'm a little bit blocked :?
Thanks !
Attachments
10hz1vpp600mvof.JPG
Freq : 10Hz
Ampl : 1V
Offset 0.6V
10hz1vpp600mvof.JPG (29.43 KiB) Viewed 9693 times
10khz1vpp600mvof.JPG
Freq : 10KHz
Ampl : 1V
Offset 0.6V
10khz1vpp600mvof.JPG (39.18 KiB) Viewed 9693 times

ESP_Sprite
Posts: 8921
Joined: Thu Nov 26, 2015 4:08 am

Re: ADC glitchs - I2S - ESP32

Postby ESP_Sprite » Tue Aug 07, 2018 3:53 am

Are you sure your I2S buffers aren't overflowing because perhaps the WiFi is somewhat slow in sending a certain packet? I'd use a queue or ringbuffer of some size to sit in between and buffer data for when that happens.

DylanR0
Posts: 12
Joined: Mon Aug 06, 2018 2:42 pm

Re: ADC glitchs - I2S - ESP32

Postby DylanR0 » Tue Aug 07, 2018 7:35 am

I tried using Wifi and Ethernet connexion, and I can't say if there is a difference.
I tested @500 Hz (always 40KHz sampling rate) and it's impossible to see the original signal.
The ESP32 is connected to the wireless hotspot of my computer and my computer to wifi/ethernet.
Do you think it's the Wifi link between my ESP32 and my computer ? I tried with another computer and I had the same results.
Attachments
500hzwifi.JPG
Wifi ; 500Hz ; 1Vamp ; 0.6Voff
500hzwifi.JPG (38.48 KiB) Viewed 9663 times
500hzeth.JPG
Ethernet; 500Hz ; 1Vamp ; 0.6Voff
500hzeth.JPG (46.33 KiB) Viewed 9663 times

DylanR0
Posts: 12
Joined: Mon Aug 06, 2018 2:42 pm

Re: ADC glitchs - I2S - ESP32

Postby DylanR0 » Tue Aug 07, 2018 9:37 am

HS :
It's my first time here, how long is it to have the permission to submit ? :?:
The flow between messages is a little bit impacted
(Sorry for double post)

ESP_Sprite
Posts: 8921
Joined: Thu Nov 26, 2015 4:08 am

Re: ADC glitchs - I2S - ESP32

Postby ESP_Sprite » Tue Aug 07, 2018 1:13 pm

Your first three messages have to be acknowledged by a moderator to check if you're not spamming; you should be free to post without that now.

I looked at your code a bit better:
- For every K of data you receive, you open a connection, send the data and close it. At 40KHz, you do that 80x per second. Note that opening and closing a connection is a pretty intense thing: why not open a connection and keep it open?
- The only buffer you have between the network and your ADC is the I2S driver buffer, which is 1K. This means that you're dropping packets when your network routines take more than 25uS... which is a really short time. Easiest way to quickly hack some more buffer into this is by increasing the dma_buf_count and dma_buf_len in the i2c_config_t struct.

DylanR0
Posts: 12
Joined: Mon Aug 06, 2018 2:42 pm

Re: ADC glitchs - I2S - ESP32

Postby DylanR0 » Tue Aug 07, 2018 1:53 pm

Thank you for the explanation.

So you're telling me that I should remove this close(s) ? (1)

Code: Select all

while(1){
        xEventGroupWaitBits(wifi_event_group,CONNECTED_BIT,false,true,portMAX_DELAY); 
        s=socket(AF_INET, SOCK_STREAM, 0);                                     
        if (xQueueReceive(i2s_event_queue, &evt, portMAX_DELAY) == pdPASS) 
        { 
            if (evt.type==I2S_EVENT_RX_DONE) 
            {
                i2s_read(I2S_NUM_0, (void*)i2s_read_buff, i2s_read_len,&bytes_read, portMAX_DELAY);
                if(s < 0) 
                {
                    ESP_LOGE(TAG, "... Impossible d'alouer un socket.\n"); // <<<--------------------- HERE (2)
                    vTaskDelay(2000 / portTICK_PERIOD_MS);
                    continue;
                }
                //ESP_LOGI(TAG, "... socket alloué\n");
                if(connect(s, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr)) != 0) 
                {
                    ESP_LOGE(TAG, "... problème de connexion errno=%d \n", errno);
                    close(s);
                    vTaskDelay(4000 / portTICK_PERIOD_MS);
                    continue;
                }
                ESP_LOGI(TAG, "... connecté \n");
                if( send(s , i2s_read_buff , i2s_read_len,0) < 0)
                {
                    ESP_LOGE(TAG, "... Send failed \n");
                    close(s);
                    vTaskDelay(4000 / portTICK_PERIOD_MS);
                    continue;
                }
                //ESP_LOGI(TAG, "... paquet envoyé");   
                //ESP_LOGI(TAG1,"%d \n", bytes_read);
                ESP_LOG_BUFFER_HEX("i2s_read_buff", i2s_read_buff, 16); 
                //close(s);  <<<----------------------------------------------------------------- HERE (1)
            }
        }
    }
By removing this "close" I only have few data then, I loop in (2). (Attachments, I restared two times so I have 2 data areas)
I can't let open, there is a too big accumulation of data.

Moreover, you're telling me that I have to find the perfect combination between buf_len and buf_count to have the time to send the data in a buffer before the DMA comeback ?
I tried to keep 2 buffers but with 1024 length and I had problems with timing not corresponding (20s measured, 100s in result and things like that). I'll try to increase the number of buffers. :)
Attachments
5KHz.JPG
5KHz.JPG (30.82 KiB) Viewed 9657 times

User avatar
fly135
Posts: 606
Joined: Wed Jan 03, 2018 8:33 pm
Location: Orlando, FL

Re: ADC glitchs - I2S - ESP32

Postby fly135 » Tue Aug 07, 2018 3:29 pm

The correct method of sending data that fast is to open the connection and keep it open while transmitting. (Just like ESP_Sprite said). I don't know what you mean by "I can't let open, there is a too big accumulation of data.". That doesn't make any sense. You read the data and you send it. But what makes more sense to to provide a queue of buffers. Feed the queue with a thread reading the I2S and send it from another thread reading the queue. That way if the network has throughput issues/pauses the data queue can buffer the I2S data until it can get streamed. Buffering a continuous data stream is always a good idea because transmitting on the network can be bursty/unreliable/intermittent in terms of data throughput.

John A

DylanR0
Posts: 12
Joined: Mon Aug 06, 2018 2:42 pm

Re: ADC glitchs - I2S - ESP32

Postby DylanR0 » Tue Aug 07, 2018 7:36 pm

I'll try tomorow,

Tell me if I'm wrong, but that's mean that just using this code :

Code: Select all

while(1){
        xEventGroupWaitBits(wifi_event_group,CONNECTED_BIT,false,true,portMAX_DELAY); 
        s=socket(AF_INET, SOCK_STREAM, 0);                                     
        if (xQueueReceive(i2s_event_queue, &evt, portMAX_DELAY) == pdPASS) 
	{ 
            	if (evt.type==I2S_EVENT_RX_DONE) 
            	{
                	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);
                }
	}         
}                	
It should work ?

When I tried without the close in the last post, I had a returned value of socket() < 0.
I didn't note the errno, my bad :roll: .
About the queue of buffers, I thought the i2s_config_t{} was ok with that.
That's why I'm a little lost with :
Feed the queue with a thread reading the I2S and send it from another thread reading the queue.
I don't really understand the sentence and I can't visualize the way to do it.

Thank you for your time :oops:

User avatar
fly135
Posts: 606
Joined: Wed Jan 03, 2018 8:33 pm
Location: Orlando, FL

Re: ADC glitchs - I2S - ESP32

Postby fly135 » Tue Aug 07, 2018 9:54 pm

You can't be creating a socket every time you read the i2s. Create the socket and connect to the server that wants the data before entering the loop. Then put the send statement in the loop after the i2s read.
I don't really understand the sentence and I can't visualize the way to do it.
Well, you are going to need some help from someone who understands multithreaded programming. You might be able to get away with putting the read and the send in the same thread, but IIRC the I2S DMA doesn't have that much buffering available. So you may end up losing data.

What that sentence means is.... you create two tasks (threads). In one task you have your loop reading the I2S and putting the buffer you just read into a queue. In the other task you create the socket and connect to the server. Then it enters a loop reading from the queue of buffers that came from the I2S thread, and sending on the connected socket. If the wifi has enough throughput but pauses briefly because of dropped packets, the I2S keeps reading and sending to the queue. Depending on the nature of the wifi connection and how often it pauses, you can decide how many buffers that you need to not lose any data.

So for example, if you decide you need 20 1K buffers, you can allocate the 20K and put the buffers in a queue you call the pool. Then the I2s gets a 1K buffer from the pool, reads data into it, then puts that buffer into another queue you call data. The socket thread reads from the data queue, sends the data, then puts the buffer into the pool queue. The queues hold pointers to your buffers. I would allocate 20K and then break it up with 20 pointers to 1K segments. The pointers go into the pool queue on creation.

John A

ESP_Sprite
Posts: 8921
Joined: Thu Nov 26, 2015 4:08 am

Re: ADC glitchs - I2S - ESP32

Postby ESP_Sprite » Wed Aug 08, 2018 3:22 am

To be fair, you can get around the multithreading bit by increasing the size and amount of buffers the I2S driver has, as I mentioned before. This will effectively work as a lightweight buffering mechanism. But you do have to understand that you should open the connection once and then, in the loop, only send data to it and do nothing else there, because whatever you're doing in that loop is going to affect your throughput and give you dropouts. Note that I also saw you trying to dump the data to the UART; this also will not work because the UART is way slower than the I2S data rate.

Who is online

Users browsing this forum: No registered users and 112 guests