ZYNQ PS 读取 TF 卡 BIN 文件中的浮点数

  • 动机
    在进行 AI 算法加速器设计时,需要读取模型导出的权重和数据集数据作为加速器的输入,而目前我个人比较常用的做法是将权重和数据集(如果数据集过大,可以选择一两张图片)放到 SD/TF 卡中,然后 PS CPU核去进行数据读取,最后传输给 PL 端的加速器。
  • 目标
    本示例工程实现了读取 SD/TF 卡中 BIN文件 所包含的浮点数 到 PS 的DDR中, 每个 BIN的浮点数均保存在一维数组空间中

如果要读取 int , 如果读取后将浮点数转为定点数,都是可以在此工程基础上进行修改,去做测试的。

1 购买示例工程的途径

  • 示例工程价格: 5 元 (教学视频无字幕)
  • 购买渠道
  1. (QQ) 736340716 雪天鱼 — 加我好友进行咨询即可,备注 SD读取工程购买 或者类似的都行
  2. 雪天鱼的 B 站工房 — 用哔哩哔哩 app 扫码下面的二维码,即可跳转至我的工房 — ZYNQ_PS读取TF卡中bin文件的浮点数据示例工程 商品
    商品链接:ZYNQ_PS读取TF卡中bin文件的浮点数据示例工程
    二维码:
    image.png|350

也可以从我的B站主页进入我的工房,然后选择 ZYNQ_PS读取TF卡中bin文件的浮点数据示例工程 商品即可

image.png|375

2 工程资料包概览

image.png|725

4个教学视频,总共 30 min 左右,其中 3-上板结果演示 已上传 B站,链接为:ZYNQ PS 读取 TF 卡 BIN 文件中的浮点数 (3)上板结果演示_哔哩哔哩_bilibili

3 Vitis 工程实际操作

参考资料:领航者ZYNQ之嵌入式SDK开发指南_V2.0.pdf — 第十三章 SD 卡读写 TXT 文本实验

  • Vivado 工程:
  1. 使能 UART 和 SD 外设(使能CD),绑定到板卡指定的管脚,并在 MIO 的配置界面将 Bank1 的电压改为 LVCMOS 1.8V
  • Vitis 应用工程:
  1. 将测试数据的文件夹复制到 TF 卡(文件系统为:FAT32)中,并插入到板卡的 TF 卡槽中
  2. 选好纯英文文件夹,创建Vitis工程
    1. 创建好平台工程后,不要编译,否则创建的应用工程无法选择开发语言为c++先创建应用工程,再进行平台的编译
  3. 导入应用源代码
  4. 修改硬件平台设置,使能 xilffs 库,并进行平台编译
  5. 进行应用编译,并下载到开发板进行测试。(需要打开串口助手)
  • DDR Size 计算
    0x3FF00000(hex) = 1,072,693,248(dec)
    1,072,693,248 Bytes / 1024 = 1,047,552 KB
    1,047,552 / 1024 = 1023 MB

  • 最终结果
    PS CPU 实际读到的浮点数与参考值基本一致,有些许不同是因为参考值是保留了10位小数位,精度高一些。而 PS CPU 保留 6位小数位。
    image.png|750

image.png|500

4 FAT FileSystem

4.1 简介

FAT、HPFS 和 NTFS 文件系统的概述 - Windows Client | Microsoft Learn

4.2 FatFs 库文件组织:

ffconf.h     FatFs 模块配置文件
ff.h         FatFs 和应用模块公用的包含文件
ff.c         FatFs 模块
diskio.h     FatFs and disk I/O 模块公用的包含文件
integer.h    数据类型定义
option       可选的外部功能
diskio.c     FatFs 与disk I/O 模块接口层文件(不属于 FatFs 需要由用户提供)

4.3 常用结构体和函数

  • File object structure (FIL) 文件对象结构, 我理解为文件句柄
  • File function return code (FRESULT) 文件函数返回码, 指定该次函数执行情况, 返回为 FR_OK=0 时,执行成功,其余返回码都表示执行有问题,但可以通过打印返回码的方式快速了解错误原因。

FatFs - f_mount (elm-chan.org)

f_open 打开或者创建一个文件:

FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode);				/* Open or create a file */
参数:
fp 文件对象
path 文件所在路径
mode 文件访问模式,具体见下图

image.png|725

// Seek File Read/Write Pointer
FRESULT f_lseek (FIL* fp, FSIZE_t ofs);	 /* Move file pointer of the file object */
fp  指向打开的文件对象的指针
ofs 设置读/写指针距文件顶部的字节偏移量。数据类型 FSIZE_t 是 DWORD(32 位)或 QWORD(64 位)的别名,具体取决于配置选项 FF_FS_EXFAT。
  • 读操作: f_read FatFs - f_read (elm-chan.org)
    该函数从文件对象的读/写指针指向的文件偏移处开始从文件中读取数据。读/写指针随着读取的字节数而前进。函数成功后,应检查 *br 以检测文件结尾。如果 *br < btr,则表示读操作期间读/写指针到达文件末尾。
FRESULT f_read (
  FIL* fp,     /* [IN] File object */  指向打开的文件对象的指针
  void* buff,  /* [OUT] Buffer to store read data */ 指向用于存储数据的buffer
  UINT btr,    /* [IN] Number of bytes to read */ 要读取的字节数
  UINT* br     /* [OUT] Number of bytes read */ 已读取的字节数
);

5 实际遇到的问题

5.1 为什么不直接读取txt文件

txt 数据如下:

0.0219814759   
-0.0472012386
-0.6958550811
0.1151463836
0.3210625350

根据python打印长度和类型得:
13 <class 'str'>
14 <class 'str'>
14 <class 'str'>
13 <class 'str'>
13 <class 'str'>

即每个符号或者数字都按1字节算,然后加上字符结尾"\0", 得到每个浮点数的总字节数,并不是 4 个字节
所以不能 4 个字节, 4个字节的读。

5.2 terminate called after throwing an instance of ‘std::bad_alloc’

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

堆分配的空间过小

5.3 ERROR : f_open returned 13

查看 ff.h 文件,我们发现返回码 13 对应:

FR_NO_FILESYSTEM,		/* (13) There is no valid FAT volume */

即 SD 卡的格式不对,

  • FPGA板卡读取不了的格式:exFAT
  • 支持的格式:FAT32

格式化教程:参考视频

  1. 下载 DiskGenius 免费版本 DiskGenius – 正式版下载|免费下载,解压即可使用
  2. 清除SD卡的所有分区(注意:千万不要删成自己电脑的其他硬盘了),看到所有空间空闲即为成功
  3. 新建新分区,文件系统类型选择 FAT32,其余保持默认就行
    image.png|475

image.png|375
4. 点击左上角的 保存更改,并确认。

5.4 ERROR : f_read returned 7

返回码 7 在 ff.h 中的 FRESULT 枚举 中表示:FR_DENIED, /* (7) Access denied due to prohibited access or directory full */

reading vit_weights_bin/pos_embed.bin
ERROR : f_read returned 7

经检查,是此文件为空文件,估计是复制时出错了。

6 未实现的思路

读取浮点数直接到 2D/3D/4D 数组
伪代码:
(1) 打开文件
(2) 复位文件指针
(3) 通过嵌套循环,读取文件数据至指定数组单元 arr[i][j]...
(4) 关闭文件

思路:读取一个 float 字节的数据,然后单个字节循环读取,直到读取到换行符"\n"
用 python 打开 txt 文件结尾字符
只软复位 CPU 来重启程序,不对PL进行编程。

  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
``` /* * This function retrieves the name of the process associated with a given PID. * The name is returned in the ret parameter. * * Parameters: * pid - process ID to look up * ret - pointer to a char pointer that will be set to the process name * * Returns: * 0 on success * negative error code on failure */ int get_process_comm(pid_t pid, char **ret) { _cleanup_free_ char *escaped = NULL, *comm = NULL; int r; assert(ret); assert(pid >= 0); if (pid == 0 || pid == getpid_cached()) { /* If the PID is 0 (kernel process) or matches the current process, get the current process name using prctl */ comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 bytes according to prctl(2) */ if (!comm) return -ENOMEM; if (prctl(PR_GET_NAME, comm) < 0) return -errno; } else { /* Otherwise, read the process name from the /proc filesystem */ const char *p; p = procfs_file_alloca(pid, "comm"); /* Note that process names of kernel threads can be much longer than TASK_COMM_LEN */ r = read_one_line_file(p, &comm); if (r == -ENOENT) return -ESRCH; if (r < 0) return r; } /* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */ escaped = new(char, COMM_MAX_LEN); if (!escaped) return -ENOMEM; cellescape(escaped, COMM_MAX_LEN, comm); *ret = TAKE_PTR(escaped); return 0; } ``` 这是一个获取指定PID进程名称的函数。如果PID为0或与当前进程匹配,则使用prctl获取当前进程名称。否则,从/proc文件系统读取进程名称。函数将返回名称,并对名称进行转义以避免不可打印字符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪天鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值