请问在linux环境下中如何 *** 作寄存器?

请问在linux环境下中如何 *** 作寄存器?,第1张

在linux下控制硬件和在无 *** 作系统下控制硬件的不同主要在于硬件的地址不一样,在linux下要使用va(虚拟地址),而在无 *** 作系统下可以直接使用硬件的pa(物理地址)。

在linux-2.6.8.1/include/asm-arm/arch-s3c2410/map.h中定义了大部分硬件的物理地址和他们的虚拟地址。

现以gpio

F为例说明,gpio

的pa

基址(ba)为0x56000000,GPFCON

pa为0x56000050

即:可见偏移量为0x50,而我们在看看GPFCON

va

,vaba

:0xf0e0

0000,va:0xf0e0

0050,偏移量为0x50。我们只要知道了vaba,和他的偏移量,我们就能计算出va,从而,就可以对其进行 *** 作了。

如何获取vaba:在linux-2.6.8.1/include/asm-arm/arch-s3c2410/map.h中有定义。

计算机中,分级分层的思想随处可见,这也是计算机上的一个基本的思想和思路。

在LINUX *** 作系统中分了三级,三级偏移,一级地址的ba为0xf0000000,偏移到第二级,0xf0e0

0000

(以GPIO为例),再次偏移到第三级,0xf0e0

0050

(以GPFCON为例)。现在,就可以在linux

下通过0xf0e0

0050来对GPFCON

寄存器来进行 *** 作了。

源码中的实现过程如下:

#define

S3C2410_ADDR(x)

(0xF0000000+(x))//map.h

//linux下所有硬件一级地址vaba:0xF0000000

#define

S3C2410_VA_GPIO

S3C2410(0X00E00000)//map.h

//GPIO的偏移量0x00E00000,加上这个偏移量后,到了GPIO器件

#define

S3C2410_GPIOREG(x)

((x)+S3C2410_VA_GPIO)

#define

S3C2410_GPFCON

S3C2410_GPIOREG(0x50)//regs-gpio.h

//GPFCON寄存器的偏移量0x50,加上这个偏移量后,到了具体的寄存器,可以对硬件进行 *** 作了

#define

S3C2410_GPFDAT

S3C2410_GPIOREG(0x54)//regs-gpio.h

#define

S3C2410_GPFUP

S3C2410_GPIOREG(0x58)//regs-gpio.h

这一问题来自项目中一个实际的需求:

我需要在Linux启动之后,确认我指定的芯片寄存器是否与我在uboot的配置一致。

举个例子:

寄存器地址:0x20000010负责对DDR2的时序配置,该寄存器是在uboot中设置,现在我想在Linux运行后,读出改寄存器的值,再来检查该寄存器是否与uboot的配置一致。

Linux应用程序运行的是虚拟空间,有没有什么机制可以是完成我提到的这一需求。若行,还请附些测试代码。

谢谢!

这个需要用mmap()函数将寄存器物理地址映射为用户空间的虚拟地址,即将寄存器的那段内存映射到用户空间,函数介绍如下:

void* mmap(void * addr, size_t len, int prot, int flags, int fd, off_t offset)

该函数映射文件描述符 fd 指定文件的 [offset, offset + len] 物理内存区至调用进程的 [addr, addr + len] 的用户空间虚拟内存区,通常用于内存共享或者用户空间程序控制硬件设备,函数的返回值为最后文件映射到用户空间的地址,进程可直接 *** 作该地址。下面是测试代码(仅供参考):

#define DDR2_REG_BASE (0x20000000)

#define MAP_SIZE 4096UL

#define MAP_MASK (MAP_SIZE - 1)

static unsigned int pTestRegBase

static int dev_fd

dev_fd = open("/dev/mem", O_RDWR | O_NDELAY)

if (dev_fd <</SPAN>0) {

LOGE("open(/dev/mem) failed.")

return

}

pTestRegBase = (void *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd,DDR2_REG_BASE &~MAP_MASK)

if (MAP_FAILED == pTestRegBase) {

printf("mmap failed. fd(%d), addr(0x%x), size(%d)\n", dev_fd, DDR2_REG_BASE, MAP_SIZE)

} else {

unsigned int reg_value = *((volatile unsigned int *)(pTestRegBase + 10))

printf("reg_value = 0xx\n", reg_value)

munmap((void*)pTestRegBase, MAP_SIZE)

}

pTestRegBase = 0

if(dev_fd)

close(dev_fd)

这里将DDR2_REG_BASE开始大小为1个page的物理地址映射到了用户空间,然后就可以用pTestRegBase作为起始地址 *** 作寄存器了。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/8962395.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-23
下一篇2023-04-23

发表评论

登录后才能评论

评论列表(0条)

    保存