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


29

内存映射的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
   );

然后它会做某事...

 // Always use volatile pointer!
   clk = (volatile unsigned *)clk_map;

当引用它时,会有0x26和0x27的这些奇怪的加法,那是什么意思?

 printf("Disabling I2S clock\n");
 *(clk+0x26) = 0x5A000000;
 *(clk+0x27) = 0x5A000000;

 usleep(10);

 printf("Confiure I2S clock\n");
 *(clk+0x26) = 0x5A000001;
 *(clk+0x27) = 0x5A000000 | 3<<12 | 1<<9; // divider: 3.125==0b11.001

 usleep(10);
 printf("Enabling I2S clock\n");
 *(clk+0x26) = 0x5A000011;

查看数据表,我可以看到它们在哪里有这些值,例如基址,但我正努力理解其他值。CLOCK_BASE确定在哪里,这是怎么回事?


1
这可能最适合StackOverflow。尽管它与RPi有关,但您更有可能在那里找到编程问题的答案。
Jivings 2012年

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

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

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

Answers:


18

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

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

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

但是,您不仅可以更改时钟值,还必须禁用时钟,更改值并重新启动。

如果这个答案太基本了,我深表歉意。在这种情况下,您的问题确实很棘手,祝您好运。您可能会发现此链接很有帮助

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

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

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

在Linux上,/ dev / mem是一个“ 字符设备文件,它是计算机主内存的映像

如果像文件一样打开它,则可以像文件一样对其进行读写。在提供的样本中,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


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

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

1

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.