USB Touchscreen Mouse


The AVR based USB Touchscreen Mouse

USB AVR Touch Screen from Sparkfun on Vimeo.

Introduction

We have been selling the PSP and Nintendo DS touchscreens for a while now and it is about time we do something cool that uses them. A LCD touchscreen project first comes to mind, but I really wanted to do something different.

Ryan, one of the other SparkFun engineers was working on the AVR Stick, which uses open source firmware available from Objective Development called V-USB to implement the USB 1.1 standard on an AVR. Basically, you can turn an AVR, like an ATMega168 into a HID (Human Interface Device), that when plugged into a USB port will act like a mouse or keyboard. A touchscreen mouse sounded oh too perfect.

Here are the materials I used to implement the USB touchscreen mouse:

Here is the serial debug code and the final USB mouse code.

You might be wondering why I didn’t use the AVR Stick. Well, there simply were not 4 open IO pins.

Touchscreen

The PSP touchscreen is a 4 wire analog resistive touchscreen. This means by touching the screen at one point, a resistance between each edge is formed for both the x and y axises. As you move your finger or stylus across the screen the resistance changes between opposing sides of each axis. By applying a voltage across each axis, a changing resistance results in a changing voltage. Thus a simple ADC on a microcontroller can be used to find x and y positions. Here is a great document that explains it a little better.

The four pins control 4 buss bars located around the peripheral of the touchscreen. In order to read either an x or a y position, two opposing bars need to be powered and a third orthogonal bar is used to measure the divided voltage.

http://www.sparkfun.com/tutorial/USB%20Touchscreen%20Mouse/bussbarssmall.jpg

This configuration means that the voltage, ground, and sense bar need to be continually switched in order to quickly read x and y positions. Here is how I hooked up the touchscreen to my ATMega168:

http://www.sparkfun.com/tutorial/USB%20Touchscreen%20Mouse/pindescrp.jpg

In my code I will need to switch between the x and y pin assignments in order to quickly read the x and y positions.

Hardware

The hardware for the touchscreen was a simple direct connection to 4 IO pins, 2 of them needing to be ADCs. Power to the screen can be supplied by an output pin being pulled high to 5V and another output pin being pulled low to ground.

The hardware used to turn my ATMega168 into a HID device was simple. All I needed were a few resistors connected to two interrupt pins on the ATMega168. The only requirement is that the D+ pin needs to be connected to the INT0 pin.

More information is available from Objective Development.

Here is a piece of my schematic:

http://www.sparkfun.com/tutorial/USB%20Touchscreen%20Mouse/schematici.jpg

Here is the complete setup:

http://www.sparkfun.com/tutorial/USB%20Touchscreen%20Mouse/touchscreen%20setup.jpg

Code

The first thing I needed to do was to make sure I could get reliable x and y position from the touchscreen before messing with the USB stuff. Here is my project source code for just reading out the ADC values for the touchscreen.

Basically, I needed two ADC readings, one for x and one for y. However, I can’t just set one pin permanently to one ADC, the pins will need to be constantly changing (refer to the chart above).

I made a function for each coordinate that changes the pin assignments and takes an ADC reading.

void read_x(void)
{
    DDRC = 0b00010010; // Output on PC4(5V) and PC1(GND), Input on PC4(ADC)
    sbi(PORTC, 4); //pull PC4 to 5V
    cbi(PORTC, 1); //pull PC1 to GND
   
    _delay_ms(1); //wait for screen to initialize
   
    ADMUX = (1 << MUX1); //ADC2
    ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><<adps1);><adps1);><adps1);><adps1);><adps1);>

    while(ADCSRA & (1 << ADSC));
    l = ADCL;
    h = ADCH & 0x03;
    h = h << 8;
    h = h + l;
}

Now, I can just print the global variable h for the ADC value.

The delay after the port assignments is important. I found that without the delay, the ADC value was not consistent, there were aberrant values present. Since we are powering one of the bus bars on the touchscreen with 5V and then quickly switching it to an ADC input, I imagine that I wasn’t waiting long enough for the capacitance in the screen to “charge”. The 1 ms delay did the trick.

Now that I know the touchscreen hardware is working, I can now look into using these values to compute mouse movements using the USB libraries.

The USB libraries for AVRs can be found on Object Development’s download page. What you get is all of the information you need to implement USB on an AVR: USB libraries, example circuits, example source code, and pretty good documentation.

Sure enough, there is some basic example code for a USB Mouse. The example is even configured for the same architecture that I was planning to use (target device, CPU clock, and fuse values), so I didn’t need to change anything in the makefile. Although, I did want to use my Atmel mkII programmer with AVRstudio, but I wasn’t about to go sifting through the makefile. The example uses avrdude and stkxxx compatible programmers and since SparkFun sells three of those programmers, why not just use one of them.

Note: If you happen to want to use a different AVR at a different speed, then you will need to adjust the makefile. However, not all clock speeds will work. Be sure to use a USB compatible speed for your clock and set the correct fuse bits. More info on what clock speeds are allowed can be found in the usbconfig.h header file. 

After you have your USB hardware setup on your AVR, plug in your programmer, open a command prompt to your firmware directory, follow the make commands in the makefile (be sure to set your fuses!! Information on fuse settings can be found in the makefile), and presto, your AVR is now a USB Mouse.

The example code makes the mouse cursor move in a circle by computing the mouse movements internally in the main.c file. This is nice and fun, especially if you are wanting to play a trick on your co-worker. We had some fun and plugged the tiny AVR Stick with the USB Mouse example into an unsuspecting staff member’s  computer; ahh good times. :)

So how do I get the ADC values of the touchscreen into movements of the mouse? </adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>Here is my USB Mouse project code.
<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);>
The main.c code uses member dx of the structure reportbuffer as a value for speed in the x direction (same for y). Basically, all I need to do is load a signed 8 bit value into reportbuffer.dx and that will move the mouse cursor at some speed.

To sum it up, all my code really does is:
1) Enable a timer to read the ADCs at a set interval
2) Fill a small buffer for the ADC values
3) </adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>Takes the difference of consecutive ADC values to determine direction
<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);>4) </adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>Executes comparisons and conditionals
<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);>5) Calculates the speed by multiplying by a scale factor
6) Load that value into reportbuffer.dx

There was a relatively large problem I ran into after step 3. The ADC value is an unsigned 10 bit number when I load it into the variables h and h1. When I do my comparisons, conditionals, and calculations to clean up the mouse movements, I have to use signed or unsigned 8 bit, 16 bit, or long values. This creates a huge problem since doing any operation between different sized binary values results in non-sense values. Overall, I needed to turn the unsigned 10 bit ADC into a unsigned 8 bit value. With some clever bit shifting I got the value I needed (I would think there is a better way to do this).  Here is the shift:

</adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>char xshifted = ((XDIFF>>3)|((XDIFF&0x8000)>>8));
<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);>
Another issue I came across was debugging. The printf interrupts conflicted with the USB interrupts, therefore I couldn’t print values for integers I needed to debug (like the xshifted variable). What I did was debug using my serial code with out the USB libraries. This was really time consuming, but it did help a bit.

Here is a video of how it works when using the back of a pen as a stylus (my finger worked OK, but a stylus was much better).

</adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>
<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);></adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>
<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);>

USB AVR Touch Screen from Sparkfun on Vimeo.

</adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>
<adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);>

</adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps2)|(1><adps1);><adps1);><adps1);><adps1);><adps1);>What I didn’t do and what needs to be done is a mouse click. There is a member called buttonmask associated to the same structure as dx. I will leave that up to you all to do.

-Aaron
</adps1);></adps1);></adps1);></adps1);></adps1);></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1></adps2)|(1>

Comments 32 comments

  • Not sure if you’ve already considered this, but if you need 8-bit unsigned values from the ADC, instead of 10-bit, you could take a look at the ADLAR bit in the ADMUX register.

  • ok I can not get this to work.
    here is my setup http://wtfmoogle.com/arduino/DSCN4993.JPG
    here is the little usb board i made
    http://wtfmoogle.com/arduino/usbthingbrd.png
    looked into it and it is digital pin 4 for D- and pin 2 for D+
    only difference i see is i used 86 ohm resistors instead of 68? that couldn’t be that much of a problem could it?
    I don’t have the touch screen yet but i plan on using 2 potentiometers to test it out.
    uploaded the .hex with avr dude…
    what am i doing wrong?

    • Hi the links u have kept are not opening.. Will u keep another ones by which i will get information.. And i also want to know the potentiometer ranges u have used. Please replyy…

  • i cant access it. worked 12 hours everyday on it. but result zero.. if there anyone who had run this. please help me.

  • thnx dear. but i have to load it directly from the flash magic right?

  • I want to make this project. i have made all setup. I have downloaded your file" final usb mouse code". but i am confused that in that there are so many files. tell me which file i have to load in MCU. please reply as fast as possible. I have to submit it by the day after tomorrow.

  • I am using Atmega168 micro controller, 4-wire analog resistive touch screen of size 18.5 inch. I had done the entire procedure given above. The problem i am facing is that when ever i connect the USB to the PC it is saying that ‘unrecognized device and asking to install the drivers’. My question is which drivers i need to install and where i have to install? please reply as early as possible.. it’s very urgent…

    • You shouldn’t need drivers if you are using windows. The device should enumerate as an HID. My guess is that there is problem with your code, you need to start debugging the USB HID files, which is not easy. Maybe try loading another HID example from this site.

      • I had understand that drivers are not needed. But for micro controller we have to set fuse bits for making it as a HID. Can u help me how to do that? And based on micro-controller we have used we have to bootload the hex file. For all these some procedure is there. can u please tell me the procedure… Please reply as early as posiible.. Its urgent… Thanking u..

      • i hav taken the entirely same arrangement as being told by u above and burnt the code given as “the final USB mouse code”….but still am facing the problem of usb not recognized. i think its asking for some kind of driver software, can anyone pls help me out with it urgently..

        thanx in advance

  • Anyone know the best way to get this to work on a teensy?

  • Hello everyone. The project I did with Mega16. Everything is right but when I do by my finger Pointer jump to corner of the display and don’t move . please help me , thanks .

  • i wish to make this project…so can u plz send me the circuit arrangement….

  • I am trying to do a similar project using Arduino. I was wondering how much different would the source code be from the AVR? I am new to this, your help would be appreciated!

  • Hey guys,
    what happens when there is no pressure on the screen? Does it skip to gnd or +v, or does it float? I don’t want my ADC reading arbitrary values when I take my finger off. Thanks!

    • OK, so I took the screen out of my palm pilot, and I hooked up all 4 wires to ground through separate 10k resistors. What happens now is that the ADC registers a value lower than the very extreme of the screen. So it no longer floats, but this also means that the highest values it picks up are around 800, not the 1023 the adc is capable of, so you lose some resolution.

  • Hi RYAN can you send me or upload the actual source project…There’s not much i can make out from the main.c file…I would like to make small changes and improve it…

  • Hi guys…Awesome stuff…It works..But the mouse pointer sometimes jumps to random location on the screen….

  • Has anyone done anything similar with the arduino?

  • If this works for both arduino chips with the same cristal how about a tut to setup this experiment with one?

  • This looks awsome could one of these be used as a USB bootloader for a sparkfun arduino without the FTDI chip?
    Then once that was done if this could be talked to with a connection as a library for wiring then keypresses output could go to a c program.
    This would be a great higher speed data logger than a serial port connection I think.

  • Hai there everyone,
    I’ve been looking at this for a few weeks now, and I’m gonna buy the stuff to build it, but I already have the Ardunio usb w/proto-sheild. Do I have to buy the new controller?

  • I am a little confused about the simplicity of your circuit. Take a look at the V-USB harware page:
    http://vusb.wikidot.com/hardware
    They use either a reduced voltage, two diodes, or a level conversion (two Zener diodes) to work with the USB spec.
    Why can you run everything with 5V?
    Thanks, Lars

    • Nice catch, you are correct, we are running out of spec. The reason why we use such simple hardware is because it works and we’re using less components! We initially tried the recommended schematics and then tried without the voltage regulation, our simple schematic worked, simple as that.

      • Hey folks,
        I had to make an account to respond to this, because it might save a ton of frustration.
        It’s true that you can build this circuit out of spec and it might work, but that can be dicey. I built something similar (attiny45 and v-usb) and I found that without the voltage regulation, only 1/3 of the computers I tried it on could recognize it as a usb device.
        It is absolutely worth it to slap on a few diodes to bring the voltage down to the 3.3-3.6 range to improve your chances for compatibility.

  • I had the same idea almost a year ago =)
    works pretty fine, but you can increase the accuracy of the touch pad if you middle 10 to 100 ADC values for each channel =)
    I tested AVR USB … or how it is called now … and it quite unstable and therefore I don’t recommend it for larger applications.
    Greets^^

  • to clarify things as i just tried this.
    The schematic is uses the ATMega168-AU
    to use with Arduino: use Digital Pin 4 for D- and Digital Pin 3 for D+
    Have fun