Using ADC and DAC

Hello:

I'm trying to learn the use of ADC and DAC in my ESP-WROOM-32 board. First I tried generating signals using a DAC and a timer, and it worked fine.

However, I'm stuck with my second task, which is to read a signal from the ADC and then outputting it to a DAC. This does not work, and the board keeps resetting itself. I can't tell what I'm doing wrong, SO here's my current code, maybe you can guide me:

#define INT_LED 2
#define DAC1    25
#define DAC2    26
#define ADC1_0  36
#define ADC1_3  39
#define PWM     32
#define PULSE   13

// Configurar propiedades del PWM
const int freq = 500;
const int ledChannel = 0;
const int resolution = 8;

int led_ctr = 0;
int i = 0, j = 0;
long d = 50;
int bit_ctr = 0;
int analog;
boolean flag_timer0 = false;
boolean flag_timer1 = false;

// Configurar interrupción Timer0

hw_timer_t *Timer0_Cfg = NULL;
hw_timer_t *Timer1_Cfg = NULL;
 
void IRAM_ATTR Timer0_ISR()
{
  // Prender y apagar LED interno
  led_ctr++;

  if(led_ctr==24000)
  {    
    digitalWrite(INT_LED, !digitalRead(INT_LED));
    led_ctr = 0;
  }

  flag_timer0 = true;
  digitalWrite(PULSE, !digitalRead(PULSE));
  analog = analogRead(ADC1_3);
  dacWrite(DAC1, int(analog/16));
}

void setup()
{
  // Configurar la dirección de los GPIO
  pinMode(INT_LED,OUTPUT);
  pinMode(DAC1,OUTPUT);
  pinMode(PWM,OUTPUT);
  pinMode(PULSE,OUTPUT);
  pinMode(ADC1_0,INPUT);
  pinMode(ADC1_3,INPUT);
  adcAttachPin(ADC1_3);

  // Configuración interrupción Timer0 para 48 kHz
  Timer0_Cfg = timerBegin(0, 80, true);
  timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
  timerAlarmWrite(Timer0_Cfg, 21, true); 
  timerAlarmEnable(Timer0_Cfg);
}

void loop() 
{  
}

i expected the internal led to blink, and the DAC to output whatever is coming in from the ADC, but it lasts for about 2 seconds, then the board resets itself.

I have several doubts, especially regarding how long does the ADC take for a conversion. My timer is set at 48 kHz, so maybe the interrupt is to fast and it doesn't last enough to complete the reading?

This is what i have so far. If anyone can give me a hand, I'll be very grateful.

Best regards,
Fenhasan

you have to be careful what functions you call in interrupt service routines
if you comment out

  flag_timer0 = true;
  digitalWrite(PULSE, !digitalRead(PULSE));
  analog = analogRead(ADC1_3);
  dacWrite(DAC1, int(analog/16));

does the blink work?

Yes, it does blink.

the interrupt rate may be too fast and the interrupt service routine does not have time to finish - hence the resetting
try

  1. put the code back in
  2. reduce the timer interrupt rate say to 100/second

does the code now work, i.e. copy the ADC to DAC?
yes - if so increase the timer interupt rate until it fails
no - you need to rethink the algorithm

what are you attempting to do? it must be more than simply copying the ADC input to the DAC? are you planning to does some processing on the data?
if so you may require a DSP microcontroller board

edit: have a look at esp32-dac-audio-arduino-examples
the ESP32 Sine Wave Example uses timer interrupts 100000times/second to generate 1kHz sine wave using 100 sample lookup table

test ESP32 timer interrupts 10000times/second to read ADC and output to DAC

// ESP32 DAQ
// ESP32 timer interrupts 10000times/second to read ADC and output to DAC

// from ESP32 Sine Wave Example https://deepbluembedded.com/esp32-dac-audio-arduino-examples/

/*
* LAB Name: ESP32 Sine Wave Generation Example
* Author: Khaled Magdy
* DeepBlueMbedded 2023
* For More Info Visit: www.DeepBlueMbedded.com
*/

#include <driver/dac.h>

// Timer0 Configuration Pointer (Handle)
hw_timer_t *Timer0_Cfg = NULL;

volatile int counter = 0;

// The Timer0 ISR Function (Executes Every Timer0 Interrupt Interval)
void IRAM_ATTR Timer0_ISR() {
  // read ADC output to DAC
  unsigned int adc=analogRead(35)>>4;   // adc/16 - 12bits to 8bits
  dac_output_voltage(DAC_CHANNEL_1, adc);
  counter++;
}

void setup() {
  Serial.begin(115200);
  Serial.println("\nESP32 DAC sine wave");
  // Configure Timer0 Interrupt 10000/second
  Timer0_Cfg = timerBegin(0, 800, true);
  timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
  timerAlarmWrite(Timer0_Cfg, 10, true);
  timerAlarmEnable(Timer0_Cfg);
  // Enable DAC1 Channel's Output
  dac_output_enable(DAC_CHANNEL_1);
  analogSetWidth(12);    // ADC 12bit resolution
  analogSetClockDiv(1);  // fastest converion time
}

void loop() {
  static long timer = millis();
  if (millis() - timer > 1000) {
    Serial.println(counter);
    counter = 0;
    timer = millis();
  }
}

serial monitor output

10005
10005
10004
10005
10005

oscilloscope output
800Hz signal input blue trace DAC output yellow trace
image

looking at part of the trace
image

each ADC read/DAC output appears to take 100microSeconds

Note
ADC sampling rate: can reach 100000 times per second with Wi-Fi turned off, and 1000 times per second with Wi-Fi turned on.
Analog-to-Digital Converter (ADC) — ESP-FAQ documentation.

@horace: Thanks for the time you took; I made a similar example and in effect, the delta T between samples is around 100 microseconds.

@flashko: I'd like to reach around 48 kilosamples per second, which might be attainable (i guess), given the WiFi module is turned off. My question would be: How do i make sure WiFi is off, so i can get faster ADC readings?

I'm sorry if my questions are basic, but i have almost no experience with both arduino and ESP32.

Best regards,
Fenhasan.

I also have no experience with ECP32. If I'm not mistaken, WiFi is always active even if you don't use it in your program. To turn off Wi-Fi, you must explicitly use a command to stop it. See here

I’m using ESP-IDF release/v3.3 for ESP32 development, but only bluetooth function is needed, how to disable Wi-Fi function through software?

https://docs.espressif.com/projects/espressif-esp-faq/en/latest/software-framework/wifi.html#i-m-using-esp-idf-release-v3-3-for-esp32-development-but-only-bluetooth-function-is-needed-how-to-disable-wi-fi-function-through-software
. Maybe this will help.

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