Sommario:

Come realizzare e testare un DAC migliore con ESP32: 5 passaggi
Come realizzare e testare un DAC migliore con ESP32: 5 passaggi

Video: Come realizzare e testare un DAC migliore con ESP32: 5 passaggi

Video: Come realizzare e testare un DAC migliore con ESP32: 5 passaggi
Video: Using the ESP32 DAC - Voltages, Waveforms & Sounds 2024, Dicembre
Anonim
Come realizzare e testare un DAC migliore con ESP32
Come realizzare e testare un DAC migliore con ESP32
Come realizzare e testare un DAC migliore con ESP32
Come realizzare e testare un DAC migliore con ESP32

L'ESP32 ha 2 convertitori da digitale ad analogico (DAC) a 8 bit. Questi DAC ci permettono di produrre tensioni arbitrarie entro un certo intervallo (0-3,3V) con 8 bit di risoluzione. In questo Instructable, ti mostrerò come costruire un DAC e caratterizzare le sue prestazioni, oltre a confrontarlo con il DAC ESP32. Gli indici di prestazione che esaminerò includono

  • Livello di rumore
  • Larghezza di banda
  • Non linearità integrale
  • Non linearità differenziale

Per testare questi indici userò l'ADS1115.

È importante notare che la tua valutazione di tutti questi indici sarà accurata solo quanto il tuo dispositivo di riferimento (in questo caso l'ADS115). Ad esempio, l'ADS115 non ha una precisione a 16 bit quando si tratta di offset e guadagno di tensione. Questi errori possono raggiungere lo 0,1%. Per molti sistemi, questi errori possono essere ignorati quando l'accuratezza assoluta è di scarsa importanza.

Forniture

  • ADS1115
  • Scheda ESP32
  • tagliere
  • cavi per ponticelli
  • Resistenza da 5 kOhm
  • 1 condensatore ceramico micro-Farad

Passaggio 1: stendere il tagliere

Preparare il tagliere
Preparare il tagliere

Collegare i seguenti pin

Tra ESP32 e ADS1115

3v3 VDD

GND GND

GPIO22 SCL

GPIO21 SDA

All'ADS1115

ADDR GND (ADS115)

Realizzare il DAC

Esistono molti modi per realizzare un DAC. Il più semplice è filtrare passa basso un segnale PWM con un resistore e un condensatore. Avrei potuto aggiungere un amplificatore operazionale qui come buffer, ma volevo mantenere le cose semplici. Questo design è semplice ed economico da implementare con qualsiasi microcontrollore che supporti il PWM. Non esaminerò qui la teoria del design (google PWM DAC).

Basta collegare GPIO255 KOhm resistore 1 microFarad Condensatore gnd

Ora collega un ponticello dal punto in cui il resistore incontra il condensatore ad A0 sull'ADS115.

Passaggio 2: valutare il livello del segnale in base al rumore

Valutare il livello del segnale rispetto al rumore
Valutare il livello del segnale rispetto al rumore

Per valutare il livello di rumore è sufficiente eseguire lo script sottostante. Per valutare ciò lasciamo semplicemente il DAC ad un valore fisso e misuriamo come la tensione oscilla nel tempo.

A causa del design del DAC, il rumore sarà maggiore quando il segnale PWM è al 50% del ciclo di lavoro. Pertanto è qui che lo valuteremo. Valuteremo anche ESP32 a questo stesso livello di segnale. Filtriamo anche il DAC ESP32 con lo stesso filtro passa basso in modo da rendere comparabile la misurazione.

Per me l'output era chiaro. Il design PWM aveva un SNR migliore di >6dB (che è 2 volte migliore). Una chiara vittoria per il nuovo DAC. Una leggera confusione è che ci sono filtri integrati nell'ADC che stanno decisamente migliorando l'SNR. Quindi i valori assoluti possono essere difficili da interpretare. Se avessi usato un filtro di secondo ordine non sarebbe stato così.

Comunque il codice è sotto

#includere

#include annunci Adafruit_ADS1115; // libreria adafruit per adc int16_t adc0; // void setup(void) { Serial.begin(115200); // Avvia serial ads.setGain(GAIN_TWO); // Guadagno 2x +/- 2.048V 1 bit =0.0625mV ads.begin(); // inizia adc float M = 0; // media iniziale float Mp = 0; // precedente media float S = 0; // Varianza iniziale float Sp = 0; // varianza precedente const int reps = 500; // numero di ripetizioni int n = 256; // numero di campioni ledcSetup(0, 25000, 8); // imposta pwm frequecny =25000 Hz con una risoluzione di 8 bit ledcAttachPin(25, 0); // imposta pwm sul pin 25 ledcWrite(0, 128); // impostalo su half duty cycle (più grande rumore) delay (3000); // attende il tempo di assestamento float snrPWM[reps]; // array di snrs per PWM float snrDAC[reps]; // array di snrs per DAC for (int i = 0; i < reps; i++) { // loop sulle ripetizioni for (int k = 1; k < (n + 1); k++) { // loop sui campioni adc0 = ads.readADC_SingleEnded(0); // ottiene la lettura M = Mp + (adc0 - Mp) / k; // calcola la media mobile Mp = M; // imposta la media precedente S = Sp + (adc0 - Mp) * (adc0 - M); // calcola la varianza mobile Sp = S; // imposta la varianza precedente } // snr in dB snrPWM = 20 * log10(3.3 / (sqrt(S / n) *.0625 *.001)); //reimposta i valori M = 0; Mp = 0; S = 0; Sp = 0; } ledcDetachPin(25); // stacca PWM dal pin 25 dacWrite(25, 128); // scrive su DAC delay(3000); // aspetta di accontentarsi di (int i = 0; i < reps; i++) { // uguale al ciclo PWM per (int k = 1; k < (n + 1); k++) { adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; } snrDAC = 20 * log10(3.3 / (sqrt(S / n) *.0625 *.001)); M = 0; Mp = 0; S = 0; Sp = 0; } // traccia gli SNR su un grafico for (int i = 1; i < reps; i++) { Serial.print("PWM_SNR(dB):"); Serial.print(snrPWM); Serial.print(", "); Serial.print("ESP32_SNR(dB):"); Serial.println(snrDAC); } } ciclo vuoto (vuoto) { }

Passaggio 3: non linearità integrale e non linearità differenziale

Non linearità integrale e non linearità differenziale
Non linearità integrale e non linearità differenziale

La non linearità integrale è una misura approssimativa di quanta deviazione c'è tra la tensione di uscita del DAC e una linea retta. Più è grande e peggio è…

La non linearità differenziale è una misura approssimativa di quanto il cambiamento osservato nella tensione (da un codice all'altro) si discosta da quanto ci si aspetterebbe da una linea retta.

I risultati qui sono stati davvero interessanti. Prima di tutto, entrambi hanno un errore inferiore a 0,5 lsb (a una risoluzione di 8 bit), il che è buono, ma il PWM ha una linearità integrale molto migliore. Entrambi hanno una non linearità differenziale comparabile, ma il DAC ESP32 ha alcuni picchi molto strani. Inoltre, il metodo PWM ha una struttura per gli errori. Essenzialmente supera e non raggiunge la tensione corretta in modo alternato.

Il mio sospetto è che si tratti di uno strano errore di arrotondamento nel modo in cui viene prodotto un segnale PWM a 8 bit su ESP32.

Un modo per correggere questo è quello di scorrere rapidamente tra due codici adiacenti (ad esempio 128, 129) con il PWM. Con un filtro passa-basso analogico, gli errori risultanti saranno in media pari a zero. L'ho simulato nel software e in effetti tutti gli errori sono scomparsi. Ora il metodo PWM ha una linearità precisa a 16 bit!

Anywho il codice per generare i dati è sotto. L'output sarà sul monitor seriale in formato.csv. Basta copiarlo in un file di testo per un'ulteriore elaborazione.

#includere

#include annunci Adafruit_ADS1115; /* Usalo per la versione a 16 bit */ int16_t adc0; void setup(void) { Serial.begin(115200); ads.setGain(GAIN_ONE); // Guadagno 2x +/- 2,048 V 1 bit = 1 mV 0,0625 mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); Serial.println("Atteso, Osservato"); ledcWrite(0, 2); ritardo (3000); for (int i = 2; i < 255; i++) { ledcWrite(0, i); ritardo(100); adc0 = ads.readADC_SingleEnded(0); float atteso = (i / 256,0 * 3,3) / 4,096 * 32767; Serial.print (previsto); Serial.print(", "); Serial.println(adc0); } } ciclo vuoto (vuoto) { }

Passaggio 4: larghezza di banda

Larghezza di banda
Larghezza di banda

Definirò la larghezza di banda come qui come la frequenza alla quale l'uscita del DAC scende di 3dB. Questa è una convenzione e, in una certa misura, arbitraria. Ad esempio, al punto 6dB, il DAC emetterà ancora un segnale che sarà solo ~50% di ampiezza.

Per misurarlo, passiamo semplicemente le onde sinusoidali a una frequenza crescente dal DAC all'ADC e misuriamo la loro deviazione standard. Non sorprende che il punto 3dB sia a 30Hz (1/(2*pi*5000*1e-6)).

L'ESP32 può eseguire 1 Mega campione al secondo. Questa è una vittoria a mani basse per ESP32. La sua ampiezza non decade affatto nella regione di prova della larghezza di banda di 100Hz.

Il codice seguente può testare la larghezza di banda del DAC PWM.

#includere

#include annunci Adafruit_ADS1115; /* Usalo per la versione a 16 bit */ int16_t adc0; int16_t adc1; void setup(void) { float M; float Mp = 0; galleggiante S = 0; flottante Sp = 0; Serial.begin(115200); ads.setGain(GAIN_ONE); // 1x guadagno +/- 4,096 V 1 bit = 2 mV 0,125 mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); ritardo (5000); Serial.println("Frequenza, Ampiezza "); for (int i = 1; i < 100; i++) { inizio lungo senza segno = millis(); unsigned long T = millis(); Sp = 0; S = 0; M = 0; Mp = 0; intk = 1; norma galleggiante; while ((T - inizio) < 1000) { int out = 24 * sin(2 * PI * i * (T - inizio) / 1000,0) + 128; ledcWrite(0, uscita); adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis(); k++; } if (i == 1) { norma = sqrt(S / k); } Serial.print(i); Serial.print(", "); Serial.println(sqrt(S / k) / norm, 3); k = 0; } } ciclo vuoto (vuoto) { }

E questo codice testerà la larghezza di banda ESP32. Assicurati di rimuovere il condensatore o i risultati saranno gli stessi per entrambi i metodi.

#includere

#include annunci Adafruit_ADS1115; /* Usalo per la versione a 16 bit */ int16_t adc0; int16_t adc1; void setup(void) { float M; float Mp = 0; galleggiante S = 0; flottante Sp = 0; Serial.begin(115200); ads.setGain(GAIN_ONE); // 1x guadagno +/- 4,096 V 1 bit = 2 mV 0,125 mV ads.begin(); ritardo (5000); Serial.println("Frequenza, Ampiezza "); for (int i = 1; i < 100; i++) { inizio lungo senza segno = millis(); unsigned long T = millis(); Sp = 0; S = 0; M = 0; Mp = 0; intk = 1; norma galleggiante; while ((T - inizio) < 1000) { int out = 24 * sin(2 * PI * i * (T - inizio) / 1000,0) + 128; dacWrite(25, uscita); adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis(); k++; } if (i == 1) { norma = sqrt(S / k); } Serial.print(i); Serial.print(", "); Serial.println(sqrt(S / k) / norma, 3); k = 0; } } ciclo vuoto (vuoto) { }

Passaggio 5: pensieri conclusivi

Il nuovo design DAC vince sulla linearità e sul rumore ma perde sulla larghezza di banda. A seconda dell'applicazione, uno di questi indici può essere più importante dell'altro. Con queste procedure di test, dovresti essere in grado di prendere obiettivamente questa decisione!

Inoltre, penso che valga la pena sottolineare qui che, poiché l'uscita PWM è a basso rumore, con una linearità eccezionale dovrebbe essere possibile costruire un DAC a risoluzione molto più elevata con l'uscita PWM (forse anche con precisione a 16 bit). Ci vorrà un po' di lavoro. Fino ad allora, ti dico addio!

Consigliato: