[RISC-V MCU 应用开发] 【RISC-V MCU CH32V103测评】+FATFS移植及目录显示

[复制链接]
 楼主| qjp1988113 发表于 2020-11-25 22:40 | 显示全部楼层 |阅读模式
本帖最后由 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:
  1. /*-----------------------------------------------------------------------*/
  2. /* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
  3. /*-----------------------------------------------------------------------*/
  4. /* This is a stub disk I/O module that acts as front end of the existing */
  5. /* disk I/O modules and attach it to FatFs module with common interface. */
  6. /*-----------------------------------------------------------------------*/

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

  9. #define BLOCK_SIZE            512 /* 块大小 */

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

  22.         /* SD卡初始化 */
  23.         status = SD_Initialize();
  24.         if(status != 0){
  25.                 return STA_NOINIT;
  26.         }
  27.         else
  28.         {
  29.                 return RES_OK;
  30.         }
  31. }
  32. /****************************************
  33. *函数名称:disk_status
  34. *输    入:drv -指定要初始化的逻辑驱动器号,即盘符
  35.                应当取值0~9
  36. *输    出:函数返回一个磁盘状态作为结果
  37. *功    能:返回磁盘驱动器状态
  38. ******************************************/                                         
  39. DSTATUS disk_status (
  40.         BYTE drv               
  41. )
  42. {
  43.            return RES_OK;
  44. }
  45. /****************************************
  46. *函数名称:disk_read
  47. *输    入:drv     -指定要初始化的逻辑驱动器号,即盘符
  48.                    应当取值0~9
  49.           buff    -数据读取缓冲区
  50.           sector  -读扇区地址
  51.           count   -连续读多少个扇区  
  52. *输    出:函数返回一个磁盘状态作为结果
  53. *功    能:在磁盘驱动器上读取扇区
  54. ******************************************/   
  55. DRESULT disk_read (
  56.         BYTE drv,               
  57.         BYTE *buff,               
  58.         DWORD sector,        
  59.         BYTE count               
  60. )
  61. {
  62.         UINT8 res;
  63.         if (count==1){
  64.                 res = SD_ReadDisk(buff,sector,count);
  65.         }
  66.         else{
  67.         }
  68.         if(res==0){
  69.                 return RES_OK;
  70.         }
  71.         else{
  72.                 return RES_ERROR;
  73.         }
  74. }
  75. /****************************************
  76. *函数名称:disk_write
  77. *输    入:drv     -指定要初始化的逻辑驱动器号,即盘符
  78.                    应当取值0~9
  79.           buff    -数据写入缓冲区
  80.           sector  -写扇区地址
  81.           count   -连续写多少个扇区  
  82. *输    出:函数返回一个磁盘状态作为结果
  83. *功    能:在磁盘驱动器上写入扇区
  84. ******************************************/   
  85. #if _READONLY == 0
  86. DRESULT disk_write (
  87.         BYTE drv,                        
  88.         const BYTE *buff,
  89.         DWORD sector,               
  90.         BYTE count               
  91. )
  92. {
  93.         UINT8 res;
  94.         if (count==1){
  95.                 res = SD_WriteDisk((UINT8 *)buff,sector,count);
  96.         }
  97.         else{
  98.         }
  99.         if(res==0){
  100.                 return RES_OK;
  101.         }
  102.         else{
  103.                 return RES_ERROR;
  104.         }
  105.         
  106. }
  107. #endif /* _READONLY */
  108. /****************************************
  109. *函数名称:disk_write
  110. *输    入:drv     -指定要初始化的逻辑驱动器号,即盘符
  111.                    应当取值0~9
  112.           ctrl    -指定命令代码
  113.           buff    -指向参数缓冲区的指针,取决于命令代码
  114.           count   
  115. *输    出:函数返回一个磁盘状态作为结果
  116. *功    能:控制设备指定特性和除了读/写外的杂项功能
  117. ******************************************/  
  118. DRESULT disk_ioctl (
  119.         BYTE drv,               
  120.         BYTE ctrl,               
  121.         void *buff               
  122. )
  123. {
  124.         return RES_OK;
  125. }
  126. /****************************************
  127. *函数名称:get_fattime
  128. *输    入:无
  129. *输    出:当前时间以双字值封装返回,位域如下:
  130.           bit31:25  年(0~127)(从1980开始)
  131.           bit24:21  月(1~12)
  132.           bit20:16  日(1~31)
  133.           bit15:11  时(0~23)
  134.           bit10:5   分(0~59)
  135.           bit4:0    秒(0~59)
  136. *功    能:获取当前时间
  137. ******************************************/  
  138. DWORD get_fattime(void)
  139. {

  140.          return 0;

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


  11. /*---------------------------------------------------------------------------/
  12. / Functions and Buffer Configurations
  13. /----------------------------------------------------------------------------*/

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


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


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


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


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


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


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



  38. /*---------------------------------------------------------------------------/
  39. / Locale and Namespace Configurations
  40. /----------------------------------------------------------------------------*/

  41. #define _CODE_PAGE        1
  42. /* The _CODE_PAGE specifies the OEM code page to be used on the target system.
  43. /  Incorrect setting of the code page can cause a file open failure.
  44. /
  45. /   932  - Japanese Shift-JIS (DBCS, OEM, Windows)
  46. /   936  - Simplified Chinese GBK (DBCS, OEM, Windows)
  47. /   949  - Korean (DBCS, OEM, Windows)
  48. /   950  - Traditional Chinese Big5 (DBCS, OEM, Windows)
  49. /   1250 - Central Europe (Windows)
  50. /   1251 - Cyrillic (Windows)
  51. /   1252 - Latin 1 (Windows)
  52. /   1253 - Greek (Windows)
  53. /   1254 - Turkish (Windows)
  54. /   1255 - Hebrew (Windows)
  55. /   1256 - Arabic (Windows)
  56. /   1257 - Baltic (Windows)
  57. /   1258 - Vietnam (OEM, Windows)
  58. /   437  - U.S. (OEM)
  59. /   720  - Arabic (OEM)
  60. /   737  - Greek (OEM)
  61. /   775  - Baltic (OEM)
  62. /   850  - Multilingual Latin 1 (OEM)
  63. /   858  - Multilingual Latin 1 + Euro (OEM)
  64. /   852  - Latin 2 (OEM)
  65. /   855  - Cyrillic (OEM)
  66. /   866  - Russian (OEM)
  67. /   857  - Turkish (OEM)
  68. /   862  - Hebrew (OEM)
  69. /   874  - Thai (OEM, Windows)
  70. /        1    - ASCII only (Valid for non LFN cfg.)
  71. */


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


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


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



  97. /*---------------------------------------------------------------------------/
  98. / Physical Drive Configurations
  99. /----------------------------------------------------------------------------*/

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


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


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


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



  115. /*---------------------------------------------------------------------------/
  116. / System Configurations
  117. /----------------------------------------------------------------------------*/

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


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

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

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


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


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

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

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

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

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


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

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

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

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

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

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

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

  73.        }
  74.        else
  75.        {
  76.             printf("[url=home.php?mod=space&uid=1100831]@read[/url] data failed!\r\n");
  77.        }
  78.     }
  79.     else
  80.     {
  81.         printf("No such files,please check!\r\n");
  82.     }

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

  10.     m = 0;
  11.     j = 1;

  12.     strcpy(tbuf,path);

  13.     printf("the root path:%s\r\n", tbuf);
  14.     while(1)
  15.     {
  16.         if ( j > m )
  17.         {                                         //只有搜索子目录时才执行
  18.             f_opendir(&dir_a[j-1], (TCHAR*)tbuf);
  19.             l[j-1] = strlen((char *)tbuf);
  20.         }
  21.         m = j;
  22.         f_readdir(&dir_a[j-1], &fileinfo);                     //读取当前目录下的一个文件
  23.         if (fileinfo.fname[0] == 0)
  24.         {                          //到末尾了,退出
  25.             if (j>1) j--;                                      //下个循环进入父目录
  26.             else break;
  27.             tbuf[l[j-1]] = '\0';                               //存储的路径返回上级目录
  28.         }
  29.         else
  30.         {
  31.            #if _USE_LFN
  32.                fn = *fileinfo.lfname ? fileinfo.lfname : fileinfo.fname;
  33.            #else
  34.                fn = fileinfo.fname;
  35.            #endif

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

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

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

  51. }
执行结果如图(当前深度设置为3):
TEST.png
程序结构目录(整合了板上的一些外设,板子引脚设计的有些合理):
qqq.png
移植过程中发现把变量赋值给其本身也会报错: 22.png
这时蛋疼,修改IDE的代码分析功能:
右击工程名--->属性:
444.jpg
程序比较乱,请高手勿喷:
FATFS.rar (939.08 KB, 下载次数: 20)


评论

good  发表于 2020-12-1 09:01
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卡?
SD.jpg
后面打算令其读取MBP文件来显示图片。
 楼主| qjp1988113 发表于 2020-12-2 08:49 | 显示全部楼层
jinglixixi 发表于 2020-12-2 08:24
我的将前半部去掉,只保留SD的部分,其结果异常(见图),不知为什么都能查看容量了,却不能读写SD卡?

后 ...

你去掉了那些?把你初始化的代码贴上来。
jinglixixi 发表于 2020-12-2 10:18 | 显示全部楼层
本帖最后由 jinglixixi 于 2020-12-2 10:20 编辑
qjp1988113 发表于 2020-12-2 08:49
你去掉了那些?把你初始化的代码贴上来。

1.jpg
...
2.jpg
...
3.jpg






 楼主| qjp1988113 发表于 2020-12-2 12:14 | 显示全部楼层

从你的串口信息看,你的SD卡,并没有正常读取啊,你检测或者换张卡。
jinglixixi 发表于 2020-12-2 12:55 | 显示全部楼层
qjp1988113 发表于 2020-12-2 12:14
从你的串口信息看,你的SD卡,并没有正常读取啊,你检测或者换张卡。

是呀,能读容量,但不能读写,且换过16G的卡,但更惨连输出信息都没有。
 楼主| qjp1988113 发表于 2020-12-2 13:11 | 显示全部楼层
jinglixixi 发表于 2020-12-2 12:55
是呀,能读容量,但不能读写,且换过16G的卡,但更惨连输出信息都没有。 ...

板上R14有没有短接,就在SD卡槽边上的那个空电阻??
jinglixixi 发表于 2020-12-2 15:10 | 显示全部楼层
qjp1988113 发表于 2020-12-2 13:11
板上R14有没有短接,就在SD卡槽边上的那个空电阻??

没问题R14、R11全部都焊上了。
 楼主| qjp1988113 发表于 2020-12-2 15:25 | 显示全部楼层
我是看你串口输出的那个SDsize是0M,不正常,正常应该有的,我的那个SD size 就是14910M
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

627

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部

111

主题

627

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部