[OTA-day6A区更新数据]

要更行数据我们首先得知道:

1.谁让OTA_FLAG标志位置位允许OTA升级?什么时候置位?怎么复位?

flash中A区OTA接收数据完成后置位OTA_FLAG;接收完成后复位不仅仅是在RAM中OTA_FLAG=0;还要将OTA_FLAG写入24C02中保存状态

2.最新版的程序下载到哪?

通过分片下载的方式下载到W25Q64中;什么叫分片下载?就是比如一个64K的文件,每次下载256字节,分数次下载 

3.OTA时,最新版本的程序文件如何下载?下载多少?

服务器告知下载并将OTA_FLAG置位;下载的大小也是通过服务器告知,下载的长度这个变量也需要保存到24C02中 

4.发生OTA事件时,B区如何更新A区?

根据保存在24C02中的下载长度,拿数据(一次拿1024字节),写到A区 

main.h

#ifndef MAIN_H
#define MAIN_H

#include "stdint.h"

#define  GD32_FLASH_SADDR   0x08000000                                             //FLASH起始地址
#define  GD32_PAGE_SIZE     1024                                                   //FLASH扇区大小
#define  GD32_PAGE_NUM      64                                                     //FLASH总扇区个数
#define  GD32_B_PAGE_NUM    20                                                     //B区扇区个数
#define  GD32_A_PAGE_NUM    GD32_PAGE_NUM - GD32_B_PAGE_NUM                        //A区扇区个数
#define  GD32_A_START_PAGE  GD32_B_PAGE_NUM                                        //A区起始扇区编号
#define  GD32_A_SADDR       GD32_FLASH_SADDR + GD32_A_START_PAGE * GD32_PAGE_SIZE  //A区起始地址

#define  UPDATA_A_FLAG      0x00000001        //状态标志位,置位表明需要更新A了

#define OTA_SET_FLAG        0xAABB1122        //OTA_flag对勾状态对应的数值,如果OTA_flag等于该值,说明需要OTA更新A区
typedef struct{          
	uint32_t OTA_flag;                        //标志性的变量,等于OTA_SET_FLAG定义的值时,表明需要OTA更新A区
	uint32_t Firelen[11];                     //W25Q64中不同块中程序固件的长度,0号成员固定对应W25Q64中编码0的块,用于OTA
}OTA_InfoCB;                                  //OTA相关的信息结构体,需要保存到24C02
#define OTA_INFOCB_SIZE sizeof(OTA_InfoCB)    //OTA相关的信息结构体占用的字节长度
	
typedef struct{
	uint8_t  Updatabuff[GD32_PAGE_SIZE];      //更新A区时,用于保存从W25Q64中读取的数据
	uint32_t W25Q64_BlockNB;                  //用于记录从哪个W25Q64的块中读取数据
}UpDataA_CB;                                  //更新A区用的结构体

extern OTA_InfoCB OTA_Info;   //外部变量声明
extern UpDataA_CB UpDataA;    //外部变量声明
extern uint32_t BootStaFlag;  //外部变量声明

#endif



 Boot.c

#include "gd32f10x.h"
#include "boot.h"
#include "main.h"
#include "usart.h"
#include "delay.h"
#include "fmc.h"
#include "iic.h"
#include "m24c02.h"

load_a load_A;        //函数指针load_A

/*-------------------------------------------------*/
/*函数名:BootLoader分支判断                       */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void BootLoader_Brance(void)
{
	if(OTA_Info.OTA_flag == OTA_SET_FLAG){       //判断OTA_flag是不是OTA_SET_FLAG定义的值,是的话进入if
		u0_printf("OTA更新\r\n");                //串口0输出信息
		BootStaFlag |= UPDATA_A_FLAG;            //置位标志位,表明需要更新A区
		UpDataA.W25Q64_BlockNB = 0;              //W25Q64_BlockNB等于0,表明是OTA要更新A区		
	}else{                                       //判断OTA_flag是不是OTA_SET_FLAG定义的值,不是的话进入else
		u0_printf("跳转A分区\r\n");              //串口0输出信息
		LOAD_A(GD32_A_SADDR);                    //跳转到A区
	}
}
/*-------------------------------------------------*/
/*函数名:设置SP                                   */
/*参  数:addr:栈顶指针初始值                     */
/*返回值:无                                       */
/*-------------------------------------------------*/
__asm void MSR_SP(uint32_t addr)
{
	MSR MSP, r0        //addr的值加载到了r0通用寄存器,然后通过MSR指令,将通用寄存器r0的值写入到MSP主堆栈指针
	BX r14             //返回调用MSR_SP函数的主函数
}
/*-------------------------------------------------*/
/*函数名:跳转到A区                                */
/*参  数:addr:A区的起始地址                      */
/*返回值:无                                       */
/*-------------------------------------------------*/
void LOAD_A(uint32_t addr)
{
	if((*(uint32_t *)addr>=0x20000000)&&(*(uint32_t *)addr<=0x20004FFF)){     //判断sp栈顶指针的范围是否合法,在对应型号的RAM控件范围内
		MSR_SP(*(uint32_t *)addr);                                            //设置SP
		load_A = (load_a)*(uint32_t *)(addr+4);                               //将函数指针load_A指向A区的复位向量
		BootLoader_Clear();                                                   //清除B区使用的外设
		load_A();                                                             //调用函数指针load_A,改变PC指针,从而转向A区的复位向量位置,完成跳转
	}
}
/*-------------------------------------------------*/
/*函数名:清除B区使用的外设                        */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void BootLoader_Clear(void)
{
	usart_deinit(USART0);   //复位串口0
	gpio_deinit(GPIOA);     //复位GPIOA
	gpio_deinit(GPIOB);     //复位GPIOB
}

main.c

#include "gd32f10x.h"
#include "main.h"
#include "usart.h"
#include "delay.h"
#include "fmc.h"
#include "iic.h"
#include "m24c02.h"
#include "boot.h"
#include "w25q64.h"

OTA_InfoCB OTA_Info;          //保存在24C02内的OTA信息相关的结构体
UpDataA_CB UpDataA;           //A区更新用到的结构体
uint32_t BootStaFlag;         //记录全局状态标志位

OTA_Info.OTA_flag = 0xAABB1122;//允许OTA升级  
int main(void)
{
	uint8_t i;               //用于for循环
	
	Delay_Init();            //延时初始化
	Usart0_Init(921600);     //串口0初始化
    IIC_Init();              //IIC初始化
	M24C02_ReadOTAInfo();    //从24C02读取数据到OTA_Info结构体
	BootLoader_Brance();     //分支判断
	
	/*--------------------------------------------------*/
	/*--------------------主循环------------------------*/
	/*--------------------------------------------------*/
	while(1){                 
		/*--------------------------------------------------*/
		/*        UPDATA_A_FLAG置位,表明需要更新A区        */
		/*--------------------------------------------------*/
		if(BootStaFlag&UPDATA_A_FLAG){
			u0_printf("长度%d字节\r\n",OTA_Info.Firelen[UpDataA.W25Q64_BlockNB]);          //串口0输出信息
			if(OTA_Info.Firelen[UpDataA.W25Q64_BlockNB] % 4 == 0){                         //判断长度是否是4的整数倍,是的话进入if
				GD32_EraseFlash(GD32_A_START_PAGE,GD32_A_PAGE_NUM);                        //擦除A区FLASH
				for(i=0;i<OTA_Info.Firelen[UpDataA.W25Q64_BlockNB]/GD32_PAGE_SIZE;i++){    //每次读写一个扇区数据,使用for循环,写入整数个扇区
					W25Q64_Read(UpDataA.Updatabuff,i*1024 + UpDataA.W25Q64_BlockNB*64*1024 ,GD32_PAGE_SIZE);               //先从W25Q64读取一个单片机扇区的数据
					GD32_WriteFlash(GD32_FLASH_SADDR + i*GD32_PAGE_SIZE,(uint32_t *)UpDataA.Updatabuff,GD32_PAGE_SIZE);    //写入到单片机A区相应的扇区
				}
				if(OTA_Info.Firelen[UpDataA.W25Q64_BlockNB] % 1024 != 0){                  //判断是否还有不足一个完整扇区的数据,有的话进入if					
					W25Q64_Read(UpDataA.Updatabuff,i*1024 + UpDataA.W25Q64_BlockNB*64*1024 ,OTA_Info.Firelen[UpDataA.W25Q64_BlockNB] % 1024);             //从W25Q64读取不足一个完整扇区的数据
					GD32_WriteFlash(GD32_FLASH_SADDR + i*GD32_PAGE_SIZE,(uint32_t *)UpDataA.Updatabuff,OTA_Info.Firelen[UpDataA.W25Q64_BlockNB] % 1024);  //然后写入单片机A区相应的扇区
				}
				if(UpDataA.W25Q64_BlockNB == 0){   //如果W25Q64_BlockNB是0,表示是OTA更新A区,进入if
					OTA_Info.OTA_flag = 0;         //设置OTA_flag,只要不是OTA_SET_FLAG定义的值即可
					M24C02_WriteOTAInfo();         //写入24C02内保存
				}
				NVIC_SystemReset();                //重启
			}else{                                 //判断长度是否是4的整数倍,不是的话进入else
				u0_printf("长度错误\r\n");         //串口0输出信息
				BootStaFlag &=~ UPDATA_A_FLAG;     //清除UPDATA_A_FLAG标志位
			}
		}
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值