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.

рис. 1
рис. 1

При более внимательном рассмотрении чип выглядит так. Тут видно усиление сигнала на микрофонах, управление громкостью звука. Возможность включать аналоговый LoopBack. Возможность пропускать сигнал через цифровые фильтры (Эллиптический и Баттерворта) на разных частотах дискретизации 8kHz, 16kHz, 48kHz.

рис. 2
рис. 2

С точки зрения программиста микроконтроллеров MAX9860 выглядит так (рис.3). Чип на шине I2C с базовым адресом равным 0x10

рис.3
рис.3

Расспиновка MAX9860ETG

Из микросхемы торчат 24 провода. Вот их назначение и смысл:

Ссылка на гуглдок MAX9860ETG+ pins

Как это обычно бывает в электронике, отладочной платы для MAX9860 нет в природе, а сам чип распространяется только в одном микроскопическом и диковинном корпусе 24TQFN-EP (с шагом 0.5мм), который увидеть можно только под микроскопом.

Поэтому для отладки драйвера чипа MAX9860 надо проектировать плату переходник для банального подключения проводов к микросхеме.

рис 4
рис 4

Или можно купить переходник на Aliexpress. Ключевое слово QFN24 Transfer Board 0.5MM. Ждать 5 недель.

Забавно, что у микросхемы MAX9860 отсутствует pin reset. Если зависнет, то поможет только перезагрузка питания. Еще чип надо тактировать частотой от 10MHz....20MHz. Для этого мне пришлось купить модуль DSPO 12.288 с кварцевым генератором 12,288MHz.

Модуль с кварцевым генератором на частоту 12.288 MHz
Модуль с кварцевым генератором на частоту 12.288 MHz

Программная часть

Что надо из софтвера?

Программа

Назначение

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
0x05

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 способами:

2^{92}=4.951760157*10^{27}

Это как количество молекул в двух человеках. Поэтому корректный конфиг имеет ключевое значение.

Запись I2C регистра выглядит так:

Запись в регистр 7 значения 0x10
Запись в регистр 7 значения 0x10

Чтение I2C регистра выглядит так. Тут важно чтобы микроконтроллер генерировал только 1 Stop сигнал в самом конце, даже несмотря та то что в пакете 2 Start сигнала. Команда чтения должна быть монолитная. Иначе из регистра прочитаются нули.

чтение регистра 0x10
чтение регистра 0x10

Микросхема отвечает на 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 есть отдельный текст: Отладка интерфейса I2S

Как отладить I2S сейчас? Можно воспроизвести статический синус. Именно статический чтобы исключить ошибки в динамическом выделении памяти. Если выбрать частоту, например, 1kHz, то получится, что надо рассчитать всего 48 PCM отсчетов, чтобы синтезировать гармонический сигнал. В прошивке достаточно зарезервировать 48*2*2=192 байт.

Прямо в прошивке расчитать 1 период для синуса 1kHz, амплитудой 3333 PCM, частоты дискретизации 48kHz и проигрывать его в цикле по DMA.

Look Up Table предварительно рассчитанного синуса для FS: 48kHz
Look Up Table предварительно рассчитанного синуса для FS: 48kHz

На шине 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.

Сигнал OUT в случае отсутствия тактирования MCLK. Шум.
Сигнал OUT в случае отсутствия тактирования MCLK. Шум.

Еще надо учитывать, то что в mono режиме MAX9860 просто игнорирует PCM данные на правом канале.

Однако можно включить стерео режим и на выходе появится сигнал.

Если воспроизвести синус на звуко излучатель и поднести смартфон с приложением Audizr, то появится вот такой спектр. Можно заметить что там 1032 Hz.

спектр звукового тонального сигнала. X-частота Y-амплитуда сигнала
спектр звукового тонального сигнала. X-частота Y-амплитуда сигнала

Достоинства 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.

прототип для отладки драйвера 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

  1. Караоке.

  2. В режиме Sidetone max8960 становится фактически слуховым аппаратом.

  3. Звуковой дальномер.

  4. Диктофон.

  5. Плейер *.wav файлов.

  6. Метроном.

  7. Громкоговоритель.

  8. Осциллограф.

  9. (проводная/беспроводная) передача модулированных данных, например FSK модуляцией.

  10. Обновление прошивки через звук.

  11. Передача бинарных данных по звуку. Интерфейс спикер->микрофон.

  12. Датчик шума.

  13. Спектро-анализатор.

  14. Переносные рации. Аудиокодек уже содержит ADC для микрофона и DAC для спикера.

  15. Синтезатор аудио частот до 24kHz.

  16. Имитация рычания мотора внутри глушителя автомобиля.

Вывод

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

Купить переходник можно тут.

Отладочная плата для Max9860

Чип AudioСodec(а) WM8731 (или (ADC/DAC)*2 из iPod(а))

MAX9860 vs WM8731

Отладка интерфейса I2S

Support for ''repeated start'' in STM32 HAL I2C library

https://habr.com/ru/articles/683762/


Вопросы для обсуждения:

  1. С какими микросхемами аудиокодеков работали Вы?

  2. Зачем в аудиокодеках функция подмешивания в воспроизведение сигнала с микрофонов (side tone)?

  3. Как протестировать что DAC работает?

  4. Как проверить корректность работы шины I2S, если нет доступа к проводам BLCK и LRCLK?

Комментарии (10)


  1. Albert2009Zi
    31.08.2023 11:27
    +1

    DMM, классно сократили. Я только из описания функционала понял, что это за девайс :)


    1. aabzel Автор
      31.08.2023 11:27
      +1

      Если будете работать в европейской или американской конторе, то обязательно услышите, что мультиметр там называют DMM.


      1. Albert2009Zi
        31.08.2023 11:27
        +1

        Уже :) Ну немцы, саксонцы по крайней мере, просто говорят "мессгерет"(дословно измерительный прибор). А так в программах, да, проскакивают названия функций и переменных с DMM. Просто в русской статье непривычно это было видеть, вот мозг сразу и не включился.


  1. smart_pic
    31.08.2023 11:27
    +5

    5--Очень экзотический формат пакета для чтение I2C регистра. Как видите тут 2 старт сигнала и один только стоп. Это как если бы в математической формуле был бы нарушен баланс между открытыми и закрытыми скобками.
    Ничего особенного, много в каких микросхемах используется такой подход


    1. aabzel Автор
      31.08.2023 11:27

      Ничего особенного, много в каких микросхемах используется такой подход

      Есть ли возможность привести пример ASIC(а)?


      1. vau
        31.08.2023 11:27
        +5

        В любой EEPROM 24 серии такой подход. Тысячи их. Вообще для I2C это стандартная тема с повторным стартом где в одной посылке надо и адрес регистра задавать и чтение выполнять


    1. nixtonixto
      31.08.2023 11:27
      +1

      I2C не запрещает при установке адреса чтения подавать комбинацию СТОП и потом сразу за ней СТАРТ — но обычно этого не делают для экономии времени и размера программы.


    1. LAutour
      31.08.2023 11:27
      +1

      Только такой подход не всегда работает в реализациях. Китайский микроконтроллер A9 мне например не удалось заставить так работать по его аппаратному I2C(через низкоуровневые функции SDK).


  1. DoHelloWorld
    31.08.2023 11:27
    +4

    или реализовывать программный I2C драйвер чисто на GPIO и аппаратных таймерах.

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


  1. Andy_Big
    31.08.2023 11:27
    -1

    Хотел прокомментировать каждый ляп, но их оказалось слишком много...