zynq中通过xilffs读写SD卡

本文主要介绍在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部分配置如下图

zynq中通过xilffs读写SD卡_第1张图片

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

zynq中通过xilffs读写SD卡_第2张图片

对于xilffs的设置如下图

zynq中通过xilffs读写SD卡_第3张图片

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"

问题

  1. 关于文件名

    刚开始定义#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个字符+.+<3字符方式,所以这里定义的文件名太长才引起的错误,所以改为#define FILE "test.txt"这样的短文件名即可解决这个问题。

  2. 关于写保护

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

  3. 关于文件长度

    解决以上两个问题后,写入文件是成功了,但是从电脑中打开查看,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));),这样需要写入的数据是写入了,而通常会多写入一些其他数据,这也是没有办法,只有在读取的时候只读取有效部分。所以最终没有完全解决这个问题,希望有知道的朋友留言指教。

你可能感兴趣的:(zynq)