Advertisement
Guest User

Untitled

a guest
Jul 18th, 2018
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.74 KB | None | 0 0
  1. //////////////////////////////////////////////
  2. //
  3. // This program will interface a synaptics
  4. // touchpad with an arduino (ATmega368),
  5. // using the PS/2 protocol.
  6. //
  7. // Then uses that touchpad as a dimmer to PWM 3 LEDS on seperate channels.
  8. //
  9. // References Synaptics Touchpad Datasheet: ACF126
  10. // http://www.synaptics.com/sites/default/files/ACF126.pdf
  11. //
  12. // Written in pure C, wiring libraries not used.
  13. //
  14. // Written by smokkin
  15. //
  16. //////////////////////////////////////////////
  17.  
  18. // clock pin = 8 // arduino pin connections
  19. // data pin = 9 // see datasheet section 3.1 for touchpad connections
  20. //
  21. // led1 pin = 3
  22. // led2 pin = 5
  23. // led3 pin = 6
  24.  
  25. // x -> // actual detected useable ranges
  26. // y -> 1500 - 4500
  27.  
  28.  
  29.  
  30. #include <avr/io.h>
  31. #include <util/delay.h>
  32. #include <math.h>
  33.  
  34.  
  35.  
  36. #define YMIN 1500 // actual useable range, X axis not yet complete
  37. #define YMAX 4500
  38.  
  39.  
  40. // if defined, will compile in serial comm tools, for debugging
  41. //#define DEBUG
  42.  
  43.  
  44. // define our CPU clock freq, the baudrate our serial connection
  45. // will use, and do the required maths.
  46. #define F_CPU 16000000UL
  47. #define BAUDRATE 9600
  48. #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
  49.  
  50.  
  51.  
  52. void timer0_init(void); // Setup timer0 to generate 2 PWM signals
  53. void timer2_init(void); // Setup timer2 to generate 1 PWM signal
  54. void touchpad_init(void); // Touchpad initialization
  55. void wait_CLOCK(uint8_t state); // Wait for clock state 0 or 1
  56. void set_CLOCK(uint8_t state); // Pull clock pin low (0) or let it float high (1)
  57. void set_DATA(uint8_t state); // Pull data pin low (0) or let it float high (1)
  58. uint8_t read_CLOCK(); // Return state of clock pin, 0 or 1
  59. uint8_t read_DATA(); // Return state of data pin, 0 or 1
  60. uint8_t PS2_get(void); // Return byte from PS2
  61. void PS2_send(uint8_t value); // Send byte to PS2
  62. void get_packet(void); // Get Synaptic absolute data stream packet
  63. void send_tp_arg(uint8_t arg); // Send special touchpad command
  64. void throw_error(char* stringptr); // Send string to serial, basically calls USART_putstring()
  65. // map() will scale a number, given 2 number ranges
  66. long map(long x, long in_min, long in_max, long out_min, long out_max);
  67.  
  68. #ifdef DEBUG
  69. void USART_init(void); // Init serial connection
  70. unsigned char USART_receive(void); // Return byte from serial
  71. void USART_send( unsigned char data); // Send byte to serial
  72. void USART_putstring(char* stringptr); // Send string to serial
  73. #endif
  74.  
  75. // Absolute Data Packet, will contain the useable info returned from the touchpad
  76. // See datasheet sections 2.3 and 3.6.2
  77. struct packetStruct {
  78. unsigned int x : 13; // (0-6143) Horizontal finger position, 0 = far left
  79. unsigned int y : 13; // (0-6143) Vertical finger position, 0 = far bottom
  80. unsigned int z : 8; // (0-255) Pressure or contact area, 0 = no contact
  81. unsigned int w : 4; // (0-15) Finger width and other state information
  82. unsigned int left : 1; // State of left physical button, 0 = not pressed, 1 = pressed
  83. unsigned int right : 1; // State of right physical button, 0 = not pressed, 1 = pressed
  84. unsigned int gesture : 1; // Tap/drag gesture in progress, 0 = no gesture, 1 = gesture
  85. unsigned int finger : 1; // Finger presence, 0 = no finger, 1 = finger
  86. };
  87.  
  88.  
  89. struct packetStruct packet; // This will contain the actual data packet
  90.  
  91.  
  92.  
  93. // Program Start
  94. // Will take input from the touchpad, and dim 3 LEDs using PWM, based on the Y value,
  95. // basically turning the touchpad into a slider/dimmer.
  96. //
  97. // All 3 LEDs are on different channels. Eventually we will divide the touchpad into
  98. // 3 different columns, one for each LED.
  99.  
  100.  
  101.  
  102.  
  103.  
  104. /* commented out for DJ
  105. int main(void) {
  106.  
  107. #ifdef DEBUG // If DEBUG is enabled, then setup serial connection
  108. USART_init();
  109. #endif
  110.  
  111. timer0_init(); // Setup timer0 to generate 2 PWM signals
  112. timer2_init(); // Setup timer2 to generate 1 PWM signal
  113. touchpad_init(); // Setup touchpad
  114.  
  115. uint8_t buf; // Temp storage for mathz
  116. char string[32]; // Temp storage for strings, used for debugging
  117. uint8_t red = 0; // Current brightness value for red LED
  118. uint8_t green = 0; // Current brightness value for green LED
  119. uint8_t blue = 0; // Current brightness value for blue LED
  120.  
  121. packet.y = 0; // Zero out the only value we care about at the moment...
  122.  
  123.  
  124.  
  125.  
  126. // Main program loop
  127.  
  128. while(1) {
  129. OCR0A = red; // timer0A is connected to red LED
  130. OCR0B = green; // timer0B is connected to green LED
  131. OCR2B = blue; // timer2B is connected to blue LED
  132.  
  133. get_packet(); // Get new data packet from touchpad
  134. if(packet.y < YMIN) // If below threshold, set to MIN
  135. packet.y = YMIN;
  136. if(packet.y > YMAX) // If above threshold, set to MAX
  137. packet.y = YMAX;
  138.  
  139.  
  140. // Scale raw data down to between 0-255... for easier mathz
  141. buf = (uint8_t)map(packet.y, YMIN, YMAX, 0, 255);
  142.  
  143. red = buf; // Set new brightness values for next loop
  144. blue = buf;
  145. green = buf;
  146.  
  147. } //end while(1) main program loop
  148.  
  149.  
  150.  
  151. /*
  152. // this is for debugging. sends raw data to serial. commented out. ignore.
  153. USART_putstring("ready\n");
  154. while(1) {
  155. get_packet();
  156. USART_putstring("X: ");
  157. itoa(packet.x, string, 10);
  158. USART_putstring(string);
  159.  
  160. USART_putstring(" Y: ");
  161. itoa(packet.y, string, 10);
  162. USART_putstring(string);
  163.  
  164. USART_putstring(" Z: ");
  165. itoa(packet.z, string, 10);
  166. USART_putstring(string);
  167.  
  168. if(packet.left == 1)
  169. USART_putstring(" LEFT");
  170. if(packet.right == 1)
  171. USART_putstring(" RIGHT");
  172.  
  173. USART_putstring("\n");
  174.  
  175. }
  176. */
  177. /* for dj
  178. return 0; // This will never be called. You just divided by zero. Black holes n shit.
  179. } // end main()
  180.  
  181. */
  182. // end commented out for dj, 2 lines
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201. // This function just calls USART_putstring()... Only used to optionally compile serial comm
  202. //
  203. void throw_error(char* stringptr) {
  204. #ifdef DEBUG
  205. USART_putstring(stringptr);
  206. #endif
  207. }
  208.  
  209.  
  210.  
  211. // This will setup timer0 to generate 2 PWM signals
  212. //
  213. void timer0_init(void) {
  214. DDRD = ((1<<PD5)|(1<<PD6)); //Set pwm pins from timer 0 as outputs
  215. TCCR0A = ((1<<COM0A1)|(1<<WGM01)|(1<<WGM00)); //Enable pwm mode in pin PD6 and set the WGM bits to Fast pwm mode
  216. TCCR0A |= (1<<COM0B1); //Enable pwm mode in pin PD5
  217. TCCR0B = ((1<<CS01)|(1<<CS00)); //Set prescaler to 32
  218. } // end timer0_init()
  219.  
  220.  
  221.  
  222. // This will setup timer2 to generate 1 PWM signal
  223. //
  224. void timer2_init(void) {
  225. DDRD |= (1<<PD3); //Set pwm pin OC2B from timer 2 as output
  226. TCCR2A = ((1<<COM2B1)|(1<<WGM21)|(1<<WGM20)); //Enable pwm mode in PD3 and set the WGM bits for fast pwm mode
  227. TCCR2B = ((1<<CS21)|(1<<CS20)); //Set prescaler to 32
  228. } // end timer2_init()
  229.  
  230.  
  231.  
  232. // Setup the touchpad. Enable stream mode and absolute data packet format.
  233. // See datasheet section 3.6.2 figure 3-18
  234. //
  235. void touchpad_init(void) {
  236. uint8_t buf;
  237.  
  238. PS2_send(0xFF); // Reset command
  239.  
  240. if (PS2_get() != 0xAA) // Note: This may need an extra-long timeout
  241. throw_error("error 1, touchpad_init\n");
  242. if (PS2_get() != 0x00)
  243. throw_error("error 2, touchpad_init\n");
  244.  
  245. send_tp_arg(0x00); // Send Identify TouchPad sequence (section 3.5.1)
  246. PS2_send(0xE9); // Status Request command
  247. buf = PS2_get(); // First status byte: TouchPad minor rev
  248.  
  249. if (PS2_get() != 0x47) // Second status byte: 0x47 == Synaptics TouchPad
  250. throw_error("error, not synaptics touchpad\n");
  251.  
  252. buf = PS2_get() & 0x0F; // Third status byte: Major rev in low 4 bits
  253. send_tp_arg(0x80); // Send Set Mode sequence (section 3.5.2)
  254. PS2_send(0xF3); // Set Sample Rate command
  255. PS2_send(0x14); // Sample Rate argument of 20
  256. PS2_send(0xF4); // Enable command
  257.  
  258. set_CLOCK(0); // inhibit until ready to recieve
  259. } // end touchpad_init()
  260.  
  261.  
  262.  
  263. // This will scale a number (x), from one number range to another
  264. //
  265. long map(long x, long in_min, long in_max, long out_min, long out_max) {
  266.  
  267. return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  268. }
  269.  
  270.  
  271.  
  272. // This will stall until specified PS2 clock state
  273. //
  274. void wait_CLOCK(uint8_t state) {
  275. while (read_CLOCK() != state) ; // Do nothing
  276. } // end wait_CLOCK()
  277.  
  278.  
  279.  
  280. // This will set the PS2 clock to specified state
  281. //
  282. void set_CLOCK(uint8_t state) {
  283. if(state == 0) {
  284. DDRB |= (1<<PB0); // Set as output
  285. PORTB &= ~(1<<PB0); // Set to logic 0
  286. }
  287. if(state == 1) {
  288. DDRB &= ~(1<<PB0); // Set as input
  289. PORTB |= (1<<PB0); // Set to 1 to active pull-up
  290. }
  291. } // end set_CLOCK()
  292.  
  293.  
  294.  
  295. // This will set the PS2 data to specified state
  296. //
  297. void set_DATA(uint8_t state) {
  298. if(state == 0) {
  299. DDRB |= (1<<PB1); // Set as output
  300. PORTB &= ~(1<<PB1); // Set to logic 0
  301. }
  302. if(state == 1) {
  303. DDRB &= ~(1<<PB1); // Set as input
  304. PORTB |= (1<<PB1); // Set to 1 to active pull-up
  305. }
  306. } // end set_DATA()
  307.  
  308.  
  309.  
  310. // This will return the state of PS2 clock
  311. //
  312. uint8_t read_CLOCK(void) {
  313. return (PINB & (1<<PB0));
  314. } // end read_CLOCK()
  315.  
  316.  
  317.  
  318. // This will return the state of PS2 data
  319. //
  320. uint8_t read_DATA(void) {
  321. uint8_t byte;
  322. byte = PINB & (1<<PB1);
  323. byte = byte >> 1;
  324. return byte;
  325. } // end read_DATA()
  326.  
  327.  
  328.  
  329. // This will return 1 byte from PS2
  330. //
  331. uint8_t PS2_get(void) {
  332. uint8_t i;
  333. uint8_t bit;
  334. uint8_t value = 0;
  335. uint8_t p = 0;
  336.  
  337. set_DATA(1);
  338. set_CLOCK(1); // Release inhibit, if necessary
  339. _delay_us(50); // May need to be 50us
  340.  
  341. wait_CLOCK(0); // Wait for start bit clock
  342. if(read_DATA() != 0)
  343. throw_error("bad start bit, PS2_get\n");
  344. wait_CLOCK(1); // End of start bit clock
  345.  
  346. for(i=0; i<8; i++) {
  347. wait_CLOCK(0); // Wait for clock pulse
  348. bit = read_DATA(); // Read data bit from pin
  349. value = value + (bit << i);
  350. p = p + bit; // Accumulate data bit into parity
  351. wait_CLOCK(1); // Wait for end of clock pulse
  352. }
  353.  
  354. wait_CLOCK(0); // Parity bit clock
  355. p = p + read_DATA(); // Accumulate parity bit into parity
  356. if ((p & 0x01) == 0) // Check for odd parity
  357. throw_error("Parity Error, PS2_get\n"); // Parity error!
  358. wait_CLOCK(1); // End of parity bit clock
  359.  
  360. wait_CLOCK(0); // Stop bit clock
  361. if (read_DATA() == 0) // Check for valid stop bit
  362. throw_error("Framing Error, PS2_get\n"); // Framing error!
  363.  
  364. wait_CLOCK(1);
  365. set_CLOCK(0); // Pull low during stop bit to inhibit
  366. _delay_us(50); // Wait out the final clock pulse
  367. return value;
  368. } // end PS2_get()
  369.  
  370.  
  371.  
  372. // This will send 1 byte across PS2
  373. //
  374. void PS2_send(uint8_t value) {
  375. uint8_t i;
  376. uint8_t ack;
  377. uint8_t p = 1;
  378.  
  379. set_CLOCK(0); // Begin inhibit, if necessary
  380. _delay_us(100); // Inhibit for about 100us
  381. set_DATA(0); // Hold data pin low while still inhibited
  382. set_CLOCK(1); // Establish “request-to-send” state
  383.  
  384. for (i = 0; i < 8; i++) {
  385. wait_CLOCK(0); // Wait for clock pulse
  386. set_DATA(value & 0x01); // Output i’th data bit
  387. p = p + value; // Accumulate parity
  388. wait_CLOCK(1); // Wait for end of clock pulse
  389. value = value >> 1; // Shift right to get next bit
  390. }
  391.  
  392. wait_CLOCK(0); // Parity bit clock
  393. set_DATA(p & 0x01); // Output parity bit
  394. wait_CLOCK(1); // End of parity bit clock
  395.  
  396. wait_CLOCK(0); // Stop bit clock
  397. set_DATA(1); // Stop bit must be 1
  398. wait_CLOCK(1); // End of stop bit clock
  399.  
  400. wait_CLOCK(0); // Line control bit clock
  401. if (read_DATA() == 1)
  402. throw_error("Missing Line Control, PS2_send\n"); // Missing line control bit!
  403.  
  404. wait_CLOCK(1); // End of line control bit clock
  405. ack = PS2_get(); // Receive acknowledge byte from device
  406. if (ack != 0xFA)
  407. throw_error("Bad ACK, PS2_send\n"); // Probably got an FE or FC error code
  408.  
  409. } // end PS2_send()
  410.  
  411.  
  412.  
  413. // This will get a data packet from the touchpad, and fill the public packetStruct
  414. // Bitbang it out.
  415. // See datasheet section 3.6.2 figure 3-18
  416. //
  417. void get_packet(void) {
  418. uint8_t byte;
  419.  
  420. byte = PS2_get();
  421. packet.left = byte & 0x01;
  422. packet.right = (byte & 0x02) >> 1;
  423.  
  424. byte = PS2_get();
  425. packet.x = (byte & 0x0F) << 8;
  426. packet.y = (byte & 0xF0) << 4;
  427.  
  428. byte = PS2_get();
  429. packet.z = byte;
  430.  
  431. byte = PS2_get();
  432. packet.x |= (byte & 0x10) << 8;
  433. packet.y |= (byte & 0x20) << 7;
  434.  
  435. byte = PS2_get();
  436. packet.x |= byte;
  437.  
  438. byte = PS2_get();
  439. packet.y |= byte;
  440.  
  441. } // end get_packet()
  442.  
  443.  
  444.  
  445. // Send special command to touchpad
  446. // See datasheet section 3.5
  447. //
  448. void send_tp_arg(uint8_t arg) {
  449. uint8_t i;
  450.  
  451. for (i = 0; i < 4; i++) {
  452. PS2_send(0xE8);
  453. PS2_send((arg >> (6-2*i)) & 3);
  454. }
  455. } // end send_tp_arg()
  456.  
  457. #ifdef DEBUG
  458.  
  459.  
  460. // This will setup serial comm, using the values #DEFINE'd above
  461. //
  462. void USART_init(void) {
  463. UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8); // Set high byte of baudrate
  464. UBRR0L = (uint8_t)(BAUD_PRESCALLER); // Set low byte of baudrate
  465. UCSR0B = (1<<RXEN0)|(1<<TXEN0); // Enable serial on pins 0 and 1, no interrupt
  466. UCSR0C = (3<<UCSZ00); // Set serial to 8N1
  467. } // end USART_init()
  468.  
  469.  
  470.  
  471. // This returns 1 byte from the serial connection
  472. //
  473. unsigned char USART_receive(void) {
  474. while(!(UCSR0A & (1<<RXC0))); // Pool the recieve register, if there is new data...
  475. return UDR0; // Return the byte
  476. } // end USART_receive()
  477.  
  478.  
  479.  
  480. // This will send 1 byte across the serial connection
  481. //
  482. void USART_send( unsigned char data) {
  483. while(!(UCSR0A & (1<<UDRE0))); // Pool the send register, if there is room...
  484. UDR0 = data; // Hand the byte to the serial hardware
  485. } // end USART_send()
  486.  
  487.  
  488.  
  489. // This will send a string across the serial connection, 1 byte at a time
  490. //
  491. void USART_putstring(char* stringptr) {
  492. while(*stringptr != 0x00){ // While we're not at the end...
  493. USART_send(*stringptr); // Send current byte
  494. stringptr++; // Increment to next byte
  495. } //end while()
  496. } // end USART_putstring()
  497. #endif
  498.  
  499. //************ PWM test
  500. // used for testing. commented out. ignore.
  501.  
  502. int main(void) {
  503. int red = 0; //Actual red value
  504. int green = 0; //Actual green value
  505. int blue = 0; //Actual blue value
  506.  
  507.  
  508.  
  509. timer0_init(); //Setup timer 0
  510. timer2_init(); //Setup timer 2
  511.  
  512.  
  513. OCR0A = (uint8_t)red; //Red led is connected to pin PD6/digital 6
  514. OCR0B = (uint8_t)green; //Green led is connected to pin PD5/digital 5
  515. OCR2B = (uint8_t)blue; //Blue led is connected to pin PD3/digital pin 3
  516.  
  517. for(;;) {
  518. _delay_ms(20);
  519.  
  520. red += 1;
  521. green += 2;
  522. blue += 3;
  523.  
  524. if(red >= 256)
  525. red -= 256;
  526. if(green >= 256)
  527. green -= 256;
  528. if(blue >= 256)
  529. blue -= 256;
  530.  
  531.  
  532.  
  533. OCR0A = (uint8_t)red; //Red led is connected to pin PD6/digital 6
  534. OCR0B = (uint8_t)green; //Green led is connected to pin PD5/digital 5
  535. OCR2B = (uint8_t)blue; //Blue led is connected to pin PD3/digital pin 3
  536. } // end main loop
  537. return 0;
  538. }
  539. //**********/// End PWM test
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement