南京邮电大学计算机学院《嵌入式系统与开发》实验报告
《嵌入式Linux下LED报警灯
驱动设计及编程》
实验报告
学生姓名: 学 号: 专业班级:
指导教师: 完成时间:
南京邮电大学计算机学院《嵌入式系统与开发》实验报告
实验5 嵌入式Linux下LED报警灯驱动设计及编程
一.实验目的
理解驱动本质,掌握嵌入式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
//#include
#include
#include
#include
#include
#include
#define ON 1 #define OFF 0
(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); } /*
功能:点亮第i个LED灯
参数:无符号整型变量iLed,表示第i个LED灯 返回值:无 */
void iLedOn(unsigned int iLed) { //读出端口M数据寄存器(S3C64XX_GPKDAT)值,修改并写回相关端口寄存器 //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); } /*
功能:熄灭第i个LED灯
参数:无符号整型变量iLed,表示第i个LED灯 返回值:无 */
void iLedOff (unsigned int iLed) { //读出端口M数据寄存器(S3C64XX_GPKDAT)值,修改并写回相关端口寄存器 //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) {
//把之前的端口K控制寄存器值读出来保存起来
//调用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 iLedOn(); break; case OFF: //熄灭所有LED灯 //add your code iLedOff(); break; } }
struct file_operations led_fops= {
.open=___ s3c6410_led_open______, .release=___s3c6410_led_release______,