UP-MOBNET-Ⅱ型实验箱LED驱动控制实验

UP-MOBNET-Ⅱ型实验箱LED驱动控制实验

实验箱


名称 移动互联网教学科研平台Ⅱ型
型号 UP-MOBNET-Ⅱ
编号 03019024
批号 32017040520



实验内容


熟悉 Linux 系统下硬件驱动编程、编程实现对嵌入式设备上 LED 灯的控制




实验环境


硬件:UP-MobNet-II 型网关部分嵌入式实验平台、U盘 软件:Vmware Workstation 、linux虚拟机、Xshell + ARM-LINUX 交叉编译开发环境
交叉编译和实验平台系统的烧写这里不再赘述:

两个环境准备




实验原理


硬件接口原理


UP-MobNet-II 型网关部分平台上共有 5 个 LED 显示灯,位于 LCD 显示屏下方,分别为 D601、D602、D603、D604、D605,对应的 Exynos4412 处理器的引脚依次为 GPX3_2、GPX3_3、GPX1_2、GPD0_4、GPL0_3上。5 个 LED 显示灯分别共阳极 3.3V 电压,因此相应 GPIO 低电平点亮,高电平熄灭。



驱动层程序分析


Linux 系统下,应用程序不可直接操作底层硬件寄存器,必须经过驱动层来完成对硬件的操作。
驱动程序分析:/UP-CUP4412/SRC/exp/driver/02_leds/driver/s3c-leds.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <plat/gpio-cfg.h>
#include <asm/irq.h>
#include <mach/gpio.h>
MODULE_LICENSE("GPL");
#define DEVICE_NAME "leds" //驱动名称
#define DEVICE_MAJOR 231 //驱动主设备号
#define DEVICE_MINOR 0
struct cdev *mycdev;
struct class *myclass;
dev_t devno;
// LED GPIO 列表
static unsigned long led_table [] = {
           
           
 EXYNOS4_GPX3(2),
 EXYNOS4_GPX3(3),
 EXYNOS4_GPX1(2),
 EXYNOS4_GPL0(4),
 EXYNOS4_GPL0(3),
};
// LED GPIO 输出类型配置列表
static unsigned int led_cfg_table [] = {
           
           
 S3C_GPIO_OUTPUT,
 S3C_GPIO_OUTPUT,
 S3C_GPIO_OUTPUT,
 S3C_GPIO_OUTPUT,
 S3C_GPIO_OUTPUT,
};
// LED IOCTL 处理函数,主要完成从用户空间传递数据进行 GPIO 引脚设置功能
static long uptech_leds_ioctl(
 struct file *file,
 unsigned int cmd,
 unsigned long arg)
{
           
           
 printk("number = %ld\n",arg);
 switch(cmd) {
           
           
 case 0:
 case 1:
 if (arg < 0 || arg > 4) {
           
           
 return -EINVAL;
 }
 if(cmd == 0 || cmd == 1)

 {
           
            // LED GPIO 设置函数接口
 gpio_set_value(led_table[arg],!cmd);
 }
 return 0;
 default:
 return -EINVAL;
 } }
// 驱动层 file_operations 接口函数初始化
static struct file_operations uptech_leds_fops = {
           
           
 .owner = THIS_MODULE,
 .ioctl = uptech_leds_ioctl,
};
//驱动程序入口初始化函数,设置 LED GPIO、向内核注册设备。
static int __init uptech_leds_init(void)
{
           
           
 int i;
 int err;
 devno = MKDEV(DEVICE_MAJOR, DEVICE_MINOR);
 mycdev = cdev_alloc();
 cdev_init(mycdev, &uptech_leds_fops);
 err = cdev_add(mycdev, devno, 1); // 初始化 cdev 结构
 if (err != 0)
 printk("Exynos4412 leds device register failed!\n");
 myclass = class_create(THIS_MODULE, "leds");
 if(IS_ERR(myclass)) {
           
           
 printk("Err: failed in creating class.\n");
 return -1;
 }
 device_create(myclass,NULL, MKDEV(DEVICE_MAJOR,DEVICE_MINOR), NULL, 
DEVICE_NAME);
// LED GPIO 配置初始化
 for (i = 0; i < 5; i++) {
           
           
 s3c_gpio_cfgpin(led_table[i], led_cfg_table[i]);
 s3c_gpio_setpull(led_table[i],S3C_GPIO_PULL_DOWN);
 gpio_set_value(led_table[i],1);
 }
 printk(DEVICE_NAME "leds initialized\n");
 return 0;
}
// 驱动卸载函数
static void __exit uptech_leds_exit(void)
{
           
           


 cdev_del(mycdev); // 释放注册的字符设备
 device_destroy(myclass,devno);
 class_destroy(myclass);
}
// 声明驱动程序入口函数
module_init(uptech_leds_init);
// 声明驱动程序出口函数
module_exit(uptech_leds_exit);



应用层程序分析:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
           
           
 int i;
 int on;
 int led_number;
 int fd;
/*
根据命令行参数内容,进行控制。将命令行参数 1 设置成 LED number,参数 2 设置成 LED 点亮熄
灭状态 on
*/
 if (argc != 3 || sscanf(argv[1], "%d", &led_number) != 1 || 
sscanf(argv[2],"%d", &on) != 1 ||
 on < 0 || on > 1 || led_number < 0 || led_number >= 5) {
           
           
 fprintf(stderr, "Usage:\n");
 fprintf(stderr, "\t ./led led_number on|off\n");
 fprintf(stderr, "Options:\n");
 fprintf(stderr, "\t led_number from 0 to 4\n");
 fprintf(stderr, "\t on: 1 off: 0\n");
 exit(1);
 }
//打开 LED 设备节点
 fd = open("/dev/leds", 0);
 if (fd < 0) {
           
           
 perror("open device /dev/leds");
 exit(1);
 }
//调用驱动层 ioctl 接口,实现对 LED 控制
 ioctl(fd, on, led_number);
 for(i=0;i<100;i++)
 usleep(1000);
//关闭 LED 设备接口
 close(fd);
 return 0;
 }



Makefile:

CROSS = arm-linux-
CC = $(CROSS)gcc
AR = $(CROSS)ar
STRIP = $(CROSS)strip
LDFLAGS +=
 
 
EXEC = test_led
OBJS = led.o
 
all: $(EXEC)
 
$(EXEC): $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBM) $(LDLIBS) $(LIBGCC) -lm
 
clean:
	-rm -f $(EXEC) *.elf *.gdb *.o



实验步骤


实验目录:

			/UP-CUP4412/SRC/kernel/ linux-3.0.15/
			/UP-CUP4412/SRC/exp/diver/02_leds/



在内核中添加 LED 设备模块驱动


1、进入宿主机中 UP-CUP4412 型光盘内核目录:
解释:内核目录这里的内核目录是/UP-CUP4412/SRC/kernel/ linux-3.0.15/,将内核解压后的目录
[root@localhost ~]# cd /UP-CUP4412/SRC/kernel/linux-3.0.15/

2、运行 make menuconfig 命令配置内核对 LED 模块的相关支持 命令:

在这里插入图片描述

选择 Device Drivers --->选项,如图

在这里插入图片描述

进入 Character devices ---> 菜单

在这里插入图片描述

选择 < M > S3C LEDs Driver 模块方式编译 LED 驱动,如图:

在这里插入图片描述

退出保存配置:

在这里插入图片描述

3、重新编译内核,运行 make 命令 最终在内核源码目录的 drivers/char/目录下生成 LED 驱动程序 s3c-leds.ko

在这里插入图片描述

备注:以上在内核中添加对 LED 设备的支持的步骤,在网关系统设备出厂自带内核中已经默认添加进 入了,用户可以省略以上步骤。以上步骤在于重现系统的构造。LED 相应驱动已经在本实验目录的 driver 目录下给出。




编译 LED 应用测试程序


1、进入实验目录:
2、清除中间代码,重新编译
当前目录下生成可执行程序 test_led。

在这里插入图片描述



实验测试

把模块和应用程序拷到U盘,在实验箱挂载:

在这里插入图片描述

在这里插入图片描述



3、加载 LED 驱动模块。
[root@UP-TECH 02_leds]# insmod driver/s3c-leds.ko 
[ 5323.825976] ledsleds initialized
[root@UP-TECH 02_leds]#

特别强调



以上在内核中添加对 LED 设备的支持的步骤,在网关系统设备出厂自带内核中已经默认添加进
入了,leds相关的驱动层已经默认添加了,所以再次添加就会失败。
这里就可以不用再insmod挂载模块了


4、查看下自己建立的设备 leds 属性:
[root@UP-TECH 02_leds]# ll /dev/leds 
crw-r--r-- 1 root root 231, 0 Jul 5 10:30 /dev/leds
[root@UP-TECH 02_leds]#

5、执行应用程序测试该驱动及设备

开始时默认全部引脚都是亮的:

在这里插入图片描述

点亮 LED3/4
熄灭 LED0/1/2

在这里插入图片描述

在这里插入图片描述

只点亮LED3
在这里插入图片描述

在这里插入图片描述

卸载U盘:

在这里插入图片描述




总结


应用程序如何调用设备驱动程序接口


一般的驱动程序是不允许应用程序调用的,只有当驱动程序留出这种供外界访问的接口才行,这种接口一般包括read,write,open,ioctl等接口,如果驱动中预留出了这些接口,就可以在应用程序中调用,比如fd=open(设备,参数);或者fd=ioctl(设备,参数);,这样就会调用到这个设备驱动中的open或者ioctl函数。所以一般如果想再应用程序中调试某个驱动程序,常见的方法就是自己建立一个驱动模块,这个模块中预留出对外接口,比如ioctl。然后在你新建的这个驱动模块中完成ioctl函数。在该实验中应用程序就是通过IOCTL调用设备驱动程序的预留接口: 就是下面的这一个小方法:
 ioctl(fd, on, led_number);


设备驱动程序的接口函数如何实现


LED IOCTL 处理函数,主要完成从用户空间传递数据进行 GPIO 引脚设置功能 通过ioctl传过来的参数来处理GPIO引脚设置,从而使得灯亮和灭 这是内核层处理用户传来的数据,即用户到内核通过IOCTL传递
static long uptech_leds_ioctl(
 struct file *file,
 unsigned int cmd,
 unsigned long arg)
{
                            
                            
 printk("number = %ld\n",arg);
 switch(cmd) {
                            
                            
 case 0:
 case 1:
 if (arg < 0 || arg > 4) {
                            
                            
 return -EINVAL;
 }
 if(cmd == 0 || cmd == 1)

 {
                            
                             // LED GPIO 设置函数接口
 gpio_set_value(led_table[arg],!cmd);
 }
 return 0;
 default:
 return -EINVAL;
 } }
// 驱动层 file_operations 接口函数初始化
static struct file_operations uptech_leds_fops = {
                            
                            
 .owner = THIS_MODULE,
 .ioctl = uptech_leds_ioctl,
};

猜你喜欢

转载自blog.csdn.net/Lazy_Goat/article/details/117337464