STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统

作者:Jack_G
时间:2023.05.26
版本:V1.0
上次修改时间:
环境:
\quad \quad \quad \quad STM32Cube MX V6.8.1
\quad \quad \quad \quad STM32CubeH7 Firmware Package V1.11.0 / 04-Nov-2022
\quad \quad \quad \quad Fatfs: R0.12C
\quad \quad \quad \quad Keil: V5.29

文章目录

  • 前言
  • 一、基本配置
      • 1.1 配置时钟源为外部晶振
      • 1.2 配置烧录程序的引脚
      • 1.3 配置时钟树,配置主频280M
  • 二、配置SDMMC
  • 三、配置FreeRTOS
  • 四、配置Fatfs
  • 五、修改堆栈
  • 六、增加测试代码


前言

裸机使用Fatfs时,没有任何问题,加入Free RTOS后就一直不能f_mount,返回值一直为1,百思不得其解,几经周转,最后重新配置了一次就正常使用了,具体配置过程如下:


一、基本配置

1.1 配置时钟源为外部晶振

STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第1张图片



1.2 配置烧录程序的引脚

STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第2张图片




1.3 配置时钟树,配置主频280M

STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第3张图片




`注意:其中:使用SD卡时,SDMMC时钟常配为48 MHz,经过分频后不超过25MHz`(但是经过实际我测试,我配置的280 MHz,SDMMC分频系数为5也能使用,即:280/(2*5) = 28 MHz,想提速考虑这部分再斟酌)

STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第4张图片



配置个串口用于信息打印测试

STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第5张图片




二、配置SDMMC

选择四线模式,分频系数我写的5(速度较低)。
STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第6张图片





查了一些博客,有的同学反映需要将数据线和命令先上拉,不然有可能出现f_mount失败的情况,修改引脚上下拉再DPIO中修改
STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第7张图片






使能SDMMC的中断,在配置完Free RTOS后优先级会自动变为5
STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第8张图片




三、配置FreeRTOS

将heap改大一点
STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第9张图片
将初始任务的堆栈改大一点
STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第10张图片





四、配置Fatfs

修改支持长文件名和MAX_SS
不建议在此单片机开启文件名的中文支持,因为RAM不够,
STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第11张图片

五、修改堆栈

增大堆栈空间
STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统_第12张图片

最后生成代码即可

六、增加测试代码

  1. 在main.c中添加fputc重定义一下printf
    添加头文件
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include 
/* USER CODE END Includes */

重定向fputc

/* USER CODE BEGIN 4 */

//重定向fputc函数printf 
int fputc(int ch,FILE *f){
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,HAL_MAX_DELAY);
	return ch;
} 
//重定向fgetc函数 scanf
int fgetc(FILE *f){
	uint8_t ch;
	HAL_UART_Receive(&huart1,(uint8_t *)&ch,1,HAL_MAX_DELAY);
	return ch;
}
/* USER CODE END 4 */
  1. 在freertos.c中添加测试代码
    (Fatfs的初始化啥的都在任务中进行初始化)

这部分是添加的测试函数代码

#include "fatfs.h"
#include "sdmmc.h"
#include 

#define FF_MAX_SS		4096

//	函数:FatFs_FileTest
//	功能:进行文件写入和读取测试
//
uint8_t  FatFs_FileTest(void)	//文件创建和写入测试
{
	uint8_t i = 0;
	uint16_t BufferSize = 0;	
	FIL	MyFile;			// 文件对象
	UINT 	MyFile_Num;		//	数据长度
	BYTE 	MyFile_WriteBuffer[] = "STM32H7B0 SD卡 文件系统测试";	//要写入的数据
	BYTE 	MyFile_ReadBuffer[1024];	//要读出的数据
	uint8_t MyFile_Res;    /* Return value for SD */
	
	printf("-------------FatFs 文件创建和写入测试---------------\r\n");
	
	MyFile_Res = f_open(&MyFile,"0:FatFs Test.txt",FA_CREATE_ALWAYS | FA_WRITE);	//打开文件,若不存在则创建该文件
	if(MyFile_Res == FR_OK)
	{
		printf("文件打开/创建成功,准备写入数据...\r\n");
		
		MyFile_Res = f_write(&MyFile,MyFile_WriteBuffer,sizeof(MyFile_WriteBuffer),&MyFile_Num);	//向文件写入数据
		if (MyFile_Res == FR_OK)	
		{
			printf("写入成功,写入内容为:\r\n");
			printf("%s\r\n",MyFile_WriteBuffer);
		}
		else
		{
			printf("文件写入失败,请检查SD卡或重新格式化!\r\n");
			f_close(&MyFile);	  //关闭文件	
			return ERROR;			
		}
		f_close(&MyFile);	  //关闭文件			
	}
	else
	{
		printf("无法打开/创建文件,请检查SD卡或重新格式化!\r\n");
		f_close(&MyFile);	  //关闭文件	
		return ERROR;		
	}
	
	printf("-------------FatFs 文件读取测试---------------\r\n");	
	
	BufferSize = sizeof(MyFile_WriteBuffer)/sizeof(BYTE);									// 计算写入的数据长度
	MyFile_Res = f_open(&MyFile,"0:FatFs Test.txt",FA_OPEN_EXISTING | FA_READ);	//打开文件,若不存在则创建该文件
	MyFile_Res = f_read(&MyFile,MyFile_ReadBuffer,BufferSize,&MyFile_Num);			// 读取文件
	if(MyFile_Res == FR_OK)
	{
		printf("文件读取成功,正在校验数据...\r\n");
		
		for(i=0;i<BufferSize;i++)
		{
			if(MyFile_WriteBuffer[i] != MyFile_ReadBuffer[i])		// 校验数据
			{
				printf("校验失败,请检查SD卡或重新格式化!\r\n");
				f_close(&MyFile);	  //关闭文件	
				return ERROR;
			}
		}
		printf("校验成功,读出的数据为:\r\n");
		printf("%s\r\n",MyFile_ReadBuffer);
	}	
	else
	{
		printf("无法读取文件,请检查SD卡或重新格式化!\r\n");
		f_close(&MyFile);	  //关闭文件	
		return ERROR;		
	}	
	
	f_close(&MyFile);	  //关闭文件	
	return SUCCESS;
}
//	函数:FatFs_GetVolume
//	功能:计算设备的容量,包括总容量和剩余容量

void FatFs_GetVolume(void)	// 计算设备容量
{
	FATFS *fs;		//定义结构体指针
	uint32_t SD_CardCapacity = 0;		//SD卡的总容量
	uint32_t SD_FreeCapacity = 0;		//SD卡空闲容量
	DWORD fre_clust, fre_sect, tot_sect; 	//空闲簇,空闲扇区数,总扇区数

	f_getfree("0:",&fre_clust,&fs);			//获取SD卡剩余的簇

	tot_sect = (fs->n_fatent-2) * fs->csize;	//总扇区数量 = 总的簇 * 每个簇包含的扇区数
	fre_sect = fre_clust * fs->csize;			//计算剩余的可用扇区数	   

	SD_CardCapacity = tot_sect / 2048 ;	// SD卡总容量 = 总扇区数 * 512( 每扇区的字节数 ) / 1048576(换算成MB)
	SD_FreeCapacity = fre_sect / 2048 ;	//计算剩余的容量,单位为M
	printf("-------------------获取设备容量信息-----------------\r\n");		
	printf("SD容量:%dMB\r\n",SD_CardCapacity);	
	printf("SD剩余:%dMB\r\n",SD_FreeCapacity);
}

void FatFs_Check(void)	//判断FatFs是否挂载成功,若没有创建FatFs则格式化SD卡
{
	BYTE work[FF_MAX_SS]; 
	
	FATFS_LinkDriver(&SD_Driver, SDPath);		// 初始化驱动
	retSD = f_mount(&SDFatFS,"0:",1);	//	挂载SD卡
	
	if (retSD == FR_OK)	//判断是否挂载成功
	{
		printf("\r\nSD文件系统挂载成功\r\n");
		FatFs_GetVolume();
	}
	else		
	{
		if(retSD == 13)
		{
			printf("SD卡还未创建文件系统,即将格式化\r\n");
			
			retSD = f_mkfs("0:",FM_FAT32,0,work,sizeof work);		//格式化SD卡,FAT32,簇默认大小16K
			
			if (retSD == FR_OK)		//判断是否格式化成功
				printf("SD卡格式化成功!\r\n");
			else
				printf("格式化失败,请检查或更换SD卡!\r\n");
		}
		else
			printf("挂载失败:%d\r\n",retSD);
	}
}
void printf_sdcard_info(void)
{
	HAL_SD_CardInfoTypeDef  SDCardInfo;  
	uint64_t CardCap;      	//SD卡容量
	HAL_SD_CardCIDTypeDef SDCard_CID; 

	HAL_SD_GetCardCID(&hsd1,&SDCard_CID);	//获取CID
	HAL_SD_GetCardInfo(&hsd1,&SDCardInfo);                    //获取SD卡信息
	CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize);	//计算SD卡容量
	switch(SDCardInfo.CardType)
	{
		case CARD_SDSC:
		{
			if(SDCardInfo.CardVersion == CARD_V1_X)
				printf("Card Type:SDSC V1\r\n");
			else if(SDCardInfo.CardVersion == CARD_V2_X)
				printf("Card Type:SDSC V2\r\n");
		}
		break;
		case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
		default:break;
	}	
		
    printf("Card ManufacturerID: %d \r\n",SDCard_CID.ManufacturerID);				//制造商ID	
 	printf("CardVersion:         %d \r\n",(uint32_t)(SDCardInfo.CardVersion));		//卡版本号
	printf("Class:               %d \r\n",(uint32_t)(SDCardInfo.Class));		    //
 	printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd);					//卡相对地址
	printf("Card BlockNbr:       %d \r\n",SDCardInfo.BlockNbr);						//块数量
 	printf("Card BlockSize:      %d \r\n",SDCardInfo.BlockSize);					//块大小
	printf("LogBlockNbr:         %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr));		//逻辑块数量
	printf("LogBlockSize:        %d \r\n",(uint32_t)(SDCardInfo.LogBlockSize));		//逻辑块大小
	printf("Card Capacity:       %d MB\r\n",(uint32_t)(CardCap>>20));				//卡容量
}

最后在任务中进行调用即可
示例:

/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
	
	FatFs_Check();
	printf_sdcard_info();
	FatFs_FileTest();
	
  for(;;)
  {
	HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
    osDelay(1000);
  }
  /* USER CODE END StartDefaultTask */
}

附上工程代码

你可能感兴趣的:(STM32,笔记,STM32CUBEMX,stm32,单片机,嵌入式硬件)