• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

TSC2046 controller and NDS touchscreen

Status
Not open for further replies.

DirtyLude

Well-Known Member
This is a very simple and cheap interface and has a lot of potential for an input device on projects. It can be mated with a graphical LCD, or simply used on it's own to simulate button points. If you get fancy, you can implement gestures, like swipes and taps... It comes in under $6 for total parts. One limitation is that the NDS touchscreen is really meant for a stylus input, you need to touch the screen with the flat of your finger with a decent amount of force to register a finger touch so beware of this limitation if you're trying to use it to emulate buttons.

You can implement a 4 wire touch screen using your uC and an ADC, and that's certainly an option, but you don't get the simplicity and accuracy of just adding this 2 dollar part. The TSC2046 is a 4 wire touchscreen controller with an SPI interface. In this example I'm using it in differential mode with 12 bit precision, which gives you precise touch points and pressure measurement. You can use 8bit precision if you want faster sampling time.

I'm not going to get into super detail about the interface, but there's no setup for the chip or anything. Every three byte command/response packet is on it's own. You send 1 byte that specifies the reading you want a response for (X position, Y position, Z1, Z2), the mode (12bit or 8bit), whether it's a single ended or differential reading, and the power down mode. I'm not using the Pen touch interrupt line, but if you specify the chip to power down after the current read, the interrupt pin will be activated and will drop low next time it detects a pen press. There's some finicky things with the pen interrupt line, so it's not as simple as it triggers every time a pen presses, but you could use this in a power saving mode if handled correctly. After you send the command byte, you get two bytes back that contain the response. The response is not right justified, so you need to bit shift it 3 bits right to get your 12bit value.

This chip is used in a lot of portable devices, so doing a search you can find at least a couple embedded linux device drivers for it. You can steal code from those for yourself.

Pressure calculation: There's a calculation method in the datasheet that uses X position, Z1, and Z2 data to give a pressure value, which I'm not using. I stole this calculation from one of the linux drivers. It gives fairly course pressure measurements and a higher value means less pressure, but it works. If you want a simple touch/no touch indicator, you can just check Z1, which is 0 on no touch.

Code:
        if (locationZ1)  //Z1 will always be zero on no touch.
        {
          pressure = 40 * locationX;
          pressure /= 4096;
          pressure *= locationZ2 - locationZ1;
          pressure /= locationZ1;
        }
        else
          pressure = 0;
Anyway, that's it. Simply continue to poll the chip for location data. This is a sampling of data I get when touching the 4 corners with a stylus.

Code:
nothing        X: 4080   Y: 2880   Z1: 0      Z2: 4080  PRS: 0
top left       X: 3680   Y: 3696   Z1: 928    Z2: 3904  PRS: 112
bottom left    X: 160    Y: 3888   Z1: 48     Z2: 3952  PRS: 81
top right      X: 3680   Y: 336    Z1: 816    Z2: 2544  PRS: 74
bottom right   X: 256    Y: 240    Z1: 64     Z2: 2032  PRS: 61
Datasheet:
http://www.electro-tech-online.com/custompdfs/2009/04/tsc2046.pdf

TSC2046 TSSOP16 $2.00
Digi-Key - 296-15049-1-ND (Texas Instruments - TSC2046IPWR)
(TSC2007 is a very similar part with I2C interface rather than SPI, it is not 5V tolarant, though)

NDS touchscreen $2.74 shipping included.
DealExtreme: $2.74 Touch Screen Replacement Module for NDS Lite
dealextreme.com has other 4 wire touchscreens as well for cheap. Just search for 'touch screen' and check the cell phone section.

Connector 95 cents
SparkFun Electronics - Nintendo DS Touch Screen Connector

Possible Connector 91 cents (46 cents for quantity 25) (I have not confirmed that this connector works, so no guarantees here)
Digi-Key - 609-1846-1-ND (FCI - SFV4R-1STE1LF)

Eagle files for my breakout board:
Index of /sam7/tsc2046/board
 

Attachments

AtomSoft

Well-Known Member
Kinda delayed post but thanks!!!

Gonna buy soon and have a play with it. Ill be sure to document it from start to finish! Thanks for the Sparkfun link. Ill be sure to get a clone heh

10062827-0410EDLF FCI SMT Connectors & FFC/FPC
or
52745-0496 Molex SMT Connectors & FFC/FPC

DealExtreme took over 1 month to get my order they suck!! even for good prices...

ebay has better deals for faster time:
http://shop.ebay.com/i.html?_nkw=ni...kw=nintendo+ds+touch+screen&_osacat=0&bkBtn=1

$1 for DS TOUCH SCREEN (LITE OR REG)
 
Last edited:

DirtyLude

Well-Known Member
I've gotten the screens from a few different places now and quality is different, if it matters to anyone. Some of them are nice and solid and some are bendy 'plasticy'. Ones I have with the green around the edge seem to be cheaper quality, but I'm sure that's not universal.
 

DirtyLude

Well-Known Member
Your what is weird? You need to give more information than that. The last person I talked with who was getting readings that weren't clean 1:1 across the screen was reading the incorrect values.
 

sdomrap

New Member
could you post the c code for detecting voltage generated by the touch screen ..please reply as soon as possible..
 

crocu

Member
Hello,

Could someone share his touchscreen driver for TSC2046 controller written for PIC ( in C18 ) ?

I'll really appreciate it.

Many thanks,
 

eences

New Member
Hi. It seems that the breakout board files are not available anymore - the link looks quite dead. Could you repost them somewhere if that's not a problem? Thanks in advance,
 

DirtyLude

Well-Known Member
Just got your PM. Sorry, I've been out of the country for a while and I don't get back until this Friday. I do not use PIC's, so I can't help you out. If you need help beyond the details I've given, you'll need to get them from someone else. Really, you just need to be able to read and write data using basic SPI.

I'll put the data files back up when I get back this weekend. I moved the server from my home to a shared server.
 

DirtyLude

Well-Known Member
This is the code I used to test.

Code:
#include "AT91SAM7S256.h"
//#include "lib_uart.h"
#include "lib_spi.h"
#include "binary.h"

#define nop()  __asm__ __volatile__("nop")

#define LED_PIN        (1U<<8)   // PA8
#define INPUT_PIN      (1U<<1)   // PA1

#define SPI_CS    	AT91C_SPI_CPOL | AT91C_SPI_CSAAT | AT91C_SPI_BITS_8 | \
                        ( ( 150 << 8 ) & AT91C_SPI_SCBR ) | \
                        ( ( 6 << 16 ) & AT91C_SPI_DLYBS ) | \
                        ( ( 6 << 24 ) & AT91C_SPI_DLYBCT )


#define	TSC_START		((unsigned char) 1 << 7)
//------------------------ Read selection bit (differential only)
#define	TSC_DIF_Y               ((unsigned char) 1 << 4)
#define	TSC_DIF_Z1		((unsigned char) 3 << 4)
#define	TSC_DIF_Z2		((unsigned char) 4 << 4)
#define	TSC_DIF_X		((unsigned char) 5 << 4)
//------------------------ 12bit / 8 bit selection
#define	TSC_8_BIT		((unsigned char) 1 << 3)
#define	TSC_12_BIT		((unsigned char) 0 << 3)
//------------------------ Single Ended / Diferential bit
#define	TSC_SER			((unsigned char) 1 << 2)
#define	TSC_DFR			((unsigned char) 0 << 2)
//------------------------ Power Down bits
#define	ADS_PD10_PDOWN		((unsigned char) 0 << 0)	/* lowpower mode + penirq */
#define	ADS_PD10_ADC_ON		((unsigned char) 1 << 0)	/* ADC on */
#define	ADS_PD10_REF_ON		((unsigned char) 2 << 0)	/* vREF on + penirq */
#define	ADS_PD10_ALL_ON		((unsigned char) 3 << 0)	/* ADC + vREF on */


static void initialize_gpio(void);
void delay_us(int time);
void delay_ms(int time);

int main(void)
{
  unsigned char power_down = 0;
  int delay = 20;
  int count = 0;
  char string[254];
  volatile unsigned char control_byte;
  unsigned char tsc_data;
  unsigned int location, locationY, locationX, locationZ1, locationZ2, pressure;
  initialize_gpio();
//  uart_initialize();
  spi_initialize( 0, SPI_CS);

//  spi_setspeed( 0, 100);  //setspeed slow for debug

  // enable global interrupts
  enableIRQ();

  volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;

  while(1)
  {
    count++;
    if( count > 4) count = 1;

    if(( pPIO->PIO_PDSR & INPUT_PIN) == INPUT_PIN)
    {
      power_down = 1;
      delay_us(delay);

       //tsc2046 control byte

      switch ( count)
      {
      case 1:
         locationX = 0;
         locationY = 0;
         locationZ1 = 0;
         locationZ2 = 0;
         control_byte = (TSC_START | TSC_DIF_Y | TSC_12_BIT | TSC_DFR | ADS_PD10_ADC_ON);
         break;
      case 2:
         control_byte = (TSC_START | TSC_DIF_Z1 | TSC_12_BIT | TSC_DFR | ADS_PD10_ADC_ON);
         break;
      case 3:
         control_byte = (TSC_START | TSC_DIF_Z2 | TSC_12_BIT | TSC_DFR | ADS_PD10_ADC_ON);
         break;
      case 4:
         control_byte = (TSC_START | TSC_DIF_X | TSC_12_BIT | TSC_DFR | ADS_PD10_ADC_ON);
         break;
      }
      tsc_data = spi_transfer_ext( 0, control_byte, 1);
      tsc_data = spi_transfer_ext( 0, 0x00, 1);
      location = (unsigned int) tsc_data << 8;
      tsc_data = spi_transfer_ext( 0, 0x00, 0);
      location = location | (unsigned int)tsc_data;

  //    tsc_data
      switch ( count)
      {
      case 1:
         locationY = (location >> 3);
         break;
      case 2:
         locationZ1 = (location >> 3);
         break;
      case 3:
         locationZ2 = (location >> 3);
         break;
      case 4:
        locationX = (location >> 3);
        if (locationZ1)
        {
          pressure = 40 * locationX;
          pressure /= 4096;
          pressure *= locationZ2 - locationZ1;
          pressure /= locationZ1;
        }
        else
          pressure = 0;

        sprintf(string, "X: %i   Y: %i   Z1: %i    Z2: %i  PRS: %i\n\r",locationX,locationY,locationZ1,locationZ2,pressure);
//        uart_puts( string);
        if( locationZ1 != 0)
          pPIO->PIO_CODR = LED_PIN;
        else
          pPIO->PIO_SODR = LED_PIN;
        break;
      }
    }
    else
    {
      if(power_down == 0)
      {
        control_byte = (TSC_START | TSC_DIF_Y | TSC_8_BIT | TSC_DFR | ADS_PD10_PDOWN);
        tsc_data = spi_transfer_ext( 0, control_byte, 1);
        tsc_data = spi_transfer_ext( 0, 0x00, 1);
        tsc_data = spi_transfer_ext( 0, 0x00, 0);
        power_down = 1;
      }
    }
  }
}

static void initialize_gpio(void)
{
  //Turn on the peripheral clock.  Without this on, inputs do not actually register in the PDSR register
  volatile AT91PS_PMC	pPMC = AT91C_BASE_PMC;			// pointer to PMC data structure
  pPMC->PMC_PCER = (1<<AT91C_ID_PIOA);				// enable PIOA peripheral clock

  volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
   pPIO->PIO_PER = (LED_PIN | INPUT_PIN);  // Set PIO to control LED and button.
  // Initialize Input
  pPIO->PIO_ODR = INPUT_PIN ;   // Disable outputs for INPUT pins. (not needed as all pins default input on reset)
  pPIO->PIO_PPUER = INPUT_PIN; //Pullup Enable (not needed as all pullups are enabled on reset)

  // Initialize Output
  pPIO->PIO_OER = LED_PIN;   // Enable output for LED.
  pPIO->PIO_SODR = LED_PIN;  // Turn LED off.
  pPIO->PIO_PPUDR = LED_PIN;  //Pullup disable
}
 
Status
Not open for further replies.

EE World Online Articles

Loading
Top