【RT-Thread】HTTP OTA固件升级
程序员文章站
2022-03-23 22:08:54
(PS:1024程序员节来写一篇硬核的博客!)这里主要讲解一下HTTP OTA固件升级实践思路及核心代码(已实践成功了),如果有疑问得欢迎评论里探讨!参考文章:STM32 通用 Bootloader1. 开发环境1.1 硬件环境MCU:STM32F103RET6AT模块:移远4GCat1无线通讯模块EC200SRS485:进行数据采集及控制FLASH:W25Q1281.2 软件环境开发工具:RT-Thread Studio嵌入式实时操作操作系统:RT-Thread...
(PS:1024程序员节来写一篇硬核的博客!)
这里主要讲解一下HTTP OTA固件升级实践思路及核心代码(已实践),如果有疑问得欢迎评论里探讨!
参考文章:STM32 通用 Bootloader
1. 开发环境
1.1 硬件环境
MCU:STM32F103RET6
AT模块:移远4GCat1无线通讯模块EC200S
RS485:进行数据采集及控制
FLASH:W25Q128
1.2 软件环境
开发工具:RT-Thread Studio
嵌入式实时操作操作系统:RT-Thread
设备驱动、组件、软件包:
2、安装开发步骤要先配置 FAL 分区,然后解决网络下载升级的问题,最后根据MQTT订阅主题信息OTA升级固件
2.1 配置 FAL 分区
2.2.1 fal_cfg.h文件
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#include <rtconfig.h>
#include <board.h>
#define NOR_FLASH_DEV_NAME "norflash0"
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32_onchip_flash;
extern struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&stm32_onchip_flash, \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "bl", "onchip_flash", 0, 64*1024, 0}, \
{FAL_PART_MAGIC_WORD, "app", "onchip_flash", 64*1024, 704*1024, 0}, \
{FAL_PART_MAGIC_WORD, "easyflash", NOR_FLASH_DEV_NAME, 0, 2*1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "ota", NOR_FLASH_DEV_NAME, 2*1024*1024, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "download", NOR_FLASH_DEV_NAME, 3*1024*1024, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "factory", NOR_FLASH_DEV_NAME, 4*1024*1024, 1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
2.1.2 SPI设备驱动初始化、SPI总线挂载初始化、虚拟文件系统初始化
#include <rtthread.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include "drv_spi.h"
#include <fal.h>
#include "fal_init_port.h"
#ifdef RT_USING_SPI
void HAL_SPI_MspInit(SPI_HandleTypeDef *spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if (spiHandle->Instance == SPI1)
{
/* SPI1 clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
else if (spiHandle->Instance == SPI2)
{
/* SPI2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
else if (spiHandle->Instance == SPI3)
{
/* SPI2 clock enable */
__HAL_RCC_SPI3_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI2 GPIO Configuration
PB3 ------> SPI2_SCK
PB4 ------> SPI2_MISO
PB5 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
}
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *spiHandle)
{
if (spiHandle->Instance == SPI1)
{
/* Peripheral clock disable */
__HAL_RCC_SPI1_CLK_DISABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
}
else if (spiHandle->Instance == SPI2)
{
/* Peripheral clock disable */
__HAL_RCC_SPI2_CLK_DISABLE();
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
}
else if (spiHandle->Instance == SPI3)
{
/* Peripheral clock disable */
__HAL_RCC_SPI3_CLK_DISABLE();
/**SPI2 GPIO Configuration
PB3 ------> SPI2_SCK
PB4 ------> SPI2_MISO
PB5 ------> SPI2_MOSI
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
}
}
#endif
#if defined(RT_USING_SFUD)
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOF_CLK_ENABLE();
rt_hw_spi_device_attach("spi2", "spi20", GPIOB, GPIO_PIN_12);
if (RT_NULL == rt_sfud_flash_probe("norflash0", "spi20"))
{
rt_kprintf("rt_sfud_flash_probe norflash0 spi20 -RT_ERROR\n");
return -RT_ERROR;
}
rt_kprintf("rt_sfud_flash_probe norflash0 spi20 success !!!\n");
return RT_EOK;
}
INIT_PREV_EXPORT(rt_hw_spi_flash_init);
#endif
int fs_init(void)
{
/* partition initialized */
fal_init();
return 0;
}
INIT_DEVICE_EXPORT(fs_init);
2.2 网络驱动及下载功能
2.2.1 EC200S注册
#include <rtthread.h>
#ifdef AT_DEVICE_USING_EC200X
#include <at_device_ec200x.h>
#include <board.h>
#include <rtdevice.h>
#define LOG_TAG "at.sample.ec200x"
#include <at_log.h>
#define EC200X_PORT_DEIVCE_NAME "ec200x"
#define EC200X_PORT_POWER_PIN -1
#define EC200X_PORT_STATUS_PIN -1
#define EC200X_PORT_WAKEUP_PIN -1
#define EC200X_PORT_CLIENT_NAME "uart2"
#define EEC200X_PORT_RECV_BUFF_LEN 2048
static struct at_device_ec200x _dev =
{
EC200X_PORT_DEIVCE_NAME,
EC200X_PORT_CLIENT_NAME,
EC200X_PORT_POWER_PIN,
EC200X_PORT_STATUS_PIN,
EC200X_PORT_WAKEUP_PIN,
EEC200X_PORT_RECV_BUFF_LEN,
};
static int ec200x_device_register(void)
{
struct at_device_ec200x *ec200x = &_dev;
return at_device_register(&(ec200x->device),
ec200x->device_name,
ec200x->client_name,
AT_DEVICE_CLASS_EC200X,
(void *) ec200x);
}
INIT_COMPONENT_EXPORT(ec200x_device_register);
2.2.2 webclient软件包
2.3 阿里云MQTT主题OTA升级固件
2.3.1 阿里云MQTT软件包
2.3.2 OTA软件包
3 OTA升级固件思路
针对STM32F103RET6的RAM只有64KB,ROM只有512KB,所以如下流程处理:
3.1 通过阿里云物联网平台下发OTA升级的主题JSON格式消息,物联网设备接收后通过cJSON软件包进行解析提取OTA升级有效数据信息,将OTA升级有效数据及升级标志存储到FLASH分区中,重启STM32设备
3.2 上电启动检测是否有升级标志,如果有升级标志,那么只创建OTA固件下载线程,则通过网络HTTP请求下载OTA升级固件到FLASH的download分区中,清除升级标志,下载完成后重新STM32设备
3.3 重启后就进入STM32 BootLoader自动固件升级,解密解压搬运到FLASH的app分区,完成后自动重启
3.4 上电启动检测是否有升级标志,如果没有则进行正常运行升级后固件程序!
本文地址:https://blog.csdn.net/hanhui22/article/details/109265496