在vivado中给pl添加bram,bram的物理地址是0x40000000,将导出的比特流文件挂载到开发板上,对bram内存的读写其实和对系统物理内存的读写应该是一样的。
1、/dev/mem设备的简介
在计算机系统中,/dev/mem
是一个特殊的设备文件,它代表了整个物理内存。这个文件提供了对物理内存的直接访问,通常用于低级内存操作,比如驱动程序开发或系统级调试。
访问 /dev/mem
设备文件通常需要 root 权限,因为它允许用户执行对物理内存的读写操作。以下是一些基本的步骤和概念:
打开设备文件:使用标准的文件操作函数,比如 open()
,打开 /dev/mem
设备文件。
定位物理地址:确定要访问的物理内存地址。在Linux中,物理地址通常是从0开始的。
内存映射:使用 mmap()
函数将物理地址映射到进程的地址空间。这允许进程像访问普通内存一样访问物理内存。
读写操作:一旦内存被映射,就可以使用标准的内存访问函数,如 read()
和 write()
,来读取或写入物理内存。
同步和一致性:由于直接访问物理内存可能会绕过CPU的缓存,因此可能需要使用 msync()
函数或其他机制来确保内存的一致性。
关闭和解除映射:操作完成后,使用 close()
关闭设备文件,并使用 munmap()
来解除内存映射。
2、mmap函数的介绍
mmap函数的原型:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数说明:
-
void *addr
:这是映射区域的起始地址。如果传入NULL
,则系统会选择一个合适的地址来放置映射区域。如果传入非NULL
值,系统将尝试在指定的地址创建映射区域,但这不是强制性的,系统可能根据内存管理的需要选择另一个地址。 -
size_t length
:映射区域的长度,以字节为单位。这个值必须与文件大小或者页的大小(通常是 4KB)对齐。 -
int prot
:保护选项,指定映射区域的访问权限。可以是以下选项的组合:PROT_EXEC
:允许执行映射区域中的代码。PROT_READ
:允许读取映射区域中的数据。PROT_WRITE
:允许写入映射区域中的数据。PROT_NONE
:没有访问权限。 -
int flags
:控制映射区域特性的标志位。常用的标志位包括:MAP_SHARED
:对映射区域的写操作将反映到文件上,多个进程可以共享映射区域。MAP_PRIVATE
:创建一个私有的复制-on-write映射,写操作不会影响文件,只影响当前进程的映射区域。MAP_ANONYMOUS
:创建一个匿名映射,不与任何文件关联。MAP_FIXED
:强制在addr
指定的地址创建映射区域。 -
int fd
:文件描述符。如果使用匿名映射,这个值应该是-1
。否则,它应该是指向要映射的文件的文件描述符。 -
off_t offset
:文件映射的起始位置,通常应该是页大小的整数倍。对于匿名映射,这个值通常设置为 0。
3、源码
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BRAM_CTRL_0 0x40000000
#define DATA_LEN 10
int main(int argc, char **argv)
{
unsigned int *map_base0;
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0) {
printf("can not open /dev/mem \n");
return (-1);
}
printf("/dev/mem is open \n");
map_base0 = mmap(NULL, DATA_LEN * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BRAM_CTRL_0);
if (map_base0 == 0) {
printf("NULL pointer\n");
}
else {
printf("mmap successful\n");
}
unsigned long addr;
unsigned int content;
printf("\nwrite data to bram\n");
addr = (unsigned long)(map_base0);
content = 0x88888888;
map_base0[0] = content;
printf("address: 0x%lx data_write: 0x%x\t\t\n",addr, content);
close(fd);
munmap(map_base0, DATA_LEN);
return 0;
}
以上代码的流程大概可以概括为:使用open() 打开/dev/mem设备文件,使用mmap函数将物理地址0x40000000映射成为虚拟地址map_base0,然后将数据赋值给变量content,再写入到内存中。
4、运行结果及测试
将源码保存为bram_test.c并编译运行,运行结果如图所示:
使用devmem2的指令查看内存0x4000000中的数据(devmem2的使用请看上篇):
devmem读出的数据和源码里写入的数据是一样的,都是0x88888888
参考:ZYNQ linux下AXI_BRAM的使用方法,PS与PL端数据交互_zynqmp linux axi little-CSDN博客