内存映射的I / O寻址如何工作?

我试图理解提供的I2S示例:有人让它运行吗?。 >
#define BCM2708_PERI_BASE        0x20000000
#define CLOCK_BASE               (BCM2708_PERI_BASE + 0x101000) /* Clocks */


它首先映射代码,如下所示。 />
clk_map = (unsigned char *)mmap(
      (caddr_t)clk_mem,
      MAP_BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED|MAP_FIXED,
      mem_fd,
      CLOCK_BASE
   );


当被引用时,有0x26和0x27的这些奇怪的加法,那是什么意思?
在数据表中,我可以看到它们在其中具有某些值,例如基址,但是我正努力理解其他值。该CLOCK_BASE确定在哪里,怎么回事?

评论

这可能最适合StackOverflow。尽管它与RPi有关,但您更有可能在那里获得编程问题的答案。

也许可以,但是我觉得这是一个更一般的Pi编程相关问题,结合了数据手册和Pi硬件的解释。让我们看看它是否能得到一些好的信息。

好的。让我们看看它是怎么回事:)

我认为这在Stack Overflow上不会做得太好-这是非常专业的方法,在这里可能会引起更多专家的关注。

#1 楼

在计算机上,您写入指定的“内存地址”。该地址被系统识别为硬件地址,并且适当的硬件接收或发送适当的值。

大多数硬件系统具有许多可以设置或读取的寄存器。有些可能有一些,有些可能有许多。这些寄存器将被分组为一个连续范围。基本指针指向该范围内的第一个指针,例如,您使用base_pointer + 1写入第二个端口。您不必这样做,可以直接写一个指针,但是使用偏移量可以使事情更容易处理。

Raspberry Pi可以识别地址为0x20000000的大量硬件寄存器。 br />从BCM2708_PERI_BASE + 0x101000访问控制时钟系统的一系列寄存器。控制I2S时钟的寄存器是该块中的第38个和第39个寄存器,使用
BCM2708_PERI_BASE + 0x101000 + 0x26和0x27

写入您必须禁用时钟,更改值并重新启动它。在这种情况下,您的问题确实很棘手,祝您好运。您可能会发现此链接很有用

更新:为什么使用mmap而不直接写入内存?

当程序运行内存地址时,它认为它不是真实的地址,它们由内存管理器映射到实际地址。这使一个程序无法影响另一个程序。两个进程可以完全愉快地读写自己的地址1234,并且内存管理器将两个位置完全分开。

硬件端口位于绝对物理地址。但是您不能直接写信给他们,因为内存管理器会把您的地址映射到您的个人内存区域。计算机的主内存'

如果像文件一样打开它,则可以像文件一样对其进行读写。在提供的示例mem_fd中,是打开/ dev / mem

后得到的文件句柄。另一个使生活更轻松的系统是将文件映射到内存并像内存一样写入文件的功能。因此,如果您要在其中读取或写入不同的特定位的文件,则可以将其映射到内存中的某个位置,然后直接将其写为内存,而不用前后移动文件指针。

因此,在此示例中,代码将创建物理内存的句柄(就好像它是磁盘上的文件一样),然后要求系统将其视为是内存。有点令人费解,但为了绕过虚拟内存管理器并写入实际物理地址,这是必需的。值0x20000000似乎有点像鲱鱼。代码建议将此地址作为提示,系统不必在这里映射/ dev / mem,尽管它可能会这样做。通常,将传递null值,并且系统会将文件句柄映射到它认为最佳的任何地址。

现在物理内存已映射到进程虚拟内存,并且可以在您需要的位置进行读写期望。

参考文献:

http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html

http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=8496&p=104359

https://superuser.com/questions/71389/what- is-dev-mem

评论


我还有两个问题:为什么要映射?为什么不直接访问内存?

–亚历山大·张伯伦
2012年6月25日13:09

@AlexChamberlain因为代码在Linux上运行,所以您无法在每个进程获得自己的虚拟内存空间时直接访问内存。但是,可以打开并映射/ dev / mem以获得对物理内存的直接访问。

–不
2014年1月7日15:08

#2 楼

@AlexChamberlain这是由于操作系统结构所致。您可以不使用mmap,但是已声明分页,因此无法直接访问。在内核模式下,您可以不用mmap,例如,通过将驱动程序作为内核模块插入而不需要mmap。另外,在最简单的OS情况下,如果不使用页表存储器,则可以通过q在没有mmap的情况下进行访问。直接物理地址访问。