// Mega644 version // Kalina Jordanova (kvj2) and Vic Jang (wj67) // Synaptics touchpad control file - interfacing with a Synaptics TM41PDD234 touchpad // April 29, 2009 // ECE 4760 Final Project #include #include #include // for sine #include #include #include #include //timeout values for each task #define t1 30 #define begin { #define end } void task1(void); void initialize(void); // MCU and sound initialization volatile unsigned char time1, time2; // timeout counters unsigned char wave; // generated string sound to be output unsigned char mode; // the sound generation mode we are in unsigned int sound; // generated sine wave to be output unsigned char wave_gen = 0; // the returned value for generateWave // for sine table generation unsigned int i; unsigned int k = 0; unsigned char buffer[2], check[2]; // array used to store message from master signed char sineTable1[128] ; // sine table unsigned char generateWave(unsigned char, unsigned char); // function to generate sound unsigned char standardNoteHarmonics[29] = {170,151,135,127,113,101,90, 85,76,67,64,57,51,90, 85,76,67,64,57,51,45, 42,38,34,32,28,25,22,21}; // pre-generated length of noise for standard notes unsigned char ocr[2] = {90,180}; // OCR0A values // harmonic note length of noise unsigned char harmonics[8] = {85,76,67,64,57,51,45,42}; // chords examples (For Ellies) unsigned char chords[24] = { 67, 45, 34, 71, 45, 36, 67, 45, 34, 71, 45, 36, 90, 57, 45, 76, 60, 38, 85, 57, 85, 101,42, 34, }; // previous y msg from master unsigned char pre_y = 0; unsigned char saved_y = 0; // LED for debugging unsigned char LED = 0; // 3 noise used to excite string unsigned long string1[256]; unsigned long string2[256]; unsigned long string3[256]; // variables used for decay mode unsigned int decay_multiplier; unsigned int decay_length[6] = {998,1006,1011,1015,1019,1023}; // ****************************************************************************************** // pre-generated noise prog_uint16_t white_noise[256] = { 4530, 22960, 20848, 30654, 24696, 22888, 22943, 5919, 29909, 19549, 29670, 25150, 20292, 23233, 29465, 32414, 18503, 22841, 6338, 15914, 5113, 7095, 8515, 15645, 30937, 28896, 26591, 16832, 8456, 31867, 24755, 10750, 4565, 13821, 12103, 5457, 798, 7908, 28741, 28898, 14010, 15855, 31427, 18721, 6687, 14068, 5799, 28634, 10920, 9509, 27966, 23321, 19531, 2421, 16775, 26497, 3312, 9163, 17604, 5993, 3399, 2075, 17026, 20573, 17970, 19535, 1977, 10939, 6932, 23463, 3254, 15468, 23160, 16356, 29187, 3026, 14204, 31868, 13967, 3488, 26445, 4777, 18155, 10675, 3504, 28617, 10923, 28235, 3357, 16065, 14311, 28077, 18985, 3344, 22402, 1483, 6772, 10861, 1908, 11612, 14784, 12275, 19595, 21971, 31433, 2540, 19807, 16475, 12408, 266, 408, 11030, 27016, 5564, 8283, 10868, 1407, 9954, 14421, 8670, 32361, 24634, 14427, 31086, 6941, 3972, 12025, 31698, 18318, 24030, 16473, 31086, 15809, 19084, 24801, 938, 32644, 32374, 12905, 32297, 13103, 16535, 528, 6240, 28251, 19826, 13317, 12517, 858, 14603, 9381, 8853, 19568, 32230, 26357, 7080, 30684, 5879, 746, 16971, 25501, 23515, 4264, 28286, 23759, 10660, 29762, 13868, 11279, 32150, 9448, 29211, 30518, 8900, 17389, 12837, 35, 13466, 23031, 4692, 3529, 8390, 466, 22857, 32654, 12364, 17647, 30271, 4042, 3413, 11653, 20004, 24534, 13703, 28237, 5957, 19002, 9955, 25842, 10247, 15642, 8777, 5076, 13773, 25406, 24863, 11027, 26046, 14469, 25004, 1646, 23729, 24961, 9922, 23605, 19072, 6605, 32349, 20283, 24776, 24232, 31733, 17365, 18790, 24961, 12230, 6672, 3389, 7578, 5641, 17017, 21002, 25055, 10518, 18226, 159, 16049, 2227, 10307, 22175, 28468, 24271, 3316, 29795, 29897, 18624, 27660, 8252, 17990, 28799, 9081, 5454, 30645, 32120, 9618, 11188 }; // variable for testing unsigned char temp; // counter for Karplus-Strong algorithm unsigned int counter1, counter2; unsigned int counter3; // length of noise for 3 notes unsigned int note_period1; // length of white noise (used) unsigned int note_period2; // length of white noise (used) unsigned int note_period3; // length of white noise (used) unsigned int noise_length; // message from Master, assigned to note_period unsigned int sample_period; // message from Master, assigned to OCR0A volatile unsigned char PushFlag = 0; // variable for start of sound // variable for SPI communication volatile unsigned char receive, transmit; volatile unsigned char data1 = 0b01000000; volatile unsigned char data2 = 0b00000001; volatile unsigned int ramp_count = 0; volatile signed char ramping = -1; //***************************************************************************************** //timer 0 compare ISR for generating sound ISR (TIMER0_COMPA_vect) begin wave = generateWave(data1, data2); //generate wave based on x-direction information PORTC = wave; end // ***************************************************************************************** //timer 2 compare match ISR for scheduling tasks ISR (TIMER2_COMPA_vect) begin if (time1>0) --time1; end // ***************************************************************************************** //ISR to receive data from touchpad ISR (SPI_STC_vect) begin if (mode != 0) TIMSK0 = 0; unsigned char spdr; // ********* Receive data ***************** // buffer[k] = SPDR; check[k] = buffer[k] & 0x01; spdr = 0x01; data1 = buffer[0]; // ISR only get one byte at a time data2 = buffer[1]; // so every time master sends msg k++; // will enter ISR twice and store msg in array if (k == 2) begin k = 0; if (check[0] == 0 && check[1] == 1) //check if msg is correct (by checking LSB) begin PushFlag = 1; end end else begin spdr = 0x02; end // send msg back (according to iteration number, for master to do error checking SPDR = spdr; // output to STK500 LED for debugging PORTA = ~buffer[1]; end // ********************************************************************************************* //Task subroutines //Task 1 void task1(void) begin // if received a msg from master, initialize noise and start playing sound (turn on ISR) if (PushFlag == 1) begin if((data1 & 0b11100000) != 0) //check for mode 0 begin PushFlag = 0; TIMSK0 = 0; for (int i = 0; i < 256; i++) begin string1[i] = white_noise[i]; string2[i] = white_noise[i]; string3[i] = white_noise[i]; end counter1 = 0; counter2 = 0; counter3 = 0; end TIMSK0 = 2; end end // ***************************************************************************************** unsigned char generateWave(unsigned char data1, unsigned char data2) begin unsigned int wave_gen, wave_mode, wave_data, x_data, y_data=0; unsigned long sine_gen; // ******************** UPDATE WAVE ********************** // // UPDATE MODES: // 0: Continuous sine wave: x data between 0 and 40, y data between 1-15 - change OCR0A and sample rate accordingly // 1: Chords: Data between 0 and 7 - use the chords table // 2: Standard: Data between 0 and 28 // 4: Harmonics, y disabled: Data between 0 and 7 - use harmonics table // 5: Harmonics, y decay: Data between 0 and 7 for harmonics table // 6 : Harmonics, harmonics: x between 0 and 7 and y between 0 and 7 // NOTE: need to always reassign OCR0a in case we were previously in the sinewave mode //get the current mode: wave_mode = (data1 >> 5); mode = wave_mode; if (wave_mode == 0) begin pre_y = y_data; // *** Continuous sine wave mode ************************************************************** x_data = (data2 >> 1); // interpret x data y_data = ((data1 & 0b00011110) >> 1); // interpret y data TCCR0B = 0b00000010; // clock prescalar to 8 for plucked string OCR0A = 90 - x_data; sine_gen = 128 + sineTable1[sound]; // if user stop touching the touchpad, start to ramp down (use the last y_data available when ramping down) if (y_data != 0) {sound = sound + y_data; saved_y = y_data;} else sound = sound + saved_y; // ramping up and ramping down algorithm if ((y_data == 0) && (ramping != -1)) begin ramping = -1; ramp_count = 511; end else if (((y_data != pre_y) && (pre_y == 0)) && (ramping != 1)) begin ramping = 1; ramp_count = 1; end // ramping if ((0 < ramp_count) && (ramp_count < 512)) ramp_count = ramp_count + ramping; // use sine_gen instead of wave_gen here because chords mode might be affected sine_gen = ((sine_gen * ramp_count) >> 9); if(sound >= 128) sound = sound - 128; return sine_gen; end else if (wave_mode == 1) begin // *** Chords *************************************************************************************** x_data = (data2 >> 1); // interpret y data y_data = ((data1 & 0b00011110) >> 1); // interpret x data OCR0A = 90; TCCR0B = 0b00000010; note_period1 = chords[x_data*3 + 0]; note_period2 = chords[x_data*3 + 1]; note_period3 = chords[x_data*3 + 2]; // add 3 string together and use fix-point divide by 3 wave_gen = ((string1[counter1]+string2[counter2]+string3[counter3])*90) >> 16; // Karplus-Strong Algorithm Implementation // ----------------------------string sound 1.---------------------------- if(counter1 >= note_period1-1) begin string1[counter1] = ((string1[counter1] + string1[counter1+1-note_period1])*127)>>8; counter1 = counter1 + 1 - note_period1; end else begin string1[counter1] = ((string1[counter1] + string1[counter1+1])*127)>>8; counter1++; end // ----------------------------string sound 2---------------------------- if(counter2 >= note_period2-1) begin string2[counter2] = ((string2[counter2] + string2[counter2+1-note_period2])*127)>>8; counter2 = counter2 + 1 - note_period2; end else begin string2[counter2] = ((string2[counter2] + string2[counter2+1])*127)>>8; counter2++; end // ------------------string sound 3---------------------------- if(counter3 >= note_period3-1) begin string3[counter3] = ((string3[counter3] + string3[counter3+1-note_period3])*127)>>8; counter3 = counter3 + 1 - note_period3; end else begin string3[counter3] = ((string3[counter3] + string3[counter3+1])*127)>>8; counter3++; end end else if (wave_mode == 2 || wave_mode == 3) begin // *** Generate a single tone - standard mode **************************************************** unsigned int ocr_index; x_data = (data2 >> 1); // interpret y data y_data = ((data1 & 0b00011110) >> 1); // interpret x data wave_data = x_data + y_data*7; note_period1 = standardNoteHarmonics[wave_data]; TCCR0B = 0b00000010; // clock prescalar to 8 for plucked string //change OCR0A if necessary if ((wave_data) < 13) ocr_index = 1; else ocr_index = 0; OCR0A = ocr[ocr_index]; // wave_gen max: 255, string max: 32767 wave_gen = (string1[counter1] >> 8); // Karplus-Strong Algorithm Implementation // 1 string if(counter1 >= note_period1-1) begin string1[counter1] = ((string1[counter1] + string1[counter1+1-note_period1])*127)>>8; counter1 = counter1 + 1 - note_period1; end else begin string1[counter1] = ((string1[counter1] + string1[counter1+1])*127)>>8; counter1++; end end else if (wave_mode == 4) begin // *** Harmonics, y disabled ************************************************************* x_data = (data2 >> 1); // interpret y_data y_data = ((data1 & 0b00011110) >> 1); // interpret x_data wave_data = x_data; OCR0A = 90; TCCR0B = 0b00000010; // clock prescalar to 8 for plucked string note_period1 = harmonics[wave_data]; wave_gen = (string1[counter1] >> 8); // Karplus-Strong Algorithm Implementation // 1 string if(counter1 >= note_period1-1) begin string1[counter1] = ((string1[counter1] + string1[counter1+1-note_period1])*127)>>8; counter1 = counter1 + 1 - note_period1; end else begin string1[counter1] = ((string1[counter1] + string1[counter1+1])*127)>>8; counter1++; end end else if (wave_mode == 5) begin // *** Harmonics, with decay ************************************************************** OCR0A = 90; TCCR0B = 0b00000010; // clock prescalar to 8 for plucked string x_data = (data2 >> 1); // interpret y_data y_data = ((data1 & 0b00011110) >> 1); // interpret x_data note_period1 = harmonics[x_data]; // get decay factor decay_multiplier = decay_length[y_data]; wave_gen = (string1[counter1] >> 8); // Karplus-Strong Algorithm Implementation // 1 string if(counter1 >= note_period1-1) begin // multiplier by decay factor rather than 127 string1[counter1] = ((string1[counter1] + string1[counter1+1-note_period1])*decay_multiplier)>>11; counter1 = counter1 + 1 - note_period1; end else begin string1[counter1] = ((string1[counter1] + string1[counter1+1])*decay_multiplier)>>11; counter1++; end end else //this is if wave_mode >= 6 - indicates double harmonics begin // *** Double Harmonics *********************************************************** x_data = (data2 >> 1); // interpret y_data y_data = ((data1 & 0b00011110) >> 1); // interpret x_data // get length of noise for both notes note_period1 = harmonics[x_data]; note_period2 = harmonics[y_data]; OCR0A = 90; TCCR0B = 0b00000010; // clock prescalar to 8 for plucked string // generate sound, add 2 string together and divided by 2 wave_gen = ((string1[counter1]+string2[counter2])>>9); // Karplus-Strong Algorithm Implementation // ----------------------------string sound 1.---------------------------- if(counter1 >= note_period1-1) begin string1[counter1] = ((string1[counter1] + string1[counter1+1-note_period1])*127)>>8; counter1 = counter1 + 1 - note_period1; end else begin string1[counter1] = ((string1[counter1] + string1[counter1+1])*127)>>8; counter1++; end // ----------------------------string sound 2---------------------------- if(counter2 >= note_period2-1) begin string2[counter2] = ((string2[counter2] + string2[counter2+1-note_period2])*127)>>8; counter2 = counter2 + 1 - note_period2; end else begin string2[counter2] = ((string2[counter2] + string2[counter2+1])*127)>>8; counter2++; end end return wave_gen; end //********************************************************** //Entry point and task scheduler loop int main(void) begin initialize(); while(1) begin if (time1==0){ time1=t1; task1();} end end //********************************************************** //Set it all up void initialize(void) begin //set up i/o data direction //DDRB.4 = 0; //input chip for Master MCU //DDRB.5 = 0; //input MOSI from Master MCU //DDRB.6 = 1; //output MISO for Master MCU //DDRB.7 = 0; //input Clock DDRB = (1<