Innehållsförteckning:

Hur man gör och testar en bättre DAC med ESP32: 5 steg
Hur man gör och testar en bättre DAC med ESP32: 5 steg

Video: Hur man gör och testar en bättre DAC med ESP32: 5 steg

Video: Hur man gör och testar en bättre DAC med ESP32: 5 steg
Video: How to use ESP32 WiFi and Bluetooth with Arduino IDE full details with examples and code 2024, Juli
Anonim
Hur man gör och testar en bättre DAC med ESP32
Hur man gör och testar en bättre DAC med ESP32
Hur man gör och testar en bättre DAC med ESP32
Hur man gör och testar en bättre DAC med ESP32

ESP32 har 2 8-bitars digitala till analoga omvandlare (DAC). Dessa DAC gör att vi kan producera godtyckliga spänningar inom ett visst område (0-3.3V) med 8 bitars upplösning. I denna instruktionsbok kommer jag att visa dig hur man bygger en DAC och karakteriserar dess prestanda samt jämför den med ESP32 DAC. Prestationsindexen jag kommer att titta på inkluderar

  • Ljudnivå
  • Bandbredd
  • Integrerad olinearitet
  • Differentiell olinearitet

För att testa dessa index kommer jag att använda ADS1115.

Det är viktigt att notera att din bedömning av alla dessa index bara kommer att vara lika exakt som din referensenhet (i detta fall ADS115). Till exempel har ADS115 inte 16-bitars precision när det gäller dess spänningsförskjutning och förstärkning. Dessa fel kan vara så stora som 0,1%. För många system kan dessa fel ignoreras när absolut noggrannhet är av begränsad anledning.

Tillbehör

  • ADS1115
  • ESP32 -kort
  • bakbord
  • bygelkablar
  • 5 kOhm motstånd
  • 1 mikro-Farad keramisk kondensator

Steg 1: Lägg ut brödbrädan

Lägga ut brödbrädan
Lägga ut brödbrädan

Anslut följande stift

Mellan ESP32 och ADS1115

3v3 VDD

GND GND

GPIO22 SCL

GPIO21 SDA

På ADS1115

ADDR GND (ADS115)

Att göra DAC

Det finns många sätt att göra en DAC. Det enklaste är att lågpassfiltrera en PWM-signal med ett motstånd och en kondensator. Jag kunde ha lagt till en op-amp här som en buffert men ville hålla det enkelt. Denna design är enkel och billig att implementera med alla mikrokontroller som stöder PWM. Jag tänker inte gå igenom teorin om designen här (google PWM DAC).

Anslut bara GPIO255 KOhm motstånd 1 microFarad kondensator gnd

Anslut nu en bygelkabel från den punkt där motståndet möter kondensatorn till A0 på ADS115.

Steg 2: Bedöm signal till bullernivå

Bedöm signal till ljudnivå
Bedöm signal till ljudnivå

För att bedöma ljudnivån, kör helt enkelt skriptet nedan. För att bedöma detta lämnar vi helt enkelt DAC vid ett fast värde och mäter hur spänningen svänger över tiden.

På grund av DAC: s konstruktion blir bullret störst när PWM -signalen är på 50% driftscykel. Därför kommer vi att bedöma det. Vi kommer också att bedöma ESP32 på samma signalnivå. Vi kommer också att filtrera ESP32 DAC med samma lågpassfilter för att göra mätningen jämförbar.

För mig var resultatet klart. PWM -designen hade> 6dB bättre SNR (det är 2 gånger bättre). En klar vinst för nya DAC. En liten förvirring är att det finns filter inbyggda i ADC som definitivt förbättrar SNR. Så de absoluta värdena kan vara svåra att tolka. Om jag hade använt ett andra ordningsfilter skulle detta inte vara fallet.

Koden finns i alla fall nedan

#omfatta

#inkludera Adafruit_ADS1115 annonser; // adafruit bibliotek för adc int16_t adc0; // void setup (void) {Serial.begin (115200); // Starta seriella annonser.setGain (GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 0.0625mV ads.begin (); // börja adc float M = 0; // initial medelflöde Mp = 0; // previouos betyder float S = 0; // initial Variance float Sp = 0; // föregående varians const int reps = 500; // antal repitioner int n = 256; // antal prover ledcSetup (0, 25000, 8); // ställ in pwm frequecny = 25000 Hz vid 8 bitars upplösning ledcAttachPin (25, 0); // ställ pwm på pin 25 ledcWrite (0, 128); // ställ in den på halvdriftscykel (största buller) fördröjning (3000); // vänta på avvecklingstid float snrPWM [reps]; // array av snrs för PWM float snrDAC [reps]; // array av snrs för DAC för (int i = 0; i <reps; i ++) {// loope over repititions for (int k = 1; k <(n+1); k ++) {// loope over samples adc0 = ads.readADC_SingleEnded (0); // läs M = Mp + (adc0 - Mp) / k; // beräkna rullande medelvärde Mp = M; // ställ in tidigare medelvärde S = Sp + (adc0 - Mp) * (adc0 - M); // beräkna rullande varians Sp = S; // ställ in tidigare varians} // snr i dB snrPWM = 20 * log10 (3.3 / (sqrt (S / n) *.0625 *.001)); // återställ värden M = 0; Smältpunkt = 0; S = 0; Sp = 0; } ledcDetachPin (25); // lossa PWM från stift 25 dacWrite (25, 128); // skriva till DAC -fördröjning (3000); // vänta med att nöja sig med (int i = 0; i <reps; i ++) {// samma som PWM -loop för (int k = 1; k <(n+1); k ++) {adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Smp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; } snrDAC = 20 * log10 (3.3 / (sqrt (S / n) *.0625 *.001)); M = 0; Smältpunkt = 0; S = 0; Sp = 0; } // plot SNR på en graf för (int i = 1; i <reps; i ++) {Serial.print ("PWM_SNR (dB):"); Serial.print (snrPWM ); Serial.print (","); Serial.print ("ESP32_SNR (dB):"); Serial.println (snrDAC ); }} void loop (void) {}

Steg 3: Integral olinearitet och differentiell olinearitet

Integral olinearitet och differentiell olinearitet
Integral olinearitet och differentiell olinearitet

Den integrerade olineariteten är ett mått på ungefär hur stor avvikelse det finns mellan din DAC -utspänning och en rak linje. Ju större detta är desto värre är det …

Den olikära differentialen är ett mått på ungefär hur mycket den observerade förändringen i spänningen (från en kod till nästa) avviker från vad som kan förväntas från en rak linje.

Resultaten här var riktigt intressanta. Först och främst har båda mindre än 0,5 lbs fel (vid 8-bitars upplösning) vilket är bra men PWM har mycket bättre integrerad linearitet. Båda har jämförbar differentiell olinearitet men ESP32 DAC har några väldigt konstiga spikar. Dessutom har PWM -metoden en viss struktur för felen. I grund och botten överskjuter och överskjuter den rätt spänning på ett växlande sätt.

Min misstanke är att detta är något konstigt avrundningsfel i hur en 8-bitars PWM-signal produceras på ESP32.

Ett sätt att korrigera för detta är att snabbt växla mellan två intilliggande koder (t.ex. 128, 129) med PWM. Med ett analogt lågpassfilter är de resulterande felen genomsnittliga till noll. Jag simulerade detta i mjukvara och alla fel försvann. Nu har PWM-metoden linjäritet som är exakt till 16-bitars!

Vem som helst som koden för att generera data finns nedan. Utmatningen kommer att visas på den seriella bildskärmen i.csv -format. Kopiera bara den till en textfil för vidare bearbetning.

#omfatta

#inkludera Adafruit_ADS1115 annonser; / * Använd detta för 16-bitarsversionen */ int16_t adc0; void setup (void) {Serial.begin (115200); ads.setGain (GAIN_ONE); // 2x förstärkning +/- 2.048V 1 bit = 1mV 0.0625mV ads.begin (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); Serial.println ("Förväntat, observerat"); ledcWrite (0, 2); fördröjning (3000); för (int i = 2; i <255; i ++) {ledcWrite (0, i); fördröjning (100); adc0 = ads.readADC_SingleEnded (0); float förväntas = (i / 256,0 * 3,3) / 4,096 * 32767; Serial.print (förväntat); Serial.print (","); Serial.println (adc0); }} void loop (void) {}

Steg 4: Bandbredd

Bandbredd
Bandbredd

Jag kommer att definiera bandbredd som här som frekvensen vid vilken utmatningen från DAC sjunker med 3dB. Detta är en konvention och till viss del godtyckligt. Till exempel, vid 6dB -punkten, kommer DAC fortfarande att sända ut en signal, det kommer bara att vara ~ 50% amplitud.

För att mäta detta passerar vi helt enkelt sinusvågor med en ökande frekvens från DAC till ADC och mäter deras standardavvikelse. Inte överraskande är 3dB-punkten vid 30Hz (1/(2*pi*5000*1e-6)).

ESP32 kan göra 1 megaprov per sekund. Detta är en praktisk vinst för ESP32. Dess amplitud förfaller inte alls i 100Hz bandbreddstestområdet.

Koden nedan kan testa PWM DAC -bandbredd.

#omfatta

#inkludera Adafruit_ADS1115 annonser; / * Använd detta för 16-bitarsversionen */ int16_t adc0; int16_t adc1; void setup (void) {float M; float Mp = 0; flyta S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x förstärkning +/- 4.096V 1 bit = 2mV 0.125mV annonser. Börjar (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); fördröjning (5000); Serial.println ("Frekvens, amplitud"); för (int i = 1; i <100; i ++) {osignerad lång start = millis (); osignerad lång T = millis (); Sp = 0; S = 0; M = 0; Smältpunkt = 0; int k = 1; float norm; medan ((T - start) <1000) {int ut = 24 * sin (2 * PI * i * (T - start) / 1000.0) + 128; ledcWrite (0, ut); adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Smp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis (); k ++; } om (i == 1) {norm = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norm, 3); k = 0; }} void loop (void) {}

Och den här koden kommer att testa ESP32 -bandbredden. Var noga med att ta bort kondensatorn annars blir resultaten desamma för båda metoderna.

#omfatta

#inkludera Adafruit_ADS1115 annonser; / * Använd detta för 16-bitarsversionen */ int16_t adc0; int16_t adc1; void setup (void) {float M; float Mp = 0; flyta S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x förstärkning +/- 4.096V 1 bit = 2mV 0.125mV annonser. Börjar (); fördröjning (5000); Serial.println ("Frekvens, amplitud"); för (int i = 1; i <100; i ++) {osignerad lång start = millis (); osignerad lång T = millis (); Sp = 0; S = 0; M = 0; Smältpunkt = 0; int k = 1; float norm; medan ((T - start) <1000) {int ut = 24 * sin (2 * PI * i * (T - start) / 1000.0) + 128; dacWrite (25, ut); adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Smp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis (); k ++; } om (i == 1) {norm = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norm, 3); k = 0; }} void loop (void) {}

Steg 5: Avslutande tankar

Den nya DAC -designen vinner på linearitet och brus men förlorar på bandbredd. Beroende på din ansökan kan ett av dessa index vara viktigare än det andra. Med dessa testförfaranden bör du kunna fatta det beslutet objektivt!

Jag tycker också att det är värt att påpeka här att eftersom PWM-utgång är lågt brus, med exceptionell linjäritet bör det vara möjligt att konstruera en mycket högre upplösning DAC med PWM-utgången (kanske till och med 16-bitars precision). Det kommer att kräva lite arbete. Tills dess säger jag hejdå!

Rekommenderad: