芯片手册信息整理
cat /proc/cpuinfo
查看树莓派CPU信息
GPFSEL0 GPIO Function Select 0 功能选择:输入/输出 (GPIO Function Select Registers)32位
14-12 000 = GPIO Pin 4 is an input
14-12 001 = GPIO Pin 4 is an output
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
- 0 = No effect
- 1 = Clear GPIO pin n
驱动编译
寄存器代码设置:
这样写是直接写入的是物理地址
volatile unsigned int* GPFSEL0 = volatile(unsigned int *)0x3f000000;
volatile unsigned int* GPSET0 = volatile(unsigned int *)0x3f00001C;
volatile unsigned int* GPCLR0 = volatile(unsigned int *)0x3f000028;
volatile:
作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
树莓派起始地址注意说明:1
我们在编写驱动程序的时候,IO空间的起始地址是0x3f000000,加上GPIO的偏移量0x2000000,所以GPIO的物理地址应该是从0x3f200000开始的,然后在这个基础上进行Linux系统的MMU内存虚拟化管理,映射到虚拟地址上。
特别注意,BCM2708 和BCM2709 IO起始地址不同,BCM2708是0x20000000,BCM2709是0x3f000000,这是造成大部分人驱动出现“段错误”的原因。树莓派3B的CPU为BCM2709。
寄存器映射虚拟地址代码设置:
ioremap(0x3f000000,4);把物理地址转换成虚拟地址
GPFSEL0 = volatile(unsigned int *) ioremap(0x3f200000,4);
GPSET0 = volatile(unsigned int *) ioremap(0x3f20001C,4);
GPCLR0 = volatile(unsigned int *) ioremap(0x3f200028,4);
配置pin4引脚为输出引脚,bit 12–14 配置成001
&、|异或运算2
*GPFSEL0 &= ~( 0x6 << 12); //把bit14 bit13 配置成0
*GPFSEL0 |= ( 0x1 << 12);
驱动程序编写:
#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 *pin4_class; //主设备
static struct device *pin4_class_dev; //次设备
static dev_t devno; //设备号
static int major =231; //主设备号
static int minor =0; //次设备号
static char *module_name="pin4"; //模块名
volatile unsigned int* GPFSE