FPGA-Xilinx ZYNQ PS端实现SD卡文件数据读取
本章节记录Xilinx ZYNQ PS端实现SD卡txt文件的数据读取。
踩坑记录,本章节主要内容参考原子哥
板子:xilinx zynq 7010
文章目录
- FPGA-Xilinx ZYNQ PS端实现SD卡文件数据读取
- 一、开发板引脚配置
- 二、PS端导入FATFS文件系统所需xilffs库
- 三、代码细节解释
- 四、完整代码
- 总结
一、开发板引脚配置
xilinx zynq 7010使用的sd卡的引脚,通过手册可知,
SD引脚为MIO40-45,card detect MIO47,
所以采用SD 0,如下图:
注意:直接跑原子哥的工程代码是行不通的,因为原子哥是7020板子,自己的是7010
二、PS端导入FATFS文件系统所需xilffs库
导入xilffs库,因为需要使用FATFS文件系统
如果代码无法识别到f_mount()函数,则需要的手动添加xilffs库,
如下图:
但我导入了这个之后,虽然可以识别到f_mount(),但无法使用ff.h中的f_gets()(已经include “ff.h”),不知道为什么,
如果有解决方法的,非常希望大家能够评论区给出。
三、代码细节解释
在copy原子哥代码时,需要注意xilffs的版本,版本不同函数有所改动,形参调用也不同。我的是xilinx zynq 7010,xilffs是3.7,原子哥是xilinx zynq 7020,xilffs是4.0.
//原子哥xilffs4.0代码:
status = f_mkfs(Path, FM_FAT32, 0, work, sizeof work);
//我xilffs3.7代码:
status = f_mkfs(Path, 1,sizeof work);
同时需要注意,因为使用的是SD 0 ,所以f_mount()函数需要选择挂载0口
status = f_mount(&fatfs, Path, 0); //挂载SD卡
同时注意,读取代码中的buffer[100]是用来获取一次100个数据的,temp_out_buffer[100]用于存储每一行的数据,用于输出或者处理,这样子分开两个数组进行分别操作,可以防止只使用一个数组出现数据覆盖的现象。
(因为txt每行的数据最多只有20个,所以buffer和temp_out_buffer数组定义只需要定义20个也是行得通的,但没试过,反正内存够)
每一行的数据获取结束标志位十分重要,这段代码不能丢!!!
temp_out_buffer[buffer_index] = '\0'; // 结束符号标志!重要!!
四、完整代码
#include "xparameters.h"
#include "xil_printf.h"
#include "ff.h"
#include "xdevcfg.h"
#include "stdio.h"
#define FILE_NAME "data.txt" //定义文件名
const char src_str[30] = "www.openedv.com"; //定义文本内容
static FATFS fatfs; //文件系统
//初始化文件系统
int platform_init_fs()
{
FRESULT status;
TCHAR *Path = "0:/";
BYTE work[512];
//注册一个工作区(挂载分区文件系统)
//在使用任何其它文件函数之前,必须使用f_mount函数为每个使用卷注册一个工作区
status = f_mount(&fatfs, Path, 0); //挂载SD卡
if (status != FR_OK) {
xil_printf("Volume is not FAT formated; formating FAT\r\n");
//格式化SD卡
status = f_mkfs(Path, 1,sizeof work);
if (status != FR_OK) {
xil_printf("Unable to format FATfs\r\n");
return -1;
}
//格式化之后,重新挂载SD卡
status = f_mount(&fatfs, Path, 1);
if (status != FR_OK) {
xil_printf("Unable to mount FATfs\r\n");
return -1;
}
}
return 0;
}
//挂载SD(TF)卡
int sd_mount()
{
FRESULT status;
//初始化文件系统(挂载SD卡,如果挂载不成功,则格式化SD卡)
status = platform_init_fs();
if(status){
xil_printf("ERROR: f_mount returned %d!\n",status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
//SD卡写数据
int sd_write_data(char *file_name,u32 src_addr,u32 byte_len)
{
FIL fil; //文件对象
UINT bw; //f_write函数返回已写入的字节数
//打开一个文件,如果不存在,则创建一个文件
f_open(&fil,file_name,FA_CREATE_ALWAYS | FA_WRITE);
//移动打开的文件对象的文件读/写指针 0:指向文件开头
f_lseek(&fil, 0);
//向文件中写入数据
f_write(&fil,(void*) src_addr,byte_len,&bw);
//关闭文件
f_close(&fil);
return 0;
}
//SD卡读数据
int sd_read_data(char *file_name,u32 src_addr,u32 byte_len)
{
FIL fil; //文件对象
UINT br; //f_read函数返回已读出的字节数
//打开一个只读的文件
f_open(&fil,file_name,FA_READ);
//移动打开的文件对象的文件读/写指针 0:指向文件开头
f_lseek(&fil,0);
//从SD卡中读出数据
f_read(&fil,(void*)src_addr,byte_len,&br);
//关闭文件
f_close(&fil);
return 0;
}
// 定义结构体存储X和Y的数值
typedef struct {
int x;
int y;
} DataPoint;
int parse_line(char *line, int *x, int *y)
{
return sscanf(line, "X: %d, Y: %d", x, y);
}
//main函数
int main()
{
int status,len;
char line[100]; // 适当的缓冲区大小以逐行读取数据
status = sd_mount(); //挂载SD卡
if(status != XST_SUCCESS){
xil_printf("Failed to open SD card!\n");
return 0;
}
else
xil_printf("Success to open SD card!\n\n");
//SD卡读数据
FIL fil; // 文件对象
TCHAR buffer[100]; // 适当的缓冲区大小以读取数据
TCHAR temp_out_buffer[100]={0};//用于临时存储一行数据并输出,会被下一行数据覆盖
UINT bytesRead;
int buffer_index = 0;
if (f_open(&fil, FILE_NAME, FA_READ) == FR_OK)
{
while (f_read(&fil, buffer, sizeof(buffer), &bytesRead) == FR_OK && bytesRead > 0)
{
for (int i = 0; i < bytesRead; i++)
{
// printf("buffer[%d] = %c\n",i,buffer[i]);
if (buffer[i] == '\n' || buffer[i] == '\r')
{
temp_out_buffer[buffer_index] = '\0'; // 结束符号标志!重要!!
buffer_index = 0;
DataPoint dataPoint;
if (parse_line(temp_out_buffer, &dataPoint.x, &dataPoint.y) == 2)
{
xil_printf("X: %d, Y: %d\r\n", dataPoint.x, dataPoint.y);
}
else
{
// xil_printf("Error parsing line: %s\n", buffer);
}
}
else
{
temp_out_buffer[buffer_index++] = buffer[i];
}
}
}
f_close(&fil);
}
else
{
printf("open file failed \n");
}
return 0;
}
总结
本章节对于FPGA PS 端SD卡文件数据读取处理进行了记录,主要还是防坑记录,毕竟自己也是找了不少资料才完成。
还有一些待完善内容,包括:文件读取数据存DDR,从DDR读出来处理后再存回DDR,然后再把处理好的数据传给PL端进行操作。