Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //////////////////////////////////////////////
- //
- // This program will interface a synaptics
- // touchpad with an arduino (ATmega368),
- // using the PS/2 protocol.
- //
- // Then uses that touchpad as a dimmer to PWM 3 LEDS on seperate channels.
- //
- // References Synaptics Touchpad Datasheet: ACF126
- // http://www.synaptics.com/sites/default/files/ACF126.pdf
- //
- // Written in pure C, wiring libraries not used.
- //
- // Written by smokkin
- //
- //////////////////////////////////////////////
- // clock pin = 8 // arduino pin connections
- // data pin = 9 // see datasheet section 3.1 for touchpad connections
- //
- // led1 pin = 3
- // led2 pin = 5
- // led3 pin = 6
- // x -> // actual detected useable ranges
- // y -> 1500 - 4500
- #include <avr/io.h>
- #include <util/delay.h>
- #include <math.h>
- #define YMIN 1500 // actual useable range, X axis not yet complete
- #define YMAX 4500
- // if defined, will compile in serial comm tools, for debugging
- //#define DEBUG
- // define our CPU clock freq, the baudrate our serial connection
- // will use, and do the required maths.
- #define F_CPU 16000000UL
- #define BAUDRATE 9600
- #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
- void timer0_init(void); // Setup timer0 to generate 2 PWM signals
- void timer2_init(void); // Setup timer2 to generate 1 PWM signal
- void touchpad_init(void); // Touchpad initialization
- void wait_CLOCK(uint8_t state); // Wait for clock state 0 or 1
- void set_CLOCK(uint8_t state); // Pull clock pin low (0) or let it float high (1)
- void set_DATA(uint8_t state); // Pull data pin low (0) or let it float high (1)
- uint8_t read_CLOCK(); // Return state of clock pin, 0 or 1
- uint8_t read_DATA(); // Return state of data pin, 0 or 1
- uint8_t PS2_get(void); // Return byte from PS2
- void PS2_send(uint8_t value); // Send byte to PS2
- void get_packet(void); // Get Synaptic absolute data stream packet
- void send_tp_arg(uint8_t arg); // Send special touchpad command
- void throw_error(char* stringptr); // Send string to serial, basically calls USART_putstring()
- // map() will scale a number, given 2 number ranges
- long map(long x, long in_min, long in_max, long out_min, long out_max);
- #ifdef DEBUG
- void USART_init(void); // Init serial connection
- unsigned char USART_receive(void); // Return byte from serial
- void USART_send( unsigned char data); // Send byte to serial
- void USART_putstring(char* stringptr); // Send string to serial
- #endif
- // Absolute Data Packet, will contain the useable info returned from the touchpad
- // See datasheet sections 2.3 and 3.6.2
- struct packetStruct {
- unsigned int x : 13; // (0-6143) Horizontal finger position, 0 = far left
- unsigned int y : 13; // (0-6143) Vertical finger position, 0 = far bottom
- unsigned int z : 8; // (0-255) Pressure or contact area, 0 = no contact
- unsigned int w : 4; // (0-15) Finger width and other state information
- unsigned int left : 1; // State of left physical button, 0 = not pressed, 1 = pressed
- unsigned int right : 1; // State of right physical button, 0 = not pressed, 1 = pressed
- unsigned int gesture : 1; // Tap/drag gesture in progress, 0 = no gesture, 1 = gesture
- unsigned int finger : 1; // Finger presence, 0 = no finger, 1 = finger
- };
- struct packetStruct packet; // This will contain the actual data packet
- // Program Start
- // Will take input from the touchpad, and dim 3 LEDs using PWM, based on the Y value,
- // basically turning the touchpad into a slider/dimmer.
- //
- // All 3 LEDs are on different channels. Eventually we will divide the touchpad into
- // 3 different columns, one for each LED.
- /* commented out for DJ
- int main(void) {
- #ifdef DEBUG // If DEBUG is enabled, then setup serial connection
- USART_init();
- #endif
- timer0_init(); // Setup timer0 to generate 2 PWM signals
- timer2_init(); // Setup timer2 to generate 1 PWM signal
- touchpad_init(); // Setup touchpad
- uint8_t buf; // Temp storage for mathz
- char string[32]; // Temp storage for strings, used for debugging
- uint8_t red = 0; // Current brightness value for red LED
- uint8_t green = 0; // Current brightness value for green LED
- uint8_t blue = 0; // Current brightness value for blue LED
- packet.y = 0; // Zero out the only value we care about at the moment...
- // Main program loop
- while(1) {
- OCR0A = red; // timer0A is connected to red LED
- OCR0B = green; // timer0B is connected to green LED
- OCR2B = blue; // timer2B is connected to blue LED
- get_packet(); // Get new data packet from touchpad
- if(packet.y < YMIN) // If below threshold, set to MIN
- packet.y = YMIN;
- if(packet.y > YMAX) // If above threshold, set to MAX
- packet.y = YMAX;
- // Scale raw data down to between 0-255... for easier mathz
- buf = (uint8_t)map(packet.y, YMIN, YMAX, 0, 255);
- red = buf; // Set new brightness values for next loop
- blue = buf;
- green = buf;
- } //end while(1) main program loop
- /*
- // this is for debugging. sends raw data to serial. commented out. ignore.
- USART_putstring("ready\n");
- while(1) {
- get_packet();
- USART_putstring("X: ");
- itoa(packet.x, string, 10);
- USART_putstring(string);
- USART_putstring(" Y: ");
- itoa(packet.y, string, 10);
- USART_putstring(string);
- USART_putstring(" Z: ");
- itoa(packet.z, string, 10);
- USART_putstring(string);
- if(packet.left == 1)
- USART_putstring(" LEFT");
- if(packet.right == 1)
- USART_putstring(" RIGHT");
- USART_putstring("\n");
- }
- */
- /* for dj
- return 0; // This will never be called. You just divided by zero. Black holes n shit.
- } // end main()
- */
- // end commented out for dj, 2 lines
- // This function just calls USART_putstring()... Only used to optionally compile serial comm
- //
- void throw_error(char* stringptr) {
- #ifdef DEBUG
- USART_putstring(stringptr);
- #endif
- }
- // This will setup timer0 to generate 2 PWM signals
- //
- void timer0_init(void) {
- DDRD = ((1<<PD5)|(1<<PD6)); //Set pwm pins from timer 0 as outputs
- TCCR0A = ((1<<COM0A1)|(1<<WGM01)|(1<<WGM00)); //Enable pwm mode in pin PD6 and set the WGM bits to Fast pwm mode
- TCCR0A |= (1<<COM0B1); //Enable pwm mode in pin PD5
- TCCR0B = ((1<<CS01)|(1<<CS00)); //Set prescaler to 32
- } // end timer0_init()
- // This will setup timer2 to generate 1 PWM signal
- //
- void timer2_init(void) {
- DDRD |= (1<<PD3); //Set pwm pin OC2B from timer 2 as output
- TCCR2A = ((1<<COM2B1)|(1<<WGM21)|(1<<WGM20)); //Enable pwm mode in PD3 and set the WGM bits for fast pwm mode
- TCCR2B = ((1<<CS21)|(1<<CS20)); //Set prescaler to 32
- } // end timer2_init()
- // Setup the touchpad. Enable stream mode and absolute data packet format.
- // See datasheet section 3.6.2 figure 3-18
- //
- void touchpad_init(void) {
- uint8_t buf;
- PS2_send(0xFF); // Reset command
- if (PS2_get() != 0xAA) // Note: This may need an extra-long timeout
- throw_error("error 1, touchpad_init\n");
- if (PS2_get() != 0x00)
- throw_error("error 2, touchpad_init\n");
- send_tp_arg(0x00); // Send Identify TouchPad sequence (section 3.5.1)
- PS2_send(0xE9); // Status Request command
- buf = PS2_get(); // First status byte: TouchPad minor rev
- if (PS2_get() != 0x47) // Second status byte: 0x47 == Synaptics TouchPad
- throw_error("error, not synaptics touchpad\n");
- buf = PS2_get() & 0x0F; // Third status byte: Major rev in low 4 bits
- send_tp_arg(0x80); // Send Set Mode sequence (section 3.5.2)
- PS2_send(0xF3); // Set Sample Rate command
- PS2_send(0x14); // Sample Rate argument of 20
- PS2_send(0xF4); // Enable command
- set_CLOCK(0); // inhibit until ready to recieve
- } // end touchpad_init()
- // This will scale a number (x), from one number range to another
- //
- long map(long x, long in_min, long in_max, long out_min, long out_max) {
- return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
- }
- // This will stall until specified PS2 clock state
- //
- void wait_CLOCK(uint8_t state) {
- while (read_CLOCK() != state) ; // Do nothing
- } // end wait_CLOCK()
- // This will set the PS2 clock to specified state
- //
- void set_CLOCK(uint8_t state) {
- if(state == 0) {
- DDRB |= (1<<PB0); // Set as output
- PORTB &= ~(1<<PB0); // Set to logic 0
- }
- if(state == 1) {
- DDRB &= ~(1<<PB0); // Set as input
- PORTB |= (1<<PB0); // Set to 1 to active pull-up
- }
- } // end set_CLOCK()
- // This will set the PS2 data to specified state
- //
- void set_DATA(uint8_t state) {
- if(state == 0) {
- DDRB |= (1<<PB1); // Set as output
- PORTB &= ~(1<<PB1); // Set to logic 0
- }
- if(state == 1) {
- DDRB &= ~(1<<PB1); // Set as input
- PORTB |= (1<<PB1); // Set to 1 to active pull-up
- }
- } // end set_DATA()
- // This will return the state of PS2 clock
- //
- uint8_t read_CLOCK(void) {
- return (PINB & (1<<PB0));
- } // end read_CLOCK()
- // This will return the state of PS2 data
- //
- uint8_t read_DATA(void) {
- uint8_t byte;
- byte = PINB & (1<<PB1);
- byte = byte >> 1;
- return byte;
- } // end read_DATA()
- // This will return 1 byte from PS2
- //
- uint8_t PS2_get(void) {
- uint8_t i;
- uint8_t bit;
- uint8_t value = 0;
- uint8_t p = 0;
- set_DATA(1);
- set_CLOCK(1); // Release inhibit, if necessary
- _delay_us(50); // May need to be 50us
- wait_CLOCK(0); // Wait for start bit clock
- if(read_DATA() != 0)
- throw_error("bad start bit, PS2_get\n");
- wait_CLOCK(1); // End of start bit clock
- for(i=0; i<8; i++) {
- wait_CLOCK(0); // Wait for clock pulse
- bit = read_DATA(); // Read data bit from pin
- value = value + (bit << i);
- p = p + bit; // Accumulate data bit into parity
- wait_CLOCK(1); // Wait for end of clock pulse
- }
- wait_CLOCK(0); // Parity bit clock
- p = p + read_DATA(); // Accumulate parity bit into parity
- if ((p & 0x01) == 0) // Check for odd parity
- throw_error("Parity Error, PS2_get\n"); // Parity error!
- wait_CLOCK(1); // End of parity bit clock
- wait_CLOCK(0); // Stop bit clock
- if (read_DATA() == 0) // Check for valid stop bit
- throw_error("Framing Error, PS2_get\n"); // Framing error!
- wait_CLOCK(1);
- set_CLOCK(0); // Pull low during stop bit to inhibit
- _delay_us(50); // Wait out the final clock pulse
- return value;
- } // end PS2_get()
- // This will send 1 byte across PS2
- //
- void PS2_send(uint8_t value) {
- uint8_t i;
- uint8_t ack;
- uint8_t p = 1;
- set_CLOCK(0); // Begin inhibit, if necessary
- _delay_us(100); // Inhibit for about 100us
- set_DATA(0); // Hold data pin low while still inhibited
- set_CLOCK(1); // Establish “request-to-send†state
- for (i = 0; i < 8; i++) {
- wait_CLOCK(0); // Wait for clock pulse
- set_DATA(value & 0x01); // Output i’th data bit
- p = p + value; // Accumulate parity
- wait_CLOCK(1); // Wait for end of clock pulse
- value = value >> 1; // Shift right to get next bit
- }
- wait_CLOCK(0); // Parity bit clock
- set_DATA(p & 0x01); // Output parity bit
- wait_CLOCK(1); // End of parity bit clock
- wait_CLOCK(0); // Stop bit clock
- set_DATA(1); // Stop bit must be 1
- wait_CLOCK(1); // End of stop bit clock
- wait_CLOCK(0); // Line control bit clock
- if (read_DATA() == 1)
- throw_error("Missing Line Control, PS2_send\n"); // Missing line control bit!
- wait_CLOCK(1); // End of line control bit clock
- ack = PS2_get(); // Receive acknowledge byte from device
- if (ack != 0xFA)
- throw_error("Bad ACK, PS2_send\n"); // Probably got an FE or FC error code
- } // end PS2_send()
- // This will get a data packet from the touchpad, and fill the public packetStruct
- // Bitbang it out.
- // See datasheet section 3.6.2 figure 3-18
- //
- void get_packet(void) {
- uint8_t byte;
- byte = PS2_get();
- packet.left = byte & 0x01;
- packet.right = (byte & 0x02) >> 1;
- byte = PS2_get();
- packet.x = (byte & 0x0F) << 8;
- packet.y = (byte & 0xF0) << 4;
- byte = PS2_get();
- packet.z = byte;
- byte = PS2_get();
- packet.x |= (byte & 0x10) << 8;
- packet.y |= (byte & 0x20) << 7;
- byte = PS2_get();
- packet.x |= byte;
- byte = PS2_get();
- packet.y |= byte;
- } // end get_packet()
- // Send special command to touchpad
- // See datasheet section 3.5
- //
- void send_tp_arg(uint8_t arg) {
- uint8_t i;
- for (i = 0; i < 4; i++) {
- PS2_send(0xE8);
- PS2_send((arg >> (6-2*i)) & 3);
- }
- } // end send_tp_arg()
- #ifdef DEBUG
- // This will setup serial comm, using the values #DEFINE'd above
- //
- void USART_init(void) {
- UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8); // Set high byte of baudrate
- UBRR0L = (uint8_t)(BAUD_PRESCALLER); // Set low byte of baudrate
- UCSR0B = (1<<RXEN0)|(1<<TXEN0); // Enable serial on pins 0 and 1, no interrupt
- UCSR0C = (3<<UCSZ00); // Set serial to 8N1
- } // end USART_init()
- // This returns 1 byte from the serial connection
- //
- unsigned char USART_receive(void) {
- while(!(UCSR0A & (1<<RXC0))); // Pool the recieve register, if there is new data...
- return UDR0; // Return the byte
- } // end USART_receive()
- // This will send 1 byte across the serial connection
- //
- void USART_send( unsigned char data) {
- while(!(UCSR0A & (1<<UDRE0))); // Pool the send register, if there is room...
- UDR0 = data; // Hand the byte to the serial hardware
- } // end USART_send()
- // This will send a string across the serial connection, 1 byte at a time
- //
- void USART_putstring(char* stringptr) {
- while(*stringptr != 0x00){ // While we're not at the end...
- USART_send(*stringptr); // Send current byte
- stringptr++; // Increment to next byte
- } //end while()
- } // end USART_putstring()
- #endif
- //************ PWM test
- // used for testing. commented out. ignore.
- int main(void) {
- int red = 0; //Actual red value
- int green = 0; //Actual green value
- int blue = 0; //Actual blue value
- timer0_init(); //Setup timer 0
- timer2_init(); //Setup timer 2
- OCR0A = (uint8_t)red; //Red led is connected to pin PD6/digital 6
- OCR0B = (uint8_t)green; //Green led is connected to pin PD5/digital 5
- OCR2B = (uint8_t)blue; //Blue led is connected to pin PD3/digital pin 3
- for(;;) {
- _delay_ms(20);
- red += 1;
- green += 2;
- blue += 3;
- if(red >= 256)
- red -= 256;
- if(green >= 256)
- green -= 256;
- if(blue >= 256)
- blue -= 256;
- OCR0A = (uint8_t)red; //Red led is connected to pin PD6/digital 6
- OCR0B = (uint8_t)green; //Green led is connected to pin PD5/digital 5
- OCR2B = (uint8_t)blue; //Blue led is connected to pin PD3/digital pin 3
- } // end main loop
- return 0;
- }
- //**********/// End PWM test
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement