Skip Navigation LinksTutorials > LPC2148 QuickStart Guide > Lesson 3 - Analog Input (ADC) > Example: Nintendo DS Touch Screen

ADC Example: Nintendo DS Touch Screen

Using ADC to measure the current X/Y position on a Nintendo DS touch screen

Resistive touch screens can be a great way to enable complex user input in your projects inexpensively and with a minimum number of pins. With just four wires you can capture gestures, buttons clicks, constantly track the position of a finger or stylus, and other interesting things. Best of all ... thanks to the success of current touch-enabled devices like the Nintendo DS, there is also a steady supply of inexpensive touch screens available (which is precisely why we've chosen to use the Nintendo DS touch screen as an example).

Resistive touch screens operate on the same principle as a simple potentiometer ... you apply 3.3v and GND on opposite ends, and measure the resulting current in between the two on a third pin (using an analog to digital converter).  The only difference is that rather than adjusting the resistance by turning a dial, you adjust it by touching a certain part of the screen.  Like a potentiometer, the resistance varies depending on the position you touch, allowing you to accurately determine exactly where you are touching with a few simple lines of code (see the potentiometer example in Lesson 3: Analog Input).

The catch with touch screens is that you have two axis to handle (X and Y), but only 4 pins to measure with (X1, X2, Y1, Y2).  You can easily measure one axis without doing anything special.  You have to be a bit tricky, though, to measure both axis in software-only, as you'll see below.  First, though, a quick diagram explaining how analog resistive touch screens work, and how to wire them up.

Resistive Touch Screen Layout

To read the current position on one axis, you simply need to apply 3.3V on one side, GND on the other, and measure the current on the bus running 'across' the axis you wish to check (see the diagrams and table below for an example of how to read both the X and the Y axis):

Measuring the X Axis on a Resistive Touch Screen Measuring the Y Axis on a Resistive Touch Screen

LPC2148 and Nintendo DS Touch Screen Connections
 X1 Y2  X2  Y1 
To measure the position on X: 3.3V ADC GND ---
To measure the position on Y: ADC 3.3V --- GND

We mentionned that there was a 'catch' to reading both axis at the same time. You might be able to see what it is looking at the table above. The "---" entries in the table mean that in order to get a correct reading, those pins need to be 'floating' (i.e., they can't be connected to either 3.3V or GND). That would be easy enough on one axis, but the problem is that you read the X and Y co-ordinates by rapidly switching between X and Y readings one after the other. That means that your pin that is 'floating' during one read (say Y1 when reading X) needs to be connected to GND on the next read. The solution is to set the GPIO pin to 'input' (with IODIR) in one read, which will simulate a floating state (removing both GND and 3.3V), and set it back to 'output' and low (GND) during the next read.

Reading the X and Y axis
The full project for this example is available for download at the bottom of this page
//             X1      Y2     X2     Y1
//            -----  -----  -----  -----
// LPC2148    P0.22  P0.21  P0.28  P0.29

#include "touchscreen.h"

// Initialise touch screen
void tsInit(void)
{
  // Enable power for ADC1
  SCB_PCONP |= SCB_PCONP_PCAD1;

  // Make sure P0.28 and 0.29 are set to GPIO (just in case)
  // They are used to toggle between GND and 'floating'
  PCB_PINSEL1 &= ~PCB_PINSEL1_P028_MASK;
  PCB_PINSEL1 |= PCB_PINSEL1_P028_GPIO;
  PCB_PINSEL1 &= ~PCB_PINSEL1_P029_MASK;
  PCB_PINSEL1 |= PCB_PINSEL1_P029_GPIO;

  // Initialise ADC converters (using 12MHz PCLK)
  AD1_CR = AD_CR_CLKS10                   // 10-bit precision
         | AD_CR_PDN                      // Exit power-down mode
         | ((3 - 1) << AD_CR_CLKDIVSHIFT) // 4.0MHz Clock (12.0MHz / 3)
         | AD_CR_SEL6 | AD_CR_SEL7;       // Use channel 6 and 7
}

// Read the current X position using ADC1.6
unsigned int tsReadX(void)
{
  // Set P0.21 as AD1.6
  PCB_PINSEL1 &= ~PCB_PINSEL1_P021_MASK;
  PCB_PINSEL1 |= PCB_PINSEL1_P021_AD16;

  // Provide 3.3v with P0.22
  PCB_PINSEL1 &= ~PCB_PINSEL1_P022_MASK;
  PCB_PINSEL1 |= PCB_PINSEL1_P022_GPIO;
  GPIO0_IODIR |= (1 << 22);   // Set 0.22 as output
  GPIO0_IOSET |= (1 << 22);   // Set 0.22 high (provides 3.3v)

  // Provide GND with P0.28
  GPIO0_IODIR |= (1 << 28);   // Set 0.28 as output
  GPIO0_IOCLR |= (1 << 28);   // Set 0.28 low (provides GND)

  // Set 0.29 'floating' (by setting it to input)
  GPIO0_IODIR &= ~(1 << 29);   // Set 0.29 as input

  // Start AD conversion
  AD1_CR &= ~(AD_CR_START_MASK | AD_CR_SELMASK);
  AD1_CR |=  (AD_CR_START_NONE | AD_CR_SEL6);
  AD1_CR |=   AD_CR_START_NOW;

  // Wait for the conversion to complete
  while (!(AD1_DR6 & AD_DR_DONE))
    ;

  // Return the processed results
  return ((AD1_DR6 & AD_DR_RESULTMASK)
          >> AD_DR_RESULTSHIFT);
}

// Read the current Y position using AD1.7
unsigned int tsReadY(void)
{
  // Set P0.22 as AD1.7
  PCB_PINSEL1 &= ~PCB_PINSEL1_P022_MASK;
  PCB_PINSEL1 |= PCB_PINSEL1_P022_AD17;

  // Provide 3.3v with P0.21
  PCB_PINSEL1 &= ~PCB_PINSEL1_P021_MASK;
  PCB_PINSEL1 |= PCB_PINSEL1_P021_GPIO;
  GPIO0_IODIR |= (1 << 21);   // Set pin to output
  GPIO0_IOSET |= (1 << 21);   // Set pin high (providing 3.3V)

  // Provide GND with P0.29
  GPIO0_IODIR |= (1 << 29);   // Set 0.29 as output
  GPIO0_IOCLR |= (1 << 29);   // Set 0.29 low (provides GND)

  // Set 0.28 'floating' (by setting it to input)
  GPIO0_IODIR &= ~(1 << 28);   // Set 0.28 as input

  // Start AD conversion
  AD1_CR &= ~(AD_CR_START_MASK | AD_CR_SELMASK);  
  AD1_CR |=  (AD_CR_START_NONE | AD_CR_SEL7);
  AD1_CR |=   AD_CR_START_NOW;                    

  // Wait for the conversion to complete
  while (!(AD1_DR7 & AD_DR_DONE))
    ;

  // Return the processed results
  return ((AD1_DR7 & AD_DR_RESULTMASK)
          >> AD_DR_RESULTSHIFT);
}
Lesson Downloads
  1. Nintendo DS Touch Screen Example - Crossworks 2.0 Project

  • Facebook
  • DZone It!
  • Digg It!
  • StumbleUpon
  • Technorati
  • Del.icio.us
  • NewsVine
  • Reddit
  • Blinklist
  • Furl it!

Comments