美文网首页
7 模拟SPI进行TF卡操作+Fatfs文件系统移植

7 模拟SPI进行TF卡操作+Fatfs文件系统移植

作者: Savior2016 | 来源:发表于2018-10-17 14:30 被阅读251次

    FATFS版本FATFS R0.13b
    SD卡容量16G

    概述

    本文的重点是进行Fatfs文件系统的移植和初步的使用。TF卡的操作实际上是指令操作,即你想它发送固定的CMD指令,它接收到指令给你返回,因此只要是它支持的通讯方式,其实操作起来原理都是差不多的。后面会稍微展开介绍一些。
    这里用的是SPI通讯,模拟SPI通讯,就是用普通的IO口模拟SPI的时序,当作SPI跟SD卡通讯。就是在这个部分,抄了一个别人开源的程序,导致我在找bug的过程中,搞清楚了整个文件系统,甚至是扇区的一些东西。
    所以总结成这篇文章作为纪念。

    1 模拟SPI

    具体时序是什么,网上已经有很多了。因为是某个大神已经公开的代码,所以我就直接贴在这里。网上其他代码大多都是转的他的,不过不知道是历史原因还是什么,他代码里有一个错误。
    发送指令时,对应的地址他做了移位操作(addr<<9),这里是他的文章链接:nios ii之Micro SD卡(TF卡)spi。这个操作的意思是,一个扇区512个字节,读写某个扇区,起始地址就是扇区*512,也就是传入的addr是扇区号,指令需要的是实际的起始地址。但是经过测试发现,现在指令传入的地址,SD卡死直接作为扇区号去操作的,因此不需要移位。
    SD_spi_Solution.h

    #ifndef SD_SPI_SOLUTION_H_
    #define SD_SPI_SOLUTION_H_
    #include "mico.h"       //头文件,根据芯片更改
    
     
    #define CMD0    0   /* GO_IDLE_STATE */
    #define CMD55   55  /* APP_CMD */
    #define ACMD41  41  /* SEND_OP_COND (ACMD) */
    #define CMD1    1   /* SEND_OP_COND */
    #define CMD17   17  /* READ_SINGLE_BLOCK */
    #define CMD8    8   /* SEND_IF_COND */
    #define CMD18   18  /* READ_MULTIPLE_BLOCK */
    #define CMD12   12  /* STOP_TRANSMISSION */
    #define CMD24   24  /* WRITE_BLOCK */
    #define CMD25   25  /* WRITE_MULTIPLE_BLOCK */
    #define CMD13   13  /* SEND_STATUS */
    #define CMD9    9   /* SEND_CSD */
    #define CMD10   10  /* SEND_CID */
     
    #define CSD     9
    #define CID     10
     
     //这部分应根据具体的连线来修改!
    //SD_MISO(38脚),SD_CLK(37脚),SD_MOSI(36脚),SD_CS(35脚)                    
    #define SD_CS        (MICO_GPIO_35)
    #define SD_MISO      (MICO_GPIO_38)
    #define SD_CLK       (MICO_GPIO_37)
    #define SD_MOSI      (MICO_GPIO_36)
    //MISO                             
    #define  SPI_MI (MicoGpioInputGet((mico_gpio_t)SD_MISO))
    //CS
    #define  SPI_CS_L   (MicoGpioOutputLow( (mico_gpio_t)SD_CS ))          
    #define  SPI_CS_H   (MicoGpioOutputHigh( (mico_gpio_t)SD_CS ))
    //CLK
    #define  SPI_CLK_L  (MicoGpioOutputLow( (mico_gpio_t)SD_CLK ))            
    #define  SPI_CLK_H  (MicoGpioOutputHigh( (mico_gpio_t)SD_CLK ))
    //MOSI
    #define  SPI_MO_L   (MicoGpioOutputLow( (mico_gpio_t)SD_MOSI ))           
    #define  SPI_MO_H   (MicoGpioOutputHigh( (mico_gpio_t)SD_MOSI ))
    //delay 1us(actually not,it maybe is several us,I don't test it)
    void usleep(u16 i);
     
    //set CS low
    void CS_Enable();
     
    //set CS high and send 8 clocks
    void CS_Disable();
     
    //write a byte
    void SDWriteByte(u8 data);
     
    //read a byte
    u8 SDReadByte();
     
    //send a command and send back the response
    u8  SDSendCmd(u8 cmd,u32 arg,u8 crc);
     
    //reset SD card
    u8 SDReset();
     
    //initial SD card
    u8 SDInit();
     
    //read a single sector
    u8 SDReadSector(u32 addr,u8 * buffer);
     
    //read multiple sectors
    u8 SDReadMultiSector(u32 addr,u8 sector_num,u8 * buffer);
     
    //write a single sector
    u8 SDWriteSector(u32 addr,u8 * buffer);
     
    //write multiple sectors
    u8 SDWriteMultiSector(u32 addr,u8 sector_num,u8 * buffer);
     
    //get CID or CSD
    u8 SDGetCIDCSD(u8 cid_csd,u8 * buffer);
     
    //spi speed(0-255),0 is fastest
    //u8 spi_speed;
    //SD IO init
    void SDIOinit(void);
     
    #endif /* SD_SPI_SOLUTION_H_ */
    
    

    SD_spi_Solution.c

    #include"SD_spi_Solution.h"
    
    u16 spi_speed = 200;//the spi speed(0-255),0 is fastest
    u8 sd_state=0;
    //delay 1us(actually not,it maybe is several us,I don't test it)
    void usleep(u16 i)
    {
        while(i --);
    }
     
    //set CS low
    void CS_Enable()
    {
        //set CS low
        SPI_CS_L;
    }
     
    //set CS high and send 8 clocks
    void CS_Disable()
    {
        //set CS high
        SPI_CS_H;
        //send 8 clocks
        SDWriteByte(0xff);
    }
     
    //write a byte
    void SDWriteByte(u8 data)
    {
        u8 i;
     
        //write 8 bits(MSB)
        for(i = 0;i < 8;i ++)
        {
            SPI_CLK_L;
            usleep(spi_speed);
            if(data & 0x80) 
                      SPI_MO_H;
            else SPI_MO_L;
            data <<= 1;
            SPI_CLK_H;
            usleep(spi_speed);
        }
     
        //when DI is free,it should be set high
        SPI_MO_H;
    }
     
    //read a byte
    u8 SDReadByte()
    {
        u8 data = 0x00,i;
     
        //read 8 bit(MSB)
        for(i = 0;i < 8;i ++)
        {
            SPI_CLK_L;
            usleep(spi_speed);
            SPI_CLK_H;
            data <<= 1;
            if(SPI_MI) 
                data |= 0x01;
            usleep(spi_speed);
        }
     
        return data;
    }
     
    //send a command and send back the response
    u8  SDSendCmd(u8 cmd,u32 arg,u8 crc)
    {
        u8 r1,time = 0;
        //send the command,arguments and CRC
        SDWriteByte((cmd & 0x3f) | 0x40);
        SDWriteByte(arg >> 24);
        SDWriteByte(arg >> 16);
        SDWriteByte(arg >> 8);
        SDWriteByte(arg);
        SDWriteByte(crc);
    
        //read the respond until responds is not '0xff' or timeout
        do{
            r1 = SDReadByte();
            time ++;
            //if time out,return
            if(time > 254) break;
        }while(r1 == 0xff);
     
        return r1;
    }
     
    //reset SD card
    u8 SDReset()
    {
        u8 i,r1,time = 0;
     
        //set CS high
        CS_Disable();
     
        //send 128 clocks
        for(i = 0;i < 16;i ++)
        {
            SDWriteByte(0xff);
        }
     
        //set CS low
        CS_Enable();
     
        //send CMD0 till the response is 0x01
        do{
            r1 = SDSendCmd(CMD0,0,0x95);
            time ++;
            //if time out,set CS high and return r1
            if(time > 254)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while(r1 != 0x01);
     
        //set CS high and send 8 clocks
        CS_Disable();
     
        return 0;
    }
     
    //initial SD card(send CMD55+ACMD41 or CMD1)
    void SDIOinit(void)
    {
         //IO初始化
        MicoGpioInitialize((mico_gpio_t)SD_CS, OUTPUT_PUSH_PULL);
        MicoGpioInitialize((mico_gpio_t)SD_MISO, INPUT_PULL_UP);
        MicoGpioInitialize((mico_gpio_t)SD_CLK, OUTPUT_PUSH_PULL);
        MicoGpioInitialize((mico_gpio_t)SD_MOSI, OUTPUT_PUSH_PULL);
    }
    u8 SDInit()
    {
        u8 r1,time = 0;
        
       
    
        SDReset();
    
        //set CS low
        CS_Enable();
     
        //check interface operating condition
        r1 = SDSendCmd(CMD8,0x000001aa,0x87);
        //if support Ver1.x,but do not support Ver2.0,set CS high and return r1
        if(r1 == 0x05)
        {
            //set CS high and send 8 clocks
            CS_Disable();
            return r1;
        }
        //read the other 4 bytes of response(the response of CMD8 is 5 bytes)
        r1=SDReadByte();
        r1=SDReadByte();
        r1=SDReadByte();
        r1=SDReadByte();
     
        do{
            //send CMD55+ACMD41 to initial SD card
            do{
                r1 = SDSendCmd(CMD55,0,0xff);
                time ++;
                //if time out,set CS high and return r1
                if(time > 254)
                {
                    //set CS high and send 8 clocks
                    CS_Disable();
                    return r1;
                }
            }while(r1 != 0x01);
     
            r1 = SDSendCmd(ACMD41,0x40000000,0xff);
     
            //send CMD1 to initial SD card
            //r1 = SDSendCmd(CMD1,0x00ffc000,0xff);
            time ++;
     
            //if time out,set CS high and return r1
            if(time > 254)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while(r1 != 0x00);
     
        //set CS high and send 8 clocks
        CS_Disable();
     
        return 0;
    }
     
    //read a single sector
    u8 SDReadSector(u32 addr,u8 * buffer)
    {
        u8 r1;
        u16 i,time = 0;
     
        //set CS low
        CS_Enable();
     
        //send CMD17 for single block read
           // addr=addr*512;
        r1 = SDSendCmd(CMD17,addr,0x55);
        //if CMD17 fail,return
        if(r1 != 0x00)
        {
            //set CS high and send 8 clocks
            CS_Disable();
            return r1;
        }
     
        //continually read till get the start byte 0xfe
        do{
            r1 = SDReadByte();
            time ++;
            //if time out,set CS high and return r1
            if(time > 30000)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while(r1 != 0xfe);
     
        //read 512 Bits of data
        for(i = 0;i < 512;i ++)
        {
            buffer[i] = SDReadByte();
        }
     
        //read two bits of CRC
        SDReadByte();
        SDReadByte();
     
        //set CS high and send 8 clocks
        CS_Disable();
     
        return 0;
    }
     
    //read multiple sectors
    u8 SDReadMultiSector(u32 addr,u8 sector_num,u8 * buffer)
    {
        u16 i,time = 0;
        u8 r1;
     
        //set CS low
        CS_Enable();
     
        //send CMD18 for multiple blocks read
        r1 = SDSendCmd(CMD18,addr,0xff);
        //if CMD18 fail,return
        if(r1 != 0x00)
        {
            //set CS high and send 8 clocks
            CS_Disable();
            return r1;
        }
     
        //read sector_num sector
        do{
            //continually read till get start byte
            do{
                r1 = SDReadByte();
                time ++;
                //if time out,set CS high and return r1
                if(time > 30000 || ((r1 & 0xf0) == 0x00 && (r1 & 0x0f)))
                {
                    //set CS high and send 8 clocks
                    CS_Disable();
                    return r1;
                }
            }while(r1 != 0xfe);
            time = 0;
     
            //read 512 Bits of data
            for(i = 0;i < 512;i ++)
            {
                *buffer ++ = SDReadByte();
            }
     
            //read two bits of CRC
            SDReadByte();
            SDReadByte();
        }while( -- sector_num);
        time = 0;
     
        //stop multiple reading
        r1 = SDSendCmd(CMD12,0,0xff);
     
        //set CS high and send 8 clocks
        CS_Disable();
     
        return 0;
    }
     
    //write a single sector
    u8 SDWriteSector(u32 addr,u8 * buffer)
    {
        u16 i,time = 0;
        u8 r1;
     
        //set CS low
        CS_Enable();
     
        do{
            do{
                //send CMD24 for single block write
                r1 = SDSendCmd(CMD24,addr,0xff);
                time ++;
                //if time out,set CS high and return r1
                if(time > 60000)
                {
                    //set CS high and send 8 clocks
                    CS_Disable();
                    return r1;
                }
            }while(r1 != 0x00);
            time = 0;
     
            //send some dummy clocks
            for(i = 0;i < 5;i ++)
            {
                SDWriteByte(0xff);
            }
     
            //write start byte
            SDWriteByte(0xfe);
     
            //write 512 bytes of data
            for(i = 0;i < 512;i ++)
            {
                SDWriteByte(buffer[i]);
            }
     
            //write 2 bytes of CRC
            SDWriteByte(0xff);
            SDWriteByte(0xff);
     
            //read response
            r1 = SDReadByte();
            time ++;
            //if time out,set CS high and return r1
            if(time > 60000)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while((r1 & 0x1f)!= 0x05);
        time = 0;
     
        //check busy
        do{
            r1 = SDReadByte();
            time ++;
            //if time out,set CS high and return r1
            if(time > 60000)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while(r1 != 0xff);
     
        //set CS high and send 8 clocks
        CS_Disable();
     
        return 0;
    }
     
    //write several blocks
    u8 SDWriteMultiSector(u32 addr,u8 sector_num,u8 * buffer)
    {
        u16 i,time = 0;
        u8 r1;
     
        //set CS low
        CS_Enable();
     
        //send CMD25 for multiple block read
        r1 = SDSendCmd(CMD25,addr,0xff);
        //if CMD25 fail,return
        if(r1 != 0x00)
        {
            //set CS high and send 8 clocks
            CS_Disable();
            return r1;
        }
     
        do{
            do{
                //send several dummy clocks
                for(i = 0;i < 5;i ++)
                {
                    SDWriteByte(0xff);
                }
     
                //write start byte
                SDWriteByte(0xfc);
     
                //write 512 byte of data
                for(i = 0;i < 512;i ++)
                {
                    SDWriteByte(*buffer ++);
                }
     
                //write 2 byte of CRC
                SDWriteByte(0xff);
                SDWriteByte(0xff);
     
                //read response
                r1 = SDReadByte();
                time ++;
                //if time out,set CS high and return r1
                if(time > 254)
                {
                    //set CS high and send 8 clocks
                    CS_Disable();
                    return r1;
                }
            }while((r1 & 0x1f)!= 0x05);
            time = 0;
     
            //check busy
            do{
                r1 = SDReadByte();printf("n%d",r1);
                time ++;
                //if time out,set CS high and return r1
                if(time > 30000)
                {
                    //set CS high and send 8 clocks
                    CS_Disable();
                    return r1;
                }
            }while(r1 != 0xff);
            time = 0;
        }while(-- sector_num);
     
        //send stop byte
        SDWriteByte(0xfd);
     
        //check busy
        do{
            r1 = SDReadByte();
            time ++;
            //if time out,set CS high and return r1
            if(time > 30000)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while(r1 != 0xff);
     
        //set CS high and send 8 clocks
        CS_Disable();
     
        return 0;
    }
     
    //get CID or CSD
    u8 SDGetCIDCSD(u8 cid_csd,u8 * buffer)
    {
        u8 r1;
        u16 i,time = 0;
     
        //set CS low
        CS_Enable();
     
        //send CMD10 for CID read or CMD9 for CSD
        do{
            if(cid_csd == CID)
                r1 = SDSendCmd(CMD10,0,0xff);
            else
                r1 = SDSendCmd(CMD9,0,0xff);
            time ++;
            //if time out,set CS high and return r1
            if(time > 254)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while(r1 != 0x00);
        time = 0;
     
        //continually read till get 0xfe
        do{
            r1 = SDReadByte();
            time ++;
            //if time out,set CS high and return r1
            if(time > 30000)
            {
                //set CS high and send 8 clocks
                CS_Disable();
                return r1;
            }
        }while(r1 != 0xfe);
     
        //read 512 Bits of data
        for(i = 0;i < 16;i ++)
        {
            *buffer ++ = SDReadByte();
        }
     
        //read two bits of CRC
        SDReadByte();
        SDReadByte();
     
        //set CS high and send 8 clocks
        CS_Disable();
     
        return 0;
    }
    

    使用的时候需要修改的是void SDIOinit(void);进行相应端口的初始化,头文件上方宏定义中关于IO口电平的操作也需要做自己的修改。
    这里附获取SD卡容量的程序供调试用:

             u8 csddata[16] = {0};
        SDGetCIDCSD(CSD, csddata);
        u32 csize = csddata[9] + ((uint32_t)csddata[8] << 8) + ((uint32_t)(csddata[7] & 0x3f) << 16) + 1;
        u32 Capacity = csize << 9;
    

    Capacity单位是Kbyte。

    2 SD卡扇区简介

    知道一些扇区的知识,有利于程序调试。下载一个DiskGenius,SD卡插在电脑上,就可以看到SD卡的磁盘信息。


    RD1

    这里要特别特别注意的是,每一步操作都确认一下是SD卡还是你自己的电脑硬盘,不要重演我的悲剧。

    2.1 格式化

    此格式化非彼格式化,这里有更多的选项,顺便熟悉一些概念。
    选中SD卡(点上方的蓝条),然后点工具栏里的delete,删除当前分区(有几个删除几个)。


    delete

    然后点工具栏里最左边的Save All,再点击New Partition,会弹出来一个框,点下面的Advanced>>,展开高级页面:


    New Partition
    按图中圈的部分改好,第二个圈让它对其8个扇区,因为Fatfs可以设置读取块的大小,最大是4096,我估计这个选项会有影响,没有具体测试。
    比较重要的是三号圈,这里是begining sector,就是FAT32的起始扇区,就是这里存储着SD卡相关的配置信息。
    改好之后点OK,然后再点Save All。

    2.2 FAT32信息

    sector

    点dector edit,再点offset,出现下面这个框:


    offset

    按图上选,点OK就会跳转到2048页扇区了。


    0
    扇区以0xEB开头,表示活跃,Fatfs会检查这一位,以0x55,0xAA结尾,软件中两个分割线之间就是一个扇区,512个字节。在中间可以占到FAT32字样,FATFS就是通过这个来初步判断是什么文件系统类型的。
    最新版本的FATFS可以自己来找这一页,所以不用太担心这个offset,R0.1版本之前的好像只会在0页查找。写在其他页会找不到文件系统。

    3 Fatfs移植

    3.1 获取源码

    FatFs官网下载源码。

    源码
    移植要用到的是source里面的文件,把它们添加到工程里。

    3.2 移植

    这里只写简单移植使用的部分,更多的功能可以结合文档去探索。

    3.2.1 头文件修改

    include 包含的头文件,有一些是windows的,酌情清除掉,添加自己芯片的头文件,一般不用添加。

    • integer.h
      这里定义的是数据类型,我直接把多余的宏定义去掉了,然后添加自己芯片定义的数据类型,如包含u8 u32等定义所在的头文件。
    #ifndef FF_INTEGER
    #define FF_INTEGER
    #include "mico.h"
            /* Embedded platform */
    
    /* These types MUST be 16-bit or 32-bit */
    typedef int             INT;
    typedef unsigned int    UINT;
    
    /* This type MUST be 8-bit */
    typedef unsigned char   BYTE;
    
    /* These types MUST be 16-bit */
    typedef short           SHORT;
    typedef unsigned short  WORD;
    typedef unsigned short  WCHAR;
    
    /* These types MUST be 32-bit */
    typedef long            LONG;
    typedef unsigned long   DWORD;
    
    /* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
    typedef unsigned long long QWORD;
    
    #endif
    
    • ffconf.h
      这个是配置文件,主要是需要修改FF_VOLUMESFF_VOLUME_STRS,修改成
      #define FF_VOLUMES 2#define FF_VOLUME_STRS "RAM","SD","SD2","USB","USB2","USB3"。之前SD卡死可以挂载0磁盘的,现在不行了,我看了底层,挂载到0的时候会进入其他判断的分支。所以这里做这样的修改,后面会把SD卡挂载到磁盘1。

    3.2.2 实现diskio.c

    这个文件就是主要的功能上实现了,在这里对接上SPI操作和FatFs,主要是实现以下函数。

    • DSTATUS disk_status
      直接返回RES_OK就可以了。
    DSTATUS disk_status(
        BYTE pdrv /* Physical drive nmuber to identify the drive */
    )
    {
        DSTATUS stat;
        stat = RES_OK;
        return stat;
    }
    
    • DSTATUS disk_initialize
      初始化函数,可以把初始化IO口,初始化SD卡的函数放到这里,也可以放在自己喜欢的地方。无论如何,在使用文件系统前把SD卡初始化做好,这里返回RES_OK就可以了。
    DSTATUS disk_initialize(
        BYTE pdrv /* Physical drive nmuber to identify the drive */
    )
    {
        DSTATUS stat;
        int result;
        result = 0;//SDInit();
    
        if (result == 0)
        {
            stat = RES_OK;
        }
        else
        {
            stat = RES_ERROR;
        }
    
        return stat;
    }
    

    参数BYTE pdrv是设备号,如果只有一个设备就不用管它,如果挂载了其他设备,就自己做一下判断。

    • DRESULT disk_read
      读函数。跟SPI那部分程序就是在这里对接的。
    DRESULT disk_read(
        BYTE pdrv,  /* Physical drive nmuber to identify the drive */
        BYTE *buff,   /* Data buffer to store read data */
        DWORD sector, /* Start sector in LBA */
        UINT count  /* Number of sectors to read */
    )
    {
    
        DRESULT stat;
        int result;
        //BYTE buffd[512]={0};
        
        if(count==1)
        {
            result=SDReadSector(sector,buff);
        }
        else
        {
                result = SDReadMultiSector(sector, count, buff);
        }
        if (result == 0)
        {
            stat = RES_OK;
        }
        else
        {
            stat = RES_ERROR;
        }
    }
    
    • DRESULT disk_write
      写函数。
    DRESULT disk_write(
        BYTE pdrv,        /* Physical drive nmuber to identify the drive */
        const BYTE *buff, /* Data to be written */
        DWORD sector,    /* Start sector in LBA */
        UINT count        /* Number of sectors to write */
    )
    {
    
        DRESULT stat;
        int result;
        if(count==1)
        {
            result=SDWriteSector(sector,(uint8_t *)buff);
        }
        else
        {
                result = SDWriteMultiSector(sector, count, (uint8_t *)buff);
        }
        
        
        if (result == 0)
        {
            stat = RES_OK;
        }
        else
        {
            stat = RES_ERROR;
        }
    }
    
    • DRESULT disk_ioctl
      信息获取的函数,这个函数在格式化的时候有用,这里可以先不管它,直接返回RES_OK。
      我进行了一些指令的实现:
    DRESULT disk_ioctl(
        BYTE pdrv, /* Physical drive nmuber (0..) */
        BYTE cmd,  /* Control code */
        void *buff /* Buffer to send/receive control data */
    )
    {
        DRESULT stat;
        
        switch (cmd)
        {
        case CTRL_SYNC:
            stat = RES_OK;
            break;
        case GET_SECTOR_COUNT:
              u8 csddata[16] = {0};
        SDGetCIDCSD(CSD, csddata);
        u32 csize = csddata[9] + ((uint32_t)csddata[8] << 8) + ((uint32_t)(csddata[7] & 0x3f) << 16) + 1;
        u32 Capacity = csize << 9;
            *((DWORD *)buff) = Capacity;
            stat = RES_OK;
            break;
        case GET_SECTOR_SIZE:
    
            *(WORD *)buff = 512; //spi flash的扇区大小是 512 Bytes
            return RES_OK;
        case GET_BLOCK_SIZE:
            *((DWORD *)buff) = 4096;
            stat = RES_OK;
            break;
    
        default:
            stat = RES_PARERR;
            break;
        }
    
        return stat;
    }
    
    • DWORD get_fattime
      最后还要添加一个函数,这个函数就是给文件添加时间戳的,也可以不用,直接返回0就可以了。
    DWORD get_fattime(void)
    {
        
        return 0;
    }
    

    4 简单实使用

    经过上面的修改就差不多可以用了。不能用就找其他移植笔记看看缺了什么没有,主要是要注意现在SD卡不能挂载在0上面了。

    4.1 挂载

     FATFS ffs;   /* Work area (filesystem object) for logical drive */
      FRESULT fr;
      fr=f_mount(&ffs, "1:/", 1);
    

    f_mount的最后一个参数是1,就会立即挂载,是0就等需要的时候才挂载。

    4.2 读写文件

        FATFS ffs;   /* Work area (filesystem object) for logical drive */
        FRESULT fr;
        fr=f_mount(&ffs, "1:/", 1);
        //准备要写入的数据
        u8 buf[512]={0};
         for(int j=0;j<512;j++)
         {
           buf[j]='a';
         }
       //接收数据的数组
       u8 bufb[512]={0};
       fr = f_open( &fil, "1:/test2.txt",  FA_OPEN_APPEND|FA_WRITE);
       // int fsizei=0;
       //fsizei=f_size(&fil);//读取文件大小
       // fr = f_lseek(&fil, f_size(&fil));//移动光标
       fr = f_write(&fil, buf, 5, &bw);//写入5个字符
       f_close(&fil);
       fr=f_open(&fil, "1:/test2.txt", FA_OPEN_EXISTING | FA_READ);
       fr=f_read(&fil, bufb, 5, &br);
       f_close(&fil);
    
    

    FA_OPEN_APPEND:文件存在就打开,并将光标移动到文件末尾,便于添加新内容。文件不存在就新建文件。
    关于后面的参数选项官网有详细的解释:


    open

    这里与时俱进,不需要自己去移动光标了,可以直接通过参数打开文件并追加内容。

    5 问题

    因为我这是事后做的记录,没有重新去再移植一遍,所以记录上可能有疏忽。如果遇到什么问题可以给我反馈一下。

    相关文章

      网友评论

          本文标题:7 模拟SPI进行TF卡操作+Fatfs文件系统移植

          本文链接:https://www.haomeiwen.com/subject/nmblzftx.html