1
\$\begingroup\$

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?

\$\endgroup\$
  • 1
    \$\begingroup\$ You cannot use the very intensive Serial.print() in an interrupt function because it takes to long. In an interrupt function you can only do simple tasks. You need to make two functions, The interrupt function put something in a buffer array and the other function reads the array and dumps it to the serial monitor. You need to set the serial connection to highest value possible. \$\endgroup\$ – Codebeat Dec 13 '19 at 21:47
2
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ If possible (I can't remember the Serial.print details) only send another print (outside the interrupt) if the serial buffer is empty. \$\endgroup\$ – Transistor Dec 13 '19 at 20:42
  • \$\begingroup\$ Ah yes, of course. Silly of me to have put a Serial.println() in there... Thanks. \$\endgroup\$ – Matthew Goulart Dec 14 '19 at 19:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.