总线地址:
CPU能够访问内存的范围。
如32位的win7系统,内存条是8G,但是系统只能识别3.8G,装64位才能识别8G。
32位能访问2的32次方4,294,967,296bit = 4194304kb =4096Mb = 4Gb。
物理地址:
又叫做硬件的实际地址或绝对地址。
虚拟地址:
逻辑地址(基于算法的地址,软件层面的地址)。
当程序运行起来需要的内存超过物理地址大小,就会通过MMU把物理地址映射成虚拟地址来。
芯片手册第六章:
寄存器:
GPFSEL0 GPIO Function Select 0 功能选择 输出/输入 32位
GPSET1 GPIO Pin Output Set 1 输出1
Set GPIO pin n //设置引脚输出高电平
0 = No effect
GOCLR0 GPIO Pin Output Clear 0 清0
Clear GPIO pin n//设置引脚输出低电平
0 = No effect
//GPSET0 GPIO Pin Output Set 0 输出0
volatile指令不会由于编译器的优化而省略,且要求每次直接读值。
IO空间起始地址是0x3f000000,加上GPIO的偏移量0x2000000,所以GPIO的物理地址应该是从0x3f2000000开始的,然后在这个基础上进行Linux系统MMU内存虚拟化管理,映射到虚拟地址
基于驱动框架编写IO口驱动程序:
手册内配置寄存器说明:
功能寄存器:
引脚4的功能寄存器配置是在第12-14位
.write = pin4_write,
};
int __init pin4_drv_init(void) //真实驱动入口
{
int ret;
devno = MKDEV(major,minor); //创建设备号
ret = register_chrdev(major, module_name,&pin4_fops); //注册驱动 告诉内核,把这个驱动加入到内核驱动的链表中
pin4_class=class_create(THIS_MODULE,"myfirstdemo"); //让代码在dev下自动生成设备(如果用手动生成设备较麻烦指令为:sudo mknod 名字 类型(通常为c字
符串设备) 主设备号 次设备号)
pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name); //创建设备文件
GPFSEL0 = (volatile unsigned int*)ioremap(0x3f200000,4); //第一个参数为寄存器总线地址,第二个参数为寄存器指针大小
GPSET0 = (volatile unsigned int*)ioremap(0x3f20001C,4); //将寄存器地址通过ioremap映射到虚拟地址中去。
GPCLR0 = (volatile unsigned int*)ioremap(0x3f200028,4);
return 0;
}
void __exit pin4_drv_exit(void)
{
iounmap(GPFSEL0); //解除虚拟地址的映射,注意与定义时相反,定义时是先生成设备文件和驱动在映射地址,
iounmap(GPSET0); //解除时是先解除虚拟地址的映射,在卸载驱动
iounmap(GPCLR0);
device_destroy(pin4_class,devno); //销毁设备
class_destroy(pin4_class); //销毁类
unregister_chrdev(major, module_name); //卸载驱动
}
module_init(pin4_drv_init); //入口 内核加载该驱动时,这个宏会被调用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
将上述代码复制到Linux内核驱动的字符设备驱动路径的文件夹内,并进行内核编译,生成驱动。
代码存放路径:
对内核进项编译。如果没有在Makefile中添加配置需要在其中添加pin4启动模块。
编译完成之后将内核字符设备内的.ko文件复制到树莓派中
在树莓派中使用sudo insmod 指令对.ko 进行装载生成pin4驱动文件,装载成功后还需要对pin4使用sudo chmod +x /dev/pin4(或sudo chmod 666 /dev/pin4)修改属性。
对上层代码进行交叉编译:
上层代码:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd;
int cmd;
fd = ("/dev/pin4",O_RDWR);
if(fd<0){
printf("open failed\n");
perror("open");
}else{
printf("open success\n");
}
printf("input commnd:1/0\n");
return 0;
}
对上层代码进行交叉编译复制到树莓派中运行。