Как стать автором
Обновить

“Сигма дельта” или как сделать хорошую звуковую карту из STM32F401

Время на прочтение5 мин
Количество просмотров17K
Всего голосов 31: ↑30 и ↓1+40
Комментарии71

Комментарии 71

У какого из них? Первый вариант с i2s очень качественный. Второй вариант все рано нуждается в доработке схемотехники. В теории он весьма и весьма неплох. Да и на практике звучит у меня лучше чем встроенная в лаптопе карточка. Немного шумит за счёт плохой развязки питания, но это решаемый вопрос.

очень качественный

а как это оценить без измерений-то?

звучит у меня лучше чем встроенная в лаптопе карточка

даже PCM270x без внешнего цапа звучит лучше, чем встроенная

Измерений чего ? Откройте документацию на чип https://www.ti.com/lit/ds/symlink/pcm5102.pdf

и посмотрите , у них все померяно... Я вполне доверяю этой компании. Дайте нормальное питание и Вы в дамках. Тут как раз все просто.

Вот с сигма дельтой , без внешнего ЦАПа, надо повозиться. Попробую сделать внешний повторитель со стабильным питанием, я специально вывел с таймеров комплементарные сигналы с STM - ки.

"Дайте нормальное питание и Вы в дамках. Тут как раз все просто."

Возможно, кому-нибудь пригодится мой опыт: В pcm5102 имеется встроенный генератор отрицательного напряжения и для него устанавливаются два конденсатора (между 2 capp(+) и 4 capm(-) ногой и 5 vneg(-) и землёй(+). В скобках указана полярность). Так вот, в даташите их ёмкость рекомендована 2.2мкф. Этого довольно мало, и при двух каналах с выходным сопротивлением 1 кОм образуется некий жутко не линейный ФНЧ 2-го порядка с частотой среза примерно 140 Гц. Так вот, я бы рекомендовал заменить оба конденсатора на 10 мкф x 16в и применить в данном случае специализированные электролиты (мой личный выбор ELNA Silmic). На слух будет на порядок лучше. Эти конденсаторы - самое слабое место данной микросхемы. Так я "патчил" китайские цапы.

Спасибо, интересно. Может чипы левые? :)

Они вроде пишут , что 1 ком это минимально допустимое сопротивление нагрузки. Видимо замеры они делали на 10 ком нагрузки.

Допустимое — это то, что ещё не выводит из строя. Все замеры делаются при других, адекватных условиях (указаны в шапке таблицы или сносках).

C этим никто вроде и не спорит.

Мне показалось, Вы смущены тем, что паспортные параметры снимаются не в предельных режимах.

Как раз не смущен

Показалось, подумал Штирлиц.

Посмотреть бы в RightMark Audio Analyzer что получилось.

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

Ким19+20 можно снять и с любым некачественным АЦП + ФНЧ 2..6 порядка.

А я и не совсем против, снимайте. Повторяю "Меня вполне устраивает качество звука." за $3. Звучит на $30, как минимум :)

Это на случай, если Вам самим интересно и вдруг не знали о способе) Ну или похвастаться. Вдруг он звучит на $300?

Не-а на $300 врядли .

Тут много чего померить надо кроме интермодуляции 19-20кгц. И шумы возле 1 кгц, и уровень нечетных гармоник. Я еще думаю... Сначала думать, потом мерить.

А что показывают шумы возле 1кГц? Паразитную модуляцию?

Собственно качество работы алгоритма - подавление шума дискретизации.

Пик чувствительности уха (ОБАУХА,ОБАНАУХА?) - 1000 Гц.

Вы имеете в виду — шум квантования?

Да . Подзабыл терминологию на русском. Половина ступеньки.

А как вы в SPI выводите четыре уровня?

При выходной частоте 101кГц выходной ФНЧ уже не ставили?

На F401 вроде есть QSPI. Можно было бы на него R2R лестницу повесить и иметь 16 уровней. Ну, или с таймерами пошаманить или даже с FSMC, просто выводя семплы на шину памяти.

Впрочем, гнать 84Мгц наружу да еще на параллельную шину не очень хорошая идея

Не SPI - a PWM - таймеры. SPI был отвергнут по причине "не успеваю посчитать"... В статье об этом есть. Если прямо на наушники, то ФНЧ вообщем то не нужен. Но если после стоит какой нибудь недорогой усилитель класса D - то обязательно нужен.

Обожаю когда люди создают что-то на стыке разных областей. Описанный вами случай - из этой серии.

И ещё... спасибо вам огромное за real engineering - очень интересно!

Сам хотел спаять платку расширения для малинки чтобы 5.1 звук слушать, но так и не добрался до этого.

Pulse-density modulation не знаю как точно по русски

Возможно... Широтно-импульсная модуляция.

Не-a ... ШИМ (широтно импульсная) это PWM ( pulse width modulation ), дословно. Это все таки другая модуляция, похожая, но другая.

Тогда переводим дословно - импульсно-плотностная модуляция. :)

Хмм. Не импортозамещается :(

Из словаря:

 Telecoms (En-Ru)

pulse-density modulation

импульсно-плотностная модуляция (для смягчения цифрового звука после декодирования в CD-проигрывателе фирмы Harman/Cardon)

Ну только если Харман/Кардон... На CD , ах да " световая пластинка " :)

Импульсно-плотностная ... Не очень как то...не звучит.

"Других писателей у меня для вас нет!" :)

Вот и я о том-же.

Импульсно-ёмкостная - очень даже ничего.

Ничего конечно, если емкость подходящая :)

Может - амплитудная модуляция?

Да уж. Русский точно не язык техники.

Число-импульсная?

"Да нет наверное"

Google переводчик (при поиске) из Wiki даёт такой перевод:
Переведено с английского языка. — Пульсационная модуляция, или PDM, является формой модуляции, используемой для представления аналогового сигнала с двоичным сигналом. Википедия (Английский язык)

Почему в микроконтроллерах нет аппаратного модуля sigma delta модулятора подобно pwm?

Видимо не пользуется достаточным спросом. Есть специализированные микросхемы, которые делают это намного лучше, например pcm5102a

Встречал решение, где два канала таймера в режиме 8-бит ШИМ управлялись каждый своим байтом двухбайтного отсчёта и их отфильтрованные выходные напряжения складывались в пропорции 1/256. По способу с СДМ - подход с СДМ применительно к МК, конечно, инновационный, но искомый однобитовый поток можно получить напрямую из компа, изменив дескриптор формата, так, чтобы комп понимал, что устройство от него хочет. В этом случае хост будет отправлять не отсчёты PCM, а нужный перекодированный сигнал. Только для него понадобится, скорее всего, usb hs (привет в сторону stm32f723)

Встречал решение, где два канала таймера в

При работающем USB каналы даже одного таймера иногда расползаются. Писал об этом здесь https://habr.com/ru/post/523836/

Впрочем может я чтото не так делал

Только для него понадобится, скорее всего, usb hs

Достаточно FS - 12 Mbps . 2.884Mbps*2 это всего 5.768Mbps .

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

А фиг его знает, будет или нет. PCM - все операционки умеют выдавать.

Кроме того stm32f401 отлично справляется с перекодированием PCM в модифицированный на 8-9 бит СДМ на 300 кГц, такой вот виртуальный АЦП :). Я немного переделал выдачу звука на открытый сток - смотрите схему. Помеха от питания ушла в ноль. Земля, в отличие от питания, внутри чипа тихая, на нее работающий по SPI дисплей почти не влияет. Сейчас вообще все отлично работает, только немного код еще почищу.

Если формат DSD over PCM - то, все же, во-первых, нужен UAC2 в дескрипторе , а во-вторых, USB HS на физике, т.к., по стандарту этого формата один байт из каждых трёх служит маркером формата и попеременно маркером канала в составе данных в этом формате. А в дескрипторе при этом оставляем PCM.

Мы рассматриваем принципиально разные классы устройств. Они в разных весовых/ценовых категориях.

Реализую похожее на FPGA. Только у меня это будет сразу усилитель D класса. Сильный упор на качество не делаю, но постараюсь сделать как можно качественнее, на сколько хватит ресурсов.

Несущую выбрал 384кГц, на эту частоту больше выбора силовых ключей. При этой частоте, разрядность ШИМ получается равной 9 битам (модулятор при этом просит около 200мГц). Больше сделать проблематично, так как от FPGA EP2C5T144C8N можно получить стабильную работу на частотах не более 260мГц. Другой ПЛИСины у меня пока нет, обкатываюсь на этой. Модулятор работает хорошо как в тестбенчах, так и в железе.

Исходный сигнал - 24 бит, 48кГц. АЦП - PCM1802. Просто потому что нашел ее в виде модуля на Али. До 384кГц довожу оверсемплингом, построенном на самопальном КИХ фильтре на 128 коэффициентов. КИХ тоже работает хорошо. Может работать на тактовой до 60МГц, но его можно еще ускорить, если конвейеризовать некоторые узкие места (в самом умножителе и между его выходом и сумматором. Мне лень было всовывать регистры между ними). Но текущей его производительности хватает и так с головой на 50 МГц. Однако, вместо Дельта-Сигмы я решил попробовать нойзшейпинг. Он точно так же должен сместить шум квантования вправо по спектру.

Из текущих проблем, чтобы впервые запустить это дело и проверить:

  1. Переделать I2S интерфейс. Я его делал первым, попутно осваивая Verilog и технологии FPGA. Потому там сплошная асинхронщина. На выходных реализую синхронный дизайн этого модуля.

  2. Разобраться с расчетом фильтра в петле ОС нойзшейпера. Можно попробовать сделать третьего порядка и вручную поиграться с коэффициентами, чтобы по получившейся импульсной характеристике провести анализ и определиться с методикой расчетов.

Ваш вариант с "многобитной" дельта-сигмой тоже попробую.

Ваш вариант с "многобитной" дельта-сигмой тоже попробую.

Будут результаты, поделитесь пжл...

Сделал Ваш вариант. Играет в принципе нормально, но чем больше каскадов ставлю последовательно (увеличиваю порядок модулятора), тем громче становится фоновый шум. По идее, он должен был смещаться за пределы слышимого диапазона, но пока что-то идет не так. Может где-то напортачил. Привожу главный кусок реализации модулятора 3 порядка на Verilog

Hidden text
	// Data lines
	wire[23:0] leftQuantizer;
	wire[23:0] rightQuantizer;
	
	// Delta 0
	wire[23:0] left_delta_0 = leftNsIn - leftQuantizer;
	wire[23:0] right_delta_0 = rightNsIn - rightQuantizer;
	
	// Sigma 0
	reg[23:0] left_sigma_0 = 0;
	reg[23:0] right_sigma_0 = 0;
	
	always @(posedge clock or posedge reset) begin
		if(reset == 1'b1) begin
			left_sigma_0 <= 0;
			right_sigma_0 <= 0;
		end else begin
			if(integr_enable == 1'b1) begin
				left_sigma_0 <= left_sigma_0 + left_delta_0;
				right_sigma_0 <= right_sigma_0 + right_delta_0;
			end
		end
	end
	
	// Delta 1
	wire[23:0] left_delta_1 = left_sigma_0 - leftQuantizer;
	wire[23:0] right_delta_1 = right_sigma_0 - rightQuantizer;
	
	// Sigma 1
	reg[23:0] left_sigma_1 = 0;
	reg[23:0] right_sigma_1 = 0;
	
	always @(posedge clock or posedge reset) begin
		if(reset == 1'b1) begin
			left_sigma_1 <= 0;
			right_sigma_1 <= 0;
		end else begin
			if(integr1_enable == 1'b1) begin
				left_sigma_1 <= left_sigma_1 + left_delta_1;
				right_sigma_1 <= right_sigma_1 + right_delta_1;
			end
		end
	end
	
	// Delta 2
	wire[23:0] left_delta_2 = left_sigma_1 - leftQuantizer;
	wire[23:0] right_delta_2 = right_sigma_1 - rightQuantizer;
	
	// Sigma 2
	reg[23:0] left_sigma_2 = 0;
	reg[23:0] right_sigma_2 = 0;
	
	always @(posedge clock or posedge reset) begin
		if(reset == 1'b1) begin
			left_sigma_2 <= 0;
			right_sigma_2 <= 0;
		end else begin
			if(integr2_enable == 1'b1) begin
				left_sigma_2 <= left_sigma_2 + left_delta_2;
				right_sigma_2 <= right_sigma_2 + right_delta_2;
			end
		end
	end
	
	assign leftQuantizer = {left_sigma_2[23:15], 15'd0};
	assign rightQuantizer = {right_sigma_2[23:15], 15'd0};

Управляется просто:

По приходу фронта на вход "data_valid", пришедшая выборка из апсемплера фиксируется во входных регистрах (в коде не приведены) leftNsIn и rightNsIn. Далее простая машина состояний по очереди раздает импульсы разрешения интеграторам, начиная с нулевого интегратора и заканчивая последним. После фиксирует результат в выходных регистрах.

Спасибо большое, я посмотрю завтра с утра, на свежую голову.

Интересный проект. Я не специалист, но мне кажется, что с многобитной дельта-сигма модуляцией

компромисс между частотой отсчетов и количеством дискретных уровней

однозначно решается в пользу дискретных уровней. Потому что, при постоянном битрейте, уменьшая частоту линейно (в N раз), мы увеличиваем разрешение сигнала экспоненциально (в 2^N раз). Выходит, что при наличии у МК N свободных выводов можно снизить частоту дискретизации в 2^N/N раз и с помощью R-2R схемы получить сигнал того же качества.

У него (stm32f401) нет DMA на паралельный порт. Поэтому ничего не выйдет. В остальном Вы тоже не правы,

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

Это не так .Однозначно в пользу частоты семплирования. Почитайте документ от Analog Devices по ссылке в конце статьи , там все есть, про профиль шума.

Допустим что частота таимера F . Количество уровней N . Тогда частота отсчетов K=F/N.

Обьем передаваемой информации V = K*log2(N) . Подставляем V = F*log2(N)/N. Чем меньше N тем больше результат.

Спасибо за замечание. Просто возникла мысль, что с помощью того же количества бит можно передать больше информации, если биты будут иметь разные веса (равные степеням двойки). Если бы у МК был быстрый и дешёвый способ выводить 8-битное число в параллельный порт 328125 раз в секунду, то мы получили бы сигнал, аналогичный 1-битному на 84 МГц. Другое дело, что на данном МК делать прерывание с такой частотой не рационально.

Ну а при равных весах бит действительно верна формула:

Обьем передаваемой информации V = K*log2(N)

328125 раз в секунду, то мы получили бы сигнал, аналогичный 1-битному на 84 МГц

Нет , не получили бы. Вы не прочитали документ от Analog Devices. Туту вообще фокус не в выводе , а в предобработке и смещении спектра шума, даже при том же выходном потоке бит в секунду.

DMA на GPIO? Запрашивает таймер, адрес данных - в памяти, адрес периферии - gpiox->dr, копируется байт или слово двухбайтное.

Да ,я видел Application note AN4666, но на младших (f103) у меня не заработало.Не помню уже что за проблемы были, но не получилось. Впрочем я особо и не упирался.

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

Спасибо, посмотрю.

Жалко я не видел раньше этот апноте. Это тоже самое. Немного разные реализация собственно фильтра, у Вас с ST и у меня, но да это тоже самое. Я ведь написал , что изобрел велосипед, ничего нового...

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

С h bridge я экспериментировал, так себе звук выходит.

у меня как раз h-bridge c выпотрошенными прошловековыми 'компьютерными' колонками в качестве нагрузки -- вполне приемлемо.

возможно, длительность deadtime была недостаточной.

Скорее бриджи были барахольные у меня. Я драйвера от моторчиков пробовал разные дешевые, им явно не хватало скоорости за пределами спека

Да, тоже пытался было найти подходящий мост, но не преуcпел --

наколхозил из рассыпухи. Если у публики есть подсказки на этот счёт --

дайте знать пожалуйста.

А из чего можно сделать 8.1 звук на usb? использовал в свое время 5.2 наушники usb. Очень нравились. Фильмы HD на них отличались от стерео в заметно лучшую сторону. Разница в ощущениях у меня была такая же как при переходе от моно к стерео.

Я предполагаю, что любой процессинг на оба уха проще (и качественнее) делать на компьютере сотвествующим драйвером на лету. Просто поищите специальный драйвер, не знаю как под виндами, но на линуксе вклеить свой обработчик без проблем (вроде) . По идее - это смешивание каналов и свертка с некоторой специальной последовательностью (немного эха и тд) На этой стм-ке это весьма проблематично , она и так перегружена, можно добавить только несложный процессинг, вроде регулировки глубины стереоэффекта смешиванием сигнала каналов в фазе или противофазе. Или нужна стм-ка побыстрее(stm32f407 или stm32f7х ). Или добавить специальный чип вроде PT2387. Правда сильно подозреваю что он делает именно "регулировку глубины стереоэффекта смешиванием" , что можно легко делать и на стм

У меня были не предобработка звука, как делают многие производители. Я разбирал наушники, в каждом были честные 4 динамика, отдельно подключающиеся к микросхеме. Звук был честным 5.2 (в каждом ухе по отдельному динамику для низких частот). В винде определялись как звуковая плата с соответствующим выбором подключений. На мат.платах компьютеров звуковая микросхема подключается к USB или хитро как нить к чипсету? Мысли вырезать ножовкой кусок от старой мамки, восстановить питание и подключить. Имеет ли смысл вот в чем вопрос?

По разному подключается, иногда прямо на шине , иногда через юсб.

// Четыре динамика

Да, а проводов сколько и какой разъем?

Что характерно есть похожая старая идея где вместо SPI как быстрый однобитовый ЦАП используется выход данных I2S - NoDAC. Тоже сдвигвый регистр но длиннее.
Код дельта-сигма кодирования битов на лету на удивление эффективен на ESP.

Ну я как бы таймеры в режиме PWM использую. Померил тут недавно, получил -82 dB и 0.07% искажений. На ESP так не получится, слишком шумная шина.

Вот они все по сути шумные, особенно если не обращать внимания на землю и развязывающие конденсаторы :) Да и кому в голову придёт питать выход от шумной линии.

82 дБ для PWM очень неплохо. Любопытно было бы взглянуть на данные по шуму и спектру 1 кГц синуса. Есть картинки?

Я их снес давно. Выложу на github когда найду(если) или перемерю. В той схеме , что на github-е искажения большие (около 2%) когда нагружены на наушники, за счет ассиметриии зарял-разряд , но не противные , так как четные. И для корректного измерения довольно много обвязки нужно, я ее собираю на макетке и потом разбираю.

Нет, не напрямую. Там резистор на 200 Ом к плюсу, и резистор и конденсатор последовательно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории