Arduino to ESP32

I have some frequency detection code (guitar tuner) that works on a Nano. I bought an ESP32 with a built in OLED thinking I could get that working, but isn't not so simple. As I understand it, the ADC sampling stuff is different.

So I need advice. I don't have the programming chops to write my own ESP32 ADC code. And I can't find an arduino that has a built in OLED/screen.

What are my options?

Start by posting your sketch for the ESP32 that you are having trouble with

Compiler is struggling with the ADC stuff, when connected to esp32

#define sampleFrequency 9615.4
#define bufferSize 1024

volatile byte  rawData[bufferSize] ;  // Buffer for ADC capture
volatile int sampleCnt ;                    // Pointer to ADC capture buffer
long currentSum, previousSum, twoPreviousSum ;
int threshold = 0;
float frequency = 0;
byte pdState = 0;

void setup() {

  Serial.begin(115200) ;
  pinMode(LED_BUILTIN, OUTPUT);
  cli();//disable interrupts

  //set up continuous sampling of analog pin 0
  //clear ADCSRA and ADCSRB registers
  ADCSRA = 0 ;
  ADCSRB = 0 ;

  ADMUX |= (1 << REFS0) ; //set reference voltage
  ADMUX |= (1 << ADLAR) ; //left align the ADC value- so we can read highest 8 bits from ADCH register only

  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // ADC clock 128 prescaler- 16mHz/128=125kHz->9615 sps
  ADCSRA |= (1 << ADATE); //enable auto trigger
  ADCSRA |= (1 << ADIE) ; //enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN) ; //enable ADC
  ADCSRA |= (1 << ADSC) ; //start ADC measurements
}

ISR(ADC_vect) {     // When ADC sample ready, put in buffer if not full
  if (sampleCnt < bufferSize)
  {
    rawData[sampleCnt] = ADCH ;
    sampleCnt++ ;
  }
}

void readData() {
  sampleCnt = 0 ;
  sei() ;         // Enable interrupts, samples placed in buffer by ISR
  while (sampleCnt < bufferSize) ;  // Spin until buffer is full
  cli() ;         // Disable interrupts
}

void findFrequency() {
  // Calculate mean to remove DC offset
  long meanSum = 0 ;
  for (int k = 0; k < bufferSize; k++) {
    meanSum += rawData[k] ;
  }
  char mean = meanSum / bufferSize ;
  // Remove mean
  for (int k = 0; k < bufferSize; k++) {
    rawData[k] -= mean ;
  }

  // Autocorrelation
  currentSum = 0 ;
  pdState = 0 ;
  for (int i = 0; i < bufferSize && (pdState != 3); i++) {
    // Autocorrelation
    float period = 0 ;
    twoPreviousSum = previousSum ;
    previousSum = currentSum ;
    currentSum = 0 ;
    for (int k = 0; k < bufferSize - i; k++) {
      currentSum += char(rawData[k]) * char(rawData[k + i]) ;
    }
    // Peak detection
    switch (pdState) {
      case 0:   // Set threshold based on zero lag autocorrelation
        threshold = currentSum / 2 ;
        pdState = 1 ;
        break ;
      case 1:   // Look for over threshold and increasing
        if ((currentSum > threshold) && (currentSum - previousSum) > 0) pdState = 2 ;
        break ;
      case 2:   // Look for decreasing (past peak over threshold)
        if ((currentSum - previousSum) <= 0) {
          // quadratic interpolation
          float interpolationValue = 0.5 * (currentSum - twoPreviousSum) / (2 * previousSum - twoPreviousSum - currentSum) ;
          period = i - 1 + interpolationValue ;
          pdState = 3 ;
        }
        break ;
      default:
        pdState = 3 ;
        break ;
    }

    // Frequency identified in Hz
    if (threshold > 100) {
      frequency = sampleFrequency / period;
      if (frequency < 400) {
        Serial.println(frequency);
        Serial.println("");
      }
    }
  }
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  readData();
  digitalWrite(LED_BUILTIN, LOW);
  findFrequency();
}

Here's a video of it working on a nano.

It is no wonder that the code does not work on an ESP32 because it contains a mass of code that is specific to AVR chip registers

I am afraid that I do not know enough about ESP32 registers to help

1 Like

try using analogRead(GPIO), e.g. have a look at esp32-adc-analog-read
you could then look at ESP32 Analog to Digital Converter (ADC) Continuous Mode Driver

Why do you absolutely need a board with a built-in screen? It seems to me that in your situation an excellent solution would be to buy the OLED separately and connect it to the Nano by wires. In this case, you will not need to rewrite the rather complex code for ADC, but only add code for Oled. It's easier, since there are many examples on the Internet.

1 Like

Please, post the picture of your ESP32 containing onBoard OLED.

Could you perhaps start again using an approach designed for the esp32?

1 Like

https://a.co/d/gd4qUjp

That one uses FFT, I’ll try it. The 2 I’ve got working on a nano used the zero-crossings and autocorrelation methods. Autocorrelation works pretty well. Theoretically FFT is more processor intensive.

You’re right about the built in screen. I have a teensy too, my nano code should work in it too. Coding a separate screen might be best.

You probably meant to say "my nano code won’t work in it either" ?

When transferring code from nano to teensy, you will encounter exactly the same problems as when moving to ESP32. In general, switching to any controller other than AVR (Nano, Uno, Mega) will require serious code rewriting.
Unless you're a very experienced programmer, your best bet is to stay with the Nano, and add a display to it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.