Skill level:     Intermediate
 

USB Touchscreen Mouse

by a1ronzo  |  
July 14, 2009  |  

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<<

    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?
Here is my USB Mouse project code.

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)
Takes the difference of consecutive ADC values to determine direction
4) Executes comparisons and conditionals
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:

char xshifted = ((XDIFF>>3)|((XDIFF&0x8000)>>8));

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).



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

Back to Tutorials

 

Comments

17 comments


Log in to post comments.

TheMoogle's rank:
+4.6
|   Jul 14, 2009 at  6:52pm
Comment rating:
0
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
by
BWA's rank:
+3.5
|   Jul 15, 2009 at  3:01am
Comment rating:
0
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^^
TheMoogle's rank:
+4.6
|   Jul 15, 2009 at 11:10am
Comment rating:
0
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?
by
Larsi's rank:
+4.2
|   Jul 15, 2009 at 12:10pm
Comment rating:
0
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
by a1ronzo is a SparkFun employee
|   Jul 15, 2009 at  3:20pm
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.
by
chriszf's rank:
+1
|   Jul 16, 2009 at  2:48pm
Comment rating:
0
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.
by
crwper's rank:
+5.5
|   Jul 16, 2009 at 12:43pm
Comment rating:
+0.15
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.
will-not-1337's rank:
+1
|   Aug  2, 2009 at  3:49am
Comment rating:
0
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?
will-not-1337's rank:
+1
|   Aug  2, 2009 at  3:51am
Comment rating:
0
I mean the ATMega168. if I have an ardunio do I have the by it?
by
josheeg's rank:
+2.9
|   Aug 11, 2009 at  7:02am
Comment rating:
0
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.
by
josheeg's rank:
+2.9
|   Aug 11, 2009 at 11:40pm
Comment rating:
0
If this works for both arduino chips with the same cristal how about a tut to setup this experiment with one?
by
manray's rank:
+2.5
|   Oct 26, 2009 at  5:11pm
Comment rating:
0
Has anyone done anything similar with the arduino?
follower's rank:
+2
|   Dec  8, 2009 at  6:58am
Comment rating:
0
> Has anyone done anything similar with the arduino?
Yes, you can check out more details here:

http://code.rancidbacon.com/ProjectLogArduinoUSB

I adapted the V-USB code to work with the Arduino.

--Philip;
by
U2's rank:
+1
|   Feb 21, 2010 at  9:09am
Comment rating:
0
Hi guys...Awesome stuff...It works..But the mouse pointer sometimes jumps to random location on the screen....
by
U2's rank:
+1
|   Feb 21, 2010 at  9:56am
Comment rating:
0
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...
by
NOTgate's rank:
+2.4
|   Apr 18, 2010 at  5:06pm
Comment rating:
0
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!
by
NOTgate's rank:
+2.4
|   Apr 24, 2010 at  2:02pm
Comment rating:
0
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.


Feedback

What's on your mind?

Please include your email address if you'd like us to respond to a specific question.

submit


If you would like to tell us more, you can fill out our form if you need some psycho-suggestive questions. Go to the form.