1 Vivado配置

​       BRAM 的使用方法为使用 AXI BRAM 控制器来控制 BRAM 生成器,Block Design 连接如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

       我这里配置的是真双端口 RAM,通过 PL 的逻辑对 BRAM 生成器的端口 B 进行写操作,在 PS 端对端口 A 进行读。

       BRAM 控制器和生成器的 IP 核配置如下:

​ 此外,我们也需要关注一下 BRAM的地址分配:

       这里的基地址和范围都可以根据自己需求修改,我这里对 BRAM 的需求不大,只用到了10个单元(10*32bit),用 4K 字节就完全足够了。

       Vivado 的相关配置到这就结束了,后续就只要按照流程生成比特流,导出 .xsa 文件即可。

2 Linux访问方式

2.1 通过 /dev/mem 访问

​       在Linux系统中,/dev/mem 是一个特殊的虚拟字符设备,它提供了用户态对内核态物理地址空间的直接访问。这个设备通常与内存映射(mmap)函数结合使用,允许用户空间程序直接读写内核物理内存,而无需经过内核空间

       我们可以采用命令行命令与用户空间程序两种方式来实现对 BRAM 的访问。

2.1.1 命令行命令

​       首先是命令行命令,devmem 是一个在 Linux 系统中用于直接访问物理内存的工具,它可以读取和写入指定物理地址处的内容,命令格式如下:

devmem <address> [64|32|16|8] [value]

       其中,address即要访问的物理地址,[64|32|16|8]是一个可选参数,为访问的位宽,如果不设置,则默认按32位访问,value也是个可选参数,如果设置了,则表示向物理内存对应地址写入相应的值;不设置,则表示向物理内存对应位置读出数据

       对于我的程序逻辑而言,直接在 PL 侧逻辑完成写后,读取即可:

devmem 0x82000008 32

       读取结果符合预期:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.1.2 用户空间程序

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>#define XPAR_BRAM_BASEADDR 0x82000000
#define DATA_LEN    1024int main()
{unsigned int *map_base;int fd = open("/dev/mem", O_RDWR | O_SYNC);if (fd < 0) {printf("can not open /dev/mem \n");return (-1);}map_base = mmap(NULL, DATA_LEN * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, XPAR_BRAM_BASEADDR);if (map_base == 0) {printf("NULL pointer\n");}else {printf("mmap successful\n");}uint32_t read_data;// 验证BRAM内容for (int i = 0; i < 5; i++) {lseek(fd, i * sizeof(uint32_t), SEEK_SET);read(fd, &read_data, sizeof(read_data));printf("BRAM1[%d] = 0x%08X\n", i, read_data);}close(fd);munmap(map_base, DATA_LEN);return 0;
}

​       前面提到,我们可以在Block Design 中的地址编辑中修改地址,它的最小单位就是4K,其它选项都是4K的整数倍,其实是有说法的,就像用户空间程序这里地址空间映射为4K字节,这是因为内存映射通常需要按页对齐(如 4KB,即 0x1000),就算映射的长度实际小于4K,也会向上对齐。

​       验证 BRAM 内容由于我涉及的只有 5 个单元,所以只查看五个单元的值。

1,特别注意 mmap 之后,一定要对应有 munmap,否则会导致内存泄露

2,munmapclose(fd) 在功能上没有严格的依赖顺序。munmap 负责解除内存映射,但不会关闭文件描述符。close(fd) 关闭文件描述符,但不会自动解除映射(已映射的内存仍可访问,但可能导致未定义行为)。

​       测试结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.2 编写字符驱动

2.2.1 设备树

       设备树只需要使用 Vitis 用 Xilinx 提供的模版生成或者使用 Petalinux 生成的设备树 pl.dtsi 即可,如果不知道怎么获取,可以参考我的另一篇博客:【ZYNQ Linux移植】2-获取设备树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​       这里需要关注的记录的是 axi_bram_ctrl_0 节点的 compatible 属性,因为我们后面使用 platform 设备驱动框架,需要用这个属性进行匹配,大家如果 Vivado 版本不一样,这里的版本会有差别,根据自己的情况进行修改。

2.2.2 驱动程序

       按照 platform 设备驱动框架编写驱动:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of.h>#define DRIVER_NAME "axi_bram"
#define BRAM_SIZE 0x1000static void __iomem *bram0_base;
static struct class *bram_class;
static struct device *dev_bram;
static struct cdev *cdev;
static dev_t dev_num;static int bram_open(struct inode *inode, struct file *file) {return 0;
}static int bram_release(struct inode *inode, struct file *file) {return 0;
}static ssize_t bram_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {if (*ppos >= BRAM_SIZE) return 0;if (*ppos + count > BRAM_SIZE)count = BRAM_SIZE - *ppos;if (copy_to_user(buf, bram0_base + *ppos, count))return -EFAULT;*ppos += count;return count;
}static ssize_t bram_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {if (*ppos >= BRAM_SIZE) return -ENOSPC;if (*ppos + count > BRAM_SIZE)count = BRAM_SIZE - *ppos;if (copy_from_user(bram0_base + *ppos, buf, count))return -EFAULT;*ppos += count;return count;
}static struct file_operations bram_fops = {.owner = THIS_MODULE,.open = bram_open,.release = bram_release,.read = bram_read,.write = bram_write,
};static int bram_probe(struct platform_device *pdev) {struct resource *res;// 获取BRAM0资源res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) return -ENODEV;bram0_base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(bram0_base)) return PTR_ERR(bram0_base);    // 创建设备号if (alloc_chrdev_region(&dev_num, 0, 1, DRIVER_NAME) < 0)return -ENODEV;// 创建设备cdev = cdev_alloc();if (!cdev) goto error;cdev_init(cdev, &bram_fops);if (cdev_add(cdev, MKDEV(MAJOR(dev_num), 0), 1) < 0) {kobject_put(&cdev->kobj);goto error;}dev_bram = device_create(bram_class, NULL, MKDEV(MAJOR(dev_num), 0), NULL, "bram0");if (IS_ERR(dev_bram)) goto error;return 0;error:unregister_chrdev_region(dev_num, 1);return -ENODEV;
}static int bram_remove(struct platform_device *pdev) {device_destroy(bram_class, MKDEV(MAJOR(dev_num), 0));unregister_chrdev_region(dev_num, 1);return 0;
}static const struct of_device_id bram_of_ids[] = {{ .compatible = "xlnx,axi-bram-ctrl-4.1" },{ }
};
MODULE_DEVICE_TABLE(of, bram_of_ids);static struct platform_driver bram_driver = {.driver = {.name = DRIVER_NAME,.of_match_table = bram_of_ids,},.probe = bram_probe,.remove = bram_remove,
};static int __init bram_init(void) {// 创建设备类bram_class = class_create(THIS_MODULE, "bram");if (IS_ERR(bram_class)) return PTR_ERR(bram_class);return platform_driver_register(&bram_driver);
}static void __exit bram_exit(void) {platform_driver_unregister(&bram_driver);class_destroy(bram_class);
}module_init(bram_init);
module_exit(bram_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Huaijun Chen");
MODULE_DESCRIPTION("Custom AXI BRAM Controller Driver");

​       驱动实际上也对内存进行了映射:devm_ioremap_resource(&pdev->dev, res)。但总体来说,使用驱动是在内核态进行操作,会比 2.1 中的映射方式安全一些,但调试难度上也更大。

2.2.3 测试应用程序

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>int main() {int fd = open("/dev/bram0", O_RDWR);if (fd < 0) {perror("open failed");return 1;}    uint32_t read_data;// 验证BRAM内容for (int i = 0; i < 5; i++) {lseek(fd, i * sizeof(uint32_t), SEEK_SET);read(fd, &read_data, sizeof(read_data));printf("BRAM[%d] = 0x%08X\n", i, read_data);}close(fd);return 0;
}

​       实际测试结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​       与 2.1 中测试结果完全相同。

2.3 使用 UIO

​       UIO(Userspace I/O,用户空间 I/O),泛指 UIO 设备和 UIO 驱动。UIO 内核驱动指负责将中断和设备内存暴露给用户空间,再由 UIO 用户态驱动来实现具体的业务

2.3.1 设备树

       与 2.2 中不同,由于需要使用 UIO(Userspace I/O,用户空间 I/O),所以需要在 Xilinx 生成的设备树的基础上进行一定的添加:

/ {uio@40000000 {compatible = "generic-uio";reg = <0x82000000 0x1000>;status = "okay";};
};

       这里需要注意 compatible 不可随便修改,因为这需要与 uio 驱动进行匹配,reg 中放我们的 BRAM 起始地址与大小(按32bit算)

       这里补充说明,修改了设备树启动后,Linux 系统会自动加载相关的驱动,并在 /dev 目录下可以看到 uio 设备的设备节点信息:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​       而在 /sys/class/uio 目录下可以查看具体 uio 的信息:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3.2 测试应用程序

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>#define UIO_DEV "/dev/uio"
#define BRAM_SIZE 0x1000int main() {int fd;volatile uint32_t *bram;// 打开UIO设备if ((fd = open(UIO_DEV, O_RDWR)) < 0) {perror("open uio0 failed");exit(EXIT_FAILURE);}// 内存映射bram = mmap(NULL, BRAM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (bram == MAP_FAILED) {perror("mmap failed");close(fd);exit(EXIT_FAILURE);}uint32_t read_data;// 验证BRAM内容for (int i = 0; i < 5; i++) {lseek(fd, i * sizeof(uint32_t), SEEK_SET);read(fd, &read_data, sizeof(read_data));printf("BRAM[%d] = 0x%08X\n", i, read_data);}munmap((void*)bram, BRAM_SIZE);close(fd);return 0;
}

​       实际测试结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​ 与前面的测试结果完全相同。

3 总结

       本文介绍了 ZYNQ Linux 下 BRAM 的三种驱动方式,分别是 /dev/mem/ 访问,编写字符驱动以及 UIO 三种方式。

       就安全性而言,字符驱动的安全性最高(当然也不能自己乱搞),/dev/mem/ 访问和UIO处于用户空间,安全性较差。

       就中断的支持方面来讲,通过 /dev/mem/ 访问是不支持中断的,其它两种均可支持中断。

       就开发难易程度而言,通过 /dev/mem/ 访问与 UIO 都非常简单,如果追求开发速度,可以先用这两种方法实现,避免拖慢整体开发速度,后续再使用字符设备驱动。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90217.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90217.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/90217.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flink ClickHouse 连接器数据写入源码深度解析

一、引言 在大数据处理的实际应用场景中&#xff0c;数据的高效存储与处理至关重要。Flink 作为一款强大的流式计算框架&#xff0c;能够对海量数据进行实时处理&#xff1b;而 ClickHouse 作为高性能的列式数据库&#xff0c;擅长处理大规模数据分析任务。Flink ClickHouse 连…

OpenCV 人脸分析------面部关键点检测类cv::face::FacemarkLBF

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 使用 Local Binary Features (LBF) 算法进行面部关键点检测&#xff08;facial landmark detection&#xff09;。该算法通过级联回归树预测人脸的…

Netstat高级分析工具:Windows与Linux双系统兼容的精准筛查利器

Netstat高级分析工具&#xff1a;Windows与Linux双系统兼容的精准筛查利器在网络安全运维中&#xff0c;快速识别可疑连接是防御入侵的关键一步。本文将介绍一款我本人开发的原创高效的双系统兼容Netstat信息分析工具&#xff0c;大幅提升恶意连接筛查效率。一、Netstat分析在安…

Bright Data MCP+Trae :快速构建电商导购助手垂直智能体

声明&#xff1a;本测试报告系作者基于个人兴趣及使用场景开展的非专业测评&#xff0c;测试过程中所涉及的方法、数据及结论均为个人观点&#xff0c;不代表任何官方立场或行业标准。 文章目录 一、引言1.1 当前AI智能体的趋势1.2 构建智能体面临的最大挑战&#xff1a;数据来…

plantuml用法总结

时序图 参考 https://blog.csdn.net/vitaviva/article/details/120735745用PlantUML简化复杂时序图的秘诀 startuml skin rose actor User as user participant "Component A" as A participant "Component B" as Buser -> A: Request data activate …

基于自研心电芯片国产化手持单导/6导/12导心电解决方案

苏州唯理作为国内心电芯片国产化厂商&#xff0c;面向家用场景&#xff0c;推出了国产化的手持单导/6导/12导心电仪技术解决方案&#xff0c;可以让家用心电图仪成本可控&#xff0c;信号链路质量更佳稳定。该方案已在多家客户中实现批量出货。唯理科技同样提供了医疗级的心电图…

Sass详解:功能特性、常用方法与最佳实践

Sass详解&#xff1a;功能特性、常用方法与最佳实践 Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;作为CSS预处理器领域的先驱&#xff0c;自2006年由Hampton Catlin创建以来&#xff0c;已成为现代前端开发中不可或缺的工具。它通过引入变量、嵌套、混合宏…

vulnhub靶机渗透:PWNLAB: INIT

一、信息收集1、主机发现2、端口扫描PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.10 ((Debian))111/tcp open rpcbind 2-4 (RPC #100000)3306/tcp open mysql MySQL 5.5.47-0deb8u151649/tcp open status 1 (RPC #100024)3、目录扫描&…

LiveKit 本地部署全流程指南(含 HTTPS/WSS)

1. 环境准备 操作系统&#xff1a;Windows 10/11 或 Linux/Mac需有本地公网/内网 IP&#xff08;如 192.168.x.x&#xff09;推荐浏览器&#xff1a;Chrome/Edge/Firefox/Safari端口未被占用&#xff0c;防火墙允许相关端口 2. 目录结构建议 livekit/livekit-server.execonf…

NumPy-统计函数详解

NumPy-统计函数详解一、基础统计函数&#xff1a;均值、方差、标准差1. 全局统计&#xff1a;忽略维度的整体计算2. 按轴统计&#xff1a;指定维度方向的计算二、位置统计&#xff1a;中位数、分位数、百分位数1. 中位数计算2. 分位数与百分位数三、离散程度&#xff1a;极差、…

音频被动降噪技术

音频被动降噪技术 音频被动降噪技术是一种通过物理结构和材料设计来减少或隔离外部噪声的降噪方式,其核心原理是通过物理屏障或吸声材料来阻断或吸收声波,从而降低环境噪声对听觉体验的影响。以下将从技术原理、应用场景、优缺点及与其他降噪技术的对比等方面进行详细分析。…

中国蚁剑使用方法

找到mysql配置文件 secure-file-priv工作目录 D:\tool\huli\gui_webshell\AntSword\AntSword\antSword-master重点是tool目录后面 前面大家可能都不一样 添加数据一句话木马 3C3F706870206576616C28245F504F53545B22636D64225D293B3F3E 翻译过来 <?php eval($_POST["c…

8.1 prefix Tunning与Prompt Tunning模型微调方法

1 prefix Tunning 链接&#xff1a;https://blog.csdn.net/m0_66890670/article/details/142942034 这里有基础的细节介绍。我下面直接总结。 连接2 &#xff1a;https://zhuanlan.zhihu.com/p/1899112824342577371&#xff0c;简单明了 prefix Tunning改变了什么呢&#xff…

FlashAttention 深入浅出

一 标准Attention的计算 1.1 标准Attention机制详解 标准Attention&#xff08;注意力&#xff09;机制是深度学习&#xff0c;尤其是在自然语言处理领域中一项革命性的技术&#xff0c;它允许模型在处理序列数据时&#xff0c;动态地将焦点放在输入序列的不同部分&#xff0c;…

C/C++ inline-hook(x86)高级函数内联钩子

&#x1f9f5; C/C inline-hook&#xff08;x86&#xff09;高级函数内联钩子 引用&#xff1a; fetch-x86-64-asm-il-sizeC i386/AMD64平台汇编指令对齐长度获取实现 &#x1f9e0; 一、Inline Hook技术体系架构 Inline Hook是一种二进制指令劫持技术&#xff0c;通过修改目…

云服务器的安全防护指南:从基础安全设置到高级威胁防御

随着云计算的广泛应用&#xff0c;云服务器已成为企业和个人存储数据、运行应用的重要基础设施。然而&#xff0c;随之而来的安全威胁也日益增多——从常见的网络攻击&#xff08;如 DDoS、SQL 注入&#xff09;到复杂的恶意软件和零日漏洞&#xff0c;无一不考验着系统的安全性…

状态机管家:MeScroll 的交互秩序维护

一、核心架构设计与性能基石 MeScroll作为高性能滚动解决方案&#xff0c;其架构设计遵循"分层解耦、精准控制、多端适配"的原则&#xff0c;通过四大核心模块实现流畅的滚动体验&#xff1a; 事件控制层&#xff1a;精准捕获触摸行为&#xff0c;区分滚动方向与距…

数据出海的隐形冰山:企业如何避开跨境传输的“合规漩涡”?

首席数据官高鹏律师数字经济团队创作&#xff0c;AI辅助凌晨三点的写字楼&#xff0c;某跨境电商的技术总监盯着屏幕上的报错提示&#xff0c;指尖悬在键盘上迟迟没落下。刚从新加坡服务器调取的用户行为数据&#xff0c;在传输到国内分析系统时被拦截了——系统提示“不符合跨…

【Rust base64库】Rust bas64编码解码详细解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Rust开发…

如何利用AI大模型对已有创意进行评估,打造杀手级的广告创意

摘要 广告创意是影响广告效果的最重要的因素之一&#xff0c;但是如何评估和优化广告创意&#xff0c;一直是一个难题。传统的方法&#xff0c;如人工评审、A/B测试、点击率等&#xff0c;都有各自的局限性和缺陷。本文将介绍一种新的方法&#xff0c;即利用人工智能大模型&am…