OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 8613|回复: 15

HAL库基于STM32CUBEIDE生成FATFS挂载SD卡 踩坑记!!!

[复制链接]

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
发表于 2020-9-29 12:18:43 | 显示全部楼层 |阅读模式
本帖最后由 jiangyy 于 2020-9-29 14:13 编辑

  HAL库也是目前比较流行的MDK开发包,但很多朋友一直在用KEIL5软件,但是后续使用HAL库开发,编译速度大大降低,好处是大家用习惯了,很上手。但是意法半导体后期主打STM32CUBEIDE软件,面向图形界面开发编程,一键生成代码,减小开发周期和开发难度,大大缩小项目开发成本和时间,而且还有一点是,HAL库对代码的严谨性特别强,这点是编程工作者不能忽略的。今天特意在这里说一下关于图形化生成FATFS文件系统,挂载SD卡。我的软件版本是STM32CubeIDE Version: 1.4.2,库包版本是STM32CubeIDE FW_F4 V1.25.1,应该算是最新的了。目前基本上已调通(这里好多坑,填补了不少),只是有一个地方出问题,就是FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); 获取剩余容量和总容量错误。我把bsp_fatfs.c代码贴出来
  1. /*
  2. * bsp_fatfs.c
  3. *
  4. *  Created on: Sep 26, 2020
  5. *      Author: jiangyuanyuan
  6. */

  7. #include "bsp_fatfs.h"
  8. FATFS fs;                 //工作空间
  9. FIL fil;                  // 文件项目
  10. uint32_t byteswritten;    // 写文件计数
  11. uint32_t bytesread;       // 读文件计数
  12. uint8_t wtext[] = "This is a 8G Card!!!"; // 写的内容
  13. uint8_t rtext[1024];             // 读取的buff
  14. char filename[] = "FATFS.txt"; // 文件名

  15. //得到磁盘剩余容量
  16. //drv:磁盘编号("0:"/"1:")
  17. //total:总容量         (单位KB)
  18. //free:剩余容量         (单位KB)
  19. //返回值:0,正常.其他,错误代码
  20. vu8 exf_getfree(u8 *drv,u32 *total,u32 *free)
  21. {
  22.         FATFS *fs1;
  23.         vu8 res;
  24.     u32 fre_clust=0, fre_sect=0, tot_sect=0;

  25.     //得到磁盘信息及空闲簇数量
  26.     res = f_getfree((const TCHAR*)drv, (DWORD*)&fre_clust, fs1);
  27.     if(res==0)
  28.         {
  29.             tot_sect=(fs1->n_fatent-2)*fs1->csize;        //得到总扇区数
  30.             fre_sect=fre_clust*fs1->csize;                        //得到空闲扇区数
  31. #if _MAX_SS!=512                                                                  //扇区大小不是512字节,则转换为512字节
  32.                 tot_sect*=fs1->ssize/512;
  33.                 fre_sect*=fs1->ssize/512;
  34. #endif
  35.                 *total=tot_sect>>1;        //单位为KB
  36.                 *free=fre_sect>>1;        //单位为KB
  37.         }
  38.         return res;
  39. }

  40. //通过串口打印SD卡相关信息
  41. void show_sdcard_info(void)
  42. {
  43.         int sdcard_status = 0;
  44.         HAL_SD_CardCIDTypeDef SDCard_CID;
  45.         uint64_t CardCap;        //SD卡容量

  46.         HAL_SD_GetCardCID(&hsd,&SDCard_CID);                    //获取CID
  47.         sdcard_status = HAL_SD_GetCardState(&hsd);
  48.         switch(hsd.SdCard.CardType)
  49.         {
  50.                 case CARD_SDSC:
  51.                 {
  52.                         if(hsd.SdCard.CardVersion == CARD_V1_X)
  53.                                 printf("Card Type:SDSC V1\r\n");
  54.                         else if(hsd.SdCard.CardVersion == CARD_V2_X)
  55.                                 printf("Card Type:SDSC V2\r\n");
  56.                 }
  57.                 break;
  58.                 case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
  59.         }

  60.         if(sdcard_status == HAL_SD_CARD_TRANSFER)
  61.         {
  62.             //打印SD卡基本信息
  63.             CardCap = (uint64_t)hsd.SdCard.BlockSize*(uint64_t)hsd.SdCard.BlockNbr;                                                                                                        //计算SD卡容量
  64.             printf("CardCapacity: %ld MB\r\n",(uint64_t)(hsd.SdCard.BlockSize*hsd.SdCard.BlockNbr));                        //显示容量
  65.             printf("Card ManufacturerID:%ld \r\n",(u32)SDCard_CID.ManufacturerID);                                                                //制造商ID
  66.             printf("Card RCA:%ld \r\n",hsd.SdCard.RelCardAdd);                                                                                                        //卡相对地址
  67.             printf("LogBlockNbr:%ld \r\n",hsd.SdCard.LogBlockNbr);                                                                                                //显示逻辑块数量
  68.             printf("LogBlockSize:%ld \r\n",hsd.SdCard.LogBlockSize);                                                                                        //显示逻辑块大小
  69.             printf("Card Capacity:%ld MB\r\n",(u32)(CardCap>>20));                                                                                                //显示容量
  70.             printf("Card BlockSize: %ld \r\n",hsd.SdCard.BlockSize);                                                                                        //显示块大小
  71.         }
  72.         else
  73.         {
  74.             printf("SD card init fail!\r\n" );
  75.         }
  76. }

  77. void SD_Auto_NewFolder(void)
  78. {
  79.         unsigned long total,free;
  80.         vu8 err;
  81. //        u8 paddr[18];                                        //存放P Addr:+p地址的ASCII值
  82. //        BYTE *work=0;/* Work area (larger is better for process time) */

  83.         printf("\r\n ****** FATFS SYSTEM ******\r\n\r\n");
  84.         /*-1- 格式化SD卡*/
  85. //        work = mymalloc(SRAMEX,_MAX_LEN);//外部内存池申请
  86. //        if(work!=NULL)
  87. //        {
  88. //                sprintf((char*)paddr,"0X%08X",(u32)work);
  89. //                printf("%s\r\n",paddr);
  90. //        }
  91. //
  92. //        err=f_mkfs("0:", FM_FAT32, 0, work, _MAX_LEN);
  93. //        if(err==0)
  94. //        {
  95. ////                f_setlabel((const TCHAR*)"0:JAYMIE");//设置Flash磁盘的名字为:ALIENTEK
  96. //                printf("Flash Disk Format Finish\r\n");        //格式化完成
  97. //        }else printf("Flash Disk Format Error\r\n");        //格式化失败
  98. //
  99. //        myfree(SRAMEX,work);//释放外部内存池内存
  100. //        work = 0;                        //指向空地址

  101.         /*-2- 挂载文件系统*/
  102.         retSD = f_mount(&fs, "0:", 0);
  103.         if(retSD)
  104.         {
  105.                 printf(" mount error : %d \r\n",retSD);
  106.                 Error_Handler();
  107.         }
  108.         else
  109.                 printf(" mount sucess!!! \r\n");

  110.         /*-3-获取SD卡容量和信息*/
  111.         err = exf_getfree("0:",&total,&free);
  112.         if(err)
  113.                 printf("SD Card Fatfs Error:%d!\r\n",err);

  114.         printf("total:%ld MB,free:%ld MB\r\n",total>>10,free>>10);//显示SD卡总容量 MB,剩余容量 MB

  115.         show_sdcard_info();

  116.         /*-4-创建新的文件并写入数据*/
  117.         retSD = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE);                //打开文件,权限包括创建、写(如果没有该文件,会创建该文件)
  118.         if(retSD)                                                                                                                        //返回值不为0(出现问题)
  119.                 printf(" open file error : %d\r\n",retSD);                                                //打印问题代码
  120.         else
  121.                 printf(" open file sucess!!! \r\n");

  122.         /*-5- 在txt文件中写入数据*/
  123.         retSD = f_write(&fil, wtext, sizeof(wtext), (void *)&byteswritten);        //在文件内写入wtext内的内容
  124.         if(retSD)                                                                                                                        //返回值不为0(出现问题)
  125.                 printf(" write file error : %d\r\n",retSD);                                                //打印问题代码
  126.         else
  127.         {
  128.                 printf(" write file sucess!!! \r\n");
  129.                 printf(" write Data : %s\r\n",wtext);                                                        //打印写入的内容
  130.         }

  131.         /*-6- 关闭txt文件*/
  132.         retSD = f_close(&fil);                                                                                                //关闭该文件
  133.         if(retSD)                                                                                                                        //返回值不为0(出现问题)
  134.                 printf(" close error : %d\r\n",retSD);                                                        //打印问题代码
  135.         else
  136.                 printf(" close sucess!!! \r\n");

  137.         /*-7- 打开文件读取数据*/
  138.         retSD = f_open(&fil, filename, FA_READ);                                                        //打开文件,权限为只读
  139.         if(retSD)                                                                                                                        //返回值不为0(出现问题)
  140.                 printf(" open file error : %d\r\n",retSD);                                                //打印问题代码
  141.         else
  142.                 printf(" open file sucess!!! \r\n");

  143.         /*-8- 读取txt文件数据*/
  144.         retSD = f_read(&fil, rtext, sizeof(rtext), (UINT*)&bytesread);                //读取文件内容放到rtext中
  145.         if(retSD)                                                                                                                        //返回值不为0(出现问题)
  146.                 printf(" read error!!! %d\r\n",retSD);                                                        //打印问题代码
  147.         else
  148.         {
  149.                 printf(" read sucess!!! \r\n");
  150.                 printf(" read Data : %s\r\n",rtext);                                                        //打印读取到的数据
  151.         }

  152.         /*-9- 关闭文件*/
  153.         retSD = f_close(&fil);                                                                                                //关闭该文件
  154.         if(retSD)                                                                                                                          //返回值不为0(出现问题)
  155.                 printf(" close error!!! %d\r\n",retSD);                                                        //打印问题代码
  156.         else
  157.                 printf(" close sucess!!! \r\n");

  158.         /*-10- 读写一致性检测*/
  159.         if(bytesread == byteswritten)                                                                                //如果读写位数一致
  160.         {
  161.                 printf(" FatFs is working well!!!\r\n");                                                //打印文件系统工作正常
  162.         }

  163. }

复制代码

上面是应用层.c文件,在/*-3-获取SD卡容量和信息*/  这个地方,exf_getfree("0:",&total,&free);的内容是错误的,我也不知道是公式的问题,还是这个底层的问题,还是文件系统中间件的问题,反正我研究了很长时间,没搞出来,后面我继续优化一下。对了,这里移植正点原子的内存池管理这章节,也是废了不少时间移植成功(涉及到内存的映射和启动文件.ld的修改),网上的涉及到.ld的修改文章很少,有的虽然修改成功了,但是生成的.bin和.hex文件超级大,后面经过一个贴友的帮助,总算修改好了启动文件。先把启动文件.ld代码贴出来,自己可以看看新增的地方。
  1. /**
  2. ******************************************************************************
  3. * @file      LinkerScript.ld
  4. * @author    Auto-generated by STM32CubeIDE
  5. * @brief     Linker script for STM32F407ZGTx Device from STM32F4 series
  6. *                      1024Kbytes FLASH
  7. *                      64Kbytes CCMRAM
  8. *                      128Kbytes RAM
  9. *
  10. *            Set heap size, stack size and stack location according
  11. *            to application requirements.
  12. *
  13. *            Set memory bank area and size if external memory is used
  14. ******************************************************************************
  15. * @attention
  16. *
  17. * <h2><center>&#169; Copyright (c) 2020 STMicroelectronics.
  18. * All rights reserved.</center></h2>
  19. *
  20. * This software component is licensed by ST under BSD 3-Clause license,
  21. * the "License"; You may not use this file except in compliance with the
  22. * License. You may obtain a copy of the License at:
  23. *                        opensource.org/licenses/BSD-3-Clause
  24. *
  25. ******************************************************************************
  26. */

  27. /* Entry Point */
  28. ENTRY(Reset_Handler)

  29. /* Highest address of the user mode stack */
  30. _estack = ORIGIN(RAM) + LENGTH(RAM);        /* end of "RAM" Ram type memory */

  31. _Min_Heap_Size = 0x200 ;        /* required amount of heap  */
  32. _Min_Stack_Size = 0x1000 ;        /* required amount of stack */

  33. /* Memories definition */
  34. MEMORY
  35. {
  36.   CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
  37.   RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128K
  38.   FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 1024K
  39.   SRAM   (rx)    : ORIGIN = 0x68000000,   LENGTH = 1024K
  40. }

  41. /* Sections */
  42. SECTIONS
  43. {
  44.   /* The startup code into "FLASH" Rom type memory */
  45.   .isr_vector :
  46.   {
  47.     . = ALIGN(4);
  48.     KEEP(*(.isr_vector)) /* Startup code */
  49.     . = ALIGN(4);
  50.   } >FLASH

  51.   /* The program code and other data into "FLASH" Rom type memory */
  52.   .text :
  53.   {
  54.     . = ALIGN(4);
  55.     *(.text)           /* .text sections (code) */
  56.     *(.text*)          /* .text* sections (code) */
  57.     *(.glue_7)         /* glue arm to thumb code */
  58.     *(.glue_7t)        /* glue thumb to arm code */
  59.     *(.eh_frame)

  60.     KEEP (*(.init))
  61.     KEEP (*(.fini))

  62.     . = ALIGN(4);
  63.     _etext = .;        /* define a global symbols at end of code */
  64.   } >FLASH

  65.   /* Constant data into "FLASH" Rom type memory */
  66.   .rodata :
  67.   {
  68.     . = ALIGN(4);
  69.     *(.rodata)         /* .rodata sections (constants, strings, etc.) */
  70.     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
  71.     . = ALIGN(4);
  72.   } >FLASH

  73.   .ARM.extab   : {
  74.     . = ALIGN(4);
  75.     *(.ARM.extab* .gnu.linkonce.armextab.*)
  76.     . = ALIGN(4);
  77.   } >FLASH
  78.   
  79.   .ARM : {
  80.     . = ALIGN(4);
  81.     __exidx_start = .;
  82.     *(.ARM.exidx*)
  83.     __exidx_end = .;
  84.     . = ALIGN(4);
  85.   } >FLASH

  86.   .preinit_array     :
  87.   {
  88.     . = ALIGN(4);
  89.     PROVIDE_HIDDEN (__preinit_array_start = .);
  90.     KEEP (*(.preinit_array*))
  91.     PROVIDE_HIDDEN (__preinit_array_end = .);
  92.     . = ALIGN(4);
  93.   } >FLASH
  94.   
  95.   .init_array :
  96.   {
  97.     . = ALIGN(4);
  98.     PROVIDE_HIDDEN (__init_array_start = .);
  99.     KEEP (*(SORT(.init_array.*)))
  100.     KEEP (*(.init_array*))
  101.     PROVIDE_HIDDEN (__init_array_end = .);
  102.     . = ALIGN(4);
  103.   } >FLASH
  104.   
  105.   .fini_array :
  106.   {
  107.     . = ALIGN(4);
  108.     PROVIDE_HIDDEN (__fini_array_start = .);
  109.     KEEP (*(SORT(.fini_array.*)))
  110.     KEEP (*(.fini_array*))
  111.     PROVIDE_HIDDEN (__fini_array_end = .);
  112.     . = ALIGN(4);
  113.   } >FLASH
  114.   
  115.   /* Used by the startup to initialize data */
  116.   _sidata = LOADADDR(.data);

  117.   /* Initialized data sections into "RAM" Ram type memory */
  118.   .data :
  119.   {
  120.     . = ALIGN(4);
  121.     _sdata = .;        /* create a global symbol at data start */
  122.     *(.data)           /* .data sections */
  123.     *(.data*)          /* .data* sections */

  124.     . = ALIGN(4);
  125.     _edata = .;        /* define a global symbol at data end */
  126.    
  127.   } >RAM AT> FLASH

  128.   /* Uninitialized data section into "RAM" Ram type memory */
  129.   .ccmram(NOLOAD) :
  130.   {
  131.     . = ALIGN(4);
  132.     _sccmram = .;       /* create a global symbol at ccmram start */
  133.     *(.ccmram)
  134.     *(.ccmram*)
  135.    
  136.     . = ALIGN(4);
  137.     _eccmram = .;       /* create a global symbol at ccmram end */
  138.   } >CCMRAM AT> FLASH /*新增*/
  139.   
  140.   . = ALIGN(4);
  141.   .bss :
  142.   {
  143.     /* This is used by the startup in order to initialize the .bss section */
  144.     _sbss = .;         /* define a global symbol at bss start */
  145.     __bss_start__ = _sbss;
  146.     *(.bss)
  147.     *(.bss*)
  148.     *(COMMON)

  149.     . = ALIGN(4);
  150.     _ebss = .;         /* define a global symbol at bss end */
  151.     __bss_end__ = _ebss;
  152.   } >RAM

  153.   /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
  154.   ._user_heap_stack :
  155.   {
  156.     . = ALIGN(8);
  157.     PROVIDE ( end = . );
  158.     PROVIDE ( _end = . );
  159.     . = . + _Min_Heap_Size;
  160.     . = . + _Min_Stack_Size;
  161.     . = ALIGN(8);
  162.   } >RAM

  163.   .sram(NOLOAD) :
  164.   {
  165.     . = ALIGN(4);
  166.     _SRAM_SYMBOLS = .;      /* create a global symbol at data start */
  167.     *(.sram)                           /* .data sections */
  168.     *(.sram*)                          /* .data* sections */

  169.     . = ALIGN(4);
  170.     _ESRAM_SYMBOLS = .;     /* define a global symbol at data end */
  171.    
  172.   } >SRAM /*新增*/
  173.   /* Remove information from the compiler libraries */
  174.   /DISCARD/ :
  175.   {
  176.     libc.a ( * )
  177.     libm.a ( * )
  178.     libgcc.a ( * )
  179.   }

  180.   .ARM.attributes 0 : { *(.ARM.attributes) }
  181. }
复制代码

内存池管理文件.c和.h
  1. /*
  2. * bsp_malloc.c
  3. *
  4. *  Created on: Sep 24, 2020
  5. *      Author: jiangyuanyuan
  6. */

  7. #include "bsp_malloc.h"

  8. //内存池(32字节对齐)
  9. __attribute__ ((aligned (32))) u8 mem1base[MEM1_MAX_SIZE];                                                                                        //内部SRAM内存池
  10. __attribute__ ((aligned (32))) u8 mem2base[MEM2_MAX_SIZE] __attribute__((section(".sram")));            //外部SRAM内存池
  11. __attribute__ ((aligned (32))) u8 mem3base[MEM3_MAX_SIZE] __attribute__((section(".ccmram")));                 //内部CCM内存池

  12. //内存管理表
  13. u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                                                                                //内部SRAM内存池MAP
  14. u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((section(".sram")));        //外部SRAM内存池MAP
  15. u16 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((section(".ccmram")));        //内部CCM内存池MAP
  16. //内存管理参数
  17. const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE,MEM3_ALLOC_TABLE_SIZE};        //内存表大小
  18. const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE,MEM3_BLOCK_SIZE};                                        //内存分块大小
  19. const u32 memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE,MEM3_MAX_SIZE};                                                        //内存总大小

  20. //内存管理控制器
  21. struct _m_mallco_dev mallco_dev=
  22. {
  23.         my_mem_init,                                                //内存初始化
  24.         my_mem_perused,                                                //内存使用率
  25.         mem1base,mem2base,mem3base,                        //内存池
  26.         mem1mapbase,mem2mapbase,mem3mapbase,//内存管理状态表
  27.         0,0,0,                           //内存管理未就绪
  28. };

  29. //复制内存
  30. //*des:目的地址
  31. //*src:源地址
  32. //n:需要复制的内存长度(字节为单位)
  33. void mymemcpy(void *des,void *src,u32 n)
  34. {
  35.     u8 *xdes=des;
  36.         u8 *xsrc=src;
  37.     while(n--)*xdes++=*xsrc++;
  38. }
  39. //设置内存
  40. //*s:内存首地址
  41. //c :要设置的值
  42. //count:需要设置的内存大小(字节为单位)
  43. void mymemset(void *s,u8 c,u32 count)
  44. {
  45.     u8 *xs = s;
  46.     while(count--)*xs++=c;
  47. }
  48. //内存管理初始化
  49. //memx:所属内存块
  50. void my_mem_init(u8 memx)
  51. {
  52.     mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零
  53.         mymemset(mallco_dev.membase[memx], 0,memsize[memx]);        //内存池所有数据清零
  54.         mallco_dev.memrdy[memx]=1;                                                                //内存管理初始化OK
  55. }
  56. //获取内存使用率
  57. //memx:所属内存块
  58. //返回值:使用率(0~100)
  59. u8 my_mem_perused(u8 memx)
  60. {
  61.     u32 used=0;
  62.     u32 i;
  63.     for(i=0;i<memtblsize[memx];i++)
  64.     {
  65.         if(mallco_dev.memmap[memx][i])used++;
  66.     }
  67.     return (used*100)/(memtblsize[memx]);
  68. }
  69. //内存分配(内部调用)
  70. //memx:所属内存块
  71. //size:要分配的内存大小(字节)
  72. //返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
  73. u32 my_mem_malloc(u8 memx,u32 size)
  74. {
  75.     signed long offset=0;
  76.     u32 nmemb;        //需要的内存块数
  77.         u32 cmemb=0;//连续空内存块数
  78.     u32 i;
  79.     if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化
  80.     if(size==0)return 0XFFFFFFFF;//不需要分配
  81.     nmemb=size/memblksize[memx];          //获取需要分配的连续内存块数
  82.     if(size%memblksize[memx])nmemb++;
  83.     for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区
  84.     {
  85.                 if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加
  86.                 else cmemb=0;                                                                //连续内存块清零
  87.                 if(cmemb==nmemb)                                                        //找到了连续nmemb个空内存块
  88.                 {
  89.             for(i=0;i<nmemb;i++)                                          //标注内存块非空
  90.             {
  91.                 mallco_dev.memmap[memx][offset+i]=nmemb;
  92.             }
  93.             return (offset*memblksize[memx]);//返回偏移地址
  94.                 }
  95.     }
  96.     return 0XFFFFFFFF;//未找到符合分配条件的内存块
  97. }
  98. //释放内存(内部调用)
  99. //memx:所属内存块
  100. //offset:内存地址偏移
  101. //返回值:0,释放成功;1,释放失败;
  102. u8 my_mem_free(u8 memx,u32 offset)
  103. {
  104.     int i;
  105.     if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化
  106.         {
  107.                 mallco_dev.init(memx);
  108.         return 1;//未初始化
  109.     }
  110.     if(offset<memsize[memx])//偏移在内存池内.
  111.     {
  112.         int index=offset/memblksize[memx];                        //偏移所在内存块号码
  113.         int nmemb=mallco_dev.memmap[memx][index];        //内存块数量
  114.         for(i=0;i<nmemb;i++)                                                  //内存块清零
  115.         {
  116.             mallco_dev.memmap[memx][index+i]=0;
  117.         }
  118.         return 0;
  119.     }else return 2;//偏移超区了.
  120. }
  121. //释放内存(外部调用)
  122. //memx:所属内存块
  123. //ptr:内存首地址
  124. void myfree(u8 memx,void *ptr)
  125. {
  126.         u32 offset;
  127.         if(ptr==NULL)return;//地址为0.
  128.          offset=(u32)ptr-(u32)mallco_dev.membase[memx];
  129.     my_mem_free(memx,offset);        //释放内存
  130. }
  131. //分配内存(外部调用)
  132. //memx:所属内存块
  133. //size:内存大小(字节)
  134. //返回值:分配到的内存首地址.
  135. void *mymalloc(u8 memx,u32 size)
  136. {
  137.     u32 offset;
  138.         offset=my_mem_malloc(memx,size);
  139.     if(offset==0XFFFFFFFF)return NULL;
  140.     else return (void*)((u32)mallco_dev.membase[memx]+offset);
  141. }
  142. //重新分配内存(外部调用)
  143. //memx:所属内存块
  144. //*ptr:旧内存首地址
  145. //size:要分配的内存大小(字节)
  146. //返回值:新分配到的内存首地址.
  147. void *myrealloc(u8 memx,void *ptr,u32 size)
  148. {
  149.     u32 offset;
  150.     offset=my_mem_malloc(memx,size);
  151.     if(offset==0XFFFFFFFF)return NULL;
  152.     else
  153.     {
  154.             mymemcpy((void*)((u32)mallco_dev.membase[memx]+offset),ptr,size);        //拷贝旧内存内容到新内存
  155.         myfree(memx,ptr);                                                                                                            //释放旧内存
  156.         return (void*)((u32)mallco_dev.membase[memx]+offset);                                  //返回新内存首地址
  157.     }
  158. }

  159. void Malloc_Test(void)
  160. {
  161.         u8 *p=0;
  162.         u8 *tp=0;
  163.         u8 paddr[18];                                        //存放P Addr:+p地址的ASCII值

  164. #ifndef __USE_SRAM
  165.         p=mymalloc(SRAMIN,2048);//内部内存池申请2K字节
  166.         if(p!=NULL)
  167.         {
  168.                 tp=p;
  169.                 sprintf((char*)paddr,"0X%08X",(u32)tp);
  170.                 sprintf((char*)p,"Memory SRAMIN ADDR:");//向p写入一些内容
  171.                 printf("%s",p);
  172.                 printf("%s\r\n",paddr);
  173.         }
  174.         myfree(SRAMIN,p);//释放内部内存池内存
  175.         p=0;                        //指向空地址

  176.         p=mymalloc(SRAMCCM,2048);//CCM内存池申请2K字节
  177.         if(p!=NULL)
  178.         {
  179.                 tp=p;
  180.                 sprintf((char*)paddr,"0X%08X",(u32)tp);
  181.                 sprintf((char*)p,"Memory SRAMCCM ADDR:");//向p写入一些内容
  182.                 printf("%s",p);
  183.                 printf("%s\r\n",paddr);
  184.         }
  185.         myfree(SRAMCCM,p);//释放CCM内存池内存
  186.         p=0;                        //指向空地址
  187. #endif
  188.         p=mymalloc(SRAMEX,2048);//外部内存池申请2K字节
  189.         if(p!=NULL)
  190.         {
  191.                 tp=p;
  192.                 sprintf((char*)paddr,"0X%08X",(u32)tp);
  193.                 sprintf((char*)p,"Memory SRAMEX ADDR:");//向p写入一些内容
  194.                 printf("%s",p);
  195.                 printf("%s\r\n",paddr);
  196.         }
  197.         myfree(SRAMEX,p);//释放外部内存池内存
  198.         p=0;                        //指向空地址
  199. }
复制代码
  1. /*
  2. * bsp_malloc.h
  3. *
  4. *  Created on: Sep 24, 2020
  5. *      Author: jiangyuanyuan
  6. */

  7. #ifndef INC_BSP_MALLOC_H_
  8. #define INC_BSP_MALLOC_H_

  9. #include "stm32f4xx_hal.h"
  10. #include "bsp_sys.h"
  11. #include "stdio.h"

  12. #define __USE_SRAM

  13. //定义三个内存池
  14. #define SRAMIN         0                //内部内存池
  15. #define SRAMEX   1                //外部内存池
  16. #define SRAMCCM  2                //CCM内存池(此部分SRAM仅仅CPU可以访问!!!)

  17. #define SRAMBANK         3        //定义支持的SRAM块数.

  18. #ifdef __USE_SRAM
  19. //mem1内存参数设定.mem1完全处于内部SRAM里面.
  20. #define MEM1_BLOCK_SIZE                        32                                                    //内存块大小为32字节
  21. #define MEM1_MAX_SIZE                        0                                                          //最大管理内存 0K
  22. #define MEM1_ALLOC_TABLE_SIZE        0                                                         //内存表大小

  23. //mem3内存参数设定.mem3处于CCM,用于管理CCM(特别注意,这部分SRAM,仅CPU可以访问!!)
  24. #define MEM3_BLOCK_SIZE                        32                                                    //内存块大小为32字节
  25. #define MEM3_MAX_SIZE                        0                                                          //最大管理内存0K
  26. #define MEM3_ALLOC_TABLE_SIZE        0                                                         //内存表大小
  27. #else
  28. //mem1内存参数设定.mem1完全处于内部SRAM里面.
  29. #define MEM1_BLOCK_SIZE                        32                                                            //内存块大小为32字节
  30. #define MEM1_MAX_SIZE                        100*1024                                                  //最大管理内存 100K
  31. #define MEM1_ALLOC_TABLE_SIZE        MEM1_MAX_SIZE/MEM1_BLOCK_SIZE         //内存表大小

  32. //mem3内存参数设定.mem3处于CCM,用于管理CCM(特别注意,这部分SRAM,仅CPU可以访问!!)
  33. #define MEM3_BLOCK_SIZE                        32                                                            //内存块大小为32字节
  34. #define MEM3_MAX_SIZE                        60 *1024                                                  //最大管理内存60K
  35. #define MEM3_ALLOC_TABLE_SIZE        MEM3_MAX_SIZE/MEM3_BLOCK_SIZE         //内存表大小
  36. #endif

  37. //mem2内存参数设定.mem2的内存池处于外部SRAM里面
  38. #define MEM2_BLOCK_SIZE                        32                                                            //内存块大小为32字节
  39. #define MEM2_MAX_SIZE                        960 *1024                                                  //最大管理内存960K
  40. #define MEM2_ALLOC_TABLE_SIZE        MEM2_MAX_SIZE/MEM2_BLOCK_SIZE         //内存表大小

  41. //内存管理控制器
  42. struct _m_mallco_dev
  43. {
  44.         void (*init)(u8);                                        //初始化
  45.         u8 (*perused)(u8);                                      //内存使用率
  46.         u8         *membase[SRAMBANK];                                //内存池 管理SRAMBANK个区域的内存
  47.         u16 *memmap[SRAMBANK];                                 //内存管理状态表
  48.         u8  memrdy[SRAMBANK];                                 //内存管理是否就绪
  49. };
  50. extern struct _m_mallco_dev mallco_dev;         //在mallco.c里面定义

  51. void mymemset(void *s,u8 c,u32 count);        //设置内存
  52. void mymemcpy(void *des,void *src,u32 n);//复制内存
  53. void my_mem_init(u8 memx);                                //内存管理初始化函数(外/内部调用)
  54. u32 my_mem_malloc(u8 memx,u32 size);        //内存分配(内部调用)
  55. u8 my_mem_free(u8 memx,u32 offset);                //内存释放(内部调用)
  56. u8 my_mem_perused(u8 memx);                                //获得内存使用率(外/内部调用)
  57. ////////////////////////////////////////////////////////////////////////////////
  58. //用户调用函数
  59. void myfree(u8 memx,void *ptr);                          //内存释放(外部调用)
  60. void *mymalloc(u8 memx,u32 size);                        //内存分配(外部调用)
  61. void *myrealloc(u8 memx,void *ptr,u32 size);//重新分配内存(外部调用)
  62. void Malloc_Test(void);
  63. #endif /* INC_BSP_MALLOC_H_ */
复制代码
上面因为我只用到外部SRAM的使用,所以没用到内部内存池和内部RAM的申请,所以头文件加了一个条件编译。以下是我SD卡打印的信息:
  1. sram:1024kb
  2. Memory SRAMEX ADDR:0X680EF800

  3. ****** FATFS SYSTEM ******

  4. 0X680E8000
  5. Flash Disk Format Finish
  6. mount sucess!!!
  7. total:722900 MB,free:38131 MB
  8. Card Type:SDHC
  9. CardCapacity: 512 MB
  10. Card ManufacturerID:3
  11. Card RCA:43690
  12. LogBlockNbr:15523840
  13. LogBlockSize:512
  14. Card Capacity:7580 MB
  15. Card BlockSize: 512
  16. open file sucess!!!
  17. write file sucess!!!
  18. write Data : This is a 8G Card!!!
  19. close sucess!!!
  20. open file sucess!!!
  21. read sucess!!!
  22. read Data : This is a 8G Card!!!
  23. close sucess!!!
  24. FatFs is working well!!!
复制代码
从串口打印数据,可以看到total:722900 MB,free:38131 MB是错误的,但是HAL_SD_CardCIDTypeDef SDCard_CID 结构体成员的信息是对的
有贴友知道err = exf_getfree("0:",&total,&free);获取错误的问题,请留言,谢谢。


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-9-29 12:24:19 | 显示全部楼层
找出BUG实属很辛苦,贵在坚持,差点放弃使用这个软件,有贴友喜欢使用这个软件的话,点个赞,谢谢
回复 支持 反对

使用道具 举报

22

主题

2251

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4471
金钱
4471
注册时间
2013-4-22
在线时间
335 小时
发表于 2020-9-29 13:43:11 | 显示全部楼层
没用过,哈哈,都是直接移植的fatfs文件系统
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-9-29 14:05:56 | 显示全部楼层
https://www.cnblogs.com/Danhuise/p/3910516.html

我参考这个帖子,获取的总容量和剩余容量还是错误。
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-9-29 14:06:33 | 显示全部楼层
三叶草 发表于 2020-9-29 13:43
没用过,哈哈,都是直接移植的fatfs文件系统

回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-9-29 16:09:12 | 显示全部楼层
本帖最后由 jiangyy 于 2020-9-29 17:46 编辑

终于改好了,发现有个地方有错误,不能完全参照正点原子的例程,因为正点原子的例程使用了内存池管理,对文件结构体变量进行了内存申请。
错误的代码如下:
  1. FATFS fs;                 //工作空间
  2. FIL fil;                  // 文件项目
  3. uint32_t byteswritten;    // 写文件计数
  4. uint32_t bytesread;       // 读文件计数
  5. uint8_t wtext[] = "This is a 8G Card!!!"; // 写的内容
  6. uint8_t rtext[1024];             // 读取的buff
  7. char filename[] = "FATFS.txt"; // 文件名

  8. //得到磁盘剩余容量
  9. //drv:磁盘编号("0:"/"1:")
  10. //total:总容量         (单位KB)
  11. //free:剩余容量         (单位KB)
  12. //返回值:0,正常.其他,错误代码
  13. vu8 exf_getfree(u8 *drv,u32 *total,u32 *free)
  14. {
  15.         FATFS *fs1;
  16.         vu8 res;
  17.     u32 fre_clust=0, fre_sect=0, tot_sect=0;

  18.     //得到磁盘信息及空闲簇数量
  19.     res = f_getfree((const TCHAR*)drv, (DWORD*)&fre_clust, fs1);
  20.     if(res==0)
  21.         {
  22.             tot_sect=(fs1->n_fatent-2)*fs1->csize;        //得到总扇区数
  23.             fre_sect=fre_clust*fs1->csize;                        //得到空闲扇区数
  24. #if _MAX_SS!=512                                                                  //扇区大小不是512字节,则转换为512字节
  25.                 tot_sect*=fs1->ssize/512;
  26.                 fre_sect*=fs1->ssize/512;
  27. #endif
  28.                 *total=tot_sect>>1;        //单位为KB
  29.                 *free=fre_sect>>1;        //单位为KB
  30.         }
  31.         return res;
  32. }
复制代码
错误的地方在于 FATFS *fs1; 这里引用的是一个结构体指针,空指针,并没有指向文件系统的成员变量。这里可以引用 FATFS fs;这个文件结构体变量命,因为它的成员变量已经在挂载文件系统的时候赋值了,所以具体代码改正如下:

  1. FATFS fs;                 //工作空间
  2. FIL fil;                  // 文件项目
  3. uint32_t byteswritten;    // 写文件计数
  4. uint32_t bytesread;       // 读文件计数
  5. uint8_t wtext[] = "This is a 8G Card!!!"; // 写的内容
  6. uint8_t rtext[1024];             // 读取的buff
  7. char filename[] = "FATFS.txt"; // 文件名

  8. //得到磁盘剩余容量
  9. //drv:磁盘编号("0:"/"1:")
  10. //total:总容量         (单位KB)
  11. //free:剩余容量         (单位KB)
  12. //返回值:0,正常.其他,错误代码
  13. vu8 exf_getfree(u8 *drv,u32 *total,u32 *free)
  14. {
  15.         vu8 res;
  16.     u32 fre_clust=0, fre_sect=0, tot_sect=0;

  17.     //得到磁盘信息及空闲簇数量
  18.     res = f_getfree((const TCHAR*)drv, (DWORD*)&fre_clust, (FATFS *)&fs);
  19.     if(res==0)
  20.         {
  21.             tot_sect = (fs.n_fatent-2) * fs.csize;        //得到总扇区数
  22.             fre_sect = fre_clust * fs.csize;                        //得到空闲扇区数
  23. #if _MAX_SS!=512                                                                  //扇区大小不是512字节,则转换为512字节
  24.                 tot_sect*=fs1->ssize/512;
  25.                 fre_sect*=fs1->ssize/512;
  26. #endif
  27.                 *total=tot_sect>>1;        //单位为KB
  28.                 *free=fre_sect>>1;        //单位为KB
  29.          }
  30.         return res;
  31. }
复制代码
还有一个地方需要修改,如下:
  1. /*-3-获取SD卡容量和信息*/
  2.         err = exf_getfree("0:",&total,&free);
  3.         if(err)
  4.                 printf("SD Card Fatfs Error:%d!\r\n",err);

  5.         printf("total:%ld MB,free:%ld MB\r\n",total>>10,free>>10);//显示SD卡总容量 MB,剩余容量 MB

  6.         show_sdcard_info();
  7.         f_mount(NULL, "0:", 0);//(新增)
  8.         f_mount(&fs, "0:", 0);//(新增)
复制代码
新增的两处地方,先卸载文件系统,在挂载文件系统,否则会死机,具体原因我也不清楚。

改完完毕,请看串口打印数据,很完美!!!妈了个巴子,终于改好了,折磨了我三天时间。

  1. sram:1024kb
  2. Memory SRAMEX ADDR:0X680EF800

  3. ****** FATFS SYSTEM ******

  4. mount sucess!!!
  5. total:7579 MB,free:7578 MB
  6. Card Type:SDHC
  7. CardCapacity: 512 MB
  8. Card ManufacturerID:3
  9. Card RCA:43690
  10. LogBlockNbr:15523840
  11. LogBlockSize:512
  12. Card Capacity:7580 MB
  13. Card BlockSize: 512
  14. open file sucess!!!
  15. write file sucess!!!
  16. write Data : This is a 8G Card!!!
  17. close sucess!!!
  18. open file sucess!!!
  19. read sucess!!!
  20. read Data : This is a 8G Card!!!
  21. close sucess!!!
  22. FatFs is working well!!!
复制代码







回复 支持 反对

使用道具 举报

0

主题

47

帖子

0

精华

初级会员

Rank: 2

积分
155
金钱
155
注册时间
2019-12-31
在线时间
29 小时
发表于 2020-9-30 08:56:31 | 显示全部楼层
atomic的看看就得了,千万不要放在项目里。
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-9-30 10:59:08 | 显示全部楼层
caoenq 发表于 2020-9-30 08:56
atomic的看看就得了,千万不要放在项目里。

原子有的地方值得参考借鉴一下,不能完全否定他,好歹也是教育的前沿。
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-9-30 11:00:38 | 显示全部楼层
【HAL库每天一例】汇总帖

https://bbs.elecfans.com/forum.p ... d=913752&extra=
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-11-21 14:02:35 | 显示全部楼层
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-11-24 10:56:30 | 显示全部楼层
sd_state = HAL_SD_Init(&hsd); 该函数可以知晓SD卡是否安装上
回复 支持 反对

使用道具 举报

13

主题

52

帖子

0

精华

初级会员

Rank: 2

积分
148
金钱
148
注册时间
2017-2-8
在线时间
39 小时
发表于 2021-1-17 23:14:13 来自手机 | 显示全部楼层
楼主可以共享下项目?我卡住了,没头绪,用的是micro SD卡,卡上写着SDHC
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2021-1-19 08:47:11 | 显示全部楼层
2hen9x1 发表于 2021-1-17 23:14
楼主可以共享下项目?我卡住了,没头绪,用的是micro SD卡,卡上写着SDHC

学习不能照搬代码,要自己学会发现问题,分析问题,解决问题,这样才会有进步。我已经分享了我的经验,底层只需要通过图形配置就可以了。
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-12-13
在线时间
5 小时
发表于 2021-1-19 16:55:07 | 显示全部楼层
太赞了,感谢楼主分享
回复 支持 反对

使用道具 举报

13

主题

52

帖子

0

精华

初级会员

Rank: 2

积分
148
金钱
148
注册时间
2017-2-8
在线时间
39 小时
发表于 2021-2-9 08:59:30 | 显示全部楼层
楼主是用SPO还是SDIO呢
回复 支持 反对

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2022-5-15 21:49:21 | 显示全部楼层
2hen9x1 发表于 2021-2-9 08:59
楼主是用SPO还是SDIO呢

SDIO+DMA
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-25 18:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表