通过/dev/mem访问超4000字节报Bus Error及Python BRAM读写问题
问题根因
你遇到的超过4000字节触发Bus Error的问题,主要来自三个核心原因:
- mmap映射长度未做页对齐:Linux 下mmap映射的第二个参数必须是页大小(通常为4KB)的整数倍,你当前直接传入
length + virt_offset,当这个值不是页对齐时,访问映射边界外的地址就会触发SIGBUS。4000字节接近4KB页大小,超出后刚好跨页触发边界访问错误。 - 内核
CONFIG_STRICT_DEVMEM限制:多数默认发行版内核开启了该配置,禁止用户空间访问1MB以上的物理内存地址,你使用的0xa0000000地址远高于该阈值,未关闭该配置会直接触发访问异常。 - numpy数组赋值范围不匹配:写操作时你直接用
array[0:length] = data,如果data的长度和length>>2(32位单位的数量)不匹配,会触发越界访问。
修复方案
前置准备
首先确认内核关闭了CONFIG_STRICT_DEVMEM:在内核编译配置中关掉该选项,或者启动内核时添加strict-devmem=0参数,重启后生效。
修正后的读代码
import os import mmap import numpy as np def read_bram(raddr, size): page_size = mmap.PAGESIZE base_addr = raddr virt_base = base_addr & ~(page_size - 1) virt_offset = base_addr - virt_base # 映射长度向上做页对齐 map_len = (virt_offset + size + page_size - 1) & ~(page_size - 1) mmap_file = os.open('/dev/mem', os.O_RDWR | os.O_SYNC) try: mem = mmap.mmap(mmap_file, map_len, mmap.MAP_SHARED, mmap.PROT_READ | mmap.PROT_WRITE, offset=virt_base) # 按实际需要的长度读取,copy后数据脱离mmap生命周期,关闭映射后仍可正常访问 rdbuf = np.frombuffer(mem, dtype=np.uint32, count=size >> 2, offset=virt_offset).copy() finally: os.close(mmap_file) mem.close() return rdbuf
修正后的写代码
import os import mmap import numpy as np def write_bram(waddr, data): page_size = mmap.PAGESIZE # data为uint32类型的numpy数组,计算总字节大小 size = data.size * 4 base_addr = waddr virt_base = base_addr & ~(page_size - 1) virt_offset = base_addr - virt_base # 映射长度向上做页对齐 map_len = (virt_offset + size + page_size - 1) & ~(page_size - 1) mmap_file = os.open('/dev/mem', os.O_RDWR | os.O_SYNC) try: mem = mmap.mmap(mmap_file, map_len, mmap.MAP_SHARED, mmap.PROT_READ | mmap.PROT_WRITE, offset=virt_base) array = np.frombuffer(mem, dtype=np.uint32, count=size >> 2, offset=virt_offset) array[:] = data # 强制刷入物理内存,保证数据写入BRAM硬件 mem.flush() finally: os.close(mmap_file) mem.close()
注意事项
- 所有操作/dev/mem的程序必须以root权限运行,否则会没有访问权限。
- 确认BRAM的物理地址范围是连续的,且大小匹配你要读写的长度,不要访问BRAM地址范围之外的空间。
- 如果需要更高的读写性能,可以去掉
os.O_SYNC标志,操作完成后手动调用mem.flush()保证数据写入硬件。
内容的提问来源于stack exchange,提问作者ram
相关产品推荐
相关产品推荐

