led驱动程序_点亮led(imx6ull)

11 篇文章 1 订阅
1 篇文章 0 订阅

点亮led

1.看原理图,确定控制led的引脚
2.看芯片手册,确定如何设置/控制引脚
3.写程序,通过程序去控制引脚的状态

1. 看原理图 确定引脚

在这里插入图片描述
如图,imx6ull开发板led2的引脚为GPIO5_3,左边连接3.3V,所以我们只需要将右边的GPIO5_3输出低电平即可点亮led2。

2. 阅读芯片手册

      CCM: Clock Controller Module (时钟控制模块)
      IOMUXC ​: IOMUX Controller,IO复用控制器
      GPIO: General-purpose input/output,通用的输入输出口

目的:查找相关寄存器,设置引脚输出低电平
在这里插入图片描述
步骤:
        1> 首先我们要设置CCM里面的CCGR1寄存器的CG15位使能GPIO5;
        2> 使能之后要设置GPIO5_3的引脚功能,来自于GPIO模块,需要设置IOMUXC里面的寄存器来选择GPIO5_3用于GPIO功能(IOMUXC里面有俩个寄存器:SW_MUX_CTL_PAD 用来设置选择引脚功能;SW_PAD_CTL_PAD 用来设置引脚是否上拉下拉电阻等等);
        3> 设置GPIO.GDIR寄存器,将GPIO5_3设置为输出模式;
        4> 设置GPIO.DR寄存器,将GPIO5_3为低电平。

2.1 设置CCM

设置CCM里面某一个寄存器,使能GPIO5,设置哪一个?看芯片手册。
在这里插入图片描述
在这里插入图片描述

如图,设置CCM里面的CCGR1寄存器的CG15位,设置为11(默认值就是11)即可使能GPIO5。

2.2 设置IOMUXC

根据原理图led2所连接的引脚SNVS_TAMPER3找到对应的寄存器。
在这里插入图片描述

如图,将MUX_MODE设置为101即可设置为GPIO功能。

	//IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址: 0x02290000 + 0x14
	static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;

	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap( 0x02290000 + 0x14, 4);
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;//先把后四位清零
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;//把后三位设置为101

这里用到ioremap是因为驱动程序不可以直接使用物理地址,需要用ioremap函数将物理地址映射为虚拟地址,用这些虚拟地址去设置寄存器。

2.3 设置GPIO.GDIR

把引脚设置为GPIO模式之后,还需要设置引脚为输出模式
在这里插入图片描述
在这里插入图片描述
如图,把第三位设置为1,引脚即为输出模式。

	//GPIO5_GDIR 地址是:0x020AC004
	static volatile unsigned int *GPIO5_GDIR;

	GPIO5_GDIR = ioremap( 0x020AC004, 4);
	*GPIO5_GDIR |= (1<<3);//第三位置一,设置为输出模式

2.4 设置GPIO.DR

设置为输出模式之后,把引脚状态设置为低电平即可点亮led。
在这里插入图片描述

	//GPIO5_DR 地址是:0x020AC000
	static volatile unsigned int *GPIO5_DR;

	GPIO5_DR= ioremap( 0x020AC000, 4);
	*GPIO5_DR &= ~(1<<3);//拉低引脚,点亮led

3. 完成代码

3.1 驱动代码

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/device.h>

static int major;
static struct class *local_led_class;

//IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址: 0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;

//GPIO5_GDIR 地址是:0x020AC004
static volatile unsigned int *GPIO5_GDIR;

//GPIO5_DR 地址是:0x020AC000
static volatile unsigned int *GPIO5_DR;

static ssize_t local_led_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)
{
	char val;
	int err;
	/* copy_from_user: 从应用程序里面得到数据 */
	err = copy_from_user(&val,buf,1);
	
	/* 去设置寄存器:输出高低电平 */
	if(val){
		/* 点亮 */
		*GPIO5_DR &= ~(1<<3);
	}
	else{
		/* 熄灭 */
	*GPIO5_DR |= (1<<3);
	}
	return 1;
														  
}

static int local_led_open(struct inode *inode, struct file *filp)
{
	/*使能gpio模块
	  配置引脚为gpio功能
	  配置gpio为输出模式*/

	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;//清掉最后的四位
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;//或上101,即可将后三位设置为101

	*GPIO5_GDIR |= (1<<3);
	return 0;
}

static struct file_operations local_led_fops= {
	.owner		= THIS_MODULE,
	.write		= local_led_write,
	.open		= local_led_open,
};

/* 入口函数 */
static int __init local_led_init(void)
{
	printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
	major = register_chrdev(0, "local_led", &local_led_fops);
	
	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap( 0x02290000 + 0x14, 4);
	
	//GPIO5_GDIR 地址是:0x020AC004
	GPIO5_GDIR = ioremap( 0x020AC004, 4);
	
	//GPIO5_DR 地址是:0x020AC000
	GPIO5_DR= ioremap( 0x020AC000, 4);
	
	local_led_class = class_create(THIS_MODULE, "local_led");
	
	device_create(local_led_class, NULL, MKDEV(major, 0), NULL, "local_led");//系统会创建名为local_led的设备结点
	return 0;
}

static void __exit local_led_exit(void)
{
	device_destroy(local_led_class, MKDEV(major, 0));
	
	class_destroy(local_led_class);
	unregister_chrdev(major, "local_led1");
}

module_init(local_led_init);
module_exit(local_led_exit);
MODULE_LICENSE("Dual BSD/GPL");

3.2 测试代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc,char **argv)
{
	int fd;
	char status = 0;
	
	if(argc != 3){
		printf("Usage : %s </dev> <off/on>\n",argv[0]);
		printf("   eg : %s </dev> on\n",argv[0]);
		printf("   eg : %s </dev> off\n",argv[0]);
		return -1;
	}

	fd = open(argv[1],O_RDWR);
	if(fd<0){
		printf("can not open %s\n",argv[0]);
	}

	if(strcmp(argv[2],"on")==0){
		status = 1;
		
	}
	write(fd,&status,1);
	return 0;
}

编译代码拷贝至开发板,加载驱动,测试即可成功。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值