如何为devmemon MT7620n使用mmap
How to use mmap for devmemon MT7620n
我正在尝试通过寄存器设置访问 MT7620n 的 GPIO。到目前为止,我可以使用 /sys/class/gpio/... 访问它们,但这对我来说还不够快。
在第 84 页的 MT7620 编程指南中,您可以看到 GPIO 基地址为 0x10000600,单个寄存器的偏移量为 4 字节。
类似于:
devmem 0x10000600
来自 shell 的工作绝对正常,但我无法从 c 程序内部访问它。
这是我的代码:
#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address
#define GPIO_BLOCK 4
volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
int m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
printf("ERROR open\n");
return -1;
}
gpiochip_0_Address = (unsigned long*)mmap(NULL, GPIO_BLOCK, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, GPIOCHIP_0_ADDDRESS);
close(m_mfd);
if(gpiochip_0_Address == MAP_FAILED)
{
printf("mmap() failed at phsical address:%d %s\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
return -2;
}
return 0;
}
我得到的输出是:
mmap() failed at phsical address:268436992 Invalid argument
我需要注意什么?我必须先让内存可访问吗?我是 运行 root。
谢谢
编辑
Peter Cordes 说得对,非常感谢。
这是我的最终解决方案,如果有人发现错误,请告诉我 ;)
#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address
volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
const size_t pagesize = sysconf(_SC_PAGE_SIZE);
unsigned long gpiochip_pageAddress = GPIOCHIP_0_ADDDRESS & ~(pagesize-1); //get the closest page-sized-address
const unsigned long gpiochip_0_offset = GPIOCHIP_0_ADDDRESS - gpiochip_pageAddress; //calculate the offset between the physical address and the page-sized-address
int m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
printf("ERROR open\n");
return -1;
}
page_virtual_start_Address = (unsigned long*)mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, gpiochip_pageAddress);
close(m_mfd);
if(page_virtual_start_Address == MAP_FAILED)
{
printf("ERROR mmap\n");
printf("mmap() failed at phsical address:%d %d\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
return -2;
}
gpiochip_0_Address = page_virtual_start_Address + (gpiochip_0_offset/sizeof(long));
return 0;
}
mmap
的文件偏移量参数必须是页面对齐的,这就是 one of the documented reasons mmap 失败并返回 EINVAL 的原因。
0x10000600
不是 4k 的倍数,甚至不是 1k 的倍数,所以这几乎肯定是您的问题。我认为任何系统的页面都不会小到 512B。
映射包含所需地址的整个页面,并访问该页面内偏移量处的 MMIO 寄存器。
要么对其进行硬编码,要么执行类似 GPIOCHIP_0_ADDDRESS & ~(page_size-1)
的操作以将地址向下舍入到页对齐边界。您应该能够做一些事情,将页面大小作为编译时常量,这样它仍然可以高效编译。
我正在尝试通过寄存器设置访问 MT7620n 的 GPIO。到目前为止,我可以使用 /sys/class/gpio/... 访问它们,但这对我来说还不够快。
在第 84 页的 MT7620 编程指南中,您可以看到 GPIO 基地址为 0x10000600,单个寄存器的偏移量为 4 字节。
类似于: devmem 0x10000600 来自 shell 的工作绝对正常,但我无法从 c 程序内部访问它。
这是我的代码:
#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address
#define GPIO_BLOCK 4
volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
int m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
printf("ERROR open\n");
return -1;
}
gpiochip_0_Address = (unsigned long*)mmap(NULL, GPIO_BLOCK, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, GPIOCHIP_0_ADDDRESS);
close(m_mfd);
if(gpiochip_0_Address == MAP_FAILED)
{
printf("mmap() failed at phsical address:%d %s\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
return -2;
}
return 0;
}
我得到的输出是:
mmap() failed at phsical address:268436992 Invalid argument
我需要注意什么?我必须先让内存可访问吗?我是 运行 root。
谢谢
编辑
Peter Cordes 说得对,非常感谢。
这是我的最终解决方案,如果有人发现错误,请告诉我 ;)
#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address
volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
const size_t pagesize = sysconf(_SC_PAGE_SIZE);
unsigned long gpiochip_pageAddress = GPIOCHIP_0_ADDDRESS & ~(pagesize-1); //get the closest page-sized-address
const unsigned long gpiochip_0_offset = GPIOCHIP_0_ADDDRESS - gpiochip_pageAddress; //calculate the offset between the physical address and the page-sized-address
int m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
printf("ERROR open\n");
return -1;
}
page_virtual_start_Address = (unsigned long*)mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, gpiochip_pageAddress);
close(m_mfd);
if(page_virtual_start_Address == MAP_FAILED)
{
printf("ERROR mmap\n");
printf("mmap() failed at phsical address:%d %d\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
return -2;
}
gpiochip_0_Address = page_virtual_start_Address + (gpiochip_0_offset/sizeof(long));
return 0;
}
mmap
的文件偏移量参数必须是页面对齐的,这就是 one of the documented reasons mmap 失败并返回 EINVAL 的原因。
0x10000600
不是 4k 的倍数,甚至不是 1k 的倍数,所以这几乎肯定是您的问题。我认为任何系统的页面都不会小到 512B。
映射包含所需地址的整个页面,并访问该页面内偏移量处的 MMIO 寄存器。
要么对其进行硬编码,要么执行类似 GPIOCHIP_0_ADDDRESS & ~(page_size-1)
的操作以将地址向下舍入到页对齐边界。您应该能够做一些事情,将页面大小作为编译时常量,这样它仍然可以高效编译。