MAX9860 это 24 pin(овый) чип американской компании Maxim Integrated у которого внутри один 16ти битный Sigma Delta ЦАП, и два AЦП с управлением по I2C. Данные загружаются и выгребаются по I2S. Конфигурация по I2C.
У меня уже было текст обзор аудиокодека WM8731: Чип AudioСodec(а) WM8731 (или (ADC/DAC)*2 из iPod(а))
В этом же тексте будет разбор кодека MAX9860.
Внимание!
C аудиокодеками надо работать с особой осторожностью так как при неправильной конфигурации I2C регистров внутри прошивки, микросхема DAC может сильным звуком контузить программиста. Никогда не надевайте наушники, если вы не уверенны в том, что сейчас будет нормальный звук.
Аппаратная часть
Что надо из оборудования:
№ |
Оборудование |
Назначение |
1 |
Программируемый бок питания. Например модель GOPHERT NPS-1601 |
для генерирования 1.8V |
2 |
Генератор частоты 12.288 MHz |
Для тактирования MAX9860 |
3 |
логический анализатор |
для разбора I2S интерфейса |
4 |
перемычки вилка-гнездо |
для сборки прототипа |
13 |
перемычки вилка-вилка |
для сборки прототипа |
5 |
DMM |
для измерения напряжения и прозванивания цепей |
6 |
Калькулятор |
для вычисления коэффициента PLL |
7 |
конденсаторы 1uF 8x, 2.2uF 2x, 0.1uF 1x, 10uF 1x |
для сборки прототипа |
8 |
кабель USB-USB micro |
для программирования отладочной платы |
9 |
плата расширитель для FootPrint(a) под корпус 24TQFN-EP |
чтобы получить доступ к пинам микросхемы MAX9860 на вилке с шагом 2,54мм |
10 |
USB-flash память |
Для записи осциллограмм |
11 |
Микроскоп |
для чтения маркировки микросхемы и проверки ориентации пайки |
12 |
макетная плата типа breadboard |
для воспроизводства схемотехники из reference дизайна |
14 |
какая-н отладочная плата с микроконтроллером |
для чтения и записи в интерфейсы I2C и I2S |
15 |
Провода-переходники с разъёма "банан" на "крокодил" (2 шт) |
для соединения прототипа и лабораторного блока питания. |
16 |
Смартфон с операционной системой Andriod |
Для проигрывания мобильного приложения Audizr. |
17 |
Электромагнитный звукоизлучатель с сопротивлением 4 Ом. |
Для воспроизводства звука. |
В первом приближении блок схема кодека это рис. 1. По сути любой аудиокодек это чип у которого на одном чипе АЦП и ЦАП, регистры конфигурирования и ручка, чтобы всем этим управлять. В данном случае этой ручкой является интерфейс I2C. В качестве числопровода для DAC выступает шина I2S.
При более внимательном рассмотрении чип выглядит так. Тут видно усиление сигнала на микрофонах, управление громкостью звука. Возможность включать аналоговый LoopBack. Возможность пропускать сигнал через цифровые фильтры (Эллиптический и Баттерворта) на разных частотах дискретизации 8kHz, 16kHz, 48kHz.
С точки зрения программиста микроконтроллеров MAX9860 выглядит так (рис.3). Чип на шине I2C с базовым адресом равным 0x10
Расспиновка MAX9860ETG
Из микросхемы торчат 24 провода. Вот их назначение и смысл:
Ссылка на гуглдок MAX9860ETG+ pins
Как это обычно бывает в электронике, отладочной платы для MAX9860 нет в природе, а сам чип распространяется только в одном микроскопическом и диковинном корпусе 24TQFN-EP (с шагом 0.5мм), который увидеть можно только под микроскопом.
Поэтому для отладки драйвера чипа MAX9860 надо проектировать плату переходник для банального подключения проводов к микросхеме.
Или можно купить переходник на Aliexpress. Ключевое слово QFN24 Transfer Board 0.5MM. Ждать 5 недель.
Забавно, что у микросхемы MAX9860 отсутствует pin reset. Если зависнет, то поможет только перезагрузка питания. Еще чип надо тактировать частотой от 10MHz....20MHz. Для этого мне пришлось купить модуль DSPO 12.288 с кварцевым генератором 12,288MHz.
Программная часть
Что надо из софтвера?
№ |
Программа |
Назначение |
1 |
Мобильное приложение Audizr |
для проверки что частота тона в самом деле соответствует настройкам воспроизведения. Audizr это программа, которая вычисляет спектр от сигнала от микрофона |
2 |
Logic 2.4.6 |
PC клиент для логического анализатора |
3 |
TeraTerm |
Терминал последовательного порта для управления драйверами отладочных плат |
4 |
программа Inkscape |
для нанесения надписей на скриншоты осциллограмм |
Для работы с MAX9860 вам нужен микроконтроллер с работающими драйверами GPIO, I2C, I2S.
У чипа MAX9860ETG 17ть 8ми битных регистров. Это 136 бит чистых конфигов, где каждый бит чего‑то да значит. При этом в карте регистров есть даже регистр с ID чипа со значением ревизии. Данные передаются по I2C старшим битом вперед.
Что надо конфигурить внутри MAX9860ETG?
У чипа MAX9860 целая куча всяческих настроек. Вот перечень того, что можно настраивать в аудиокодеке:
Параметр |
Акроним |
Пояснение |
Регистр настройки |
Единица измерений |
ADC Voice Filter |
AVFLT |
Частота и тип цифрового фильтра для ADC |
0x08 |
Hz |
Bit Clock |
BCLK |
Битовая частота в режиме мастера |
0x07 |
Hz |
DAC Voice Filter |
DVFLT |
Частота и тип цифрового фильтра для DAC |
0x08 |
Hz |
level of left ADC output mixed into the DAC |
DVST |
Уровень смешивания сигнала с АЦП с входом ЦАП |
0x0B |
dB |
Microphone Preamp Gain |
PAM |
Предварительное грубое аналоговое усиление микрофона |
0x0C |
dB |
ADC Output Level Left |
ADCLL |
Цифровое Усиление левого микрофона |
0x0A |
? |
ADC Output Level Right |
ADCRL |
Цифровое Усиление правого микрофона |
0x0A |
? |
DAC digital audio level |
DVA |
Ослабление громкоговорителя |
0x09 |
? |
dac gain |
DVG |
Усиление ЦАП спикера |
0x0B |
? |
I2S Bus Role |
MAS |
Роль кодека на шине I2S |
0x06 |
Master/Slave |
Left Microphone PGA |
PGAM |
Предварительное точное аналоговое усиление микрофонов |
0x0C |
dB |
master clock |
MCLK |
Частота тактирования чипа |
0x03 |
Hz |
Master Mode |
MAS |
Роль на шине I2S |
0x06 |
-- |
Left/Right Clock |
LRCLK |
Частота дискретизации |
0x02 0x04 |
Hz |
Чип можно конфигурировать по I2C. Базовый адрес равен значению 16=0x10.
address |
address |
address |
|
Addr Type |
dec |
hex |
bin |
base address |
16 |
0x10 |
0b0001_0000 |
write |
32 |
0x20 |
0b0010_0000 |
read |
33 |
0x21 |
0b0010_0001 |
Внутри 17 регистров для конфигураций:
В микросхеме 92 бита чистых конфигов. Это значит, что микросхему MAX9860 можно сконфигурировать 4951760157141521099596496896 способами:
Это как количество молекул в двух человеках. Поэтому корректный конфиг имеет ключевое значение.
Запись I2C регистра выглядит так:
Чтение I2C регистра выглядит так. Тут важно чтобы микроконтроллер генерировал только 1 Stop сигнал в самом конце, даже несмотря та то что в пакете 2 Start сигнала. Команда чтения должна быть монолитная. Иначе из регистра прочитаются нули.
Микросхема отвечает на I2C команды даже если отсутствует тактирование на проводе MCLK. Что ж, до регистров достучались. Научились их читать и писать. Вот кстати работающий конфиг для перевода чипа в I2S режим (LR=48kHz, I2S slave, MCLK=12.228 MHz).
К слову, в микросхеме MAX9860 я обнаружил один не задокументированный регистр. Это регистр с адресом 0xf9. Если прочитать по адресу 0xf9, то прочитается значение 0x80. Как интерпретировать битовое поле по адресу 0xF9 известно только разработчикам чипа. В спеке по поиску f9 ничего не находится.
Как регулировать громкость звука в аудиокодеке MAX9860?
В чипе MAX9860 громкость можно конфигурировать двумя способами:
# |
Register |
Reg Name |
Reg Addr |
Min |
Max |
Step |
Unit |
1 |
DVA |
DAC Attenuation |
0x09 |
-90 |
+3 |
1 |
dB |
2 |
DVG |
DAC Gain |
0x0B |
0 |
+24 |
6 |
dB |
Можно и вовсе изменять амплитуду самих PCM отсчетов. Это тоже влияет на громкость.
Код драйвера MAX9860
В официальном ядре Linux драйвера для чипа MAX9860 нет. Можете сами убедиться в этом на сайте, который индексирует официальные сорцы Linux.
Однако есть что-то на github, но это только для Linux. Для микроконтроллеров эти драйверы не применимы так как в них есть динамическое выделение памяти. По факту для аудиокодека MAX9860 отсутствует драйвер для запуска на микроконтроллерах. Даже в проекте Zephyr Project отсутствует драйвер для MAX9860. Вот это художество
https://github.com/jakelaw/MAX9860_initialization
разумеется, нельзя назвать драйвером. То как должен быть оформлен полноценный драйвер есть отдельный текст https://habr.com/ru/articles/683762/
Вот так может выглядеть API для драйвера MAX9860:
#ifndef MAX9860_DRV_H
#define MAX9860_DRV_H
#include <stdbool.h>
#include <stdint.h>
#include "i2s_types.h"
#include "max9860_const.h"
#include "max9860_dep.h"
#include "max9860_mic_drv.h"
#include "max9860_speaker_drv.h"
#include "max9860_types.h"
extern const Max9860RegName_t RegNameLUT[];
uint32_t max9860_static_reg_cnt(void);
bool max9860_check(void);
bool max9860_save_mode_set(void);
bool max9860_is_connected(void);
bool max9860_init(void);
bool max9860_reg_set(uint8_t reg_addr, uint8_t reg_val);
bool max9860_reg_set_verify(uint8_t reg_addr, uint8_t reg_val);
bool max9860_reg_get(uint8_t reg_addr, uint8_t* const reg_val);
bool max9860_reg_read_all(void);
bool max9860_proc(void);
bool max9860_bus_role_set(I2sRole_t volume);
bool max9860_write_lazy_reg(uint8_t reg_addr, uint8_t reg_val);
bool max9860_write_reg_by_bitmask(uint8_t reg_addr, char* bit_mask);
bool max9860_reset(void);
bool is_valid_voice_filter(DigitalFilter_t digital_filter);
bool max9860_voice_filter_set(Converter_t converter, DigitalFilter_t digital_filter);
I2sRole_t max9860_bus_role_get(void);
uint32_t max9860_reg_cnt(void);
DigitalFilter_t max9860_voice_filter_get(Converter_t converter);
#endif /* MAX9860_DRV_H */
Часть про DAC:
#ifndef MAX9860_SPEAKER_DRV_H
#define MAX9860_SPEAKER_DRV_H
#include <stdbool.h>
#include <stdint.h>
#include "i2s_types.h"
#include "max9860_types.h"
bool max9860_voice_filter_set(Converter_t converter, DigitalFilter_t digital_filter);
bool is_valid_voice_filter(DigitalFilter_t digital_filter);
bool max9860_dac_set(bool on_off);
bool max9860_dac_get(void);
bool max9860_digital_audio_level_set(Gain_t gain);
bool max9860_dac_gain_set(Gain_t gain);
bool max9860_volume_set(uint8_t volume);
DigitalFilter_t max9860_voice_filter_get(Converter_t converter);
Gain_t max9860_digital_audio_level_get(void);
Gain_t max9860_dac_gain_get(void);
Gain_t Code2DvaGain(uint8_t code);
uint8_t DvaGain2Code(Gain_t gain);
uint8_t Gain2DvstCode(Gain_t side_tone_gain);
uint8_t max9860_volume_get(void);
#endif /* MAX9860_SPEAKER_DRV_H */
часть про ADC:
#ifndef MAX9860_MIC_DRV_H
#define MAX9860_MIC_DRV_H
#include <stdbool.h>
#include <stdint.h>
#include "i2s_types.h"
#include "max9860_types.h"
bool max9860_sidetone_level_set(SideToneGain_t side_tone_gain);
bool max9860_adc_set(MicChannel_t mic_channel, bool on_off);
bool max9860_adc_get(MicChannel_t mic_channel);
bool max9860_sidetone_set(bool on_off);
bool max9860_digital_audio_level_set(Gain_t gain);
bool max9860_adc_output_level_set(MicChannel_t mic_channel, AdcGain_t adc_gain);
bool is_valid_adc_gain(AdcGain_t adc_gain);
bool max9860_microphone_preamp_set(Gain_t gain);
bool max9860_microphone_programmable_gain_amplifier_set(Gain_t gain);
Gain_t max9860_microphone_programmable_gain_amplifier_get(void);
Gain_t PamCode2Gain(uint8_t pam_code);
AdcGain_t max9860_adc_output_level_get(MicChannel_t mic_channel);
SideToneGain_t max9860_sidetone_level_get(void);
uint8_t Gain2PgamCode(Gain_t gain);
uint8_t Gain2PamCode(Gain_t gain);
uint8_t Gain2DvstCode(Gain_t side_tone_gain);
Gain_t max9860_microphone_preamp_get(void);
SideToneGain_t Code2SideToneGain(uint8_t code);
AdcGain_t AdcCode2Gain(uint8_t code);
Gain_t PgamCode2Gain(uint8_t pgam_code);
uint8_t AdcGain2Code(AdcGain_t adc_gain);
#endif /* MAX9860_MIC_DRV_H */
Отладка шины I2S
Сами PCM данные со звуком в чип можно вгонять по двум интерфейсам: TDM или I2S. Вот настройка битов для I2S режима (WIC=0, BCI=0, DLY=1, TDM=0).
Про отладку I2S есть отдельный текст: Отладка интерфейса I2S
Как отладить I2S сейчас? Можно воспроизвести статический синус. Именно статический чтобы исключить ошибки в динамическом выделении памяти. Если выбрать частоту, например, 1kHz, то получится, что надо рассчитать всего 48 PCM отсчетов, чтобы синтезировать гармонический сигнал. В прошивке достаточно зарезервировать 48*2*2=192 байт.
Прямо в прошивке расчитать 1 период для синуса 1kHz, амплитудой 3333 PCM, частоты дискретизации 48kHz и проигрывать его в цикле по DMA.
На шине I2S должен появится такой цифровой сигнал. На проводе BCLK 1.724 MHz, LRCLK 53.591 kHz, OUTN 1.118 kHz
Полная осциллограмма такая. На проводе OUTP и OUTN 1.118 kHz
На осциллографе видно, что MAX9860 выдает 2 сигнала, которые смещены по фазе на пол периода. Или, попросту, сигнал и инвертированный сигнал. Видимо это сделано специально для прокладывания diff пары по плате от аудиокодека к усилителю.
Стоит отметить один контринтуитивный момент. Если во время проигрывания звука отключить тактирование MCLK, то сигнал на выходе исчезнет, даже если MAX9860 работал в режиме I2S slave. Получается, что тактирование обязательно для подсистемы DAC.
Еще надо учитывать, то что в mono режиме MAX9860 просто игнорирует PCM данные на правом канале.
Однако можно включить стерео режим и на выходе появится сигнал.
Если воспроизвести синус на звуко излучатель и поднести смартфон с приложением Audizr, то появится вот такой спектр. Можно заметить что там 1032 Hz.
Достоинства MAX9860
++ MAX9860 это очень простой аудио кодек. Всего 16 регистров. Чтобы вы понимали, в современных аудиокодеках например CS47L63 заложено 936 регистров по 32 бит каждый. Это 29952 бит одних только конфигов. CS47L63 на 3 порядка сложнее чем MAX9860 .
++ I2C регистры можно читать. Это выгодно отличает MAX9860 от пресловутого WM8731 (в котором нельзя читать I2C регистры).
++ Минимальная схемотехническая обвязка микросхемы. Всего 14 керамических конденсатора и кварцевый генератор.
++ В карте регистров есть регистра с ID чипа (0xFF) и значения ревизии (значение 0x40). Поэтому получится сделать link тест.
Недостатки MAX9860
1--Только один DAC. Это mono.
2--Сравнительно низкая производительность: максимальная частота дискретизации 48kHz, разрядность 16бит.
3--Отсутствие доступных отладочных модулей на основе MAX9860. Трудно собрать прототип. Надо конденсаторы, генератор частоты, плата переходник, перемычки, программируемый генератор напряжения. Вот так, кстати, выглядит минималистичный прототип для отладки драйвера MAX9860.
4--Микросхему надо питать очень экзотическим напряжением: 1.8V. Это затрудняет отладку так как ни одна отладочная плата не выдает на улицу 1,8V. Для отладки вам понадобится управляемый лабораторный источник опорного напряжения с возможностью установки произвольного напряжения (в частности 1,8V). Например модель GWINSTEK GPS-3030DD
5--Очень экзотический формат пакета для чтение I2C регистра. Как видите тут 2 старт сигнала и один только стоп. Это как если бы в математической формуле был бы нарушен баланс между открытыми и закрытыми скобками.
Получается, что для чтения регистров MAX9860 по I2C в проектах на STM32 нужно использовать особенную функцию HAL_I2C_Mem_Read_IT
HAL_StatusTypeDef
HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c,
uint16_t DevAddress,
uint16_t MemAddress,
uint16_t MemAddSize,
uint8_t *pData,
uint16_t Size);
или реализовывать программный I2C драйвер чисто на GPIO и аппаратных таймерах.
6--Где-то на 14ой минуте работы I2S трафика, I2С link внезапно пропадает. Регистр ревизии 0xFF перестает читаться как 0x40.
Поэтому изменять громкость во время проигрывания звука на лету едва ли получится.
7--Отсутствует пин reset. Если отвалится I2C link, то зовём человека.
8--Обнаружен не задокументированный регистр с адресом 0xf9! Вероятно это аппаратная закладка. Утечка управления.
9--В режиме mono MAX9860 игнорирует PCM данные на правом канале.
10--Нет функции анализа потока PCM семплов (максимальный минимальный). Было бы полезно определять максимальную амплитуда PCM и на основе неё подбирать адаптивную громкость.
MAX9860 vs WM8731
Как известно, всё познается в сравнении. Вот сравнение микросхемы MAX9860 с другим распространенным аудио чипом WM8731.
На фоне WM8731, MAX9860 выглядит более пригодным для ответственных систем. В MAX9860 есть возможность читать регистры, выше мощность сигнала, шире температурный диапазон, ниже частота тактирования, ниже напряжение питания. Однако в MAX9860 меньше производительность. Меньше разрядность, нет stereo, меньше максимальная частота дискретизации. Полное сравнение тут.
Можно заметить, что все аудио кодеки по сути это 2 цифро-аналоговых устройства на одном кристалле: DAC и ADC. Если вы используете, например, только DAC, то можно просто не собирать код для ADC. Это упростить ваш проект и увеличит надежность.
Идеи устройств на чипе MAX9860
Караоке.
В режиме Sidetone max8960 становится фактически слуховым аппаратом.
Звуковой дальномер.
Диктофон.
Плейер *.wav файлов.
Метроном.
Громкоговоритель.
Осциллограф.
(проводная/беспроводная) передача модулированных данных, например FSK модуляцией.
Обновление прошивки через звук.
Передача бинарных данных по звуку. Интерфейс спикер->микрофон.
Датчик шума.
Спектро-анализатор.
Переносные рации. Аудиокодек уже содержит ADC для микрофона и DAC для спикера.
Синтезатор аудио частот до 24kHz.
Имитация рычания мотора внутри глушителя автомобиля.
Вывод
MAX9864 это простой миниатюрный ASIC для воспроизведение и записи 16 битного моно звука. Вокруг этого чипа нет нормальной инфраструктуры (отладочные платы, примеры драйверов для микроконтроллеров).
Как видите, для отладки драйвера аудиокодека надо очень много разнообразного оборудования и примочек.
Словарь
Для работы с аудио кодеками надо распознавать следующие акронимы
Акроним |
Расшифровка |
DAC |
Digital-to-analog converter |
ASIC |
application-specific integrated circuit |
GSM |
??? |
PCM |
Pulse-code modulation |
PGA |
programmable gain amplifier |
АЦП |
Аналого-цифровой преобразователь |
ЦАП |
Цифро-аналоговый преобразователь |
MCLK |
master clock |
DMA |
Direct memory access |
DMM |
Digital Multi Meter |
I2C |
Inter-Integrated Circuit |
I2S |
Inter-IC Sound (Inter-integrated sound) |
PAM |
PreAMp |
24 TQFN-EP |
Exposed pad |
QFN |
Quad Flat No-leads |
TDM |
Time Division Multiplexed |
AGC |
automatic gain control |
MAX |
Maxim Integrated |
PLL |
Phase-locked loop |
ADC |
Analog-to-digital converter |
Links
Купить переходник можно тут.
Чип AudioСodec(а) WM8731 (или (ADC/DAC)*2 из iPod(а))
Support for ''repeated start'' in STM32 HAL I2C library
https://habr.com/ru/articles/683762/
Вопросы для обсуждения:
С какими микросхемами аудиокодеков работали Вы?
Зачем в аудиокодеках функция подмешивания в воспроизведение сигнала с микрофонов (side tone)?
Как протестировать что DAC работает?
Как проверить корректность работы шины I2S, если нет доступа к проводам BLCK и LRCLK?
Комментарии (10)
smart_pic
31.08.2023 11:27+55--Очень экзотический формат пакета для чтение I2C регистра. Как видите тут 2 старт сигнала и один только стоп. Это как если бы в математической формуле был бы нарушен баланс между открытыми и закрытыми скобками.
Ничего особенного, много в каких микросхемах используется такой подходaabzel Автор
31.08.2023 11:27Ничего особенного, много в каких микросхемах используется такой подход
Есть ли возможность привести пример ASIC(а)?
vau
31.08.2023 11:27+5В любой EEPROM 24 серии такой подход. Тысячи их. Вообще для I2C это стандартная тема с повторным стартом где в одной посылке надо и адрес регистра задавать и чтение выполнять
nixtonixto
31.08.2023 11:27+1I2C не запрещает при установке адреса чтения подавать комбинацию СТОП и потом сразу за ней СТАРТ — но обычно этого не делают для экономии времени и размера программы.
LAutour
31.08.2023 11:27+1Только такой подход не всегда работает в реализациях. Китайский микроконтроллер A9 мне например не удалось заставить так работать по его аппаратному I2C(через низкоуровневые функции SDK).
DoHelloWorld
31.08.2023 11:27+4или реализовывать программный I2C драйвер чисто на GPIO и аппаратных таймерах.
Ну не обязательно колхозить. Насколько помню можно спуститься до регистров и написать драйвер на CMSIS, там можно сколько угодно стартов сделать
Albert2009Zi
DMM, классно сократили. Я только из описания функционала понял, что это за девайс :)
aabzel Автор
Если будете работать в европейской или американской конторе, то обязательно услышите, что мультиметр там называют DMM.
Albert2009Zi
Уже :) Ну немцы, саксонцы по крайней мере, просто говорят "мессгерет"(дословно измерительный прибор). А так в программах, да, проскакивают названия функций и переменных с DMM. Просто в русской статье непривычно это было видеть, вот мозг сразу и не включился.