rt thread studio使用QBOOT和片外flash实现OTA升级
我们这里要使用单片机外部flash作为OTA的下载分区,外部flash硬件连接关系
PB3-->SPI3_CLK
PB4-->SPI3_MISO
PB5-->SPI3_MOSI
PE1-->SPI3_CSS
第一步
使用rt thread studio新建一个bootloader的工程,我这里使用的是stm32f407vgt6的芯片
使能SPI驱动和SFUD驱动
打开board.h文件,取消#define BSP_USING_SPI3的注释
然后在stm32f4xx_hal_conf.h文件中打开对 SPI 的支持,也就是取消掉 HAL_SPI_MODULE_ENABLED 这个宏定义的注释
将CubeMx 生成的 void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)函数复制到board.c文件中
从上图可以看出FAL抽象层位于SFUD框架的上层,可以将多个Flash硬件(包括片内Flash和片外Flash)统一进行管理,并向上层比如DFS文件系统层提供对底层多个Flash硬件的统一访问接口,方便上层应用对底层硬件的访问操作。
所以我们先要实现SFUD的flash驱动
与SFUD相关的文件在rt-thread下components下drivers下spi下sfud里
我们在applications新建w25qxx.c文件
添加以下代码
#include <rtthread.h>
#include "drv_spi.h"
#include "spi_flash_sfud.h"
#define SPI_BUS_NAME "spi3"
#define W25Q_SPI_DEVICE_NAME "spi30"
#define W25Q_FLASH_NAME "W25Q128"
rt_uint8_t wData[4096] = {"SPI bus write data to W25Q flash."};
rt_uint8_t rData[4096];
static int rt_hw_spi_flash_init()
{
rt_err_t ree = RT_EOK;
ree = rt_hw_spi_device_attach(SPI_BUS_NAME, W25Q_SPI_DEVICE_NAME, GPIOE, GPIO_PIN_1);
/* 使用 SFUD 探测 spi10 从设备,并将 spi10 连接的 flash 初始化为块设备,名称 W25Q128 */
if (RT_NULL == rt_sfud_flash_probe(W25Q_FLASH_NAME, W25Q_SPI_DEVICE_NAME))
{
return -RT_ERROR;
}
return ree;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
static void sfud_w25q_sample(void)
{
rt_spi_flash_device_t flash_dev;
sfud_flash_t sfud_dev;
struct rt_device_blk_geometry geometry;
// 1- use sfud api
rt_kprintf("\n 1 - Use SFUD API \n");
sfud_dev = rt_sfud_flash_find_by_dev_name(W25Q_FLASH_NAME);
if(sfud_dev == RT_NULL){
rt_kprintf("sfud can't find %s device.\n", W25Q_FLASH_NAME);
}else{
rt_kprintf("sfud device name: %s, sector_count: %d, bytes_per_sector: %d, block_size: %d.\n",
sfud_dev->name, sfud_dev->chip.capacity / sfud_dev->chip.erase_gran,
sfud_dev->chip.erase_gran, sfud_dev->chip.erase_gran);
if(sfud_erase_write(sfud_dev, 0x002000, sizeof(wData), wData) == SFUD_SUCCESS)
rt_kprintf("sfud api write data to w25q128(address:0x2000) success.\n");
if(sfud_read(sfud_dev, 0x002000, sizeof(rData), rData) == SFUD_SUCCESS)
rt_kprintf("sfud api read data from w25q128(address:0x2000) is:%s\n", rData);
}
// 2- use rt_device api
rt_kprintf("\n 2 - Use rt_device API \n");
flash_dev = (rt_spi_flash_device_t)rt_device_find(W25Q_FLASH_NAME);
if(flash_dev == RT_NULL){
rt_kprintf("rt_device api can't find %s device.\n", W25Q_FLASH_NAME);
}else{
rt_device_open(&flash_dev->flash_device, RT_DEVICE_OFLAG_OPEN);
if(rt_device_control(&flash_dev->flash_device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry) == RT_EOK)
rt_kprintf("spi flash device name: %s, sector_count: %d, bytes_per_sector: %d, block_size: %d.\n",
flash_dev->flash_device.parent.name, geometry.sector_count, geometry.bytes_per_sector, geometry.block_size);
if(rt_device_write(&flash_dev->flash_device, 0x03, wData, 1) > 0)
rt_kprintf("rt_device api write data to w25q128(address:0x3000) success.\n");
if(rt_device_read(&flash_dev->flash_device, 0x03, rData, 1) > 0)
rt_kprintf("rt_device api read data from w25q128(address:0x3000) is:%s\n", rData);
rt_device_close(&flash_dev->flash_device);
}
}
MSH_CMD_EXPORT(sfud_w25q_sample, sfud w25q128 sample);
然后编译下载
可以看到W25Q128的flash芯片初始化成功了,测试一下sfud_w25q_sample命令
可以看到使用SFUD的API和rt_device API读写flash都是可以的,那么SFUD设备驱动成功了。
按照这个图,flash硬件层移植完毕
第二步,添加fal软件包
右键详细配置
编译一下,发现找不到fal_cfg.h文件
在工程目录下的porting文件夹里是有fal_cfg.h文件的,只是没有添加到编译目录下
我们把这个文件放到inc文件夹里
再编译一下,还有个错误,找不到stm32f2_onchip_flash
通过fal_cfg.h可以看到里面使用了芯片内部flash,所以在board.h里需要打开BSP_USING_ON_CHIP_FLASH
编译后提示STM32_FLASH_START_ADRESS_16K这些没有定义
然后在fal_cfg.h文件里添加以下定义
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#include <rtconfig.h>
#include <board.h>
#include <rtconfig.h>
#define FLASH_SIZE_GRANULARITY_16K (4 * 16 * 1024)
#define FLASH_SIZE_GRANULARITY_64K (64 * 1024)
#define FLASH_SIZE_GRANULARITY_128K (7 * 128 * 1024)
#define STM32_FLASH_START_ADRESS_16K STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_64K (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
#define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32_onchip_flash_16k;
extern const struct fal_flash_dev stm32_onchip_flash_64k;
extern const struct fal_flash_dev stm32_onchip_flash_128k;
/* ===================== Flash device Configuration ========================= */
extern struct fal_flash_dev nor_flash0;
#define FAL_FLASH_DEV_TABLE \
{ \
&stm32_onchip_flash_16k, \
&stm32_onchip_flash_64k, \
&stm32_onchip_flash_128k, \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "bl", "onchip_flash_128k", 0, 64*1024, 0}, \
{FAL_PART_MAGIC_WORD, "app", "onchip_flash_128k", 64*1024, 704*1024, 0}, \
{FAL_PART_MAGIC_WORD, "download", FAL_USING_NOR_FLASH_DEV_NAME, 0, 1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
注意:::::
这里的onchip_flash_128k要和drv_flash_f4.c里的名字一样
有的文档里写的名字是stm32_onchip如果你照搬过来,那就错了
因为stm32f4系列的内部flash分布和其他型号的不一样,如图
所以在drv_flash_f4.c会有onchip_flash_16k、onchip_flash_64k、onchip_flash_128k这三种定义
这里是针对stm32f4系列的,其他型号可能不太一样。
再编译一下,没有报错了,然后在main.c里添加#include "fal.h"和fal_init();
再把w25qxx.c文件里的W25Q_FLASH_NAME改成FAL_USING_NOR_FLASH_DEV_NAME
编译、下载
各个分区都初始化成功
测试fal命令试一下,探测和读命令
读、写、擦除等
接下来向工程中添加qboot软件包,添加完qboot后会出现一些其他软件包,应该是qboot依赖这些软件包
配置QBoot组件,在RT-Thread Settings
界面,双点qboot组件,进入选项配置界面
如果开启using shell command of qboot的话程序会在bootloader启动后等待一段时间,这个在调试阶段有用,正式应用场景下这个等待时间不可接受。建议关闭。
这里的一些配置根据自己需要修改吧,这里使用了syswatch所以还要添加syswatch相关的驱动
在软件包里搜索一些syswatch看下用法
打开syswatch_config.h去掉这两个的注释
syswatch使用了IWDG看门狗,打开stm32f4xx_hal_conf.h取消HAL_IWDG_MODULE_ENABLED的注释
编译一下没有错误了,看了下ROM占用112.76K了,有点大,后面根据需要再裁减吧。
下载,看到我们的bl分区设置的是64K,显然不够用了,打开fal_cfg.h文件把bl分区改为128k
总ROM是1024K,bl分区占了128k,剩余896K全部用作app分区。
再编译下载,可以看到打印出来的分区和我们设置的一致
我们这里只是只做了bootloader程序,还没加应用程序。
接下来开始做app的程序。
我们随便找一个程序,把下载地址改为0x08020000,下载到单片机试一下。
更改下载地址是在linkscripts下的link.lds里修改
下载完成后看到是可以跳转到应用程序的,但是系统在不停的重启,仔细想了一下,app程序里必须要重新设置中断向量表啊,把这个给忘了
在main.c文件里重新设置中断向量表
然后编译、下载。app程序启动成功,但运行了几秒钟又重启了,这个类似看门狗复位,仔细想了一下,在bootloader里加了syswatch,那么系统的看门狗肯定是启动了,那么就要在app程序里也加上syswatch。
添加方法和bootloader里一样,这里不再赘述了。
添加完syswatch后下载测试,发现app程序启动正常,没有再重启了。
app程序能正常启动后我们就要在app添加ota下载功能了,我们要把程序下载到外部flash就要有相关的fal驱动。
然后在应用程序里依照上面的方法添加SPI驱动,SFUD驱动,FAL驱动,并测试一下fal读写、擦除命令等
完成以后再软件包里搜索ota_downloader
双击后配置一下ota的默认下载地址,就是电脑的IP地址
注意:我的这个工程里是有网络通信的程序,如果没有则无法实现http的ota
编译、下载、我们在开机的时候打印一下当前版本号
系统启动成功后我们改一下这个版本号,如果ota升级成功了这个版本号就会变成新的版本号了
改完以后再编译一下,这次就不要用下载器下载程序了。
我们找到当前项目所在目录的Debug文件夹,查看是否有rtthread.bin文件,以及生成时间,是否是我们当前生成的。
再找到rt_ota_packaging_tool.exe这个工具,目录workspace\gaoliu0201\packages\ota_downloader-latest\tools\ota_packager
将刚才生成的bin文件压缩成可以ota升级的rbl文件
压缩算法要和bootloader里的压缩算法一致,我们这里没有加密
注意固件版本要和当前芯片里的固件版本不一样,如果一样的话就会跳过当前版本的升级。
打包后的程序在Debug文件夹下
然后打开mywebserver.exe,将rbl文件所在的目录添加到服务目录,IP地址为电脑的IP,点击启动,可以勾上访问日志和错误日志
然后将开发板插上网线,获取到IP后发送http_ota命令
开发板将从192.168.1.81处下载rtthread.rbl文件
mywebserver.exe里也可以看到访问记录,状态码200表示下载成功。
开发板开始下载升级程序
虽然ota程序下载成功了,但程序跳转启动的时候在擦除内部flash的时候出错了,擦除地址越界
stm32f407vgt6的flash是1024K,地址从0x08000000到0x080fffff
但擦除的时候地址到0x08120000肯定就出错了。
检查了很久也没找到哪里有问题,但可以肯定问题出在bootloader程序里。
试了下在http://iot.rt-thread.com网站上在线生成的BootLoader下载到单片机启动后打印出来的分区是这样的。
只有两个分区,且app分区的地址偏移是0x00000000,大小是0x000e0000
猜想应该是这里的问题,也是打开bootloader程序的fal_cfg.h,把里面的bl分区删掉。并将app分区的偏移地址改为0
然后用st-link或者j-link把单片机的flash全部擦除,重新编译下载bootloader
bootloader分区也改成两个了,和咱们预想的一样。
然后就看到开始从外部flash里往内部flash里写程序了
我们之前使用http_ota命令下载的固件是存放在外部flash里的,我们只是清空了单片机内部flash,所以开始向app空间拷贝程序了,新的程序也正常启动。我们再更改一下固件版本使用http_ota再试一遍。
更改系统版本为"V1.1.3"
编译、重新用bin文件生成rbl文件,然后发送http_ota命令
文件下载,更新、启动一气呵成,成功升级到V1.1.3版本。
整个过程还是遇到很多问题的,陆陆续续搞了好几天了,记录一下,以备后面查阅。
rt thread studio使用QBOOT和片外flash实现OTA升级相关推荐
- RT Thread利用STM32CUBEMX和RT Thread studio来创建模板工程
(1)RT Thread利用STM32CUBEMX来创建模板工程 1.参考文档: 基于 CubeMX 移植 RT-Thread Nano:RT-Thread 文档中心 注意:串口2必须使能异步模式(启 ...
- RT Thread Studio 配置IIC并读取AS5600角度
RT Thread Studio 配置IIC并读取AS5600角度 一.RT Thread Studio 配置IIC 1.在RT Thread Seting 中开启IIC功能 并保存 一定要保存才能更 ...
- xpt 2046的触摸屏 rt thread设备驱动框架
1 基于rtt 开发触摸屏驱动 准备使用rtt 框架 , 驱动xpt 2046的触摸屏, 翻阅大量资料发现, 大部分文章强调的是时序图, 而且很多代码要么直接操作寄存器, 要么是io 口模拟, 只能用 ...
- stm32f407单片机rt thread 片外spi flash OTA升级配置示例
参考地址https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/ 第一步,生成Boot ...
- 关于RT thread系统节拍时钟的配置
关于RT thread系统节拍时钟的配置 -----本文基于rt-thread-3.1.3版本编写 首先,使用RTthread OS时,要配置(或者明白)它的系统节拍 ...
- rt thread 使用FAL遇到fal_init() undefined reference
rt thread FAL 0.5版,之前有没有不知道,遇到一个坑. 在main.cpp里面已经 #include <fal.h> fal_init() 编译报错,说 fal_init() ...
- RT Thread Free Modbus移植问题整理
RT Thread Free Modbus移植问题整理 问题描述: 在读写寄存器中,写数据正常,只能读1个寄存器的值,多个值会异常. 在移植过程中发现串口(或RS485)数据接收长度异常. 一.环境描 ...
- Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32
1.前言 [2014年4月重写该博文] 经过若干时间的努力终于搞定了STM32+LwIP和yeelink平台的数据互通,在学习的过程中大部分时间花在以太网协议栈学习上,但是在RT Th ...
- RT Thread根据开发板制作BSP方法
之前一直不懂怎么使用RT Thread的软件包,感谢网上的大神,看了你们的博客后大概了解一些,在此做下记录.用RT Thread软件包需要RT Thread的系统,但是RT Thread和RT Thr ...
最新文章
- Linxu终端gcc与gcc -c的区别
- 朴素贝叶斯分类器(Navie Bayesian Classifier)中的几个要点(一)
- Python练习题:批量删除多个文件夹内的相同文件
- ASP.NET MVC 学习之路-4
- 单碟1.75T 西数14TB充氦硬盘今年上
- Redis设计与实现笔记
- (1) 漂亮的日期控件
- oracle开窗函数是什么,ORACLE数据库(六)-----开窗函数
- 【渝粤教育】电大中专药事管理与法规 (2)作业 题库
- matlab评估边缘检测性能,【模糊推理】模糊逻辑图像边缘检测,原理+matlab代码~...
- 【转】9、XAML名称空间详解
- 深度优先,广度优先,拓扑排序(实战题解)
- 来自百度的71款开源项目
- 计算机组组内培训记录,计算机教研组活动记录
- 原生JS实现的跳一跳小游戏完整实例
- 华为手机更新EIMU10之后google play 商店消失
- 极致体验,解密微信背后的音视频通话技术
- 影视后期制作学习(AE)(父子级链接-表达式)
- 手机里竟然有这么多传感器!终于都搞懂了
- 超详细的Android so库的逆向调试