树莓派IO口驱动之PIN5

 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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值