Electronic – ESP32 Sample a 1kHz square wave (10%-90% duty cycle) with analogRead()

adcesp32interruptspwm

I need to sample the peak voltage of a 1kHz square wave. The duty cycle varies between 10% and 90%. I am using an ESP32 and hoped to use analogRead() to sample the data.

My first idea was to attach an interrupt to a digital pin being fed the square wave. It seems that the analog read only sometimes happens on time. The first signal in this image is the input signal at roughly 50% duty cycle. The second is the start and end of the analog read:

  digitalWrite(32, HIGH);
  int level = analogRead(CP_READ);
  digitalWrite(32, LOW);

enter image description here

As you can see, the reads sometimes occur after the falling edge of the input signal even though the interrupt was attached to RISING. Curously, setting it to FALLING yields exactly the same result as above. Also, it doesn't even seem to trigger on each rising/falling edge. As you can see, it skips 2 pulses…

Here is a small sample of the output:

Current CP voltage level is: 4095
Current CP voltage level is: 2925
Current CP voltage level is: 955
Current CP voltage level is: 3687
Current CP voltage level is: 1344
Current CP voltage level is: 0
Current CP voltage level is: 4095
Current CP voltage level is: 4095
Current CP voltage level is: 4095
Current CP voltage level is: 4095
Current CP voltage level is: 3149
Current CP voltage level is: 1044
Current CP voltage level is: 0
Current CP voltage level is: 4095
Current CP voltage level is: 4095
Current CP voltage level is: 4095
Current CP voltage level is: 4095
Current CP voltage level is: 2737
Current CP voltage level is: 784
Current CP voltage level is: 3423
Current CP voltage level is: 1198
Current CP voltage level is: 0

In my test case, it should always be 4095…

This is the whole interrupt:

 void IRAM_ATTR isr(){
      digitalWrite(32, HIGH);
      int level = analogRead(CP_READ);
      digitalWrite(32, LOW);

      Serial.print("Current CP voltage level is: ");      
      Serial.println(level);

}

Is there anything I should know about the ADC? is there a sort of "setup" time that is required to get it going that I can account for?

Best Answer

The ADC read is very short, you can see that with your logic analyzer trace. So you can rule that out as the problem.

The Serial.print lines inside the ISR are probably taking way too much time to handle the interrupts at the 1kHz rate. You should instead buffer the result and print out the results outside of the interrupt.