嵌入式Linux下LED报警灯驱动设计及编程.docx
《嵌入式Linux下LED报警灯驱动设计及编程.docx》由会员分享,可在线阅读,更多相关《嵌入式Linux下LED报警灯驱动设计及编程.docx(17页珍藏版)》请在冰豆网上搜索。
嵌入式Linux下LED报警灯驱动设计及编程
《嵌入式Linux下LED报警灯
驱动设计及编程》
实验报告
学生姓名:
学号:
专业班级:
指导教师:
完成时间:
实验5嵌入式Linux下LED报警灯驱动设计及编程
1.实验目的
理解驱动本质,掌握嵌入式Linux系统下驱动开发相关知识,包括端口寄存器访问、接口函数编写、和文件系统挂接、注册及相关应用编程等知识点。
2.实验内容
实验5.1嵌入式Linux下LED报警灯驱动设计及跑马灯应用编程
实验5.2添加看门狗功能的跑马灯应用编程
3.预备知识
Linux使用、驱动相关知识等
4.实验设备及工具(包括软件调试工具)
硬件:
ARM嵌入式开发平台、PC机Pentium100以上、串口线。
软件:
WinXP或UBUNTU开发环境。
五.实验5.1步骤
5.1前期准备
(1)看懂相关硬件电路图【见S3C6410实验箱电路图-底板.pdf】,以LED报警灯为例进行设计
打开PDF硬件电路图,明确LED灯用到的多个GPIO及其控制器
本实验电路LED1GPM0
LED2GPM1
LED3GPM2
LED4GPM3
LED5GPM4
LED6GPM5
LED7GPQ0
LED8GPQ1
得出结论:
8个LED灯使用到的硬件控制器分别为GPM和GPQ两个硬件控制器
(2)在芯片手册中找到相应的硬件控制器部分,重心是看懂端口寄存器
本实验要求完成LED流水灯设计,所以需要设置控制器中端口寄存器:
GPMCON设置相应位为输出口
GPMDAT控制相应位输出高电平点亮LED灯
输出低电平熄灭LED灯
(3)linux内核中相关寄存器读写函数
读寄存器函数
readl(寄存器虚地址);
写寄存器函数
writel(值(无符号整型),寄存器虚地址);
义在
文件夹下
具体端口寄存器地址宏定/opt/FriendlyARM/linux-2.6.38/arch/arm/mach-s3c64xx/include/mach的文件中,如端口M寄存器在gpio-bank-m.h文件中有定义:
#defineS3C64XX_GPMCON(S3C64XX_GPM_BASE+0x00)
#defineS3C64XX_GPMDAT(S3C64XX_GPM_BASE+0x04)
5.2LED报警灯驱动设计s3c6410_leddrv.c
(1)头文件包含和相关宏定义
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineON1
#defineOFF0
(2)编写驱动接口函数
/*
功能:
配置GPM0~5/GPQ0~1为输出口
参数:
无
返回值:
无
*/
voidLedConfig(void)
{
//读出端口M控制寄存器(S3C64XX_GPMCON)值,修改并写回相关端口寄存器
//addyourcode
unsignedinttmp;
tmp=readl(S3C64XX_GPMCON);
tmp&=
~((0XF<<0X0)|(0XF<<0X4)|(0XF<<0X8)|(0XF<<0XC)|(0XF<<0X10)|(0XF<<0X14));
tmp|=
(0X1<<0X0)|(0X1<<0X4)|(0X1<<0X8)|(0X1<<0XC)|(0X1<<0X10)|(0X1<<0X14);
writel(tmp,S3C64XX_GPMCON);
}
/*
功能:
点亮第i个LED灯
参数:
无符号整型变量iLed,表示第i个LED灯
返回值:
无
*/
voidiLedOn(unsignedintiLed)
{
//读出端口M数据寄存器(S3C64XX_GPKDAT)值,修改并写回相关端口寄存器
//addyourcodehere
unsignedinttmp;
tmp=readl(S3C64XXGPMDAT);
tmp&=
~((0X1<<0X0)|(0X1<<0X1)|(0X1<<0X2)|(0X1<<0X3)|(0X1<<0X4)|(0X1<<0X5));
writel(tmp,S3C64XXGPMDAT);
/*
功能:
熄灭第i个LED灯
参数:
无符号整型变量iLed,表示第i个LED灯
返回值:
无
*/
voidiLedOff(unsignedintiLed)
{
//读出端口M数据寄存器(S3C64XX_GPKDAT)值,修改并写回相关端口寄存器
//addyourcodehere
unsignedinttmp;
tmp=readl(S3C64XXGPMDAT);
tmp&=
~((0X1<<0X0)|(0X1<<0X1)|(0X1<<0X2)|(0X1<<0X3)|(0X1<<0X4)|(0X1<<0X5));
tmp|=
(0X1<<0X0)|(0X1<<0X1)|(0X1<<0X2)|(0X1<<0X3)|(0X1<<0X4)|(0X1<<0X5);
writel(tmp,S3C64XXGPMDAT);
}
(2)和文件系统接口对接
staticints3c6410_led_open(structinode*inode,structfile*filp)
//把之前的端口K控制寄存器值读出来保存起来
//调用LedConfig函数,把GPIO口配置成输出口
//addyourcode
oldgpmconval=readl(S3C64XXGPMCON);
LedConfig();
renturn0;
}
staticints3c6410_led_release(structinode*inode,structfile*filp)
{
//恢复之前的端口K控制寄存器初始值
//addyourcode
writel(oldgpmconval,S3C64XXGPMCON);
renturn0;
}
staticlongs3c6410_led_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
{
switch(cmd)
caseON:
//点亮所有LED灯
//addyourcode
iLedOn();
break;
caseOFF:
〃熄灭所有LED灯
//addyourcodeiLedOff();
break;
}
}
structfile_operationsled_fops=
.open=s3c6410ledopen
.release=s3c6410_led_release
.unlocked_ioctl=s3c6410ledioctl
};
(3)添加模块标记代码
staticint__initled_dev_init(void)
intret;
ret=register_chrdev(O,"leddev",&led_fops)_;//注册设备
printk(DEVICE_NAME"\tinitialized'n");
returnret;
staticvoid__exitled_dev_exit(void)
{
//注销设备//addyourcode
unregisterchrdev(leddevNo,"leddev");.
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lic@njupt.");
5.2编写Makefile并加载到内核
(1)编写Makefile如下:
obj-m:
=leddrv.o_
all:
make-C/opt/FriendlyARM/linux-2.6.38SUBDIRS=$(shellpwd)
modules
clean:
rm-rf*.ko*.o
(3)编译
使用命令编译:
#make
编译完成后生成驱动文件leddrv.ko
(3)加载驱动
使用命令进行驱动加载#insmodleddrv.ko.。
(4)创建设备文件,将驱动设备号和设备文件名关联
相关命令为:
_#mknod/dev/leddevc2530_。
5.3编写应用程序
任务:
要求每5秒点亮所有的LED灯,然后熄灭,过5秒再点亮LED灯
#include
#inelude
#include
#includevfentl.h>
#include
#defineON1
#defineOFF0
voidmain()
{
fd=open(___”/dev/leddev”___,O_RDWR);
if(fd<0)
exit
(1);
while
(1)
{
//点亮LED灯
ioctl(fd,ON);
sleep(5);
//熄灭LED灯
__ioctl(fd,OFF);
sleep(5);
}
close(fd);
}
5.4按照现在的驱动设计,假设要完成LED跑马灯实验,请问是否可行___B___[A.
可行B.不可行]。
如果不可行的话,应该怎样改造驱动代码和应用程序。
驱动代码修改部分:
应用程序修改部分:
六.实验5.2步骤
6.1实验预备知识
(1)相关硬件
看门狗硬件主要用于监控系统软件或者应用软件是否发生故障,如发生故障则可以通过发出硬件复位信号,使得系统能够重启,如果再配合相关自动加载应用程序等措施,则可以保证应用程序在发生故障后能够自恢复和重启。
看门狗硬件由看门狗控制器组成,位于S3C6410处理器内部,无须处理器外其它硬件配合,因此仅需直接编程端口寄存器,并封装成文件系统接口即可。
(2)端口寄存器及相关操作
在内核代码文件中已经定义好看门狗相关端口寄存器对应的虚地址,见/opt/FriendlyARM/linux-2.6.38/arch/arm/plat-samsung/include/plat/regs-watchdog.h,如下:
写寄存器函数
writel(值(无符号整型),寄存器虚地址);
6.2看门狗驱动代码(s3c6410_wdtdrv.c)设计
(1)头文件包含和相关宏定义
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#undefS3C_VA_WATCHDOG
#defineS3C_VA_WATCHDOG(0)
#include
(2)编写驱动接口函数
/*
功能:
打开看门狗,允许复位,禁止看门狗中断,并设置看门狗最长看门时间
参数:
无
返回值:
无
*/
voidWdtConfig(void)
{
//读出看门狗控制寄存器S3C2410_WTCON,保存原值,并按照要求修改
//最后写回看门狗端口控制寄存器S3C2410_WTCON
//addyourcode
unsignedinttmp;
tmp=(0XFF<<8)|(0X0<<6)|(0X1<<5)|(0X2<<3)|(0XFF<<8)|(0X0<<2)|(0X1<<1)|(0XFF<<8)|(
0X1<<0);
writel(tmp,S3C2410_WTCON);
}
(2)和文件系统接口对接
staticints3c6410_wdt_open(structinode*inode,structfile*filp)
//打开看门狗,允许复位,禁止看门狗中断,并设置看门狗最长看门时间
//addyourcode
old_wdtcon_val=readl(S3C2410_WTCON);
WdtConfig();
}
staticssize_ts3c6410_wdt_write(structfile*file,constchar__user*data,size_tlen,loff_t*ppos)
{
//把data指针所指向的用户空间值更新到看门狗计数寄存器S3C2410_WTCNT中
//addyourcode
unsignedintval;
copy_from_user(&val,data,4);
writel(val,S3C2410_WTCNT);
return0;
}
staticints3c6410_wdt_release(structinode*inode,structfile*filp)
{
//恢复之前的看门狗端口控制寄存器的原始值
//addyourcode
writel(old_wdtcon_val,S3C2410_WTCON);
return0;
}
structfile_operationswdt_fops=
{
.open=_s3c6410_wdt_open__,
.release=_s3c6410_wdt_release_,
.write=_s3c6410_wdt_write_,
};
(3)添加模块标记代码
staticint__initwdt_dev_init(void)
{
注册设备
intret;
ret=__register_chrdev(0,"wdtdev",&wdt_fops)
printk(DEVICE_NAME"\tinitialized\n");
returnret;
}
staticvoid__exitwdt_dev_exit(void)
{
//注销设备
//addyourcode
unregister_chrdev(wdtdevNo,"wdtdev");
}
module_init(wdt_dev_init);
module_exit(wdt_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lic@njupt.");
5.2编写Makefile并加载到内核
(1)编写Makefile如下:
obj-m:
=wdtdrv.o
all:
make-C/opt/FriendlyARM/linux-2.6.38SUBDIRS=$(shellpwd)
modules
clean:
rm-rf*.ko*.o
(3)编译
使用命令编译:
#make
编译完成后生成驱动文件wdtdrv.ko。
(3)加载驱动
使用命令进行驱动加载#insmodwdtdrv.ko。
(4)创建设备文件,将驱动设备号和设备文件名关联
相关命令为:
#mknod/dev/leddevc2520。
___
5.3编写应用程序
任务:
要求每5秒点亮所有的LED灯,然后熄灭,过5秒再点亮LED灯,要求能够添加看门狗支持
#include
#include
#include
#include
#include
#include
#defineON1
#defineOFF0
void*wdt_thrd_func(void*arg);
voidmain()
{
pthread_twdt_thd;
fd1=open(__"/dev/leddev"___,O_RDWR);//打开LED设备
if(fd1<0)
exit
(1);
fd2=open(__"/dev/wdtdev"___,O_RDWR);//打开看门狗设备
if(fd2<0)
exit
(1);
//创建看门狗喂狗线程
if(pthread_create(&wdt_thd,NULL,wdt_thrd_func,NULL)!
=0){
printf("Createwatchdogthreaderror!
\n");
exit
(1);
}
while
(1)
{
//点亮LED灯
ioctl(fd,ON);
sleep(5);
//熄灭LED灯
ioctl(leddevfd,OFF);
sleep(5);
}
close(fd);
}
void*wdt_thrd_func(void*arg)
//每隔10秒喂狗一次unsignedintwdt_val=0XFFFF;
while
(1)
{
//喂狗
write(fd2,&wdt_val,sizeof(int));
sleep(10);
}
return;
}