实验5  嵌入式LinuxLED报警灯驱动设计及编程

.实验目的

理解驱动本质,掌握嵌入式Linux系统下驱动开发相关知识,包括端口寄存器访问、接口函数编写、和文件系统挂接、注册及相关应用编程等知识点。

.实验内容

实验5.1 嵌入式Linux下LED报警灯驱动设计及跑马灯应用编程

实验5.2 添加看门狗功能的跑马灯应用编程

.预备知识

Linux使用、驱动相关知识等

.实验设备及工具(包括软件调试工具)

硬件:ARM 嵌入式开发平台、PC 机Pentium100 以上、串口线。

软件: WinXP或UBUNTU开发环境。

.实验5.1步骤

5.1 前期准备

(1)看懂相关硬件电路图【见S3C6410实验箱电路图-底板.pdf】,以LED报警灯为例进行设计

打开PDF硬件电路图,明确LED灯用到的多个GPIO及其控制器

本实验电路  LED1-------GPM0

LED2-------GPM1

LED3-------GPM2

LED4-------GPM3

LED5-------GPM4

LED6-------GPM5

LED7-------GPQ0

LED8-------GPQ1

得出结论: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文件中有定义:

#define S3C64XX_GPMCON                     (S3C64XX_GPM_BASE + 0x00)

#define S3C64XX_GPMDAT                     (S3C64XX_GPM_BASE + 0x04)

注意:上面斜体部分原代码有错误,请找到该文件并修改

5.2 LED报警灯驱动设计s3c6410_leddrv.c

(1)头文件包含和相关宏定义

#include <linux/miscdevice.h>

#include <linux/delay.h>

#include <asm/irq.h>

//#include <mach/regs-gpio.h>

#include <mach/hardware.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/mm.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/delay.h>

#include <linux/moduleparam.h>

#include <linux/slab.h>

#include <linux/errno.h>

#include <linux/ioctl.h>

#include <linux/cdev.h>

#include <linux/string.h>

#include <linux/list.h>

#include <linux/pci.h>

#include <asm/uaccess.h>

#include <asm/atomic.h>

#include <asm/unistd.h>

#include <mach/map.h>

#include <mach/regs-clock.h>

#include <mach/regs-gpio.h>

#include <plat/gpio-cfg.h>

#include <mach/gpio-bank-m.h>

#define ON 1

#define OFF 0

unsigned int old_gpmcon_val;

int leddevNo;

(2)编写驱动接口函数

/*

功能:配置GPM0~5/GPQ0~1为输出口

参数:无

返回值:无

*/

void LedConfig(void)

{

//读出端口M控制寄存器(S3C64XX_GPMCON)值,修改并写回端口寄存器

//add your code

unsigned int tmp;

        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);  

}

/*

功能:点亮所有LED灯

参数:无

返回值:无

*/

void  AllLedOn(void)

{

//读出端口M数据寄存器(S3C64XX_GPMDAT)值,修改并写回端口寄存器

//add your code here

unsigned int tmp;

        tmp =readl(S3C64XX_GPMDAT);

        tmp &= ~((0X1<<0X0)|(0X1<<0X1)|(0X1<<0X2)|(0X1<<0X3)|(0X1<<0X4)|(0X1<<0X5));

        writel(tmp,S3C64XX_GPMDAT);   

}

/*

功能:熄灭所有LED灯

参数:无

返回值:无

*/

void AllLedOff(void)

{

//读出端口M数据寄存器(S3C64XX_GPMDAT)值,修改并写回端口寄存器

//add your code here

unsigned int tmp;

        tmp =readl(S3C64XX_GPMDAT);

        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,S3C64XX_GPMDAT);

}

(2)和文件系统接口对接

static int s3c6410_led_open(struct inode *inode, struct file *filp)

{

//把之前的端口M控制寄存器值读出来保存起来

//调用LedConfig函数,把GPIO口配置成输出口

//add your code

old_gpmcon_val=readl(S3C64XX_GPMCON);

        LedConfig();

        renturn  0;

}

static int s3c6410_led _release(struct inode *inode, struct file *filp)

{

//恢复之前的端口K控制寄存器初始值

//add your code

writel(old_gpmcon_val,S3C64XX_GPMCON);

                 renturn  0;

}

static long s3c6410_led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

switch(cmd)

{

case ON:

//点亮所有LED灯

//add your code

AllLedOn();

break;

case OFF:

//熄灭所有LED灯

//add your code

AllLedOff();

break;

}

}

struct file_operations led_fops=

{

.open=_ s3c6410_led_open___,

.release=_ s3c6410_led_release____,

. unlocked_ioctl=_ s3c6410_led_ioctl____,

};

(3)添加模块标记代码

static int __init led_dev_init(void)

{

leddevNo = _ register_chrdev(0,"leddev",&led_fops)__;//注册设备

if(leddevNo<=0)

{

printk("REGISTER LEDDEV FAIL\n");

return -1;

}

printk ("LED device initialized\n");

return 0;

}

static void __exit  led_dev_exit(void)

{

//注销设备

//add your code

_ unregister_chrdev(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.38 __SUBDIRS=$(shell pwd)   modules

clean:

rm -rf *.ko *.o

(3) 编译

使用命令编译:

__#make________________________________

编译完成后生成驱动文件_leddrv.ko________。

(4) 加载驱动

将驱动搬运到开发板上【参考文档04- Tiny6410 Linux开发指南.pdf的1.9.1节】

使用命令进行驱动加载__#insmod leddrv.ko_____。

(5)创建设备文件,将驱动设备号和设备文件名关联

查看/proc/devices文件,得到系统为LED设备分配的设备号为_253___。

创建设备节点,相关命令为:

_#mknod  /dev/leddev c   253 0_____

备注:

5.3 编写应用程序

任务:要求每5秒点亮所有的LED灯,然后熄灭,过5秒再点亮LED灯

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#define ON 1

#define OFF 0

void main()

{

int fd;

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);

}

编译应用程序命令为:

_#arm-linux-gcc    -o  ledapp   ledapp.c_____。

将应用程序加载到开发板上【具体方法参考文档04- Tiny6410 Linux开发指南.pdf的1.9.1节】,并修改权限,命令为:

#chmod +x ledapp

测试应用程序,命令为_#./ledapp____:

测试LED灯变化规律为:

____LED灯以10秒为周期亮灭,其中点亮5秒,然后熄灭5秒,循环往复___________

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,如下:

#define S3C2410_WTCON          S3C_WDOGREG(0x00)

#define S3C2410_WTDAT           S3C_WDOGREG(0x04)

#define S3C2410_WTCNT           S3C_WDOGREG(0x08)

读寄存器函数

readl(寄存器虚地址);

写寄存器函数

writel(值(无符号整型), 寄存器虚地址);

6.2 看门狗驱动代码(s3c6410_wdtdrv.c)设计

(1)头文件包含和相关宏定义

#include <linux/module.h>

#include <linux/moduleparam.h>

#include <linux/types.h>

#include <linux/timer.h>

#include <linux/miscdevice.h>

#include <linux/watchdog.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <linux/interrupt.h>

#include <linux/clk.h>

#include <linux/uaccess.h>

#include <linux/io.h>

#include <linux/cpufreq.h>

#include <linux/slab.h>

#include <mach/map.h>

#include <plat/regs-watchdog.h>

unsigned int old_wdtcon_val;

int wdtdevNo;

(2)编写驱动接口函数

/*

功能:打开看门狗,允许复位,禁止看门狗中断,并设置看门狗最长看门时间

参数:无

返回值:无

*/

void WdtConfig(void)

{

//读出看门狗控制寄存器S3C2410_WTCON,保存原值,并按照要求修改

//最后写回看门狗端口控制寄存器S3C2410_WTCON

//add your code

unsigned int tmp;

tmp=(0XFF<<8)|(0X0<<6)|(0X1<<5)|(0X2<<3)|(0XFF<<8)|(0X0<<2)|(0X1<<1)|(0XFF<<8)|(0X1<<0);

        writel(tmp,S3C2410_WTCON);

}

(2)和文件系统接口对接

static int s3c6410_wdt_open(struct inode *inode, struct file *filp)

{

//打开看门狗,允许复位,禁止看门狗中断,并设置看门狗最长看门时间

//add your code

old_wdtcon_val=readl(S3C2410_WTCON);

        WdtConfig();

}

static ssize_t s3c6410_wdt_write(struct file *file, const char __user *data,size_t len, loff_t  *ppos)

{

//把data指针所指向的用户空间值更新到看门狗计数寄存器S3C2410_WTCNT中

//add your code

unsigned int val;

        copy_from_user(&val,data,4);

        writel(val,S3C2410_WTCNT);

        return 0;

}

static int s3c6410_wdt_release(struct inode *inode, struct file *filp)

{

//恢复之前的看门狗端口控制寄存器的原始值

//add your code

writel(old_wdtcon_val,S3C2410_WTCON);

        return 0;

}

struct file_operations wdt_fops=

{

.open=_ s3c6410_wdt_open__,

.release=_ s3c6410_wdt_release_,

. write=_ s3c6410_wdt_write_,

};

(3)添加模块标记代码

static int __init wdt_dev_init(void)

{

int ret;

ret = _ register_chrdev(0,"wdtdev",&wdt_fops)__;//注册设备

printk (DEVICE_NAME"\tinitialized\n");

return ret;

}

static void __exit  wdt_dev_exit(void)

{

//注销设备

//add your code

_ 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.38___SUBDIRS=$(shell pwd)   modules

clean:

rm -rf *.ko *.o

(3) 编译

使用命令编译:

_#make_______________

编译完成后生成驱动文件__wdtdrv.ko______。

(3) 加载驱动

使用命令进行驱动加载__# insmod wdtdrv.ko__。

(4)创建设备文件,将驱动设备号和设备文件名关联

相关命令为:

___#mknod   /dev/leddev  c  252  0____。

5.3 编写应用程序

任务:要求每5秒点亮所有的LED灯,然后熄灭,过5秒再点亮LED灯,要求能够添加看门狗支持

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <pthread.h>

#define ON 1

#define OFF 0

void *wdt_thrd_func(void *arg);

void main()

{

pthread_t wdt_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("Create watchdog  thread  error!\n");

exit(1);

}

while(1)

{

//点亮LED灯

ioctl(fd,  ON);

sleep(5);

//熄灭LED灯

ioctl(leddev_fd,OFF);_

sleep(5);

}

close (fd);

}

void *wdt_thrd_func(void *arg)

{

//每隔10秒喂狗一次

unsigned int wdt_val=0XFFFF;

while(1)

{

//喂狗

write(fd2,&wdt_val,sizeof(int));

sleep(10);

}

return;

}

编译时使用命令:

arm-linux-gcc -o wdt_led_app wdt_led_app.c  -lpthread

执行命令:

./wdt_led_app

现象:LED灯每10秒亮灭一次,间隔5秒。

如果把上述喂狗线程改为如下:

void *wdt_thrd_func(void *arg)

{

//每隔10秒喂狗一次

unsigned int wdt_val=0XFFFF;

while(1)

{

//喂狗

//write(fd2,&wdt_val,sizeof(int));

sleep(10);

}

return;

}

重新编译并执行文件,观察实验台LED现象为:

__LED灯亮灭几次后系统复位______________________。

南京邮电大学嵌入式系统开发实验5:嵌入式Linux下LED报警灯驱动设计及编程相关推荐

  1. 嵌入式系统开发笔记2:Linux的主流发行版本

    本系列文章将向大家介绍嵌入式系统开发的各方面知识. 本文将向大家介绍Linux的主流发行版本. 本文为转载文章,原文网址:Linux各个发行版本对比与简介 首先我们要能够清晰的区分Linux系统内核与 ...

  2. 嵌入式系统开发笔记80:应用Qt Designer进行主界面设计

    前言   本篇文章讲解PyQt的基本使用方法,我们将应用Qt Designer来设计一个主界面,学习完本篇文章的内容后,你将获得如下技能.   (1)在VS Code中启动Qt Designer    ...

  3. python嵌入式系统开发_Python在嵌入式项目中辅助开发.PDF

    22 SYSPRACTICE 系统实践 on在嵌入式项目中的辅助开发 Pyth 彭树林 摘要:嵌入式系统设计开发过程中常会遇到诸如算法分析.原型验证.自动化测试.辅助工具设计等工作,其 开发效率和质量 ...

  4. 南京邮电大学嵌入式系统开发实验3:嵌入式数据库sqlite移植及使用

    实验3  嵌入式数据库sqlite移植及使用 一.实验目的 理解嵌入式软件移植的基本方法,掌握sqlite数据库软件移植的步骤,掌握sqlite开发的两种方式-命令模式和C代码开发模式的使用方法,并编 ...

  5. 嵌入式系统开发与应用——嵌入式 Linux 调试环境搭建

    附录:UBoot常用命令手册 一. 实验目的 1.掌握VMware中设置共享文件夹的方法,为后续实验做准备: 2.熟悉 Linux TFTP 配置,为后续 Linux 底层开发做准备(后面会用 tft ...

  6. python嵌入式系统开发_图解嵌入式系统开发之语言篇:初识Python

    一直忙于工作,似乎忘记了抽时间学习新知识,最近难得空闲,花了两天时间看了一下Python语法.作为工作中经常使用C/C++的人,学习Python的过程中最大的感受就是"似曾相识". ...

  7. 从零开始的嵌入式系统开发学习Day3(linux C)

    目录 一.输入输出函数 1.1 getchar()/putchar() 1.1.1 getchar() 1.1.2 putchar() 1.2 get()/puts() 1.2.1 gets() 1. ...

  8. linux系统小灯项目报告,linux下led小灯的驱动.doc

    linux下led小灯的驱动 我第一个字符设备驱动程序的痛苦经历 2009-12-26 21:07 写驱动程序是个痛苦成长的过程... 对驱动的编译,先要有支持的内核源码树,所以先得编译内核.由于过了 ...

  9. 嵌入式系统开发笔记0_0:目录

    本系列文章将向大家介绍嵌入式系统开发的各方面知识. 本系列文章所介绍的知识和内容,除电路图设计外,其它均采用开源系统,所以你不会在这个系列文章中看到Keil.IAR等软件. 本系列文章涉及C.C++. ...

最新文章

  1. 暑期集训1:C++STL 例1:UVA-10815
  2. Collection+JSON 文档
  3. Android 页面进行镜像反转-面试
  4. 深度学习和目标检测系列教程 17-300: 3 个类别面罩检测类别数据集训练yolov5s模型
  5. Gemstones(牛客第八场多校)
  6. [css] 如何解决html设置height:100%无效的问题?
  7. Django之Apache2部署
  8. HDU1054 Strategic Game —— 最小点覆盖 or 树形DP
  9. python对文件的操作
  10. 华为快应用 阻止事件冒泡
  11. MATLAB代码:电-气-热综合能源系统耦合优化调度 关键词:综合能源系统 优化调度 电气热耦合 主要内容:代码主要做的是一个考虑电网、热网以及气网耦合调度的综合能源系统优化调度模型
  12. 吾爱破解python就业班_“吾”字是什么意思?
  13. 微信小程序影视评论交流平台系统毕业设计毕设(2)小程序功能
  14. 运筹优化——生产排程问题简介
  15. dev-tool安装方法(手动安装版)
  16. VMware中kali2022通过物理机代理上网(桥接模式)
  17. 2019杭州西溪龙舟文化节在西安大明宫举行
  18. [UOJ#207]共价大爷游长沙
  19. 中科大算法设计与分析部分答案
  20. ..\OBJ\OLED.axf: Error: L6200E: Symbol Usart_Int multiply defined (by usart_1.o and usart.o).

热门文章

  1. 机房温度过高应这样预防
  2. 王者荣耀 微信登录 服务器找不到,王者荣耀微信登录失败怎么办 王者荣耀微信登录失败解决办法...
  3. Nexus war 下载
  4. 在这个五月《安装Linux》简直易如反掌
  5. 使用pyqt5的日期控件做一个小日历方便查看
  6. MySQL语法添加多个外码约束
  7. python:在指定范围内按学号随机生成座位顺序,并分行输出
  8. DPC(Defect Point Correction)------坏点校正
  9. struct结构体里能放函数吗?
  10. 2020计算机考试内容,2020年全国计算机二级OFFICE考试内容