FPGA-Xilinx ZYNQ PS端实现SD卡文件数据读取

本章节记录Xilinx ZYNQ PS端实现SD卡txt文件的数据读取。
踩坑记录,本章节主要内容参考原子哥
板子:xilinx zynq 7010


一、开发板引脚配置

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端进行操作。