本文主要介绍在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));),这样需要写入的数据是写入了,而通常会多写入一些其他数据,这也是没有办法,只有在读取的时候只读取有效部分。所以最终没有完全解决这个问题,希望有知道的朋友留言指教
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
与电子爱好者谈读图二被打赏50分 | |
【FRDM-MCXN947评测】Core1适配运行FreeRtos被打赏50分 | |
【FRDM-MCXN947评测】双核调试被打赏50分 | |
【CPKCORRA8D1B评测】---移植CoreMark被打赏50分 | |
【CPKCORRA8D1B评测】---打开硬件定时器被打赏50分 | |
【FRDM-MCXA156评测】4、CAN loopback模式测试被打赏50分 | |
【CPKcorRA8D1评测】--搭建初始环境被打赏50分 | |
【FRDM-MCXA156评测】3、使用FlexIO模拟UART被打赏50分 | |
【FRDM-MCXA156评测】2、rt-thread MCXA156 BSP制作被打赏50分 | |
【FRDM-MCXN947评测】核间通信MUTEX被打赏50分 |