这里将树莓派的的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
- GPSEL0
将该寄存器的14,13 12位配置成0 0 1,在配置这三位的二进制的时候为了避免影响到其他位的原始状态,故需要进行按位与和按位或的运算
*GPFSEL0 &= ~(0x6 << 12);
*GPFSEL0 |= (0x1 << 12);
经过这两步运算,即可以把Pin4引脚配置成输出引脚
- GPSET0(字1寄存器)
该寄存器可以将引脚配置成低电平1
*GPSET0 |= (0x1 << 4);
- 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");