-
Notifications
You must be signed in to change notification settings - Fork 2
Touchpanel
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.
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.
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:
- Input Coordinate Transformation
-
evdev is an Xorg input driver for Linux's generic event devices
Evdev Axis Inversion -
Touch screen relative coordinates
Shows by example how to do it
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:
- dronus has made a patched version which can invert the x/y-axis:
https://github.com/dronus/linux/commit/24666a13e8dfac1dfeaf55fa3c6e413b64af1a42 - valdodov has done something similar:
http://www.raspberrypi.org/phpBB3/viewtopic.php?p=309437#p309437
Application notes:
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;
}
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_stateudelay(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);
frominclude/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 beads7846_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)
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;
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 |
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 | |
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.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;
This panel uses the ADS7846 touch controller.
- MI0283QT9A schematics + layout
- lallafa has written a blogpost about his experience using dronus' patch.
- Forum search: ads784*
- Forum thread by dronus: http://www.raspberrypi.org/phpBB3/viewtopic.php?f=45&t=23302&p=323265
This panel uses the TSC2046 touch controller (supported by ads7846.c).
- Forum search: tsc2046
- Resistive touchscreen
- Toucscreen calibration: https://www.alwaysinnovating.com/wiki/index.php/Touchscreen_calibration
- evtest can be used to monitor input events
apt-get install evtest