AY3910RegWrite.ino 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*******************************************************************
  2. * AY-3-3910 Register writer for Arduino
  3. * (c) 2014 Manoel "Godzil" Trapier
  4. *
  5. * All the code is made by me apart from the the timer code that
  6. * was inspired from code found on the internet. I'm sorry, I can't
  7. * remmember where.
  8. **************************** Licence ******************************
  9. * This file is licenced under the licence:
  10. * WTFPL v2 Postal Card Edition:
  11. *
  12. * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  13. * Version 2, December 2004
  14. *
  15. * Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
  16. *
  17. * Everyone is permitted to copy and distribute verbatim or modified
  18. * copies of this license document, and changing it is allowed as long
  19. * as the name is changed.
  20. *
  21. * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  22. * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  23. *
  24. * 0. You just DO WHAT THE FUCK YOU WANT TO.
  25. * 1. If you like this software you can send me a (virtual) postals
  26. * card. Details bellow:
  27. *
  28. * < godzil-nospambot at godzil dot net >
  29. *
  30. * If you want to send a real postal card, send me an email, I'll
  31. * give you my address. Of course remove the -nospambot from my
  32. * e-mail address.
  33. *
  34. ******************************************************************/
  35. const int freqOutputPin = 11; // OC2A output pin for ATmega328 boards
  36. // Constants are computed at compile time
  37. // If you change the prescale value, it affects CS22, CS21, and CS20
  38. // For a given prescale value, the eight-bit number that you
  39. // load into OCR2A determines the frequency according to the
  40. // following formulas:
  41. //
  42. // With no prescaling, an ocr2val of 3 causes the output pin to
  43. // toggle the value every four CPU clock cycles. That is, the
  44. // period is equal to eight slock cycles.
  45. //
  46. // With F_CPU = 16 MHz, the result is 2 MHz.
  47. //
  48. // Note that the prescale value is just for printing; changing it here
  49. // does not change the clock division ratio for the timer! To change
  50. // the timer prescale division, use different bits for CS22:0 below
  51. const int ocr2aval = 3;
  52. // The following are scaled for convenient printing
  53. //
  54. void setup_clock()
  55. {
  56. pinMode(freqOutputPin, OUTPUT);
  57. // Set Timer 2 CTC mode with no prescaling. OC2A toggles on compare match
  58. //
  59. // WGM22:0 = 010: CTC Mode, toggle OC
  60. // WGM2 bits 1 and 0 are in TCCR2A,
  61. // WGM2 bit 2 is in TCCR2B
  62. // COM2A0 sets OC2A (arduino pin 11 on Uno or Duemilanove) to toggle on compare match
  63. //
  64. TCCR2A = ((1 << WGM21) | (1 << COM2A0));
  65. // Set Timer 2 No prescaling (i.e. prescale division = 1)
  66. //
  67. // CS22:0 = 001: Use CPU clock with no prescaling
  68. // CS2 bits 2:0 are all in TCCR2B
  69. TCCR2B = (1 << CS20);
  70. // Make sure Compare-match register A interrupt for timer2 is disabled
  71. TIMSK2 = 0;
  72. // This value determines the output frequency
  73. OCR2A = ocr2aval;
  74. }
  75. enum { INACTIVE = B00, READ = B01, WRITE = B10, ADDRESS = B11};
  76. void setup_data(int mode)
  77. {
  78. switch(mode)
  79. {
  80. default:
  81. case READ:
  82. case INACTIVE:
  83. DDRD = B00000000; // Set all D port as input
  84. DDRB &= ~0x03;
  85. break;
  86. case ADDRESS:
  87. case WRITE:
  88. DDRD = B11111111; // Set all D port as output
  89. DDRB |= 0x03;
  90. break;
  91. }
  92. }
  93. void setup_control()
  94. {
  95. DDRC = DDRC | B00000011;
  96. PORTC &= ~B00000011;
  97. }
  98. void set_control(int mode)
  99. {
  100. PORTC = (PORTC & 111111100) | (mode);
  101. }
  102. void SetData(unsigned char data)
  103. {
  104. PORTD = data & 0xFC;
  105. PORTB = data & 0x03;
  106. }
  107. unsigned char GetData(void)
  108. {
  109. return (PORTD & 0xFC) | (PORTB & 0x03);
  110. }
  111. /* Registers */
  112. enum
  113. {
  114. REG_FREQ_A_LO = 0,
  115. REG_FREQ_A_HI,
  116. REG_FREQ_B_LO,
  117. REG_FREQ_B_HI,
  118. REG_FREQ_C_LO,
  119. REG_FREQ_C_HI,
  120. REG_FREQ_NOISE,
  121. REG_IO_MIXER,
  122. REG_LVL_A,
  123. REG_LVL_B,
  124. REG_LVL_C,
  125. REG_FREQ_ENV_LO,
  126. REG_FREQ_ENV_HI,
  127. REG_ENV_SHAPE,
  128. REG_IOA,
  129. REG_IOB
  130. };
  131. void write_2149_reg(uint8_t reg, uint8_t value)
  132. {
  133. setup_data(ADDRESS);
  134. SetData(reg & 0x0F);
  135. set_control(ADDRESS);
  136. delayMicroseconds(3);
  137. set_control(INACTIVE);
  138. delayMicroseconds(1);
  139. setup_data(WRITE);
  140. SetData(value);
  141. delayMicroseconds(1);
  142. set_control(WRITE);
  143. delayMicroseconds(5);
  144. set_control(INACTIVE);
  145. PORTD = 0;
  146. //setup_data(INACTIVE);
  147. }
  148. uint8_t read_2149_reg(uint8_t reg)
  149. {
  150. uint8_t ret = 0;
  151. return ret;
  152. }
  153. char regs[14];
  154. int j;
  155. void setup()
  156. {
  157. setup_clock();
  158. setup_control();
  159. setup_data(INACTIVE);
  160. Serial.begin(115200);
  161. // Be sure to kill all possible sound by setting volume to zero
  162. write_2149_reg(REG_LVL_A, B00000000);
  163. write_2149_reg(REG_LVL_B, B00000000);
  164. write_2149_reg(REG_LVL_C, B00000000);
  165. j = 0;
  166. }
  167. void loop()
  168. {
  169. int i;
  170. while (Serial.readBytes(regs, 14) != 14);
  171. for(i = 0; i < 14; i++)
  172. {
  173. write_2149_reg(i, regs[i]);
  174. }
  175. }