linux驱动开发 | led驱动
一、led驱动原理led的引脚是GPIO1_IO03引脚。想使用这个引脚,必须先初始化1.打开引脚的时钟打开gpio1的时钟,先清0 在写1val = readl(IMX6U_CCM_CCGR1);val &= ~(3<<26);/* bit26 27清零 */val |= (3<<26);/* 打开gpio1时钟 */2.复用模式引脚上电默认就是复用为GPIO1_
·
一、寄存器初始化
led的引脚是
LED使用GPIO1_IO03引脚。下面是初始化的步骤。
1.打开引脚的时钟

打开gpio1的时钟,先清0 在写1
val = readl(IMX6U_CCM_CCGR1);//注意 这个地址是虚拟地址 ioremap
val &= ~(3<<26);/* bit26 27清零 */
val |= (3<<26);/* 打开gpio1时钟 */
writel(val,IMX6U_CCM_CCGR1);
2.复用模式

引脚上电默认就是复用为GPIO1_IO03
writel(5,SW_MUX_GPIO1_IO03);//注意 这个地址是虚拟地址 ioremap
3.引脚电气属性寄存器
HYS(bit16):使能迟滞比较器,当 IO 作为输入功能的时候有效,用于设置输入接收器的施密特触发器是否使能。如果需要对输入波形进行整形的话可以使能此位。此位为 0 的时候禁止迟滞比较器,为 1 的时候使能迟滞比较器。 这里不需要使用

PUS(bit15:14):设置上下拉电阻,100k下拉,47k上拉,100k上拉,22k上拉
PUE(bit13):当 IO 作为输入的时候,这个位用来设置 IO 使用上下拉还是状态保持器。当为 0的时候使用状态保持器,当为 1 的时候使用上下拉。状态保持器在IO 作为输入的时候才有用,顾名思义,就是当外部电路断电以后此 IO 口可以保持住以前的状态。
PKE(bit12):此为用来使能或者禁止上下拉/状态保持器功能,为0 时禁止上下拉/状态保持器,为 1 时使能上下拉和状态保持器。

ODE(bit11):当 IO 作为输出的时候,此位用来禁止或者使能开路输出,此位为 0 的时候禁止开路输出,当此位为 1 的时候就使能开路输出功能。

SPEED(bit7:6):当 IO 用作输出的时候,此位用来设置 IO 速度
DSE(bit5:3):当 IO 用作输出的时候用来设置 IO 的驱动能力。3.3V 下 R0 是 260Ω,1.8V 下 R0 是 150Ω,接 DDR 的时候是 240Ω
SRE(bit0):当此位为 0 的时候是低压摆率,当为 1 的时候是高压摆率。这里的压摆率就是 IO 电平跳变所需要的时间,比如从 0 到 1 需要多少时间,时间越小波形就越陡,说明压摆率越高;反之,时间越多波形就越缓,压摆率就越低。如果你的产品要过 EMC 的话那就可以使用小的压摆率,因为波形缓和,如果你当前所使用的 IO做高速通信的话就可以使用高压摆率。
writel(0x10B0,SW_PAD_GPIO1_IO03);//注意 地址是虚拟地址 ioremap
4.引脚方向
val = readl(GPIO1_GDIR);//注意是虚拟地址
val &= ~(1<<3);/* 清零 */
val |= (1<<3);/* 设置为输出 */
writel(val,GPIO1_GDIR);
二、驱动程序编写
#include <linux/ide.h>
#include <linux/module.h>
//#include <linux/kernel.h>
//#include <linux/delay.h>
// #include <linux/init.h>
// #include <linux/types.h> //dev_t
// #include <linux/kdev_t.h> //设备号头文件
// #include <linux/kern_levels.h> //printk 消息级别
// #include <linux/errno.h>
// #include <linux/gpio.h>
// #include <asm/mach/map.h>
// #include <asm/uaccess.h>
// #include <asm/io.h>
/********************************************************************
* led.c
* 作者:张亚胜
* 版本:V1.0
* 描述:led驱动文件
* 其他:无
* 网站:www.s123.xyz
* 日志:出版V1.0 2020/7/26 张亚胜创建
* ******************************************************************/
#define LED_MAJOR 200 /* 主设备号 */
#define LED_NAME "led" /* 设备名字 */
#define LED_OFF 0 /* 关灯 */
#define LED_ON 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;
//led操作函数
void led_switch(u8 sta)
{
u32 val=0;
if(sta == LED_ON){
val = readl(GPIO1_DR);
val &= ~(1<<3);//GPIO1_IO03 bit3清零
writel(val,GPIO1_DR);
}
else if(sta == LED_OFF)
{
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 retval=0;
unsigned char databuf[1];
unsigned char ledsta;
retval = copy_from_user(databuf,buf,cnt);
if(retval < 0){
printk("kernel write failed!\r\n");
return -EFAULT;
}
ledsta = databuf[0];
led_switch(ledsta);
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,
.release = led_release,
.read = led_read,
.write = led_write,
};
static int __init led_init(void)
{
int retval = 0;
u32 val = 0;
/* 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);/* bit26 27清零 */
val |= (3<<26);/* 打开gpio1时钟 */
writel(val,IMX6U_CCM_CCGR1);
/* 3.设置复用功能 */
writel(5,SW_MUX_GPIO1_IO03);//GPIO1_IO03
/* 设置io属性 */
writel(0x10B0,SW_PAD_GPIO1_IO03);
/* 4.设置输出功能 */
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.注册字符设备驱动 */
retval = register_chrdev(LED_MAJOR,LED_NAME,&led_fops);
if(retval < 0){
printk("register chrdev failed!\r\n");
return -EIO;
}
return retval;
}
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("zys");
三、测试app编写
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
/********************************************************************
* 文件名:ledApp.c
* 作者:张亚胜
* 版本:V1.0
* 描述:ledApp测试文件
* 其他:使用方法:./ledApp /dev/led 0 //写0 关灯
* ./ledApp /dev/led 1 //写1 开灯
* 网站:www.s123.xyz
* 日志:出版V1.0 2020/7/26 张亚胜创建
* ******************************************************************/
/*
* @description : main 主程序
* @param - argc : argv 数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
int fd,retval;
char *filename;
char buf[100];
if(argc != 3){
printf("params err!\r\n");
return -1;
}
filename = argv[1];
fd = open(filename,O_RDWR);
if(fd<0){
printf("open err!\r\n");
return -1;
}
buf[0] = atoi(argv[2]);
write(fd,buf,1);
retval = close(fd);
return retval;
}
四、编译
编译驱动程序,Makefile如下,make生成led.ko
KERNELDIR := /home/zys/linux/IMX6ULL/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)
obj-m := led.o
bulid: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
编译应用程序ledApp
arm-linux-gnueabihf-gcc ledApp.c -o ledApp
五、测试
将编译出来的 led.ko和 ledApp这两个文件拷贝到 rootfs/lib/modules/4.1.15 目录中,
重启开发板,进入到目录 lib/modules/4.1.15 中,输入如下命令加载 led.ko 驱动模块:
depmod //第一次加载驱动的时候需要运行此命令
modprobe led.ko //加载驱动
驱动加载成功以后创建“/dev/led”设备节点,命令如下:
mknod /dev/led c 200 0
驱动节点创建成功以后就可以使用 ledApp 软件来测试驱动是否工作正常,输入如下命令打
开 LED 灯:
./ledApp /dev/led 1 //打开 LED 灯
如果要卸载驱动的话输入如下命令即可:
rmmod led.ko

可以正常开灯关灯
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)