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

目录

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();
        }
        
    }
}

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 合并STM32bootloaderapp程序需要两个步骤:首先是生成bootloaderapp程序的二进制文件,然后是将它们合并成一个二进制文件。 生成二进制文件有很多种方式,可以通过Keil、IAR等集成开发环境自动生成。也可以使用GCC编译生成Hex格式的文件。在这里,我们以使用Keil为例: 1. 配置bootloaderapp程序的工程文件,包括源代码、头文件和库文件等。 2. 进行编译和连接,生成.hex或.bin格式的文件。对于Keil,这些文件可以在Project\Obj目录下找到。 3. 复制bootloaderapp程序的.hex或.bin文件到一个临时文件夹。 合并二进制文件的过程大致如下: 1. 打开一个二进制文件编辑器,例如HxD、HEXplorer等。在这里,我们以HEXplorer为例。 2. 打开要合并的bootloader.hex文件,复制其数据的部分(从“:”到本行结束),然后打开要合并的app程序.hex文件,将该数据添加到文件的末尾。 3. 如果app程序的ENTRY地址与bootloader程序的ENTRY地址不同,则需要修改数据块的START地址。例如,如果bootloader程序ENTRY地址为0x08000000,而app程序的ENTRY地址为0x08004000,则需要将数据块的START地址修改为“:200000005C0000000C00000010040000D4”(0x08000000+0x4000=0x08004000)。 4. 保存文件,将其烧录到STM32芯片即可完成合并。 总之,合并STM32bootloaderapp程序需要先生成二进制文件,然后通过二进制文件编辑器将它们合并成一个文件,并进行修改和调整。最终保存、烧录到芯片即可。 ### 回答2: 在STM32芯片,通常有两个不同的程序Bootloader和应用程序App)。Bootloader程序位于芯片的Flash的特定地址,它是专门用于更新应用程序程序App程序是实际的应用程序,它在Flash的不同地址处。 合并BootloaderApp程序可能是为了减少系统的存储器占用率,提高系统性能,增加自由度等许多因素,那么接下来,我将向您介绍如何将这两个程序合并在一起。 首先,需要确定App程序是否有与Bootloader重叠的代码。如果有,则需要将这些代码移动到没有重叠的位置。其次,需要尝试新的链接脚本,以确保两个程序可以正确地链接在一起。 接着,将两个程序合并为单个Bin文件。确保App程序添加到Bootloader程序的完整程序。最后,将应用程序的入口点设置为Bootloader程序的入口点,以便引导程序直接运行应用程序。 在合并BootloaderApp程序之前,需要确保所有的代码、文本、数据段、BSS段等在Linker脚本都被合并。如果两个程序之间存在代码引用或数据引用,那么在进行合并时,可能遇到符号冲突的问题。这些问题需要根据芯片的体系结构进行仔细处理。 最后,可以使用芯片厂商提供的在线更新工具或USB接口来更新新合并的程序。同时,建议保留原始Bootloader程序副本,并留下有足够的空间用于Bootloader升级和App程序更新。 在合并Bootloader和应用程序时,需要谨慎操作并正确理解程序内部的所有细节。对于初学者,建议多阅读有关Linker脚本、芯片体系结构和在线更新工具等方面的文档。只要掌握了一定的知识,合并两个程序是相对容易的。 ### 回答3: 合并STM32bootloaderapp程序可以通过以下步骤完成: 第一步:准备工作。需要在开发板上安装bootloader程序app程序,并确保它们可以正常工作。 第二步:将app程序复制到bootloader程序空间。要将app程序复制到bootloader程序空间,需要使用类似于bootloaders的工具,如Jtag和swd调试工具。此时,需要打开读写权限。通过这种方式,可以将app程序的bin文件复制到bootloader程序的空间。 第三步:在bootloader程序添加升级代码。为实现升级功能,需要在bootloader程序的代码添加升级代码。升级代码会扫描设备的特定区域,找到新的app程序,并将其加载到设备。在加载新的app程序时,需要保证其正确性。 第四步:设置跳转指令。当app程序加载到设备时,需要跳转到app程序的入口点。这可以通过添加跳转指令或在app程序入口处添加向bootloader程序的跳转指令来完成。 综上所述,合并STM32bootloaderapp程序需要在开发板上安装bootloader程序app程序,并确保其可以正常工作。然后,将app程序复制到bootloader程序空间,并添加升级代码。最后,设置跳转指令以确保设备可以跳转到app程序的入口点。完成以上步骤后,实现STM32bootloaderapp程序的合并。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值