Add version rollback function for OTA

This commit is contained in:
huang
2023-05-04 10:16:09 +08:00
committed by wgzAIIT
parent 84f78b6435
commit 0ecb29c887
5 changed files with 243 additions and 187 deletions
@@ -459,6 +459,10 @@ void InitBoardHardware()
#ifdef BSP_USING_OTA #ifdef BSP_USING_OTA
FLASH_Init(); FLASH_Init();
//跳转成功将对应跳转失败标志清零 //跳转成功将对应跳转失败标志清零
ota_info_t ota_info;
memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
ota_info.lastjumpflag=0x00000000;
UpdateOTAFlag(&ota_info);
FLASH_DeInit(); FLASH_DeInit();
#endif #endif
} }
@@ -58,11 +58,11 @@ static const lookuptable_t FlashLookupTable={
/******************************************************************************* /*******************************************************************************
* 函 数 名: Flexspi_Nor_Wait_Busy * 函 数 名: Flexspi_Nor_Wait_Busy
* 功能描述: 等待FlexSPI NOR Flash忙碌状态结束 * 功能描述: 等待FlexSPI NOR Flash忙碌状态结束
* 形 参: instance:FlexSPI实例号 * 形 参: instance:FlexSPI实例号
baseAddr:开始读取的Flash地址(32bit) baseAddr:开始读取的Flash地址(32bit)
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
static status_t Flexspi_Nor_Wait_Busy(uint32_t instance, uint32_t baseAddr) static status_t Flexspi_Nor_Wait_Busy(uint32_t instance, uint32_t baseAddr)
{ {
@@ -101,11 +101,11 @@ static status_t Flexspi_Nor_Wait_Busy(uint32_t instance, uint32_t baseAddr)
/******************************************************************************* /*******************************************************************************
* 函 数 名: Flexspi_Nor_Write_Enable * 函 数 名: Flexspi_Nor_Write_Enable
* 功能描述: 使能 FlexSPI NOR Flash的写入操作 * 功能描述: 使能 FlexSPI NOR Flash的写入操作
* 形 参: instance:FlexSPI实例号 * 形 参: instance:FlexSPI实例号
baseAddr:开始读取的Flash地址(32bit) baseAddr:开始读取的Flash地址(32bit)
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
static status_t Flexspi_Nor_Write_Enable(uint32_t instance, uint32_t baseAddr) static status_t Flexspi_Nor_Write_Enable(uint32_t instance, uint32_t baseAddr)
{ {
@@ -125,12 +125,12 @@ static status_t Flexspi_Nor_Write_Enable(uint32_t instance, uint32_t baseAddr)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flexspi_clock_config * 函 数 名: flexspi_clock_config
* 功能描述: 配置FlexSPI模块的时钟 * 功能描述: 配置FlexSPI模块的时钟
* 形 参: instance:FlexSPI实例号 * 形 参: instance:FlexSPI实例号
freq:表示所需的FlexSPI时钟频率 freq:表示所需的FlexSPI时钟频率
sampleClkMode:指定FlexSPI时钟的采样时钟模式,可以选择SDR或DDR模式 sampleClkMode:指定FlexSPI时钟的采样时钟模式,可以选择SDR或DDR模式
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
static void flexspi_clock_config(uint32_t instance, uint32_t freq, uint32_t sampleClkMode) static void flexspi_clock_config(uint32_t instance, uint32_t freq, uint32_t sampleClkMode)
{ {
@@ -210,10 +210,10 @@ static void flexspi_clock_config(uint32_t instance, uint32_t freq, uint32_t samp
/******************************************************************************* /*******************************************************************************
* 函 数 名: flexspi_clock_gate_enable * 函 数 名: flexspi_clock_gate_enable
* 功能描述: 开启FlexSPI模块的时钟门控 * 功能描述: 开启FlexSPI模块的时钟门控
* 形 参: 无 * 形 参: 无
* 返 回 值: 无 * 返 回 值: 无
*******************************************************************************/ *******************************************************************************/
static void flexspi_clock_gate_enable(void) static void flexspi_clock_gate_enable(void)
{ {
@@ -222,10 +222,10 @@ static void flexspi_clock_gate_enable(void)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flexspi_clock_gate_disable * 函 数 名: flexspi_clock_gate_disable
* 功能描述: 关闭FlexSPI模块的时钟门控 * 功能描述: 关闭FlexSPI模块的时钟门控
* 形 参: 无 * 形 参: 无
* 返 回 值: 无 * 返 回 值: 无
*******************************************************************************/ *******************************************************************************/
static void flexspi_clock_gate_disable(void) static void flexspi_clock_gate_disable(void)
{ {
@@ -234,12 +234,12 @@ static void flexspi_clock_gate_disable(void)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flexspi_get_clock * 函 数 名: flexspi_get_clock
* 功能描述: 获取FlexSPI时钟频率 * 功能描述: 获取FlexSPI时钟频率
* 形 参: instance:FlexSPI实例号 * 形 参: instance:FlexSPI实例号
type:所需时钟类型 type:所需时钟类型
freq:用于存储获取到的时钟频率类型 freq:用于存储获取到的时钟频率类型
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
static status_t flexspi_get_clock(uint32_t instance, flexspi_clock_type_t type, uint32_t *freq) static status_t flexspi_get_clock(uint32_t instance, flexspi_clock_type_t type, uint32_t *freq)
{ {
@@ -291,13 +291,13 @@ static status_t flexspi_get_clock(uint32_t instance, flexspi_clock_type_t type,
/******************************************************************************* /*******************************************************************************
* 函 数 名: flexspi_get_ticks * 函 数 名: flexspi_get_ticks
* 功能描述: 计算FlexSPI时钟周期数 * 功能描述: 计算FlexSPI时钟周期数
* 形 参: ticks:用于存储计算结果的指针,即所需的时钟周期数; * 形 参: ticks:用于存储计算结果的指针,即所需的时钟周期数;
intervalNs:所需的时间间隔,以纳秒(ns)为单位; intervalNs:所需的时间间隔,以纳秒(ns)为单位;
freq:FlexSPI时钟频率,单位为MHz freq:FlexSPI时钟频率,单位为MHz
unit:时钟周期单位,即计算结果中每个时钟周期代表的时间长度,以ns为单位 unit:时钟周期单位,即计算结果中每个时钟周期代表的时间长度,以ns为单位
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
static status_t flexspi_get_ticks(uint32_t *ticks, uint32_t intervalNs, uint32_t freq, uint32_t unit) static status_t flexspi_get_ticks(uint32_t *ticks, uint32_t intervalNs, uint32_t freq, uint32_t unit)
{ {
@@ -330,11 +330,11 @@ static status_t flexspi_get_ticks(uint32_t *ticks, uint32_t intervalNs, uint32_t
/******************************************************************************* /*******************************************************************************
* 函 数 名: flexspi_configure_dll * 函 数 名: flexspi_configure_dll
* 功能描述: 用来配置FLEXSPI存储器的DLL(延迟锁存器) * 功能描述: 用来配置FLEXSPI存储器的DLL(延迟锁存器)
* 形 参: instance:FLEXSPI实例号 * 形 参: instance:FLEXSPI实例号
config:存储器配置信息,包括读取时钟源、数据有效时间等参数 config:存储器配置信息,包括读取时钟源、数据有效时间等参数
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
static status_t flexspi_configure_dll(uint32_t instance, flexspi_mem_config_t *config) static status_t flexspi_configure_dll(uint32_t instance, flexspi_mem_config_t *config)
{ {
@@ -473,11 +473,11 @@ static status_t flexspi_configure_dll(uint32_t instance, flexspi_mem_config_t *c
/******************************************************************************* /*******************************************************************************
* 函 数 名: flexspi_config_mcr1 * 函 数 名: flexspi_config_mcr1
* 功能描述: 配置FlexSPI模块的MCR1寄存器 * 功能描述: 配置FlexSPI模块的MCR1寄存器
* 形 参: instance:FLEXSPI实例号 * 形 参: instance:FLEXSPI实例号
onfig指向FlexSPI存储器配置结构体的指针 onfig指向FlexSPI存储器配置结构体的指针
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
static status_t flexspi_config_mcr1(uint32_t instance, flexspi_mem_config_t *config) static status_t flexspi_config_mcr1(uint32_t instance, flexspi_mem_config_t *config)
{ {
@@ -513,10 +513,10 @@ static status_t flexspi_config_mcr1(uint32_t instance, flexspi_mem_config_t *con
/******************************************************************************* /*******************************************************************************
* 函 数 名: FLASH_GetSectorSize * 函 数 名: FLASH_GetSectorSize
* 功能描述: 获取扇区大小 * 功能描述: 获取扇区大小
* 形 参: 无 * 形 参: 无
* 返 回 值: 返回扇区大小,HYPER FLASH为64K字节,NOR FLASH为4K字节 * 返 回 值: 返回扇区大小,HYPER FLASH为64K字节,NOR FLASH为4K字节
*******************************************************************************/ *******************************************************************************/
uint32_t FLASH_GetSectorSize(void) uint32_t FLASH_GetSectorSize(void)
{ {
@@ -529,10 +529,10 @@ uint32_t FLASH_GetSectorSize(void)
/******************************************************************************* /*******************************************************************************
* 函 数 名: FLASH_GetProgramCmd * 函 数 名: FLASH_GetProgramCmd
* 功能描述: 获取页大小 * 功能描述: 获取页大小
* 形 参: 无 * 形 参: 无
* 返 回 值: 返回页大小,HYPER FLASH为512字节,NOR FLASH为256字节 * 返 回 值: 返回页大小,HYPER FLASH为512字节,NOR FLASH为256字节
*******************************************************************************/ *******************************************************************************/
uint32_t FLASH_GetProgramCmd(void) uint32_t FLASH_GetProgramCmd(void)
{ {
@@ -548,10 +548,10 @@ uint32_t FLASH_GetProgramCmd(void)
/******************************************************************************* /*******************************************************************************
* 函 数 名: FLASH_Init * 函 数 名: FLASH_Init
* 功能描述: Flash接口初始化,需在进行Flash相关操作前进行调用 * 功能描述: Flash接口初始化,需在进行Flash相关操作前进行调用
* 形 参: 无 * 形 参: 无
* 返 回 值: 无 * 返 回 值: 无
*******************************************************************************/ *******************************************************************************/
void FLASH_Init(void) void FLASH_Init(void)
{ {
@@ -567,10 +567,10 @@ void FLASH_Init(void)
/******************************************************************************* /*******************************************************************************
* 函 数 名: FLASH_DeInit * 函 数 名: FLASH_DeInit
* 功能描述: Flash接口反初始化,需在完成Flash相关操作后进行调用 * 功能描述: Flash接口反初始化,需在完成Flash相关操作后进行调用
* 形 参: 无 * 形 参: 无
* 返 回 值: 无 * 返 回 值: 无
*******************************************************************************/ *******************************************************************************/
void FLASH_DeInit(void) void FLASH_DeInit(void)
{ {
@@ -583,11 +583,11 @@ void FLASH_DeInit(void)
/******************************************************************************* /*******************************************************************************
* 函 数 名: FLASH_EraseSector * 函 数 名: FLASH_EraseSector
* 功能描述: 擦除一个Flash扇区 * 功能描述: 擦除一个Flash扇区
* 形 参: addr:擦除区域起始地址 * 形 参: addr:擦除区域起始地址
* 返 回 值: None * 返 回 值: None
* 注 释: 擦除一个扇区的最少时间:30ms~200/400ms * 注 释: 擦除一个扇区的最少时间:30ms~200/400ms
*******************************************************************************/ *******************************************************************************/
uint8_t FLASH_EraseSector(uint32_t addr) uint8_t FLASH_EraseSector(uint32_t addr)
{ {
@@ -613,13 +613,13 @@ uint8_t FLASH_EraseSector(uint32_t addr)
/******************************************************************************* /*******************************************************************************
* 函 数 名: FLASH_WritePage * 函 数 名: FLASH_WritePage
* 功能描述: 写Flash一个页 * 功能描述: 写Flash一个页
* 形 参: addr:写入区域起始地址 * 形 参: addr:写入区域起始地址
buf:数据存储区 buf:数据存储区
len:要写入的字节数(最大256) len:要写入的字节数(最大256)
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
* 注 释: 在指定地址开始写入最大256字节的数据 * 注 释: 在指定地址开始写入最大256字节的数据
*******************************************************************************/ *******************************************************************************/
uint8_t FLASH_WritePage(uint32_t addr, const uint32_t *buf, uint32_t len) uint8_t FLASH_WritePage(uint32_t addr, const uint32_t *buf, uint32_t len)
{ {
@@ -648,12 +648,12 @@ uint8_t FLASH_WritePage(uint32_t addr, const uint32_t *buf, uint32_t len)
/******************************************************************************* /*******************************************************************************
* 函 数 名: FLASH_Read * 函 数 名: FLASH_Read
* 功能描述: 读Flash内容 * 功能描述: 读Flash内容
* 形 参: addr:读取区域起始地址 * 形 参: addr:读取区域起始地址
buf:数据存储区 buf:数据存储区
len:要读取的字节数 len:要读取的字节数
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
status_t FLASH_Read(uint32_t addr, uint32_t *buf, uint32_t len) status_t FLASH_Read(uint32_t addr, uint32_t *buf, uint32_t len)
{ {
@@ -680,12 +680,12 @@ status_t FLASH_Read(uint32_t addr, uint32_t *buf, uint32_t len)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flash_erase * 函 数 名: flash_erase
* 功能描述: 擦除Flash指定长度的空间 * 功能描述: 擦除Flash指定长度的空间
* 形 参: addr:擦除区域起始地址 * 形 参: addr:擦除区域起始地址
byte_cnt:要擦除的字节数,以4k字节为最小擦除单位 byte_cnt:要擦除的字节数,以4k字节为最小擦除单位
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
* 注 释: 不满4k字节的,也需要擦除掉4k字节 * 注 释: 不满4k字节的,也需要擦除掉4k字节
*******************************************************************************/ *******************************************************************************/
status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt) status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt)
{ {
@@ -707,12 +707,12 @@ status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flash_write * 函 数 名: flash_write
* 功能描述: 在指定的flash起始地址写入指定长度的数据 * 功能描述: 在指定的flash起始地址写入指定长度的数据
* 形 参: addr:写入区域起始地址 * 形 参: addr:写入区域起始地址
buf:数据存储区 buf:数据存储区
byte_cnt:要写入的字节数 byte_cnt:要写入的字节数
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
status_t flash_write(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt) status_t flash_write(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt)
{ {
@@ -736,12 +736,12 @@ status_t flash_write(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flash_read * 函 数 名: flash_read
* 功能描述: 读Flash内容 * 功能描述: 读Flash内容
* 形 参: addr:读取区域起始地址 * 形 参: addr:读取区域起始地址
buf:数据存储区 buf:数据存储区
len:要读取的字节数 len:要读取的字节数
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
status_t flash_read(uint32_t addr, uint8_t *buf, uint32_t len) status_t flash_read(uint32_t addr, uint8_t *buf, uint32_t len)
{ {
@@ -768,12 +768,12 @@ status_t flash_read(uint32_t addr, uint8_t *buf, uint32_t len)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flash_copy * 函 数 名: flash_copy
* 功能描述: 实现flash数据在分区之间的拷贝 * 功能描述: 实现flash数据在分区之间的拷贝
* 形 参: srcAddr:源flash的起始地址 * 形 参: srcAddr:源flash的起始地址
dstAddr:目标flash的起始地址; dstAddr:目标flash的起始地址;
imageSize:要拷贝的flash空间大小,单位为字节 imageSize:要拷贝的flash空间大小,单位为字节
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
status_t flash_copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize) status_t flash_copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize)
{ {
@@ -834,11 +834,11 @@ status_t flash_copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize)
/******************************************************************************* /*******************************************************************************
* 函 数 名: NOR_FLASH_Erase * 函 数 名: NOR_FLASH_Erase
* 功能描述: 以扇区为擦除单位擦除Flash指定长度的空间,最终擦除的字节可能大于imageSize * 功能描述: 以扇区为擦除单位擦除Flash指定长度的空间,最终擦除的字节可能大于imageSize
* 形 参: addr:擦除区域起始地址 * 形 参: addr:擦除区域起始地址
imageSize:要擦除的字节数 imageSize:要擦除的字节数
* 返 回 值: None * 返 回 值: None
*******************************************************************************/ *******************************************************************************/
status_t NOR_FLASH_Erase(uint32_t app_base_addr,uint32_t imageSize) status_t NOR_FLASH_Erase(uint32_t app_base_addr,uint32_t imageSize)
{ {
@@ -860,13 +860,13 @@ status_t NOR_FLASH_Erase(uint32_t app_base_addr,uint32_t imageSize)
/******************************************************************************* /*******************************************************************************
* 函 数 名: NorFlash_Write_PageProgram * 函 数 名: NorFlash_Write_PageProgram
* 功能描述: 写入Flash指定长度的数据 * 功能描述: 写入Flash指定长度的数据
* 形 参: pBuffer:数据存储区 * 形 参: pBuffer:数据存储区
WriteAddr:写入区域起始地址 WriteAddr:写入区域起始地址
NumByteToWrite:要写入的字节数(最大256) NumByteToWrite:要写入的字节数(最大256)
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
* 注 释: 在指定地址开始写入最大256字节的数据 * 注 释: 在指定地址开始写入最大256字节的数据
*******************************************************************************/ *******************************************************************************/
void NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) void NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{ {
@@ -883,24 +883,24 @@ void NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t Num
/******************************************************************************* /*******************************************************************************
* 函 数 名: NorFlash_Write_NoCheck * 函 数 名: NorFlash_Write_NoCheck
* 功能描述: 无检验写入W25QXX从指定地址开始指定长度的数据 * 功能描述: 无检验写入W25QXX从指定地址开始指定长度的数据
* 形 参: pBuffer:数据存储区 * 形 参: pBuffer:数据存储区
WriteAddr:开始写入的地址(24bit) WriteAddr:开始写入的地址(24bit)
NumByteToWrite:要写入的字节数(最大65535) NumByteToWrite:要写入的字节数(最大65535)
* 返 回 值: 无 * 返 回 值: 无
* 注 释: 必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败! * 注 释: 必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
具有自动换页功能,在指定地址开始写入指定长度的数据,但是要确保地址不越界! 具有自动换页功能,在指定地址开始写入指定长度的数据,但是要确保地址不越界!
*******************************************************************************/ *******************************************************************************/
void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{ {
uint16_t pageRemain; uint16_t pageRemain;
pageRemain = 256 - WriteAddr%256;//单页剩余的字节数 pageRemain = 256 - WriteAddr%256;//单页剩余的字节数
if(NumByteToWrite <= pageRemain) if(NumByteToWrite <= pageRemain)
{ {
pageRemain = NumByteToWrite;//不大于256个字节 pageRemain = NumByteToWrite;//不大于256个字节
} }
while(1) while(1)
@@ -908,21 +908,21 @@ void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByte
NorFlash_Write_PageProgram(pBuffer,WriteAddr,pageRemain); NorFlash_Write_PageProgram(pBuffer,WriteAddr,pageRemain);
if(NumByteToWrite == pageRemain) if(NumByteToWrite == pageRemain)
{ {
break;//写入结束了 break;//写入结束了
} }
else //NumByteToWrite>pageRemain else //NumByteToWrite>pageRemain
{ {
pBuffer += pageRemain; pBuffer += pageRemain;
WriteAddr += pageRemain; WriteAddr += pageRemain;
NumByteToWrite -= pageRemain;//减去已经写入了的字节数 NumByteToWrite -= pageRemain;//减去已经写入了的字节数
if(NumByteToWrite > 256) if(NumByteToWrite > 256)
{ {
pageRemain = 256;//一次可以写入256个字节 pageRemain = 256;//一次可以写入256个字节
} }
else else
{ {
pageRemain = NumByteToWrite;//不够256个字节了 pageRemain = NumByteToWrite;//不够256个字节了
} }
} }
} }
@@ -930,13 +930,13 @@ void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByte
/******************************************************************************* /*******************************************************************************
* 函 数 名: NorFlash_Write * 函 数 名: NorFlash_Write
* 功能描述: 写入W25QXX在指定地址开始写入指定长度的数据 * 功能描述: 写入W25QXX在指定地址开始写入指定长度的数据
* 形 参: pBuffer:数据存储区 * 形 参: pBuffer:数据存储区
WriteAddr:开始写入的地址(24bit) WriteAddr:开始写入的地址(24bit)
NumByteToWrite:要写入的字节数(最大65535) NumByteToWrite:要写入的字节数(最大65535)
* 返 回 值: None * 返 回 值: None
* 注 释: 该函数带擦除操作 * 注 释: 该函数带擦除操作
*******************************************************************************/ *******************************************************************************/
void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{ {
@@ -946,61 +946,61 @@ void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
uint16_t i; uint16_t i;
uint8_t *NorFlash_BUF = 0; uint8_t *NorFlash_BUF = 0;
NorFlash_BUF = NorFlash_BUFFER;//RAM缓冲区4K NorFlash_BUF = NorFlash_BUFFER;//RAM缓冲区4K
WriteAddr &= 0x0FFFFFFF; WriteAddr &= 0x0FFFFFFF;
secPos = WriteAddr/SECTOR_SIZE;//扇区地址 secPos = WriteAddr/SECTOR_SIZE;//扇区地址
secOff = WriteAddr%SECTOR_SIZE;//在扇区内的偏移 secOff = WriteAddr%SECTOR_SIZE;//在扇区内的偏移
secRemain = SECTOR_SIZE - secOff;//扇区剩余空间大小 secRemain = SECTOR_SIZE - secOff;//扇区剩余空间大小
if(NumByteToWrite <= secRemain) if(NumByteToWrite <= secRemain)
{ {
secRemain = NumByteToWrite;//不大于4096个字节 secRemain = NumByteToWrite;//不大于4096个字节
} }
while(1) while(1)
{ {
FLASH_Read(FLASH_BASE + secPos*SECTOR_SIZE, (void *)NorFlash_BUF, SECTOR_SIZE);//读出整个扇区的内容 FLASH_Read(FLASH_BASE + secPos*SECTOR_SIZE, (void *)NorFlash_BUF, SECTOR_SIZE);//读出整个扇区的内容
for(i=0;i<secRemain;i++)//校验数据 for(i=0;i<secRemain;i++)//校验数据
{ {
if(NorFlash_BUF[secOff+i] != 0xFF) if(NorFlash_BUF[secOff+i] != 0xFF)
{ {
break;//需要擦除 break;//需要擦除
} }
} }
if(i < secRemain)//需要擦除 if(i < secRemain)//需要擦除
{ {
FLASH_EraseSector(FLASH_BASE + secPos*SECTOR_SIZE); FLASH_EraseSector(FLASH_BASE + secPos*SECTOR_SIZE);
for(i=0;i<secRemain;i++)//复制 for(i=0;i<secRemain;i++)//复制
{ {
NorFlash_BUF[i+secOff] = pBuffer[i]; NorFlash_BUF[i+secOff] = pBuffer[i];
} }
NorFlash_Write_NoCheck(NorFlash_BUF,FLASH_BASE + secPos*SECTOR_SIZE,SECTOR_SIZE);//写入整个扇区 NorFlash_Write_NoCheck(NorFlash_BUF,FLASH_BASE + secPos*SECTOR_SIZE,SECTOR_SIZE);//写入整个扇区
} }
else else
{ {
NorFlash_Write_NoCheck(pBuffer,FLASH_BASE + WriteAddr,secRemain);//写已经擦除了的,直接写入扇区剩余区间. NorFlash_Write_NoCheck(pBuffer,FLASH_BASE + WriteAddr,secRemain);//写已经擦除了的,直接写入扇区剩余区间.
} }
if(NumByteToWrite == secRemain) if(NumByteToWrite == secRemain)
{ {
break;//写入结束了 break;//写入结束了
} }
else//写入未结束 else//写入未结束
{ {
secPos++;//扇区地址增1 secPos++;//扇区地址增1
secOff=0;//偏移位置为0 secOff=0;//偏移位置为0
pBuffer += secRemain;//指针偏移 pBuffer += secRemain;//指针偏移
WriteAddr += secRemain;//写地址偏移 WriteAddr += secRemain;//写地址偏移
NumByteToWrite -= secRemain;//字节数递减 NumByteToWrite -= secRemain;//字节数递减
if(NumByteToWrite > SECTOR_SIZE) if(NumByteToWrite > SECTOR_SIZE)
{ {
secRemain = SECTOR_SIZE;//下一个扇区还是写不完 secRemain = SECTOR_SIZE;//下一个扇区还是写不完
} }
else else
{ {
secRemain = NumByteToWrite;//下一个扇区可以写完了 secRemain = NumByteToWrite;//下一个扇区可以写完了
} }
} }
} }
@@ -1008,12 +1008,12 @@ void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
/******************************************************************************* /*******************************************************************************
* 函 数 名: NOR_FLASH_Write * 函 数 名: NOR_FLASH_Write
* 功能描述: 写入W25QXX在指定地址开始写入指定长度的数据 * 功能描述: 写入W25QXX在指定地址开始写入指定长度的数据
* 形 参: FlashAddress:用于存储当前写入Flash地址的指针,写入过程中会移动 * 形 参: FlashAddress:用于存储当前写入Flash地址的指针,写入过程中会移动
Data:要写入数据存储区 Data:要写入数据存储区
DataLength:要写入的字节数 DataLength:要写入的字节数
* 返 回 值: 0 * 返 回 值: 0
*******************************************************************************/ *******************************************************************************/
#ifndef USE_HIGHT_SPEED_TRANS #ifndef USE_HIGHT_SPEED_TRANS
uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength) uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength)
@@ -94,11 +94,11 @@ static const uint32_t crc32tab[] = {
/******************************************************************************* /*******************************************************************************
* 函 数 名: calculate_crc32 * 函 数 名: calculate_crc32
* 功能描述: 计算给定Flash内存地址范围中数据的CRC32校验和 * 功能描述: 计算给定Flash内存地址范围中数据的CRC32校验和
* 形 参: addr:表示Flash地址的起始位置 * 形 参: addr:表示Flash地址的起始位置
len:表示需要计算CRC32的数据长度 len:表示需要计算CRC32的数据长度
* 返 回 值: 计算得到的CRC32值 * 返 回 值: 计算得到的CRC32值
*******************************************************************************/ *******************************************************************************/
uint32_t calculate_crc32(uint32_t addr, uint32_t len) uint32_t calculate_crc32(uint32_t addr, uint32_t len)
{ {
@@ -115,10 +115,10 @@ uint32_t calculate_crc32(uint32_t addr, uint32_t len)
/******************************************************************************* /*******************************************************************************
* 函 数 名: UpdateOTAFlag * 函 数 名: UpdateOTAFlag
* 功能描述: 更新OTA Flag区域的信息,版本完成下载后在app里进行调用 * 功能描述: 更新OTA Flag区域的信息,版本完成下载后在app里进行调用
* 形 参: ptr:ota_info_t结构体指针,描述OTA升级相关信息 * 形 参: ptr:ota_info_t结构体指针,描述OTA升级相关信息
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
*******************************************************************************/ *******************************************************************************/
status_t UpdateOTAFlag(ota_info_t *ptr) status_t UpdateOTAFlag(ota_info_t *ptr)
{ {
@@ -135,31 +135,31 @@ status_t UpdateOTAFlag(ota_info_t *ptr)
} }
/******************************************************************************* /*******************************************************************************
* 函 数 名: UpdateApplication * 函 数 名: UpdateApplication
* 功能描述: 在bootloader里进行调用,根据Flash中Flag分区中的信息决定是否进行版本更新 * 功能描述: 在bootloader里进行调用,根据Flash中Flag分区中的信息决定是否进行版本更新
* 形 参: 无 * 形 参: 无
* 返 回 值: 无 * 返 回 值: 无
* 注 释: 该函数调用后无论结果如何都将跳转到app分区 * 注 释: 该函数调用后无论结果如何都将跳转到app分区
*******************************************************************************/ *******************************************************************************/
void UpdateApplication(void) void UpdateApplication(void)
{ {
status_t status; status_t status;
ota_info_t ota_info; // 定义OTA信息结构体 ota_info_t ota_info; // 定义OTA信息结构体
// 从Flash中读取OTA信息 // 从Flash中读取OTA信息
memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t)); memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
// 如果OTA升级状态为准备状态,且APP分区与download分区版本不同,才可以进行升级 // 如果OTA升级状态为准备状态,且APP分区与download分区版本不同,才可以进行升级
if((ota_info.status == OTA_STATUS_READY) && (ota_info.os.crc32 != ota_info.down.crc32)) if((ota_info.status == OTA_STATUS_READY) && (ota_info.os.crc32 != ota_info.down.crc32))
{ {
Serial_PutString("\r\n------Start to update the app!------\r\n"); Serial_PutString("\r\n------Start to update the app!------\r\n");
// 校验downlad分区固件CRC // 校验downlad分区固件CRC
if(calculate_crc32(DOWN_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32) if(calculate_crc32(DOWN_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32)
{ {
ota_info.status = OTA_STATUS_UPDATING; ota_info.status = OTA_STATUS_UPDATING;
UpdateOTAFlag(&ota_info); UpdateOTAFlag(&ota_info);
// 1.如果CRC校验通过,开始升级,逐字节拷贝Flash,先备份当前XiUOS System分区内容 // 1.如果CRC校验通过,开始升级,逐字节拷贝Flash,先备份当前XiUOS System分区内容
status = flash_copy(XIUOS_FLAH_ADDRESS, BAKUP_FLAH_ADDRESS, ota_info.os.size); status = flash_copy(XIUOS_FLAH_ADDRESS, BAKUP_FLAH_ADDRESS, ota_info.os.size);
if((status == kStatus_Success) &&(calculate_crc32(BAKUP_FLAH_ADDRESS, ota_info.os.size) == ota_info.os.crc32)) if((status == kStatus_Success) &&(calculate_crc32(BAKUP_FLAH_ADDRESS, ota_info.os.size) == ota_info.os.crc32))
{ {
@@ -179,7 +179,7 @@ void UpdateApplication(void)
goto finish; goto finish;
} }
// 2.拷贝download分区到XiUOS System分区 // 2.拷贝download分区到XiUOS System分区
status = flash_copy(DOWN_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.down.size); status = flash_copy(DOWN_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.down.size);
if((status == kStatus_Success) &&(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32)) if((status == kStatus_Success) &&(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32))
{ {
@@ -189,7 +189,7 @@ void UpdateApplication(void)
ota_info.os.crc32 = ota_info.down.crc32; ota_info.os.crc32 = ota_info.down.crc32;
ota_info.os.version = ota_info.down.version; ota_info.os.version = ota_info.down.version;
strncpy(ota_info.os.description, ota_info.down.description, sizeof(ota_info.down.description)); strncpy(ota_info.os.description, ota_info.down.description, sizeof(ota_info.down.description));
ota_info.status == OTA_STATUS_IDLE; // 拷贝download分区到XiUOS System分区成功,将OTA升级状态设置为IDLE ota_info.status == OTA_STATUS_IDLE; // 拷贝download分区到XiUOS System分区成功,将OTA升级状态设置为IDLE
UpdateOTAFlag(&ota_info); UpdateOTAFlag(&ota_info);
} }
else else
@@ -206,7 +206,7 @@ void UpdateApplication(void)
} }
else else
{ {
// 如果download分区CRC校验失败,升级失败 // 如果download分区CRC校验失败,升级失败
Serial_PutString("\r\n------Download Firmware CRC check failed!------\r\n"); Serial_PutString("\r\n------Download Firmware CRC check failed!------\r\n");
ota_info.status = OTA_STATUS_ERROR; ota_info.status = OTA_STATUS_ERROR;
strncpy(ota_info.error_message, "Download Firmware CRC check failed!",sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "Download Firmware CRC check failed!",sizeof(ota_info.error_message));
@@ -39,9 +39,53 @@ static void InitialVersion(void)
} }
} }
static void BackupVersion(void)
{
status_t status;
ota_info_t ota_info;
memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
ota_info.status = OTA_STATUS_BACKUP;
UpdateOTAFlag(&ota_info);
status = flash_copy(BAKUP_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.bak.size);
if((status == kStatus_Success) &&(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.bak.size) == ota_info.bak.crc32))
{
Serial_PutString("\r\n------Backup app version success!------\r\n");
ota_info.os.size = ota_info.bak.size;
ota_info.os.crc32 = ota_info.bak.crc32;
ota_info.os.version = ota_info.bak.version;
ota_info.lastjumpflag=0xABABABAB;
strncpy(ota_info.os.description, ota_info.bak.description, sizeof(ota_info.bak.description));
UpdateOTAFlag(&ota_info);
}
else
{
Serial_PutString("\r\n------Backup app version failed!------\r\n");
ota_info.status = OTA_STATUS_ERROR;
strncpy(ota_info.error_message, "Backup app version failed!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
}
void jump_to_application(void) void jump_to_application(void)
{ {
ota_info_t ota_info;
FLASH_Init();
memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
if (ota_info.lastjumpflag!=0x00000000)
{
Serial_PutString("\r\n------Bootloader false, begin backup!------\r\n");
BackupVersion();
}
else
{
ota_info.lastjumpflag=0xABABABAB;
UpdateOTAFlag(&ota_info);
}
FLASH_DeInit();
SCB->VTOR = (uint32_t)XIUOS_FLAH_ADDRESS; SCB->VTOR = (uint32_t)XIUOS_FLAH_ADDRESS;
asm volatile("LDR R0, = 0x60100000"); asm volatile("LDR R0, = 0x60100000");
@@ -77,19 +121,25 @@ void BootLoaderJumpApp(void)
ImxrtMsDelay(10); ImxrtMsDelay(10);
} }
while(1) while(1)
{ {
if((ret)&&(ch1 == 0x20)) if((ret)&&(ch1 == 0x20))
{ {
Serial_PutString("\r\nPlease slecet:"); Serial_PutString("\r\nPlease slecet:");
Serial_PutString("\r\n 1:run app"); Serial_PutString("\r\n 1:run app");
Serial_PutString("\r\n 2:update app"); Serial_PutString("\r\n 2:update app");
Serial_PutString("\r\n 3:reboot \r\n"); Serial_PutString("\r\n 3:reboot \r\n");
ch2 = GetKey(); ch2 = GetKey();
switch(ch2) switch(ch2)
{ {
case 0x31: case 0x31:
jump_to_application(); jump_to_application();
break; break;
@@ -106,6 +156,7 @@ void BootLoaderJumpApp(void)
{ {
UpdateApplication(); UpdateApplication();
} }
FLASH_DeInit(); FLASH_DeInit();
jump_to_application(); jump_to_application();
break; break;
@@ -33,6 +33,7 @@ typedef enum {
OTA_STATUS_DOWNLOADING, // 正在下载固件 OTA_STATUS_DOWNLOADING, // 正在下载固件
OTA_STATUS_DOWNLOADED, // 固件下载完成 OTA_STATUS_DOWNLOADED, // 固件下载完成
OTA_STATUS_UPDATING, // 正在进行OTA升级 OTA_STATUS_UPDATING, // 正在进行OTA升级
OTA_STATUS_BACKUP, // 正在版本回退
OTA_STATUS_ERROR, // 出现错误,升级失败 OTA_STATUS_ERROR, // 出现错误,升级失败
} ota_status_t; } ota_status_t;