作者:KK
上期回顾:(点此连接跳转),上期介绍了如何利用rtthread系统同步网络时间和天气预报到UI上,本期将介绍一下如何通过SD卡和ymodem串口升级固件。
视频演示:
1.固件升级演示: 固件升级在第三个界面,已经提前把待升级的固件和图片bin文件放在了SD卡里,升级前软件版本为V1,升级后软件版本为V2,并且更改了表盘,升级完成后,会记录升级的时间,详细请看视频演示:
2.命令行演示: 命令行添加了更多功能,不仅可以通过命令行升级固件,还可以把sd卡中的图片文件复制到spi flash中,命令行的更多功能,欢迎下载源代码体验。
1.文件系统简介
1.1 DFS 简介
DFS( Device File System)是一种抽象的文件机制,RT-Thread中对文件系统的相关操作实际上都是通过操作DFS实现,也就是说DFS是对各种文件系统的抽象。DFS使的其他部分无须关心不同文件系统之间的差异,使得RT-Thread可以支持多种类型的文件系统。
1.2 DFS 框架
RT-Thread DFS 组件的主要功能特点有:
- 为应用程序提供统一的 POSIX 文件和目录操作接口:read、write、poll/select 等。
- 支持多种类型的文件系统,如 FatFS、RomFS、DevFS 等,并提供普通文件、设备文件、网络文件描述符的管理。
- 支持多种类型的存储设备,如 SD Card、SPI Flash、Nand Flash 等。
DFS 的层次架构如下图所示,主要分为 POSIX 接口层、虚拟文件系统层和设备抽象层。
1.3 elm-FAT文件系统简介
FatFs 是一个通用的文件系统(FAT/exFAT)模块,用于在小型嵌入式系统中实现FAT文件系统。
1.4 使用流程
- 初始化 DFS 组件。
- 初始化具体类型的文件系统。
- 在存储器上创建块设备。
- 格式化块设备。
- 挂载块设备到 DFS 目录中。
- 当文件系统不再使用,可以将它卸载
1.5 注册elm-FAT文件系统
elm-FAT文件系统注册过程如下图所示:
1.6 挂载elm-FAT文件系统
代码语言:javascript复制 1void sd_mount(void *parameter)
2{
3 while (1)
4 {
5 rt_thread_mdelay(500);
6 if(rt_device_find("sd0") != RT_NULL)
7 {
8 if (dfs_mount("sd0", "/fatfs", "elm", 0, 0) == RT_EOK)
9 {
10 LOG_I("sd card mount to '/fatfs'");
11 break;
12 }
13 else
14 {
15 LOG_W("sd card mount to '/fatfs' failed!");
16 }
17 }
18 }
19}
20
21int stm32_sdcard_mount(void)
22{
23 rt_thread_t tid;
24
25 tid = rt_thread_create("sd_mount", sd_mount, RT_NULL,
26 1024, RT_THREAD_PRIORITY_MAX - 2, 20);
27 if (tid != RT_NULL)
28 {
29 rt_thread_startup(tid);
30 }
31 else
32 {
33 LOG_E("create sd_mount thread err!");
34 }
35 return RT_EOK;
36}
37INIT_APP_EXPORT(stm32_sdcard_mount);
- 在文件系统操作表中找出elm文件系统
- 检查"/fatfs"路径是否存在
- 检查elm文件系统是否已经挂载在文件系统表中
- 检查文件系统表是否有空余,如果有,把空余地址指向elm文件系统
- 注册文件系统
- 调用elm文件系统的挂载接口
1.7 测试elm-FAT文件系统
在根目录下使用ls命令,可以查看目录:
2.设计界面
使用TouchGFX 4.14.0 Designer添加设置界面。增加进度条,和两个按钮,以及固件版本和更新时间的记录(记录环境变量使用的是easyflash软件包)。我这个界面设计的比较简陋,重在实现功能,审美好的人,欢迎重新设计这个界面。
依然利用TouchGFX的MVP架构,将UI命令传递到后台。 参考前边的文章:【DIY数字仪表】使用TouchGFX的MVP架构来实现GUI和硬件的双向交互(2)
3.添加sd卡或者spi flash拷贝到SDRAM的代码
代码语言:javascript复制 1bool TouchGFXHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes)
2{
3 uint32_t dataOffset = (uint32_t)src;
4 if (dataOffset >= 0x90000000 && dataOffset < 0x92000000)
5 {
6 char *updata_pciture;
7
8 /* get the updata pciture location from Env */
9 updata_pciture = ef_get_env("updata_pciture");
10
11 if(0 == strcmp(updata_pciture, "spi_flash"))
12 {
13 const struct fal_partition *part;
14 part = fal_partition_find("tgfx");
15
16 dataOffset = dataOffset - 0x90000000;
17 // for copying data from there.
18 if (part != RT_NULL)
19 {
20 fal_partition_read(part, dataOffset, (uint8_t *)dest, numBytes);
21 }
22 return true;
23 }
24 else
25 {
26 int fd;
27 struct statfs buffer;
28 if(rt_device_find("sd0") != RT_NULL)
29 {
30 if ((dfs_statfs("/",&buffer) == RT_EOK)|(dfs_mount("sd0", "/", "elm", 0, 0) == RT_EOK))
31 {
32 fd = open("/ER_EROM1", O_RDONLY, 0);
33 if (fd < 0)
34 {
35 rt_kprintf("open file for read failedn");
36 return false;
37 }
38 dataOffset = dataOffset - 0x90000000;
39 lseek(fd, dataOffset, SEEK_SET);
40 // for copying data from there.
41 read(fd, (uint8_t *)dest, numBytes);
42 close(fd);
43 }
44 return true;
45 }
46 else
47 {
48 return false;
49 }
50 }
51 }
52 else
53 {
54 // For all other addresses, just use the default implementation.
55 // This is important, as blockCopy is also used for other things in the core framework.
56 return HAL::blockCopy(dest, src, numBytes);
57 }
58}
此代码用来根据设置的环境变量选择从sd卡还是spi flash拷贝图片。
4.添加msh命令
代码语言:javascript复制 1#ifdef RT_USING_FINSH
2#include <finsh.h>
3/* export to finsh */
4FINSH_FUNCTION_EXPORT(ReadUpdataToSpiflash, Read data To Spiflash test);
5
6#ifdef FINSH_USING_MSH
7static void cmd_updata(int argc, char *argv[])
8{
9 char* filename;
10
11 if(argc == 2)
12 {
13 filename = argv[1];
14 }
15 else
16 {
17 filename = DEFAULT_FILENAME;
18 recv_partition = DEFAULT_DOWNLOAD_PART;
19 LOG_I("Default save firmware on download partition.n");
20 }
21 ReadUpdataToSpiflash(filename);
22}
23FINSH_FUNCTION_EXPORT_ALIAS(cmd_updata, __cmd_updata, Read data To Spiflash test);
24#endif /* FINSH_USING_MSH */
25#endif /* RT_USING_FINSH */
添加msh命令,使通过msh命令也能升级固件,将SD的图片资源拷贝到spi flash的功能
updata命令默认将从sd卡中读取ER_IROM1.rbl固件,将固件下载到download分区。
通过updata /ER_EROM1命令,可以将sd中的图片资源拷贝到tgfx分区(spi flash中图片所在的位置)中
5.生成bin文件
在keil中添加以下命令,然后便会在binary目录下,生成外部flash和内部flash的bin文件:
利用rt_ota_packaging_tool工具,对内部flash烧录bin文件进行加密和压缩,然后将生成的ER_IROM1.rbl文件和ER_EROM1文件拷贝到SD卡中:
6.制作BootLoader
参考以下文章:STM32通用Bootloader——FOTA rt_fota集成了ymodem的协议,在没有app的情况下,也可以通过rt_fota的ymodem命令给固件和图片资源升级。 ymodem_ota命令,默认将固件下载到download分区:
ymodem_ota -p tgfx命令,可以将sd中的图片资源拷贝到tgfx分区中:
代码开源地址:https://gitee.com/Aladdin-Wang/hellotouchGFX