Программирование микросхем AKM для работы в soft mode на базе ATmega88

Доброго времени суток. Полгода назад, в связи с решением проектировать в качестве ВКРБ схему ЦАП+усь, встал вопрос выбора подходящей микросхемы для того, чтобы использовать её в качестве «сердца» разрабатываемого устройства. Поскольку актуальные версии микросхем ЦАП от Sabre являются труднодоступными, как и даташиты на них, было принято решение проектировать на чипах AKM. Субъективно, в моём личном топе они занимают благодарное второе место (приходилось много слушать 4490). Таким образом было принято решение использовать AK4493EQ. Он заметно опережает 4490 по своим характеристикам и несильно уступает 4497 при вшестеро меньшей цене.

Так и подкрался вопрос о проектировании цифровой части (в первую очередь).

Поскольку интернет пестрит огромным количеством готовых конвертеров USB->I2S, в условиях сильной ограниченности по времени решено разрабатывать устройство с поддержкой стандартов Bolero и не изобретать велосипед. Получилось то, что изображено на рисунке.

Далее по порядку.

Когда впервые встаёт задача сделать что-то настолько практическое при наличии исключительно теоретических знаний из университета.

Когда впервые открываешь даташит на современную микросхему ЦАП встаёт вопрос: «Неужели это всё нужно читать и понимать?». Куча временных диаграмм, графиков и, что самое страшное, огромное количество чистого текста. Если попытаться сначала просто читать текст даташита подряд в лоб, то через пару страниц натыкаешься на таблицу. И ещё одну.. И так далее...

А  дальше очевидно. С программной точки зрения только таблицы и нужны, в них есть вся необходимая информация по пинам и режимам их работы.

Разумеется, таблиц в даташите намного больше, и, чтобы не приходилось постоянно свайпить страницу туда-сюда, проще всего было заскринить с него все таблицы и сделать отдельную папку.

После того, как все таблицы в удобном виде оказались под рукой, становится очевидно, что половина из них на самом деле не будет использоваться по тем или иным причинам. Например невозможно осуществлять регулировку громкости, при «честном» воспроизведении DSD потока. Или нет необходимости менять качество звукового сигнала, уменьшать размах напряжения на выходе и т.п.

Как только завершается анализ всех полученных таблиц (я их скриншотил с описанием, чтобы не приходилось часто лезть в даташит обратно), уже можно приступать к самому программированию.

Для ещё большего удобства, по информации из самого конца даташита (значения внутренних регистров по умолчанию), я выписал все регистры с их битами и значениями по умолчанию и сделал заметку (выделил те биты, значение которых придётся менять и что они означают).

Вот теперь можно приступать к программированию.

Поскольку на протяжении всего цикла работы, меня очень поддерживал и помогал admin (Андрей), за что выражаю ему огромную благодарность, в качестве МК (микроконтроллера) используется ATmega88. Не вникал особо почему именно он, но, возможно, во многом благодаря тому, что любой из его пинов ввода-вывода можно настроить как пин прерывания.

Поскольку опыт работы с МК был у меня последние полгода, к сожалению, не могу рассказать этот момент от лица новичка с мельчайшими подробностями, так что скорее всего это к вопросу о личной подготовке перед началом работы, данная статья больше о программировании уже под конкретную задачу.

В даташите на 4493 чётко регламентировано, что передача происходит двумя последовательными байтами, где первый байт — адрес регистра, к которому идёт обращение, а 7й и 6й биты — адрес устройства (зависит от сигнала на ногах cad0 и cad1, по алгоритму работы похоже на обычный адрес SPI). Второй байт — данные, загружаемые в регистр. Формат процедуры передачи данных также происходит по шине SPI, так что в первую очередь необходимо проинициализировать устройство, как мастер SPI, а затем написать процедуру передачи данных (есть в программном коде, прилагающимся к статье — процедуры masterSPI и transmitSPI).

Переменная cad1 необходима для того, чтобы различить, в какой именно ЦАП сейчас передавать данные. Так как в разрабатываемом устройстве стоит 2 микросхемы ЦАП (Л и Р, соответственно), то необходимо различать настройку этих микросхем. Поскольку разница в настройки заключается в одном единственном регистре (где как раз и происходит выбор — это Л и Р микросхема) было решено на лету менять адрес Р микросхемы, только при работе с этим регистром (defibe SET_CAD1...), а всё остальное время обе микросхемы обладают одинаковым адресом.

Остальные дефайны:

1) SPI — название порта, чтобы было семантически удобнее обращатьсся

2) Дальше дефайн огромного количества контактов, тоже исключительно ради удобства, никакой магии

3)SET_MUTE — сигнал для реле (схема подавления щелчков)

4) Ну и дефайн адресов регистров 4493

В main сначала происходит изначальная настройка портов. Первые 2 строчки — настройка конкретных пинов на ввод или вывод, затем установка одного из генераторов и сигнала SS в высокое состояние (сигнал шины SPI, когда в низком состоянии, передача не происходит). Далее идёт инициализация и волшебная функция checkDP. 

CheckDP просто проходит по всем битам на входе МК и загружает соответствующие значения в микросхемы ЦАП (как раз процедура основной функциональности всей программы).

Более интересно обстоят дела с её вызовам по изменении любого бита на входе. В мейне есть строчка «pcicr = 0x6». PCICR отвечает за активацию соответствующих портов атмеги как полноценных портов прерывания. То есть каждый пин порта может использоваться как генератор прерываний, причём один порт — одно прерывание, а не каждый пин = прерывание, как можно было подумать сначала. Например PCINT_1 отвечает за прерывание по PORTC, а PCINT_2 по PORTD. Причин у вызовы прерывания может быть множество (срез, фронт, изменение сигнала и т.п.). Поскольку нас интересует любое возможное изменение в конфигурации воспроизводимого трека или состояния цифрового фильтра, порт настроен на фиксацию любого изменения состояния любого из пинов соответствующего порта. Регистры PCMSK отвечают за выбор пинов, отвечающих за прерывания.

sei — разрешает глобальные прерывания в программе, а в бесконечном цикле идёт ожидание прерывания.

Запись ISR(PCINT#_vect), где # — номер вектора прерывания (0 — PORTB, 1 — PORTC, 2 — PORTD) означает, что эта процедура является обработчиком соответствующего прерывания.

checkDP является отдельной процедурой, а не чисто обработчиком прерывания исключительно ради того, чтобы можно было вызвать его при старте программы.

Это мой первый опыт написания статей и подозреваю, что если она привлечёт чьё-нибудь внимание, могут возникнуть вопросы, на которые с радостью отвечу)

Вложение: KursC.rar 26,98 KB (Скачиваний: 51)

Похожие статьи

1 комментарий

.

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.