【TINY4412】嵌入式Linux LED驱动程序编写

主要步骤

  • 烧录内核及根文件系统
  • 用《从 0 开始学 Linux 驱动开发(一)》中的步骤做初步尝试
  • 驱动程序分析
  • 配置WDT定时器(ledwdt.c)
  • 编写各个驱动操作函数
  • 编写应用程序(ledwdt_demo.c)
  • 编译驱动并传到开发板中
  • 参考资料

烧录内核及根文件系统

  1. 重新编译内核
    (1)在模块运行之前,为了消除内核中自带的LED模块的影响,需要将自带的LED模块关掉:
make menuconfig

【TINY4412】嵌入式Linux LED驱动程序编写_第1张图片

【TINY4412】嵌入式Linux LED驱动程序编写_第2张图片

【TINY4412】嵌入式Linux LED驱动程序编写_第3张图片

(2)在编写驱动之前,因为友善之臂将LED灯的驱动默认加载到内核中,所以需要先把内核自带的watch dog模块裁剪掉,要不然会出现错误:
Device Drivers/ Watchdog Timer Support/ S3C2410 Watchdog中;
【TINY4412】嵌入式Linux LED驱动程序编写_第4张图片

(3)保存退出之后,重新make成zImage文件。

  1. 烧录内核及根文件系统
    在终端输入:
fastboot
sudo fastboot flash kernel zImage

在这里插入图片描述

sudo fastboot flash ramdisk ramdisk-u.img

【TINY4412】嵌入式Linux LED驱动程序编写_第5张图片

sudo fastboot flash fat rootfs_qtopia_qt4.img

【TINY4412】嵌入式Linux LED驱动程序编写_第6张图片

下载内核和根文件系统镜像后:

sudo fastboot reboot

【TINY4412】嵌入式Linux LED驱动程序编写_第7张图片

用《从 0 开始学 Linux 驱动开发(一)》中的步骤做初步尝试

原文地址:https://paper.seebug.org/779/

  1. 创建新文件夹:在*/home/dy/tiny4412/kernel/linux-3.5/drivers*目录下;
mkdir hello
  1. 使用教程中的代码,但要Makefile中的修改路径:
KERN_DIR ?= /home/dy/tiny4412/kernel/linux-3.5

【TINY4412】嵌入式Linux LED驱动程序编写_第8张图片

如果不修改,insmod .ko文件时会报错,这是因为编译内核的交叉编译器和内核不匹配,导致有些参数不兼容。错误如下:
在这里插入图片描述

  1. 在./hello下编译,生成hello.ko文件;
make

在这里插入图片描述

  1. 用minicom传输文件

(1)设置Filenames and paths;

minicom -s

【TINY4412】嵌入式Linux LED驱动程序编写_第9张图片

(2)在*/tmp*下输入命令:

rx hello.ko

在这里插入图片描述

(3)在minicom终端中CTRL+A Z,选S,选择传输协议 xmodem ,就可以选择PC机上的hello.ko(用空格选中传输文件);

(4)传输完毕后可在*/tmp*目录下看到hello.ko。
在这里插入图片描述

  1. 加载内核模块:
insmod hello.ko

在这里插入图片描述

  1. 查看当前已经被加载的内核模块:
lsmod

【TINY4412】嵌入式Linux LED驱动程序编写_第10张图片

  1. 移除模块
rmmod

驱动程序分析

  1. 设备号

(1)主次设备号
一个字符设备或块设备都有一个主设备号和一个次设备号。主设备号用来标识与设备文件相连的驱动程序,用来反映设备类型;次设备号被驱动程序用来辨别操作的是哪个设备,用来区分同类型的设备。
在这里插入图片描述

(2)分配设备号
【TINY4412】嵌入式Linux LED驱动程序编写_第11张图片

(3)初始化并添加cdev
【TINY4412】嵌入式Linux LED驱动程序编写_第12张图片

(4)设备注销
在这里插入图片描述

  1. 数据结构

(1)struct file
代表一个打开的文件描述符,系统中每一个打开的文件在内核中都有一个关联的struct file。它由内核在open时创建,并传递给在文件上操作的任何函数,直到最后关闭。当文件的所有实例都关闭之后,内核释放这个数据结构。
【TINY4412】嵌入式Linux LED驱动程序编写_第13张图片

(2) struct inode
用来记录文件的物理信息。它和代表打开的file结构是不同的。一个文件可以对应多个file结构,但只有一个inode结构。inode一般作为file_operations结构中函数的参数传递过来。

(3) struct file_operations
结构体file_operations在头文件 linux/fs.h中定义,用来存储驱动内核模块提供的对设备进行各种操作的函数的指针。该结构体的每个域都对应着驱动内核模块用来处理某个被请求的事务的函数的地址。
【TINY4412】嵌入式Linux LED驱动程序编写_第14张图片

配置WDT定时器(ledwdt.c)

  1. 看门狗功能
    (1)当作常规时钟,可以产生中断;
    (2)当看门狗定时器使用,当计数器WTCNT为0时,产生复位。

  2. 看门狗定时器

(1)看门狗定时器功能框图如下:
【TINY4412】嵌入式Linux LED驱动程序编写_第15张图片

看门狗模块包括一个预比例因子放大器,一个四分频的分频器,一个16位计数器。看门狗的时钟信号源来自PCLK,为了得到宽范围的看门狗信号,PCLK先被预分频,然后再进过分频器分频。预分频比例因子和分频器的分频值,都可以由看门狗控制寄存器(WTCON)决定,预分频比例因子的范围是0~255,分频器的分频比可以是16、32、64或128。

(2)看门狗定时器时钟周期
看门狗定时器时钟周期的计算如下:
在这里插入图片描述

t_watchdog表示看门狗计数计时器WTCNT每减少1所用的时间,WTCNT相当于一个节拍的作用,当WTCNT=0时,如果看门狗控制寄存器WTCON[0]开启复位功能,则复位;如果看门狗控制寄存器WTCON[0]禁止复位功能,开启中断,则中断操作,并将数据寄存器WTDAT中的值重新赋值到计数寄存器WTCNT内,循环中断操作。

  1. 看门狗定时器相关寄存器

(1)看门狗定时器控制寄存器(WTCON)
WTCON寄存器的内容包括:用户是否启动看门狗定时器、4个分频比的选择、是否允许中断产生、是否允许复位操作等。如果用户想把看门狗定时当作一般定时器使用,应该使能中断功能,禁止看门狗定时器复位。 WTCON描述如下:
【TINY4412】嵌入式Linux LED驱动程序编写_第16张图片

(2)看门狗定时器数据寄存器(WTDAT)
WTDAT用于指定超时时间。在看门狗把复位功能禁止并打开中断使能后,此时看门狗定时器就是一个普通的定时器,使用方法和普通定时器一样。当使用复位功能后,由于WTCNT的值减到0时,系统就会复位,所以WTCNT的值装不进看门狗计数寄存器WTCNT中。WTDAT描述如下:
在这里插入图片描述

(3)看门狗计数寄存器(WTCNT)
WTCNT包含看门狗定时器工作的时候,计数器的当前计数值。WTCNT描述如下:
在这里插入图片描述

  1. 在驱动程序中添加看门狗定时器的配置
    【TINY4412】嵌入式Linux LED驱动程序编写_第17张图片

(1)request_irq( )用来注册中断服务,函数原型为:

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)

irq:要申请的硬件中断号,对应IRQ_WDT;
handler:向系统注册的中断处理函数,对应do_irq;
irqflags:中断处理的属性,这里的IRQF_SHARED表示多个设备共享中断;
devname:设置中断名称,对应led1dog;
dev_id:在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL,这里设置为0x1111。
需要在入口函数中注册中断,回调中断处理函数。

(2)ioremap( )用来将I/O内存资源的物理地址映射到核心虚地址空间(3GB-4GB)中(这里是内核空间),函数原型为:
void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags)

phys_addr:要映射的起始的IO地址;
size:要映射的空间的大小;
flags:要映射的IO空间和权限有关的标志。

  1. 中断处理函数:实现了让LED闪烁的功能
    【TINY4412】嵌入式Linux LED驱动程序编写_第18张图片

  2. 释放中断调用
    在这里插入图片描述

编写各个驱动操作函数

  1. read( )函数
    【TINY4412】嵌入式Linux LED驱动程序编写_第19张图片

(1)函数原型
ssize_t (*read) (struct file * filp, char __user * buffer, size_t size , loff_t * p)

filp:为进行读取信息的目标文件,对应fops
buffer:为对应放置信息的缓冲区(即用户空间内存地址),对应usr;
size:为要读取的信息长度;
p:为读的位置相对于文件开头的偏移,在读取信息后,这个指针一般都会移动,移动的值为要读取信息的长度值,对应pos。

(2)Copy_to_user( to, &from, sizeof(from))函数
To:用户空间函数(可以是数组);
From:内核空间函数(可以是数组);
sizeof(from):内核空间要传递的数组的长度。

  1. write( )函数
    【TINY4412】嵌入式Linux LED驱动程序编写_第20张图片

(1)函数原型
ssize_t (*write) (struct file * filp, const char __user * buffer, size_t count, loff_t * ppos)

filp:为目标文件结构体指针,对应fops;
buffer:为要写入文件的信息缓冲区,对应buf;
count:为要写入信息的长度;
ppos:为当前的偏移位置,这个值通常是用来判断写文件是否越界,对应pos。

(2)Copy_from_user(&from , to , sizeof(to) )函数
To:用户空间函数(可以是数组);
From:内核空间函数(可以是数组);
sizeof(from):内核空间要传递的数组的长度。

  1. 在设备操作合集中加入read和write
    【TINY4412】嵌入式Linux LED驱动程序编写_第21张图片

编写应用程序(ledwdt_demo.c)

  1. 建立设备文件名;
    【TINY4412】嵌入式Linux LED驱动程序编写_第22张图片

  2. 调用read( )函数:利用read函数读出指定LED的状态,输出状态信息;
    【TINY4412】嵌入式Linux LED驱动程序编写_第23张图片

网上的参考代码在调用read函数时,把传递的信息长度设为2,导致led3和led4无法输出状态信息。改为4后就可以成功读取信息。参考代码如下图所示:
【TINY4412】嵌入式Linux LED驱动程序编写_第24张图片

  1. 调用write( )函数:利用write函数控制控制制定LED的状态。
    【TINY4412】嵌入式Linux LED驱动程序编写_第25张图片

编译驱动并传到开发板中

  1. 修改Makefile路径,并在最后加上ledwdt_demo的编译信息;
    【TINY4412】嵌入式Linux LED驱动程序编写_第26张图片

  2. 编译生成ledwdt.ko和ledwdt_demo可执行文件;

make
make ledwdt_demo

在这里插入图片描述

  1. 将文件传到开发板上

(1)打开minicom,设置文件路径:

minicom -s

【TINY4412】嵌入式Linux LED驱动程序编写_第27张图片

选择Filenames and paths,设置Upload directory:
/home/dy/tiny4412/kernel/linux-3.5/drivers/ledwdt
【TINY4412】嵌入式Linux LED驱动程序编写_第28张图片

(2)进入文件系统:

cd tmp/

在这里插入图片描述

(3)输入命令:

rx ledwdt.ko

CTRL+A Z,出现如下界面:
【TINY4412】嵌入式Linux LED驱动程序编写_第29张图片

(4)输入S(Send files),选择xmodem,传输成功;
在这里插入图片描述

【TINY4412】嵌入式Linux LED驱动程序编写_第30张图片

(5)按照相同步骤传输ledwdt_demo文件,/tmp目录下出现这两个文件:
在这里插入图片描述

  1. 运行.ko文件

(1)

insmod ledwdt.ko

LED1开始闪烁。之前在驱动代码里write( )函数中选择在内核中打印LED1闪烁的信息,但在minicom中无法停止打印,所以删去了那行代码。
在这里插入图片描述

(2)

lsmod

出现ledwdt
【TINY4412】嵌入式Linux LED驱动程序编写_第31张图片

  1. 运行可执行文件

(1)给ledwdt_demo增加可执行权限:

chmod u+x ledwdt_demo

在这里插入图片描述

(2)运行ledwdt_demo:

./ledwdt_demo

【TINY4412】嵌入式Linux LED驱动程序编写_第32张图片

  1. 删除.ko文件
rmmod ledwdt

不要加.ko!
在这里插入图片描述

参考资料

[1] https://blog.csdn.net/weixin_37771089/article/details/84988642
[2] http://blog.knownsec.com/2019/01/从-0-开始学-linux-驱动开发一/
[3] https://blog.csdn.net/liu454638324/article/details/40433529
[4] https://blog.csdn.net/muyang_ren/article/details/38090417
[5] https://blog.csdn.net/qq_21593899/article/details/51713740
[6] https://www.cnblogs.com/wenqiang/p/4781499.html
[7] https://blog.csdn.net/z961968549/article/details/78512230
[8] https://blog.csdn.net/morixinguan/article/details/50619675
[9] http://www.cnblogs.com/geneil/archive/2011/12/03/2272869.html

你可能感兴趣的:(TINY4412)