FileX+LevelX移植stm32f407

分享下之前移植ThreadX+FileX+LevelX移植到stm32f407+nandflash的经验
板子的话,用的是我之前自己布板焊接的。
我这里使用的是标准库移植的。
先放上ThreadX官方的文档介绍,都是中文的很好懂。
链接: Azure RTOS ThreadX 文档.
通过上面那个链接可以进入到ThreadX全家桶的所有文档里

移植前的准备工作

首先要先移植ThreadX,移植完后,移植levelX,通过LevelX对接到FileX里。

ThreadX移植

这里移植ThreadX参考硬汉哥的移植流程,下面放个链接
链接: ThreadX移植教程.

LevelX移植

LevelX实际上是一个nftl层,是我们的存储介质到文件系统中的中间层,用来实现nandflash的磨损均衡,掉电保护,坏块管理的功能。

源码下载

首先,我们要到这个链接下: azure-rtos/levelx.下载到LevelX的源码。解压到我们要移植的工程里面。
在这里插入图片描述
由于分享的是以前的移植过程,使用的是以前的版本,实际上官网上已经更新到了6.18。
进入到filex的文件目录,比较重要的是common和samples两个文件夹,cmomon里有src和inc两个文件夹,其中src里是.c文件,inc里是.h文件。
samples是微软提供的一些例程文件。
在这里插入图片描述

源码添加到工程

这里由于我们使用的nandflash,所以只需要添加nandflash的API到我们的工程里。如下图所示
在这里插入图片描述

补充接口文件

参考LevelX官方说明文档,得知我们需要补充结构体LX_NAND_FLASH的以下几个函数和参数
我们可以新建一个文件,在这个文件里实现以下部分的功能
在这里插入图片描述
其中
这三个是参数
lx_nand_flash_total_blocks是nandflash的总块数
lx_nand_flash_pages_per_block是每块包含的页数
lx_nand_flash_bytes_per_page是每页有多少字节
以下10个是函数指针,
lx_nand_flash_driver_read是扇区读函数
lx_nand_flash_driver_write是扇区写函数
lx_nand_flash_driver_block_erase是块擦除函数
lx_nand_flash_driver_block_erased_verify是块擦除验证函数
lx_nand_flash_driver_page_erased_verify是页擦除验证函数
lx_nand_flash_driver_block_status_get块状态获取函数
lx_nand_flash_driver_block_status_set块状态设置函数
lx_nand_flash_driver_extra_bytes_get额外字节获取函数
lx_nand_flash_driver_extra_bytes_set额外字节设置函数
lx_nand_flash_driver_system_error出错时会调用的函数,相当于错误通知
下面这个是存放LevelX扇区缓冲区的指针
lx_nand_flash_page_buffer
首先,根据我用的Nandflash来补充以下参数

#define NAND_PAGE_SIZE             ((uint16_t)0x0800) /* 定义一个页有多少个字节,这里是2048字节 */

#define TOTAL_BLOCKS                        4096 /*定义nandflash的总块数,我用的是有4096块,两个plane*/
#define PHYSICAL_PAGES_PER_BLOCK            64 /* 每个块包含的页的数量,我这里一块有64个页                                              */
#define BYTES_PER_PHYSICAL_PAGE             2048        /* 定义每页包含的字节数量                                         */
#define WORDS_PER_PHYSICAL_PAGE             2048/4      /* 每页包含的字节数量,按words算就是2048/4                                               */
#define SPARE_BYTES_PER_PAGE                64          /* 每个页备用区的数量,2048字节的页大小对应的备用区一般都是64字节                                    */
                                                        /* For 2048 byte block spare area:                              */
//下边这几个是LevelX定义的备用区的保存位置,这个我们不用改,后面补充接口函数时直接用就行
#define BAD_BLOCK_POSITION                  0           /*      0 is the bad block byte postion                         */
#define EXTRA_BYTE_POSITION                 2           /*      2 is the extra bytes starting byte postion              */
#define ECC_BYTE_POSITION                   40          /*      40 is the ECC starting byte position   */     
补充扇区读函数

它的函数原型是:

UINT (*lx_nand_flash_driver_read)(ULONG block, ULONG page, ULONG *destination, ULONG words);

这个函数负责读取nandflash中的特定界面,里面要实现ECC错误检查和错误校正。其中输入参数
block:要读第几块
page:要读第几页
destination:读出的数据的存放地址
words:读的个数(这里是以word为单位的,也就是读words*4个字节)
下面放一下我的具体实现

UINT  nand_driver_read_page(ULONG block, ULONG page, ULONG *destination, ULONG words)
{
	u32 PageNum=0,i=0,n=0;
	u8 nand_err=0;
	u8 ecc_num=0;
	UINT lx_err=0;
	
	PageNum=(block<<6)|(page);
//	printf("Read: block=%d,page=%d,pagenum=%d,words=%d,err=%d\r\n",block,page,PageNum,words,nand_err);
	for(i=0;i<TIME_OUT;i++)
	{
		nand_err=NAND_ReadPage(PageNum,0,(u8*)destination,words*4);
		if(nand_err==0)
		{
			break;
		}
		printf("read page error,%d\r\n",nand_err);
		tx_thread_sleep(50);
	}
//	for(u16 i=0;i<words;i++)
//	{
//		printf("%08X+%d,",destination[i],i);
//	}
//	printf("\r\n");
	
	if(nand_err!=0)
	{
		return (LX_ERROR);
	}
	/******ECC校验*******/
	if(page==0)
	{
		for(i=0;i<words;i++)
		{
			if(destination[i]==0xFFFFFFFF)
			{
				n++;
			}else
			{
				break;
			}
		}
	}
	
	if(n==words||page==0)//全为0xFFFFFFFF不需要进行ECC校验
	{
		return LX_SUCCESS;
	}
	ecc_num=(words*4)/256;
	memset(&nand_dev.ecc_buf[0],0xFF,3*ecc_num);
	nand_err=NAND_ReadSpare(PageNum,ECC_BYTE_POSITION,&nand_dev.ecc_buf[0],3*ecc_num);
	if(nand_err!=0)
	{
		printf("read ecc error,%d\r\n",nand_err);
		return (LX_ERROR);
	}
	for(i=0;i<ecc_num;i++)
	{
		lx_err=_lx_nand_flash_256byte_ecc_check((u8*)destination,&nand_dev.ecc_buf[i*3]);
		if(lx_err!=0&&lx_err!=6)
		{
			printf("ECC验证出错,%d\r\n",lx_err);
			return (LX_ERROR);
		}
	}
	return LX_SUCCESS;
}

上边TIME_OUT是我自己定义的一个超时设定,主要是为了防止读数据时偶发性的超时,做一个二次读确认。
说下ECC的具体实现思路,这里直接调用了LevelX自带的ECC校验函数,以256字节为单位,每256字节生成3个ECC校验值。每次写数据时,计算写入数据的ECC值,并将他存储到每页中spare的ECC_BYTE_POSITION的偏移地址处,2048字节的话就是要存储24字节的ECC值。这里可以看出LevelX预留的是刚好够的64-40刚好等于24字节。

而读数据时,先将数据读出来,再将我们先前存入的ECC值读出来,对读出的数据进行ECC校验,并将结果与读出的ECC值做对比,如果不一致的话,尝试修复一下数据,LevelX提供的ECC函数每256字节是可以修正1b的错误的。
以上就是ECC的大体实现思路。
再说下,移植过程中发现的小问题,算是LevelX的一个小Bug吧,影响不是很大。在LevelX的API函数lx_nand_flash_open.c的286和296行会对nandflash每个块的第0页在不擦除的情况下进行两次读写。由于每次写入数据均大于256字节,所以要对这两次都进行ECC校验,但是Nandflash的特性是每次写入之前都要先擦除,也就是Nandflash的写入操作只能从1->0。这样就导致我们第二次校验的ECC值大概率是错误的。我当时为了这个问题临时是使用了把第0页的ECC校验屏蔽了。
这个问题之前移植时已经向官方反馈了,前几天他们工作人员发邮件给我,说最近会解决这个问题。期待一下。

补充扇区写函数

函数原型:

    UINT (*lx_nand_flash_driver_write)(ULONG block, ULONG page, ULONG *source, ULONG words);

参数与读函数一致。这个函数负责将数据写入Nandflash里。同样也需要实现ECC的相关功能
直接放具体的实现把:

UINT  nand_driver_write_page(ULONG block, ULONG page, ULONG *source, ULONG words)
{
	u32 PageNum=0;
	u8 nand_err=0;
	u8 ecc_num=0,i=0;
//	u8 ecc_buf[24]={0xFF};
	
	PageNum=(block<<6)|(page);
//	printf("Write: block=%d,page=%d,pagenum=%d,words=%d\r\n",block,page,PageNum,words);
	for(i=0;i<TIME_OUT;i++)
	{
		nand_err=NAND_WritePage(PageNum,0,(u8*)source,words*4);
		if(nand_err==0)
		{
			break;
		}
		printf("wirte page error,%d\r\n",nand_err);
		tx_thread_sleep(50);
	}
//	for(u16 i=0;i<words;i++)
//	{
//		printf("%08X+%d,",source[i],i);
//	}
//	printf("\r\n");

	
	if(nand_err!=0)
	{
		return (LX_ERROR);
	}
//	if((page==0)&&(source[0]&LX_BLOCK_ERASED)==LX_BLOCK_ERASED)
//	{
//		return LX_SUCCESS;
//	
//	}
	ecc_num=(words*4)/256;
	memset(&nand_dev.ecc_buf[0],0xFF,3*ecc_num);
	for(i=0;i<ecc_num;i++)
	{
		_lx_nand_flash_256byte_ecc_compute((u8*)source,&nand_dev.ecc_buf[i*3]);
	}
	nand_err=NAND_WriteSpare(PageNum,ECC_BYTE_POSITION,&nand_dev.ecc_buf[0],3*ecc_num);
	if(nand_err!=0)
	{
		printf("wirte ecc error,%d\r\n",nand_err);
		return (LX_ERROR);
	}
//	memset(ecc_buf,0xFF,3*ecc_num);
//	nand_err=NAND_ReadSpare(PageNum,ECC_BYTE_POSITION,ecc_buf,3*ecc_num);
	
	return LX_SUCCESS;
}
补充块擦除函数

函数原型:

UINT (*lx_nand_flash_driver_block_erase)(ULONG block, ULONG erase_count);

erase_count是擦除的数量,这里我直接调用了之前已经整理好的块擦除函数。

UINT  nand_driver_block_erase(ULONG block, ULONG erase_count)
{
	u8 nand_err=0;
	
	LX_PARAMETER_NOT_USED(erase_count);
	printf("erase block:%d,num=%d\r\n",block,erase_count);
	nand_err=NAND_EraseBlock(block);
	if(nand_err!=0)
	{
		printf("block_erase error,%d\r\n",nand_err);
		return (LX_ERROR);
	}
	return(LX_SUCCESS);
}
补充块擦除验证函数

函数原型:

    UINT (*lx_nand_flash_driver_block_erased_verify)(ULONG block);

这个函数是每次擦除块之后调用的,因为Nandflash擦除是0->1,理论上一个块擦除后数据应该全是0xFF,但是Nandflash使用的过程中可能会出现坏块,就导致擦除完之后不是0xFF,LevelX通过这个函数来确定坏块的产生。这个函数要对比块里的数据是不是全为0xFF 包括Page的数据区和备用区。
具体实现:

UINT  nand_driver_block_erased_verify(ULONG block)
{
	u16 i=0,j=0;
	u32 PageNum=0;
	
	for(i=0;i<PHYSICAL_PAGES_PER_BLOCK;i++)
	{
		PageNum=0;
		PageNum=(block<<6)|(i);
		memset(verifybuf,0,sizeof(verifybuf));
		NAND_ReadPage(PageNum,0,(u8*)verifybuf,NAND_PAGE_SIZE);
		for(j=0;j<NAND_PAGE_SIZE/4;j++)
		{
			if(verifybuf[j]!=0xFFFFFFFF)
			{
				printf("block[%d]_erased_verify error\r\n",block);
				return(LX_ERROR);
			}
		}
		NAND_ReadSpare(PageNum,0,SpareArea,64);
		for(j=0;j<64;j++)
		{
			if(SpareArea[j]!=0xFF)
			{
				printf("block[%d]_erased_verify error\r\n",block);
				return(LX_ERROR);
			}
		}
	}
	return(LX_SUCCESS); 
}
补充页擦除验证函数

函数原型:

    UINT (*lx_nand_flash_driver_page_erased_verify)(ULONG block, ULONG page);

与上个函数类似,这个函数是对页进行校验。
具体实现:

UINT  nand_driver_page_erased_verify(ULONG block, ULONG page)
{
	u16 i=0;
	u32 PageNum=0;
	
	PageNum=(block<<6)|(page);
	memset(verifybuf,0,sizeof(verifybuf));
	NAND_ReadPage(PageNum,0,(u8*)verifybuf,NAND_PAGE_SIZE);
	
	for(i=0;i<NAND_PAGE_SIZE/4;i++)
	{
		if(verifybuf[i]!=0xFFFFFFFF)
		{
			printf("page_erased_verify error\r\n");
			return(LX_ERROR);
		}
	}
	NAND_ReadSpare(PageNum,0,SpareArea,64);
	for(i=0;i<64;i++)
	{
		if(SpareArea[i]!=0xFF)
		{
			printf("page_erased_verify error\r\n");
			return(LX_ERROR);
		}
	}
	return(LX_SUCCESS); 
}
补充块状态获取函数

函数原型:

    UINT (*lx_nand_flash_driver_block_status_get)(ULONG block, UCHAR *bad_block_flag);

LevelX每个块的状态被放在第0page的spare区中,位置,LevelX已经给我们设置好了,是在BAD_BLOCK_POSITION处。我们要实现的就是从第Block的0page的Spare的BAD_BLOCK_POSITION处读出1字节的数据到bad_block_flag处就行了。
具体实现:

UINT  nand_driver_block_status_get(ULONG block, UCHAR *bad_block_byte)
{
	u32 PageNum=0,i=0;
	u8 nand_err=0;
	
	PageNum=(block<<6);
	for(i=0;i<TIME_OUT;i++)
	{
		nand_err=NAND_ReadSpare(PageNum,BAD_BLOCK_POSITION,bad_block_byte,1);
		if(nand_err==0)
		{
			break;
		}
		printf("status_get error!,%d\r\n",nand_err);
		tx_thread_sleep(50);
	}
	
	if(nand_err!=0)
	{
		
		return(LX_ERROR);
	}
//	printf("block:%d,status_get:%d\r\n",block,*bad_block_byte);
	return(LX_SUCCESS);
}
补充块状态设置函数

函数原型:

    UINT (*lx_nand_flash_driver_block_status_set)(ULONG block, UCHAR bad_block_flag);

与上函数类似,这个函数用来标记nandflash的块状态。
具体实现:

UINT  nand_driver_block_status_set(ULONG block, UCHAR bad_block_byte)
{
	u32 PageNum=0,i=0;
	u8 nand_err=0;
	
	PageNum=(block<<6);
	printf("block:%d,status_set:%d\r\n",block,bad_block_byte);
	for(i=0;i<TIME_OUT;i++)
	{
		nand_err=NAND_WriteSpare(PageNum,BAD_BLOCK_POSITION,&bad_block_byte,1);
		if(nand_err==0)
		{
			break;
		}
		printf("status_set write error!,%d\r\n",nand_err);
		tx_thread_sleep(50);
	}
	
	if(nand_err!=0)
	{
		
		return(LX_ERROR);
	}
	return(LX_SUCCESS);
}
补充块额外字节获取与设置函数

函数原型:

UINT (*lx_nand_flash_driver_extra_bytes_get)(ULONG block, ULONG page, UCHAR *destination, UINT size);

根据LevelX的官方文档解释,可知,这个额外字节对于64字节的spare,是有4字节大小的。这4个字节是LevelX定义的一个扇区映射存放地点,下面是这个32位字大小每一位的含义
在这里插入图片描述
具体代码实现:

UINT  nand_driver_block_extra_bytes_get(ULONG block, ULONG page, UCHAR *destination, UINT size)
{
	u32 PageNum=0,i=0;
	u8 nand_err=0;
	
	PageNum=(block<<6)|page;
	for(i=0;i<TIME_OUT;i++)
	{
		nand_err=NAND_ReadSpare(PageNum,EXTRA_BYTE_POSITION,destination,size);
		if(nand_err==0)
		{
			break;
		}
		printf("extra_get error!,%d,%d\r\n",nand_err,size);
		tx_thread_sleep(50);
	}
	
//	destination+=size;
//	printf("extra_get: block=%d,page=%d,size=%d,err=%d\r\n",block,page,size,nand_err);
	if(nand_err!=0)
	{
		
		return(LX_ERROR);
	}
//	printf("\r\n");
	return(LX_SUCCESS);
}
UINT  nand_driver_block_extra_bytes_set(ULONG block, ULONG page, UCHAR *source, UINT size)
{
	u32 PageNum=0,i=0;
	u8 nand_err=0;
	
	PageNum=(block<<6)|page;
//	printf("\r\n");
	for(i=0;i<TIME_OUT;i++)
	{
		nand_err=NAND_WriteSpare(PageNum,EXTRA_BYTE_POSITION,source,size);
		if(nand_err==0)
		{
			break;
		}
		printf("extra_set write error!,%d\r\n",nand_err);
		tx_thread_sleep(50);
	}
	
//	source+=size;
	if(nand_err!=0)
	{
		
		return(LX_ERROR);
	}
	return(LX_SUCCESS);
}
补充系统错误处理函数

原型:

    UINT  (*lx_nand_flash_driver_system_error)(UINT error_code, ULONG block, ULONG page);

这个函数在LevelX遇到错误时自动调用,相当于一个错误通知函数,函数参数error_code是错误代码,另外两个分别是出错的地方所在的块和页。
我这里写的就比较简单啦,就是单纯的打印一下在哪出的错,以及错误代码。

UINT  nand_driver_system_error(UINT error_code, ULONG block, ULONG page)
{
    LX_PARAMETER_NOT_USED(error_code);
    LX_PARAMETER_NOT_USED(block);
    LX_PARAMETER_NOT_USED(page);
		printf("err:%d,block:%d,page:%d\r\n",error_code,block,page);
    /* Custom processing goes here...  all errors except for LX_NAND_ERROR_CORRECTED are fatal.  */
    return(LX_ERROR);
}

在LevelX中操作函数

以上已经补充完了LevelX需要的所有底层API函数,接下来我们需要将这些函数注册到LevelX里面,以便LevelX能够调用到我们写的函数。相当于一个初始化函数,要在LevelX运行之前执行。

UINT  nand_flash_initialize(LX_NAND_FLASH *nand_flash)
{
		memset((char*)nand_flash_simulator_buffer,0xFF,BYTES_PER_PHYSICAL_PAGE);
		memset((char*)verifybuf,0xFF,BYTES_PER_PHYSICAL_PAGE);
    /* Setup geometry of the NAND flash.  */
    nand_flash -> lx_nand_flash_total_blocks =                  TOTAL_BLOCKS;
    nand_flash -> lx_nand_flash_pages_per_block =               PHYSICAL_PAGES_PER_BLOCK;
    nand_flash -> lx_nand_flash_bytes_per_page =                BYTES_PER_PHYSICAL_PAGE;

    /* Setup function pointers for the NAND flash services.  */
    nand_flash -> lx_nand_flash_driver_read =                   nand_driver_read_page;
    nand_flash -> lx_nand_flash_driver_write =                  nand_driver_write_page;
    nand_flash -> lx_nand_flash_driver_block_erase =            nand_driver_block_erase;
    nand_flash -> lx_nand_flash_driver_block_erased_verify =    nand_driver_block_erased_verify;
    nand_flash -> lx_nand_flash_driver_page_erased_verify =     nand_driver_page_erased_verify;
    nand_flash -> lx_nand_flash_driver_block_status_get =       nand_driver_block_status_get;
    nand_flash -> lx_nand_flash_driver_block_status_set =       nand_driver_block_status_set;
    nand_flash -> lx_nand_flash_driver_extra_bytes_get =        nand_driver_block_extra_bytes_get;
    nand_flash -> lx_nand_flash_driver_extra_bytes_set =        nand_driver_block_extra_bytes_set;
    nand_flash -> lx_nand_flash_driver_system_error =           nand_driver_system_error;

    /* Setup local buffer for NAND flash operation. This buffer must be the page size of the NAND flash memory.  */
    nand_flash -> lx_nand_flash_page_buffer =  &nand_flash_simulator_buffer[0];

    /* Return success.  */
    return(LX_SUCCESS);
}

上述函数的参数的nand_flash可以看作一个对象(其实看他们开源的代码,其实很多C源码都是以面向对象的思想写的,参考这种思想,后来也对我自己的项目以面向对象的思想进行了重构,多读读源码还是挺有意义的),其中有各种参数和方法可以调用。我们就是对这个对象中的某些方法进行补充。最后调用这个对象来实现我们需要的操作。

先写这麽多吧,后面FileX和LevelX的对接,等以后有时间了写了再写吧。

### 回答1: STM32 FileX是一款嵌入式文件系统,专为STM32微控制器系列而设计和优化。它提供了一个强大而灵活的文件管理系统,适用于存储和管理嵌入式系统中的各种文件类型。 STM32 FileX具有以下特点和优势: 1. 系统资源占用低:FileX对内存资源的要求非常低,可以在有限的嵌入式系统中运行,而不会造成系统资源的浪费,从而使得STM32微控制器可以更加高效地执行其他任务。 2. 多种文件类型支持:FileX可以处理各种类型的文件,包括文本文件、二进制文件、图像文件等。它支持常见的文件操作,如打开、读取、写入、重命名、删除等,使得嵌入式系统可以灵活地处理不同类型的文件。 3. 文件系统安全性:FileX提供了数据完整性和文件系统安全性的保护机制。通过使用校验和、CRC校验、写入保护等技术,可以保证文件在读写过程中不会被破坏或损坏,确保数据的可靠性和完整性。 4. 支持多线程:FileX支持多线程操作,可以同时处理多个文件的读写操作。这在复杂的嵌入式系统中非常有用,可以提高系统的整体性能和效率。 5. 高度可配置:FileX可以根据具体的应用需求进行灵活的配置。用户可以根据需要选择适合的文件系统大小、块大小、簇大小等参数,以满足自己的存储容量和性能要求。 总的来说,STM32 FileX是一款功能强大、高效可靠的嵌入式文件系统。它在不占用过多系统资源的同时,提供了丰富的文件操作功能,可以满足各种嵌入式系统对文件管理的需求。无论是嵌入式设备的开发者还是应用工程师,都能够通过使用STM32 FileX轻松实现文件的存储、管理和操作。 ### 回答2: STM32 FileXSTMicroelectronics开发的一款嵌入式文件系统。它是专门为STM32微控制器设计的,提供了可靠的文件系统功能,能够在嵌入式系统中进行文件的读写和管理。 STM32 FileX具有以下特点和功能: 1. 高性能和低资源占用:STM32 FileX采用了高效的算法和数据结构,使其能够在嵌入式系统中快速且高效地进行文件的读写操作,并且占用的系统资源较少,有利于节省处理器的计算能力和内存空间。 2. 可靠的数据保护:STM32 FileX提供了可靠的数据保护机制,包括存储介质上的文件一致性检查、写操作的缓存管理、数据的完整性和可靠性验证等,能够有效地防止数据损坏和丢失,保证了数据的可靠性和一致性。 3. 多种文件系统支持:STM32 FileX支持多种文件系统,包括FAT12、FAT16、FAT32等,能够适应不同的应用需求和存储介质类型。 4. 灵活的文件管理功能:STM32 FileX提供了丰富的文件管理功能,包括文件的创建、打开、读写、删除等操作,能够方便地进行文件的管理和维护。 5. 完善的API接口和开发工具:STM32 FileX提供了完善的API接口和开发工具,使开发者能够快速地集成和使用该文件系统,提高开发效率。 6. 应用广泛:STM32 FileX适用于多种嵌入式应用场景,包括工业自动化、智能家居、车载娱乐系统、医疗设备等,能够满足不同领域的文件管理需求。 总的来说,STM32 FileX是一款高性能、可靠的嵌入式文件系统,能够方便地进行文件的读写和管理,适用于各种嵌入式系统的开发。 ### 回答3: STM32 FileX是一个嵌入式文件系统,专为STM32系列微控制器开发的。它是一个可靠、高效、安全的文件系统,能够管理和操作嵌入式系统中的文件和文件夹。 STM32 FileX提供了许多功能,包括文件的创建、读取、写入、删除等。用户可以通过简单的API来访问这些功能,并可以根据自己的需求进行定制。 STM32 FileX能够有效地管理嵌入式系统中的存储器资源。它支持不同类型的存储介质,如RAM、Flash、SD卡等。通过使用FileX,开发人员可以轻松地在嵌入式系统中添加文件系统,从而使得数据的存储和管理更加方便。 STM32 FileX具有很高的性能和可靠性。它采用了先进的文件索引技术,能够快速地定位文件和文件夹。同时,它还具备数据保护机制,能够确保文件的完整性和安全性。 STM32 FileX是易于使用和集成的。它提供了一个直观的编程接口,使开发人员能够快速地熟悉和使用。此外,它还提供了丰富的示例代码和文档,帮助开发人员更好地理解和使用该文件系统。 总之,STM32 FileX是一个专为STM32系列微控制器开发的嵌入式文件系统。它具有高效、可靠、安全的特性,能够方便地管理和操作嵌入式系统中的文件和文件夹。无论是存储数据,还是进行软件更新和配置,STM32 FileX都能够提供可靠的支持。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值