树莓派学习——博通BCM2835芯片手册导读、IO口驱动代码调试和测试学习
一、树莓派寄存器介绍:
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口驱动代码调试和测试学习相关推荐
- 11.树莓派博通BCM2835芯片手册导读与IO口驱动代码调试和测试
11.树莓派博通BCM2835芯片手册导读与IO口驱动代码调试和测试 硬件地址的相关概念 总线地址 32位的操作系统 ,cpu最多只能访问2^32bit,即只能访问4G的内存 64位的操作系统 ,cp ...
- 树莓派学习笔记(十五)博通BCM2835芯片手册导读
树莓派3b的CPU型号为:BCM2835(ARM-cotexA53架构) CPU型号为2440.2410(ARM9架构) 编写驱动需要电路图(作用通过电路图找到寄存器).芯片手册 树莓派官网:http ...
- 树莓派——8、树莓派博通BCM2835芯片手册导读
(122条消息) 树莓派高阶课程7:树莓派博通BCM2835芯片手册导读_哒宰的自我修养的博客-CSDN博客 博通BCM2835芯片手册导读 驱动的两大利器: 电路图:通过电路图找到寄存器 芯片手册: ...
- 树莓派高阶课程7:树莓派博通BCM2835芯片手册导读
树莓派博通BCM2835芯片手册导读 驱动的两大利器: 电路图:通过电路图找到寄存器 芯片手册:进行编写 1.树莓派寄存器的介绍: GPFSEL0 GPIO Function Select 0: // ...
- 树莓派博通BCM2835芯片手册导读及io口驱动代码的实现
树莓派博通BCM2835芯片手册导读及io口驱动代码的实现 树莓派寄存器的介绍 寄存器地址问题 驱动代码的实现 在linux中生成树莓派所需要的的程序及实现现象 一.树莓派寄存器的介绍 GPFSEL0 ...
- 树莓派高级开发之树莓派博通BCM2835芯片手册导读与及“相关IO口驱动代码的编写”
首先我们要知道,驱动的两大利器:电路图(通过电路图去寻找寄存器)和芯片手册 一.寄存器的介绍 芯片手册第六章的89页,GPIO有41个寄存器,所有访问都是32位的.Description是寄存器的功能 ...
- 基于博通bcm2835芯片手册进行简单的树莓派引脚驱动
目录 1.配置寄存器 2.设置寄存器的地址 3.编写驱动代码 4.编写应用层代码 5.编译 6.测试 1.配置寄存器 我们要进行树莓派引脚的驱动就要对树莓派的引脚进行一些配置,比如我想把树莓派的某个 ...
- 树莓派 博通BCM2835芯片手册
手册提取链接 链接:https://pan.baidu.com/s/1fdmIBNn1Pr1j3-ercNhKJg 提取码:8y1b 驱动的两大利器: 1.电路图:通过电路图找到寄存器 2.芯片手册 ...
- 树莓派博通BCM2835芯片手册导读
驱动两大利器︰电路图(通过电路图找寄存器)和芯片手册. 寄存器 芯片手册第六章P89∶ 字段名 描述 用法 GPFSEL0 GPIO Function select 0,功能选择输出/输入 以引脚9举 ...
最新文章
- 从视觉系统的原理入手 破解VR眩晕症
- php分布式redis实现session共享
- 无乱码的中文Joomla 1.0.15
- R语言学习笔记:向量
- Python爬虫入门(8):Beautiful Soup的用法
- Django框架连接MySQL数据库
- 从2018年12月起陆续将博客搬至博客园(cnblogs)
- 编译实验(一)词法分析
- nyoj--86--找球号(一)(hashset二分)
- 23行代码_动图展示——快排详解(排序最快的经典算法)
- 实习生对企业的认识_如何成为您认识的超级明星实习生
- 2021年河南省高考成绩啥时候查询,2021年河南高考成绩什么时候出来,今天几点钟出成绩可以查询...
- centos io 查看程序_快速免费搭建自己的带有直播、分销、团购、秒杀功能的小程序商城...
- 光有想法怎么开技术公司?
- 实用的科技论文写作短语
- 局域网内两台电脑ping不通
- unity 报错 Some objects were not cleaned up when closing the scene. 原因与方案
- 2020年中国透明聚丙烯(TPP)行业概况:仍有较大市场空间 [图]
- APP开发多少钱多少人和哪些注意事项
- 数据结构作业3-4(周)问题F:Turn off the light(关下灯)