// 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 #include // for sine #include #include #include #include #define begin { #define end } //Initiate the task subroutine - used to calculate x, y and z positions #define t1 15 volatile unsigned char time1;//timeout counters void task1(void); //TOUCHPAD INITIALIZATION //Routines to send and receive touchpad information void initialize(void); //all the usual mcu stuff void send(unsigned char); //define the sending routine volatile unsigned char read(void); //define the reading routine volatile unsigned char command; void init_receive(); //initialize the receive ISR for streaming mode void disable_receive(); //disable the ISR for streaming mode volatile unsigned char status, junk; //used to store and send data bytes to/from touchpad volatile char ack; //Define macros to set and clear the data and clock pins #define READ(U, N) ((U) >> (N) & 1u) #define SET(U, N) ((void)((U) |= 1u << (N))) #define CLR(U, N) ((void)((U) &= ~(1u << (N)))) #define FLIP(U, N) ((void)((U) ^= 1u << (N))) //Variables used to store and retrieve data volatile unsigned char data_received; //data received flag indicator volatile unsigned char parity_err[6] = {0,0,0,0,0,0}; //used to check the bytes being tranmitted volatile unsigned char start_err[6] = {0,0,0,0,0,0}; volatile unsigned char stop_err[6] = {0,0,0,0,0,0}; volatile unsigned char i_read = 0; //index of the current byte being read volatile unsigned char bits[6][11]; //storage space for packets //CALCULATION INITIALIZATION //Detect touchpad change modes or play new sound states using these flags unsigned char countzeros = 0; unsigned char newpress = 1; unsigned int x_sine_saved = 0, y_sine_saved = 0, sine_count = 0; //special flags for sine mode unsigned char sine_stop = 0; unsigned int x_mode = 3, y_mode = 0, saved_y = 0; // mode select variables unsigned char prev_x_mode, harmonic_y = 0; signed int x_note = 0, y_note = 0; //store x and y data to transmit int curX, preX, curY, preY, curZ, preZ; int gesture_count; char mode_command = 0; int xGesture = 0, yGesture = 0; //Initialize Mode Selection State Machine #define NoGesture 0 #define GestureStandby 1 #define GestureDetected 2 #define MaybeNoGesture 3 unsigned char Gesture = NoGesture; //TRANSMIT INITIALIZATION //SPI communication variables unsigned char receive = 0; unsigned char data1 = 0b00000000, data2 = 0b00000001; // ************************************************************************* // Initialize the ISR - ready to receive data from the touchpad void init_receive() { i_read = 0; // Reset byte counter data_received = 0; // Reset data flag PCMSK3 = 4; PCICR = 0x08; // PCINT interrupt enable } // ************************************************************************* // Disable the ISR - not ready to receive data: currently processing data void disable_receive() { PCMSK3 = 0; PCICR = 0; // PCINT interrupt disable } // ************************************************************************************ // This function sends command to the mouse void send(unsigned char command) { char parity; //3 byte i, ack, p = 1; i_read = 0; SET(PORTD, 4); //4 set_CLOCK(0); /* Begin inhibit, if necessary. */ parity = (command & 0x01) ^ //Calculate odd parity ((command & 0x02) >> 1) ^ ((command & 0x04) >> 2) ^ ((command & 0x08) >> 3) ^ ((command & 0x10) >> 4) ^ ((command & 0x20) >> 5) ^ ((command & 0x40) >> 6) ^ ((command & 0x80) >> 7); _delay_us(100); //5 wait_us(100); /* Inhibit for about 100us. */ SET(PORTD, 5); //6 set_DATA(0); /* Hold data pin low while still inhibited. */ CLR(PORTD, 4); //7 set_CLOCK(1); /* Establish ¡§request-to-send¡¨ state. */ while(!(PIND & 0x04)); // wait for clock for( i = 0; i<8; i++){ //8 for (i = 0; i < 8; i++) { while(PIND & 0x04){} //9 wait_CLOCK(0); /* Wait for clock pulse. */ if (!(command & 0x01)) SET(PORTD, 5); //10 set_DATA(value & 0x01); /* Output i¡¦th data bit. */ else CLR(PORTD, 5); while(!(PIND & 0x04)){} //12 wait_CLOCK(1); /* Wait for end of clock pulse. */ command = command >> 1; //13 value = value >> 1; /* Shift right to get next bit. */ } //14 } while(PIND & 0x04){} //15 wait_CLOCK(0); /* Parity bit clock. */ if (parity) //16 set_DATA(p & 0x01); /* Output parity bit. */ SET(PORTD, 5); else CLR(PORTD, 5); while(!(PIND & 0x04)){} //17 wait_CLOCK(1); /* End of parity bit clock. */ while(PIND & 0x04){} //18 wait_CLOCK(0); /* Stop bit clock. */ CLR(PORTD, 5); //19 set_DATA(1); /* Stop bit must be 1. */ while(!(PIND & 0x04)){} //20 wait_CLOCK(1); /* End of stop bit clock. */ while(PIND & 0x04){} //21 wait_CLOCK(0); /* Line control bit clock. */ if (PIND & 0x08); //22 if (read_DATA() == 1) while(!(PIND & 0x04)){} //24 wait_CLOCK(1); /* End of line control bit clock. */ ack = read(); //25 ack = PS2_get(); /* Receive acknowledge byte from device. */ //26 if (ack != 0xFA) //27 PS2_error(); /* Probably got an FE or FC error code. */ } // ************************************************************************* // This function reads a byte of data from the mouse and returns the byte : REMOTE MODE volatile unsigned char read(void) begin unsigned char i, t, p = 0; value = 0; CLR(PORTD, 4); //4 set_CLOCK(1); /* Release inhibit, if necessary. */ while(PIND & 0x04){} //5 wait_CLOCK(0); /* Wait for start bit clock. */ if (PIND & 0x08) begin start_err[i_read] = 1; bits[i_read][0] = 1; end else bits[i_read][0] = 0; while(!(PIND & 0x04)){} //6 wait_CLOCK(1); /* End of start bit clock. */ for (i = 0; i< 8; i++){ //7 for (i = 0; i < 8; i++) { while(PIND & 0x04){} //8 wait_CLOCK(0); /* Wait for clock pulse. */ if (PIND & 0x08) t = 1; else t = 0; //9 bit = read_DATA(); /* Read data bit from pin. */ bits[i_read][i+1] = t; value = value + (t<0) --time1; end // ********************************************************** //Entry point and task scheduler loop int main(void) begin initialize(); //initialize the program and the touchpad //main task scheduler loop while(1) begin if (time1==0){ time1=t1; task1();} end end // ********************************************************** // The task responsible for calculations of data packets received from the touchpad // and for transmitting new data values to the sound generation MCU void task1(void) begin // Calculate x, y and z values based on the data packet received from the touchpad if (data_received == 1) begin preX = x; //store old values preY = y; preZ = z; x = (bits[1][1] << 8) + (bits[1][2] << 9) + (bits[1][3] << 10) + (bits[1][4] << 11) + (bits[3][5] << 12) + (bits[4][1] << 0) + (bits[4][2] << 1) + (bits[4][3] << 2) + (bits[4][4] << 3) + (bits[4][5] << 4) + (bits[4][6] << 5) + (bits[4][7] << 6) + (bits[4][8] << 7); y = (bits[1][5] << 8) + (bits[1][6] << 9) + (bits[1][7] << 10) + (bits[1][8] << 11) + (bits[3][6] << 12) + (bits[5][1] << 0) + (bits[5][2] << 1) + (bits[5][3] << 2) + (bits[5][4] << 3) + (bits[5][5] << 4) + (bits[5][6] << 5) + (bits[5][7] << 6) + (bits[5][8] << 7); z = (bits[2][1] << 0) + (bits[2][2] << 1) + (bits[2][3] << 2) + (bits[2][4] << 3) + (bits[2][5] << 4) + (bits[2][6] << 5) + (bits[2][7] << 6) + (bits[2][8] << 7); curX = x; //store new values curY = y; curZ = z; // STATE MACHINE FOR DETECTING MODE CHANGE switch(Gesture) begin // No Gesture: idle mode, waiting for a prolonged touch from the user case NoGesture: if (x > 3000 && x < 4000 && y > 1500 && y < 3500 && z > 30) // Make sure the user is enabling range we are looking at begin if(gesture_count < 30) gesture_count++; else begin Gesture = GestureStandby; end end else //not in standby mode begin gesture_count = 0; PORTC = PORTC & 0b11111110; //update LEDs mode_command = 0; end break; // Wait for a motion in either x or y, if the change in x or why is large enough, change the mode // in the relevent direction case GestureStandby: if (z > 20) begin PORTC = PORTC | 0b00000001; //update LEDs // Find direction of motion if (curX - preX > 400) begin Gesture = GestureDetected; xGesture = 1; end else if (preX - curX > 400) begin Gesture = GestureDetected; xGesture = -1; end else if (x < 3000 || x > 4000) //outside of range begin Gesture = NoGesture; gesture_count = 0; end if (curY - preY > 400) begin Gesture = GestureDetected; yGesture = 1; end else if (preY - curY > 400) begin Gesture = GestureDetected; yGesture = -1; end else if (y < 1500 || y > 3500) begin Gesture = NoGesture; gesture_count = 0; end end else Gesture = NoGesture; break; // Once a gesture has been detected, update the x and y modes accordingly and debounce Gesture case GestureDetected: if (x_mode == 3) harmonic_y = y_mode; prev_x_mode = x_mode; if (x_mode == 0 && xGesture == -1) x_mode = 3; else if (x_mode == 3 && xGesture == 1) x_mode = 0; else x_mode = x_mode + xGesture; if (y_mode == 0 && yGesture == -1) y_mode = 2; else if (y_mode == 2 && yGesture == 1) y_mode = 0; else y_mode = y_mode + yGesture; if (x_mode == 0 || x_mode == 1 || x_mode == 2) y_mode = 0; else if (prev_x_mode != 3 && x_mode == 3) y_mode = harmonic_y; PORTC = (PORTC & 0b00000001) | ((2< 100)) && (z > 10))) begin newpress = 0; mode_command = 0; sine_press = 0; // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY DATA TO TRANSMIT // Packet Format: // data1: mmmyyyy0 // data2: xxxxxxx1 // key: // m - mode // y - y_value // x - x_value // ranges x = [1350, 5800], y = [1250, 4500] // Calculate x and y values and create data packets for each mode if (x_mode == 0) //-----------------------continous mode----- x: [0, 40] and y: [1, 15] begin y_mode = 0; if (sine_count == 5) begin x_note = (x - 1350)/111; y_note = (y - 1250)/216; if (x_note < 0) x_note = 0; else if (x_note > 39) x_note = 39; if (y_note < 1) y_note = 1; else if (y_note > 15) y_note = 15; x_sine_saved = x_note; y_sine_saved = y_note; end else begin sine_count++; x_note = x_sine_saved; y_note = y_sine_saved; end if (sine_stop == 1) begin y_note = 0; sine_stop = 0; end data1 = (((x_mode << 5) + (y_note << 1)) & 0b11111110); //make sure to send 0 in bit 1 od data1 data2 = ((x_note << 1) | 0b00000001); //and 1 in bit 1 of data2 to sync with sound MCU end else if (x_mode == 1) //--------------------chords mode---- x: [0, 7] and y: [0, 3] begin y_mode = 0; x_note = (x - 1350)/556; y_note = (y - 1250)/812; if (x_note < 0) x_note = 0; else if (x_note > 7) x_note = 7; if (y_note < 0) y_note = 0; else if (y_note > 3) y_note = 3; data1 = (((x_mode << 5) + (y_note << 1)) & 0b11111110); data2 = ((x_note << 1) | 0b00000001); end else if (x_mode == 2) //--------------------standard note mode------ x: [0, 6] and y: [0, 3] begin x_note = (x - 1350)/636; y_note = (y - 1250)/812; if (x_note < 0) x_note = 0; else if (x_note > 6) x_note = 6; if (y_note < 0) y_note = 0; else if (y_note > 3) y_note = 3; y_mode = 0; data1 = (((x_mode << 5) + (y_note << 1)) & 0b11111110); data2 = ((x_note << 1) | 0b00000001); // add one more C7 at the very end - to make 4 complete octaves + a fifth C if (x > 5500 && y_note == 3) data2 = data2 + 2; //change the x value by 1 end else if (x_mode == 3) //--------------------harmonics---- x: [0, 7] begin data1 = (((x_mode+1) + y_mode)<<5); x_note = (x - 1350)/556; if (x_note < 0) x_note = 0; else if (x_note > 7) x_note = 7; data1 = ((((x_mode+1) + y_mode)<<5) & 0b11111110); data2 = ((x_note << 1) | 0b00000001); if (y_mode == 0); //------------------ y disabled - don't change data else if (y_mode == 1) //------------------ y decay [0,5] begin y_note = (y - 1250)/542; if (y_note < 0) y_note = 0; // y_note: decay time else if (y_note > 5) y_note = 5; data1 = data1 + (y_note << 1); end else //------------------ y harmonics [0,7] begin y_note = (y - 1250)/406; if (y_note < 0) y_note = 0; else if (y_note > 7) y_note = 7; data1 = data1 + (y_note << 1); end end // ********** SEND DATA *********** Include error checking to make sure the slave receives // the correct bytes do begin do begin //data &= 0b11111110; SPDR = data1; //wait until SPIF is set (SPI done) while (!(SPSR & (1<