Interesting ESP32 issue: Can't use analogRead in ESP_WiFiManager Library

khoih-prog
Posts: 53
Joined: Sat Feb 22, 2020 8:16 pm

Interesting ESP32 issue: Can't use analogRead in ESP_WiFiManager Library

Postby khoih-prog » Tue Oct 20, 2020 11:45 pm

See already solved issue Not able to read analog port when using the autoconnect example in ESP_WiFiManager Library

The root cause of this issue is as follows

1. ESP32 has 2 ADCs, named ADC1 and ADC2

2. ESP32 ADCs functions

- ADC1 controls ADC function for pins GPIO32-GPIO39
- ADC2 controls ADC function for pins GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27

3.. ESP32 WiFi uses ADC2 for WiFi functions

- in order to use ADC2 for other functions, we have to acquire complicated firmware locks and very difficult to do
- It's not advisable to use ADC2 with WiFi

See in file adc_common.c
In ADC2, there're two locks used for different cases:
1. lock shared with app and Wi-Fi:
ESP32:
When Wi-Fi using the ADC2, we assume it will never stop, so app checks the lock and returns immediately if failed.
ESP32S2:
The controller's control over the ADC is determined by the arbiter. There is no need to control by lock.

2. lock shared between tasks:
when several tasks sharing the ADC2, we want to guarantee
all the requests will be handled.
Since conversions are short (about 31us), app returns the lock very soon,
we use a spinlock to stand there waiting to do conversions one by one.

adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock.
So it's suggested to use ADC1, and pins GPIO32-GPIO39

Please see the test results in Not able to read analog port when using the autoconnect example

khoih-prog
Posts: 53
Joined: Sat Feb 22, 2020 8:16 pm

Re: Interesting ESP32 issue: Can't use analogRead in ESP_WiFiManager Library

Postby khoih-prog » Wed Oct 21, 2020 12:43 am

This is the quick fix if somehow we must use those pins serviced by ADC2 (GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27) to work with ESP32 WiFi

Code: Select all

#if !( ESP32 || ESP8266 )
  #error This code is intended to run on the ESP32/ESP8266 platform! Please check your Tools->Board setting.
#endif

#define USE_MULTI_WIFI      true

#if ESP32
  #include <WiFi.h>
  #include <WiFiMulti.h>

  WiFiMulti wifiMulti;

  #define USE_ADC2      true
  //#define USE_ADC2      false

  #if USE_ADC2
    // ADC2 for GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27
    int sensorPin1   = 12;
    int sensorPin2   = 14;  
  #else
    // DC1 for GPIO032-GPIO39
    int sensorPin1   = 34;
    int sensorPin2   = 35;
  #endif
  
  // Kludge to fix ADC2 + WiFi
  #include "soc/sens_reg.h"    // needed for manipulating ADC2 control register
  uint64_t reg_b;             // Used to store ADC2 control register
  //////
  
#elif ESP8266
  #include <ESP8266WiFi.h>
  #include <ESP8266WiFiMulti.h>

  ESP8266WiFiMulti wifiMulti;
  
  int sensorPin1    = 12;     // select the input pin for the potentiometer
  int sensorPin2    = 13;     // select the input pin for the potentiometer
#endif

#define SSID_MAX_LEN      32
#define PASS_MAX_LEN      64

typedef struct
{
  char ssid[SSID_MAX_LEN + 1];
  char pass[PASS_MAX_LEN + 1];
}  WiFi_Credentials;

WiFi_Credentials WiFi_Creds[] =
{
  { "HueNet1", "12345678"},
  { "HueNet2", "12345678"},
  { "HueNet3", "12345678"}
};

#define NUMBER_SSIDS    ( sizeof(WiFi_Creds) / sizeof(WiFi_Credentials) )

uint8_t status;


int sensorValue = 0;            // variable to store the value coming from the sensor

uint8_t connectMultiWiFi(void)
{
  Serial.println("\nConnecting Wifi...");

  int i = 0;
  status = wifiMulti.run();
  delay(3000);

  while ( ( i++ < 10 ) && ( status != WL_CONNECTED ) )
  {
    status = wifiMulti.run();

    if ( status == WL_CONNECTED )
      break;
    else
      delay(3000);
  }

  if ( status == WL_CONNECTED )
  {
    Serial.println("WiFi connected to after " + String(i) + " times.");
    Serial.println("SSID = " + WiFi.SSID());
    Serial.println("RSSI = " + String(WiFi.RSSI()));
    Serial.println("Channel: " + String(WiFi.channel()));
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }
  else
    Serial.println("WiFi not connected");

  return status;
}

void check_WiFi(void)
{
  if ( (WiFi.status() != WL_CONNECTED) )
  {
    Serial.println("\nWiFi lost. Call connectMultiWiFi in loop");
    connectMultiWiFi();
  }
}

#if (ESP32 && USE_ADC2)
void save_ADC_Reg(void)
{
  // Save ADC2 control register value : Do this before begin Wifi/Bluetooth
  reg_b = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG);
}

void restore_ADC_Reg(void)
{
  // ADC2 control register restoring 
  WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, reg_b);
  SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
}
#endif

void readAnalog(void)
{
#if (ESP32 && USE_ADC2) 
  restore_ADC_Reg();
#endif
  
  sensorValue = analogRead(sensorPin1);
  Serial.print("Pin " + String(sensorPin1) + " = ");
  Serial.println(sensorValue);

  sensorValue = analogRead(sensorPin2);
  Serial.print("Pin " + String(sensorPin2) + " = ");
  Serial.println(sensorValue);
}

void check_status(void)
{
  static ulong checkstatus_timeout  = 0;
  static ulong checkwifi_timeout    = 0;

  static ulong current_millis;

#define WIFICHECK_INTERVAL    1000L
#define ANALOGREAD_INTERVAL   2000L

  current_millis = millis();

#if USE_MULTI_WIFI
  // Check WiFi every WIFICHECK_INTERVAL (1) seconds.
  if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0))
  {
    //check_WiFi();
    checkwifi_timeout = current_millis + WIFICHECK_INTERVAL;
  }
#endif

  // Print hearbeat every ANALOGREAD_INTERVAL (2) seconds.
  if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0))
  {
    readAnalog();
    checkstatus_timeout = current_millis + ANALOGREAD_INTERVAL;
  }
}

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial);

  delay(200);

  Serial.print("\nStarting WiFiMulti_ESP32_AnalogRead on ");
  Serial.println(ARDUINO_BOARD);

#if (ESP32 && USE_ADC2)
  save_ADC_Reg();
#endif  

#if USE_MULTI_WIFI
  for (int i = 0; i < NUMBER_SSIDS; i++)
  {
    wifiMulti.addAP(WiFi_Creds[i].ssid, WiFi_Creds[i].pass);
  }

  connectMultiWiFi();
#endif
  
}

void loop()
{
  // put your main code here, to run repeatedly
  check_status();
}
and this is the terminal output when using in sketch

Code: Select all

#define USE_ADC2 true

Code: Select all

Starting WiFiMulti_ESP32_AnalogRead on ESP32_DEV

Connecting Wifi...
WiFi connected to after 1 times.
SSID = HueNet1
RSSI = -40
Channel: 2
IP address: 192.168.2.164
Pin 12 = 24
Pin 14 = 20
Pin 12 = 67
Pin 14 = 68
Pin 12 = 17
Pin 14 = 16
Pin 12 = 54
Pin 14 = 81
Pin 12 = 119
Pin 14 = 17
Pin 12 = 51
Pin 14 = 69
Pin 12 = 20
Pin 14 = 5
Pin 12 = 20
Pin 14 = 82
Pin 12 = 36
Pin 14 = 14
Pin 12 = 32
Pin 14 = 22
Pin 12 = 81
Pin 14 = 35
Pin 12 = 83
Pin 14 = 66
Pin 12 = 32
Pin 14 = 26
Pin 12 = 105
Pin 14 = 85
Pin 12 = 80
Pin 14 = 102
Pin 12 = 74


Who is online

Users browsing this forum: No registered users and 13 guests