Esp-idf: DMA ADC Fails On Connection to AP when in STA (station) mode (IDFGH-239) (IDFGH-1442)

Created on 30 Jun 2019  路  27Comments  路  Source: espressif/esp-idf

This is a duplicate of #1977. It appears that has been open for over a year.

Development Kit: Platform IO
Kit version (for WroverKit/PicoKit/DevKitC): v3.1-dev-661-gf586f5e6
Core (if using chip or module): ESP32 Lolin
IDF version v3.1-dev-661-gf586f5e6
Development Env: VS Code + PlatformIO
Operating System: Windows
Power Supply: USB

Platform Espressif 32 (Stage)

Updating espressif32 @ 29b3a81
Updating tool-esptoolpy @ 1.20100.0
Updating framework-arduinoespressif32 @ 6826508
Updating tool-espotapy @ 1.1.0
Problem Description

When acquiring ADC data through DMA transfers and the device is in station mode (WIFI_MODE_STA). As the device connects to the AP, the ADC DMA buffer ceases to show valid data and continues to read (a probably random) fixed value.

This does not happen in WIFI_MODE_AP or WIFI_MODE_APSTA
Expected Behavior

The ADC should continue to read valid data.
Actual Behavior

C00, F06, 3E6, 7E8, 0, 2D, 604, 22F, DFF, A84, F84, FE0, 8D2, CF2, FE, 4E1, 18E, 0, 93A, 518, F94, D2C, 9F0, FF0, 21F, 5CA, 66, 0, 84C, 430, F38, C62, E7C, FF0, 6C3,
B00, 0, 300, 34E, 0, B80, 748, FFC, EB0, C00, F00, 3AF, 7A6, 0, E, 670, 27E, E12, A8F, F80, FE0, 8DC, CB1, D5, 49E, 168, 0, 964, 580,
0, 9D, 5C0, 20C, DC0, 9FF, FC7, FCF, 900, D27, 160, 500, 11C, 0, 900, 4CE, F8D, D0F, DE2, FD4, 5E9, A45, 0, 218, 3EF, 3F, C38, 7FF, FFD, F1E, B03, EA7, 300, 71A, 0, 0, 700, 302, E8E, B48, F00, FFE, 7E6, C12, 33, 3FE, 22B, 0, A6E, 60F, FE0, DE0, CFF, F86, 4D8, 90A, 0, 104, 509, 14E, D22, 931, FA4, F92,
160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,

Steps to repropduce

Start WiFi.
Start ADC acquisition.
Wait for device to connect to AP.

Code to reproduce this issue

include

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 "WiFi.h"

include "dac_cosine.h"

define TAG "adc_i2s"

// Physically connect pins 25 and 34

uint32_t SAMPLE_RATE = 120E3;
uint32_t NUM_SAMPLES = 64;
uint32_t SIGNAL_FREQ = 10E3;

define WIFICLIENT_SSID ("MYAP")

define WIFICLIENT_PWD ("1234567")

define WIFISERVER_SSID ("MYDAQ")

define WIFISERVER_PWD ("1234567")

IPAddress local_IP(192,168,4,22);
IPAddress gateway(192,168,4,22);
IPAddress subnet(255,255,255,0);

static QueueHandle_t i2s_event_queue;
static EventGroupHandle_t wifi_event_group;

void WiFiEvent(WiFiEvent_t event)
{
switch(event) {
case SYSTEM_EVENT_STA_GOT_IP:{
Serial.println();
Serial.println("CONNECTED");
Serial.println();
break;
}
default:{
break;
}
} // switch
} // WiFiEvent

void setup(){
Serial.begin(921600);
WiFi.onEvent(WiFiEvent);
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(WIFICLIENT_SSID, WIFICLIENT_PWD);

i2s_config_t i2s_config ;
i2s_config.mode =  i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN);
i2s_config.sample_rate = SAMPLE_RATE;                           // 120 KHz
i2s_config.dma_buf_len = NUM_SAMPLES;                           // 512
i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;         // Should be mono but doesn't seem to be
i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
i2s_config.use_apll = true,
i2s_config.fixed_mclk = SAMPLE_RATE;
i2s_config.communication_format = I2S_COMM_FORMAT_I2S;
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
i2s_config.dma_buf_count = 2;
//install and start i2s driver
i2s_driver_install(I2S_NUM_0, &i2s_config, 1, &i2s_event_queue);
// Connect ADC to I2S
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_6);

// Generate test signal
int step = nearbyint(0.008192 * SIGNAL_FREQ);       // ~10kHz
dac_cosine_enable(DAC_CHANNEL_1);                   // enable the generator
dac_frequency_set(0, step);                         // frequency setting is common to both channels
dac_scale_set(DAC_CHANNEL_1, 0);                    // No scaling (0~3.7v)
dac_offset_set(DAC_CHANNEL_1, 0);                   // No Offest
dac_invert_set(DAC_CHANNEL_1, 2);                   // Sinewave
dac_output_enable(DAC_CHANNEL_1);                   // Start DAC

i2s_adc_enable(I2S_NUM_0);                          // Start ADC

}

void loop(){
uint16_t i2s_read_buff[NUM_SAMPLES];
system_event_t evt;
if (xQueueReceive(i2s_event_queue, &evt, portMAX_DELAY) == pdPASS) {
if (evt.event_id==2) {
i2s_read_bytes(I2S_NUM_0, (char*)i2s_read_buff, NUM_SAMPLES * 2, portMAX_DELAY);
for (int i=0;i Serial.printf("%X, ", i2s_read_buff[i] & 0xFFF);
}
Serial.println();
}
}
}

Most helpful comment

@mishafarms thanks, I am able to reproduce. However adding one thing seems to resolve it:
esp_wifi_set_ps(WIFI_PS_NONE);
So wifi powersave is the problem

All 27 comments

I would like to know as well. Spent well over a week trying to get ADC1 working before finding these threads.
ADC1 stops as soon as doing _esp_wifi_connect()_.
It works if I do an _esp_wifi_disconnect()_ before _i2s_read()_.
Feels so odd that the datasheet claims a high performance ADC, but you cannot really use it.
I also like to get the pattern table running because I need several channels at high speed, but haven't got it to work.

What did you do to get the pattern table working? I got it to work by removing the static in front of the 2 functions in the file in the esp-idf/components/driver/rtc_module.c and added the declaration into esp-idf/components/driver/include/driver/adc.h

esp_err_t adc_set_i2s_data_len(adc_unit_t adc_unit, int patt_len);
esp_err_t adc_set_i2s_data_pattern(adc_unit_t adc_unit, int seq_num, adc_channel_t channel, adc_bits_width_t bits, adc_atten_t atten);

I then call these functions in my code.
// add second channel
adc_set_i2s_data_pattern(I2S_ADC_UNIT, 1, I2S_ADC_CHANNEL2, ADC_WIDTH_12Bit, ADC_ATTEN_11db);
adc_set_i2s_data_len(I2S_ADC_UNIT, 2);

I then got the data interleaved. You have to double the sample rate for 2 channels.

I think there is some way to copy the driver files into your components directory and not modify the
released version, But I haven't gotten that to work yet.
Michael

Re. pattern table usage, you might be interested in the example code I posted from issue #3263 . @mishafarms did you get a problem with weird channel ordering (like 5, 5, 6, 6, 5, 6, 6)?

Re. ADC issues, I notice you're using the APLL, and you might be running into the issue I found here (APLL cannot be used while using the I2S direct-from-ADC mode): #3692 .

Re. the ADC issue itself, I dimly remember that one of the ADC modules is incompatible with the wifi module being enabled, but I'll have to dig that up.

Oh, it was ADC2 and you're using ADC1, so it's probably not that. From here:

ADC2 is used by the Wi-Fi driver. Therefore the application can only use ADC2 when the Wi-Fi driver has not started.

I tried disabling APLL, no change.

I did not see any weird channel ordering.

Michael

@michafarms I suspect you might not really be using the APLL in your posted code anyway. The fixed_mclk is set to your sample rate, which is far higher than the MCLK value is allowed to be. The code in the RTC module will fall back to the PLL D2, and the only sign of this will be a debug line that looks like:

I (3484) I2S: PLL_D2: Req RATE: 

@mishafarms It seems like we're working with similar features. I'm totally unable to get the channel ordering/pattern table working though. If you have a few minutes, do you think you could build and run the project here and see if you get the same bug I do? It would be a huge help just to have another data point for this.

ADC1 pattern table! => SOLVED
ADC1 + WiFi => SOLVED (disable WiFi power save, not included in my example)

I finally got the ADC1 pattern tables to work, but not with WiFi connected.
I use DevKitC with ESP32-WROVER-B, 240MHz.
Please see provided code which I tried to add a lot of comments in.
You can choose whether to turn WiFi on/off, or disconnect before starting I2S ADC1 DMA.
It doesn't matter if you initialise I2S before or after Wifi, or if running WiFi on PRO_CPU and I2S on APP_CPU.

Sample rate can be from 5kHz up to 1.3MHz!
ESP32 Datasheet 4.1.2 says max 2Msps (not sure how to get there).
Have not checked if output rate gets divided by number of channels (probably does).

I also tried starting WiFi after _i2s_adc_enable();_ but before _i2s_read();_ . It doesn't help.

Sample output from channel 0, 3, 6, 7, looks like this:
I (23161) ADC/DAC: 6a 07 a7 75 67 69 56 3a 67 07 a7 75 6b 69 51 3a
Chan[n] : ADC raw; [0] : 076a, [3] : 0a56, [6] : 0967, [7] : 05a7

The full code...
Copy your ESP_IDF example structure:

examples\peripherals\i2s_adc_dac\main\app_main.c

and replace everything in _app_main.c_ with this:
i2s_adc_dac.zip
Or delete app_main.c and rename this to app_main.c

That is great.

I wish someone would look at the original issue.

Michael

All, I want to jump in here, I have exactly the same. All is running, then as soon as STA connects it stops, keeping the existing value in all entries...

Running @giPeteR example connected to STA I am getting changing ADC raw values. This is on fairly recent master branch.

Hi,
I think this is the same issue as #1333, we fixed it on ESP-IDF(update rtc library on the master), but I'm not sure if this fix has been applied to the arduino project. Another solution to this issue is to initialize the ADC after WIFI initialization and connection.

thanks!!

Guys this is not the same, and I am not running on Arduino. I have tried to initialise the ADC after WIFI and before WIFI and I get the same results.

I also am NOT using the Arduino. I am using a single channel. I am on the master branch of esp-idf.
It doesn't seem to matter the order that you initialize.

I think that this is still an issue.
Michael

@mishafarms can you reproduce with the example given by giPeteR above? What settings necessary to reproduce?

@negativekelvin I just ran giPeteR's code and it works. I get all the channels data.
But when I enable the Wifi it fails. It does not even print out all the
channels anymore.

If you put this code in the app_main function.

while(1)
{
    vTaskDelay(10000 / portTICK_PERIOD_MS);
    skip_connect = 0;
    esp_wifi_connect();
}

You get the correct data for about 5 samples and then
when it reconnects to the Wifi it fails. Here is the output from my test.

I (10996) ADC/DAC: 79 07 7e 07 ce 60 98 30 7d 07 7f 70 c0 60 cb 30
Chan[n] : ADC raw [0] : 077e [3] : 0098 [6] : 00ce

I (12006) ADC/DAC: 7f 07 30 70 80 61 e3 33 7e 07 31 70 80 61 e3 33
Chan[n] : ADC raw [0] : 077f [3] : 03e3 [6] : 0180 [7] : 0030

I (13006) ADC/DAC: 80 07 4f 70 8f 61 f2 33 7f 07 4f 70 8f 61 f0 33
Chan[n] : ADC raw [0] : 0780 [3] : 03f2 [6] : 018f [7] : 004f

I (14006) ADC/DAC: 7e 07 62 70 93 61 fa 33 7f 07 62 70 96 61 fa 33
Chan[n] : ADC raw [0] : 077e [3] : 03fa [6] : 0193 [7] : 0062

I (15006) ADC/DAC: 7d 07 31 70 71 61 e1 33 80 07 32 70 70 61 e0 33
Chan[n] : ADC raw [0] : 077d [3] : 03e1 [6] : 0171 [7] : 0031

I (16006) ADC/DAC: e7 33 e7 33 e7 33 e7 33 e7 33 e7 33 e7 33 e7 33
Chan[n] : ADC raw [3] : 03e7

I (16506) tcpip_adapter: sta ip: 192.168.252.140, mask: 255.255.255.192, gw: 192.168.252.129
I (16506) wifi station: got ip:192.168.252.140
I (17006) ADC/DAC: e7 33 e7 33 e7 33 e7 33 e7 33 e7 33 e7 33 e7 33
Chan[n] : ADC raw [3] : 03e7

I (18006) ADC/DAC: e7 33 e7 33 e7 33 e7 33 e7 33 e7 33 e7 33 e7 33
Chan[n] : ADC raw [3] : 03e7

You can see at first we get all the channels and then once Wifi is re-established, we stop reading
data from the ADC.
Michael

@mishafarms thanks, I am able to reproduce. However adding one thing seems to resolve it:
esp_wifi_set_ps(WIFI_PS_NONE);
So wifi powersave is the problem

@negativekelvin You have found a workaround. Thank you. I think I can live without
powersave.

Michael

When using WIFI, if the power saving mode is not used, the SAR power domain will be turned off when entering the power saving mode to reduce power consumption. This is the root cause of this problem. The current solution is to set WIFI to WIFI_PS_NONE mode.

I think you mean

When using WIFI, if the power saving mode is not used, the SAR power domain will be turned off when entering the power saving mode to reduce power consumption.

So will there be a way for the user app to take a lock to prevent this while still using powersave?

Yes, we will implement this.

@negativekelvin
Yes, as you said, I made the logic wrong : b
Correct it:
_When using WIFI, if the power saving mode is used, the SAR power domain will be turned off when entering the power saving mode to reduce power consumption._

Thank you guys, we will implement this workaround asap!

@negativekelvin
...adding one thing seems to resolve it:
esp_wifi_set_ps(WIFI_PS_NONE);

THANKS! Now everything works.
I know I turned off power save for ADC and I2S, but obviously WiFi rules them all :(
It seems you have to put esp_wifi_set_ps(WIFI_PS_NONE); right after esp_wifi_init() but before i2s_init(). Meaning, you cannot start or init I2S before WiFi.

(I wonder what happens at a reconnect? Will it remember WIFI_PS_NONE?)

@negativekelvin I also encountered this problem, using your solution esp_wifi_set_ps(WIFI_PS_NONE);, the DMA ADC can read the normal value without restarting the device.
However, after executing esp_restart();, the device DMA ADC is read-only to a zero value.
And I reset the device by ESP32 reset IO, then the result is normal.

ESP-IDF Version: v4.1-dev-815-ga45e998-dirty
Development Kit: ESP32-DevKitC
Operating System: Ubuntu 14.04 x86_64
Power Supply: USB

The full code
Copy your ESP_IDF example structure:
examples\peripherals\i2s_adc_dac\main\app_main.c
and replace everything in app_main.c with this:
app_main.zip

@mishafarms https://github.com/espressif/esp-idf/issues/3973 has been fixed, would you please help try the fix mentioned in there? Thanks.

Was this page helpful?
0 / 5 - 0 ratings