Простой Дельта-Сигма ЦАП. Что это и с чем его едят.

С Цифро-Аналоговыми-Преобразованиями мы уже знакомились в нескольких статьях. Единственный тип этих преобразования, который мы не рассмотрели: метод передискретизации.

  Передискретизация позволяет использовать ЦАП с меньшей разрядностью для достижения большей разрядности итогового преобразования, подобно методу ШИМ.

Одним из видов является Дельта-Сигма преобразование, которое основано на изменении плотности импульсов. Именно импульсов, то есть с помощью одного цифрового вывода можно формировать аналоговый сигнал. Как?

154_4

Путем усреднения импульсов того или иного участка графика мы получаем определенное значение амплитуды. Принцип очень напоминает ЧМ(FM), и как вы могли заметить, для работы необходима опорная частота.

Устройство

DeltaSigmaGraph

 

  • Модулятор — блок, который принимает цифровые данные (сэмпл формата ИКМ) и превращает их в единый поток импульсов, представленных выше.
  • Второй блок делает из импульсов аналоговый сигнал. Причем «Усреднителем» и фильтром будет являться не только ФНЧ(Low-Pass), но и сами узлы аудио-аппаратуры. К примеру, подключив к модулятору напрямую динамик мы уже будем слышать аналоговый сигнал, но с ВЧ шумами.

Вообще термин «Дэльта-Сигма» относится к арифметической разности и суммы соответственно, что мы увидим ниже.

Блок схема модулятора выглядит следующим образом:

 

DeltaSigmaDBlockDiagram

Формирование импульса происходит циклически и количество циклов напрямую зависит от входных данных. То есть, число на входе (сэмпл) изменяет период, что в свою очередь влияет на частоту, а затем на плотность импульсов в общей картине. Как вы можете видеть, имеется отрицательная обратная связь для контроля формирования импульса. Мы «дробим» значения амплитуд на много 1бит импульсов разной частоты.

Одним из преимуществ данной системы является высокое качество при минимальных затратах на компоненты.

Отношение сигнал/шум = Ч.Котельникова * 2N. Для ДС-ЦАП существует константа «оверсэмплинг» — число, определяющее отношение опорной частоты к дискретизации сэмплов(по Котельникову) и она равна 64. К примеру, мы хотим преобразовать поток N-бит 22500Гц: опорная частота = (22500 * 2) * 64 = 2.88MHz.

Блок схема фильтра заключается в простой RC цепочке:

Low_pass_filter

 

В самом простом представлении это ФНЧ, еще эту систему называют дециматором. Мы, фактически, уменьшаем частоту дискретизации выходных импульсов до слышимого диапазона путем их усреднения.

Реализация

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

Схема модулятора разрядностью 8бит:

Ashampoo_Snap_2014.05.06_19h58m33s_001_

 

Ее я подсмотрел у Xilinx. Дельта сумматор вычисляет разность между входным и выходным, на данный момент, сигналом. Это та самая отрицательная обратная связь. Причем выходной сигнал создается Сигма защелкой, дублируется и передается в виде 10бит числа на вход сумматора. (см.рис) И это количество нулей компенсирует тот факт, что у Дельта сумматора входы безнакового типа. Сигма сумматор складывает предыдущее значение с защелки со значением Дельта сумматора. Такими хитрыми манипуляциями мы создаем неоднородный поток импульсов.

Для Фильтра-Низких-Частот и прочего рекомендуют посмотреть таблицу:

Ashampoo_Snap_2014.05.06_20h56m06s_002_

DS ЦАП на ПЛИС

Мы все ближе и ближе приближаемся к ПЛИС. Что ж, за основу я решил взять проект графического процессора. Это MAXII EPM240 с выведенными ногами и внешней SRAM, которую мы пока не будем использовать.

Характеристики будущего ЦАП:

  • Разрядность: 8бит
  • Частота дискретизации сэмплов: 22500Гц

DSCN5541

 

Электрическая схема проста до безобразия. Это ФНЧ, подключенный к порту ПЛИС + светодиод для индикации. Также необходимо подключить внешний тактовый генератор на PIN12 ПЛИС, у меня имелся на плате 50MHz, его я и задействовал.

Ashampoo_Snap_2014.05.06_22h35m45s_003_

 

Наш модуль ЦАП достаточно просто описывается на Verilog-е, код которого я также позаимствовал у Xilinx 🙂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module dac(DACout, DACin, Clk);
output DACout; // This is the average output that feeds low pass filter
reg DACout; // for optimum performance, ensure that this ff is in IOB
input [7:0] DACin; // DAC input 
input Clk;
reg [9:0] DeltaAdder; // Output of Delta adder
reg [9:0] SigmaAdder; // Output of Sigma adder
reg [9:0] SigmaLatch; // Latches output of Sigma adder
reg [9:0] DeltaB; // B input of Delta adder
always @(SigmaLatch) DeltaB = {SigmaLatch[9], SigmaLatch[9]} << (8);
always @(DACin or DeltaB) DeltaAdder = DACin + DeltaB;
always @(DeltaAdder or SigmaLatch) SigmaAdder = DeltaAdder + SigmaLatch;
always @(posedge Clk)
begin
SigmaLatch <= SigmaAdder;
DACout <=  SigmaLatch[9];
end
endmodule

В графическом варианте схема выглядит так: (я добавил защелку для лучшей синхронизации)

Ashampoo_Snap_2014.05.06_22h47m03s_004_

 

Но-но-но! Откуда мы будем брать данные (сэмплы)? Необходим поток ИКМ с частотой 22.5кГц.

Вы можете пересылать данные UART, COM или другим модулем, однако ни того, ни другого у меня нет, поэтому я буду пересылать сэмплы через параллельный интерфейс. Единственный МК с «распушенной» внешней шиной у меня — Arduino Due. Схема подключение представлена ниже, а пины вы можете посмотреть в assigment editor-е:

screen777

Адресная шина нам совсем не нужна, тк. отправлять данные мы будем потоково. Я конечно понимаю, что это забивание гвоздей микроскопом, но как иначе проверить работу ЦАП?

Внесем соответствующие изменения в схему:

Ashampoo_Snap_2014.05.06_23h01m54s_005_

 

Аудио пин, после ФНЧ, необходимо подключить к усилителю, либо в линейный вход звуковой карты ПК.

Задача со стороны МК состоит в отправке 8бит значений амплитуды на любой адрес, но с постоянной частотой 22500Гц. Кстати, метод memcpy() тут не подойдет, так как настроить SMC контроллер на частоту дискретизации не получиться. Единственный вариант: таймер.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include «bmp.h»
#include <DueTimer.h>
#include <Parallel.h>
 
uint32_t i = 0;
uint8_t* spu = (uint8_t*)0×60000000; //SPU ADDR
 
void play() {
  spu[0] = sound[i];
  i = (i<sizeof(sound))? i+1 : 0;
}
 
void setup() {
  Parallel.begin(PARALLEL_BUS_WIDTH_8, PARALLEL_CS_0, 1, false, true);
  Parallel.setCycleTiming(0,0);
  Parallel.setPulseTiming(0,0,0,0);
  Parallel.setAddressSetupTiming(0,0,0,0);
  Timer3.attachInterrupt(play).setFrequency(22500).start();
}
 
void loop() {
 
}

Я ничего не знаю про таймеры в ARM, поэтому использовал библиотеку.  В bmp.h файле находиться всего один массив с аудио данными: const unsigned char sound[x] = {…} Для конвертации можете воспользоваться утилитой wav2c. Или вот вам файл с синусоидой.

Общая конструкция: (почти ничем не отличается от бывшего видеопроцессора)

DSCN5539

 

Испытания

Первое, что приходит в голову: синусоида, с помощью нее мы можем легко определить искажения. Даже после ФНЧ осциллографом можно увидеть опорную частоту:

pic_126_2

 

На вид искажение довольно неплохие. Дельта-Сигма ЦАП справляется гораздо лучше с более высокими частотами, а здесь всего 440Гц. При воспроизведении какого либо звукового фрагмента искажения не так заметны на слух. Я взял фрагмент из одной композиции. bmp.h файл.
То, что получилось на выходе:

Я полагаю, для восьми бит качество очень даже хорошее. При использовании ШИМ или R2R я не смог добиться подобного результата.

Воспроизведение из SRAM

Согласитесь, хоть это и тест, но «воспроизводить» звук Ардуиной, преобразовывать это на ПЛИС — невесть что.

Решение: подключение к ПЛИС микросхемы SRAM. Теперь непосредственно воспроизведением будет заниматься ПЛИС, а Arduino лишь перешлет раз звуковые данные.

screen977

 

По тому же параллельному интерфейсу мы подключаем SRAM, объемом 64кб; к шине адреса и данные прибавляются еще два: WE и OE (связь двухсторонняя). Лучше взять память объемом ~2мБайт, но тогда адресную шину микроконтроллера необходимо будет так же увеличивать. Внесем изменения в схему:

Ashampoo_Snap_2014.05.10_23h39m55s_001_

 

За основу была взята схема видеопроцессора. Алгоритм работы линейный:

  1. Передача звуковых данных из SRAM в ЦАП. 64кб = ~2.5сек
  2. Извещаем микроконтроллер о разрешении записи, путем подачи на пин FRAME (подключите к МК)  низкого уровня.
  3. Открываем доступ микроконтроллеру к памяти. Маршрут: внешняя шина -> ПЛИС -> SRAM.
  4. Задержка на несколько миллисекунд.
  5. Закрываем доступ микроконтроллеру к памяти.

Запустив всю конструкцию без микроконтроллера, мы должны услышать что-то подобное:

Это содержимое памяти после подачи питания. Пора перейти к программе контроллера:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include «bmp.h»
//#include <DueTimer.h>
#include <Parallel.h>
 
uint32_t i = 0;
uint8_t* spu = (uint8_t*)0×60000000; //SPU ADDR
 
//void play() {
  // spu[0] = sound[i];
  // i = (i<sizeof(sound))? i+1 : 0;
//}
 
void setup() {
  Parallel.begin(PARALLEL_BUS_WIDTH_8, PARALLEL_CS_0, 16, false, true);
  Parallel.setCycleTiming(1,1);
  Parallel.setPulseTiming(0,0,0,0);
  Parallel.setAddressSetupTiming(0,0,0,0);
  //Timer3.attachInterrupt(play).setFrequency(22500).start();
  pinMode(53, INPUT);
 
}
 
void loop() {
  if (PIO_Get( g_APinDescription[53].pPort, PIO_INPUT, g_APinDescription[53].ulPin ) == 0) {
    memcpy(spu, sound, 65536);
  }
}

Кстати, задача упростилась: ему необходимо по низкому уровню FRAME ПЛИС отправлять звуковые данные объемом 64кб. Либо отправить их один раз и вовсе отключиться.

Для теста я взял другой фрагмент, так как использовать один и тот же не имеет смысла. Все, что должно измениться — это длительность звучания и независимость от Arduino.

Но действительность может отличаться от теории из-за внешних факторов. Одними из которых являются неудачная разводка платы и перенебрегание блокировочными конденсаторами. Так что причина снижения качества не в схеме ПЛИС или устройстве ЦАП.

Вообще, неплохо бы было добавить регистры управления проигрывателем, тем самым довести его до звукового процессора, но сейчас не об этом.

Видео обоих испытаний:

Файлы тестов (все):

Вы можите оставить комментарий, или поставить трэкбек со своего сайта.

3 комментария к “Простой Дельта-Сигма ЦАП. Что это и с чем его едят.”