analog microphone/Reading it/08. Reading it on an ESP32
Reading it · 08 of 10

Reading it on an ESP32

An ESP32 reads in finer steps than an Uno, about 0.7 mV to the Uno's 4.9, but its readings also wander further on their own. What decides whether a sound can be told from nothing is the swing against that wander, so measure the quiet swing at start-up and count only what rises above it. Use an ADC1 pin, and VCC from 3V3.

Finer steps, more wander

An Uno's converter turns 0 to 5 V into 1024 steps, about 4.9 mV each. An ESP32's turns its range, about 0.1 to 3.1 V at the Arduino core's default setting, into 4096 steps, about 0.7 mV each. So the same swing is roughly seven times as many counts on an ESP32.

That would make an ESP32 the better ear, except that its readings wander on their own. Read a pin whose voltage is perfectly still and an Uno returns the same count, give or take one; an ESP32 commonly scatters over a few tens of counts. Tens of counts of 0.7 mV is tens of millivolts, several times the Uno's wander.

The same sound on four boards
Sound
Swing from 3V3
14 mV
Uno, from 5V
3 counts
ESP32
19 counts
No board can tell this from silence. The swing is inside the band every board's readings wander over on their own. This block is for loud sounds, and this is not one.

Pick a sound. Each row is one board, with VCC on its own logic supply: the bar is the swing the sound makes, the grey band how far that board's readings wander with no sound at all. Both the sound sizes and the wander are illustrative, not measured. Talking a metre away is inside every board's band; a raised voice close by is clear of all of them.

Measure the quiet swing

The cure is the same on every board, so the sketch does it on every board. For one quiet second at start-up it measures the swing window after window and keeps the biggest. That is the quiet swing: the converter's own wander plus whatever the room is doing. After that it prints each window's swing and how far it rises above the quiet one.

A threshold set this way fits the board it runs on. On an Uno it lands around ten millivolts, on an ESP32 at a few tens, and neither sketch needs to know which board it is on. A clap switch puts its threshold a fixed margin above it.

Millivolts, 3V3 and ADC1

The sketch reads millivolts. On an ESP32 analogReadMilliVolts converts the count with calibration written into the chip at the factory; on an Uno or a Pico the count is scaled by the converter's full scale.

VCC comes from 3V3. From 5V the resting level would be higher and the gain higher too, but a loud sound would drive SIGNAL to 5 V, over what an ESP32's pin is rated for.

And SIGNAL goes to an ADC1 pin: GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3. The classic ESP32's other converter, ADC2, is shared with the radio and fails while Wi-Fi is on.

The code

Measures the quiet swing first: the biggest peak-to-peak it sees in a second of silence. Then it prints each 50 ms window's swing and how far it rises above the quiet one. Works on every board; it matters most on an ESP32.

mic_above_quiet.ino
/*
  Analog Microphone - above the quiet swing             TK27 / /p/tk27

  Wiring. Count from the square pad on the TinkerBlock board, parts
  up, header at the bottom:

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
              ESP32-S3, GP26 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The analog pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int MIC_PIN = A0;

// Uno and Pico only: the ADC's full scale, in mV.
// Uno: 5000. Pico: 3300.
const float FULL_SCALE_MV = 5000.0;
const unsigned long WINDOW_MS = 50;
const unsigned long CALIBRATE_MS = 1000;

float quietMv;

float readMilliVolts() {
#if defined(ARDUINO_ARCH_ESP32)
  return analogReadMilliVolts(MIC_PIN);   // calibrated in the chip
#else
  return analogRead(MIC_PIN) * FULL_SCALE_MV / 1023.0;
#endif
}

// Highest minus lowest over one window, in mV.
float swingMilliVolts() {
  float lo = 100000;
  float hi = -1;
  unsigned long start = millis();
  while (millis() - start < WINDOW_MS) {
    float mv = readMilliVolts();
    if (mv < lo) lo = mv;
    if (mv > hi) hi = mv;
  }
  return hi - lo;
}

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("Measuring the quiet swing. Keep quiet...");
  quietMv = 0;
  unsigned long start = millis();
  while (millis() - start < CALIBRATE_MS) {
    float s = swingMilliVolts();
    if (s > quietMv) quietMv = s;   // keep the biggest
  }
  Serial.print("Quiet swing ");
  Serial.print(quietMv, 0);
  Serial.println(" mV");
}

void loop() {
  float swing = swingMilliVolts();
  float above = swing - quietMv;   // what the room adds

  Serial.print("swing ");
  Serial.print(swing, 0);
  Serial.print(" mV, above quiet ");
  Serial.println(above > 0 ? above : 0, 0);
}

Keep quiet for the first second, or the quiet swing will include your noise and the sketch will ignore it too. On an ESP32 expect a quiet swing of tens of millivolts; on an Uno, ten or so.

When it does not work

The quiet swing is tens of millivolts on my ESP32.

Typical. An ESP32's ADC wanders by a few tens of counts from reading to reading with nothing changing, and each count is under a millivolt. A USB lead that also powers other things can add hum. The sketch measures it so it can ignore it; nothing needs fixing unless it is hundreds of millivolts.

It worked until I turned Wi-Fi on.

SIGNAL is on an ADC2 pin. On the classic ESP32 the radio uses ADC2 while Wi-Fi is on, and readings from it fail or return rubbish. Move SIGNAL to an ADC1 pin: GPIO 34 here, or any of GPIO 32 to 39.

analogReadMilliVolts does not compile.

It is part of Espressif's ESP32 Arduino core, in the 2.x and 3.x releases. Update the core in the Boards Manager. On an Uno or a Pico the sketch never calls it: the #if sends them down the analogRead path.

Should I power it from 5V on an ESP32 for more gain?

No. From 5V a loud sound takes SIGNAL up to 5 V, and the ESP32's pins are rated for 3.3 V. Use 3V3. The gain is lower than from 5V, which costs sensitivity to quiet sounds, and this block is for loud ones anyway.

Where this goes next

A TK01 that toggles on a clap, and ignores the clap's own echo.

A clap switch

Edit this page — content/books/analog-microphone/reading-it-on-an-esp32.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Analog Microphone

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum