一、Study16DV300的常用外设详解
1.1 说明
刚好拿来做设备树的这样一个平台来讲解了,在设备树的课程里面,已经把大部分的内核驱动的东西都已经分析了
大部分驱动,使用的虽然是4.9的内核,比2.6.35的内核比较新,但是驱动部分基本没什么变化
所以就挑了一个经典的,在核心课程一期里面讲解过,但是设备树课程里面又没讲过,并且这个平台的驱动还是有点问题
后面再讲解一个根文件系统的课程,因为这根文件系统是比较复杂的,特别是启动后,加载ko,启动双摄显示的例子
1.2 Hi3516DV300内核驱动的一般分析
看这个课程之前,一定要先看设备树课程,也就是嵌入式核心课程二期,设备树专题
因为这个设备树课程是先讲设备树的这样一个原理的,而我们的Hi3516DV300这个平台,它的驱动,就使用了设备树,所以不先看那个课程,直接来看这个课程,就会比较懵。
- Hi3516DV300内核驱动的一般分析
设备树和U-boot是有一定的关联的,在Hi3516DV300这样一个平台,U-boot没有使用设备树,而内核使用了设备树机制,关于这个U-boot可用可不用,用和不用的区别,在设备树课程里面讲得非常详细,源码级的解读。
GPIO,串口,I2C等SOC内置外设的驱动,都是用了设备树机制,严格按照设备驱动框架
核心课程一期,跟具体的芯片有关,跟具体的外设芯片有关,但是在Hi3516DV300里面,不管是串口,还是GPIO什么的,好像都和ARM有关,用的都是ARM公司的一些芯片,为什么呢?因为ARM公司在更高级的芯片里面,把这些东西标准化了;也就是说,不仅仅是做产品的,我们拿别人的芯片做产品的人,我们不用去写驱动了,甚至连芯片厂商都不用去写驱动了。
驱动谁来写
一开始是做产品的公司
后面是芯片原厂
再后来是ARM公司
所以:
像海思这样的半导体厂商,他出这样的芯片的时候呢,甚至这里面的很多驱动,他都不用去提供。
他买过来的ARM内核设计,本身就附带有这样的驱动,如果你的GPIO,串口用的就是ARM这边的标准控制器,你这边实际上是可以直接用它的驱动的
层次越高,就越讲规矩,就约不会胡乱来
内部外设的驱动很多都是ARM标准的,譬如GPIO和串口,详情见《详解linux设备树全集》
外部外设驱动有些用了设备树,也有些没有,取决于具体BSP工作者;
原始版本来自:触摸屏厂商
2.6.54版本的内核,不能使用设备树,因为内核都不支持
4.9版本的内核,内核用了设备树,触摸屏驱动可以用设备树,也可以不用设备树
触摸只是用来传参的,如果传参要求优雅,那么可以使用设备树,如果不要求传参优雅,那么可以不用设备树。
用不用,区别都不大,如果是触摸屏芯片厂商的工程师,要求提供标准的玩法,或者是想给Linux内核贡献一个标准版本驱动的补丁,这个是应该使用设备树的;这种做法是比较正统的。
如果只是产品公司的工程师,只是因为产品用了这个触摸屏的芯片,拿过来,只是希望产品能够work,这个时候可以不用,因为用的时候比较麻烦一点,不用的话,就比较省心,简单粗暴,所以很多板卡厂商很多时候就不用设备树。
我们买的这个开发板,就没有使用设备树
芯片内部的:都和GPIO,串口类似
芯片外部的:都和触摸屏这种是类似的
1.3 Study16DV300的触摸屏驱动测试
1.3.1 先进行测试
先进行触摸屏测试,这里没有event开头的,所以这里是没有触摸屏的
没有的原因是因为:根文件系统里面,配置触摸屏这个地方,就配错了
这里是把触摸屏驱动,单独编译为一个.ko文件了,然后,在根文件系统里面,添加了insmod命令去加载模块
但是装载错了
所以,要修改一下,去insmod这个
那么,为什么是装载这个呢?
可以从编译完成了的那里面来找:可以从Ubuntu里面找,或者从板子这边找;现在先从板子这边找:
这三个都是触摸屏的驱动,现在先装载gslx680.ko这个驱动
修改好了之后,就进行重启
重启之后,就会加载这个event0
然后,去cat这个event0
这个时候,按触摸屏,就会有反应,差不多是对的
按这个触摸屏的时候,硬件本身会触发一个中断,从而触发驱动
如果i2c接口是对的,i2c驱动工作正常,数据是能从触摸屏芯片,到我们监听接口这边来的,只是这个数据,我们这边直接看,是看不到的,也就是说这个数据目前对不对,我们是不知道的。
1.3.2 编写ts_app.c,并交叉编译,丢进去运行,打印触摸坐标,看对不对。
- 编写应用代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <string.h>
#include <unistd.h>
//首先宏定义了我们的设备文件,设备文件号,好和具体的去对应的
#define DEVICE_KEY "/dev/input/event1"
#define DEVICE_MOUSE "/dev/input/event3"
#define X210_KEY "/dev/input/event1"
#define X210_TS "/dev/input/event2"
//注意设备文件是event0
#define Study16DV300_TS "/dev/input/event0"
int main(void)
{
int fd = -1, ret = -1;
int flag = 0;
struct input_event ev;
// 第1步:打开设备文件
fd = open(Study16DV300_TS, O_RDONLY);
if (fd < 0)
{
perror("open");
return -1;
}
//在这里循环地去读取它
while (1)
{
// 第2步:读取一个event事件包
memset(&ev, 0, sizeof(struct input_event));
//每一个输入类设备,都是一个标准的input event事件
//每次过来的一包数据,都是一个标准的struct input_event
//所以我们去read,因为这种输入类设备都是阻塞式的,如果没有按下触摸屏,那么就会在read的时候阻塞
//当触摸屏芯片给了我们数据之后,然后我们的驱动就会向上report,这个report数据就会把我们的read函数给解冻
//把它给激活,激活后,就能读下来了,读下来之后,就去校错
ret = read(fd, &ev, sizeof(struct input_event));
if (ret != sizeof(struct input_event))
{
perror("read");
close(fd);
return -1;
}
#if 0
// 第3步:解析event包,才知道发生了什么样的输入事件
//如果没有问题,那就先打印出来
printf("-------------------------\n");
//消息类型
printf("type: %hd\n", ev.type);
//编码
printf("code: %hd\n", ev.code);
//值
printf("value: %d\n", ev.value);
printf("\n");
#endif
//电容触摸屏的意思
if (ev.type == EV_ABS)
{
switch (ev.code)
{
case ABS_MT_POSITION_X:
flag = 1;
printf("x = %d, ", ev.value);
break;
case ABS_MT_POSITION_Y:
flag = 0;
printf("y = %d\r\n", ev.value);
printf("-------------------------\n");
break;
default:
break;
}
}
}
// 第4步:关闭设备
close(fd);
return 0;
}
- 先把文件放到Ubuntu里面
首先放到Ubuntu里面去,并且,这个目录,已经通过nfs进行共享了
- 在开发板里面,挂载nfs文件系统
mount -t nfs -o nolock 192.168.1.141:/home/aston/rootfs /mnt
- 在开发板里面,进入到mnt目录
这个是已经编译好的
- 用共享文件夹,进行编译
工具链的名称是:arm-himix200-linux-gcc
交叉编译的命令是:arm-himix200-linux-gcc app_input.c -o myapp
- 交叉编译后,生成了myapp
- 拷贝到nfs文件夹下
- 然后,在板子上面,就有这个文件了
- 然后,就有效果了
数据不对,y的数值变大,又变小
测试结论:
(1)触摸硬件基本完好,底层I2C通信完好,坐标范围是:1280X800
(2)推测:触摸屏驱动底层都工作了,但是坐标上报不对,分辨率配置不对
与硬件有关的东西,都是没问题的,只是上层不对
很要求你能够冷静地分析