树莓派:mmap 点亮 led 灯 example,pi2 model B 直接物理地址映射
2015-10-30 23:43
435 查看
通常:
If you want to find a way for access physical memory in Linux there are only two solutions. The first is to develop a module running in kernel space with the correct privileges to access physical memory and the second is to use a special devices called “/dev/mem”.
mmap 可以直接将系统内存(/dev/mem)映射到用户进程空间的虚拟地址,通过调整位置,可以通过读写
如果是将物理地址映射到内核空间,则使用 ioremap
注意,需要能够读写
see link:
http://www.tldp.org/LDP/khg/HyperNews/get/devices/devices.html
http://www.tldp.org/LDP/khg/HyperNews/get/devices/fake.html
抛砖引玉,直接上代码:
哈,亮了:
查看树莓派gpio的物理地址:
树莓派1的外设文档,好像除了基地址不一样其他差不太多:
https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
要区分文档中的三个地址,bus address、physical address、virtual address
Peripherals (at physical address 0x20000000 on) are mapped into the kernel virtual address
space starting at address 0xF2000000. Thus a peripheral advertised
here at bus address 0x7Ennnnnn is available in the ARM kenel at virtual address 0xF2nnnnnn.
树莓派系统中,借助ARM内部的第一个MMU(全硬件映射),CPU将部分总线地址映射成了物理地址(通常总线地址与物理地址一样,但是如果中间有MMU, IOMMU 这两个地址就有差别了),然后通过第二个MMU(硬件)和linux系统的页表(数据结构)再映射到操作系统中的虚拟地址。CPU连接外设的总线起始地址为0x7E00 0000,被第一个MMU映射到物理 地址之后的起始地址变为0x2000 0000。以此类推,CPU与GPIO外设的总线起始地址为0x7E20 0000 = 0x7E00 0000+0x0020 0000,被MMU映射之后的GPIO外设地址为0x2000 0000+0x0020 0000。那么对于Linux系统而言,GPIO相关操作的物理起始地址为0x2020 0000(我们只需要关心物理地址就可以了,无需管第一个MMU的映射),然后再经过Linux系统的页表映射为虚拟地址就变成了 0xF2000000(kernel的逻辑地址,在高内存中)。在操作系统中所能访问的只能是虚拟地址(要么通过静态映射,要么通过动态映射,如mmap, mmap是将物理地址映射为可以在用户进程空间操作的虚拟地址——应该就是建立一个合适的页表映射吧)。如下图所示(注意,树莓派2 model B与此图有点差别,pi2 model B GPIO的物理起始地址为 0x3f200000):
以上都是自己总结,如有错误纯属罕见,哈哈。
关于 总线地址,物理地址,虚拟地址等等,see link:
http://www.makelinux.net/ldd3/chp-15-sect-1
关于虚拟地址,用户空间,内核空间,see link:
http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/
https://shanetully.com/2014/12/translating-virtual-addresses-to-physcial-addresses-in-user-space/
mmap 使用:
各种派:
https://linux.cn/article-6789-1.html
http://www.eeboard.com/evaluation/ricoboard/
If you want to find a way for access physical memory in Linux there are only two solutions. The first is to develop a module running in kernel space with the correct privileges to access physical memory and the second is to use a special devices called “/dev/mem”.
mmap 可以直接将系统内存(/dev/mem)映射到用户进程空间的虚拟地址,通过调整位置,可以通过读写
/dev/mem来读写系统的物理地址。因此可以很方便的用来写用户空间的驱动程序,只不过就是用户空间不能响应中断。
如果是将物理地址映射到内核空间,则使用 ioremap
注意,需要能够读写
/dev/mem的前提是你的内核关闭了
CONFIG_STRICT_DEVMEM配置选项(CONFIG_STRICT_DEVMEM=n),否则即使是root用户也不能够读写该设备。
see link:
http://www.tldp.org/LDP/khg/HyperNews/get/devices/devices.html
http://www.tldp.org/LDP/khg/HyperNews/get/devices/fake.html
抛砖引玉,直接上代码:
/** * guo.wei.1107@163.com */ #include <stdint.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <errno.h> // the raspberry pi 2 model B GPIO base address and pin2 registers #define GPIO_BASE 0x3f200000 // 该地址的是通过树莓派的地址映射找到的,见下文 #define GPIO_GPFSEL0 0x00 // offset of pin2 function select register, 32bit #define GPIO_GPSET0 0x1C // offset of pin2 set register, 32bit #define GPIO_GPCLR0 0x28 // offset of pin2 clear register, 32bit int main(int argc, char *argv[]) { int fd; // map is the memory to process, should run with sudo if ((fd = open("/dev/mem", O_RDWR)) == -1) { perror("open"); exit(1); } char *addr; addr = mmap(0, sysconf(_SC_PAGESIZE)/*getpagesize()*/, PROT_READ | PROT_WRITE, MAP_SHARED , fd, GPIO_BASE); if(addr == MAP_FAILED) { perror("mmap"); exit(1); } uint32_t * GPFSEL0 = (uint32_t *)(addr+GPIO_GPFSEL0); uint32_t * GPSET0 = (uint32_t *)(addr+GPIO_GPSET0); uint32_t * GPCLR0 = (uint32_t *)(addr+GPIO_GPCLR0); *GPFSEL0 = *GPFSEL0 | 0x40; // set the pin2 function register as output mode for(;;) { *GPCLR0 = 0x04; // set to 0 sleep(1); *GPSET0 = 0x04; // set to 1 sleep(1); } return 0; }
哈,亮了:
查看树莓派gpio的物理地址:
cat /proc/iomem | grep gpio
树莓派1的外设文档,好像除了基地址不一样其他差不太多:
https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
要区分文档中的三个地址,bus address、physical address、virtual address
Peripherals (at physical address 0x20000000 on) are mapped into the kernel virtual address
space starting at address 0xF2000000. Thus a peripheral advertised
here at bus address 0x7Ennnnnn is available in the ARM kenel at virtual address 0xF2nnnnnn.
树莓派系统中,借助ARM内部的第一个MMU(全硬件映射),CPU将部分总线地址映射成了物理地址(通常总线地址与物理地址一样,但是如果中间有MMU, IOMMU 这两个地址就有差别了),然后通过第二个MMU(硬件)和linux系统的页表(数据结构)再映射到操作系统中的虚拟地址。CPU连接外设的总线起始地址为0x7E00 0000,被第一个MMU映射到物理 地址之后的起始地址变为0x2000 0000。以此类推,CPU与GPIO外设的总线起始地址为0x7E20 0000 = 0x7E00 0000+0x0020 0000,被MMU映射之后的GPIO外设地址为0x2000 0000+0x0020 0000。那么对于Linux系统而言,GPIO相关操作的物理起始地址为0x2020 0000(我们只需要关心物理地址就可以了,无需管第一个MMU的映射),然后再经过Linux系统的页表映射为虚拟地址就变成了 0xF2000000(kernel的逻辑地址,在高内存中)。在操作系统中所能访问的只能是虚拟地址(要么通过静态映射,要么通过动态映射,如mmap, mmap是将物理地址映射为可以在用户进程空间操作的虚拟地址——应该就是建立一个合适的页表映射吧)。如下图所示(注意,树莓派2 model B与此图有点差别,pi2 model B GPIO的物理起始地址为 0x3f200000):
以上都是自己总结,如有错误纯属罕见,哈哈。
关于 总线地址,物理地址,虚拟地址等等,see link:
http://www.makelinux.net/ldd3/chp-15-sect-1
关于虚拟地址,用户空间,内核空间,see link:
http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/
https://shanetully.com/2014/12/translating-virtual-addresses-to-physcial-addresses-in-user-space/
mmap 使用:
char* addr; addr= mmap((void*)0x100000, 1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); printf("%p\n", addr); if(addr== MAP_FAILED) { perror("mmap"); return 0; } // 如果不提供文件描述符(-1),则需要加上MAP_ANONYMOUS标志(相当于在你的进程空间malloc的一块内存), // 文件 /dev/mem 是一个表示你电脑内存的字符设备, Byte addresses in mem are interpreted as physical memory addresses // 一般不使用MAP_FIXED,因为有可能地址 0x100000 已经被映射过了;如果是想共享内存,必须设置为 MAP_SHARED,否则改动的只是你自己的copy部分,就跟c++传值一样。 // 映射是以页为单位的 4096 Byte, 所以这里想映射1000个字节,其结果就是映射了一个页 // 因此,如果上述代码映射成功,表示该程序的虚拟地址从 0x1000000~0x1000000+4096 是可用的, // 读写 addr[4095] 没问题,但是如果是读写 addr[4096] 就会 segment fault 了
各种派:
https://linux.cn/article-6789-1.html
http://www.eeboard.com/evaluation/ricoboard/
相关文章推荐
- 树莓派中python获取GY-85九轴模块信息示例
- 在树莓派2或树莓派B+上安装Python和OpenCV的教程
- Raspberry PI 512M 入手
- banana pi BPI-M2 四核开源单板计算机
- 香蕉派 banana pi 英文论坛与GITHUB正式上线
- 香蕉派 banana pi BPI-M2_WiringPI 测试成功 代码已经上传GITHUB
- 树莓派(Raspberry Pi):完美的家用服务器
- 树莓派使用实例之:2 Pi R
- Arduino VS 树莓派:哪个才是你的菜?
- 在树莓派上安装游戏模拟器
- 把你的树莓派打造成一个NAS
- 教你用树莓派打造一个家庭影院
- 树莓派使用实例之:2 Pi R 第二篇:Web服务器
- Monitorix :支持服务器和树莓派的轻量级系统监控系统
- 如何安装树莓派摄像头模块
- 超级树莓派兄弟