一、树莓派寄存器介绍:

  • GPFSEL0 GPIO Function Select 0: 功能选择 输入/输出

  • GPSET0 GPIO Pin Output Set 0 : 输出0

  • GPSET1 GPIO Pin Output Set 1 : 输出1

  • 0 = No effect

  • 1 = Set GPIO pin n

  • GPCLR0 GPIO Pin Output Clear 0: 清零

  • 0 = No effect

  • 1 = Clear GPIO pin n

  • GPCLR1 GPIO Pin Output Clear 1 :清1

  • 每个寄存器都是32位的

举个例子,例如:我们把引脚5配置位输出引脚

FSEL5 17-15 001 我们把5引脚的17-15配置成001 GPIO Pin 5 is an output

注意:我们配置的底层引脚对应得是BCM

寄存器第0组位 FESL0–9

寄存器第1组位 FSEL10–19

具体的引脚信息可以通过官网查询

树莓派引脚

二、寄存器的地址问题

我们在编写驱动程序的时候,IO空间的起始地址是 0x3f000000 ,加上GPIO的偏移量 0x2000000 ,所以GPIO的物理地址应该是从 0x3f200000 开始的,然后在这个基础上进行Linux系统的MMU内存虚拟化管理,映射到虚拟地址上。

该图的尾部偏移是对的根据GPIO的物理地址0x3f200000可以知道:

  • GPFSEL0 0x3f200000

  • GPSET0 0x3f20001c

  • GPCLR0 0x3f200028

补充:这里我们的地址是物理地址,是操作不了的,所以需要转换成 虚拟地址 ,来进行操作

void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);ioremap宏定义在asm/io.h内:#define ioremap(cookie,size)           __ioremap(cookie,size,0)

参数:

  • phys_addr:要映射的起始的IO地址

  • size:要映射的空间的大小

  • flags:要映射的IO空间和权限有关的标志

  • 该函数返回映射后的内核虚拟地址(3G-4G). 接着便可以通过读写该返回的内核虚拟地址去访问之这段I/O内存资源

三、以 pin5 引脚为例子:

pin5drive.c

#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 device声明
#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 unsigned int* GPFSEL0 = NULL; // volatile不会因编译器的优化而省略,每次直接读值
volatile unsigned int* GPSET0  = NULL;
volatile unsigned int* GPCLR0  = NULL;static int pin5_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
{printk("pin5_read\n"); // 内核的打印函数return 0;
}//pin5_open函数
static int pin5_open(struct inode *inode, struct file *file)
{printk("pin5_open\n"); // 内核的打印函数,和printf类似// 配置pin5引脚为输出引脚 ,需要把 bit 15~17 配置成001*GPFSEL0 &= ~(0x6 << 15); // 0x6 0110 左移15位,取反后为1001,把bit 16、17配置成 0 *GPFSEL0 |=  (0x1 << 15); // 把 第 15 位bit 配置成 1, 15~17为001输出 / 000输入,其中一工为0~31位return 0;
}//open_write函数
static ssize_t pin5_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{int cmd;printk("pin5_write\n");//      获取上层write函数的值copy_from_user(&cmd,buf,count); // 从上层获取函数的值第一个参数是一个char类型的指针const char __user *buf,用int也行//      根据值来设定操作 io 口,高电频还是低电频printk("get value\n");if(cmd == 1){*GPSET0 |= 0x1 << 5; // 把第 0 组 第5引脚置为 1 }else if(cmd == 0){*GPCLR0 |= 0x1 << 5;    // 第 5位置1 让清零寄存器把第 5 引脚清零}else{printk("undo\n");}return 0;
}
static struct file_operations pin5_fops = {.owner = THIS_MODULE,.open  = pin5_open,.write = pin5_write,.read  = pin5_read,
};int __init pin5_drv_init(void) //真实驱动入口
{int ret;printk("insmod driver pin5 success\n");devno = MKDEV(major,minor); //2. 创建设备号ret = register_chrdev(major , module_name, &pin5_fops); //3.注册驱动,告诉内核,把这个驱动加入到内核的链表中pin5_class = class_create( THIS_MODULE, "myfirstdemo" ); // 让代码在dev自动生成设备pin5_class_dev = device_create( pin5_class , NULL , devno , NULL ,module_name ); //创建设备文件GPFSEL0 = ( volatile unsigned int *)ioremap(0x3f200000,4);//    第一个参数为物理地址,第二个参数为映射的大小GPSET0  = ( volatile unsigned int *)ioremap(0x3f20001C,4);//    一般寄存器32位,4个字节 GPCLR0  = ( volatile unsigned int *)ioremap(0x3f200028,4);//    把物理地址 转换为 虚拟地址//ioremap由于返回值是void*型需要强制转换  void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags)   return 0;
}void __exit pin5_drv_exit(void)
{iounmap(GPFSEL0);       //iounmap函数用于取消ioremap()所做的映射iounmap(GPSET0);iounmap(GPCLR0);device_destroy(pin5_class,devno);class_destroy(pin5_class);unregister_chrdev( major, module_name);// 卸载驱动}module_init(pin5_drv_init); // 驱动入口,驱动安装的时候,会调用这个宏
module_exit(pin5_drv_exit);
MODULE_LICENSE("GPL v2");

应用层代码测试 pin5test.c

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>int main()
{int fd;int usecmd;int data;fd = open("/dev/pin5",O_RDWR);if(fd < 0){printf("open file failed\n");perror("why : ");}else{printf("open success\n");}printf("请输入你的指令 : 1/0 , 1: pin5 HIGH , 0: pin5 LOW\n");scanf("%d",&usecmd);if(usecmd == 1){data = 1;printf("data = %d\n",data);}else if(usecmd == 0){data = 0;printf("data = %d\n",data);}fd = write(fd, &data,1);}

(2)编译驱动代码 pin5drive.c ,放入源码树目录的 /drivers/char 目录下

1、先用 vi Makefile 打开,添加相应pin5 驱动说明

2、编译生成 .ko 文件

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules

3、把ko文件发送到树莓派上

scp pin5dirve.ko pi@192.168.3.43:/home/pi

4、编译测试代码 pin5test.c 并将其发送到树莓派

arm-linux-gnueabihf-gcc pin5test.c -o pin5test
scp pin5test pi@192.168.3.43:/home/pi

5、安装 pin5 驱动

sudo insmod pin5drive.ko // 安装驱动,要超级权限

此时 /dev 目录下会有 pin5 :

lsmod // 可查看驱动是否安装

6、此时需要给pin5驱动 加权限,这样应用层才能看到测试信息

sudo chmod 666 /dev/pin5   // 666 为可读可写可操作权限

端口号,设备号都有体现

7、运行测试代码 :

./pin5test

刚开始查看树莓派端口情况:

gpio readall

以输入1为例子:

此时驱动被修改成功为输出端口,为OUT

树莓派学习——博通BCM2835芯片手册导读、IO口驱动代码调试和测试学习相关推荐

  1. 11.树莓派博通BCM2835芯片手册导读与IO口驱动代码调试和测试

    11.树莓派博通BCM2835芯片手册导读与IO口驱动代码调试和测试 硬件地址的相关概念 总线地址 32位的操作系统 ,cpu最多只能访问2^32bit,即只能访问4G的内存 64位的操作系统 ,cp ...

  2. 树莓派学习笔记(十五)博通BCM2835芯片手册导读

    树莓派3b的CPU型号为:BCM2835(ARM-cotexA53架构) CPU型号为2440.2410(ARM9架构) 编写驱动需要电路图(作用通过电路图找到寄存器).芯片手册 树莓派官网:http ...

  3. 树莓派——8、树莓派博通BCM2835芯片手册导读

    (122条消息) 树莓派高阶课程7:树莓派博通BCM2835芯片手册导读_哒宰的自我修养的博客-CSDN博客 博通BCM2835芯片手册导读 驱动的两大利器: 电路图:通过电路图找到寄存器 芯片手册: ...

  4. 树莓派高阶课程7:树莓派博通BCM2835芯片手册导读

    树莓派博通BCM2835芯片手册导读 驱动的两大利器: 电路图:通过电路图找到寄存器 芯片手册:进行编写 1.树莓派寄存器的介绍: GPFSEL0 GPIO Function Select 0: // ...

  5. 树莓派博通BCM2835芯片手册导读及io口驱动代码的实现

    树莓派博通BCM2835芯片手册导读及io口驱动代码的实现 树莓派寄存器的介绍 寄存器地址问题 驱动代码的实现 在linux中生成树莓派所需要的的程序及实现现象 一.树莓派寄存器的介绍 GPFSEL0 ...

  6. 树莓派高级开发之树莓派博通BCM2835芯片手册导读与及“相关IO口驱动代码的编写”

    首先我们要知道,驱动的两大利器:电路图(通过电路图去寻找寄存器)和芯片手册 一.寄存器的介绍 芯片手册第六章的89页,GPIO有41个寄存器,所有访问都是32位的.Description是寄存器的功能 ...

  7. 基于博通bcm2835芯片手册进行简单的树莓派引脚驱动

    目录 1.配置寄存器 2.设置寄存器的地址 3.编写驱动代码 4.编写应用层代码 5.编译 6.测试 1.配置寄存器 我们要进行树莓派引脚的驱动就要对树莓派的引脚进行一些配置,比如我想把树莓派的某个 ...

  8. 树莓派 博通BCM2835芯片手册

    手册提取链接 链接:https://pan.baidu.com/s/1fdmIBNn1Pr1j3-ercNhKJg 提取码:8y1b 驱动的两大利器: 1.电路图:通过电路图找到寄存器 2.芯片手册 ...

  9. 树莓派博通BCM2835芯片手册导读

    驱动两大利器︰电路图(通过电路图找寄存器)和芯片手册. 寄存器 芯片手册第六章P89∶ 字段名 描述 用法 GPFSEL0 GPIO Function select 0,功能选择输出/输入 以引脚9举 ...

最新文章

  1. 从视觉系统的原理入手 破解VR眩晕症
  2. php分布式redis实现session共享
  3. 无乱码的中文Joomla 1.0.15
  4. R语言学习笔记:向量
  5. Python爬虫入门(8):Beautiful Soup的用法
  6. Django框架连接MySQL数据库
  7. 从2018年12月起陆续将博客搬至博客园(cnblogs)
  8. 编译实验(一)词法分析
  9. nyoj--86--找球号(一)(hashset二分)
  10. 23行代码_动图展示——快排详解(排序最快的经典算法)
  11. 实习生对企业的认识_如何成为您认识的超级明星实习生
  12. 2021年河南省高考成绩啥时候查询,2021年河南高考成绩什么时候出来,今天几点钟出成绩可以查询...
  13. centos io 查看程序_快速免费搭建自己的带有直播、分销、团购、秒杀功能的小程序商城...
  14. 光有想法怎么开技术公司?
  15. 实用的科技论文写作短语
  16. 局域网内两台电脑ping不通
  17. unity 报错 Some objects were not cleaned up when closing the scene. 原因与方案
  18. 2020年中国透明聚丙烯(TPP)行业概况:仍有较大市场空间 [图]
  19. APP开发多少钱多少人和哪些注意事项
  20. 数据结构作业3-4(周)问题F:Turn off the light(关下灯)

热门文章

  1. adobe AE: 磁盘缓存文件夹所在的驱动器没有足够的可用空间来安全存储在首选项中指定的全部量
  2. 数字逻辑电路:一致性电路表决电路
  3. tp5 HBuilder h5打包app,并下载
  4. 《循序渐进LINUX》笔记
  5. 代码千万别写太长了!
  6. solidworks零件原点与装配原点重合
  7. EXCEL 如何实现下拉填充公式,保持公式部分内容不变,使用绝对引用
  8. 普通高等学校高职高专教育指导性专业目录专业简介
  9. 今夜では一人で雛祭り    001
  10. 无忧无虑的生活,只存在于梦想里吗?