Жене мешают смотреть последние новости из телефона и телевизора приходящие поесть (первично ?) и поиграть на компьютере (вторично?) внуки. Она их конечно любит , но звуки их взаимодействия с компьютером ее сильно раздражают. Пришлось надеть на внуков наушники. А звуковой выход у компа в неудобном месте и каждый ребенок хочет звук со своей громкостью. Ну пришлось разработать внешнюю USB звуковую карточку. Хочется и красиво и качественно.  Впрочем, внуки скорее  только повод для поностальгировать по своей старой специальности радиоконструктора и вообще, так как  последние двадцать с лишним лет я далеко от нее и пишу заклинания программы реконструкции изображений для медицинских томографов в больших и не очень фирмах , то есть энжинер-погромист по специальности. Хотел написать статью на эту очень интересную и важную тему (компьютерная томография), но выяснилось что мне нельзя по условиям контракта ...   Итак вернемся к нашим баранам внукам и  звуковым карточкам, которые у  нас есть в нескольких экземплярах ,овер дофига, купил пока были дешевые, модули из Китая: Stm32f401ccu6 black pill – сейчас $3 за штучку; I2S DAC Decoder GY-PCM5102  ->$3.5 за штучку; SPI display ips 1.3 inch 240x240 (controller st7789) ->$7 за два. Сначала построим максимальную конфигурацию из двух экранов и I2S  GY-PCM5102. Конфигурируем куб, разбавляем его говно код своим  г. кодом, добавляем ФАПЧ ( фазовой автоматической подстройки частоты  или  PLL на ихнем ) , для согласования скоростей приходящих от компьютера данных и выдачи на i2s внешний ЦАП (DAC). Хмм , звучит очень неплохо, явно лучше большинства встроенных звуковушек. PCM5102 – весьма и весьма качественный ЦАП за свою цену в пару- тройку долларов за модуль с чипом. Добавляем отображение индикаторов уровня на паре неплохих дисплеев st7789... С ними нужно было немного повозиться. Во первых у этих не выведен CS (Chip Select – ножка выбора чипа) . Поэтому каждому свой SPI ( SPI_1 и SPI_3). Во вторых их DMA (прямой доступ к памяти) сильно тормозит. Соотвественно копирование полного экрана из памяти занимает для SPI_1 - 32 mS  , а для SPI_3  - 51 миллисекунды соотвественно. Исходя из этого стрелки измерителей и их тени(!) отрисовываются и стираются инкрементально что помещается в 8 миллисекунд в сумме на оба экрана. Положение стрелок задается максимумом в примерно 20 мс с постоянной времени затухания 300 мс(примерно как у настоящих VU измерителей). чудесная и актуальная песня В.Высоцкого "Аисты" (video)  И тут я вспомнил , очень давно, больше 30 лет тому назад меня учили на заклинателя синего дыма , то есть я знаю зачем осциллографу ручки, а микросхемам ножки. Ручки – чтобы их дергать, а ножки -  чтобы ими дергать! Может можно ли рендедерить звук самой Stm-кой , без внешнего i2s чипа?   На этом чипе (STM32f401) нет  ЦАП-а. К качестве оного можно использовать таймер с его ШИМ (PWM) или SPI.    Таймеры можно инициализировать на два три или 4 канала для N уровней сигнала на частоте Fbus = 84 Мгц мы получим частоту дискретизации Fds =  84 000 000 / N , или наоборот N=Fbus/ Fds . Например для частоты дискретизации 44100 Гц мы получим  84 000 000/44100 = 1904 уровня, что соотвествует примерно log2(1904) = 10.9 бит.  Ну или на 96000 Гц соотвественно 84МГц/96КГц = 875 уровней что соотвествует 9.8 бит Маловато будет.    SPI может выдавать только два уровня 0 или 1, правда до 42 мегабит в секунду.   Хмм.. 1 бит  мало однако ... есть PDM (Pulse-density modulation не знаю как точно по русски)!  Сформулируем тоже в виде кода(входной сигнал от -1.0 до 1.0 ) в цикле: Прочитать данные левого и правого каналов из приемного циклического буфера USB c интерполяцией (лучше билинейной). Вызвать функцию  sigma_delta. Результат отправить на выдачу . Фокус тут в том что если входной сигнал ограничен некоторой частотой, а частота семплирования (отсчетов) достаточно велика , то пропустив выходной сигнал через фильтр нижних частот получим сигнал приближенный к исходному, причем тем лучше чем больше частота семплирования! Рассмотрим пример. Входной сигнал – постоянный x=0.31415   для 10 вызовов фунция даст вот такую последовательность [1,-1, 1,1,-1,1,1,-1,1,1] их среднее будет 0.4 , для 1000 вызовов среднее будет 0.314 , для 10000  -> 0.3142 и тд. То есть, чем больше частота отсчетов, тем аккуратнее апроксимация ограниченного по частоте входного сигнала. Фокус изобрели в 60-х годах прошлого века. К сожалению, реализовать этот алгоритм прямо на stm -ке с генерацией бит и выдачей на SPI у меня не получилось, неободимая частота должна быть около 2.884 Мгц (https://en.wikipedia.org/wiki/Super_Audio_CD) . Выглядит малореальным сгенерировать два канала с семплированием с интерполяцией из usb буфера и вызовом функции  sigma_delta для каждого бита и упаковки бит на выдачу в SPI  при частоте процессора всего 84 Мгц. Всего 15 клоков на левый и 15 клоков на правый каналы на бит при забитой DMA шине – это нереально... Облом ?    А что если переписать  sigma_delta так, чтобы она выдавала не два уровня сигнала [1 -1] (с одним компаратором около нуля ), а больше ?  Например 4 уровня [3 1 -1 -3] ? Или еще больше, например N+1 (мы заодно сместили входной и выходной сигнал к диапазону от [0 N], так нужно для выдачи ШИМ на таймер): Ура – мы изобрели велосипед.  Если бы я внимательней читал статью про Delta-sigma modulation то обратил бы внимание что один бит – это частный случай, о чем там написано черным по белому :( Теперь мы можем выбрать удобный для реализации компромисс между частотой отсчетов и количеством дискретных уровней.  Простая дискретизация сигнала дает равномерный по частоте шум величиной в половину шага дискретизации. Сигма дельта дает шум прямо пропорциональный частоте сигнала(в первом приближении). То есть энергия спектра шума дискретизации смещается вверх, за пределы слышимых частот!  Фокус можно повторить с двойным , тройным и тд интегралом:      Есть аналогия с цифровыми фильтрами низкой частоты высоких порядков. Однако дизайн стабильных фильтров высокого порядка оставим профессионалам (по дизайну фильтров) . В коде мы реализуем простой фильтры первого и второго порядка, с реализацией в числах с фиксированной точкой (у нас на STM это самый быстрый тип int32_t ). Для реализации я выбрал частоту 101 Кгц  соотвественно количество уровней 828 (84МГц/101КГц) на сигма-дельта  второго порядка интегрирования, впрочем при желаниии  можно поиграть с опциями.  Количество дисплеев лучше задать 0 для конфигурации с сигма- дельта, поскольку помехи от них будут слышны в наушниках, впрочем не очень сильные, слушать можно. Но предпочтительный вместе с индикаторами уровня использовать внешний DAC или организовывать развязку питания для них. Без дисплеев , с RC фильтром низкой частоты сигма-дельта на STM32f401 дает очень хороший звук, лучше большинства встроенных звуковых карточек на недорогих компах и явно лучше дешевых китайских звуковых затычек USB->3.5мм для наушников. PS. Профи в области обработки звука и радиоконструкторы, не придирайтесь. Во первых за 30 с лишним лет я много забыл и сейчас в этой области я просто любитель. Во вторых не хотелось переусложнять математикой статью тут ее реально нужно много для детального описания .. Еще Видео : Снег кружится группы Пламя  удалил ,жадные правообладатели уже нажаловались. Ну и фиг с ними. На эту тему Analog Devices ( осторожно English, есть много интересных ссылок в конце ) Ну и исходный код на гитхабе   image processing