Inhoudsopgave:
- Benodigdheden
- Stap 1: Het breadboard neerleggen
- Stap 2: beoordeel het signaal-naar-ruisniveau
- Stap 3: Integrale niet-lineariteit en differentiële niet-lineariteit
- Stap 4: Bandbreedte
- Stap 5: Afsluitende gedachten
Video: Een betere DAC maken en testen met ESP32 - Ajarnpa
2024 Auteur: John Day | [email protected]. Laatst gewijzigd: 2024-01-30 11:15
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
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
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
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
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:
Betere alligatorclips: 3 stappen (met afbeeldingen)
Betere krokodillenklemmen: toen ik een jongen was, waren krokodillenklemmen zwaar en gemaakt om goed te werken. Ze waren gemaakt van zwaarder staal met schroefklemmen en goede veren. Nu zijn alligatorclips bloedarmoede kleine dingen met een kleine nutteloze kaakopening. Ik wilde wat betere alligatorkl
Betere projecten met PCB's: 6 stappen
Betere projecten met PCB's: Als je tijd hebt besteed aan het werken met elektronicaprojecten, dan weet je hoe leuk en opwindend het kan zijn. Niets is opwindender dan uw circuit voor uw ogen tot leven te zien komen. Het wordt nog spannender wanneer uw project verandert in een
Een computer coderen en testen in machinetaal: 6 stappen
Een computer coderen en testen in machinetaal: in deze Instructable laat ik je zien hoe je een computerprogramma codeert en test in machinetaal. Machinetaal is de moedertaal van computers. Omdat het is samengesteld uit reeksen van enen en nullen, is het niet gemakkelijk te begrijpen door mensen. Om te werken
Een Bluetooth-adapter Pt.2 maken (een compatibele luidspreker maken): 16 stappen
Een Bluetooth-adapter Pt.2 maken (een compatibele luidspreker maken): in deze instructie laat ik u zien hoe u mijn Bluetooth-adapter kunt gebruiken om een oude luidspreker Bluetooth-compatibel te maken. * Als u mijn eerste instructie over "Maken nog niet hebt gelezen een Bluetooth-adapter" Ik raad u aan dit te doen voordat u doorgaat.C
Een betere laptopvoedingskabel: 14 stappen
Een betere laptopvoedingskabel: Ben je het beu om je laptop te gebruiken in collegezalen met meer dan 300 zitplaatsen en één stopcontact… of wanneer alle stoelen naast de stopcontacten vol zijn? (en je bent te lui om je laptop van tevoren op te laden) Je kunt je netsnoer eenvoudig verlengen tot 7 meter en