您的位置:首页 > 其它

树莓派: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)映射到用户进程空间的虚拟地址,通过调整位置,可以通过读写
/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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树莓派