解决STM32F407VET6使用STM32CubeMX配置FatFs时挂载返回03错误码问题

[STM32] – STM32F407VET6使用STM32CubeMX配置FatFs,以及挂载时返回错误码3问题的解决

  • 1.使用STM32CubeMX配置FatFs
  • 1.1 工程准备
  • 1.2 配置CubeMX
  • 1.2.1 配置SDIO
  • 1.2.2 配置DMA(如果不想用DMA那么此步骤可省略)
  • 1.2.3 配置FatFs
  • 1.2.4 配置NVIC
  • 1.2.5 修改时钟配置
  • 1.2.6 修改工程设置并输出工程
  • 2 添加TF读写测试代码
  • 3 使用f_mount()函数挂载时返回错误3(FR_NOT_READY)问题的解决
  • 3.1 修改代码以解决挂载时返回错误3
  • 3.2 挂载时返回错误3的原因
  • 1.使用STM32CubeMX配置FatFs

    为测试新买的开发板TF卡读写是否正常,使用STM32CubeMX(后简称CubeMX)进行代码构建。生成代码后烧录测试,发现在挂载TF卡时无法成功,返回值为错误3(FR_NOT_READY)。经排查后问题已解决,遂记录配置过程供大家参考,并讲解挂载时返回错误3的解决方式。

    1.1 工程准备

    ①为了输出TF卡(或者SD卡)的读写测试结果,需要你的工程能实现串口打印。因此请准备好一个使用CubeMX生成的工程(我生成的为Keil工程),要求此工程能够使用printf函数打印信息到串口调试助手上。因为这个过程非常简单,并且教程极多,请自行搜索并准备工程。生成的工程根目录内容类似下图:

    使用CubeMX生成的工程根目录

    ②请确认你的TF卡槽连接的IO,不同的板卡IO不同,例如我的板卡上热拔插检测引脚没有连接,本教程以我的IO连接为例,原理图如下所示:

    SDIO原理图

    1.2 配置CubeMX

    双击工程文件夹根目录中“xxx.ioc”文件,此时会进入CubeMX的配置界面。

    1.2.1 配置SDIO

    ①点击左侧“Connectivity”,Mode选择“SD 4 bits Wide bus”,将“SDIOCLK clock divide factor”设置为2(调试时先不要太快,试验成功后可以自行改),如下图所示:

    ②勾选NVIC中的“SDIO global interruptSDIO”,如下所示:

    ③配置GPIO,请参照你的板卡原理图进行配置。此处以我的原理图为例,配置如下图所示:

    ④注意,如果你的板卡上有热拔插检测引脚,请根据板卡原理图,直接在右侧的“PinOut View”窗口点击对应的引脚,设置为“GPIO_Input”模式。这里假设我的板卡热拔插检测引脚连接到PE2,则设置如下所示:

    1.2.2 配置DMA(如果不想用DMA那么此步骤可省略)

    ①在SDIO配置下的“DMA Settings”栏目下点击ADD,添加RX与TX请求,添加后的配置无需修改,使用默认的参数即可:

    1.2.3 配置FatFs

    ①点击右侧的“Middleware and Software Packs”,选择“FATFS”,Mode勾选“SDCard”,并修改“Set Defines”中的“CODE_PAGE (Code page ontarget)”为“DBSC”,修改“USE_LFN (Use Long Filename)”为“Enabled with dynamicworking buffer on the STACK”。如下所示:

    ②(此步骤使用DMA时才需要配置)如果使用了DMA,则需要在“Advanced Settings”栏目将“Use dma template”设置为“Enable”:

    ③(当你的板卡连接了热拔插检测引脚时此步骤才需要配置)如果你的板卡SD卡热拔插引脚连接到了GPIO上,那么需要在“Platform Settings”中将“Detect_SDIO”项配置为你前面设置为输入的那个引脚。比如我在前面假设我的板子检测引脚连接到了PE2,则配置如下:

    !!!注意:如果你的板子上热拔插检测引脚未连接GPIO,那么这项可以不选,后面有警告直接忽略即可。当然你也可以随便选一个未使用的IO配置成输入模式,然后在这里选择该引脚,这样警告就消失了,但是要将此引脚接地,否则可能识别为卡没有插入导致TF读写测试不通过

    1.2.4 配置NVIC

    ①打开“System Core”中的“NVIC”,修改DMA的两个通道的“Preemption Priority”值,只要大于SDIO global interrupt”的值就可以了:

    1.2.5 修改时钟配置

    ①点击“Clock Configuration”栏,将“48MHz clocks”的频率修改为48

    1.2.6 修改工程设置并输出工程

    ①打开“Project Manager”栏目,将“Minimum Stack Size”设置为0x500(空间足够的话最好设置大一点,比如可以设置为0x1000),设置后点击“GENERATE CODE”生成代码:

    2 添加TF读写测试代码

    ①打开Keil工程,在“main.c”文件中的main()函数前添加TF卡测试代码,代码内容如下:

    //需要修改MX_SDIO_SD_Init为1B
    
    #define u8 uint8_t
    #define u16 uint16_t
    #define u32 uint32_t
    
        FATFS fs;
        FIL fil;
        uint32_t total,mfree;                  // file objects
    	uint32_t byteswritten;                /* File write counts */
    	uint32_t bytesread;                   /* File read counts */
    	uint8_t wtext[] = "SDTest File";      /* File write buffer */
    	uint8_t rtext[100];                   /* File read buffers */
    	char filename[] = "SDTest.txt";
      
    u8 exf_getfree(u8 *drv,u32 *total,u32 *free)
    {
    	FATFS *fs1;
    	u8 res;
        u32 fre_clust=0, fre_sect=0, tot_sect=0;
        res =(u32)f_getfree((const TCHAR*)drv, (DWORD*)&fre_clust, &fs1);
        if(res==0)
    	{											   
    	    tot_sect=(fs1->n_fatent-2)*fs1->csize;	
    	    fre_sect=fre_clust*fs1->csize;				   
    #if _MAX_SS!=512				  				
    		tot_sect*=fs1->ssize/512;
    		fre_sect*=fs1->ssize/512;
    #endif	  
    		*total=tot_sect>>1;	
    		*free=fre_sect>>1;	
     	}
    	return res;
    }
    
    void Fatfs_RW_test(void)
    {
    	  printf("\r\n ****** FatFs Example ******\r\n\r\n");
     
        /*##-1- Register the file system object to the FatFs module ##############*/
    		
        retSD = f_mount(&fs, "0", 1);
    		
    		
    		//f_mkdir("0:dxc");
        if(retSD)
        {
            printf(" Mount error!!! Error Num : %d \r\n",retSD);
            Error_Handler();
        }
        else
        {
          printf(" Mount sucess :) \r\n");
        }
         
        /*##-2- Create and Open new text file objects with write access ######*/
    		retSD=exf_getfree("0",&total,&mfree);
    		if(retSD==0)
    			printf(" total : %d MB,free : %d MB  \r\n\r\n",total>>10,mfree>>10);
    		else
    			 printf(" Getfree error!!! \r\n");
        retSD = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE);
        if(retSD)
          printf(" Open file error!!! Error Num : %d\r\n",retSD);
        else
          printf(" Open file sucess :) \r\n");
         
        /*##-3- Write data to the text files ###############################*/
        retSD = f_write(&fil, wtext, sizeof(wtext), (void *)&byteswritten);
        if(retSD)
          printf(" Write file error!!! Error Num : %d\r\n",retSD);
        else
        {
          printf(" Write file sucess :) \r\n");
            printf(" Write Data : %s\r\n\r\n",wtext);
        }
         
        /*##-4- Close the open text files ################################*/
        retSD = f_close(&fil);
        if(retSD)
            printf(" Close error!!! Error Num : %d\r\n",retSD);
        else
          printf(" Close sucess :) \r\n");
         
        /*##-5- Open the text files object with read access ##############*/
        retSD = f_open(&fil, filename, FA_READ);
        if(retSD)
            printf(" Open file error!!! Error Num : %d\r\n",retSD);
        else
            printf(" Open file sucess :) \r\n");
         
        /*##-6- Read data from the text files ##########################*/
        retSD = f_read(&fil, rtext, sizeof(rtext), (UINT*)&bytesread);
        if(retSD)
            printf(" Read error!!! Error Num : %d\r\n",retSD);
        else
        {
            printf(" Read sucess :) \r\n");
            printf(" Read Data : %s\r\n\r\n",rtext);
        }
         
        /*##-7- Close the open text files ############################*/
        retSD = f_close(&fil);
        if(retSD)  
            printf(" Close error!!! Error Num : %d\r\n",retSD);
        else
            printf(" Close sucess :) \r\n\r\n");
         
        /*##-8- Compare read data with the expected data ############*/
        if(bytesread == byteswritten)
        { 
            printf(" FatFs is working well!!!\r\n");
        }
    }
    

    ②在main()函数中,MX_SDIO_SD_Init和MX_FATFS_Init执行完以后的地方调用TF测试代码:

    3 使用f_mount()函数挂载时返回错误3(FR_NOT_READY)问题的解决

    经过上面的配置,如果你用的是旧版CubeMX软件,那么编译并烧录后便可以通过TF测试了(具体多旧的版本未知)。
    如果此时你烧录运行发现输出了Mount Error的信息,Num值为3,如下图所示:

    则说明你需要进行以下修改:

    3.1 修改代码以解决挂载时返回错误3

    找到“void MX_SDIO_SD_Init(void)”函数,将“hsd.Init.BusWide”的值由“SDIO_BUS_WIDE_4B”修改为“SDIO_BUS_WIDE_1B”,修改后如下所示:

    此时重新编译并运行,问题便得以解决,以下是测试通过时的输出信息:

    3.2 挂载时返回错误3的原因

    在SDIO进行初始化时,使用的是1位宽模式进行配置的,在初始化完成后才会使用4位宽进行数据传输。新版的CubeMX软件生成代码时不知道为何会在初始化时直接配置成4位宽模式,从而导致初始化不过,返回错误3。因此只要将初始化代码中位宽进行修改即可。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 解决STM32F407VET6使用STM32CubeMX配置FatFs时挂载返回03错误码问题

    发表评论