[ BLE4.0 ] 伦茨ST17H66开发-文件系统FS-写入和读取数据

目录

一、前言

二、FS系统

三、详细步骤

3.1 查阅SDK手册

3.2 修改宏定义

3.3 初始化FS

3.3.1 参数是什么

3.3.2 如何确定地址参数

3.4 写入数据

3.5 读取数据

四、注意事项


一、前言

        在单片机程序开发中,数据的存储与读取无疑是实际开发中十分重要的一环,那么我们常见的存储方式要么是借助外部存储芯片,要么是存储在Flash。伦茨芯片提供了一种名为FS的文件系统,本质上也是存储在Flash中,但其能够更方便的帮助我们存储结构体等数据信息。

二、FS系统

        为了方便应用存取内部 flash 中的数据,ST17H65/66 实现了一个轻量级文件系统,该文件 系统提供一组同步 API,支持 16bit 文件 ID,文件查找,读、写、删除、以及文件系统查 询,垃圾文件回收[--引自开发手册-文件系统]。

        注意这个地方其实是有坑的,如果可以自己读写Flash的话,也是种不错的选择。

三、详细步骤

3.1 查阅SDK手册

        其中,提到了FS文件系统存储的功能的相关示例代码。我们根据其提供的示例代码和操作流程,逐步完成。

3.2 修改宏定义

        首先,打开宏定义,修改宏USE_FS为1。

3.3 初始化FS

        在任务文件中,导入fs.h文件。

        随后调用hal_fs_init()函数

hal_fs_init(0x11030000,3); // 初始化一块3*4K的空间

3.3.1 参数是什么

        首先使用这个函数,我们必须知道参数是什么?给函数一个合适的参数,才能让程序能够正常运行。

        通过查阅开发手册,我们可以得到如下信息:

        第一个参数代表文件系统的起始地址,其起始地址为0x11005000,且起始地址必须与4096字节对齐,也就是说起始地址只能是类似0x11005000、0x11006000、0x11007000等。

        第二个参数是扇区数量,综合手册其他资料来看,其一个扇区为4K,每个扇区为4096字节,与前面对应。

        由于其取值范围为3~78,我们通过最小起始地址0x11005000可以推断出,其总的可以供我们使用的内存大小为78*4096 = 319488字节,也就是0x4E000,加上偏移的0x11000000可以得出,其总的内存地址范围为0x11005000 ~ 0x1104E000(仅猜测,准确值需要查阅芯片手册,但这些范围一定可用

3.3.2 如何确定地址参数

        如果大家使用过Flash想必一定知道,我们使用Flash存储数据一定会避开程序占用的Flash的地址,防止出现错误。

        那么,我们现在不知道程序占用的地址,怎么才能避开呢?一种方案是选择足够靠后的地址,但这种方法不符合科学。第二种方案是通过查看程序所占用的Flash地址的范围,主动避开。

        本文将使用第二种方法,教大家避开程序所占用的地址。

        当大家使用伦茨的烧写程序烧写程序时,注意一条调试语句。

        我们可以看到APP========0x11005000------0x1100c55c========,这说明编译后的程序所占的内存地址范围为0x11005000 ~ 0x1100C55C,为避开这个地址,我们同样也可以选择例程中的0x11030000。

3.4 写入数据

        下面我们完成写入数据的程序,随后烧写运行后,再写入读数据的程序,打印查看效果。

        如果刚刚你和我一起查阅了开发手册,那么你会发现,手册中提供的写入函数与认识SDK文档中的不一致。

        那么这是为什么呢?

        其实,这是因为文件系统的垃圾回收机制。这个功能在手册中也是有具体函数实现的。

        而认识SDK文档中,使用的osal_snv_write函数,其内部包含了垃圾回收机制。同时,官方也建议我们使用包含垃圾回收机制的函数。这一点在开发手册中也有提到。

        因此,我们使用osal_snv_write函数写入一串数据。

//下列代码写在任务初始化函数中
hal_fs_init(0x11030000,3); // 初始化一块3*4K的空间
uint8_t data[10]={'\0'};
sprintf((char *)data,"Hello\n");
osal_snv_write(1,sizeof(data),data);
LOG("Write OK");

        烧写完毕后,看到调试信息即可。

        但实际上,这样并不对!

        我可以明确的告诉大家,其给出的代码很多都不能正常运行,官方在文档中给出的很多语句直接拷贝都是错误的,这是因为文档中往往只提到了关键语句,而非全部语句。

        通过添加调试语句,输出初始化状态,我们可以看懂,初始化是不成功的。

        因此,我通过对其例程的分析,按照如下代码可以实现功能。

fs_t fst;
hal_fs_ctx(&fst);
uint8_t status = hal_fs_init(0x1103C000,3);
if(status == SUCCESS)
	LOG("Init OK");
else
	LOG("Not OK=%d \n",status);
uint8_t data[10]={'\0'};
sprintf((char *)data,"Hello\n");
status = osal_snv_write(0x80,10,data);
if(status == SUCCESS)
	LOG("Write OK");
else
	LOG("Not OK=%d \n",status);

        可以看到,现在初始化是成功的。

3.5 读取数据

        通过上面的代码,我们可以看出写入的是ASCII格式的"Hello\n"字符串,下面我们更改函数,读取并打印出来。在定时任务中,读取并打印出来。

        根据错误码,我们可以查到原因是打开失败。

        那我们修改一下代码,每次读取之前给他初始化一下呢。

        烧录,查看程序输出,发现其可以实现输出功能,但仅能输出一次。

        那么这是什么原因呢?

        其实经过几个小时的摸索,发现原来是因为没有垃圾回收导致的。每次读取完后,进行垃圾回收即可。代码如下:

fs_t fst;
hal_fs_ctx(&fst);
hal_fs_init(0x1103C000,3);
LOG("Reading...");
uint8_t data2[10];
LOG("Read=%d\n",osal_snv_read(0x80,10,data2));
LOG("%s",data2);
hal_fs_garbage_collect();

        那么,我的代码中存在hal_fs_init函数,那每次执行任务岂不是都要初始化一遍?其实不是。根据调试信息可以看出,hal_fs_init函数仅在第一次执行,这点我们通过其函数实现也能发现。

        程序执行时,如果已经初始化完成了,将不会再初始化。

        那么编译新代码后查看结果。

        可以看到,读取功能已经实现。

四、注意事项

        若要使用上述函数并实现功能,你必须导入下面的一些文件,分别是fs.c和osal_snv.c,但这不代表你仅导入这些文件。

        这其中的一些代码引入了其他的一些头文件和函数,比如crc16.c,你导入这些文件的同时务必要导入对应的头文件,以保证代码的正常运行。

  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西西菜鸟

打赏支持获得问题解答机会

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值