我可以使用user space
上的mmap
系统调用访问/dev/mem
中的i / o端口
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_PADS (BCM2708_PERI_BASE + 0x100000)
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000)
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
#define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000)
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdint.h>
static volatile uint32_t *gpio;
int main(int argc, char **argv)
{
int fd ;
//Obtain handle to physical memory
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
printf("Unable to open /dev/mem: %s\n", strerror(errno));
return -1;
}
//map a page of memory to gpio at offset 0x20200000 which is where GPIO goodnessstarts
gpio = (uint32_t *)mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x20200000);
if ((int32_t)gpio < 0){
printf("Mmap failed: %s\n", strerror(errno));
return -1;
}
//set gpio17 as an output
//increment the pointer to 0x20200004
//set the value through a little bit twiddling where we only modify the bits 21-23 in the register
*(gpio + 1) = (*(gpio + 1) & ~(7 << 21)) | (1 << 21);
//toggle gpio17 every second
while(1){
//set the pin high
//increment the pointer to 0x2020001C
*(gpio + 7) = 1 << 17;
//sleep
sleep(1);
//set the pin to low
//increment the pointer to 0x20200028
*(gpio + 10) = 1 << 17;
sleep(1);
}
}
地图仅适用于用户空间。现在,我如何在kernel space
设备驱动程序?
答案 0 :(得分:3)
ex的每个模块:GPIO模块都有自己的存储器映射,即处理器技术参考手册中指定的物理地址。首先,您需要使用check_mem_region
检查是否正在使用内存区域。如果使用request_mem_region
对该内存区域进行空闲请求访问,则使用ioremap
或ioremap_nocache
(将总线内存映射到CPU空间)映射GPIO模块,这会返回一个void指针。返回的地址不能保证可以直接用作虚拟地址;它只能由ioread*|iowrite*|read*|write*
等函数使用。使用ioread8|16|32/iowrite8|16|32
函数从/向I / O端口读取或写入。最后,您需要iounmap
取消映射内存,然后需要使用release_mem_region
释放内存区域。通常在内核空间中,大多数时候不需要检查和请求内存区域。您只需要使用ioremap
或ioremap_nocache
将总线内存映射到CPU空间,并使用iounmap
取消映射。