habrahabr

Звук на чипе AY-3-8910 (или Yamaha YM2149F) родом с ZX Spectrum на PC через USB

  • воскресенье, 25 января 2015 г. в 02:11:20
http://habrahabr.ru/post/248115/

Прошло около года, с момента успешного подключения музыкального синтезатора YM2149F к LPT порту компьютера. LPT это конечно хорошо, однако время не стоит на месте, и найти компьютер или ноутбук с LPT портом становится все сложнее и сложнее. Да и сам автор (то есть я) устал лазить каждый раз под стол, где стоит системник, и перетыкать LPT плату на что-то другое, например программатор (у меня LPT-программатор Willem, ну да не суть). Поэтому на сей раз подключать чип YM2149F будем к USB. Ну и конечно, чтобы соотвествовать эпохе, будем это делать на копеечном древнем микроконтроллере PIC16F628.

image

Вкратце, YM2149F (или ее функциональный аналог AY-3-8910) — микросхема звукового трехголосного синтезатора, применялась в старых компьютерах типа Atari ST, Amstrad CPC, ZX Spectrum, MSX и некоторых других для проигрывания музыки. В России чип приобрел определенную известность благодаря установки в различные клоны ZX Spectrum'а. За время шествования ZX Spectrum по бывшему СССР музыкантами были написаны тысячи мелодий под этот звуковой программируемый генератор. Да и сейчас можно вполне найти людей, создающих музыку именно под этот чип. В конце статьи будут приведены ссылки на огромнейший архив чип-тюнов для YM/AY на сотни часов непрерывного прослушивания.


Демо


Как и в прошлый раз, перед началом, даю сразу ссылку на прослушивания конечного результата: https://soundcloud.com/tronix286 Последние записи сделаны как раз с этого устройства. Записывал так-себе плеером, который пишет максимум в 128Kb/s MP3, поэтому в реальности устройство звучит «ярче». Но составить общее представление о звуке можно.

Железо


Почему такой странный выбор контроллера? Почему не AVR/ARM/iCore i7/FTDI на худой конец? Частично ответ на этот вопрос дан в начале топика: ретро синтезатору — ретро микроконтроллер! Тем более, что у AY-3-8910 и фирмы Microchip, можно сказать, общие корни. А вообще, так сложилась серия странных обстоятельств. Во-первых я наткнулся в интернете на библиотеку, реализующую программный (софтварный) стек USB 1.1 для микроконтроллеров PIC16F628 — вот эта библиотека: 16FUSB. Во-вторых, у меня давно лежала и пылилась парочка PIC16F628A, которые я не знал куда деть. В третьих, на компе уже стоял настроенный софт (MPLABX, MPASM) и имеется программатор для PIC. Ну и в отличии от программного стека V-USB на AVR, известного многим, на PIC'ах без аппаратного USB проектов мало или даже вообще нет. А это значит, что нужно восстановить историческую несправедливость.

Вот типовая схема включения с сайта библиотеки 16fusb:

image

В комплекте с библиотекой 16fusb идет хороший пример под названием «direct-io». Смысл прост — посылаем через USB байт и он «отображается» на восьми ножках микроконтроллера. Так же можно посылать дополнительно два управляющих сигнала, то есть еще два бита (или две ножки). И в обратном направлении, то есть от контроллера к хосту (компьютеру).
image

Для управления YM2149F используется восьмибитная шина данных D0-D7 и три управляющих сигнала BC1, BDIR и RESET. BC1 и BDIR управляют выбором адреса регистра и его значением, а так же переводят микросхему в неактивное состояние. Сигнал RESET используется для сброса всех регистров на первоначальное значение. Таким образом, чтение из PIC в компьютер не нужно; нужна только возможность посылать команды на YM. И нужен еще третий управляющий сигнал, а значит еще одна ножка МК.

В своей прошивке для управления конкретно YM2149F было сделано следующее:
  • выкинуто все, что связано с чтением сигналов из PIC в хост (компьютер) для увеличения быстродействия обработки реквестов USB;
  • состояние направлений портов ввода-вывода жёстко задано при инициализации МК и не изменяется в процедурах выдачи байта на ноги.
  • организован кольцевой буфер на 64 байта. При декодировании запроса от хоста байты складываются в буфер. Когда есть свободное время, данные из буфера выдаются на YM.
  • оптимизирована скорость выдачи байта на ноги МК. Частично за счет жестко указанных направлений ввода-вывода, частично из-за известности предыдущего состояния управляющих бит.
  • пофикшен глюк с зацикливанием PIC через несколько тысяч пакетов (развернут цикл RxLoop в файле isr.asm, вместо goto RxLoop вставлена проверка на признак конца пакета)
  • что-то еще, не помню


Как уже сказано выше, возникает потребность в еще одном управляющем сигнале — RESET, а свободных ножек уже нет. Поэтому для тактирования PIC применен кварцевый генератор, а не кварц, тем самым высвобождая одну ногу МК (RA6), необходимую для управления сигналом RESET. Нога RA5, торчащая в воздухе, в данном семействе работает только на вход и не может быть использована для управления выходным сигналом. На нее можно было-бы переложить функционал по отлавливанию конца USB пакета (EOP) с ножки RB2, однако это не так просто — в отличии от ножки RB2 ножка RA5 делит функционал с MCLR и VPP для программирования и внутри организован вход как триггер шмитта. Ему просто не хватит напряжения после диодов для сработки. С другой стороны, для тактирования YM2149F собран генератор на микросхеме 74HC02 и кварце 3.579545 MHz. Можно было бы попробовать использовать вторую свободную половину микросхемы для сборки аналогичного генератора и для PIC, но остановило два момента: 1) у меня нету кварца на 24МГц (а кварцевый генератор был, с какой-то древней мамки) 2) я не знаю, как поведет себя 74HC02, если с «разных боков» у нее будут разные частоты, причем одна из них довольно высокая (24МГц все таки очень большая частота). Еще один из вариантов, как освободить ногу RA6 для кварца: Сигналы BC1 и BDIR принимают только такие значения:
BC1    BDIR
 0       0
 0       1
 1       1

И никогда BC1 = 1, BDIR = 0. Это можно использовать как RESET, добавив NOT и NOR логику из половинки микросхемы 74HC02 и проинвертировав сигнал на выходе с помощью транзистора. Конечно для выдачи BC = 1 и BDIR = 0 нужно немного подправить прошивку.

И еще, нога RA4, которая управляет сигналом BDIR, с открытым коллектором, поэтому ее обязательно нужно подтянуть к питанию — на схеме это 10K резистор R5.

Софт


Со стороны компьютера, в качестве музыкального проигрывателя, выступает отличный кросс-платформенный плеер чип-тюнов ZX Tune:
image

Напрямую он не поддерживает USB, зато если находит у себя в директории одну из библиотек dlportio.dll/inpout32.dll/inpoutx64.dll, то позволяет переключится в настройках вывода звука на YM-LPT (для прошлого проекта), а затем использует функцию __stdcall void DlPortWritePortUchar(unsigned short port, unsigned char val); для выдачи байт YM2149. Порт 0x378 данные, Порт 0x37a передача управляющих сигналов (D1 — ~BDIR, D2 — BC1, D3 — ~RESET). Таким образом, можно написать маленькую библиотеку-заглушку с одной единственной функцией DlPortWritePortUchar, в которой перенаправлять выдачу байт на USB-устройство, что и было сделано. Я просто взял исходники библиотеки inpout32 за основу и написал функцию-заглушку для перенаправления выдачи байт на это устройство. В итоге, достаточно положить эту библиотеку-заглушку inpout32.dll или inpoutx64.dll, в зависимости от используемой версии плеера (x86/x64), в одну директорию с плеером ZX Tune, запустить его и в настройках звука переместить устройство aylpt на самый верх (как на скриншоте выше).

Скачать бесплатно и без СМС


Драйвера для Win XP, Win 7 (x32/x64) можно скачать здесь: 16FUSB_driver-libusb-win32-1.2.6.0.zip

Схема устройства: ym-usb_scheme_1.0.rar
Скомпилированная прошивка (.hex) и скомпилированные DLL-заглушки: ym-usb_firmware_and_DLLs_v1.2.rar
Исходные коды прошивки: ym-usb_PIC16F628A_source_v1.2.rar
Исходные коды библиотеки-заглушки: inpout32-64_DLL_source_v1.2.rar
General Instruments AY-3-8910 / 8912 Programmable Sound Generator (PSG) data Manual: http://bulba.untergrund.net/AY-3-8910.rar
Тема на форуме ZX.PK.ru, из которой «родилось» устройство: http://zx-pk.ru/showthread.php?t=22202

Огромный архив трекерной музыки: Modland (ФТП)
ZX музыка онлайн: http://zxtunes.com/

Всем добра!