1、PIN5口完整驱动代码
#include <linux/fs.h> //file_operations声明
#include <linux/module.h> //module_init module_exit声明
#include <linux/init.h> //__init __exit 宏定义声明
#include <linux/device.h> //class devise声明
#include <linux/uaccess.h> //copy_from_user 的头文件
#include <linux/types.h> //设备号 dev_t 类型声明
#include <asm/io.h> //ioremap iounmap的头文件
static struct class* pin5_class;
static struct device* pin5_class_dev;
static dev_t devno;//设备号类型声明,用来接收设备编号
static int major=233;//主设备号
static int minor=1;//次设备号
static char* module_name="pin5";//模块名
//volatile 作用:1,指令不会因编译器的优化而省略 1,且要求直接读值
volatile unsigned int* GPFSEL0=NULL;//第0组寄存器
volatile unsigned int* GPSET0=NULL;//第0组输出寄存器
volatile unsigned int* GPCLR0=NULL;//第0组清零寄存器
static int pin5_open(struct inode* indoe, struct file* file)
{
printk("pin5_open\n");
//bit17-15 配置成001及配置成输出
*GPFSEL0 &=~(0x6<<15);
*GPFSEL0 |=(0x1<<15);
return 0;
}
static ssize_t pin5_write(struct file* file, const char __user* user, size_t contex, loff_t* opps)//向设备发送数据
{
int cmd;
int ret_user;
printk("pin5_write\n");
//static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
ret_user=copy_from_user(&cmd,user,contex);//从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0
if(ret_user==0)
{
printk("copy_from_user data sucess!\n");
}
else
{
printk("copy_from_user data error!\n");
}
if(cmd == 1)
{
printk("SET1\n");
*GPSET0 |=0x1<<5;
}
else if(cmd == 0)
{
printk("SET0\n");
*GPCLR0 |=0x1<<5;
}
else
{
printk("undo!\n");
}
return 0;
}
static struct file_operations pin5_fops={
.owner=THIS_MODULE,
.open =pin5_open,
.write=pin5_write,
};
int __init pin5_init(void)//真实驱动入口
{
int ret=0;
devno=MKDEV(major,minor);//获取设备编号
//int register_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops); //向内核注册一个设备,返回值为注册的主设备号
//unsignedintmajor 主设备号;constchar*name,设备号名字,structfile_operations*fops,字符设备操作函数
ret=register_chrdev(major,module_name,&pin5_fops);//注册驱动函数,告诉内核把这个驱动加入到内核驱动链表中,正常注册后,返回分配的主设备号
//struct class *class_create(struct module *owner, const char *name);创建class,并将class注册到内核中,返回class结构体指针
pin5_class=class_create(THIS_MODULE,"my_char_driver");
if(pin5_class == NULL)
{
printk("class_creat error!\n");
}
//struct device *device_create(struct class *class, struct device *parent,dev_t devt, const char *fmt, ...)
pin5_class_dev=device_create(pin5_class,NULL,devno,NULL,module_name);//在dev目录下创建相应的设备节点
if(pin5_class_dev == NULL)
{
printk("device_creat error!\n");
}
//void *ioremap(unsigned long offset, unsigned long size);//将IO内存资源映射到核心虚拟地址空间
//物理地址是段地址左移四位加上偏移地址,十六进制左移四位也就是后边加个0
GPFSEL0 = (volatile unsigned int*)ioremap(0x3f200000,4);
GPSET0 = (volatile unsigned int*)ioremap(0x3f20001c,4);
GPCLR0 = (volatile unsigned int*)ioremap(0x3f200028,4);
return 0;
}
void __exit pin5_exit(void)
{
//解除映射:void iounmap(void* addr)//取消ioremap所映射的IO地址*/
iounmap(GPFSEL0);
iounmap(GPSET0);
iounmap(GPCLR0);
//void device_destroy(struct class *cls, dev_t devt);
device_destroy(pin5_class,devno);//销毁设备
class_destroy(pin5_class);//销毁类
//int unregister_chrdev(unsigned int major, const char *name);//卸载驱动
unregister_chrdev(major, module_name);
}
module_init(pin5_init);//驱动加载
module_exit(pin5_exit);//驱动卸载
MODULE_LICENSE("GPL v2");
2、测试代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
int cmd;
int data;
fd=open("/dev/pin5",O_RDWR);
if(fd < 0)
{
printf("open error.....\n");
perror("why:");
}
else
{
printf("open file success.....\n");
}
while(1)
{
printf("input: 1-HIGH 0-LOW:");
scanf("%d",&cmd);
if(cmd == 1)
{
data=1;
}
if(cmd == 0)
{
data=0;
}
printf("data=%d\n",data);
fd=write(fd,&data,1);
}
return 0;
}
3.芯片手册阅读笔记
PIN5
地址偏移量0x20000000
树莓派,IO空间的起始地址是 0x3f000000
The GPIO has 41 registers. All accesses are assumed to be 32-bit.
41个GPIO寄存器,所有的都是32位的寄存器
总线地址 寄存器名字 寄存器功能描述 大小 读OR写
0x 7E20 0000 GPFSEL0 GPIO Function Select 0 32 R/W
0x 7E20 001C GPSET0 GPIO Pin Output Set 0(设置输出0) 32 W
0x 7E20 0020 GPSET1 GPIO Pin Output Set 1(设置输出1) 32 W
0x 7E20 0028 GPCLR0 GPIO Pin Output Clear 0 (输出清0) 32 W
0x 7E20 002C GPCLR1 GPIO Pin Output Clear 1 (输出清1) 32 W
GPIO Function Select Registers (GPFSELn)
GPIO功能选择寄存器
列子:
000 = GPIO Pin 9 is an input 输入
001 = GPIO Pin 9 is an output 输出
17-15 FSEL5 FSEL5 - Function Select 5 R/W 0
17-15 配置成001及配置成输出
GPIO Pin Output Set Registers (GPSETn)
GPIO 接口输出设置寄存器
31-0 SETn (n=0..31) 0 = No effect R/W 0
1 = Set GPIO pin n
GPIO Pin Output Clear Registers (GPCLRn)
GPIO接口输出清除寄存器
31-0 CLRn (n=0..31) 0 = No effect R/W 0
1 = Clear GPIO pin n