Оглавление:

Как сделать и протестировать лучший ЦАП с ESP32: 5 шагов
Как сделать и протестировать лучший ЦАП с ESP32: 5 шагов

Видео: Как сделать и протестировать лучший ЦАП с ESP32: 5 шагов

Видео: Как сделать и протестировать лучший ЦАП с ESP32: 5 шагов
Видео: Доработка ESP32 ВАЖНО! 2024, Ноябрь
Anonim
Как сделать и протестировать лучший ЦАП с ESP32
Как сделать и протестировать лучший ЦАП с ESP32
Как сделать и протестировать лучший ЦАП с ESP32
Как сделать и протестировать лучший ЦАП с ESP32

ESP32 имеет 2 8-битных цифро-аналоговых преобразователя (ЦАП). Эти ЦАП позволяют создавать произвольные напряжения в определенном диапазоне (0–3,3 В) с разрешением 8 бит. В этом руководстве я покажу вам, как построить ЦАП и охарактеризовать его производительность, а также сравню его с ЦАП ESP32. Индексы производительности, на которые я буду смотреть, включают

  • Уровень шума
  • Пропускная способность
  • Интегральная нелинейность
  • Дифференциальная нелинейность

Для проверки этих показателей я буду использовать ADS1115.

Важно отметить, что ваша оценка всех этих показателей будет настолько точной, насколько точна ваше эталонное устройство (в данном случае ADS115). Например, ADS115 не имеет 16-разрядной точности, когда дело касается смещения напряжения и усиления. Эти ошибки могут достигать 0,1%. Для многих систем эти ошибки можно игнорировать, если абсолютная точность не имеет большого значения.

Запасы

  • ADS1115
  • Доска ESP32
  • макет
  • перемычки
  • Резистор 5 кОм
  • 1 керамический конденсатор Фарад

Шаг 1: разметка макета

Макет макетной платы
Макет макетной платы

Подключите следующие контакты

Между ESP32 и ADS1115

3v3 VDD

GND GND

GPIO22 SCL

GPIO21 SDA

На ADS1115

ADDR GND (ADS115)

Изготовление ЦАП

Есть много способов сделать ЦАП. Самый простой - это фильтр нижних частот для ШИМ-сигнала с помощью резистора и конденсатора. Я мог бы добавить сюда операционный усилитель в качестве буфера, но хотел, чтобы все было просто. Этот дизайн прост и дешев для реализации с любым микроконтроллером, поддерживающим ШИМ. Я не буду здесь останавливаться на теории конструкции (Google PWM DAC).

Просто подключите GPIO255 кОм резистор 1 мкФ конденсатор gnd

Теперь подключите перемычку от точки, где резистор встречается с конденсатором, к A0 на ADS115.

Шаг 2: Оцените отношение сигнала к уровню шума

Оценить уровень сигнала и шума
Оценить уровень сигнала и шума

Чтобы оценить уровень шума, просто запустите сценарий ниже. Чтобы оценить это, мы просто оставляем ЦАП на фиксированном значении и измеряем колебания напряжения во времени.

Из-за конструкции ЦАП шум будет самым большим, когда сигнал ШИМ имеет рабочий цикл 50%. Поэтому здесь мы и будем его оценивать. Мы также оценим ESP32 на том же уровне сигнала. Мы также отфильтруем ЦАП ESP32 с тем же фильтром нижних частот, чтобы измерения были сопоставимы.

Для меня вывод был очевиден. Конструкция PWM имела более высокий SNR на> 6 дБ (это в 2 раза лучше). Явная победа для нового ЦАП. Одна небольшая проблема заключается в том, что в АЦП встроены фильтры, которые определенно улучшают отношение сигнал / шум. Таким образом, может быть трудно интерпретировать абсолютные значения. Если бы я использовал фильтр второго порядка, этого не было бы.

В любом случае код ниже

#включают

#include Adafruit_ADS1115 ads; // библиотека adafruit для adc int16_t adc0; // установка void (void) {Serial.begin (115200); // Запускаем серийный номер ads.setGain (GAIN_TWO); // 2-кратное усиление +/- 2,048 В 1 бит = 0,0625 мВ ads.begin (); // начинаем adc float M = 0; // начальное среднее значение с плавающей запятой Mp = 0; // предыдущее среднее значение с плавающей запятой S = 0; // начальная дисперсия float Sp = 0; // предыдущая дисперсия const int reps = 500; // количество повторов int n = 256; // количество выборок ledcSetup (0, 25000, 8); // устанавливаем частоту ШИМ = 25000 Гц при разрешении 8 бит ledcAttachPin (25, 0); // устанавливаем шим на вывод 25 ledcWrite (0, 128); // установить половину рабочего цикла (самый большой шум) delay (3000); // ждем установления времени float snrPWM [reps]; // массив snrs для ШИМ float snrDAC [reps]; // массив snrs для DAC for (int i = 0; i <reps; i ++) {// цикл по повторениям for (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; // установить предыдущую дисперсию} // snr в дБ snrPWM = 20 * log10 (3.3 / (sqrt (S / n) *.0625 *.001)); // сбросить значения M = 0; Mp = 0; S = 0; Sp = 0; } ledcDetachPin (25); // отключаем ШИМ от вывода 25 dacWrite (25, 128); // запись в ЦАП delay (3000); // ждем, пока установится (int i = 0; i <reps; i ++) {// то же, что и цикл ШИМ для (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; } // строим SNR на одном графике для (int i = 1; i <reps; i ++) {Serial.print ("PWM_SNR (dB):"); Serial.print (snrPWM ); Serial.print (","); Serial.print ("ESP32_SNR (дБ):"); Serial.println (snrDAC ); }} недействительный цикл (void) {}

Шаг 3: интегральная нелинейность и дифференциальная нелинейность

Интегральная нелинейность и дифференциальная нелинейность
Интегральная нелинейность и дифференциальная нелинейность

Интегральная нелинейность - это приблизительная мера отклонения между выходным напряжением вашего ЦАП и прямой линией. Чем больше это, тем хуже …

Дифференциальная нелинейность - это приблизительная мера того, насколько наблюдаемое изменение напряжения (от одного кода к другому) отклоняется от того, что можно было бы ожидать от прямой линии.

Результаты здесь были действительно интересными. Во-первых, оба имеют ошибку менее 0,5 фунта / кв. Дюйм (при 8-битном разрешении), что хорошо, но у ШИМ гораздо лучшая интегральная линейность. Оба имеют сравнимую дифференциальную нелинейность, но у ЦАП ESP32 есть очень странные шипы. Более того, метод ШИМ имеет некоторую структуру ошибок. По сути, он чередуется с перерегулированием и занижением правильного напряжения.

Я подозреваю, что это какая-то странная ошибка округления в том, как 8-битный сигнал ШИМ создается на ESP32.

Один из способов исправить это - быстро переключаться между двумя соседними кодами (например, 128, 129) с помощью ШИМ. С аналоговым фильтром нижних частот результирующие ошибки будут в среднем равны нулю. Я смоделировал это в программном обеспечении, и действительно, все ошибки исчезли. Теперь метод ШИМ имеет линейность с точностью до 16 бит!

Anywho код для генерации данных ниже. Вывод будет на последовательном мониторе в формате.csv. Просто скопируйте его в текстовый файл для дальнейшей обработки.

#включают

#include Adafruit_ADS1115 ads; / * Используйте это для 16-битной версии * / int16_t adc0; установка void (void) {Serial.begin (115200); ads.setGain (GAIN_ONE); // 2-кратное усиление +/- 2,048 В 1 бит = 1 мВ 0,0625 мВ ads.begin (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); Serial.println («Ожидаемый, наблюдаемый»); ledcWrite (0, 2); задержка (3000); для (int я = 2; я <255; я ++) {ledcWrite (0, я); задержка (100); adc0 = ads.readADC_SingleEnded (0); ожидаемое число с плавающей точкой = (i / 256.0 * 3.3) / 4.096 * 32767; Serial.print (ожидается); Serial.print (","); Serial.println (adc0); }} недействительный цикл (void) {}

Шаг 4: пропускная способность

Пропускная способность
Пропускная способность

Я собираюсь определить здесь полосу пропускания как частоту, при которой выходной сигнал ЦАП падает на 3 дБ. Это условность и до некоторой степени произвольная. Например, в точке 6 дБ ЦАП по-прежнему будет выдавать сигнал с амплитудой примерно 50%.

Чтобы измерить это, мы просто пропускаем синусоидальные волны с возрастающей частотой от ЦАП к АЦП и измеряем их стандартное отклонение. Неудивительно, что точка 3 дБ находится на частоте 30 Гц (1 / (2 * pi * 5000 * 1e-6)).

ESP32 может делать 1 мегасэмпл в секунду. Это очевидная победа для ESP32. Его амплитуда вообще не уменьшается в тестовой области с полосой пропускания 100 Гц.

Приведенный ниже код может проверить пропускную способность ЦАП с ШИМ.

#включают

#include Adafruit_ADS1115 ads; / * Используйте это для 16-битной версии * / int16_t adc0; int16_t adc1; установка void (void) {float M; поплавок Mp = 0; поплавок S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x усиление +/- 4,096 В 1 бит = 2 мВ 0,125 мВ ads.begin (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); задержка (5000); Serial.println («Частота, Амплитуда»); для (int я = 1; я <100; я ++) {беззнаковый длинный старт = миллис (); беззнаковое длинное T = millis (); Sp = 0; S = 0; M = 0; Mp = 0; int k = 1; норма поплавка; while ((T - начало) <1000) {int out = 24 * sin (2 * PI * i * (T - начало) / 1000.0) + 128; ledcWrite (0, вне); adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; Т = миллис (); k ++; } если (я == 1) {норма = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norm, 3); k = 0; }} недействительный цикл (void) {}

И этот код проверит пропускную способность ESP32. Обязательно удалите конденсатор, иначе результаты будут одинаковыми для обоих методов.

#включают

#include Adafruit_ADS1115 ads; / * Используйте это для 16-битной версии * / int16_t adc0; int16_t adc1; установка void (void) {float M; поплавок Mp = 0; поплавок S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x усиление +/- 4,096 В 1 бит = 2 мВ 0,125 мВ ads.begin (); задержка (5000); Serial.println («Частота, Амплитуда»); для (int я = 1; я <100; я ++) {беззнаковый длинный старт = миллис (); беззнаковое длинное T = millis (); Sp = 0; S = 0; M = 0; Mp = 0; int k = 1; норма плавания; while ((T - начало) <1000) {int out = 24 * sin (2 * PI * i * (T - начало) / 1000.0) + 128; dacWrite (25, выход); adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; Т = миллис (); k ++; } если (я == 1) {норма = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norm, 3); k = 0; }} недействительный цикл (void) {}

Шаг 5: заключительные мысли

Новая конструкция ЦАП выигрывает по линейности и шуму, но проигрывает по полосе пропускания. В зависимости от вашего приложения один из этих показателей может быть более важным, чем другой. С помощью этих процедур тестирования вы сможете объективно принять это решение!

Кроме того, я думаю, что здесь стоит указать, что, поскольку выход ШИМ имеет низкий уровень шума, с исключительной линейностью можно создать ЦАП с гораздо более высоким разрешением с выходом ШИМ (возможно, даже с 16-битной точностью). Это потребует некоторой работы. А пока я прощаюсь с вами!

Рекомендуемые: