历史上的今天
返回首页

历史上的今天

今天是:2025年07月23日(星期三)

正在发生

2021年07月23日 | 嵌入式驱动移植之触摸驱动初识

2021-07-23 来源:eefocus

开发环境

BootLoader:u-boot-1.1.6

kernel:linux-2.6.30.4

CPU:s3c2440

开发板:TQ2440

参考资料:《天嵌科技Linux移植手册》


移植步骤

1、触摸驱动编写

此处直接用天嵌提供的源码,从天嵌科技提供的 2.6.30.4 的源码中的“drivers/input/touchsreen/”拷贝“tq2440_ts.c”文件到我的内核的“drivers/input/touchsreen/”目录下,然后修改驱动源码的 41 行为如下内容:


//extern struct semaphore ADC_LOCK; //这个原来的内容

DECLARE_MUTEX(ADC_LOCK); //这是修改后的内容


说明:修改原因,因为天嵌科技提供的触摸驱动中使用了 ADC 驱动中的 ADC_LOCK,而这里并没有移植 ADC 驱动,所以这里做一下简单的改变。

源代码如下:


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#include

#include


/* For ts.dev.id.version */

#define S3C2410TSVERSION 0x0101


#define WAIT4INT(x)  (((x)<<8) |

     S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN |

     S3C2410_ADCTSC_XY_PST(3))


#define AUTOPST      (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN |

     S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))


static char *tq2440ts_name = "TQ2440 TouchScreen";


static struct input_dev *dev;

static long xp;

static long yp;

static int count;


extern struct semaphore ADC_LOCK;

static int OwnADC = 0;


static void __iomem *base_addr;

/*

static inline void tq2440_ts_connect(void)

{

s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);

s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);

s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);

s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);

}

*/

static void touch_timer_fire(unsigned long data)

{

  unsigned long data0;

  unsigned long data1;

int updown;


  data0 = ioread32(base_addr+S3C2410_ADCDAT0);

  data1 = ioread32(base_addr+S3C2410_ADCDAT1);


  updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));


  if (updown) {

  if (count != 0)

  {

long tmp;

                                                                                                 

tmp = xp;

xp = yp;

yp = tmp;

                                                                                                 

                        xp >>= 2;

                        yp >>= 2;


  input_report_abs(dev, ABS_X, xp);

  input_report_abs(dev, ABS_Y, yp);


  input_report_key(dev, BTN_TOUCH, 1);

input_report_abs(dev, ABS_PRESSURE, 1);

  input_sync(dev);

  }


  xp = 0;

  yp = 0;

  count = 0;


  iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);

  iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);

  }

  else

  {

  count = 0;


  input_report_key(dev, BTN_TOUCH, 0);

  input_report_abs(dev, ABS_PRESSURE, 0);

  input_sync(dev);


  iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);

if (OwnADC)

{

OwnADC = 0;

up(&ADC_LOCK);

}

  }

}


static struct timer_list touch_timer =

TIMER_INITIALIZER(touch_timer_fire, 0, 0);


static irqreturn_t stylus_updown(int irq, void *dev_id)

{

unsigned long data0;

unsigned long data1;

int updown;


if (down_trylock(&ADC_LOCK) == 0)

{

OwnADC = 1;

data0 = ioread32(base_addr+S3C2410_ADCDAT0);

data1 = ioread32(base_addr+S3C2410_ADCDAT1);


updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));


if (updown)

{

touch_timer_fire(0);

}

else

{

OwnADC = 0;

up(&ADC_LOCK);

}

}


return IRQ_HANDLED;

}



static irqreturn_t stylus_action(int irq, void *dev_id)

{

unsigned long data0;

unsigned long data1;


if (OwnADC)

{

data0 = ioread32(base_addr+S3C2410_ADCDAT0);

data1 = ioread32(base_addr+S3C2410_ADCDAT1);


xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;

yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;

count++;


if (count < (1<<2))

{

iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);

iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);

}

else

{

mod_timer(&touch_timer, jiffies+1);

iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);

}

}


return IRQ_HANDLED;

}


static struct clk *adc_clock;


static int __init tq2440ts_init(void)

{

struct input_dev *input_dev;


adc_clock = clk_get(NULL, "adc");

if (!adc_clock)

{

printk(KERN_ERR "failed to get adc clock sourcen");

return -ENOENT;

}

clk_enable(adc_clock);


base_addr=ioremap(S3C2410_PA_ADC,0x20);

if (base_addr == NULL)

{

printk(KERN_ERR "Failed to remap register blockn");

return -ENOMEM;

}


/* Configure GPIOs */

// tq2440_ts_connect();


iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),base_addr+S3C2410_ADCCON);

iowrite32(0xffff,  base_addr+S3C2410_ADCDLY);

iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);


/* Initialise input stuff */

input_dev = input_allocate_device();


if (!input_dev)

{

printk(KERN_ERR "Unable to allocate the input device !!n");

return -ENOMEM;

}


dev = input_dev;

dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);

dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);

input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);

input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);

input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);


dev->name = tq2440ts_name;

dev->id.bustype = BUS_RS232;

dev->id.vendor = 0xDEAD;

dev->id.product = 0xBEEF;

dev->id.version = S3C2410TSVERSION;


if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM, tq2440ts_name, dev))

{

printk(KERN_ERR "tq2440_ts.c: Could not allocate ts IRQ_ADC !n");

iounmap(base_addr);

return -EIO;

}

if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM, tq2440ts_name, dev))

{

printk(KERN_ERR "tq2440_ts.c: Could not allocate ts IRQ_ADC !n");

iounmap(base_addr);

return -EIO;

}


printk(KERN_INFO "%s successfully loadedn", tq2440ts_name);


input_register_device(dev);


return 0;

}


static void __exit tq2440ts_exit(void)

{

disable_irq(IRQ_ADC);

disable_irq(IRQ_TC);

free_irq(IRQ_TC,dev);

free_irq(IRQ_ADC,dev);


if (adc_clock)

{

clk_disable(adc_clock);

clk_put(adc_clock);

adc_clock = NULL;

}


input_unregister_device(dev);

iounmap(base_addr);

}



module_init(tq2440ts_init);

module_exit(tq2440ts_exit);


其实就是将此驱动程序编译进内核中,使内核支持触摸功能,可以采用编译成模块,加载进内核的方式,也可以直接编译进内核。此处采用第二种方式。

修改同目录下的“Kconfig”和“Makefile”文件。

在 Kconfig 文件的 468 行添加如下内容:


config TOUCHSCREEN_TQ2440

tristate "EmbedSky TQ2440 TouchScreen input driver"

depends on ARCH_S3C2410 && INPUT && INPUT_TOUCHSCREEN

help

Say Y here if you have the TQ2440 TouchScreen.

and depends on TQ2440_ADC

If unsure, say N.

To compile this driver as a module, choose M here: the

module will be called tq2440_ts.


在 Makefile 文件的最后添加如下内容:


obj-$(CONFIG_TOUCHSCREEN_TQ2440) += tq2440_ts.o


2、配置内核

System Type —>

[ ] ADC common driver support

Device Drivers —>

Input device support —>

[* ] Touchscreens —>

<*> EmbedSky TQ2440 TouchScreen input driver

配置完毕后,保存配置,然后编译内核,烧写镜像到开发板中,内核就能够支持触摸功能了。但是现在还没有移植QT,所以无法使用触摸功能,接下来配置一下QT。


3、文件系统中添加Qte

首先要制作带有Qte的文件系统,此处直接从天嵌科技提供的文件系统(rootfs_2.6.30.4 的文件系统)源码里面复制:“/opt/”目录和“/root/”目录到自己建立的文件系统里面,替换掉以前的目录。使用的qtopia 是 2.2.0 版本的。

然后再在文件系统的“/bin/”目录下面新建一个名为:“qtopia”的可执行文件,内容如下:


#!/bin/sh

echo Start Qtopia-2.2.0 > /dev/tq2440_serial0

if [ -f /etc/pointercal ] ; then

$QPEDIR/bin/qpe > /dev/null 2>/dev/null

else

ts_calibrate

$QPEDIR/bin/qpe > /dev/null 2>/dev/null

fi


添加可执行权限:


chmod  u+x  qtopia


修改“/etc/init.d/rcS”文件,下面列出新添加的内容:


PATH=/sbin:/bin:/usr/sbin:/usr/bin

runlevel=S

prevlevel=N

umask 022

export PATH runlevel prevlevel

#

#Trap CTRL-C &c only in this shell so we can interrupt subprocesses.

#

mount -a

mkdir /dev/pts

mount -t devpts devpts /dev/pts

echo /sbin/mdev > /proc/sys/kernel/hotplug

mdev -s

mkdir -p /var/lock

mkdir /dev/fb /dev/v4l

ln -s /dev/fb0 /dev/fb/0

ln -s /dev/video0 /dev/v4l/video0

ln -s /dev/ts0 /dev/h3600_tsraw #建立一个触摸设备的链接


export set TSLIB_TSDEVICE=/dev/event0

export set TSLIB_CONFFILE=/etc/ts.conf

export set TSLIB_PLUGINDIR=/lib/ts

export set TSLIB_CALIBFILE=/etc/pointercal

export set HOME=/root

export set QTDIR=/opt/Qtopia

export set QPEDIR=/opt/Qtopia

export set KDEDIR=/opt/kde

export set QWS_KEYBOARD="TTY:/dev/tty1"

export set QWS_MOUSE_PROTO="TPanel:/dev/event0 USB:/dev/mouse0"

export set PATH=$QPEDIR/bin: $PATH

export set LD_LIBRARY_PATH= $QTDIR/lib: $QPEDIR/lib


qtopia & #启动 Qte 的脚本,上面几行是设置 QT 的环境变量

/bin/hostname -F /etc/sysconfig/HOSTNAME


然后复制 tslib 的相关文件到新建的文件系统中:

复制“ts.conf”文件到新建的文件系统的“etc/”目录下,“ts.conf”文件的内容如下:

#Uncomment if you wish to use the linux input layer event interface

module_raw input

#Uncomment if you’re using a Sharp Zaurus SL-5500/SL-5000d

#module_raw collie

#Uncomment if you’re using a Sharp Zaurus SL-C700/C750/C760/C860

#module_raw corgi

#Uncomment if you’re using a device with a UCB1200/1300/1400 TS interface

#module_raw ucb1x00

#Uncomment if you’re using an HP iPaq h3600 or similar

#module_raw h3600

#Uncomment if you’re using a Hitachi Webpad

#module_raw mk712

#Uncomment if you’re using an IBM Arctic II

#module_raw arctic2

module pthres pmin=1

module variance delta=30

module dejitter delta=100

module linear


复制可执行程序“ts_calibrate”到新建的文件系统的“sbin/”目录下,这是触摸校正程序;

推荐阅读

史海拾趣

艾吉芯(Agertech)公司的发展小趣事

在电子行业的快速发展中,艾吉芯公司凭借其在半导体芯片研发领域的深厚积累,成功推出了一系列高性能的半导体分立器件。这些产品不仅满足了市场对功率半导体的高效、稳定需求,更在技术创新方面取得了显著突破。艾吉芯公司通过持续的研发投入和严格的生产质量控制,确保了产品的可靠性和竞争力,逐渐在市场中树立起了良好的口碑。

Digital公司的发展小趣事

随着业务的不断发展和市场的不断扩大,DIALIGHT公司逐渐实现了全球化布局。他们在美国、英国、丹麦、德国、马来西亚、新加坡、澳大利亚、墨西哥和巴西等地设立了分支机构或办事处,为全球客户提供及时、高效的服务。此外,DIALIGHT还积极寻求与其他企业的合作与共赢,通过战略合作协议的签署,为双方带来新的业务机遇和合作空间。这些举措不仅增强了DIALIGHT的市场竞争力,也为其未来的发展奠定了坚实的基础。

请注意,由于篇幅限制,以上三个故事仅为DIALIGHT公司发展历程的简要概述。如需更详细的信息和更多故事,建议查阅相关资料或访问公司官网。

Decawave公司的发展小趣事

在2015年的微软室内定位大赛中,Decawave的UWB技术大放异彩。公司凭借其高精度、低误差的UWB定位解决方案,在激烈的竞争中脱颖而出,荣获最佳无线电定位解决方案奖。这一荣誉不仅证明了Decawave在UWB技术领域的领先地位,也为其在市场上的推广和应用奠定了坚实的基础。

Broadband公司的发展小趣事

作为一家技术驱动的公司,Decawave始终将创新作为公司发展的核心动力。公司不断投入研发资源,推动UWB技术的升级和演进。通过不断的技术创新和产品升级,Decawave的UWB技术不断取得新的突破和进展,为电子行业的发展注入了新的活力。同时,公司也积极关注市场动态和客户需求的变化,不断调整和优化其产品和解决方案,以更好地满足客户的需求和期望。

富芯森美(FUXINSEMI)公司的发展小趣事

随着新能源汽车产业的快速发展,富芯森美敏锐地捕捉到了这一市场机遇。公司投入大量资源研发车规级功率半导体器件,产品设计遵循APQP标准,制造管理符合IATF 16949要求,质量检验则严格遵循AEC-Q101标准。这些举措使得富芯森美的车规级产品能够满足汽车行业的严苛要求,成功打入新能源汽车供应链体系,为公司带来了新的增长点。

DILABS公司的发展小趣事

随着全球环保意识的提高,DILABS开始注重绿色生产。他们引入了先进的环保技术和设备,确保在生产过程中最大限度地减少废弃物和污染物的排放。同时,DILABS还积极推动电子产品的环保设计,帮助客户实现绿色采购和可持续发展。

问答坊 | AI 解惑

单片机开发调试应注意的问题

如何用keil调试时计算延时的方法|单片机系统设计与C51编程实践|C51单片机开发工具DIY|实战msp430B捕获PWM波的脉冲宽度|EMC8BIT单片机指令应用的误区与技巧|EM78系列单片机的子程序库|单片机系统开发的规范化问题|PWM技术在单片机控制智能充电器中的 ...…

查看全部问答>

示波器测晶振输出

请问有源晶振的输出信号,用示波器能测出来吗?探头如何选择?…

查看全部问答>

IP核的问题,救命!!!!

你好,我想问下有人是否用过ALTERA公司的免费IP核啊?我用了这个核进行了软件仿真和硬件下载,可是下载到硬件是老是出现一个问题,对话框里是这样的,而且没有关闭对话框的地方:希望高手可以尽快给回答下好吗?谢谢啊!      &nbs ...…

查看全部问答>

串口数据入库问题

我想将从串口读的数据入到CE设备上的数据库中,请问我应该如何做?EVC有专门的串口类吗?…

查看全部问答>

有人转让恩智浦LPC1114 & LPC1343开发板吗

有人转让论坛里送的恩智浦LPC1114 & LPC1343开发板吗?报个价给俺…

查看全部问答>

什么情况,TI教室出错了?个人资料里面怎么显示的真实姓名为账号呢?

什么情况,TI教室出错了?个人资料里面怎么显示的真实姓名为账号呢?…

查看全部问答>

CCS 连接出错

Error connecting to the target: Error 0x80000200/-1037 Fatal Error during: OCS, PTI_ERR_EMU_CLOSE Error Occured at 0x00000000…

查看全部问答>

深度了解16位8通道同步采样数据采集系统AD7606

深度了解16位8通道同步采样数据采集系统AD7606呵呵,好资料,点击直接下载…

查看全部问答>

我想问一下电子称有什么可创新的地方吗

请问做个电子称够分量参加大学生创新项目吗,现在一直在纠结这个问题,想做电子称,但是找不到创新点,…

查看全部问答>