Arduino + AY-3-8910 или YM2149F
Если у вас нет подходящего генератора или вы не можете его собрать и т.д.
Скетч аналогичный предыдущему, но, с дополнительным генератором сигнала в районе 2МГц
Так же в нем не используются стандартные функции для работы с COM портом, а используется непосредственная инициализация регистров порта и обработчик прерывания, что вдвое сократило размер скомпилированного кода и ускорило обработку данных, соответственно улучшив работу генератора Clock сигнала для AY/YM
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 перенесен с 11 на 12, а на 11-ом теперь находится выход генератора сигнала.
Сигнал генерируется таймером в CTC режиме, а частота сигнала задается значением, устанавливаемым в OCR2A (в данном случае это примерно 2 МГц).
[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 это отношения не имеет. Т.е. регулировка должна произодиться на выходе микросхемы.
Здравствуйте, я собрал плеер по вашей инструкции, загрузил скетч в ардуино, и чип начал играть музыку. Все три канала работают как надо, но когда дело доходит до шумового канала чип вместо смачного «пшшш» делает только тихий щелчок. Проверял на двух разных чипах, в чем может быть проблема?