本篇内容主要讲解“Linux driver怎么配置使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux driver怎么配置使用”吧!
成都创新互联是一家专业提供通城企业网站建设,专注与做网站、网站设计、H5开发、小程序制作等业务。10年已为通城众多企业、政府机构等服务。创新互联专业网站制作公司优惠进行中。
AM335x触摸屏控制器支持如下四种工作模式:
• 8路通用的ADC
• 4路作为4线触摸屏连接,4路作为通用ADC
• 5路作为5线触摸屏连接,3路作为通用ADC
• 8路作为8线触摸屏连接
ADC采用的是12位SAR ADC, 采样速率为每秒200k次. AD采样模拟信号是从start of conversion为高时开始并在下降沿后的1个时钟周期内继续采样. 它在采样周期结束时捕获模拟信号并启动转换. 它在12个时钟周期内将采样数据数字化,当end of conversion信号被使能为高时, 表明数据ADCOUT<11:0>已可读. 当以前的数据被读取后一个新的转换周期就可以开始了。 请注意,ADC输出的是加权的二进制数据
4线触摸屏的连接
5线触摸屏连接
8线触摸屏连接
Device Drivers ---> [*] Staging drivers ---> [*] Industrial I/O support ---> [*] Enable buffer support within IIO <*> Industrial I/O lock free software ring < > Industrial I/O buffering based on kfifo -*- Enable triggered sampling support (2) Maximum number of consumers per trigger Analog to digital converters ---> <*> TI's ADC driver
这里<*> TI's ADC driver 是直接编译进内核, 如果只是想编译为模块则可以点击空格更改为
在arch/arm/mach-omap2/board-am335xevm.c(我的板子是board-com335x.c)里添加如下代码:
#includestatic struct adc_data am335x_adc_data = { .adc_channels = 4, }; static struct mfd_tscadc_board tscadc = { .tsc_init = &am335x_touchscreen_data, .adc_init = &am335x_adc_data, };
如果你要同时使用adc和触摸屏的话照上边这样设置即可.
如果只使用adc则要移除触摸屏的平台数据(platform data),如下所示:
static struct adc_data am335x_adc_data = { .adc_channels = 8, }; /* static struct tsc_data am335x_touchscreen_data = { .wires = 4, .x_plate_resistance = 200, .steps_to_configure = 5, }; */ static struct mfd_tscadc_board tscadc = { /* .tsc_init = &am335x_touchscreen_data, */ .adc_init = &am335x_adc_data, };
将直流电压连接到AIN0到AIN7的引脚上(你使用了哪个就接在哪个引脚),千万注意测试电压只能在0~1.8v之间
3.1 查看IIO设备
root@arago-armv7:~# ls -al /sys/bus/iio/devices/iio\:device0/ drwxr-xr-x 5 root root 0 Jan 1 00:00 . drwxr-xr-x 4 root root 0 Jan 1 00:00 .. drwxr-xr-x 2 root root 0 Jan 1 00:00 buffer -r--r--r-- 1 root root 4096 Jan 1 00:00 dev -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage0_raw -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage1_raw -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage2_raw -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage3_raw -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage4_raw -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage5_raw -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage6_raw -r--r--r-- 1 root root 4096 Jan 1 00:00 in_voltage7_raw -rw-r--r-- 1 root root 4096 Jan 1 00:00 mode -r--r--r-- 1 root root 4096 Jan 1 00:00 name drwxr-xr-x 2 root root 0 Jan 1 00:00 power drwxr-xr-x 2 root root 0 Jan 1 00:00 scan_elements lrwxrwxrwx 1 root root 0 Jan 1 00:00 subsystem -> ../../../../../../bus/iio -rw-r--r-- 1 root root 4096 Jan 1 00:00 uevent
3.2 单次模式
检查ADC模式, 如下所示即为单次模式
cat /sys/bus/iio/devices/iio\:device0/mode oneshot
如果不是单次模式可以使用如下命令更改
Echo onesht > /sys/bus/iio/devices/iio\:device0/mode
从某一端口读取ADC输出数据:
in_voltageX_raw: raw value of the channel X of the ADC
从以下命令可知in_voltageX_raw里保存的就是ADC的原始数据, 4095即满量程数据
root@arago:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw 4095
D = Vin * (2^n - 1) / Vref
比如读取回来ADC的数据是2298那么输入电压就是
Vin = D / ((2^n - 1) / Vref)
Vin = 2298 / ((2^12 – 1) / 1.8)
Vin = 1.01V
相关资料:
1 AM335x ADC Driver's Guide http://www.deyisupport.com/question_answer/w/faq/469.am335x-linux.aspx
2 AM335X 触摸屏的硬件连接及Linux驱动
http://ti.eetop.cn/viewnews-4453
3 Using resistive touch screens for human/machine interface
http://www.ti.com/lit/an/slyt209a/slyt209a.pdf
因为触摸屏使用的是input子系统所以要讲解触摸屏之前首先要讲解一下input子系统, 它的核心文件是input.c
Input子系统结构与功能实现
1 Input子系统是分层结构的,总共分为三层: 硬件驱动层,子系统核心层,事件处理层。
(1)其中硬件驱动层负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,需要驱动程序的作者来编写
(2)子系统核心层是链接其他两个层之间的纽带与桥梁,向下提供驱动层的接口,向上提供事件处理层的接口
(3)事件处理层负责与用户程序打交道,将硬件驱动层传来的事件报告给用户程序
2各层之间通信的基本单位就是事件,任何一个输入设备的动作都可以抽象成一种事件,如键盘的按下,触摸屏的按下,鼠标的移动等。事件有三种属性:类型(type),编码(code),值(value),Input子系统支持的所有事件都定义在input.h中,包括所有支持的类型,所属类型支持的编码等。事件传送的方向是 硬件驱动层-->子系统核心-->事件处理层-->用户空间
3 以触摸屏为例说明输入子系统的工作流程:
注:am335x sdk6的触摸屏驱动所用驱动层对应的模块文件为:ti_tsc.c,事件处理层对应的模块文件为 evdev.c
(1)ti_tsc模块初始化函数中将触摸屏注册到了输入子系统中,于此同时,注册函数在事件处理层链表中寻找事件处理器,这里找到的是evdev,并且将驱动与事件处理器挂载。并且在/dev/input中生成设备文件event0,以后我们访问这个文件就会找的我们的触摸屏驱动程序。
(2)应用程序打开设备文件/dev/input/event0,读取设备文件,调用evdev模块中read,如果没有事件,进程就会睡眠。
(3)当触摸屏按下,驱动层通过input子系统核心层将事件(就是X,Y坐标, 压感, 按下/松开)传给事件处理层也就是evdev,evdev唤醒睡眠的进程,将事件传给进程处理。
下边看下代码流程:
input_init() class_register register_chrdev(INPUT_MAJOR, "input", &input_fops); 可以看到input子系统帮我们写了以上两个函数, 那么这个input_fops是不是就是我们要填充的file_operations呢? static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, .llseek = noop_llseek, };
这个file_operations并没有read/write等接口, 由此我们可知该结构体只是一个连接上下层的作用, 这是一种分层的思想. 那么他就是通过open成员来连接上下层, 我们来看下open成员做了什么事情:
input_open_file handler = input_table[iminor(inode) >> 5];//使用此设备号拿到handler结构体 new_fops = fops_get(handler->fops); //获取新的file_operations file->f_op = new_fops; //使用handler的fops成员来作为新的file_operations new_fops->open(inode, file); //handler->fops->open(indoe, file)
由此可知: 通过次设备号拿到数组中的handler成员, 就完成了上层的input_fops到底层的真实handler->fops的转换,
底层的handler->fops->open(indoe, file) 就是真实的open, 对应的read/write也是
现在最关键的就是input_table[]数组是怎么来的呢?
通过查找代码发现在 input_register_handler里使用了它, 那么谁调用了这个函数呢? 在input子系统的下边有很多驱动都用到了这个函数, 他们首先查找有没有能匹配的硬件,如果有就调用这个函数将input_handler放入数组里边.
这些驱动在以下的软件部分可以看到:
软件部分
Evdev.c Joydev.c Keyboard.c Mousedev.c等这些就是input子系统向上注册input_handler
input_register_handler input_attach_handler 判断硬件的id_table能否与自己的id_table匹配, 如果匹配这建立连接
硬件部分:
input_register_device input_attach_handler 判断软件的id_table能否与自己的id_table匹配, 如果匹配这建立连接
device和handler在注册的时候都会查找对方是否有可以与自己匹配的, 如果有就调用connect函数来连接彼此.
下边以evdev.c为例来说明软硬件两部分是如何建立连接的:
evdev_connect() evdev->handle.dev = input_get_device(dev); evdev->handle.handler = handler;
在evdev.c中又创建了一个handle结构体他分别指向device和handler, 这样软硬件两边通过这个结构体找到对方.
static struct tsc_data am335x_touchscreen_data = { .wires = 4, //4线触摸屏 .x_plate_resistance = 200, //阻抗200欧姆 .steps_to_configure = 5, //在产生中断之前在fifo中的样本个数, 最大16 };
ti_tsc_init platform_driver_register (&ti_tsc_driver); tscadc_probe input_allocate_device //分配 request_irq input_dev->name = "ti-tsc"; //设置 input_dev->dev.parent = &pdev->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);//可以产生按键类事件/绝对位移类事件 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);//触摸屏触摸屏事件 input_register_device//注册
中断处理函数
tscadc_interrupt tscadc_readl 读取中断状态寄存器, adc与tsc共用一个中断源 判断中断原因然后上报事件 input_report_abs(input_dev, ABS_X, val_x);//x坐标 input_report_abs(input_dev, ABS_Y, val_y);//y坐标 input_report_abs(input_dev, ABS_PRESSURE, z);//压感 input_report_key(input_dev, BTN_TOUCH, 1);//按下/松开 input_sync(input_dev); 检查是否是抬起中断 status = tscadc_readl(ts_dev, TSCADC_REG_RAWIRQSTATUS); if (status & TSCADC_IRQENB_PENUP) input_report_key(input_dev, BTN_TOUCH, 0); input_report_abs(input_dev, ABS_PRESSURE, 0); input_sync(input_dev);
到此,相信大家对“Linux driver怎么配置使用”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!