[原创] 【STM32H7S78-DK】测评+ToucGFX之FATFS文件系统移植

lugl4313820   2024-9-21 18:57 楼主

【前言】

在实际工程中,如果需要用到外部储存,特别是大文件,测需要用到SD卡,开发板板载了SD读卡器,此次分享如何在TouchGFX中读取SD卡的属性,以及读取指定文件的内容。本次主要学习官方示例:

1、STM32Cube_FW_H7RS_V1.1.0\Projects\STM32H7S78-DK\Examples\SD\SD_ReadWrite_DMA,此示例为如何初始化SD卡。

2、STM32Cube_FW_H7RS_V1.1.0\Projects\STM32H7S78-DK\Applications\FatFs\FatFs_uSD_RTOS,此工程示例如何在FreeRTOS中实现FATFS的工程配置以及文件的读写功能。

此次的工程在前一篇的TouchGFX工程中添加指定的功能:【STM32H7R/S-DK】创建TouchGFX工程基础 - stm32/stm8 - 电子工程世界-论坛 (eeworld.com.cn)

【实现方法】

一、SD的图形化配置,打开STM32CubeMX,打开工程,添加SDMMC1,并配置为4bit传输模式,时钟为下降沿时采样,以及总结分频。

image.png  

同时开启中断,以及核对与开发板原理图的GPIO是否一致,此次配置GPIO默认与原理图一致,不需要修改GPIO的配置。

生成工程后,使用MDK打开。

二、由于在SD的Init中需要用HAL_Delay函数,需要手工开启SysTick中断,如果没有开启就会阻塞在初始化上。

我这里的解决方法是自己重写了HAL_Delay函数,以及初始化的函数。

#include  "delay.h"
 #include "main.h"
uint8_t fac_us=0;
uint16_t fac_ms=0;
 
void Delay_Init()
{
	//只可以选择不分频或者8分频,这里选择系统时钟8分频,最后频率为9MHZ
	SysTick->CTRL &= ~(1<<2);
	//SystemCoreClock为72000000,最终fac_us为9,也就是记录震动9次。因为频率为9MHZ所以为1us
	fac_us  = SystemCoreClock  / 8000000;  
	fac_ms  = fac_us*1000;  //1000us=1ms
}
 
/*
	CTRL     SysTick控制及状态寄存器
	LOAD     SysTick重装载数值寄存器
	VAL      SysTick当前数值寄存器
*/
void Delay_us(uint32_t nus)
{
	uint32_t temp;
	SysTick->LOAD  =nus*fac_us;   //设置加载的值,比如1us就要计数9次。nus传入1,CALIB=1*9=9,最后就是1us
	SysTick->VAL   =0x00;         //清空计数器中的值,LOAD里的值不是写入后就会加载,而是在systick使能且VAL值为0时才加载
	SysTick->CTRL  |=SysTick_CTRL_ENABLE_Msk;  //使能时钟,开始计时
	do
	{
		temp=SysTick->CTRL;   //查询是否计数完成
	}while((temp&0x01)&&!(temp&(1<<16)));   //先判断定时器是否在运行,再判断是否计数完成
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;      					 //清空计数器	 
}
 
void Delay_ms(uint32_t nms)
{
	uint32_t temp;
	SysTick->LOAD  =nms*fac_ms;   //设置加载的值,比如1us就要计数9次。nus传入1,CALIB=1*9=9,最后就是1us
	SysTick->VAL   =0x00;         //清空计数器中的值,LOAD里的值不是写入后就会加载,而是在systick使能且VAL值为0时才加载
	SysTick->CTRL  |=SysTick_CTRL_ENABLE_Msk;  //使能时钟,开始计时
	do
	{
		temp=SysTick->CTRL;   //查询是否计数完成
	}while((temp&0x01)&&!(temp&(1<<16)));   //先判断定时器是否在运行,再判断是否计数完成
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;      					 //清空计数器	 
}

void HAL_Delay(uint32_t nms)
{
	uint32_t temp;
	SysTick->LOAD  =nms*fac_ms;   //设置加载的值,比如1us就要计数9次。nus传入1,CALIB=1*9=9,最后就是1us
	SysTick->VAL   =0x00;         //清空计数器中的值,LOAD里的值不是写入后就会加载,而是在systick使能且VAL值为0时才加载
	SysTick->CTRL  |=SysTick_CTRL_ENABLE_Msk;  //使能时钟,开始计时
	do
	{
		temp=SysTick->CTRL;   //查询是否计数完成
	}while((temp&0x01)&&!(temp&(1<<16)));   //先判断定时器是否在运行,再判断是否计数完成
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;      					 //清空计数器	 
}

在main.c中添加初始化函数就行了。

三、SD测试,在TouchGFX中添加一个Text控件,以及一个按键,在Screen1View.cpp中添加测试代码:

void Screen1View::fungetsdinfo()
{
    HAL_SD_CardInfoTypeDef pCardInfo = {0};
    HAL_StatusTypeDef ret = HAL_SD_GetCardInfo(&hsd1,&pCardInfo);
    Unicode::snprintf(textCardInfoBuffer, TEXTCARDINFO_SIZE, "CardType=%d\nCardVersion=%d\nBlockSize=%dk\n",
		                                                         pCardInfo.CardType,pCardInfo.CardVersion,pCardInfo.BlockSize);
    textCardInfo.invalidate();
}

其功能为读取SD卡的一些基本参数,并更新到text控制中,下载后得到界面如下:

image.png  

四、FATFS移植

1、在生成的工程中的文件夹内,已经有了fatfs的源码了,路径为:Middlewares\Third_Party\FatFs\source,我们只需要添加指定文件到工程中。

2、根据官方的示例,我添加了如下文件到工程中:

image.png   同时根据官方的示例对几个配置文件进行修改。

1、修改sd_diskio_config.h中的指定的hsd1

image.png  

2、修改ffconf.h如下:



#define FFCONF_DEF 80286	/* Revision ID */
/*-----------------------------------------------------------------------------/
/ Additional user header to be used
/-----------------------------------------------------------------------------*/
#include "main.h"
#include "stm32h7rsxx_hal.h"

/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/

#define FF_FS_READONLY	0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/  Read-only configuration removes writing API functions, f_write(), f_sync(),
/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/  and optional writing functions as well. */

#define FF_FS_MINIMIZE	0
/* This option defines minimization level to remove some basic API functions.
/
/   0: Basic functions are fully enabled.
/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/      are removed.
/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/   3: f_lseek() function is removed in addition to 2. */

#define FF_USE_FIND		0
/* This option switches filtered directory read functions, f_findfirst() and
/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */

#define FF_USE_MKFS		1
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */

#define FF_USE_FASTSEEK	1
/* This option switches fast seek function. (0:Disable or 1:Enable) */

#define FF_USE_EXPAND	0
/* This option switches f_expand function. (0:Disable or 1:Enable) */

#define FF_USE_CHMOD	0
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */

#define FF_USE_LABEL	0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/  (0:Disable or 1:Enable) */

#define FF_USE_FORWARD	0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */

#define FF_USE_STRFUNC	2
#define FF_PRINT_LLI	1
#define FF_PRINT_FLOAT	1
#define FF_STRF_ENCODE	3


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

#define FF_CODE_PAGE	936
/* This option specifies the OEM code page to be used on the target system.
/  Incorrect code page setting can cause a file open failure.
/
/   437 - U.S.
/   720 - Arabic
/   737 - Greek
/   771 - KBL
/   775 - Baltic
/   850 - Latin 1
/   852 - Latin 2
/   855 - Cyrillic
/   857 - Turkish
/   860 - Portuguese
/   861 - Icelandic
/   862 - Hebrew
/   863 - Canadian French
/   864 - Arabic
/   865 - Nordic
/   866 - Russian
/   869 - Greek 2
/   932 - Japanese (DBCS)
/   936 - Simplified Chinese (DBCS)
/   949 - Korean (DBCS)
/   950 - Traditional Chinese (DBCS)
/     0 - Include all code pages above and configured by f_setcp()
*/

#define FF_USE_LFN		0
#define FF_MAX_LFN		255


#define FF_LFN_UNICODE	0


#define FF_LFN_BUF		255
#define FF_SFN_BUF		12


#define FF_FS_RPATH		0


/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/

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

#define FF_STR_VOLUME_ID	0
#define FF_VOLUME_STRS		"RAM","NAND","CF","SD","SD2","USB","USB2","USB3"


#define FF_MULTI_PARTITION	0


#define FF_MIN_SS		512
#define FF_MAX_SS		512


#define FF_LBA64		0


#define FF_MIN_GPT		valueNotSetted

#define FF_USE_TRIM		0
-----------------------------------------------------------------------*/

#define FF_FS_TINY		0

#define FF_FS_EXFAT		0

#define FF_FS_NORTC		0
#define FF_NORTC_MON	6
#define FF_NORTC_MDAY	4
#define FF_NORTC_YEAR	2015

#define FF_FS_NOFSINFO	0


#define FF_FS_LOCK		2


#define FF_FS_REENTRANT	0
#define FF_FS_TIMEOUT	1000


/*--- End of configuration options ---*/

3、编写用户函数fatfs.c函数,此函数也是学习FATFS的示例工程,在工程中创建一个FreeRTOS的任务线程,如果检测到SD插入,则进行挂载,挂载结束后写入文件STM32.TXT,并写入一串符串:const static uint8_t wtext[] = "This is STM32 working\n with FatFs uSD+FreeRTOS\n eeworld"; /* File write buffer */

如果写入成功,再读取此文件到rtext字符数组中。

4、为了测试,我又单独写了一个读取函数,方便touchGFX进行读取测试,代码如下:

void fs_read(void)
{
    FRESULT res;                                          /* FatFs function common result code */
    uint32_t byteswritten, bytesread;                     /* File write/read counts */
    res = f_open(&SDFile, "STM32.TXT", FA_READ);
    if(res == FR_OK)
    {
      /* Read data from the text file */
      res = f_read(&SDFile, ( void *)rtext, sizeof(rtext), (void *)&bytesread);

      if((bytesread > 0) && (res == FR_OK))
      {
        /* Close the open text file */
        f_close(&SDFile);
      }
        f_close(&SDFile);
    }
}

四、TouchGFX界面设计

在touchGFX Designer中,再添加text控制与一个button控件,添加读取测试,代码如下:

void Screen1View::funShow()
{
    fs_read();
    Unicode::fromUTF8(rtext,textFileBuffer,100);
    textFile.invalidate();

}

【实现效果】

点击屏幕中的不同按键,可以获取对应的信息。

image.png   【总结】

此次工程为我第一次体验基于的TouchGFX下面的SD卡的读写测试,在SD驱动Init中遇到了因为HAL_Delay的问题折腾了好几天,最后追踪到问题点,并成功解决。基余的根据官方的示例并无困难。

【附工程源码】

eepworld_sdmmc.zip (81.5 MB)
(下载次数: 2, 2024-9-21 18:55 上传)
本帖最后由 lugl4313820 于 2024-9-21 18:57 编辑

回复评论 (13)

不错不错,值得学习

点赞  2024-9-21 21:41

大佬牛皮,学习了

没用比没有强
点赞  2024-9-22 16:38
引用: kylixyao 发表于 2024-9-21 21:41 不错不错,值得学习

感谢大佬的关注。

点赞  2024-9-22 22:16
引用: 电子烂人 发表于 2024-9-22 16:38 大佬牛皮,学习了

大佬过奖了,您的文章比我写得好!

点赞  2024-9-22 22:17

厉害厉害,可以把SD卡的图片读取出来,然后显示吗?

点赞  2024-9-23 09:10
引用: wangerxian 发表于 2024-9-23 09:10 厉害厉害,可以把SD卡的图片读取出来,然后显示吗?

这个使用LTDC应该不是难题,难题是TouchGFX他有自己的图片算法,我得仔细想想。

点赞  2024-9-23 21:37

lu哥,我就收藏了。。。。。。。。。。。。。。。。。。。

btw,rust还搞不?

点赞  2024-9-24 08:51
引用: lugl4313820 发表于 2024-9-23 21:37 这个使用LTDC应该不是难题,难题是TouchGFX他有自己的图片算法,我得仔细想想。

他用的好像是bmp格式存储图片数据的,我觉得可以试试。

点赞  2024-9-24 09:07
引用: hellokitty_bean 发表于 2024-9-24 08:51 lu哥,我就收藏了。。。。。。。。。。。。。。。。。。。 btw,rust还搞不?

rust现在还没有那个水平来搞呀,还没有入门呢

 

点赞  2024-9-24 21:59

lu哥加油。。。。。准备沿着你的脚印前进呢。。。。。。。。

点赞  2024-9-25 08:30

谢谢分享,期待后续深度评测

默认摸鱼,再摸鱼。2022、9、28
点赞  2024-9-25 14:03
工程代码10积分 下载后怎么是STM32H7S78-DK_Appli\STM32H7S78-DK_Appli.axf: Error: L6200E: Symbol __stdout multiply defined (by stdio_streams.o and usart.o).
点赞  2024-10-18 15:47
引用: mameng 发表于 2024-10-18 15:47 工程代码10积分 下载后怎么是STM32H7S78-DK_Appli\STM32H7S78-DK_Appli.axf: Error: L6200E: Symbol __stdo ...

你检查一下工程,看一下usart.h的头文件是不是包含进去了。

点赞  2024-10-18 19:57
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复