// Matthew Ito, Jsoon Kim // Generates DDS signal, as well as gathering data from the SNES #include #include #include #include "dpcmtable.h" #define maxkeys 12 #define countMS 62 //ticks/mSec #define t1 625 //10 ms #define t2 8 // division for speech generation on PWM #define begin { #define end } //accumulator 1 unsigned long accumulator1 @0x2f0; unsigned char highbyte1 @0x2f3; //accumulator 2 unsigned long accumulator2 @0x2f4; unsigned char highbyte2 @0x2f7; //incrementers unsigned long increment1; unsigned long increment2; unsigned int outI, tableI; //indexes char cycle ; //decode phase counter char out, lastout; //output values char p1, p2, p3, p4 ; //hold 4 differentials char packed ; //byte containing 4 2-bit values int TableSize; //DTMF tone select unsigned char DTMF_select; //DPCM sound select unsigned char DPCM_select; //DTMF/DPCM output select, 1=DTMF, 0=DPCM unsigned char DTMForDPCM; //SNES counter variable and buffer unsigned int snes_buffer, snes_counter; //last sound command input unsigned char lastSoundInput; //counter variable int i; int time1; //task1 timer int time2; //voice timer - does virtual offset of 8 //sine table char sineTable[256] @0x300; //need loc to avoid glitch //reconstruction PCMvalues flash char PCMvalue[4] = {-20, -4, 4, 20}; //init function void initialize(void); //DPCM sound control void DPCM(void); //DTMF tone control void DTMF(void); //increments given for the various frequencies //1477 hz = 60CBF2B //1336 hz = 578E5C5 //1209 hz = 4F3BA77 //941 hz = 3DAB5C4 //852 hz = 37D6302 //770 hz = 327674D //697 hz = 2DADB83 flash unsigned long inctbl[7] = {0x060CBF2B, 0x0578E5C5, 0x04F3BA77, 0x03DAB5C4, 0x037D6302, 0x0327674D, 0x02DADB83}; //read SNES controller void getSNES(void); interrupt [TIM0_OVF] void sgen(void) begin //decrement virtual timer if(time1 > 0) time1--; if (DTMForDPCM) begin //the DDS code and scaling accumulator1 = accumulator1 + increment1; accumulator2 = accumulator2 + increment2; OCR0 = 128 + sineTable[highbyte1] + sineTable[highbyte2]; end else if(--time2==0) begin //reportVdec(tableI); time2=8; cycle = outI%4; if (cycle==0) //unpack next byte begin packed = dpcmtable[tableI]; p1 = (packed & 192)>>6; p2 = (packed & 48)>>4; p3 = (packed & 12)>>2; p4 = (packed & 3); tableI++; //compute the output and send to PWM out = lastout + PCMvalue[p1] - lastout>>4 ; end else if (cycle==1) out = lastout + PCMvalue[p2] - lastout>>4 ; else if (cycle==2) out = lastout + PCMvalue[p3] - lastout>>4 ; else if (cycle==3) out = lastout + PCMvalue[p4] - lastout>>4 ; //update outputs OCR0 = out; lastout = out; outI++; if (tableI==TableSize) begin //set to DTMF on constant signal increment1 = 0; increment2 = 0; DTMForDPCM = 1; end end end void main(void) { //trigger timer0 interrupt on overflow TIMSK = 0b00000001; //B.3 : OC0 sound signal : output //B.4 : SNES clk : output //B.5 : SNES latch : output //B.6 : SNES data : input DDRB = 0b00111000; //activate PWM increment1 = 0x00000000; accumulator1 = 0; increment2 = 0x00000000; accumulator2 = 0; //setup timer0, OC0 interrupt TCNT0 = 0; OCR0 = 0; TCCR0 = 0b01101001; //init sound gen variables lastout = 128; time2 = t2; //init the sine table for (i=0; i<256; i++) begin sineTable[i] = (char)(63.0 * sin(6.283*((float)i)/256.0)); end //output snesbuffer, input sound control //A.7 = N (128) //A.6 = S (64) //A.5 = W (32) //A.4 = E (16) //A.3 = A (8) //A.2 = X (4) //A.1 = sound select //A.0 = sound select DDRA = 0b11111100; #asm("sei"); //enable interrupts while(1) begin if(time1==0) begin time1 = t1; getSNES(); //load buffer onto portA PORTA = snes_buffer; //if sound input is not the same as last input start new sound if(lastSoundInput != (PINA.1<<1)+PINA.0) begin lastSoundInput = (PINA.1<<1)+PINA.0; DPCM_select = lastSoundInput; DPCM(); end end end end //read SNES controller void getSNES(void) begin snes_counter = 0; while(snes_counter < 24) begin //delay #asm nop nop nop nop #endasm snes_counter++; //process latch if (snes_counter==1) PORTB.5 = 1; //latch high else if (snes_counter==2) begin snes_buffer = ~PINB.6; //read first button PORTB.5 = 0; //latch low end else begin if(snes_counter%2) //pulse clk line PORTB.4 = 1; else begin snes_buffer = (snes_buffer<<1)|~PINB.6; //read PORTB.4 = 0; end end end end //DPCM sound generation //dictates the initial start point of the array //of values, as well as the end point //then generates DDS void DPCM(void) begin switch(DPCM_select) begin case 1: //incoming TableSize = 1619; outI = 0; tableI = 0; DTMForDPCM = 0; break; case 2: //target neutralized TableSize = 4279; outI = 0; tableI = 1620; DTMForDPCM = 0; break; case 3: //force silence //set to DDS on constant signal increment1 = 0; increment2 = 0; DTMForDPCM = 1; break; end end //DTMF tone generation --not used, but available for use to generate //DTMF tones, if desired void DTMF(void) begin switch(DTMF_select) begin case 1: //represents 1 increment1 = inctbl[2]; increment2 = inctbl[6]; break; case 2: //represents 2 increment1 = inctbl[1]; increment2 = inctbl[6]; break; case 3: //represents 3 increment1 = inctbl[0]; increment2 = inctbl[6]; break; case 4: //represents 4 increment1 = inctbl[2]; increment2 = inctbl[5]; break; case 5: //represents 5 increment1 = inctbl[1]; increment2 = inctbl[5]; break; case 6: //represents 6 increment1 = inctbl[0]; increment2 = inctbl[5]; break; case 7: //represents 7 increment1 = inctbl[2]; increment2 = inctbl[4]; break; case 8: //represents 8 increment1 = inctbl[1]; increment2 = inctbl[4]; break; case 9: //represents 9 increment1 = inctbl[0]; increment2 = inctbl[4]; break; case 0: //represents 0 increment1 = inctbl[1]; increment2 = inctbl[3]; break; default: increment1 = 0; increment2 = 0; break; end end