Table des matières:

Comment faire et tester un meilleur DAC avec ESP32 : 5 étapes
Comment faire et tester un meilleur DAC avec ESP32 : 5 étapes

Vidéo: Comment faire et tester un meilleur DAC avec ESP32 : 5 étapes

Vidéo: Comment faire et tester un meilleur DAC avec ESP32 : 5 étapes
Vidéo: Premiers tests pour bien débuter avec l'ESP32 [ESP32 #1] 2024, Novembre
Anonim
Comment faire et tester un meilleur DAC avec ESP32
Comment faire et tester un meilleur DAC avec ESP32
Comment faire et tester un meilleur DAC avec ESP32
Comment faire et tester un meilleur DAC avec ESP32

L'ESP32 dispose de 2 convertisseurs numérique-analogique (DAC) 8 bits. Ces DAC nous permettent de produire des tensions arbitraires dans une certaine plage (0-3,3V) avec 8 bits de résolution. Dans ce Instructable, je vais vous montrer comment construire un DAC et caractériser ses performances ainsi que le comparer au DAC ESP32. Les indices de performance que j'examinerai comprennent

  • Niveau de bruit
  • Bande passante
  • Non-linéarité intégrale
  • Non-linéarité différentielle

Pour tester ces indices j'utiliserai l'ADS1115.

Il est important de noter que votre évaluation de tous ces indices ne sera aussi précise que votre appareil de référence (dans ce cas l'ADS115). Par exemple, l'ADS115 n'a pas de précision de 16 bits en ce qui concerne son décalage de tension et son gain. Ces erreurs peuvent atteindre 0,1%. Pour de nombreux systèmes, ces erreurs peuvent être ignorées lorsque la précision absolue est une préoccupation limitée.

Fournitures

  • ADS1115
  • Carte ESP32
  • planche à pain
  • fils de liaison
  • Résistance de 5 kOhms
  • 1 condensateur céramique micro-Farad

Étape 1: Disposition de la planche à pain

Disposer la planche à pain
Disposer la planche à pain

Câblez les broches suivantes

Entre l'ESP32 et l'ADS1115

Disque dur 3v3

TERRE TERRE

GPIO22 SCL

GPIO21 SDA

A l'ADS1115

ADDR GND (ADS115)

Faire le DAC

Il existe de nombreuses façons de créer un DAC. Le plus simple est de filtrer passe-bas un signal PWM avec une résistance et un condensateur. J'aurais pu ajouter un ampli-op ici comme tampon, mais je voulais garder les choses simples. Cette conception est simple et peu coûteuse à mettre en œuvre avec n'importe quel microcontrôleur prenant en charge le PWM. Je ne vais pas passer en revue la théorie de la conception ici (google PWM DAC).

Connectez simplement la résistance GPIO255 KOhm 1 microFarad Condensateur gnd

Connectez maintenant un fil volant du point où la résistance rencontre le condensateur à A0 sur l'ADS115.

Étape 2: Évaluer le signal par rapport au niveau de bruit

Évaluer le niveau du signal par rapport au bruit
Évaluer le niveau du signal par rapport au bruit

Pour évaluer le niveau de bruit, exécutez simplement le script ci-dessous. Pour évaluer cela, nous laissons simplement le DAC à une valeur fixe et mesurons comment la tension oscille dans le temps.

En raison de la conception du DAC, le bruit sera le plus important lorsque le signal PWM est à un cycle de service de 50 %. C'est donc ici que nous l'évaluerons. Nous évaluerons également l'ESP32 à ce même niveau de signal. Nous allons également filtrer le DAC ESP32 avec le même filtre passe bas afin de rendre la mesure comparable.

Pour moi, le résultat était clair. La conception PWM avait un SNR supérieur à 6 dB (c'est 2 fois mieux). Une nette victoire pour le nouveau DAC. Une légère confusion est qu'il existe des filtres intégrés dans l'ADC qui améliorent très certainement le SNR. Les valeurs absolues peuvent donc être difficiles à interpréter. Si j'avais utilisé un filtre de second ordre, ce ne serait pas le cas.

Quoi qu'il en soit le code est ci-dessous

#comprendre

#inclure les annonces Adafruit_ADS1115; // bibliothèque adafruit pour adc int16_t adc0; // void setup(void) { Serial.begin(115200); // Démarrez les annonces en série.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit =0.0625mV ads.begin(); // début adc float M = 0; // flottant moyen initial Mp = 0; // le flottant moyen précédent S = 0; // Variance flottante initiale Sp = 0; // variance précédente const int reps = 500; // nombre de répétitions int n = 256; // nombre d'échantillons ledcSetup(0, 25000, 8); // définir pwm frequecny = 25000 Hz à une résolution de 8 bits ledcAttachPin (25, 0); // définit pwm sur la broche 25 ledcWrite (0, 128); // définissez-le sur la moitié du cycle de service (le plus gros bruit) delay (3000); // attend le temps de stabilisation float snrPWM[reps]; // tableau de snrs pour PWM float snrDAC[reps]; // tableau de snrs pour DAC for (int i = 0; i < reps; i++) { // boucle sur les répétitions pour (int k = 1; k < (n + 1); k++) { // boucle sur les échantillons adc0 = ads.readADC_SingleEnded(0); // lire M = Mp + (adc0 - Mp) / k; // calcule la moyenne mobile Mp = M; // définir la moyenne précédente S = Sp + (adc0 - Mp) * (adc0 - M); // calcule la variance glissante Sp = S; // définir la variance précédente } // snr en dB snrPWM = 20 * log10(3.3 / (sqrt(S / n) *.0625 *.001)); //réinitialiser les valeurs M = 0; MP = 0; S = 0; Sp = 0; } ledcDetachPin(25); // détache le PWM de la broche 25 dacWrite (25, 128); // écriture dans le DAC delay(3000); // attendre pour régler (int i = 0; i < reps; i++) { // identique à la boucle PWM pour (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; } // tracer les SNR sur un graphique pour (int i = 1; i < reps; i++) { Serial.print("PWM_SNR(dB):"); Serial.print(snrPWM); Serial.print(", "); Serial.print("ESP32_SNR(dB):"); Serial.println(snrDAC); } } boucle vide (vide) { }

Étape 3: Non-linéarité intégrale et non-linéarité différentielle

Non-linéarité intégrale et non-linéarité différentielle
Non-linéarité intégrale et non-linéarité différentielle

La non-linéarité intégrale est une mesure de l'écart approximatif entre la tension de sortie de votre DAC et une ligne droite. Plus c'est gros, pire c'est…

La non-linéarité différentielle est une mesure d'environ combien le changement observé dans la tension (d'un code à l'autre) s'écarte de ce qui serait attendu d'une ligne droite.

Les résultats ici étaient vraiment intéressants. Tout d'abord, les deux ont une erreur inférieure à 0,5 lb (à une résolution de 8 bits), ce qui est bien, mais le PWM a une bien meilleure linéarité intégrale. Les deux ont une non-linéarité différentielle comparable, mais le DAC ESP32 présente des pics très étranges. De plus, la méthode PWM a une certaine structure pour les erreurs. Essentiellement, il dépasse et dépasse la tension correcte de manière alternative.

Je soupçonne qu'il s'agit d'une erreur d'arrondi étrange dans la façon dont un signal PWM 8 bits est produit sur l'ESP32.

Une façon de corriger cela est de faire un cycle rapide entre deux codes adjacents (par exemple 128, 129) avec le PWM. Avec un filtre passe-bas analogique, les erreurs résultantes seront en moyenne nulles. J'ai simulé cela dans le logiciel et en effet toutes les erreurs ont disparu. Maintenant, la méthode PWM a une linéarité précise à 16 bits !

Anywho le code pour générer les données est ci-dessous. La sortie sera sur le moniteur série au format.csv. Copiez-le simplement dans un fichier texte pour un traitement ultérieur.

#comprendre

#inclure les annonces Adafruit_ADS1115; /* Utilisez ceci pour la version 16 bits */ int16_t adc0; void setup(void) { Serial.begin(115200); ads.setGain(GAIN_ONE); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin (25, 0); Serial.println("Attendu, Observé "); ledcWrite(0, 2); retard(3000); for (int i = 2; i < 255; i++) { ledcWrite(0, i); retard (100); adc0 = ads.readADC_SingleEnded(0); flottant attendu = (i / 256,0 * 3,3) / 4,096 * 32767; Serial.print (attendu); Serial.print(", "); Serial.println(adc0); } } boucle vide (vide) { }

Étape 4: bande passante

Bande passante
Bande passante

Je vais définir la bande passante comme ici comme la fréquence à laquelle la sortie du DAC chute de 3dB. C'est une convention et, dans une certaine mesure, arbitraire. Par exemple, au point 6dB, le DAC produira toujours un signal dont l'amplitude sera d'environ 50 %.

Pour mesurer cela, nous passons simplement des ondes sinusoïdales à une fréquence croissante du DAC vers l'ADC et mesurons leur écart type. Sans surprise, le point 3dB est à 30Hz (1/(2*pi*5000*1e-6)).

L'ESP32 peut faire 1 méga échantillon par seconde. C'est une victoire haut la main pour l'ESP32. Son amplitude ne diminue pas du tout dans la région de test de la bande passante de 100 Hz.

Le code ci-dessous peut tester la bande passante du PWM DAC.

#comprendre

#inclure les annonces Adafruit_ADS1115; /* Utilisez ceci pour la version 16 bits */ int16_t adc0; int16_t adc1; void setup(void) { float M; flottant Mp = 0; flotteur S = 0; flottant Sp = 0; Serial.begin(115200); ads.setGain(GAIN_ONE); // 1x gain +/- 4,096V 1 bit = 2mV 0,125mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin (25, 0); retard (5000); Serial.println("Fréquence, Amplitude "); for (int i = 1; i < 100; i++) { début long non signé = millis(); T long non signé = millis(); Sp = 0; S = 0; M = 0; MP = 0; entier k = 1; norme flottante; while ((T - start) < 1000) { int out = 24 * sin(2 * PI * i * (T - start) / 1000.0) + 128; ledcWrite(0, out); 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) { norme = sqrt(S / k); } Serial.print(i); Serial.print(", "); Serial.println(sqrt(S/k)/norme, 3); k = 0; } } boucle vide (vide) { }

Et ce code testera la bande passante ESP32. Assurez-vous de retirer le condensateur ou les résultats seront les mêmes pour les deux méthodes.

#comprendre

#inclure les annonces Adafruit_ADS1115; /* Utilisez ceci pour la version 16 bits */ int16_t adc0; int16_t adc1; void setup(void) { float M; flottant Mp = 0; flotteur S = 0; flottant Sp = 0; Serial.begin(115200); ads.setGain(GAIN_ONE); // 1x gain +/- 4,096V 1 bit = 2mV 0,125mV ads.begin(); retard (5000); Serial.println("Fréquence, Amplitude "); for (int i = 1; i < 100; i++) { début long non signé = millis(); T long non signé = millis(); Sp = 0; S = 0; M = 0; MP = 0; entier k = 1; norme flottante; while ((T - start) < 1000) { int out = 24 * sin(2 * PI * i * (T - start) / 1000.0) + 128; dacWrite (25, sortie); 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) { norme = sqrt(S / k); } Serial.print(i); Serial.print(", "); Serial.println(sqrt(S/k)/norme, 3); k = 0; } } boucle vide (vide) { }

Étape 5: Réflexions de clôture

La nouvelle conception du DAC gagne en linéarité et en bruit mais perd en bande passante. Selon votre application, l'un de ces indices peut être plus important que l'autre. Avec ces procédures de test, vous devriez être en mesure de prendre cette décision de manière objective !

De plus, je pense qu'il vaut la peine de souligner ici que, comme la sortie PWM est à faible bruit, avec une linéarité exceptionnelle, il devrait être possible de construire un DAC à résolution beaucoup plus élevée avec la sortie PWM (peut-être même une précision de 16 bits). Cela va demander du travail. D'ici là, je vous dis adieu !

Conseillé: