编写树莓派引脚驱动代码

这里将树莓派的的pin4引脚的配置成输出引脚为例

一.配置三个寄存器

树莓派每个寄存器配有32位的二进制数,第32位处于最高位,作为符号判断,故从31位开始:
31 30 29 28 27 26 25 24 23 …14 13 12 11 10 9 8 7 6 5 4 3 2 1

  1. GPSEL0
    将该寄存器的14,13 12位配置成0 0 1,在配置这三位的二进制的时候为了避免影响到其他位的原始状态,故需要进行按位与和按位或的运算
	*GPFSEL0 &= ~(0x6 << 12)*GPFSEL0 |=  (0x1 << 12)

经过这两步运算,即可以把Pin4引脚配置成输出引脚

  1. GPSET0(字1寄存器)

该寄存器可以将引脚配置成低电平1

	*GPSET0 |= (0x1 << 4);
  1. GPCLR0(清零寄存器)
    该寄存器可以将引脚配置成高电平0
	*GPCLR0 |= (0x1 << 4);

二.程序代码

#include<linux/device.h>	//包含class device结构体类型
#include<linux/types.h>		//包含dev_t 宏定义的声明,用来定义设备号
#include<linux/fs.h>		//包含file_opreation结构体类型,用来初始化驱动模块的相关属性
#include<linux/init.h>		//初始化驱动模块和退出驱动模块的头文件,包含_init _exit 宏定义的声明
#include<linux/module.h>	//卸载驱动模块的头文件,包含module_init,和module_exit函数库
#include<linux/uaccess.h>	//包含copy_from_user的头文件
#include<asm/io.h>			//包含ioremap,iounmap的头文件



//linux/device.h头文件下的class,device
static struct class *pin5_class;
static struct device *pin5_class_dev;


//对驱动模块的相关属性进行初始定义(设备号,主设备号和次设备号;驱动模块名称)
static dev_t devno;               //设备号,linux/types.h头文件下的dev_t宏定义
static int major = 231;           //主设备号
static int minor = 0;             //次设备号
static char *module_name = "pin5";//驱动模块名称

//定义寄存器
volatile unsigned int * GPFSEL0 = NULL;
volatile unsigned int * GPSET0  = NULL;
volatile unsigned int * GPCLR0  = NULL;


//和内核内操作文件的具有相同形参的函数,open,write,read
static int pin5_open(struct inode *inode,struct file *file)
{
	printk("Drive pin5_open successfully!\n");
	*GPFSEL0 &= ~(0x6 << 12)*GPFSEL0 |=  (0x1 << 12)return 0;
}
static ssize_t pin5_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
	
	//配置pin4为输出引脚,将bit 12~14 配置成0 0 1 即可,
	//在配置这3位时,为了不影响其他的引脚的状态,需要做按位与和按位或操作
	//按位与&(两者对应位同为1运算则结果为1,否则为0):可以将某个位的低电平1拉为高电平0(1变0用按位与)
	//按位或|(两者对应位只要有一个为1则运算结果为1,否则为0):可以将某个位的高电平0拉低为低电平1(0变1用按位或)
	//涉及多个位的电平变化时,需要两者结合运算,运输前后顺序自选(先按位与或者再按位或,先按位或再按位与)
   char usercmd;
   printk("Drvie pin4_write successfully!\n");
   copy_from_user(&usercmd,buf,count);
   if(usercmd==2)
   {
   		printk("Set 1\n");
   		*GPSET0 |= (0x1 << 4);//设置为低电平1
   }
   else if(usercmd==0)
   {
   		printk("Set 0\n");//设置为高电平0
   		*GPCLR0 |= (0x1 << 4);
   }
   else{
   		printk("undo\n");
   }

	return 0;
}

//绑定操作文件的函数到内核,linux/fs.h头文件下的file_opreations结构体数据类型
static struct file_operations pin5_fops={

	.owner = THIS_MODULE,
	.open  = pin5_open,
	.write = pin5_write,
};

//安装驱动模块
int __init pin5_drv_init()
{
	int ret;
	printk("Insmod driver pin4 successfully!\n");
	devno = MKDEV(major,minor);//绑定设备号
	ret = register_chrdev(major,module_name,&pin5_fops);//注册驱动,告诉内核,我要把这个驱动加入到内核的驱动链表当中
	pin5_class = class_create(THIS_MODULE,"MyFirstDriven");
	pin5_class_dev = device_create(pin5_class,NULL,devno,NULL,module_name);//创建设备文件
	GPFSEL0 = (volatile unsigned int *)ioremap(0x3f2000000,4);
	GPSET0  = (volatile unsigned int *)ioremap(0x3f200001C,4);
	GPCLR0  = (volatile unsigned int *)ioremap(0x3f2000028,5);
	return 0;
}


//卸载驱动模块
void __exit pin5_drv_exit()
{
	device_destroy(pin5_class,devno);
	class_destroy(pin5_class);
	unregister_chrdev(major,module_name);//卸载驱动
	iounmap(GPFSEL0);
	iounmap(GPSET0);
	iounmap(GPCLR0);

}

module_init(pin5_drv_init);
module_exit(pin5_drv_exit);
MODULE_LICENSE("GPL v2");
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值