{"id":1818,"date":"2015-12-06T14:34:47","date_gmt":"2015-12-06T11:34:47","guid":{"rendered":"http:\/\/www.avray.ru\/?page_id=1818"},"modified":"2015-12-12T21:52:52","modified_gmt":"2015-12-12T18:52:52","slug":"play-yrg-files-from-sd-card","status":"publish","type":"page","link":"https:\/\/www.avray.ru\/ru\/play-yrg-files-from-sd-card\/","title":{"rendered":"\u041f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u0435 YRG, RSF \u0444\u0430\u0439\u043b\u043e\u0432 \u0441 SD \u043a\u0430\u0440\u0442\u044b"},"content":{"rendered":"<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Arduino \u0441\u043a\u0435\u0442\u0447 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c YRG \u0438 RSF \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u043a\u043e\u0440\u043d\u044f SD \u043a\u0430\u0440\u0442\u044b \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c AY-3-8910\/12 YM2149F \u0447\u0438\u043f\u0435 \u0438\u043b\u0438 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0435 \u0441 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0430. \u0421\u043a\u0435\u0442\u0447 \u0442\u0430\u043a \u0436\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 2\u041c\u0413\u0446 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u0438\u043f\u0430.<br \/>\n(\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043e 12.12.2015 \u0434\u043e RSF \u0432\u0435\u0440\u0441\u0438\u0438 3)<\/p>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/p>\n<p>\u041f\u0438\u043d\u044b \u043d\u0430 Arduino:<\/p>\n<p>A0 &#8212; DA0,\u00a0A1 &#8212; DA1,\u00a0A2 &#8212; DA2,\u00a0A3 &#8212; DA3, A4 &#8212; DA4, 5 &#8212; DA5, 6 &#8212; DA6, 7 &#8212; DA7<\/p>\n<p>3 &#8212; BC1, 2 &#8212; BDIR<\/p>\n<p>9 &#8212; \u0432\u044b\u0445\u043e\u0434 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 2\u041c\u0413\u0446<\/p>\n<p>SD \u043a\u0430\u0440\u0442\u0430:<\/p>\n<p>MOSI &#8212; 11, MISO &#8212; 12, CLK(SCK) &#8212; 13, CS &#8212; 4<\/p>\n<pre>#include &lt;SPI.h&gt;\r\n#include &lt;SD.h&gt;\r\n\r\nconst int CS_Pin = 4;\r\n\/\/                 PC0 PC1 PC2 PC3 PC4 PD5 PD6 PD7\r\nconst byte ad[8] = {A0, A1, A2, A3, A4,  5,  6,  7 }; \/\/ connect to DA0,1,...,7\r\nconst int pinBC1 = 3;\r\nconst int pinBDIR = 2;\r\nconst byte freqOutputPin = 9;   \/\/ OCR1A output pin for ATmega328, 2MHz output frequency for AY\/YM chip\r\n\r\n\r\n\/\/Port at which pins BC1\/BDIR is\r\n#define __BCPORT__ PORTD\r\n#define __BC1__ 3  \/\/ PORT PIN (PD3)\r\n#define __BDIR__ 2 \/\/ PORT PIN (PD2)\r\n\r\nvoid initFrequencyGenerator()\r\n{ \/\/ Set Timer 1 CTC mode OCR1A toggles on compare match\r\n    TCCR1A = 0x40;\r\n    TCCR1B = 0x09; \/\/ prescaller\r\n    \/\/ This value determines the output frequency: 0 - 16MHz, 1 - 8MHz, 2 - 4MHz, 3 - 2MHz, 4 - 1MHz\r\n    OCR1A = 3;\r\n}\r\n\r\n\r\nFile dataFile;\r\nFile entry,root;\r\n\r\nvoid setup()\r\n{\r\n  \/\/init pins\r\n  for(byte i=0; i &lt; 8; i++) pinMode(ad[i], OUTPUT);\r\n\r\n  pinMode(CS_Pin, OUTPUT);\r\n\r\n  pinMode(pinBC1, OUTPUT);\r\n  pinMode(pinBDIR, OUTPUT);\r\n\r\n  \/\/inactive mode\r\n  digitalWrite(pinBC1, LOW);\r\n  digitalWrite(pinBDIR, LOW);\r\n\r\n  Serial.begin(57600);\r\n\r\n  \/\/ see if the card is present and can be initialized:\r\n  if (!SD.begin(CS_Pin))\r\n  {\r\n    Serial.println(\"Card failed, or not present\");\r\n    return;\r\n  }\r\n  Serial.println(\"card initialized.\");\r\n\r\n  root = SD.open(\"\/\",FILE_READ);\r\n  \r\n  initFrequencyGenerator();\r\n  pinMode(freqOutputPin, OUTPUT);\r\n}\r\n\r\n\r\n\r\nvoid send_data(byte address, byte data) {\r\n\/\/ WRITE REGISTER NUMBER\r\n  \/\/write address to DA0-DA7 pins\r\n  PORTC |= address &amp; 0x1F; \/\/ DA0-DA4\r\n  PORTD |= address &amp; 0xE0; \/\/ DA5-DA7\r\n  \/\/validate addess\r\n  \/\/set BC1+BDIR bits, latch address mode\r\n  __BCPORT__ |= (1 &lt;&lt; __BDIR__) + (1 &lt;&lt; __BC1__);\r\n  asm(\"nop\\nnop\\nnop\\nnop\\nnop\\nnop\\nnop\\nnop\\nnop\"); \/\/set+hold address delay 558ns (400+100 min)\r\n  \/\/clear BC1+BDIR bits, inactive mode\r\n  __BCPORT__ &amp;= ~((1 &lt;&lt; __BDIR__) + (1 &lt;&lt; __BC1__));\r\n  \/\/ reset pins to tristate mode\r\n  PORTC &amp;= ~(address &amp; 0x1F);\r\n  PORTD &amp;= ~(address &amp; 0xE0);\r\n\r\n\/\/ WRITE REGISTER DATA\r\n  \/\/write data to pins\r\n  PORTC |= data &amp; 0x1F;\r\n  PORTD |= data &amp; 0xE0;\r\n  \/\/validate data\r\n  \/\/set BDIR bit, write to reg mode\r\n  __BCPORT__ |= ( 1 &lt;&lt; __BDIR__); \r\n  asm(\"nop\\nnop\\nnop\\nnop\\nnop\"); \/\/310ns delay (250min-500max) nop=62ns on 16MHz\r\n  \/\/clear BDIR bit, inactive mode\r\n  __BCPORT__ &amp;= ~( 1 &lt;&lt; __BDIR__); \r\n  \/\/ reset pins to tristate mode\r\n  PORTC &amp;= ~(data &amp; 0x1F);\r\n  PORTD &amp;= ~(data &amp; 0xE0);\r\n}\r\n\r\n\r\nbyte buf[128];\r\nbyte buf2[14];\r\nunsigned long t;\r\n\r\nvoid play_yrg()\r\n{\r\n   while(dataFile.available())\r\n   {\r\n     \/\/ read 16 x16 regs\r\n     byte bframes = dataFile.read(buf,128)\/16;\r\n\r\n     for (byte frame = 0; frame &lt; bframes; frame++)\r\n     {\r\n       \/\/ send diff registers from current frame\r\n       for (byte reg = 0; reg &lt; 14; reg++)\r\n       {\r\n           if (reg == 13 &amp;&amp; buf[frame*16+reg]==255) break;\r\n           if(reg == 13 || buf2[reg] != buf[frame*16+reg]) send_data(reg, buf[frame*16+reg]);\r\n       }\r\n       memcpy(buf2,&amp;buf[frame*16],14);\r\n       \/\/delay(20);\r\n       while(millis() - t < 20); \r\n       t = millis();\r\n     }\r\n   }\r\n}\r\n\r\nvoid play_rsf()\r\n{\r\n   \/\/unsigned long frames, loopframe, offset;\r\n   word freq, offset;\r\n   byte val, zeroes, ptr = 0, count, mask2, mask1, delay_time, skip;\r\n   \r\n   if( dataFile.read(buf,4) &lt;= 0 ) return; \/\/ short file\r\n\r\n   if(buf[0] != 'R' || buf[1] != 'S' || buf[2] != 'F') return; \/\/not RSF\r\n   \r\n   switch(buf[3])\r\n  { \/\/ reading RSF HEADER v3 only supported!\r\n     case 3: \/\/ RSF ver.3\r\n           if( dataFile.read(buf,14) == 0 ) return; \/\/ short file\r\n           memcpy(&#038;freq,&#038;buf[0],sizeof(word));\r\n           memcpy(&#038;offset,&#038;buf[2],sizeof(word));\r\n           \/\/memcpy(&#038;frames,&#038;buf[4],sizeof(unsigned long));\r\n           \/\/memcpy(&#038;loopframe,&#038;buf[8],sizeof(unsigned long));\r\n           break;\r\n     default:\r\n           return;\r\n   }\r\n\r\n   if( freq &gt; 1000 ) return; \/\/ frequency is too fast\r\n   \r\n   delay_time = 1000 \/ freq;\r\n  \r\n   \/\/ skip text info\r\n   dataFile.seek(offset);\r\n   \r\n   \/\/ play song data\r\n   if( (count = dataFile.read(buf,128)) &lt;= 0 ) return;\r\n\r\n   for(;;) {   \r\n         if(ptr &gt; count \/ 2)\r\n         { \/\/ half buffer is already played move it and load more\r\n           byte msize = count - ptr;\r\n           memmove(buf,&#038;buf[ptr], msize);\r\n           if( (count = dataFile.read(&#038;buf[msize],ptr)) == 0 ) return;\r\n           count += msize;\r\n           ptr = 0;\r\n         }\r\n         skip = 1;\r\n         val = buf[ptr++];\r\n       \r\n         switch(val)\r\n         {\r\n           case 255:\r\n               break;\r\n           case 254:\r\n               skip = buf[ptr++];\r\n               if(ptr >= count) return;\r\n               break;\r\n           default:\r\n               mask2 = val;\r\n               mask1 = buf[ptr++];\r\n               byte reg = 0;\r\n               while( mask1 != 0)\r\n               {\r\n                   if(mask1 & 1) send_data(reg,buf[ptr++]);\r\n                   mask1 &gt;&gt;= 1;\r\n                   reg++;\r\n               }\r\n               reg = 8;\r\n               while( mask2 != 0)\r\n               {\r\n                   if(mask2 & 1) send_data(reg,buf[ptr++]);\r\n                   mask2 &gt;&gt;= 1;\r\n                   reg++;\r\n               }\r\n         }             \r\n\r\n         \/\/delay(delay_time);\r\n         while(millis() - t &lt; delay_time * skip);\r\n         t = millis();\r\n   }\r\n}\r\n\r\nvoid loop()\r\n{\r\n byte file_type;\r\n  \/\/ reset AY\r\n for(int i=0;i&lt;14;i++) send_data(i, 0);\r\n memset(buf2,0,14);\r\n\r\n for(;;) { \/\/ find file\r\n    file_type = 0;\r\n    if(entry) entry.close();\r\n    entry = root.openNextFile();\r\n    if(!entry) { \/\/ end of files on SD\r\n       root.rewindDirectory();\r\n       entry = root.openNextFile();\r\n    }\r\n    \r\n    if(entry.isDirectory()) continue;\r\n    \r\n    if(strcasestr(entry.name(),\".yrg\")) {\r\n      file_type = 1;\r\n      break;\r\n    }\r\n    if(strcasestr(entry.name(),\".rsf\")) {\r\n      file_type = 2;\r\n      break;\r\n    }\r\n }\r\n dataFile = SD.open(entry.name(),FILE_READ);\r\n Serial.print(\"File: \");\r\n Serial.println(entry.name());\r\n\r\n t = millis();\r\n \r\n switch(file_type)\r\n {\r\n    case 1:\r\n        play_yrg();\r\n        break;\r\n    case 2:\r\n        play_rsf();\r\n        break;\r\n }\r\n \r\n dataFile.close();\r\n entry.close();\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p style=\"text-align: center;\">[ad name=&#187;HTML&#187;]<\/p>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Arduino \u0441\u043a\u0435\u0442\u0447 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c YRG \u0438 RSF \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u043a\u043e\u0440\u043d\u044f SD \u043a\u0430\u0440\u0442\u044b \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c AY-3-8910\/12 YM2149F \u0447\u0438\u043f\u0435 \u0438\u043b\u0438 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0435 \u0441 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0430. \u0421\u043a\u0435\u0442\u0447 \u0442\u0430\u043a \u0436\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 2\u041c\u0413\u0446 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u0438\u043f\u0430. (\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043e 12.12.2015 \u0434\u043e RSF \u0432\u0435\u0440\u0441\u0438\u0438 3) \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435: \u041f\u0438\u043d\u044b \u043d\u0430 Arduino: A0 &#8212; DA0,\u00a0A1 &#8212; DA1,\u00a0A2 &#8212; DA2,\u00a0A3 &#8212; DA3, A4 &#8212; DA4, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"closed","template":"page-fullwidth.php","meta":{"footnotes":""},"class_list":["post-1818","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/pages\/1818","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/comments?post=1818"}],"version-history":[{"count":0,"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/pages\/1818\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/media?parent=1818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}