打印
[RISC-V MCU 应用开发]

【RISC-V MCU CH32V103测评】+FATFS移植及目录显示

[复制链接]
994|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 qjp1988113 于 2020-11-26 08:56 编辑

拿到开发板已经快一周了,一直想做点什么,可是感觉V103的库做的和F103的太兼容了,就连函数的结构都差不多。前面先试了下几个外设,库函数好评,特别是IIC的库,我很喜欢这种把IIC协议分段写的模式,对于其他IIC芯片,自己就可以灵活运用了。经过昨天和今天的一点时间,我移植了下FATFS,并读写了TXT和,列出目录。下面谈一谈FATFS的移植,在这里,我一开始用最新版本的,可是总是碰到内存不足的,各种莫名其妙的问题,搞的不胜其烦。不是默认分配的内存大了,就是各种溢出的问题。后来想了下,以前在用M0时也用过FATFS,但FATFS不是最新版本的(M0的FLASH和RAM也不大).找到旧版的FATFS文件,主要就是:"diskio.c"、"diskio.h"、"ff.c"、"ff.h"、"ffconfig.h"。其中用户操作"diskio.c"和"ffconfig.h"即可。我仅做了SD的挂载,SPI FLASH未做。
diskio.c:
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/

#include "diskio.h"
#include "spi_sd.h"    //添加自己的SD驱动头文件

#define BLOCK_SIZE            512 /* 块大小 */

/****************************************
*函数名称:disk_initialize
*输    入:drv -指定要初始化的逻辑驱动器号,即盘符
               应当取值0~9
*输    出:函数返回一个磁盘状态作为结果
*功    能:初始化磁盘驱动器
******************************************/
DSTATUS disk_initialize (
        BYTE drv                                
)
{
        UINT8 status;

        /* SD卡初始化 */
        status = SD_Initialize();
        if(status != 0){
                return STA_NOINIT;
        }
        else
        {
                return RES_OK;
        }
}
/****************************************
*函数名称:disk_status
*输    入:drv -指定要初始化的逻辑驱动器号,即盘符
               应当取值0~9
*输    出:函数返回一个磁盘状态作为结果
*功    能:返回磁盘驱动器状态
******************************************/                                         
DSTATUS disk_status (
        BYTE drv               
)
{
           return RES_OK;
}
/****************************************
*函数名称:disk_read
*输    入:drv     -指定要初始化的逻辑驱动器号,即盘符
                   应当取值0~9
          buff    -数据读取缓冲区
          sector  -读扇区地址
          count   -连续读多少个扇区  
*输    出:函数返回一个磁盘状态作为结果
*功    能:在磁盘驱动器上读取扇区
******************************************/   
DRESULT disk_read (
        BYTE drv,               
        BYTE *buff,               
        DWORD sector,        
        BYTE count               
)
{
        UINT8 res;
        if (count==1){
                res = SD_ReadDisk(buff,sector,count);
        }
        else{
        }
        if(res==0){
                return RES_OK;
        }
        else{
                return RES_ERROR;
        }
}
/****************************************
*函数名称:disk_write
*输    入:drv     -指定要初始化的逻辑驱动器号,即盘符
                   应当取值0~9
          buff    -数据写入缓冲区
          sector  -写扇区地址
          count   -连续写多少个扇区  
*输    出:函数返回一个磁盘状态作为结果
*功    能:在磁盘驱动器上写入扇区
******************************************/   
#if _READONLY == 0
DRESULT disk_write (
        BYTE drv,                        
        const BYTE *buff,
        DWORD sector,               
        BYTE count               
)
{
        UINT8 res;
        if (count==1){
                res = SD_WriteDisk((UINT8 *)buff,sector,count);
        }
        else{
        }
        if(res==0){
                return RES_OK;
        }
        else{
                return RES_ERROR;
        }
        
}
#endif /* _READONLY */
/****************************************
*函数名称:disk_write
*输    入:drv     -指定要初始化的逻辑驱动器号,即盘符
                   应当取值0~9
          ctrl    -指定命令代码
          buff    -指向参数缓冲区的指针,取决于命令代码
          count   
*输    出:函数返回一个磁盘状态作为结果
*功    能:控制设备指定特性和除了读/写外的杂项功能
******************************************/  
DRESULT disk_ioctl (
        BYTE drv,               
        BYTE ctrl,               
        void *buff               
)
{
        return RES_OK;
}
/****************************************
*函数名称:get_fattime
*输    入:无
*输    出:当前时间以双字值封装返回,位域如下:
          bit31:25  年(0~127)(从1980开始)
          bit24:21  月(1~12)
          bit20:16  日(1~31)
          bit15:11  时(0~23)
          bit10:5   分(0~59)
          bit4:0    秒(0~59)
*功    能:获取当前时间
******************************************/  
DWORD get_fattime(void)
{

         return 0;

}
ffconfig.h (进行配置)
/*---------------------------------------------------------------------------/
/  FatFs - FAT file system module configuration file  R0.09  (C)ChaN, 2011
/----------------------------------------------------------------------------/
/
/ CAUTION! Do not forget to make clean the project after any changes to
/ the configuration options.
/
/----------------------------------------------------------------------------*/
#ifndef _FFCONF
#define _FFCONF 6502        /* Revision ID */


/*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations
/----------------------------------------------------------------------------*/

#define        _FS_TINY                1        /* 0:Normal or 1:Tiny */
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
/  object instead of the sector buffer in the individual file object for file
/  data transfer. This reduces memory consumption 512 bytes each file object. */


#define _FS_READONLY        0        /* 0:Read/Write or 1:Read only */
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/  writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/  f_truncate and useless f_getfree. */


#define _FS_MINIMIZE        0        /* 0 to 3 */
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/
/   0: Full function.
/   1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
/      are removed.
/   2: f_opendir and f_readdir are removed in addition to 1.
/   3: f_lseek is removed in addition to 2. */


#define        _USE_STRFUNC        0        /* 0:Disable or 1-2:Enable */
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */


#define        _USE_MKFS                0        /* 0:Disable or 1:Enable */
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */


#define        _USE_FORWARD        0        /* 0:Disable or 1:Enable */
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */


#define        _USE_FASTSEEK        0        /* 0:Disable or 1:Enable */
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */



/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/----------------------------------------------------------------------------*/

#define _CODE_PAGE        1
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/  Incorrect setting of the code page can cause a file open failure.
/
/   932  - Japanese Shift-JIS (DBCS, OEM, Windows)
/   936  - Simplified Chinese GBK (DBCS, OEM, Windows)
/   949  - Korean (DBCS, OEM, Windows)
/   950  - Traditional Chinese Big5 (DBCS, OEM, Windows)
/   1250 - Central Europe (Windows)
/   1251 - Cyrillic (Windows)
/   1252 - Latin 1 (Windows)
/   1253 - Greek (Windows)
/   1254 - Turkish (Windows)
/   1255 - Hebrew (Windows)
/   1256 - Arabic (Windows)
/   1257 - Baltic (Windows)
/   1258 - Vietnam (OEM, Windows)
/   437  - U.S. (OEM)
/   720  - Arabic (OEM)
/   737  - Greek (OEM)
/   775  - Baltic (OEM)
/   850  - Multilingual Latin 1 (OEM)
/   858  - Multilingual Latin 1 + Euro (OEM)
/   852  - Latin 2 (OEM)
/   855  - Cyrillic (OEM)
/   866  - Russian (OEM)
/   857  - Turkish (OEM)
/   862  - Hebrew (OEM)
/   874  - Thai (OEM, Windows)
/        1    - ASCII only (Valid for non LFN cfg.)
*/


//#define        _USE_LFN        0                /* 0 to 3 */
#define _USE_LFN    0       /* 0 to 3 */
#define        _MAX_LFN        255                /* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN support.
/
/   0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
/   1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
/   2: Enable LFN with dynamic working buffer on the STACK.
/   3: Enable LFN with dynamic working buffer on the HEAP.
/
/  The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
/  Unicode handling functions ff_convert() and ff_wtoupper() must be added
/  to the project. When enable to use heap, memory control functions
/  ff_memalloc() and ff_memfree() must be added to the project. */


#define        _LFN_UNICODE        0        /* 0:ANSI/OEM or 1:Unicode */
/* To switch the character code set on FatFs API to Unicode,
/  enable LFN feature and set _LFN_UNICODE to 1. */


#define _FS_RPATH                0        /* 0 to 2 */
/* The _FS_RPATH option configures relative path feature.
/
/   0: Disable relative path feature and remove related functions.
/   1: Enable relative path. f_chdrive() and f_chdir() are available.
/   2: f_getcwd() is available in addition to 1.
/
/  Note that output of the f_readdir fnction is affected by this option. */



/*---------------------------------------------------------------------------/
/ Physical Drive Configurations
/----------------------------------------------------------------------------*/

#define _VOLUMES        1
/* Number of volumes (logical drives) to be used. */


#define        _MAX_SS                512                /* 512, 1024, 2048 or 4096 */
/* Maximum sector size to be handled.
/  Always set 512 for memory card and hard disk but a larger value may be
/  required for on-board flash memory, floppy disk and optical disk.
/  When _MAX_SS is larger than 512, it configures FatFs to variable sector size
/  and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */


#define        _MULTI_PARTITION        0        /* 0:Single partition, 1/2:Enable multiple partition */
/* When set to 0, each volume is bound to the same physical drive number and
/ it can mount only first primaly partition. When it is set to 1, each volume
/ is tied to the partitions listed in VolToPart[]. */


#define        _USE_ERASE        0        /* 0:Disable or 1:Enable */
/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
/  should be added to the disk_ioctl functio. */



/*---------------------------------------------------------------------------/
/ System Configurations
/----------------------------------------------------------------------------*/

#define _WORD_ACCESS        0        /* 0 or 1 */
/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
/  option defines which access method is used to the word data on the FAT volume.
/
/   0: Byte-by-byte access.
/   1: Word access. Do not choose this unless following condition is met.
/
/  When the byte order on the memory is big-endian or address miss-aligned word
/  access results incorrect behavior, the _WORD_ACCESS must be set to 0.
/  If it is not the case, the value can also be set to 1 to improve the
/  performance and code size.
*/


/* A header file that defines sync object types on the O/S, such as
/  windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */

#define _FS_REENTRANT        0                /* 0:Disable or 1:Enable */
#define _FS_TIMEOUT                1000        /* Timeout period in unit of time ticks */
#define        _SYNC_t                        HANDLE        /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */

/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
/
/   0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
/   1: Enable reentrancy. Also user provided synchronization handlers,
/      ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
/      function must be added to the project. */


#define        _FS_SHARE        0        /* 0:Disable or >=1:Enable */
/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
   defines how many files can be opened simultaneously. */


#endif /* _FFCONFIG */
对于创建读写TXT的程序(混合了SD底层的直接读写):
 //SD TEST
    mem_init();        //初始化内部内存池
    Delay_Ms(300);
    while(SD_Initialize())//检测不到SD卡
    {
        printf("SD Card Error!\r\n");
        printf("Please Check! \r\n");
        LED2_TOG();
        Delay_Ms(300);
    }
    //检测SD卡成功
    LED2_OFF();
    printf("SD Card OK!\r\n");
    sd_size=SD_GetSectorCount();
    printf("SD Card Size: %d MB\r\n",sd_size>>11);
    SD_Read_Sectorx(0);
    printf("\r\n");
    //通过FATFS系统函数
    f_mount(0,&fs);

    /*   得到SD卡的总容量和剩余容量 */
    while(fat_getfree("0",&total,&free))
    {
         printf("@:FAT ERROR!\r\n");
         LED2_TOG();
         Delay_Ms(300);
    }
    LED2_OFF();

    printf("SD total is:%dMB!\r\n",total>>10);
    printf("SD Free  is:%dMB!\r\n",free>>10);
    /////////////////////////
    printf("FatFS write read test!\r\n");
    /*   创建文件并可对其写入 */
    rt = f_open(&fdst,"0:/Write.txt",FA_CREATE_ALWAYS | FA_WRITE);

    if ( rt == FR_OK )
    {
       printf(">Create Write.txt successful!\r\n");
       /* 将缓冲区的数据写到文件中 */
       rt = f_write(&fdst,g_szTextBuf, sizeof(g_szTextBuf), &bw);
       /*关闭文件 */
       f_close(&fdst);

       printf(">Write Write.txt successful!\r\n");
    }
    else
    {
        printf("[url=home.php?mod=space&uid=322316]@create[/url] Write.txt failed!\r\n");
    }
    Delay_Ms(1000);


    rt=f_open(&fdst,"0:/Write.txt",FA_READ);//打开文件

    if(rt == FR_OK)
    {
       printf(">Open Write.txt successful!\r\n");

       f_read(&fdst,buf,512,(UINT32*)&br);

       if(br)
       {
           printf(">The read data is: %s \r\n",buf);
       }
       else
       {
           printf("[url=home.php?mod=space&uid=1100831]@read[/url] data failed!\r\n");
       }
    }

    f_close(&fdst);
    /////////////////////////
    printf("FatFS read test!\r\n");
    //打开SD卡test.txt文本
    rt=f_open(&fdst,"0:/Book/test.txt",FA_READ);

    if(rt==0)
    {
       f_read(&fdst,buf,512,(UINT32*)&len);

       if(len)
       {
            printf("the read data is :%s\r\n",buf);

       }
       else
       {
            printf("[url=home.php?mod=space&uid=1100831]@read[/url] data failed!\r\n");
       }
    }
    else
    {
        printf("No such files,please check!\r\n");
    }

    f_close(&fdst);
遍历目录函数:
void ScanFileWithLevel(u8 * path)
{
    //现采用目录深度可控的非递归方法如下:
    #define LEVEL          <font color="#ff0000">3 </font>                                  //LEVEL设置大小代表遍历的深度,8就代表8层,内存足够的话可以设置更大些
    u8 j,m;
    u8 l[LEVEL];                                               //l[]保存每层文件夹长度,返回上级目录时用
    DIR dir_a[LEVEL];                                          //FATFS使用的目录结构,只有这个比较占内存需要LEVEL*36字节
    char tbuf[64];                                             //注意tbuf的大小要能放得下最深的文件名绝对路径
    char *fn;

    m = 0;
    j = 1;

    strcpy(tbuf,path);

    printf("the root path:%s\r\n", tbuf);
    while(1)
    {
        if ( j > m )
        {                                         //只有搜索子目录时才执行
            f_opendir(&dir_a[j-1], (TCHAR*)tbuf);
            l[j-1] = strlen((char *)tbuf);
        }
        m = j;
        f_readdir(&dir_a[j-1], &fileinfo);                     //读取当前目录下的一个文件
        if (fileinfo.fname[0] == 0)
        {                          //到末尾了,退出
            if (j>1) j--;                                      //下个循环进入父目录
            else break;
            tbuf[l[j-1]] = '\0';                               //存储的路径返回上级目录
        }
        else
        {
           #if _USE_LFN
               fn = *fileinfo.lfname ? fileinfo.lfname : fileinfo.fname;
           #else
               fn = fileinfo.fname;
           #endif

           sprintf((char *)tbuf,"%s/%s",tbuf,fn);//搜索到的文件或文件名连接成完整的路径

           //strcat(tbuf,"/");
           //strcat(tbuf,fn);//字符串连接

            if (fileinfo.fattrib & AM_DIR)
            {                   //是目录
                printf("%s [%dD]\r\n", tbuf,j);                //打印目录
                if (j<LEVEL) j++;                                  //下个循环进入子目录
            }
            else
            {
                printf("%s [%dF]\r\n", tbuf,j);                //打印文件
                tbuf[l[j-1]] = '\0';                           //存储的路径返回目录
            }
        }
    }

}
执行结果如图(当前深度设置为3):

程序结构目录(整合了板上的一些外设,板子引脚设计的有些合理):

移植过程中发现把变量赋值给其本身也会报错:
这时蛋疼,修改IDE的代码分析功能:
右击工程名--->属性:

程序比较乱,请高手勿喷:
FATFS.rar (939.08 KB)


使用特权

评论回复
评论
zhengfish 2020-12-1 09:01 回复TA
good 

相关帖子

沙发
jinglixixi| | 2020-11-26 01:42 | 只看该作者
感谢分享!!!

使用特权

评论回复
板凳
740071911| | 2020-11-26 08:45 | 只看该作者
我也在玩,跟你的结果差不多,文件名不对劲,你的也是呦

使用特权

评论回复
地板
jinglixixi| | 2020-12-2 08:24 | 只看该作者
本帖最后由 jinglixixi 于 2020-12-2 08:26 编辑

我的将前半部去掉,只保留SD的部分,其结果异常(见图),不知为什么都能查看容量了,却不能读写SD卡?

后面打算令其读取MBP文件来显示图片。

使用特权

评论回复
5
qjp1988113|  楼主 | 2020-12-2 08:49 | 只看该作者
jinglixixi 发表于 2020-12-2 08:24
我的将前半部去掉,只保留SD的部分,其结果异常(见图),不知为什么都能查看容量了,却不能读写SD卡?

后 ...

你去掉了那些?把你初始化的代码贴上来。

使用特权

评论回复
6
jinglixixi| | 2020-12-2 10:18 | 只看该作者
本帖最后由 jinglixixi 于 2020-12-2 10:20 编辑
qjp1988113 发表于 2020-12-2 08:49
你去掉了那些?把你初始化的代码贴上来。


...

...







使用特权

评论回复
7
qjp1988113|  楼主 | 2020-12-2 12:14 | 只看该作者

从你的串口信息看,你的SD卡,并没有正常读取啊,你检测或者换张卡。

使用特权

评论回复
8
jinglixixi| | 2020-12-2 12:55 | 只看该作者
qjp1988113 发表于 2020-12-2 12:14
从你的串口信息看,你的SD卡,并没有正常读取啊,你检测或者换张卡。

是呀,能读容量,但不能读写,且换过16G的卡,但更惨连输出信息都没有。

使用特权

评论回复
9
qjp1988113|  楼主 | 2020-12-2 13:11 | 只看该作者
jinglixixi 发表于 2020-12-2 12:55
是呀,能读容量,但不能读写,且换过16G的卡,但更惨连输出信息都没有。 ...

板上R14有没有短接,就在SD卡槽边上的那个空电阻??

使用特权

评论回复
10
jinglixixi| | 2020-12-2 15:10 | 只看该作者
qjp1988113 发表于 2020-12-2 13:11
板上R14有没有短接,就在SD卡槽边上的那个空电阻??

没问题R14、R11全部都焊上了。

使用特权

评论回复
11
qjp1988113|  楼主 | 2020-12-2 15:25 | 只看该作者
我是看你串口输出的那个SDsize是0M,不正常,正常应该有的,我的那个SD size 就是14910M

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

627

帖子

2

粉丝