Why does my level meter suck so hard? (ESP32, FastLED)

The ESP32 unit I’m using says WROOM 32 on it; I have “ESP32-WROOM-DA Module” selected in the Arduino IDE. I have a string of 200 RGBA LEDs wrapped around a tube, so that I have two rows of 100 LEDs, which I’ve split into two groups (I’m sure there’s a much easier way to declare those arrays, but I seem to be a dunce when it comes to learning how to code). Anyway, I doubt that’s causing my problems here. First problem is that my A/Ds are giving me nothing half the time, even when I’m feeding them a constant sine wave at 440Hz. My code includes some lines to print millis and the raw values coming from the A/Ds, and this is what it looks like:

6912 0 0
6918 243 202
6924 396 411
6931 43 145
6937 0 0
6944 0 0
6950 0 0
6956 376 336
6963 271 351
6969 0 0
6976 0 0
6982 0 0
6989 201 112
6995 396 407
7001 110 203
7008 0 0
7014 0 0
7021 0 0
7027 356 304
7033 325 380
7040 0 0
7046 0 0

The second problem is really baking my noodle too, but I have a feeling someone might just tell me I’m using the wrong pins or something; when it gets a signal in the left channel it sees a signal in both channels; when it gets a signal in the right channel it sees a signal in the right channel; when it gets a signal in both channels it only sees a signal in the left channel! Aargh! Doing my head in.

Here’s my pathetic code:

#include <FastLED.h>
#define NUM_LEDS 200 
#define DATA_PIN 15
CRGB leds[NUM_LEDS];
byte grp0[] = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198};
byte grp1[] = {1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199};

void setup() { 
	Serial.begin(115200);
	FastLED.addLeds<WS2812,DATA_PIN,BGR>(leds,NUM_LEDS);
	FastLED.setBrightness(127);
}

void loop() {
  int LInLev = analogRead(25);
  int RInLev = analogRead(26);
  int sens = 99; // min 99
  int LLev = map(LInLev, 0, 1023, 0, sens); 
  int RLev = map(RInLev, 0, 1023, 0, sens);
  fill_solid(leds, NUM_LEDS, CRGB::Black);
  for (int iL = 0; iL < LLev; iL++) {
    leds[grp0[iL]] = CRGB::Red;
  }
  for (int iR = 0; iR < RLev; iR++) {
    leds[grp1[iR]] = CRGB::Green;
  }
  FastLED.show();
  int tme = millis();
  Serial.print(tme);
  Serial.print("\t");
  Serial.print(LInLev);
  Serial.print("\t");
  Serial.println(RInLev);
}

The poxy red and green is just for testing; I’m planning on something a bit fancier than that, but the damn thing has to work first. If anyone can tell me where I’m going wrong, that would be greatly appreciated :slight_smile:

1 Like

Your 440Hz sine wave will be above zero half the time and below zero for the other half, so the values you have listed look roughly correct. You should explain what you were expecting to see from a sine wave fed to a A/D converter: in particular the reference voltage you are using, the signal level of the sine wave, and what that level is referenced to.

1 Like

The input is just a headphone plug into my phone; couldn’t say what the signal level is, other than what you’d expect from that source. I have no idea what you mean by reference voltage, or “what that level is referenced to”.

I’d expect a sound of constant volume to give me a more or less constant value; the crucial bit of this code is just whatever I could find on the web by searching “LED VU meter” and so on. 440Hz goes past 0 every 1.14 milliseconds, and my program is only looping every 6-7 milliseconds… Is it perhaps that it’s just reporting an instantaneous value of where that sine wave happens to be when the analogRead line loops past? It’s a bit different if I give it 12kHz (and remember, this is just the left channel which gives me a signal on both inputs for some weird reason):

17586 0 0
17593 373 0
17599 209 69
17606 0 320
17612 0 0
17618 404 0
17625 0 336
17631 0 215

It also flashes black half the time when I feed it music. This is not how a level meter is supposed to work…

Do I need to run each signal through a capacitor or something? There was no mention of such a thing in any of the how-tos I dug up.

1 Like

Using an ADC to read the signal directly means that the reading you take does not necessarily relate to any particular part of the signal.

A signal level meter will usually show the maximum level. This uses a sample and hold circuit configured as a peak detector. The ADC then reads the signal from the sample and hold circuit at a rate that is less than or equal to the sample period. You could take lots of readings over a longer period (say, 10 times the maximum frequency) and assume that the highest reading was also the highest signal value. Similarly you could take readings over an extended period and average them, assuming that the readings were fairly distributed within the signal levels. In each case the accuracy would be very dependent on the signal type: a steady 440Hz signal would give good accuracy over a period of say 3 times the frequency, but for a phone audio signal a longer period would be required, and you might still completely miss significant peaks.

Your ADC will not read signals levels below 0V, so your analysis will be restricted to the positive-going part of the signal. That’s not a problem when calculating a maximum, but you need to allow for it if calculating an average.

It is difficult to comment on the channel oddity without knowing how everything is connected up, but the likelihood is that there is a ground issue.

3 Likes

I just have the common wire going to a ground pin on the ESP32, and the left wire to pin 25, and the right one to pin 26. It’s very strange…

You haven’t indicated what device you are getting this signal from or how you are connecting it. Have you confirmed that the two channels are correct by listening with an audio input device, such as a small powered speaker? Some devices will configure the channels according to the device that they think is plugged in, including putting both channels to one output if they think it is a single speaker.

From memory pins 25 and 26 are adc 2, which cant be used with wifi. Do you have wifi or bluetooth enabled?