首页 > 编程语言 >Flash简介及其中的Bootloader如何实现对APP程序的下载更新或重装

Flash简介及其中的Bootloader如何实现对APP程序的下载更新或重装

时间:2024-07-18 10:28:23浏览次数:15  
标签:Flash HAL pUSBUART APP FLASH uint8 return Bootloader buf

目录

1.eMMC、Nand Flash都属于Flash,Flash的具体类别如下

2.Bootloader在APP程序下载更新或重装中存在的意义

3.Bootloader下载更新或重装APP程序的思路框架

4.Bootloader下载更新或重装APP程序代码实现


1.eMMC、Nand Flash都属于Flash,Flash的具体类别如下

        在单片机板子的Flash中,已预先包含Bootloader和APP程序(Bootloader存在的意义为帮助APP程序实现更新或重装,原因见下文2)

2.Bootloader在APP程序下载更新或重装中存在的意义

3.Bootloader下载更新或重装APP程序的思路框架

        上图中第6步的启动程序的具体方法如下图:

 4.Bootloader下载更新或重装APP程序代码实现

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os2.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "draw.h"
#include "stdio.h"
#include "draw.h"
#include "ux_api.h"
#include "modbus.h"
#include "errno.h"
#include "uart_device.h"
#include "semphr.h"
#include "bootloader.h"

#define CFG_OFFSET 0x081FE000
#define SECTOR_SIZE (8*1024)

#define UPDATE_TIMEOUT 1000

static struct UART_Device *g_pUpdateUART;

int isSoftReset(void)
{
    return HAL_RCC_GetResetSource() & RCC_RESET_FLAG_SW;
}

uint32_t get_app_vector(void)
{
    PFirmwareInfo ptFlashInfo = (PFirmwareInfo)CFG_OFFSET;
    return ptFlashInfo->load_addr;
}

static void SoftReset(void)
{
    __set_FAULTMASK(1);//关闭所有中断
    HAL_NVIC_SystemReset();
}

static void start_app_c(void)
{
    /* 触发软件复位 */
    SoftReset();
}

static uint32_t BE32toLE32(uint8_t *buf)
{
    return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3] << 0);
}

static int GetLocalFirmwareInfo(PFirmwareInfo ptFirmwareInfo)
{
    volatile PFirmwareInfo ptFlashInfo = (PFirmwareInfo)CFG_OFFSET;
    
    if (ptFlashInfo->file_len == 0xFFFFFFFF)
        return -1;
    
    *ptFirmwareInfo = *ptFlashInfo;
    return 0;
}

static int GetServerFirmwareInfo(PFirmwareInfo ptFirmwareInfo)
{
    uint8_t data = '1';
    uint8_t buf[sizeof(FirmwareInfo)];

    /* send 0x01 cmd to PC */
    if (0 != g_pUpdateUART->Send(g_pUpdateUART, &data, 1, UPDATE_TIMEOUT))
        return -1;

    /* wait for response */
    while (1)
    {
        if (0 != g_pUpdateUART->RecvByte(g_pUpdateUART, &data, UPDATE_TIMEOUT*10))
            return -1;

        if (data != 0x5a)
        {
            buf[0] = data;
            break;
        }
    }

    /* get firmware info */
    for (int i = 1; i < sizeof(FirmwareInfo); i++)
    {
        if (0 != g_pUpdateUART->RecvByte(g_pUpdateUART, &buf[i], UPDATE_TIMEOUT))
            return -1;
    }

    ptFirmwareInfo->version = BE32toLE32(&buf[0]);
    ptFirmwareInfo->file_len = BE32toLE32(&buf[4]);
    ptFirmwareInfo->load_addr = BE32toLE32(&buf[8]);
    ptFirmwareInfo->crc32 = BE32toLE32(&buf[12]);
    strncpy((char *)ptFirmwareInfo->file_name, (char *)&buf[16], 16);

    return 0;
    
}

static int GetServerFirmware(uint8_t *buf, uint32_t len)
{
    uint8_t data = '2';

    /* send 0x02 cmd to PC */
    if (0 != g_pUpdateUART->Send(g_pUpdateUART, &data, 1, UPDATE_TIMEOUT))
        return -1;

    /* get firmware info */
    for (int i = 0; i < len; i++)
    {
        if (0 != g_pUpdateUART->RecvByte(g_pUpdateUART, &buf[i], UPDATE_TIMEOUT*10))
            return -1;
    }
    return 0;
}


/* https://lxp32.github.io/docs/a-simple-example-crc32-calculation/ */
static int GetCRC32(const char *s,size_t n)
{
    uint32_t crc=0xFFFFFFFF;

    for(size_t i=0;i<n;i++) {
            char ch=s[i];
            for(size_t j=0;j<8;j++) {
                    uint32_t b=(ch^crc)&1;
                    crc>>=1;
                    if(b) crc=crc^0xEDB88320;
                    ch>>=1;
            }
    }

    return ~crc;
}


static int WriteFirmware(uint8_t *firmware_buf, uint32_t len, uint32_t flash_addr)
{
    FLASH_EraseInitTypeDef tEraseInit;
    uint32_t SectorError;
    uint32_t sectors = (len + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
    uint32_t flash_offset = flash_addr - 0x08000000;
    uint32_t bank_sectors;
    uint32_t erased_sectors = 0;
    
    HAL_FLASH_Unlock();

    /* erase bank1 */
    if (flash_offset < 0x100000)
    {
        tEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
        tEraseInit.Banks     = FLASH_BANK_1;
        tEraseInit.Sector    = flash_offset / SECTOR_SIZE;
        bank_sectors = (0x100000 - flash_offset) / SECTOR_SIZE;
        if (sectors <= bank_sectors)
            erased_sectors = sectors;
        else
            erased_sectors = bank_sectors;
        tEraseInit.NbSectors = erased_sectors;
        
        if (HAL_OK != HAL_FLASHEx_Erase(&tEraseInit, &SectorError))
        {
            g_pUpdateUART->Send(g_pUpdateUART, (uint8_t *)"HAL_FLASHEx_Erase Failed\r\n", strlen("HAL_FLASHEx_Erase Failed\r\n"), UPDATE_TIMEOUT);
            HAL_FLASH_Lock();
            return -1;
        }

        flash_offset += erased_sectors*SECTOR_SIZE;
    }

    sectors -= erased_sectors;
    flash_offset -= 0x100000;
    
    /* erase bank2 */
    if (sectors)
    {
        tEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
        tEraseInit.Banks     = FLASH_BANK_2;
        tEraseInit.Sector    = flash_offset / SECTOR_SIZE;
        bank_sectors = (0x100000 - flash_offset) / SECTOR_SIZE;
        if (sectors <= bank_sectors)
            erased_sectors = sectors;
        else
            erased_sectors = bank_sectors;
        tEraseInit.NbSectors = erased_sectors;
        
        if (HAL_OK != HAL_FLASHEx_Erase(&tEraseInit, &SectorError))
        {
            g_pUpdateUART->Send(g_pUpdateUART, (uint8_t *)"HAL_FLASHEx_Erase Failed\r\n", strlen("HAL_FLASHEx_Erase Failed\r\n"), UPDATE_TIMEOUT);
            HAL_FLASH_Lock();
            return -1;
        }
    }

    /* program */
    len = (len + 15) & ~15;

    for (int i = 0; i < len; i+=16)
    {
        if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, flash_addr, (uint32_t)firmware_buf))
        {
            g_pUpdateUART->Send(g_pUpdateUART, (uint8_t *)"HAL_FLASH_Program Failed\r\n", strlen("HAL_FLASH_Program Failed\r\n"), UPDATE_TIMEOUT);
            HAL_FLASH_Lock();
            return -1;
        }

        flash_addr += 16;
        firmware_buf += 16;
    }


    HAL_FLASH_Lock();
    return 0;

}

static int WriteFirmwareInfo(PFirmwareInfo ptFirmwareInfo)
{
    FLASH_EraseInitTypeDef tEraseInit;
    uint32_t SectorError;
    uint32_t flash_addr = CFG_OFFSET;
    uint8_t *src_buf = (uint8_t *)ptFirmwareInfo;
    
    HAL_FLASH_Unlock();

    /* erase bank2 */
    tEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
    tEraseInit.Banks     = FLASH_BANK_2;
    tEraseInit.Sector    = (flash_addr - 0x08000000 - 0x100000) / SECTOR_SIZE;
    tEraseInit.NbSectors = 1;
    
    if (HAL_OK != HAL_FLASHEx_Erase(&tEraseInit, &SectorError))
    {
        g_pUpdateUART->Send(g_pUpdateUART, (uint8_t *)"HAL_FLASHEx_Erase Failed\r\n", strlen("HAL_FLASHEx_Erase Failed\r\n"), UPDATE_TIMEOUT);
        HAL_FLASH_Lock();
        return -1;
    }

    /* program */
    for (int i = 0; i < sizeof(FirmwareInfo); i+=16)
    {
        if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, flash_addr, (uint32_t)src_buf))
        {
            g_pUpdateUART->Send(g_pUpdateUART, (uint8_t *)"HAL_FLASH_Program Failed\r\n", strlen("HAL_FLASH_Program Failed\r\n"), UPDATE_TIMEOUT);
            HAL_FLASH_Lock();
            return -1;
        }

        flash_addr += 16;
        src_buf += 16;
    }

    HAL_FLASH_Lock();
    return 0;
}

void BootLoaderTask( void *pvParameters )	
{
    struct UART_Device *pUSBUART = GetUARTDevice("usb");
    FirmwareInfo tLocalInfo;
    FirmwareInfo tServerInfo;
    int err;
    int need_update = 0;
    uint8_t *firmware_buf;

    vTaskDelay(10000); /* wait for pc ready */
    pUSBUART->Init(pUSBUART, 115200, 'N', 8, 1);

    g_pUpdateUART = pUSBUART;

    while (1)
    {
        /* read cfg info, to detect app's version */
        err = GetLocalFirmwareInfo(&tLocalInfo);
        if (err)
        {
            /* update */
            need_update = 1;
        }
        else
        {
            pUSBUART->Send(pUSBUART, (uint8_t *)"GetLocalFirmwareInfo OK\r\n", strlen("GetLocalFirmwareInfo OK\r\n"), UPDATE_TIMEOUT);
        }

        err = GetServerFirmwareInfo(&tServerInfo);

        if (!err)
        {
            /* compare version */
            if (tServerInfo.version > tLocalInfo.version)
            {
                /* update */
                need_update = 1;
            }
        }
        else
        {
            need_update = 0;
            pUSBUART->Send(pUSBUART, (uint8_t *)"GetServerFirmwareInfo Failed\r\n", strlen("GetServerFirmwareInfo Failed\r\n"), UPDATE_TIMEOUT);
        }


        if (need_update)
        {
            firmware_buf = pvPortMalloc(tServerInfo.file_len);
            if (!firmware_buf)
            {
                /* error */
                pUSBUART->Send(pUSBUART, (uint8_t *)"Malloc Failed\r\n", strlen("Malloc Failed\r\n"), UPDATE_TIMEOUT);
            }
            
            err = GetServerFirmware(firmware_buf, tServerInfo.file_len);
            if (!err)
            {
                /* calc CRC */                
                uint32_t crc = GetCRC32((const char *)firmware_buf, tServerInfo.file_len);
                if (crc == tServerInfo.crc32)
                {
                    /* OK */
                    /* burn */
                    pUSBUART->Send(pUSBUART, (uint8_t *)"Download OK\r\n", 13, UPDATE_TIMEOUT);
                    WriteFirmware(firmware_buf, tServerInfo.file_len, tServerInfo.load_addr);
                    WriteFirmwareInfo(&tServerInfo);

                    /* start app */
                    pUSBUART->Send(pUSBUART, (uint8_t *)"Start app\r\n", strlen("Start app"), UPDATE_TIMEOUT);
                    start_app_c();
                }
                else
                {
                    pUSBUART->Send(pUSBUART, (uint8_t *)"GetCRC32 Failed\r\n", strlen("GetCRC32 Failed\r\n"), UPDATE_TIMEOUT);
								}
            }
            else
            {
                pUSBUART->Send(pUSBUART, (uint8_t *)"GetServerFirmware Failed\r\n", strlen("GetServerFirmware Failed\r\n"), UPDATE_TIMEOUT);
						}
        }
        else
        {
            /* start app */
            pUSBUART->Send(pUSBUART, (uint8_t *)"Start app\r\n", strlen("Start app"), UPDATE_TIMEOUT);
            start_app_c();
        }
        
    }
}

标签:Flash,HAL,pUSBUART,APP,FLASH,uint8,return,Bootloader,buf
From: https://blog.csdn.net/qq_45031559/article/details/140426083

相关文章

  • C. Jellyfish and Green Apple
    原题链接题解1.由于是除二操作,所以最后的平均数一定能表示成\(k_1\cdot\frac{1}{2^{i_1}}+...+k_t\cdot\frac{1}{2^{i_t}}\)的形式2.最小的\(\frac{1}{2^i}\)由于没有往下再分,所以数量一定是偶数,把他们的数量除二加到\(\frac{1}{2^{i-1}}\)上,此时\(i-1\)就变最小的了......
  • 达梦数据库的系统视图v$rapply_sys
    达梦数据库的系统视图v$rapply_sys在达梦数据库(DMDatabase)中,V$RAPPLY_SYS是一个系统视图,用于显示数据库的实时应用(Real-timeApply)系统信息。实时应用是一种数据库复制技术,允许将一个数据库的更改实时应用到另一个数据库中,通常用于数据同步、数据分发和灾难恢复等场景。......
  • uniapp(全端兼容) - 最新详细实现 “卡片式堆叠“ 轮播图效果,堆叠在一起的轮播图片可
    效果图在uni-app微信小程序/手机h5网页网站/安卓app/苹果app/支付宝小程序/nvue等(全平台完美兼容)开发中,实现uniApp各端都兼容的图片堆叠轮播图功能,层叠轮播插件,详细实现上下层叠轮播图并且在全平台通用兼容,卡片叠加在一起的轮播翻滚,错开叠加来回拖曳左右滚动切换,支持修改......
  • AI Earth——MuSyQ 30m/10天叶片叶绿素含量产品(中国)应用 app
    应用介绍 ​​​​​​​30m/10天合成的叶片叶绿素含量产品是空天院多源协同定量遥感产品生产系统((Multi-sourcedataSynergizedQuantitativeremotesensingproductionsystem,MuSyQ))产品之一。叶片叶绿素含量(Chlleaf)是植被遥感监测中最重要的参数之一,目前国际上缺少高分......
  • uniapp设置缓存过期时间
    在uni-app中,如果你想要实现数据的缓存并让这个缓存保留24小时,你可以使用uni.setStorageSync(同步存储)或uni.setStorage(异步存储)方法结合JavaScript的日期时间处理来实现。不过,需要注意的是,uni.setStorage系列API本身并不直接支持设置过期时间。因此,你需要自己管理过期时间。以下是......
  • (新)app逆向二(adb操作)
    一、逆向的基本流程#1.获取app的目标(官网,豌豆荚,下载历史老版本);尽量不要去华为,小米应用市场下载;——》拿到app放在电脑上,并且安装到手机上#2.使用抓包工具,手机上操作app,进行抓包是(charles,fiddler);#3.使用反编译工具(JADX,JD_GUI),把apk问阿金反编译成java代码,分析代码,定位位置......
  • uniapp对接人脸识别,人脸核身,双录 ,阿里云,以及腾讯云对接方法。
    腾讯云uniapp接入】第一步,申请人脸核身服务:https://cloud.tencent.com/apply/p/shcgszvmppc第二步,申请业务流程WBAppid:-获取WBappid方法指引:https://cloud.tencent.com/document/product/1007/49634-申请链接:https://console.cloud.tencent.com/faceid/access第三步,uni插件接入......
  • 看广告app开发(聚合广告SDK)
    开发一个看广告APP并集成聚合广告SDK是一个涉及多个步骤的过程。以下是一个大致的开发流程:一、确定需求和目标明确看广告APP的用户群体、需求和目标。这有助于确定APP的定位和功能设计1。确定要展示的广告类型,如横幅广告、插屏广告、视频广告等,以及广告的展示频率、时间和位......
  • (新)app逆向一 虚拟环境的使用
    python虚拟环境创建1.使不同的应用开发环境独立2.环境升级也不影响其他的应用,也不会影响全局的python环境3.防止报管理混乱及版本的冲突导出项目的依赖#.查看模块pipfreeze#虚拟模块导出到文件中pipfreeze>requirements.txt#别人要用我们的项目-打开项目后执行......
  • 基于SSM的校园志愿者管理系统小程序+99213(免费领源码)可做计算机毕业设计JAVA、PHP、爬
    小程序+springboot校园志愿者管理系统摘 要随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,校园志愿者管理系统被用户普遍使用,为方便用户能够可以随时进行在线查看校园志愿......