【OTA笔记】STM32+ESP8266 OTA开发步骤(更新中)

个人学习过程记录,问题较多,请勿参考

硬件结构

STM32F103VET6, 100pin, 512k Flash, 64k RAM。
ESP8266 板载天线,透传模式。

项目设计

连接腾讯IOT云控制LED灯亮灭以及亮度等,并通过云实现OTA版本管理与升级。
ESP8266 通过连接WIFI连接IOT云。

功能设计

初始化状态设备是AP模式(服务器),通过上位机软件连接WIFI后,传输需要设备连接的互联网WIFI(包括WIFI名称,密码),传输完成后设备保存信息到Flash,设备重启,重启后根据Flash状态确定是否是初始状还是配置完的状态,设备进入Station模式(设备),根据保存的信息连接WIFI后再配置TCP等连接。

软件设计

设计思路

软件开发包括用户bootloader,版本记录,app主体,备份OTA。

Flash划分:
bootloader 0x8000000 大小0x4000 16K
版本记录 0x8004000 大小0x800 2K
app 0x8004800 大小0x30000 120K
ota 0x8034800 大小0x1D800 118K

bootloader:存放OTA版本检查,代码复制,跳转app等功能;
版本记录:开头4个字节存放OTA升级标志,通过检查此标志确定是否需要升级app;
app:产品功能实现;
ota:新版本app代码存储空间;

通讯协议

测试过程:
升级命令 “update”
清除OTA FLASH
接收WIFI传过来的bin程序

bootloader代码实现

#include "stm32f1x_hal.h"
#include "string.h"
#include "stdbool.h"


typedef void (*function_t)(void);

#define FLASH_UPDATE_FLAG_ADDRESS		0x08004000
#define FLASH_APP_ADDRESS				0x08004800
#define FLASH_OTA_ADDRESS				0x08034800
/*
@ 跳转APP函数
*/
void Jump_To_App(void)
{
	uint32_t ulAppAddr;
	function_t jump_app;
	if ((*(uint32_t*)FLASH_APP_ADDRESS & 0x2ffe0000) == 0x20000000)
	{
		ulAppAddr = *(uint32_t*)(FLASH_APP_ADDRESS + 4);
		jump_app = (*function_t)ulAppAddr;
		__set_MSP(*(uint32_t*)FLASH_APP_ADDRESS);
		jump_app();
	}
}
//读数据
uint32_t FlashRead(uint32_t StartAddress)
{
    return *(uint32_t *)StartAddress;
}
//更新标志位
bool check_update_flag(void)
{
    bool status = false;
    if (FlashRead(FLASH_UPDATE_FLAG_ADDRESS) == 0x55555555)
    {
        status = true;
    }
    return status; 
}

//将APP2代码复制到APP1中
void updateInterface_CopyCode_FromApp2ToApp1(void)
{
    uint32_t i = 0;
	uint32_t ulErrorAddr = 0;
	FLASH_EraseInitTypeDef sEraseInit_t;
	
	sEraseInit_t.Banks = FLASH_BANK_1;
	sEraseInit_t.NbPages = 1;
	sEraseInit_t.PageAddress = FLASH_APP_ADDRESS;
	sEraseInit_t.TypeErase = FLASH_TYPEERASE_PAGES;
	
	HAL_FLASH_Unlock(); // 先解锁

    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | 
                          FLASH_FLAG_PGERR | FLASH_FLAG_OPTVERR); // 清除一些错误标志
	
    for(i = 0; i < 96; i++)
    {
		sEraseInit_t.PageAddress = FLASH_APP_ADDRESS + (0x800 * i);		
        HAL_FLASHEx_Erase(&sEraseInit_t, &ulErrorAddr); // 擦除指定的闪存地址
        //FLASH_WaitForLastOperation(1000);
    }        
	
    for (i = 0; i < FLASH_OTA_SPACE; i += 4)
    {
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_APP_ADDRESS + i, *(uint32_t *)(FLASH_OTA_ADDRESS + i)); // 4个字节写入
    }
	
	HAL_FLASH_Lock(); // 最后上锁
	
}

void main(void)
{
	HAL_Init();
	
	if (check_update_flag() == true) // 检查有没有更新标志
	{
		if ((((*(__IO uint32_t*)(FLASH_OTA_ADDRESS + 4))&0xFF000000) == 0x08000000) 
			&& (((*(__IO uint32_t*)(FLASH_OTA_ADDRESS))&0xFF000000) == 0x20000000)) // OTA 区有带升级的包
		{
			// 迁移更新包到FLASH_APP_ADDRESS
			updateInterface_CopyCode_FromApp2ToApp1();
			
		}
	}
	if (((*(__IO uint32_t*)(FLASH_APP_ADDRESS + 4))&0xFF000000) == 0x08000000)
	{
		Jump_To_App();
	}
	while (1)
	{
		/* 跳转不成功会进入这里 */
		...
	}
}

APP代码实现

#include "stm32f1x_hal.h"
#include "string.h"

#define FLASH_UPDATE_FLAG_ADDRESS		0x08004000
#define FLASH_APP_ADDRESS				0x08004800
#define FLASH_OTA_ADDRESS				0x08034800

typedef void (*pFunction)(void);

/*
@ 跳转到bootloader
@ app下载好新固件后可运行此函数跳转到bootloader
*/
void Jump_To_Bootloader(void)
{
	uint32_t ulJaddr = 0;
	pFunction jump2boot;
	
	__disable_irq(); // 关闭中断
	
	if (((*(uint32_t*)0x08000000) & 0x2ffe0000) == 0x20000000)
	{
		ulJaddr = *(uint32_t*)(0x08000000 + 4);
		jump2boot = (pFunction)ulJaddr;
		__set_MSP(*(uint32_t*)0x08000000);
		jump2boot();
	}
}

void main(void)
{
	SCB->VTOR = FLASH_APP_ADDRESS + 4; // 设置中断向量表
	
	HAL_Init();
	SystemClock_Config();
	/* 外设初始化 */
	...
	while (1)
	{
		/* 产品功能实现 */
		...
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值