这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » FPGA » Zynq中通过xilffs库读写SD卡的例程

共2条 1/1 1 跳转至

Zynq中通过xilffs库读写SD卡的例程

菜鸟
2017-06-27 15:46:53     打赏
本文主要介绍在zynq中通过xilffs库读写SD卡的一个例子,并给出在使用中遇到的问题。


在Xilinx SDK的standalone已移植好了FatFs库(SDK中叫做xilffs),所以在SDK中添加xilffs库后就可以在程序中使用FatFs中各API来操作SD卡,该库支持FAT12, FAT16 and FAT32文件系统(本例将SD卡格式化为FAT32)。FatFs API详细说明可查看 http://elm-chan.org/fsw/ff/00index_e.html 。


一个例子


zynq中PS部分已经集成了SD卡控制器,在PS部分需要打开SD卡控制器,并配置对应管脚(取决于开发板),本人用的开发板PS部分配置如下图


综合实现生成.bit后导出,lautch SDK进入SDK新建工程和BSP,由于用了xilffs库所以在BSP中需要选择打开xilffs,如下图


对于xilffs的设置如下图


enable_mmc选择false;fs_interface选择1;read_only选择false。可以参考后面Description描述来设置。本例使用如上默认配置即可。


c程序如下:
/*
* main.c
*
* Created on: 2016年8月20日
* Author: hsp
* 本文件实现SD写入一段字符串,然后从其中读出并打印到串口。
*
*/


#include 
#include "platform.h"
#include "xparameters.h"


#include "xil_printf.h"
#include "ff.h"
#include "xdevcfg.h"


static FATFS fatfs;


int SD_Init()
{
FRESULT rc;


rc = f_mount(&fatfs,"",0);
if(rc)
{
xil_printf("ERROR : f_mount returned %d\r\n",rc);
return XST_FAILURE;
}
return XST_SUCCESS;
}


int SD_Transfer_read(char *FileName,u32 DestinationAddress,u32 ByteLength)
{
FIL fil;
FRESULT rc;
UINT br;


rc = f_open(&fil,FileName,FA_READ);
if(rc)
{
xil_printf("ERROR : f_open returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_lseek(&fil, 0);
if(rc)
{
xil_printf("ERROR : f_lseek returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_read(&fil, (void*)DestinationAddress,ByteLength,&br);
if(rc)
{
xil_printf("ERROR : f_read returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_close(&fil);
if(rc)
{
xil_printf(" ERROR : f_close returned %d\r\n", rc);
return XST_FAILURE;
}
return XST_SUCCESS;
}


int SD_Transfer_write(char *FileName,u32 SourceAddress,u32 ByteLength)
{
FIL fil;
FRESULT rc;
UINT bw;


rc = f_open(&fil,FileName,FA_CREATE_ALWAYS | FA_WRITE);
if(rc)
{
xil_printf("ERROR : f_open returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_lseek(&fil, 0);
if(rc)
{
xil_printf("ERROR : f_lseek returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_write(&fil,(void*) SourceAddress,ByteLength,&bw);
if(rc)
{
xil_printf("ERROR : f_write returned %d\r\n", rc);
return XST_FAILURE;
}
rc = f_close(&fil);
if(rc){
xil_printf("ERROR : f_close returned %d\r\n",rc);
return XST_FAILURE;
}
return XST_SUCCESS;
}


#define FILE "test.txt"


int main()
{
init_platform();


const char src_str[] = "hsp test sd card write and read!";
u32 len = strlen(src_str);


SD_Init();
SD_Transfer_write(FILE,(u32)src_str,(len+1000));//当直接指定len时没有写出,需要指定较大的长度才会写出,原因未知


char dest_str[33];//len<=33
SD_Init();
SD_Transfer_read(FILE,(u32)dest_str,(len+1));


xil_printf("%s\r\n",dest_str);
print("SD write and read over!\r\n");


cleanup_platform();
return 0;
}


. SD_Init函数主要用f_mount函数注册工作区域
. SD_Transfer_read主要用f_open打开文件,后用f_read将从文件中读取数据到缓冲区,最后用f_close关闭文件
. SD_Transfer_write主要用f_open打开文件,后用f_write将缓冲区的内容写入到文件,最后用f_close关闭文件


FatFs API详细说明请参考上面FatFs链接中的说明。


注意:由于使用了strlen函数需要#include ;使用了FatFs API所以要#include "ff.h";使用了XST_SUCCESS之类的宏定义作为返回值所以要#include "xdevcfg.h"。


问题


关于文件名


刚开始定义#define FILE "husipeng_test.txt",每次运行在打开文件时返回6即FR_INVALID_NAME,也就是说文件名无效,查询API库Path Names页面,再看文件ffconf.h中有定义#define _FS_RPATH 0U;即文件名不能用子目录而且为8.3 format file name (SFN)格式,也就说文件名只能为:<8>

关于写保护


解决了以上文件名错误后,发现本次打开文件返回10即FR_WRITE_PROTECTED,也就是SD卡打开了写保护,本人开发板上使用的小卡且也没有写保护的设置管脚。最后发现直接在PS部分SD卡设置里将WP取消选择即可(改正后设置如上面PS部分设置图中所示),出错原因应该是开发板上没有写保护管脚相关的设置,而开始在PS中又设置了WP管脚并设定到了一个MIO管脚,这将导致对写保护的误判;WP管脚需要拉低才能取消写保护,才能写SD卡,所以也可以将SD控制器的WP管脚连到EMIO,然后在PL部分将此EMIO拉低即可;而这里选择使用前面不连接WP的方法。


关于文件长度


解决以上两个问题后,写入文件是成功了,但是从电脑中打开查看,test.txt文件是存在了,但是内容为空,产看写入字节数bw的值也非0的正确值,理应写入了才对,但实际上却没有写进去,后来改变写入数据的大小发现每次写入的字节数比f_write(&fil,(void*) SourceAddress,ByteLength,&bw);传递的参数ByteLength小几十到一百多B不等;也就是说最终真的写入文件的字节数比ByteLength小(而返回写入的字节数bw却与ByteLength相等);后来怀疑是内部缓存没有更新到文件中,但检查f_close中也调用了f_sync(fp);即Flush cached data。最后直接将传递入的ByteLength加大1000(如上程序中SD_Transfer_write(FILE,(u32)src_str,(len+1000));),这样需要写入的数据是写入了,而通常会多写入一些其他数据,这也是没有办法,只有在读取的时候只读取有效部分。所以最终没有完全解决这个问题,希望有知道的朋友留言指教


高工
2020-07-23 22:13:59     打赏
2楼

感谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]