Arduino + AY-3-8910 or YM2149F
If you dont have generator for clock signal you can use this sketch instead of previous.
const byte ad[8] = { 8, 9, 2, 3, 4, 5, 6, 7 }; // connect to DA0,1,...,7
const byte pinBC1 = 10;
const byte pinBDIR = 12;
const byte freqOutputPin = 11; // OC2A output pin for ATmega328 boards
//Fast pin switching macros
#define __BCPORT__ PORTB
#define __BC1__ 2 // PORT PIN
#define __BDIR__ 4 // PORT PIN
void initFrequencyGenerator()
{ // Set Timer 2 CTC mode OC2A toggles on compare match
TCCR2A = 0x42;
TCCR2B = 0x01; // prescaller
TIMSK2 = 0;
// This value determines the output frequency: 0 - 16MHz, 1 - 8MHz, 2 - 4MHz, 3 - 2MHz, 4 - 1MHz
OCR2A = 3;
}
void setup() {
// INTERRUPT DISABLE
cli();
//init pins
for(byte i=0; i < 8; i++) pinMode(ad[i], OUTPUT);
pinMode(0, INPUT);
pinMode(pinBC1, OUTPUT);
pinMode(pinBDIR, OUTPUT);
//inactive mode
digitalWrite(pinBC1, LOW);
digitalWrite(pinBDIR, LOW);
pinMode(freqOutputPin, OUTPUT);
initFrequencyGenerator();
//serial init at 57600
UBRR0H = 0;
UBRR0L = 0x10;
UCSR0C = 0x06;
UCSR0A = 0;
UCSR0B = 0x90;
// INTERRUPT ENABLE
sei();
}
void send_data(byte address, byte data) {
// WRITE REGISTER NUMBER
//write address to DA0-DA7 pins
PORTB |= address & 0x03;
PORTD |= address & 0xFC;
//validate addess
//set BC1+BDIR bits, latch address mode
__BCPORT__ |= (1 << __BDIR__) + (1 << __BC1__);
asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); //set+hold address delay 500ns (400+100 min)
//clear BC1+BDIR bits, inactive mode
__BCPORT__ &= ~((1 << __BDIR__) + (1 << __BC1__));
// reset pins to tristate mode
PORTB &= ~(address & 0x03);
PORTD &= ~(address & 0xFC);
// WRITE REGISTER DATA
//write data to pins
PORTB |= data & 0x03;
PORTD |= data & 0xFC;
//validate data
//set BDIR bit, write to reg mode
__BCPORT__ |= ( 1 << __BDIR__);
asm("nop\nnop\nnop\nnop"); //250ns delay (250min-500max) nop=62.5ns on 16MHz
//clear BDIR bit, inactive mode
__BCPORT__ &= ~( 1 << __BDIR__);
// reset pins to tristate mode
PORTB &= ~(data & 0x03);
PORTD &= ~(data & 0xFC);
}
// SERIAL INTERRUPT HANDLER
bool reg = false;
byte reg_num = 0;
ISR(USART_RX_vect)
{
byte r = UDR0;
if (bit_is_clear(UCSR0A, FE0))
{
if(reg == false)
{
if(r <= 15)
{
reg_num = r;
reg = true;
}
}
else
{
send_data(reg_num, r);
reg = false;
}
}
}
void loop() {
// Write your code here :)
}
BDIR pin moved from 11 to 12, pin 11 now is used to generate clock signal for AY/YM.
Clock signal is generated by timer2 in CTC mode. Frequency is set by OCR2A (for value 3 it is about 2MHz).
[ad name="HTML"]

Работает отлично! Молотит, аж пыль из колонок летит ;). По скорости воспроизведения есть отличия с тем кварцем, что у меня, но не слишком большие.
Я тут ещё вот что подумал. Как я понял частота генератора задаётся путём деления. Можно залить скетч, немного пересчитав nop ы, потом запаять в ардуину кварц на 14МГц. Тогда генератор будет выдавать частоту 1.75МГц, что как и в оригинальном ZX. Ну хотя на 2МГц оно как-то бодрее. 🙂
Да кстати, не знаю как на AVR эмуляторе и на AY-8-8910, но на YM2149 не воспроизводятся DigitalAY, щелкает лишь что-то в динамиках. Но это не напрягает вообще.
Digital AY не пойдет, скорости последовательного интерфейса не хватает, максимум 2КГц мне удалось добиться на 1МГц работы ком порта 🙂
Если поставить 14МГц кварц, то и для USART придется пересчитывать коэфициенты для 14МГц, а то он не будет принимать данные. Это не проблема, если что пересчитаю.
Еще есть идея сделать Atmega8 со встроенным кварцем вместо ардуины 🙂
На счёт 14MГц , чисто теоритически нужно создать загрузчик, залить в ардуино и поправить boards.txt. Вот к примеру: http://homes-smart.ru/index.php/oborudovanie/arduino/avr-zagruzchik Может как-нибудь со временем попробую поиздеваюсь над ардуиной.
На счёт Atmega8 на внутреннем генераторе – опять же чисто мысли, что возможно скорость звука будет при работе, незначительно меняться.
А с другой стороны, ардуино со всей обвязкой по цене не сильно дороже 8меги.
Так там вроде даже не надо загрузчик, достаточно поменять кварц и в скетче для USART настройки выставить на 14МГц
Для кварцев 8+ МГц никаких дополнительных настроек вроде нет во фьюзах. Остальное вычисляется при программировании установкой регистров задающих частоты, например тот же ICR для таймера или UBRR как в этом скетче, тут частота кристалла делится на 16 и на скорость порта – 1.
Еще нопов наверное придется добавить, т.к. такт уже будет не 62нс а больше )
Когда я покупал кучку Atmega8 они стоили около 25-30р за штуку, а вот ардуины от 100р, так что у меня атмег8 на 10 лет вперед ))))
Нопов добавлять как бы и не нужно, такт получается 71нс, по скетчу этого хватает. Ну а UBRR, тут нужно мне покурить 🙂
Сейчас вернул схему на внешний кварц 1.84, пускай пока так играет, а дальше видно будет.
Запустил сегодня плеер на кварце 14Мгц 😉
В ардуино иде скетчи на этом кварце не заливаются ни в какую, хоть и boards.txt подправлен. Пришлось через программатор загружать.
В итоге всё работает, получил на 11 пине, 1.75 Мгц. UBRR пересчитывать не стал, сделал так:
#define USART_BAUDRATE 57600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) – 1)
В сетапе :
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
UCSR0C = (1 << UCSZ01) | (1 <> 8);
UBRR0L = BAUD_PRESCALE;
UCSR0B |= (1 << RXCIE0)
Отлично! А не заливает, потому что бутлоадер настроен на 16МГц.
Кстати, а F_CPU у вас исправлен на 14000000UL?
еще рекомендую использовать удвоенную скорость USART, т.к. меньше ошибок будет, но для 14МГц значения вроде одинаковые.
кстати, рекомендую использовать калькулятор
Я так понимаю, что иде берёт информацию о частоте процессора из boards.txt,
т.е. выбирается конфигурация прописанной платы, а частота из этой строки:
a328p_14MHz.build.f_cpu=14000000L
Но всё равно не понятно, почему не заливает скетчи через сериал.
Я ведь прошивал бутлоадер именно для кварца 14МГц, из среды иде, через usbasp…
За калькулятор спасибо!
Здесь я затрудняюсь ответить, каким образом там заливается HEX из временного каталога…
Возможно всё-же что-то не так с бутлоадером или настройками.
Так теперь вопрос по калькулятору 😉
Взял скетч, прописал UBBR0L=0х0E (для 14 МГц) 1.3% of error. Загрузил, плеер работает, всё ОК.
Посмотрел значение для кварца 16МГц UBBR= 0x22 – 0,8% of error. В вашем скетче 0х10 – 2.1%
Или я что-то не понимаю?
Всё верно, там же таблица из 2 частей состоит, с обычной скоростью и удвоенной.
0x10 это для обычной скорости, 0x22 для удвоенной,
Можете прописать 0x22 и сделать после этого
UCSR0A |= _BV(U2X); //для atmega328p
UCSRA |= _BV(U2X); //для atmega8
это включит удвоенную скорость
0x22 видимо лучше, т.к. несоответствие скоростей будет меньше.
Указанный процент ошибки говорит не об ошибках передачи, а об ошибке вычисления скорости от эталонной.
Теоретически, последовательный интерфейс допускает расхождение скоростей, точно не помню, до 20% вроде, где-то читал.
А можно добавить регулировку громкости звука на двух кнопках + – ?
Я так понял там есть регулировка громкости в каком то регистре, только я не очень понимаю как это реализовать ( подскажите пожалуйста.
Не совсем понятно, что имеется в виду, если вы имеете в виду занижать значение регистров амплитуды, то это не самый лучший вариант, т.к. будет портиться звучание. Здесь 2 варианта, либо делать аналоговую регулировку, либо ставить цифровую схему управления громкостью. Но к AY/YM это отношения не имеет. Т.е. регулировка должна произодиться на выходе микросхемы.
Здравствуйте, я собрал плеер по вашей инструкции, загрузил скетч в ардуино, и чип начал играть музыку. Все три канала работают как надо, но когда дело доходит до шумового канала чип вместо смачного “пшшш” делает только тихий щелчок. Проверял на двух разных чипах, в чем может быть проблема?