Parallel sending with generator

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).

ay_arduino

14 thoughts on “Parallel sending with generator

  1. Работает отлично! Молотит, аж пыль из колонок летит ;). По скорости воспроизведения есть отличия с тем кварцем, что у меня, но не слишком большие.
    Я тут ещё вот что подумал. Как я понял частота генератора задаётся путём деления. Можно залить скетч, немного пересчитав nop ы, потом запаять в ардуину кварц на 14МГц. Тогда генератор будет выдавать частоту 1.75МГц, что как и в оригинальном ZX. Ну хотя на 2МГц оно как-то бодрее. 🙂

  2. Да кстати, не знаю как на AVR эмуляторе и на AY-8-8910, но на YM2149 не воспроизводятся DigitalAY, щелкает лишь что-то в динамиках. Но это не напрягает вообще.

  3. Digital AY не пойдет, скорости последовательного интерфейса не хватает, максимум 2КГц мне удалось добиться на 1МГц работы ком порта 🙂
    Если поставить 14МГц кварц, то и для USART придется пересчитывать коэфициенты для 14МГц, а то он не будет принимать данные. Это не проблема, если что пересчитаю.
    Еще есть идея сделать Atmega8 со встроенным кварцем вместо ардуины 🙂

  4. На счёт 14MГц , чисто теоритически нужно создать загрузчик, залить в ардуино и поправить boards.txt. Вот к примеру: http://homes-smart.ru/index.php/oborudovanie/arduino/avr-zagruzchik Может как-нибудь со временем попробую поиздеваюсь над ардуиной.
    На счёт Atmega8 на внутреннем генераторе – опять же чисто мысли, что возможно скорость звука будет при работе, незначительно меняться.
    А с другой стороны, ардуино со всей обвязкой по цене не сильно дороже 8меги.

    1. Так там вроде даже не надо загрузчик, достаточно поменять кварц и в скетче для USART настройки выставить на 14МГц
      Для кварцев 8+ МГц никаких дополнительных настроек вроде нет во фьюзах. Остальное вычисляется при программировании установкой регистров задающих частоты, например тот же ICR для таймера или UBRR как в этом скетче, тут частота кристалла делится на 16 и на скорость порта – 1.
      Еще нопов наверное придется добавить, т.к. такт уже будет не 62нс а больше )

      Когда я покупал кучку Atmega8 они стоили около 25-30р за штуку, а вот ардуины от 100р, так что у меня атмег8 на 10 лет вперед ))))

      1. Нопов добавлять как бы и не нужно, такт получается 71нс, по скетчу этого хватает. Ну а UBRR, тут нужно мне покурить 🙂
        Сейчас вернул схему на внешний кварц 1.84, пускай пока так играет, а дальше видно будет.

  5. Запустил сегодня плеер на кварце 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)

    1. Отлично! А не заливает, потому что бутлоадер настроен на 16МГц.
      Кстати, а F_CPU у вас исправлен на 14000000UL?
      еще рекомендую использовать удвоенную скорость USART, т.к. меньше ошибок будет, но для 14МГц значения вроде одинаковые.

      кстати, рекомендую использовать калькулятор

      1. Я так понимаю, что иде берёт информацию о частоте процессора из boards.txt,
        т.е. выбирается конфигурация прописанной платы, а частота из этой строки:
        a328p_14MHz.build.f_cpu=14000000L
        Но всё равно не понятно, почему не заливает скетчи через сериал.
        Я ведь прошивал бутлоадер именно для кварца 14МГц, из среды иде, через usbasp…
        За калькулятор спасибо!

        1. Здесь я затрудняюсь ответить, каким образом там заливается HEX из временного каталога…
          Возможно всё-же что-то не так с бутлоадером или настройками.

      2. Так теперь вопрос по калькулятору 😉
        Взял скетч, прописал UBBR0L=0х0E (для 14 МГц) 1.3% of error. Загрузил, плеер работает, всё ОК.
        Посмотрел значение для кварца 16МГц UBBR= 0x22 – 0,8% of error. В вашем скетче 0х10 – 2.1%
        Или я что-то не понимаю?

        1. Всё верно, там же таблица из 2 частей состоит, с обычной скоростью и удвоенной.
          0x10 это для обычной скорости, 0x22 для удвоенной,
          Можете прописать 0x22 и сделать после этого
          UCSR0A |= _BV(U2X); //для atmega328p
          UCSRA |= _BV(U2X); //для atmega8
          это включит удвоенную скорость
          0x22 видимо лучше, т.к. несоответствие скоростей будет меньше.
          Указанный процент ошибки говорит не об ошибках передачи, а об ошибке вычисления скорости от эталонной.
          Теоретически, последовательный интерфейс допускает расхождение скоростей, точно не помню, до 20% вроде, где-то читал.

  6. А можно добавить регулировку громкости звука на двух кнопках + – ?
    Я так понял там есть регулировка громкости в каком то регистре, только я не очень понимаю как это реализовать ( подскажите пожалуйста.

    1. Не совсем понятно, что имеется в виду, если вы имеете в виду занижать значение регистров амплитуды, то это не самый лучший вариант, т.к. будет портиться звучание. Здесь 2 варианта, либо делать аналоговую регулировку, либо ставить цифровую схему управления громкостью. Но к AY/YM это отношения не имеет. Т.е. регулировка должна произодиться на выходе микросхемы.

Leave a Reply

Your email address will not be published. Required fields are marked *