Пролог
NAU8814YG это 24 битный аудио кодек от тайваньской компании Nuvoton Technology в 24-пиновом QFN корпусе с управлением по I2C (либо SPI). В случае управления по I2C чип отзывается на адрес 0x1A.

Компания Nuvoton Technology известна тем, что другой её аудиокодек NAU88C22 был заложен в культовый SDR-приёмник Малахит DSP3.
У меня уже были обзоры других аудио ASICов, которые так или иначе исполняют роль кодека:
ASIC | URL | Type |
MAX98357B | DAC | |
MP23DB01HPTR | ADC | |
MAX9860 | ADC+DAC | |
AD9833 | DAC | |
WM8731 | ADC+DAC |
Теория
Для понимания спек по аудиокодекам надо быть знакомым с этими понятиями:
аудио кодек — это цифро‑аналоговое устройство, где есть пара ADC + DAC. На входе обычно есть сумматор на операционных усилителях для подмешивания к основному сигналу вспомогательные аналоговые сигналы с разных проводов: AUX, MIC, есть еще аналоговый инвертор, усилитель (boost). Число провод на основе I2S (или TDM) и интерфейс I2C для того, чтобы всем этим добром повелевать.
Notch filter — это тип режекторного фильтра (band stop). Это такой фильтр который уменьшает амплитуды в пределах специфического диапазона частот и пропускает все остальные частоты. У notch фильтров этот диапазон частот очень узкий.

Attack time — это продолжительность времени, которое нужно аудиосигналу чтобы достигнуть максимальной амплитуды после срабатывания. Время между моментом, когда сигнал на входе устройства превышает порог активации устройства, и моментом, когда устройство реагирует определенным образом на вход.
Аппаратная часть
В первом приближении микросхему NAU8814YG можно рассмотреть вот так. Просто коробочка у которой есть входы и выходы.

Расспиновка чипа такая.

На минус втором уровне абстракции так

На минус третьем уровне абстракции то, что под капотом NAU8814 выглядит так

Это референс схемотехника

Так как чип управляется по I2C вспомним основные моменты по I2C

Аналогично про I2S.

Как отлаживать NAU8814?
Любая разработка начинается только тогда, когда появляются полноценные средства для отладки. В чипе NAU8814 заложено три механизма для отладки:
Вы можете читать регистры I2C. Так можно контролировать корректность записи.
У аудиокодека NAU8814 есть цифровой выходной пин 12 SPKCSb/GPIO (SPI Chip Select or General Purposes I/O). Им можно отлаживать внутренние подсистемы аудиокодека: PLL, Audio Jack.
Для отладки режимов работы есть специальный аналоговый пин MOUT (пин 16). На него вы можете вывести любой сигнал.
Источник данных | Конфиг |
MIC | BYPMOUT=1 |
DAC | DACMOUT=1 |
AUX | AUXMOUT=1 |
Программная часть
Первым делом просканируем шину I2C и посмотрим кто там живёт...

Тут ASICу NAU8814YG посвящаются два I2C адреса: 0x34 и 0x35.
hex | bin | Пояснение |
0x34 | 0011_0100 | адрес для записи |
0x35 | 0011_0101 | адрес для чтения |
Вот и получается, что настоящий адрес устройства это 0011_010 = 0001_1010 = 0x1A. Прямо как у WM8731.
Чтение I2C ячейки
Первым делом надо отладить чтение I2C регистра. Ибо как мы без чтения собираемся доказывать корректность записи? А чтение I2C регистра с подвохом. Надо адресу регистра приписывать справа один младший нулевой dummy бит.

Это же можно представить в виде таблицы

Вот так выглядит идеологически правильная осциллограмма чтения регистра 0x40 (Additional ID) NAU8814.

Запись I2C ячейки
Запись совсем простая. Отправить 3 байта по I2C с бинарным спец. форматом.

так это выглядит в натуре. Запись регистра с адресом 0x01 значением 0x155

Удалось вычитать значения внутренних 9-битных регистров ASIC NAU8814

продолжение

Как видно регистр SILICON_REVISION на самом деле нулевой. Это несоответствие с спецификацией. Там обещали значение 0xEE.
Настройка PLL
Как и всё в цифровой электронике, для того чтобы заработали ADC и DAC на их необходимо подать тактирование. В той плате, где у меня установлен NAU8814 тактирование приходит не от кварцевого генератора, а от микроконтроллера. Провод MCLK припаян к пину с PWM функцией от аппаратного таймера. Поэтому мне пришлось предварительно написать драйвер аппаратного таймера и генератора PWM. Вот так, в частности, можно сконфигурировать контур PLL, чтобы на АЦП и ЦАП поступило тактирование.

Коэффициенты можно вычислить методом перебора вот по этой функции
/*
see 12.8. CLOCK GENERATION BLOCK
Table 25: Registers associated with PLL
F1 = (MCLK / D)
f2 = (4 * P * IMCLK)
f_pll = f2/4
f2 = R * F1
R = f2 / f1 = xy.abcdefgh decimal value
N = xy
K = (2^24) * (0.abcdefgh)
IMCLK = (256) * (desired codec sample rate)
*/
bool nau8814_calc_pll(uint32_t mclk_hz, uint32_t fs_hz, uint32_t k_step ) {
bool res = false;
LOG_INFO(NAU8814, "CalcPll,MCLK:%u Hz,FS:%u Hz,Kstep:%u", mclk_hz, fs_hz,k_step);
Nau8814PllInfo_t PllInfo = {0};
float calc_fs_hz = 0.0;
float diff_fs_hz = 0.0;
float min_err_fs_hz = FLT_MAX;
PllInfo.mclk_hz =mclk_hz;
PllInfo.fs_hz = fs_hz;
uint32_t i = 0 ;
uint32_t D = 0; // PLLMCLK PLL Clock
uint32_t N = 0; // PLLN
uint32_t K = 0; // PLLK
uint32_t P = 0; // MCLKSEL
for(D = 1; D <= 2; D++) {
for(N = 5; N <= 13; N++) {
for(K = 0; K <= 0x00FFFFFF; K += k_step) {
for(P = 0; P < ARRAY_SIZE(MasterClockSelInfo); P++) {
PllInfo.f_1 = ((float)PllInfo.mclk_hz) / ((float)D);
PllInfo.fraction = ((float)K) / ((float)0x1000000);
PllInfo.R = ((float)N) + PllInfo.fraction;
PllInfo.f_2 = PllInfo.R * PllInfo.f_1;
PllInfo.f_pll = PllInfo.f_2 / 4.0;
PllInfo.i_mclk = PllInfo.f_pll / ((float)MasterClockSelInfo[P].divider);
calc_fs_hz = PllInfo.i_mclk / 256.0;
diff_fs_hz = fabsf(calc_fs_hz - ((float)fs_hz));
if(diff_fs_hz < min_err_fs_hz) {
i++;
min_err_fs_hz = diff_fs_hz;
PllInfo.N = N;
PllInfo.K = K;
PllInfo.D = D;
printf("\r%u,%s",i, Nau8814PllInfoToStr(&PllInfo));
res = true;
}
}
}
}
}
printf(CRLF);
return res;
}
Вот что мне посчитала функция для MCLK:5MHz,NeedFS:48kHz:
D:1,N:9,K:13932032,R:9.83,F1:5.00MHz,F2:49.15MHz,Fpll:12.29MHz,IMCLK:12.29MHz,RealFS:48000.1 Hz,ErrFS: 0.1 Hz,
Для контроля факта применения настроек PLL надо, как раз, воспользоваться отладочным пином CSd/GPIO. Я вывел «на улицу» частоту PLL/4 и электродом осциллографа увидел частоту 3.25 MHz. Это значит, что перед делителем частота PLL равна 13 MHz.
Это как раз совпадает с расчётными run-time значениями в прошивке.

Успех!
Воспроизведение звука
Для того чтобы переключить ASIC в режим воспроизведения звука надо прописать конфиги внутренний мультиплексоров вот как, чтобы данные пошли по красному тракту.

Я создал в коде прошивки массив int16_t семплов (96 элементов), рассчитал в элементы массива значения синуса

и воспроизвел на I2S этот массив. В результате осциллографом я увидел сигнал на пине MOUT.
На выходе аудиокодека SPK сигнал дифференциальный. То есть сдвинутый по фазе на 180 градусов.
Отлично! Значит, что всё понято правильно.
Значения I2C регистров при которых есть звук на SPK и MOUT
18:58-->nau8814_map
+-----+------+------+--------+---------------------+---------------------+
| No |addrD |addrH | val | val [bin] | name |
+-----+------+------+--------+---------------------+---------------------+
| 0 | 0 | 0x00 | 0x0000 | 0000_0000_0000_0000 | SOFTWARE_RESET |
| 1 | 1 | 0x01 | 0x013d | 0000_0001_0011_1101 | POWER_MANAGEMENT_1 |
| 2 | 2 | 0x02 | 0x0015 | 0000_0000_0001_0101 | POWER_MANAGEMENT_2 |
| 3 | 3 | 0x03 | 0x00ed | 0000_0000_1110_1101 | POWER_MANAGEMENT_3 |
| 4 | 4 | 0x04 | 0x0010 | 0000_0000_0001_0000 | AUDIO_INTERFACE |
| 5 | 5 | 0x05 | 0x0000 | 0000_0000_0000_0000 | COMPANDING |
| 6 | 6 | 0x06 | 0x0100 | 0000_0001_0000_0000 | CLOCK_CONTROL_1 |
| 7 | 7 | 0x07 | 0x0000 | 0000_0000_0000_0000 | CLOCK_CONTROL_2 |
| 8 | 8 | 0x08 | 0x0034 | 0000_0000_0011_0100 | GPIO_CTRL |
| 9 | 10 | 0x0a | 0x0000 | 0000_0000_0000_0000 | DAC_CTRL |
| 10 | 11 | 0x0b | 0x00ff | 0000_0000_1111_1111 | DAC_VOLUME |
| 11 | 14 | 0x0e | 0x0180 | 0000_0001_1000_0000 | ADC_CTRL |
| 12 | 15 | 0x0f | 0x00ff | 0000_0000_1111_1111 | ADC_VOLUME |
| 13 | 18 | 0x12 | 0x012c | 0000_0001_0010_1100 | EQ1_LOW_CUTOFF |
| 14 | 19 | 0x13 | 0x002c | 0000_0000_0010_1100 | EQ2_PEAK_1 |
| 15 | 20 | 0x14 | 0x002c | 0000_0000_0010_1100 | EQ3_PEAK_2 |
| 16 | 21 | 0x15 | 0x002c | 0000_0000_0010_1100 | EQ4_PEAK3 |
| 17 | 22 | 0x16 | 0x002c | 0000_0000_0010_1100 | EQ5_HIGH_CUTOFF |
| 18 | 24 | 0x18 | 0x0000 | 0000_0000_0000_0000 | DAC_LIMITER_1 |
| 19 | 25 | 0x19 | 0x0070 | 0000_0000_0111_0000 | DAC_LIMITER_2 |
| 20 | 27 | 0x1b | 0x0000 | 0000_0000_0000_0000 | NOTCH_FILTER_0_HIGH |
| 21 | 28 | 0x1c | 0x0000 | 0000_0000_0000_0000 | NOTCH_FILTER_0_LOW |
| 22 | 29 | 0x1d | 0x0000 | 0000_0000_0000_0000 | NOTCH_FILTER_1_HIGH |
| 23 | 30 | 0x1e | 0x0000 | 0000_0000_0000_0000 | NOTCH_FILTER_1_LOW |
| 24 | 32 | 0x20 | 0x0018 | 0000_0000_0001_1000 | ALC_CTRL_1 |
| 25 | 33 | 0x21 | 0x000b | 0000_0000_0000_1011 | ALC_CTRL_2 |
| 26 | 34 | 0x22 | 0x0032 | 0000_0000_0011_0010 | ALC_CTRL_3 |
| 27 | 35 | 0x23 | 0x0008 | 0000_0000_0000_1000 | NOISE_GATE |
| 28 | 36 | 0x24 | 0x0008 | 0000_0000_0000_1000 | PLL_N_CTRL |
| 29 | 37 | 0x25 | 0x000c | 0000_0000_0000_1100 | PLL_K_1 |
| 30 | 38 | 0x26 | 0x0093 | 0000_0000_1001_0011 | PLL_K_2 |
| 31 | 39 | 0x27 | 0x00e9 | 0000_0000_1110_1001 | PLL_K_3 |
| 32 | 40 | 0x28 | 0x0000 | 0000_0000_0000_0000 | ATTENUATION_CTRL |
| 33 | 44 | 0x2c | 0x000b | 0000_0000_0000_1011 | INPUT_CTRL |
| 34 | 45 | 0x2d | 0x0010 | 0000_0000_0001_0000 | PGA_GAIN |
| 35 | 47 | 0x2f | 0x0150 | 0000_0001_0101_0000 | ADC_BOOST |
| 36 | 49 | 0x31 | 0x000a | 0000_0000_0000_1010 | OUTPUT_CTRL |
| 37 | 50 | 0x32 | 0x0001 | 0000_0000_0000_0001 | SPEAKER_MIXER_CTRL |
| 38 | 54 | 0x36 | 0x003f | 0000_0000_0011_1111 | SPKOUT_VOLUME |
| 39 | 56 | 0x38 | 0x0001 | 0000_0000_0000_0001 | MIXER_CONTROL |
| 40 | 58 | 0x3a | 0x0000 | 0000_0000_0000_0000 | POWER_MANAGEMENT_4 |
| 41 | 59 | 0x3b | 0x0000 | 0000_0000_0000_0000 | TIME_SLOT |
| 42 | 60 | 0x3c | 0x0004 | 0000_0000_0000_0100 | ADCOUT_DRIVE |
| 43 | 62 | 0x3e | 0x00ee | 0000_0000_1110_1110 | SILICON_REVISION |
| 44 | 63 | 0x3f | 0x001a | 0000_0000_0001_1010 | 2_WIRE_ID |
| 45 | 64 | 0x40 | 0x00ca | 0000_0000_1100_1010 | ADDITIONAL_ID |
| 46 | 65 | 0x41 | 0x0124 | 0000_0001_0010_0100 | RESERVED |
| 47 | 69 | 0x45 | 0x0001 | 0000_0000_0000_0001 | HIGH_VOLTAGE_CTRL |
| 48 | 70 | 0x46 | 0x0010 | 0000_0000_0001_0000 | ALC_ENHANCEMENTS_1 |
| 49 | 71 | 0x47 | 0x0000 | 0000_0000_0000_0000 | ALC_ENHANCEMENTS_2 |
| 50 | 73 | 0x49 | 0x0007 | 0000_0000_0000_0111 | ADDITIONAL_IF_CTRL |
| 51 | 75 | 0x4b | 0x0000 | 0000_0000_0000_0000 | POWER_TIE_OFF_CTRL |
| 52 | 76 | 0x4c | 0x0006 | 0000_0000_0000_0110 | AGC_P2P_DETECTOR |
| 53 | 77 | 0x4d | 0x0000 | 0000_0000_0000_0000 | AGC_PEAK_DETECTOR |
| 54 | 78 | 0x4e | 0x0011 | 0000_0000_0001_0001 | CONTROL_AND_STATUS |
| 55 | 79 | 0x4f | 0x0018 | 0000_0000_0001_1000 | OUTPUT_TIE_OFF_CTRL |
+-----+------+------+--------+---------------------+---------------------+
Запись звука
Для активации микрофона надо прописать в I2C регистры вот эти значения битов. Тогда активируется тракт от микрофона к I2S.

Далее всё аналогично тексту про WM8731 (ссылка) и микрофон MP23DB01HPTR (ссылка). Воспроизводим с телефона тон. Записываем по I2S звук кодеком в RAM память. Вычисляем DFT, находим частоту с максимальной амплитудой и сравниваем её с настройками воспроизведения на смартфоне.
Итак, следите за руками... Я беру двухканальный функциональный генератор RIGOL DG1022, настраиваю его первый канал на испускание 2k Hz с амплитудой 100mV и прикладываю щуп на 24й пин MIP_P NAU8814. Затем я записываю аудиодорожку продолжительностью 300 семплов на 48kHz в RAM память микроконтроллера. Это получается трек длительностью 6.25ms.

Этот трек можно увидеть если построить график. Для этого я написал скрипт на Python
import matplotlib.pyplot as plt
import csv
import sys
F_adc_hz = 48000.0
t_sample = 1.0/F_adc_hz
X = []
Y = []
corr = []
file_name=sys.argv[1]
with open(file_name, 'r') as datafile:
plotting = csv.reader(datafile, delimiter='|')
for ROWS in plotting:
X.append(float(ROWS[1])*t_sample)
Y.append(float(ROWS[4]))
print ('X {} Nums'.format(len(X)))
print ('Y {} Nums'.format(len(Y)))
print ('Type X {} '.format(type(X)))
print ('Type Y {} '.format(type(Y)))
plt.plot(X, Y,label="ADC")
plt.legend(loc='best')
file_name = file_name.replace('.', '_')
file_name = file_name.replace('__', '_')
plt.title('{}'.format(file_name))
plt.xticks(rotation=-90)
plt.xlabel('Time,[s]')
plt.ylabel('ADC, [sample]')
plt.savefig('{}.png'.format(file_name))
plt.show()
вот такой получился график сигнала во временной области. Это синус Freq:2kHz, Amp:100mV.

Получив трек, я подаю его на алгоритм вычисления DFT. Тут сразу вырисовывается максимум амплитудой порядка 5k на 2080 Hz.

или лучше показать спектр графиком

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

Это всего на 4% отличается от настроек в функциональном генераторе. Там было на 2000 Hz. Запись тоже работает корректно. Чудно!
Примечание
Стоит также отметить, что в Artery MCU каждый отдельный I2S может быть либо передатчиком, либо приёмником. Ника не одновременно.

Если же мы хотим сделать полнодуплексную трансляцию, то надо настроить синхронную работу двух отдельных I2S трансиверов (I2S2 и I2S2EXT).
Достоинства NAU8814YG
NAU8814YG это санкционно-стойкий аудио кодек.
Есть регистр с ID. Благодаря этому можно сделать модульный тест на для процедуры чтения.
I2C ячейки можно читать. Это выгодно отличает NAU8814 от WM8731!
Есть отладочные пины GPIO/ MOUT.
Недостатки NAU8814YG
Для аудио кодека NAU8814YG отсутствуют отладочные платы. Для освоения этого ASICа вам придется самому проектировать схемотехнику, самому трассировать топологию электронной платы, самому заниматься производством PCB. Никаких DevBoard(ов) для NAU8814, к сожалению, нет. Хотя ASIC, сам по себе, очень интересный.
Как известно у чипа 7-битный адрес. Это значит, что можно адресовать 128 регистров. Одновременно с этим, в DataSheet(те) на NAU8814 определено только 55 регистров. Возникает резонные вопрос: aдресуют ли что-нибудь оставшиеся 73 адреса?
Оказывается, что да. Есть регистр с адресом 0x48=72, который содержит загадочное значение 0x0006=0b0_0000_0110.

Всё это провоцирует мысли, что внутри NAU8814 живёт ещё какой-то скрытый функционал, про который разработчики из Nuvoton Technology пожелали не писать в datasheet(e). Выглядит как vendor locking. Вот такая вот пасхалка заложена...
Идеи проектов на аудиокодеке NAU8814YG
Простые аудио проекты:
Диктофон.
Плейер Wav файлов.
Электронный камертон, метроном для пианистов или прибор для настойки гитары.
Стенд для тестирования наушников.
Караоке. Чип может усиливать аналоговый сигнал от микрофона.
В режиме MIC bysass кодек превращается в слуховой аппарат. Слух будет как у филина!
Осциллограф на основе входного пина AUX.
Генератор сигналов на основе LineOut выходов
Датчик шума.
Спектро-анализатор.
Имитация рычания мотора внутри глушителя автомобиля.
Дефектоскоп.
Из аудиокодека можно сделать синтезатор для обучения игры на рояле.
Сложные аудио проекты:
Звуковая локализация. Несколько кодеков можно использовать как N независимых микрофонов. Это значит, что можно вычислять корреляцию 2х сигналов и выявлять угол направления прихода звуковой волны. Называется эта тема Angle Of Arrival AOA. Это может пригодиться, например, для ориентации поворотных видеокамер или для выявления источника стрельбы.
Звуковые эффекты: Эхо, дисторшн. Так как можно считывать и воспроизводить звук в цифровом виде, то тут можно по-разному экспериментировать с синтезом разнообразных цифровых фильтров или изучать их используя реальных звук в real-time.
Звуковой дальномер. Сонар для определения расстояния до препятствия.
Передача и прём бинарных данных по звуку! Например DTMFом можно передавать по 4 бита за раз. Беспроводной аудио интерфейс! Можно написать DeskTop утилиту, которая будет воспроизводить файлы и через провод AudioJack переливать файлы по DTMF в AudioFlash(ку). И никакой детектор USB трафика этого никогда не заметит! Или можно сделать обновление прошивки по звуку.
Можно сравнить технические характеристики NAU8814 c другими аудиокодеками.

Итоги
Удалось научиться воспроизводить цифровой звук из I2S и удалось записывать звук с NAU8814YG. Аудиокодек NAU8814YG подчинен воле российского человека!
Запуск аудиокодека провоцирует подтягивание огромного количества программных зависимостей. Для работы NAU8814 нужен драйвер I2C, I2S, PWM. Для I2S нужен драйвер GPIO, SPI, DMA, TIME. Для PWM нужен TIMER. И так далее и так далее.

В этом аудиокодеке так много мультиплексоров, что его можно сравнить с железнодорожными вокзалом со своими ж\д стрелками. Управлять аудиокодеком — это то же, что работать диспетчером на крупном ж\д терминале.
Если вы знаете другие хорошие аудиокодеки, то пишете в комментариях.
Словарь
Для понимания документации и спецификаций на этот аудиокодек вам надо уметь правильно интерпретировать вот эти акронимы
Акроним | Расшифровка |
PLL | Phase-locked loop |
ALC | Automatic Level Control |
PCM | Pulse-code modulation |
I2S | Inter-IC Sound Bus |
I2C | Inter-Integrated Circuit |
PGA | programmable-gain amplifiers |
DC | Direct current |
ADC | Analog-to-digital converter |
DAC | digital to analog converter |
QFN | Quad Flat No-leads package |
Контрольные вопросы:
Что такое Notch filter?
Что такое equalizer?
Что такое De-emphasis?
Что такое Attack time?
URLs
Обзор Усилителя Звука из Apple AirTag https://habr.com/ru/articles/767386/
Обзор Aппаратного Aудио кодека MAX9860 (2x ADC+DAC) https://habr.com/ru/articles/758140/
Чип AudioСodec(а) WM8731 (или (ADC/DAC)*2 из iPod(а)) https://habr.com/ru/articles/703588/
NAU8814YG https://www.nuvoton.com/products/smart-home-audio/audio-converters/audio-codec-series/nau8814yg/
Зачем программисту микроконтроллеров комплексные числа (или обзор MEMS микрофона MP23DB01HPTR) https://habr.com/ru/articles/765896/
NAU881x-stm32-C https://github.com/muhammadrefa/NAU881x-stm32-C
Аналитика по NAU8814 https://docs.google.com/spreadsheets/d/1XXffSqG6324FbjQRW5MAGq5seiLfEc9OIFj81_xSCBA/edit#gid=0
микрофон - датчик объёма https://habr.com/ru/articles/792096/
Сайт компании разработчика кодека https://www.nuvoton.com/
NV-NAU8814 https://www.techdesign.com/market/nuvoton/product-detail/ntc000033/nv-nau8814