Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 5
×

Звукова підсистема на одноплатних комп’ютерах

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Деякий час тому мене зацікавило, як влаштована звукова підсистема на одноплатних комп’ютерах (SBC). Ця стаття — короткий підсумок аналізу декількох моделей SBC, що базуються на SoC Rockchip RK3328, Rockchip RK3399 та Allwinner A64.

Загальний огляд

Аудіотракт можна розглядати як абстрактну чорну скриньку з входом та виходом. На вхід подаємо семпли, на виході отримуємо звукові коливання. Якщо заглянути всередину цієї скриньки, то там буде ще кілька «скриньок» сполучених між собою, приблизно як на цій діаграмі:

uOZIpDs

Компоненти, які використовуються для цих функціональних блоків, у кожному SBC різні, але загальний принцип однаковий: два основні блоки, котроллер I2S та CODEC, сполучені за допомогою I2S шини.

CODEC

Для початку розглянемо CODEC (COder/DECoder). Цей компонент, головна функція якого конвертування цифрових даних (байтів) в аналоговий сигнал, та навпаки. Два основні його блоки: DAC (digital-to-analog converter) та ADC (analog-to-digital converter). CODEC може мати кілька цифрових входів-виходів і кілька аналогових: мікрофон, лінійний вхід, динамік, навушники, лінійний вихід, тощо. Окрім конвертерів, CODEC зазвичай має й інші функціональні частини: внутрішні підсилювачі та послаблювачі, мікшери, реалізації різних DSP алгоритмів. Все це разом дещо нагадує пульт в студії звукозапису.


Realtek ALC5640
Fqxje0M

CODEC може бути реалізований як внутрішній IP блок SoC або як фізично окрема мікросхема. Від того як це зроблено залежить спосіб, яким операційна система контролює його налаштування. У випадку інтеграції на SoC, процесор може отримати прямий доступ до регістрів CODEC-у через «вікно» в фізичній пам’яті. Якщо ж це окрема мікросхема, то всі операції з регістрами виконуються за допомогою послідовної шини даних, яка зв’язує CODEC та SoC. Найчастіше для цього використовується I2C.

Якщо CODEC не має внутрішнього підсилювача, або він недостатньо потужний, то між аналоговим виходом та динаміком ставиться зовнішній підсилювач, зазвичай з можливістю керування ним операційною системою, яка може вмикати його при програванні звуку та вимикати коли він не потрібен, щоб зменшити споживання енергії.

Контроллер I2S

CODEC отримує аудіодані від контроллера I2S. Теоретично, якщо CODEC є частиною SoC, він може мати прямий доступ до пам’яті через DMA запити або в PIO режимі. На практиці ж навіть у цьому випадку цим займається контроллер, а CODEC отримує дані через внутрішню (щодо SoC) I2S шину.

Основна задача контроллера, у випадку програвання звуку: отримати байти від процесора/пам’яті і передати їх далі, CODEC-у. Для запису напрямок даних зворотній: отримати байти від CODEC-у та записати їх в пам’ять або передати процесору.

Дані, які мають бути надіслані, або тільки що отримані контроллер зберігає в одному з внутрішніх FIFO буферів: TXFIFO або RXFIFO. Перед тим як почати транспортування даних драйвер контроллера повинен налаштувати параметри
аудіопотоку: частоту дискретизації, кількість каналів, розмір семпла. Після цього драйвер заповнює (при передачі) внутрішній буфер контроллера за допомогую DMA операції, або послідовно записуючи семпли в регістр TXDATA, та віддає команду почати надсилати. Кожен надісланий семпл видаляється з буфера, і як тільки заповнення TXFIFO падає нижче визначегого рівня контроллер повідомляє про це операційну систему через переривання і драйвер надає нову порцію даних.

При запису аудіо все відбувається в зворотному випадку: контроллер додає отримані семпли в RXFIFO і як тільки їх стає більше певного рівня, контроллер повідомляє ОС що потрібно їх звідти забрати.

Шина I2S

CODEC та контроллер поєднані за допомогою I2S шини. Це послідовний інтерфейс розроблений компанією Philips в 1986 році спеціально для поєднання аудіоприладів. Найпростіший варінт шини має три сигнали: SCK (serial clock, bit clock, BCLK), WS (word select, left/right clock, LRCLK, frame-sync, FS), SD (serial data, SDIN, SDOUT, DACDAT, ADCDAT). SCK надає частоту тактування, SD передає семпли, а WS визначає для в який канал має піти семпл — правий чи лівий. Шина може мати більше одного сигнала SD, для одночасних операцій програвання та запису, або для операцій з масивами мікрофонів чи динаміків. Також замість одного сигналу LRCLK може бути два — окремо для програвання (TXLRCLK) та запису (RXLRCLK).

I2S timing diagram (source)
kd76sSH

Якщо один з компонентів має внутрішню цифрову логіку, наприклад DSP алгоритми в CODEC, ця логіка потребує джерело тактової частоти для функціонування. Ним може бути ще один, необов’язковий, сигнал шини — MCLK (master clock). Його частота, зазвичай, це частота дискретизації помножена на степінь двійки, найчастіше 256, але іноді 128 або 512.

Альтернативно, на вхід MCLK CODEC-у може подаватись сигнал не з контроллера, а з зовнішього фіксованого генератора або з одного з генераторів SoC.

Стандарт I2S не визначає яка з сторін має генерувати BCLK та WS. Тому перш ніж почати комунікацію контроллер та CODEC мають погодити, хто є генератором, а хто споживачем синхросигналів (про це трохи нижче).

Існує декілька форматів (або ж варіантів) I2S: стандартний, left-justified, right-justified, DSP, PCM. Вони функціонують за більш-менш однаковим принципом і відрізняються тільки деталями: де початок семпла, як FS сигналізує зміну канала. Сучасні компоненти з підтримкою I2S можуть використовувати принаймні найбільш популярні з цих форматів.

Device Tree та драйвера

Інформація про всю цю структуру (контроллер, CODEC, підсилювачі, шина) зберігається в .dtb файлі, який містить опис «дерева пристроїв» і передається операційній системі завантажувачем ОС або вбудовується в саме ядро під час компіляції.

Для прикладу розглянемо релевантні частини з опису Pinebook Pro, дещо змінені для більшої наглядності.

rk3399-pinebook-pro.dts

/ {
    /* Audio components */
    es8316-sound {
        compatible = "simple-audio-card";
        pinctrl-names = "default";
        pinctrl-0 = <&hp_det_gpio>;
        simple-audio-card,name = "rockchip,es8316-codec";
        simple-audio-card,format = "i2s";
        simple-audio-card,mclk-fs = <256>;

        simple-audio-card,aux-devs = <&speaker_amp>;
        simple-audio-card,bitclock-master = <&i2s1>;
        simple-audio-card,frame-master = <&i2s1>;

        simple-audio-card,cpu {
            sound-dai = <&i2s1>;
        };

        simple-audio-card,codec {
            sound-dai = <&es8316>;
        };
    };

    speaker_amp: speaker-amplifier {
        compatible = "simple-audio-amplifier";
        enable-gpios = <&gpio4 RK_PD3 GPIO_ACTIVE_HIGH>;
        sound-name-prefix = "Speaker Amplifier";
        VCC-supply = <&pa_5v>;
    };

    i2s1: i2s@ff890000 {
        compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
        reg = <0x0 0xff890000 0x0 0x1000>;
        interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH 0>;
        dmas = <&dmac_bus 2>, <&dmac_bus 3>;
        dma-names = "tx", "rx";
        clock-names = "i2s_clk", "i2s_hclk";
        clocks = <&cru SCLK_I2S1_8CH>, <&cru HCLK_I2S1_8CH>;
        pinctrl-names = "default";
        pinctrl-0 = <&i2s_8ch_mclk_gpio>, <&i2s1_2ch_bus>;
        power-domains = <&power RK3399_PD_SDIOAUDIO>;
        #sound-dai-cells = <0>;
        rockchip,capture-channels = <8>;
        rockchip,playback-channels = <8>;
        status = "okay";
    };

    i2c1 {
        es8316: es8316@11 {
            compatible = "everest,es8316";
            reg = <0x11>;
            clocks = <&cru SCLK_I2S_8CH_OUT>;
            clock-names = "mclk";
            #sound-dai-cells = <0>;
        };
    };
};

Вузол es8316 описує ES8316 CODEC. Це окрема мікросхема, вона під’єднана до I2C шини номер 1 (i2c1), має I2C адресу 0×11. MCLK подається напряму від RK3399 SoC, з генератора SCLK_I2S_8CH_OUT.

Вузол i2s1 — це один з трьох контроллерів I2C RK3399. Поля цього вузла описують вікно в фізичній пам’яті через яке процессор має доступ до внутрішніх регістрів контроллера, номер переривання, DMA канали для операцій з пам’яттю та генератори, які подаються на вхід IP блоку контроллера.

ES8316 не має внутрішніх підсилювачів, тільки послаблювачі, тож для дого щоб подати звук на динамік використовується зовнішній підсилювач описаний вузлом speaker_amp. Драйвер підсилювача може контролювати напругу подану на нього через регулятор живлення або ввімкнути чи вимкнути проходження звуку змінюючи значення GPIO сигналу.

Поєднує всі три компонента віртульна звукова карта es8316-sound. Поле simple-audio-card,cpu містить посилання на CPU-частину аудіотракту, яка обмінюється даними з пам’яттю та процесором. У даному випадку це i2s1. simple-audio-card,codec посилається на CODEC-частину (es8316). А поле simple-audio-card,aux-devs є списком всіх допоміжних компонентів, які не є частиною основної архітектури «контроллер/CODEC». В Pinebook Pro це лише один підсилювач.

Решта полів використовується для узгодження параметрів шини I2S між сторонами тракту: який варіант I2S обрати, яка константа використовується для обчислення частоти MCLK, яка зі сторін, CODEC чи контроллер, є генератором синхросигналів, а яка споживачем.

Для того щоб відтворити звук додаток відкриває канал зв’язку з драйвером віртуальної карти simple-audio-card. В UNIX-подібних системах, це зазвичай файл пристрою в директорії /dev/. Використовуючи API ядра додаток спочатку встановлює параметри аудіопотоку: частоту дискретизації, формат семплів, кількість каналів. Поєднуючи ці дані з інформацією з вузла device tree драйвер обчислює частоти BCLK, WS, MCLK, конфігурує CPU-частину та CODEC-частину аудіотракту і запускає операцію передачі данних.

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Распознавание звука с вокодера легче будет? Я сейчас в интернет кафе. Нет возможности скомандовать: Нука гугл найди мне smthng... С вокодером была бы. Легко одел бы себе на горло такую штуку. Что там преобразуется? Колебания голосовых связок? ТАК (погуглил) эта штука не вокодер. Когда рак горла у курильщиков. Голос робота.

Але нащо тобі то треба знати на будь-якому рівні?
Знати внутрішні протоколи тобі потрібно ЛИШЕ у випадку, якщо ти плануєш там щось міняти. Як ні — тобі треба знати API та не вигадувати собі геморою.

PS. Візьми собі нормальне USB аудіо і буде тобі щастя.

USB Audio не подходит для например тех кто пишет музыку с использованием VST синтезаторов и плагинов, из за задержек. Например с драйверами ASIO и USB аудио картой, насколько я помню, задержку нужно устанавливать не менее 10ms (а это достаточно много), иначе будет щелкать, хрипеть и т.д. Может с USB 3.0 ситуация поменялась, но когда то было так.

Сильно зависит от драйвера и самой звуковухи. Обычно в тракте самой [паршивой] звуковухи бывают задержки, а не на USB.

Если бы тормоза были в USB, в игры невозможно было бы играть на USB-устройствах, особенно в киберспорте. Даже для банальной работы мышью 10мс это таки дохера, там куда меньше задержки.

Там может зависеть от драйвера. Мы сейчас делаем для роутеров переходник со шнуркового телефона на USB, управление из юзерспейса. Вот обнаружилось, что когда идет много WiFi трафика, он отбирает проц у USB системы, и начинаются лаги и дропы. Кернельщики сказали, что надо писать свой драйвер (по типу USB сетевушек), чтобы обработка шла в более высоком приоритете. BTW у нас сейчас 100 мс буфера, и не всегда помогает.

А что мешает докинуть больше буфера? WiFi не самая слабая нагрузка, не забывай что он достаточно серьёзно шифрованный. И приоритетом там не отделаешься. Буферезировать нужно именно сеть, а не USB.

Но здесь речь о компьютерах, там возможности посурьёзнее, да и вафля не так мешается, благо аппаратное декодирование.

А что мешает докинуть больше буфера?

В железке 8КБ оперативы. Бизнес такой бизнес.

не забывай что он достаточно серьёзно шифрованный

Этим железо занимается. А вот бриджевать между вайфаем и эзернетом все равно процу приходится. И спидтест с мобильного может хорошо попортить жизнь телефонии.

Буферезировать нужно именно сеть, а не USB

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

Мы сейчас делаем для роутеров переходник со шнуркового телефона на USB, управление из юзерспейса.

А как подключенный переходник видится? Точнее, из каких эндпоинтов состоит. Потому что, если я ничего не путаю, юсб звуковушка — это изохронные эндпоинты (а у них резервируется полоса под передачу, но данные не гарантированно доставляются) + контрольный эндпоинт.

Кернельщики сказали, что надо писать свой драйвер (по типу USB сетевушек)

У юсб сетевушки (RNDIS) bulk эндпоинты + контрольный эндпоинт. В приоритете гарантированная доставка, но нет гарантии по времени доставки.
Вы с телефона, звук, данные или все вместе суете?

Мы сделали bulk эндпойнты, через которые идет и голос, и контрольные команды — так работал уже поддерживаемый USB DECT донгл. И разбираться с изохронными и с ALSA — большой кусок времени. Устройство vendor-specific и не пытается быть звуковушкой.

Вы с телефона, звук, данные или все вместе суете?

Все вместе, но данных там — запись и чтение регистров SLIC, по сути.

В USB 2.0 HID пристроях мінімальний можливий інтервал 1мс. Якщо треба швидше — пишіть свій драйвер.

Так 1 ≠ 10, це по-перше, а по-друге, є різниця між інтервалом опитування та затримкою.

Спасибо. Интересно. Существует ли способ конфигурировать работу самого кодека? Например если не/требуется предусилиение сигнала (или уже данных) или включение алгоритмов из встроенного DSP. Насколько большие задержки в таких системах и способны ли они работать в полнодуплексном режиме?

Существует ли способ конфигурировать работу самого кодека? Например если не/требуется предусилиение сигнала (или уже данных) или включение алгоритмов из встроенного DSP.

ALSA mixer позволяет. Но зависит от того, насколько этот функционал детально в драйвере кодека реализовали.

-

Встроенного DSP в примитивной микрушке, которая даже звук пересемплить по частоте не может без **учих шакалов? Можно я в этом месте поржу?

Еще в этом же кодеке есть эквалайзер и фильтр для подавления шума ветра.

Как человек, который ещё в начале 2000 зарабатывал этим, как контрактор, себе икру на хлеб с маслом, в чипе за $1.81 нет НИ-ХУ-ЧЕГО. Все в софте. Эквалайзер аппаратный был на Aureal Vortex 8830. Даже на Sound Blaster Live и прочих был полу-софтвартный. С тех пор их делают только в high end железе.

Похоже что есть, упустил из виду, что для мобильного применения. Был не прав. В дексктопных кодеках, даже в самом последнем: www.realtek.com/...​eripheral-ics/item/alc898

пишут:

Software Features

Meets Microsoft WLP 3.x and future WLP audio requirements
WaveRT-based audio function driver for Windows Vista and Windows 7
Direct Sound 3D™ compatible
I3DL2 compatible
7.1+2 channel multi-streaming enables concurrent gaming/VoIP
Emulation of 26 sound environments to enhance gaming experience
Multiband software equalizer and tools provided
Voice Cancellation and Key Shifting effect
Dynamic range control (expander, compressor, and limiter) with adjustable parameters
Intuitive Configuration Panel (Realtek Audio Manager) to enhance user experience
Microphone Acoustic Echo Cancellation (AEC), Noise Suppression (NS), and Beam Forming (BF) technology for voice applications
Smart multiple streaming operation
Optional Dolby PCEE program, SRS TruSurround HD, SRS Premium Sound, Fortemedia SAM, Creative Host Audio, Synopsys Sonic Focus, DTS Surround Sensation | UltraPC, and DTS Connect licenses

Підписатись на коментарі