Inhoudsopgave:

Een betere DAC maken en testen met ESP32 - Ajarnpa
Een betere DAC maken en testen met ESP32 - Ajarnpa

Video: Een betere DAC maken en testen met ESP32 - Ajarnpa

Video: Een betere DAC maken en testen met ESP32 - Ajarnpa
Video: How to setup and use ESP32 Cam with Micro USB WiFi Camera 2024, November
Anonim
Een betere DAC maken en testen met ESP32
Een betere DAC maken en testen met ESP32
Een betere DAC maken en testen met ESP32
Een betere DAC maken en testen met ESP32

De ESP32 heeft 2 8-bit digitaal naar analoog converters (DAC's). Met deze DAC's kunnen we willekeurige spanningen produceren binnen een bepaald bereik (0-3,3V) met een resolutie van 8 bits. In deze Instructable laat ik je zien hoe je een DAC bouwt en de prestaties karakteriseert en vergelijkt met de ESP32 DAC. De prestatie-indexen die ik zal bekijken, zijn onder meer:

  • Geluidsniveau
  • Bandbreedte
  • Integrale niet-lineariteit
  • Differentiële niet-lineariteit

Om deze indices te testen zal ik de ADS1115 gebruiken.

Het is belangrijk op te merken dat uw beoordeling van al deze indices slechts zo nauwkeurig is als uw referentieapparaat (in dit geval de ADS115). De ADS115 heeft bijvoorbeeld geen 16-bits precisie als het gaat om de spanningsverschuiving en versterking. Deze fouten kunnen oplopen tot 0,1%. Voor veel systemen kunnen deze fouten worden genegeerd wanneer absolute nauwkeurigheid van beperkt belang is.

Benodigdheden

  • ADS1115
  • ESP32-bord
  • broodplankje
  • jumperdraden
  • 5 kOhm Weerstand
  • 1 micro-Farad keramische condensator

Stap 1: Het breadboard neerleggen

Het breadboard neerleggen
Het breadboard neerleggen

Bedraad de volgende pinnen:

Tussen de ESP32 en de ADS1115

3v3 VDD

GND GND

GPIO22 SCL

GPIO21 SDA

Op de ADS1115

ADDR GND (ADS115)

De DAC maken

Er zijn veel manieren om een DAC te maken. Het eenvoudigst is om een PWM-signaal laagdoorlaatbaar te filteren met een weerstand en een condensator. Ik had hier een op-amp als buffer kunnen toevoegen, maar ik wilde het simpel houden. Dit ontwerp is eenvoudig en goedkoop te implementeren met elke microcontroller die PWM ondersteunt. Ik ga hier niet de theorie van het ontwerp doornemen (google PWM DAC).

Sluit gewoon GPIO255 KOhm-weerstand 1 microFarad Condensator gnd. aan

Sluit nu een jumperdraad aan vanaf het punt waar de weerstand de condensator ontmoet naar A0 op de ADS115.

Stap 2: beoordeel het signaal-naar-ruisniveau

Signaal-tot-ruisniveau beoordelen
Signaal-tot-ruisniveau beoordelen

Voer het onderstaande script uit om het geluidsniveau te beoordelen. Om dit te beoordelen laten we de DAC gewoon op een vaste waarde staan en meten we hoe de spanning oscilleert in de tijd.

Door het ontwerp van de DAC is de ruis het grootst wanneer het PWM-signaal een duty cycle van 50% heeft. Daarom zullen we het hier beoordelen. We zullen de ESP32 ook beoordelen op hetzelfde signaalniveau. Ook de ESP32 DAC gaan we filteren met hetzelfde laagdoorlaatfilter om de meting vergelijkbaar te maken.

Voor mij was de output duidelijk. Het PWM-ontwerp had >6dB betere SNR (dat is 2 keer beter). Een duidelijke overwinning voor nieuwe DAC. Een kleine verwarring is dat er filters zijn ingebouwd in de ADC die de SNR zeker verbeteren. Dus de absolute waarden kunnen moeilijk te interpreteren zijn. Als ik een filter van de tweede orde had gebruikt, zou dit niet het geval zijn.

Hoe dan ook, de code staat hieronder

#erbij betrekken

#include Adafruit_ADS1115 advertenties; // adafruit-bibliotheek voor adc int16_t adc0; // void setup (void) {Serial.begin(115200); // Start seriële advertenties.setGain (GAIN_TWO); // 2x winst +/- 2.048V 1 bit =0.0625mV ads.begin(); // begin adc float M = 0; // initiële gemiddelde float Mp = 0; // vorige gemiddelde float S = 0; // initiële variantie float Sp = 0; // vorige variantie const int reps = 500; // aantal herhalingen int n = 256; // aantal monsters ledcSetup (0, 25000, 8); // set pwm frequecny = 25000 Hz bij 8 bits resolutie ledcAttachPin (25, 0); // zet pwm op pin 25 ledcWrite (0, 128); // stel het in op halve werkcyclus (grootste ruis) vertraging (3000); // wacht op afwikkelingstijd float snrPWM [reps]; // array van snrs voor PWM float snrDAC [reps]; // array van snrs voor DAC voor (int i = 0; i < reps; i ++) {// loop over herhalingen voor (int k = 1; k < (n + 1); k ++) {// loop over samples adc0 = advertenties.readADC_SingleEnded(0); // lees M = Mp + (adc0 - Mp) / k; // bereken het voortschrijdend gemiddelde Mp = M; // stel vorige gemiddelde S = Sp + (adc0 - Mp) * (adc0 - M); // bereken de rollende variantie Sp = S; // stel vorige variantie in } // snr in dB snrPWM = 20 * log10 (3,3 / (sqrt (S / n) *.0625 *.001)); // reset waarden M = 0; Mp = 0; S = 0; Sp = 0; } ledcDetachPin(25); // koppel PWM los van pin 25 dacWrite (25, 128); // schrijf naar DAC-vertraging (3000); // wacht om genoegen te nemen met (int i = 0; i < herhalingen; i ++) {// hetzelfde als PWM-lus voor (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; } // plot SNR's in één grafiek voor (int i = 1; i < reps; i++) { Serial.print("PWM_SNR(dB):"); Serial.print(snrPWM); Serieel.print(", "); Serial.print("ESP32_SNR(dB):"); Serial.println(snrDAC); } } void lus(void) { }

Stap 3: Integrale niet-lineariteit en differentiële niet-lineariteit

Integrale niet-lineariteit en differentiële niet-lineariteit
Integrale niet-lineariteit en differentiële niet-lineariteit

De integrale niet-lineariteit is een maat voor ongeveer hoeveel afwijking er is tussen uw DAC-uitgangsspanning en een rechte lijn. Hoe groter dit is, hoe erger het is…

De differentiële niet-lineariteit is een maat voor ongeveer hoeveel de waargenomen verandering in de spanning (van de ene code naar de volgende) afwijkt van wat zou worden verwacht van een rechte lijn.

De resultaten hier waren echt interessant. Allereerst hebben beide een fout van minder dan 0,5 lsb (bij een resolutie van 8 bits), wat goed is, maar de PWM heeft een veel betere integrale lineariteit. Beide hebben vergelijkbare differentiële niet-lineariteit, maar de ESP32 DAC heeft een aantal zeer rare pieken. Bovendien heeft de PWM-methode enige structuur in de fouten. In wezen overschrijdt en onderschrijdt het de juiste spanning op een afwisselende manier.

Mijn vermoeden is dat dit een rare afrondingsfout is in hoe een 8-bits PWM-signaal wordt geproduceerd op de ESP32.

Een manier om dit te corrigeren is door met de PWM snel te wisselen tussen twee aangrenzende codes (bijv. 128, 129). Met een analoog laagdoorlaatfilter worden de resulterende fouten gemiddeld tot nul. Ik heb dit softwarematig gesimuleerd en inderdaad zijn alle fouten verdwenen. Nu heeft de PWM-methode een lineariteit die tot op 16 bits nauwkeurig is!

Anywho de code om de gegevens te genereren is hieronder. De uitvoer staat op de seriële monitor in.csv-formaat. Kopieer het gewoon naar een tekstbestand voor verdere verwerking.

#erbij betrekken

#include Adafruit_ADS1115 advertenties; /* Gebruik dit voor de 16-bits versie */ int16_t adc0; void setup (void) {Serial.begin(115200); ads.setGain(GAIN_ONE); // 2x winst +/- 2.048V 1 bit = 1mV 0.0625mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); Serial.println("Verwacht, waargenomen "); ledcWrite(0, 2); vertraging (3000); for (int i = 2; i < 255; i++) { ledcWrite(0, i); vertraging (100); adc0 = advertenties.readADC_SingleEnded(0); float verwacht = (i / 256,0 * 3,3) / 4,096 * 32767; Serial.print (verwacht); Serieel.print(", "); Serieel.println(adc0); } } void lus(void) { }

Stap 4: Bandbreedte

Bandbreedte
Bandbreedte

Ik ga bandbreedte hier definiëren als de frequentie waarmee de output van de DAC met 3dB daalt. Dit is een conventie en tot op zekere hoogte arbitrair. Op het 6dB-punt zal de DAC bijvoorbeeld nog steeds een signaal uitvoeren, het zal slechts ~ 50% amplitude zijn.

Om dit te meten, laten we eenvoudig sinusgolven met een toenemende frequentie van de DAC naar de ADC door en meten we hun standaarddeviatie. Het is niet verwonderlijk dat het 3dB-punt op 30Hz ligt (1/(2*pi*5000*1e-6)).

De ESP32 kan 1 Mega-sample per seconde doen. Dit is een absolute overwinning voor de ESP32. De amplitude neemt helemaal niet af in het 100Hz-bandbreedtetestgebied.

De onderstaande code kan de PWM DAC-bandbreedte testen.

#erbij betrekken

#include Adafruit_ADS1115 advertenties; /* Gebruik dit voor de 16-bits versie */ int16_t adc0; int16_t adc1; void setup (void) { float M; vlotter Mp = 0; vlotter S = 0; vlotter Sp = 0; Serieel.begin(115200); ads.setGain(GAIN_ONE); // 1x winst +/- 4.096V 1 bit = 2mV 0.125mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); vertraging (5000); Serial.println ("Frequentie, Amplitude "); for (int i = 1; i < 100; i++) { unsigned long start = millis(); niet-ondertekende lange T = millis(); Sp = 0; S = 0; M = 0; Mp = 0; intk = 1; vlotternorm; while ((T - start) < 1000) { int out = 24 * sin (2 * PI * i * (T - start) / 1000,0) + 128; ledcWrite(0, uit); adc0 = advertenties.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis(); k++; } if (i == 1) { norm = sqrt(S / k); } Serieel.print(i); Serieel.print(", "); Serial.println(sqrt(S / k) / norm, 3); k = 0; } } void lus(void) { }

En deze code test de ESP32-bandbreedte. Zorg ervoor dat u de condensator verwijdert, anders zijn de resultaten voor beide methoden hetzelfde.

#erbij betrekken

#include Adafruit_ADS1115 advertenties; /* Gebruik dit voor de 16-bits versie */ int16_t adc0; int16_t adc1; void setup (void) { float M; vlotter Mp = 0; vlotter S = 0; vlotter Sp = 0; Serieel.begin(115200); ads.setGain(GAIN_ONE); // 1x winst +/- 4.096V 1 bit = 2mV 0.125mV ads.begin(); vertraging (5000); Serial.println ("Frequentie, Amplitude "); for (int i = 1; i < 100; i++) { unsigned long start = millis(); niet-ondertekende lange T = millis(); Sp = 0; S = 0; M = 0; Mp = 0; intk = 1; vlotternorm; while ((T - start) < 1000) { int out = 24 * sin (2 * PI * i * (T - start) / 1000,0) + 128; dacWrite(25, uit); adc0 = advertenties.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis(); k++; } if (i == 1) { norm = sqrt(S / k); } Serieel.print(i); Serieel.print(", "); Serial.println(sqrt(S / k) / norm, 3); k = 0; } } void lus(void) { }

Stap 5: Afsluitende gedachten

Het nieuwe DAC-ontwerp wint op lineariteit en ruis, maar verliest op bandbreedte. Afhankelijk van uw toepassing kan een van deze indices belangrijker zijn dan de andere. Met deze testprocedures zou u die beslissing objectief moeten kunnen nemen!

Ik denk ook dat het hier de moeite waard is om erop te wijzen dat, omdat de PWM-uitvoer weinig ruis heeft, het met uitzonderlijke lineariteit mogelijk moet zijn om een DAC met een veel hogere resolutie te construeren met de PWM-uitvoer (misschien zelfs 16-bits precisie). Dat gaat wat werk kosten. Tot die tijd zeg ik je vaarwel!

Aanbevolen: