Índice:

Como fazer e testar um DAC melhor com ESP32: 5 etapas
Como fazer e testar um DAC melhor com ESP32: 5 etapas
Anonim
Como fazer e testar um DAC melhor com ESP32
Como fazer e testar um DAC melhor com ESP32
Como fazer e testar um DAC melhor com ESP32
Como fazer e testar um DAC melhor com ESP32

O ESP32 tem 2 conversores digital para analógico (DACs) de 8 bits. Esses DACs nos permitem produzir tensões arbitrárias dentro de uma certa faixa (0-3,3 V) com 8 bits de resolução. Neste Instructable, vou mostrar como construir um DAC e caracterizar seu desempenho, bem como compará-lo com o ESP32 DAC. Os índices de desempenho que examinarei incluem

  • Nível de ruído
  • Largura de banda
  • Não linearidade integral
  • Não linearidade diferencial

Para testar esses índices usarei o ADS1115.

É importante observar que sua avaliação de todos esses índices será tão precisa quanto o seu dispositivo de referência (neste caso, o ADS115). Por exemplo, o ADS115 não tem precisão de 16 bits quando se trata de deslocamento e ganho de tensão. Esses erros podem chegar a 0,1%. Para muitos sistemas, esses erros podem ser ignorados quando a precisão absoluta é uma preocupação limitada.

Suprimentos

  • ADS1115
  • Placa ESP32
  • tábua de pão
  • fios de ligação
  • Resistor de 5 kOhm
  • 1 capacitor de cerâmica micro-Farad

Etapa 1: Layout da placa de ensaio

Disposição da placa de ensaio
Disposição da placa de ensaio

Ligue os seguintes pinos

Entre o ESP32 e o ADS1115

3v3 VDD

GND GND

GPIO22 SCL

GPIO21 SDA

No ADS1115

ADDR GND (ADS115)

Fazendo o DAC

Existem muitas maneiras de fazer um DAC. O mais simples é filtrar um sinal PWM com um resistor e um capacitor. Eu poderia ter adicionado um amplificador operacional aqui como um buffer, mas queria manter as coisas simples. Este projeto é simples e barato de implementar com qualquer microcontrolador que suporte PWM. Não vou abordar a teoria do design aqui (google PWM DAC).

Basta conectar GPIO255 KOhm resistor 1 microFarad Capacitor gnd

Agora conecte um fio jumper do ponto onde o resistor encontra o capacitor para A0 no ADS115.

Etapa 2: avaliar o nível de ruído do sinal

Avalie o sinal para o nível de ruído
Avalie o sinal para o nível de ruído

Para avaliar o nível de ruído, basta executar o script abaixo. Para avaliar isso, simplesmente deixamos o DAC em um valor fixo e medimos como a tensão oscila ao longo do tempo.

Devido ao design do DAC, o ruído será maior quando o sinal PWM estiver em 50% do ciclo de trabalho. Portanto, é aqui que iremos avaliá-lo. Também avaliaremos o ESP32 neste mesmo nível de sinal. Também filtraremos o ESP32 DAC com o mesmo filtro passa-baixo para tornar a medição comparável.

Para mim, a saída foi clara. O projeto PWM teve SNR> 6dB melhor (que é 2 vezes melhor). Uma vitória clara para o novo DAC. Uma pequena confusão é que existem filtros embutidos no ADC que estão definitivamente aprimorando o SNR. Portanto, os valores absolutos podem ser difíceis de interpretar. Se eu tivesse usado um filtro de segunda ordem, esse não seria o caso.

De qualquer forma, o código está abaixo

#incluir

#include Adafruit_ADS1115 ads; // biblioteca adafruit para adc int16_t adc0; // configuração do void (void) {Serial.begin (115200); // Iniciar serial ads.setGain (GAIN_TWO); // ganho 2x +/- 2,048V 1 bit = 0,0625mV ads.begin (); // iniciar adc float M = 0; // flutuação média inicial Mp = 0; // previouos mean float S = 0; // Variância inicial float Sp = 0; // variância anterior const int reps = 500; // número de repetições int n = 256; // número de amostras ledcSetup (0, 25000, 8); // define pwm frequecny = 25000 Hz com resolução de 8 bits ledcAttachPin (25, 0); // define pwm no pino 25 ledcWrite (0, 128); // define para meio ciclo de serviço (maior ruído) delay (3000); // espera pelo tempo de acomodação float snrPWM [reps]; // array de snrs para PWM float snrDAC [reps]; // array de snrs para DAC for (int i = 0; i <reps; i ++) {// loop sobre repetições para (int k = 1; k <(n + 1); k ++) {// loop over samples adc0 = ads.readADC_SingleEnded (0); // obtém a leitura M = Mp + (adc0 - Mp) / k; // calcula a média contínua Mp = M; // definir a média anterior S = Sp + (adc0 - Mp) * (adc0 - M); // calcula a variação contínua Sp = S; // definir variância anterior} // snr em dB snrPWM = 20 * log10 (3,3 / (sqrt (S / n) * 0,0625 * 0,001)); // redefine os valores M = 0; Mp = 0; S = 0; Sp = 0; } ledcDetachPin (25); // desanexar o PWM do pino 25 dacWrite (25, 128); // escrever no atraso DAC (3000); // espere para se conformar com (int i = 0; i <reps; i ++) {// mesmo que o loop PWM para (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) * 0,0625 * 0,001)); M = 0; Mp = 0; S = 0; Sp = 0; } // plotar SNRs em um gráfico para (int i = 1; i <reps; i ++) {Serial.print ("PWM_SNR (dB):"); Serial.print (snrPWM ); Serial.print (","); Serial.print ("ESP32_SNR (dB):"); Serial.println (snrDAC ); }} loop vazio (vazio) {}

Etapa 3: Não linearidade integral e não linearidade diferencial

Não linearidade integral e não linearidade diferencial
Não linearidade integral e não linearidade diferencial

A não linearidade integral é uma medida de aproximadamente quanto desvio existe entre a tensão de saída do DAC e uma linha reta. Quanto maior é, pior é …

A não linearidade diferencial é uma medida de aproximadamente o quanto a mudança observada na tensão (de um código para o próximo) se desvia do que seria esperado de uma linha reta.

Os resultados aqui foram realmente interessantes. Em primeiro lugar, ambos têm menos de 0,5 lsb de erro (em resolução de 8 bits), o que é bom, mas o PWM tem linearidade integral muito melhor. Ambos têm não linearidade diferencial comparável, mas o ESP32 DAC tem alguns picos muito estranhos. Além disso, o método PWM tem alguma estrutura para os erros. Essencialmente, ele ultrapassa e diminui a voltagem correta de forma alternada.

Minha suspeita é que este é algum erro de arredondamento estranho em como um sinal PWM de 8 bits é produzido no ESP32.

Uma maneira de corrigir isso é alternar rapidamente entre dois códigos adjacentes (por exemplo, 128, 129) com o PWM. Com um filtro passa-baixo analógico, os erros resultantes serão em média zero. Simulei isso no software e de fato todos os erros desapareceram. Agora, o método PWM tem linearidade com precisão de 16 bits!

Anywho o código para gerar os dados está abaixo. A saída será no monitor serial no formato.csv. Basta copiá-lo para um arquivo de texto para processamento posterior.

#incluir

#include Adafruit_ADS1115 ads; / * Use para a versão de 16 bits * / int16_t adc0; configuração de vazio (vazio) {Serial.begin (115200); ads.setGain (GAIN_ONE); // ganho 2x +/- 2,048V 1 bit = 1mV 0,0625mV ads.begin (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); Serial.println ("Esperado, Observado"); ledcWrite (0, 2); atraso (3000); para (int i = 2; i <255; i ++) {ledcWrite (0, i); atraso (100); adc0 = ads.readADC_SingleEnded (0); flutuação esperada = (i / 256,0 * 3,3) / 4,096 * 32767; Serial.print (esperado); Serial.print (","); Serial.println (adc0); }} loop vazio (vazio) {}

Etapa 4: largura de banda

Largura de banda
Largura de banda

Definirei largura de banda como a frequência na qual a saída do DAC cai em 3 dB. Esta é uma convenção e, até certo ponto, arbitrária. Por exemplo, no ponto de 6dB, o DAC ainda emitirá um sinal que terá uma amplitude de aproximadamente 50%.

Para medir isso, simplesmente passamos ondas senoidais em uma frequência crescente do DAC para o ADC e medimos seu desvio padrão. Sem surpresa, o ponto de 3dB está em 30 Hz (1 / (2 * pi * 5000 * 1e-6)).

O ESP32 pode fazer 1 Mega amostra por segundo. Esta é uma vitória incontestável para o ESP32. Sua amplitude não decai na região de teste de largura de banda de 100Hz.

O código abaixo pode testar a largura de banda PWM DAC.

#incluir

#include Adafruit_ADS1115 ads; / * Use para a versão de 16 bits * / int16_t adc0; int16_t adc1; configuração de vazio (vazio) {float M; float Mp = 0; float S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x ganho +/- 4,096V 1 bit = 2mV 0,125mV ads.begin (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); atraso (5000); Serial.println ("Frequência, Amplitude"); para (int i = 1; i <100; i ++) {início longo sem sinal = milis (); T longo sem sinal = milis (); Sp = 0; S = 0; M = 0; Mp = 0; int k = 1; norma de flutuação; while ((T - início) <1000) {int out = 24 * sin (2 * PI * i * (T - início) / 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 = milis (); k ++; } if (i == 1) {norma = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norma, 3); k = 0; }} loop vazio (vazio) {}

E este código testará a largura de banda ESP32. Certifique-se de remover o capacitor ou os resultados serão os mesmos para os dois métodos.

#incluir

#include Adafruit_ADS1115 ads; / * Use para a versão de 16 bits * / int16_t adc0; int16_t adc1; configuração de vazio (vazio) {float M; float Mp = 0; float S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x ganho +/- 4,096V 1 bit = 2mV 0,125mV ads.begin (); atraso (5000); Serial.println ("Frequência, Amplitude"); para (int i = 1; i <100; i ++) {início longo sem sinal = milis (); T longo sem sinal = milis (); Sp = 0; S = 0; M = 0; Mp = 0; int k = 1; norma de flutuação; while ((T - início) <1000) {int out = 24 * sin (2 * PI * i * (T - início) / 1000,0) + 128; dacWrite (25, out); adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = milis (); k ++; } if (i == 1) {norma = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norma, 3); k = 0; }} loop vazio (vazio) {}

Etapa 5: pensamentos finais

O novo design DAC ganha em linearidade e ruído, mas perde em largura de banda. Dependendo da sua aplicação, um desses índices pode ser mais importante do que o outro. Com esses procedimentos de teste, você deve ser capaz de tomar essa decisão objetivamente!

Além disso, acho que vale a pena apontar aqui que, como a saída PWM é de baixo ruído, com linearidade excepcional, deve ser possível construir um DAC de resolução muito maior com a saída PWM (talvez até mesmo a precisão de 16 bits). Isso vai dar algum trabalho. Até então, eu lhe digo adeus!

Recomendado: