驻马店网站建设电话百度快速收录教程
概要
一. 整体架构流程
1.1 硬件准备
1.2 软件准备
二 . 编写 LED 驱动
2.1 创建驱动文件
2.2 编辑驱动测试代码并编译驱动
三. 测试驱动
3.1 加载驱动
3.2 创建设备节点
四. 实验现象
概要
在嵌入式 Linux 系统中,设备驱动是连接硬件与操作系统的桥梁。点灯大法好,通过编写 Linux 驱动,可以方便地控制开发板上的 LED 灯。
一. 整体架构流程
1.1 硬件准备
- IMX6ULL开发板
- 板载外设LED。
- LED 正极 -> GPIO 引脚(GPIO1_IO03)
- LED 负极 -> GND
1.2 软件准备
- Linux 内核源码。
- 交叉编译工具链:用于编译内核模块。
- 开发环境:ubuntu。
二 . 编写 LED 驱动
2.1 创建驱动文件
在 Linux 内核源码目录下,创建一个新的驱动文件 led.c。在驱动代码中,完成对LED引脚的初始化配置,将其复用为IO输出引脚。其次,定义用户空间应用程序要调用的led_open
函数,led_read
函数,led_write
函数,led_release
函数以完成对设备文件的访问操作。
驱动代码如下所示:
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define LED_MAJOR 200 /* 主设备号 */
#define LED_NAME "led" /* 设备名字 */#define LEDOFF 0
#define LEDON 1 /* 寄存器物理地址 */
#define CCM_CCGR1_BASE (0X020C406C)
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
#define GPIO1_DR_BASE (0X0209C000)
#define GPIO1_GDIR_BASE (0X0209C004)/* 映射后的寄存器虚拟地址指针 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;void led_switch(u8 sta)
{u32 val = 0;if(sta == LEDON) {val = readl(GPIO1_DR);val &= ~(1 << 3); writel(val, GPIO1_DR);}else if(sta == LEDOFF) {val = readl(GPIO1_DR);val|= (1 << 3); writel(val, GPIO1_DR);}
}static int led_open(struct inode *inode, struct file *filp)
{return 0;
}static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue;unsigned char databuf[1];unsigned char ledstat;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0]; /* 获取状态值 */if(ledstat == LEDON) { led_switch(LEDON); /* 打开LED灯 */} else if(ledstat == LEDOFF) {led_switch(LEDOFF); /* 关闭LED灯 */}return 0;
}static int led_release(struct inode *inode, struct file *filp)
{return 0;
}/* 设备操作函数 */
static struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,
};static int __init led_init(void)
{int retvalue = 0;u32 val = 0;/* 初始化LED *//* 1、寄存器地址映射 */IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);/* 2、使能GPIO1时钟 */val = readl(IMX6U_CCM_CCGR1);val &= ~(3 << 26); /* 清楚以前的设置 */val |= (3 << 26); /* 设置新值 */writel(val, IMX6U_CCM_CCGR1);/* 3、设置GPIO1_IO03的复用功能,将其复用为* GPIO1_IO03,最后设置IO属性。*/writel(5, SW_MUX_GPIO1_IO03);/*寄存器SW_PAD_GPIO1_IO03设置IO属性*bit 16:0 HYS关闭*bit [15:14]: 00 默认下拉*bit [13]: 0 kepper功能*bit [12]: 1 pull/keeper使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 110 R0/6驱动能力*bit [0]: 0 低转换率*/writel(0x10B0, SW_PAD_GPIO1_IO03);/* 4、设置GPIO1_IO03为输出功能 */val = readl(GPIO1_GDIR);val &= ~(1 << 3); /* 清除以前的设置 */val |= (1 << 3); /* 设置为输出 */writel(val, GPIO1_GDIR);/* 5、默认关闭LED */val = readl(GPIO1_DR);val |= (1 << 3); writel(val, GPIO1_DR);/* 6、注册字符设备驱动 */retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);if(retvalue < 0){printk("register chrdev failed!\r\n");return -EIO;}return 0;
}static void __exit led_exit(void)
{/* 取消映射 */iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO03);iounmap(SW_PAD_GPIO1_IO03);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);/* 注销字符设备驱动 */unregister_chrdev(LED_MAJOR, LED_NAME);
}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jiajiajia");
2.2 编辑驱动测试代码并编译驱动
在驱动文件目录下完成对测试文件的编写,其中完成对驱动函数的调用,进而完成对设备的控制。在 Linux 内核源码目录下,使用以下命令编译驱动,并将编译后的.ko文件以及可执行的测试文件挂载到nfs文件夹下,启动IMX6ULL确认挂在成功。
三. 测试驱动
3.1 加载驱动
在开发板上,使用以下命令加载驱动:
modprobe led
3.2 创建设备节点
加载驱动后,使用以下命令创建设备节点:其中200表示驱动注册的主设备号。
mknod /dev/led c 200 0
确认设备节点创建成功。
四. 实验现象
通过执行对应的测试文件,对目标设备传入0或1参数,完成对目标设备的控制