1. 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.
    Dismiss Notice

TSC2046 controller and NDS touchscreen

Discussion in 'Microcontrollers' started by DirtyLude, Apr 22, 2009.

  1. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,904
    Likes:
    56
    Location:
    Toronto, Canada
    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 (text):
            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 (text):
    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
     

    Attached Files:

  2. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    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: Feb 19, 2010
  3. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,904
    Likes:
    56
    Location:
    Toronto, Canada
    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.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. birdman0_o

    birdman0_o Active Member

    Joined:
    Feb 23, 2009
    Messages:
    1,370
    Likes:
    18
    Location:
    Montreal, Quebec

    Mine are weird, the scale seems to be logarithmic instead of linear, which I don't understand...
     
  6. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,904
    Likes:
    56
    Location:
    Toronto, Canada
    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.
     
  7. sdomrap

    sdomrap New Member

    Joined:
    Feb 25, 2010
    Messages:
    1
    Likes:
    0
    could you post the c code for detecting voltage generated by the touch screen ..please reply as soon as possible..
     
  8. birdman0_o

    birdman0_o Active Member

    Joined:
    Feb 23, 2009
    Messages:
    1,370
    Likes:
    18
    Location:
    Montreal, Quebec
    C code for which processor?
     
  9. crocu

    crocu Member

    Joined:
    Feb 20, 2009
    Messages:
    118
    Likes:
    1
    Location:
    France
    Hello,

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

    I'll really appreciate it.

    Many thanks,
     
  10. eences

    eences New Member

    Joined:
    Mar 14, 2009
    Messages:
    2
    Likes:
    0
    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,
     
  11. crocu

    crocu Member

    Joined:
    Feb 20, 2009
    Messages:
    118
    Likes:
    1
    Location:
    France
    Hello,

    nobody can help ?
     
  12. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,904
    Likes:
    56
    Location:
    Toronto, Canada
    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.
     
  13. crocu

    crocu Member

    Joined:
    Feb 20, 2009
    Messages:
    118
    Likes:
    1
    Location:
    France
    Many thanks DirtyLude, let's wait you are back home.
     
  14. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,904
    Likes:
    56
    Location:
    Toronto, Canada
  15. crocu

    crocu Member

    Joined:
    Feb 20, 2009
    Messages:
    118
    Likes:
    1
    Location:
    France
    Thanks, would you please post the driver file in C as well ?
     
  16. DirtyLude

    DirtyLude Well-Known Member

    Joined:
    Aug 5, 2003
    Messages:
    1,904
    Likes:
    56
    Location:
    Toronto, Canada
    This is the code I used to test.

    Code (text):
    #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
    }
     
     
  17. eences

    eences New Member

    Joined:
    Mar 14, 2009
    Messages:
    2
    Likes:
    0
    Thanks for the files and the example.
     
    Last edited: Sep 3, 2011

Share This Page