Skip to content
notro edited this page May 2, 2013 · 42 revisions

People with a github account can edit these pages.
Please help advancing the knowledge on this subject. Add your experience with a particular display under it's own heading.
Remember to add a link to the information source.

touchpanel

Some displays have touchpanels with a controller on the breakoutboard.
I have only one display with touch, the ITDB02-28, but sadly it uses nearly all my GPIOs for the display.

But nevertheless touch support will be a part of fbtft in the future.
Probably the driver will register a touch device that is setup with the characteristics of the touchpanel.
When the ads7846 driver is loaded, it finds a touch device that matches the one on the display.

ads7846_test

The latest image contains a modified version of ads7846. This version registers it's own device and provides arguments for all config values.
To show arguments: modinfo -p ads7846_test

What I'm unsure about is should I use the inversion patching used by dronus and valdodov. Is there a way around patching it?

Info about inverting and swapping:

ADS784x

Many displays with a touchpanel uses an ADS784x touch controller.
It has a Linux driver: drivers/input/touchscreen/ads7846.c

It's not enabled in the kernel config by default (make menuconfig):

Device Drivers  ---> Input device support  --->[*]  Touchscreens  ---> ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens

Patched versions:

Application notes:

Max SPI speed

Max SPI speed is: 125000 * (8+16+2) Hz = 125000 * 26 Hz = 3250 kHz
On the Raspberry Pi, we have two close values on this list: 1.9 MHz and 3.9 MHz
Asking for 2 MHz will rount down to neares value which i 1.935 MHz

The value 125000 probably comes from Datasheet - ELECTRICAL CHARACTERISTICS:

|-----------------------------------------------------------|
|                                 |    ADS7846E     |       |
| PARAMETER          | CONDITIONS | MIN | TYP | MAX | UNITS |
|-----------------------------------------------------------|
| Throughput Rate    |            |     |     | 125 | kHz   | 
|-----------------------------------------------------------|

Excerpt from ads7846.c

/* this driver doesn't aim at the peak continuous sample rate */
#define	SAMPLE_BITS	(8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)

static int __devinit ads7846_probe(struct spi_device *spi)

	/* don't exceed max specified sample rate */
	if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
		dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
				(spi->max_speed_hz/SAMPLE_BITS)/1000);
		return -EINVAL;
	}

Decoding the ads7846_platform_data fields

This an excerpt of linux/spi/ads7846.h

    /* Touchscreen characteristics vary between boards and models.  The
     * platform_data for the device's "struct device" holds this information.
     *
     * It's OK if the min/max values are zero.
     */
    
    struct ads7846_platform_data {
    	u16	model;			/* 7843, 7845, 7846, 7873. */
    	u16	vref_delay_usecs;	/* 0 for external vref; etc */
    	u16	vref_mv;		/* external vref value, milliVolts
    					 * ads7846: if 0, use internal vref */
    	bool	keep_vref_on;		/* set to keep vref on for differential
    					 * measurements as well */
    	bool	swap_xy;		/* swap x and y axes */
    
    	/* Settling time of the analog signals; a function of Vcc and the
    	 * capacitance on the X/Y drivers.  If set to non-zero, two samples
    	 * are taken with settle_delay us apart, and the second one is used.
    	 * ~150 uSec with 0.01uF caps.
    	 */
    	u16	settle_delay_usecs;
    
    	/* If set to non-zero, after samples are taken this delay is applied
    	 * and penirq is rechecked, to help avoid false events.  This value
    	 * is affected by the material used to build the touch layer.
    	 */
    	u16	penirq_recheck_delay_usecs;
    
    	u16	x_plate_ohms;
    	u16	y_plate_ohms;
    
    	u16	x_min, x_max;
    	u16	y_min, y_max;
    	u16	pressure_min, pressure_max;
    
    	u16	debounce_max;		/* max number of additional readings
    					 * per sample */
    	u16	debounce_tol;		/* tolerance used for filtering */
    	u16	debounce_rep;		/* additional consecutive good readings
    					 * required after the first two */
    	int	gpio_pendown;		/* the GPIO used to decide the pendown
    					 * state if get_pendown_state == NULL
    					 */
    	int	(*get_pendown_state)(void);
    	int	(*filter_init)	(const struct ads7846_platform_data *pdata,
    				 void **filter_data);
    	int	(*filter)	(void *filter_data, int data_idx, int *val);
    	void	(*filter_cleanup)(void *filter_data);
    	void	(*wait_for_sync)(void);
    	bool	wakeup;
    	unsigned long irq_flags;
    };
  • model - 7843, 7845, 7846, 7873 (default: 7846)
  • vref_delay_usecs - 0 for external vref; etc
    micro seconds to delay between SPI transfers (spi_transfer.delay_usecs)
  • vref_mv - external vref value, milliVolts ads7846: if 0, use internal vref
    used for hwmon sensor code
  • keep_vref_on - set to keep vref on for differential measurements as well
    used in ads7846_setup_spi_msg(). READ_X(vref) == ADS_START | ADS_A2A1A0_d_ x | ADS_12_BIT | ADS_DFR | ADS_PD10_ADC_ON | (vref ? ADS_PD10_REF_ON : 0)
    #define ADS_PD10_REF_ON (2 << 0) /* vREF on + penirq */
  • swap_xy - swap x and y axes
  • settle_delay_usecs - Settling time of the analog signals; a function of Vcc and the capacitance on the X/Y drivers.
    If set to non-zero, two samples are taken with settle_delay us apart, and the second one is used. ~150 uSec with 0.01uF caps.
    micro seconds to delay between SPI transfers (spi_transfer.delay_usecs)
  • penirq_recheck_delay_usecs - If set to non-zero, after samples are taken this delay is applied and penirq is rechecked,
    to help avoid false events. This value is affected by the material used to build the touch layer.
    used in ads7846_report_state udelay(ts->penirq_recheck_delay_usecs);
  • x_plate_ohms - Used to calculate pressure in ads7846_report_state() (default: 400)
  • y_plate_ohms - Not used by driver
  • x_min - Minimum value for x-axis (default: 0)
  • x_max - Maximum value for x-axis (default: MAX_12BIT == 0x0FFF == 4095)
    input_set_abs_params(input_dev, ABS_X, pdata->x_min ? : 0, pdata->x_max ? : MAX_12BIT, 0, 0);
    from include/uapi/linux/input.h: Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in units per millimeter (units/mm)
  • y_min - Minimum value for y-axis (default: 0)
  • y_max - Maximum value for y-axis (default: MAX_12BIT == 0x0FFF == 4095)
    input_set_abs_params(input_dev, ABS_Y, pdata->y_min ? : 0, pdata->y_max ? : MAX_12BIT, 0, 0);
  • pressure_min, pressure_max - (pressure_max default: ~0 == 0xFFFF)
    input_set_abs_params(input_dev, ABS_PRESSURE, pdata->pressure_min, pdata->pressure_max, 0, 0);
  • debounce_max - max number of additional readings per sample (0,1,2)
    if filter is not defined and debounce_max is non-zero, filter will be ads7846_debounce_filter()
  • debounce_tol - tolerance used for filtering
    used in ads7846_debounce_filter
  • debounce_rep - additional consecutive good readings required after the first two
    used in ads7846_debounce_filter
  • gpio_pendown - the GPIO used to decide the pendown state if get_pendown_state == NULL
  • irq_flags - (default: IRQF_TRIGGER_FALLING)

Two solutions

dronus' approach
Using his patched ads7846.c:

    /* arch/arm/mach-bcm2708/bcm2708.c */
    static struct ads7846_platform_data ads7846_config = {
    	.x_max      = 0x0fff,
    	.y_max      = 0x0fff,
    	.x_plate_ohms    = 180,
    	.pressure_max    = 255,
    	.debounce_max    = 10,
    	.debounce_tol    = 3,
    	.debounce_rep    = 1,
    	.gpio_pendown    = 17,
    	.keep_vref_on    = 1,
    	.swap_xy                = true,
    	.invert_x    = true
    ;
    
    static struct spi_board_info bcm2708_spi_devices[] = {
     {
    	.modalias    = "ads7846",
    	.bus_num    = 0,
    	.chip_select    = 0,
    	.max_speed_hz           = 500000,
    	//    .controller_data  = &ads7846_mcspi_config,
    	.irq      = GPIO_IRQ_START+17,
    	.platform_data    = &ads7846_config,
    	.mode = SPI_MODE_0
     },
    };

valdodov's aproach
arch/arm/mach-bcm2708/bcm2708.c:

#include <linux/spi/ads7846.h>

.....

#define PEN_DOWN_STATE_PIN   17

.....

#ifdef CONFIG_SPI
static int ads7846_pendown_state(void)
{
   return !gpio_get_value(PEN_DOWN_STATE_PIN);   /* Touchscreen PENIRQ */
}
static struct ads7846_platform_data ads_info = {
   .model         = 7846,
   .swap_xy = 1,
   .x_min         = 280,
   .x_max         = 3830,
   .y_min         = 190,
   .y_max         = 3830,
   .vref_delay_usecs   = 100,
   .x_plate_ohms      = 576,
   .y_plate_ohms      = 366,
   .pressure_max      = 15000,
   .debounce_max      = 1,
   .debounce_rep      = 0,
   .debounce_tol      = (~0),
   .get_pendown_state   = ads7846_pendown_state,
};

static struct spi_board_info bcm2708_spi_devices[] = {
   {
      .modalias = "spi-ssd1289",
      .max_speed_hz = 16000000,
      .bus_num = 0,
      .chip_select = 0,
      .mode = SPI_MODE_0,
   },
   {   
      .modalias   = "ads7846",
      .chip_select   = 1,
      .bus_num      = 0,
      .max_speed_hz   = 5000 * 26,
      .platform_data   = &ads_info,
      .irq      = -1, 
   }
};
#endif


void __init bcm2708_init(void)
{
.....
#ifdef CONFIG_SPI
   bcm2708_spi_devices[1].irq=gpio_to_irq(PEN_DOWN_STATE_PIN);
   spi_register_board_info(bcm2708_spi_devices, ARRAY_SIZE(bcm2708_spi_devices));
#endif
.....
}

drivers/input/touchscreen/ads7846.c diff

@@ @@ static void ads7846_report_state(struct ads7846 *ts)
		if (ts->swap_xy)
			swap(x, y);

+		x=pdata->x_max+320-x;
+		y=pdata->y_max+280-y;
+
		if (!ts->pendown) {
			input_report_key(input, BTN_TOUCH, 1);
			ts->pendown = true;

Comparison of the two approaches

spi_board_info
 Field              |   valdodov    |   dronus              |
-------------------------------------------------------------
 modalias       	|  "ads7846"    |  "ads7846"            |
 chip_select    	|  1            |  0                    |
 bus_num        	|  0            |  0                    |
 max_speed_hz   	|  5000 * 26    |  500000               |
 platform_data  	|  &ads_info    |  &ads7846_config      |
 irq            	|  -1           |  GPIO_IRQ_START+17    |
ads7846_platform_data
 Field              |   valdodov              |   dronus              |
-----------------------------------------------------------------------
 model              |  7846                   |  (defaults to 7846)   |
 swap_xy            |  1                      |  true                 |
 invert_x           |          n/a            |  true                 |
 x_min              |  280                    |                       |
 x_max              |  3830                   |  0x0fff               |
 y_min              |  190                    |                       |
 y_max              |  3830                   |  0x0fff               |
 vref_delay_usecs   |  100                    |                       |
 keep_vref_on       |                         |  1                    |
 x_plate_ohms       |  576                    |  180                  |
 y_plate_ohms       |  366                    |                       |
 pressure_max       |  15000                  |  255                  |
 debounce_max       |  1                      |  10                   |
 debounce_rep       |  0                      |  1                    |
 debounce_tol       |  (~0)                   |  3                    |
 gpio_pendown       |                         |  17                   |
 get_pendown_state  |  ads7846_pendown_state  |                       |
get_pendown_state()

dronus relies on the built in function, with .gpio_pendown = 17,

static int get_pendown_state(struct ads7846 *ts)
{
	if (ts->get_pendown_state)
		return ts->get_pendown_state();

	return !gpio_get_value(ts->gpio_pendown);
}

valdodov provides his own, with #define PEN_DOWN_STATE_PIN 17

static int ads7846_pendown_state(void)
{
   return !gpio_get_value(PEN_DOWN_STATE_PIN);   /* Touchscreen PENIRQ */
}
ads7846_report_state() diff

ads7846.h: #define MAX_12BIT ((1<<12)-1) = 0x0fff = 4095
dronus

    if(ts->invert_x)
      x=MAX_12BIT-x;
    if(ts->invert_y)
      y=MAX_12BIT-y;

valdodov

		x=pdata->x_max+320-x;
		y=pdata->y_max+280-y;

Watterott MI0283QT-9A

This panel uses the ADS7846 touch controller.

ITDB02-2.8

This panel uses the TSC2046 touch controller (supported by ads7846.c).

References

Tools

  • evtest can be used to monitor input events apt-get install evtest

piwik

Clone this wiki locally