个人学习过程记录,问题较多,请勿参考
硬件结构
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)
{
/* 产品功能实现 */
...
}
}