• 单片机 MCU 固件打包脚本软件


    1 前言

    开发完 MCU 软件后,通常都会生成 hex 文件或者 bin 文件,用来做固件烧录或者升级,如果用来做产品开发,就涉及到固件版本的问题,初学者通常采用固件文件重命名来区分版本。

    如果需要将版本写入固件中,就需要通过一定的方式去实现,实现的方式有很多。


    2 介绍

    下面介绍一个自动打包单片机固件的脚本软件,主要实现以下功能:

    • 基于 Windows 平台的单片机 MCU 固件脚本打包工具
    • 支持 hex 文件的裁剪和 hex 文件的合并
    • 可以为 hex 固件添加版本信息、Git Commit 分支和提交记录等
    • 按照版本信息命名hex固件,可生成 bin 文件等
    • 以上均可通过 ini 配置文件设置参数对 hex 文件进行操作

    3 实现步骤

    下面以 MDK + STM32 开发为例介绍。

    3.1 __attribute__ 机制

    首先了解一下__attribute__机制,它是个编译器指令,告诉编译器声明的特性,或者让编译器进行更多的错误检查和高级优化。
    GUN C中可以使用__attribute__()给变量、函数和类型设置各种属性,而__attribute__的section选项可以改变段的特性;

    其中__attribute__((section("section_name")))的作用是将该定义的函数或数据变量放入指定名为”section_name”段中。

    无论是 GNU 还是 ARM 的编译器, 都支持__attribute__所指定的编译属性。

    打开keil的options…,取消勾选下图所示,然后点击“Edit…”。

    自动弹出“*.sct”文件(先编译通过再操作),下面就是 Keil 中 STM32 的链接文件,编译器会根据链接文件和__attribute__的section选项(可以自己添加一个段,分配地址和大小)等分配函数和数据变量在程序固件中的地址。

    copy
    ; *************************************************************
    ; *** Scatter-Loading Description File generated by uVision ***
    ; *************************************************************
    
    LR_IROM1 0x08000000 0x00010000  {    ; load region size_region
      ER_IROM1 0x08000000 0x00010000  {  ; load address = execution address
       *.o (RESET, +First)
       *(InRoot$$Sections)
       .ANY (+RO)
       .ANY (+XO)
      }
      RW_IRAM1 0x20000000 0x00005000  {  ; RW data
       .ANY (+RW +ZI)
      }
    }

    这里不做过多介绍了,下面介绍的方式不需要自己修改“*.sct”文件,还是采用__attribute__的section选项,只不过在section选项中指定位置即可。

    copy
    __attribute__ ((section(".ARM.__at_0x08000020")))

    3.2 代码实现

    1. 定义一个结构体,里面定义一些软件版本相关的信息

    copy
    typedef struct
    {
        char szVersion[32];    // 软件版本
        char szBuildDate[32];  // 程序编译日期
        char szBuildTime[32];  // 程序编译时间
        char szCommitId[32];  // git commit id
    }AppInfo_t;

    2. 通过__attribute__定义一个只读结构体变量(只读的目的:防止程序改变、节约RAM),赋初值(其中__DATE___TIME__是C语言中的内置宏,分别是当前的编译日期和编译时间)。

    copy
    const AppInfo_t __attribute__ ((section(".ARM.__at_0x08002000"))) sg_tAppInfo =
    {
        "STM32_TEST",
        __DATE__,
        __TIME__,
        ""
    };

    注:STM32的代码起始地址是从0x08000000开始的,且存储中断向量表信息,因此在选择程序地址的时候一定要绕开,也不能太靠后,不然生成的bin文件超出了实际的代码固件大小,在实现bin文件升级的时候就会耗时太长。

    3. 通过串口打印出来

    copy
    int main(void)
    {
        FML_USART_Init();
    
        USART_Printf(0, "Version  : %s\r\n", sg_tAppInfo.szVersion);
        USART_Printf(0, "buildTime: %s\r\n", sg_tAppInfo.szBuildDate);
        USART_Printf(0, "buildTime: %s\r\n", sg_tAppInfo.szBuildTime);
        USART_Printf(0, "commitId: %s\r\n\r\n", sg_tAppInfo.szCommitId);
    
        while(1);
    }

    4. 提交git编译后,可以看的 git commit id 值(通过 git commit 可以迅速定位是什么时候的源码进行编译的

    3.3 固件打包

    下载固件打包脚本,根据配置设置后,双击 bat 即可完成固件打包,然后点击下载验证即可。

    需要通过 J-LINK 工具包或者 ST-Link 工具打开生成的固件进行烧录(通过Keil编译直接下载的没有用,我这里用的是 ST-Link 工具)。


    4 配置文件内容

    下面列举配置文件中的选项

    copy
    ; 文中的路径可采用绝对路径或者相对路径(相对于固件打包bat文件而言)
    ; 版本信息 Flash 起始地址 预留大小 前缀字符串
    [version]
    addr=0x08002000
    size=32
    strPrefix=
    
    ; Git 信息 Flash 起始地址 预留大小
    [git_commit]
    addr=0x08002060
    size=32
    
    [boot_file]
    ; Boot Hex 文件路径 文件名称
    hexFilePath=.\
    hexFileName=test_boot
    
    [file]
    ; Hex 文件路径 文件名称
    hexFilePath=.\
    hexFileName=test
    
    ; 裁剪起始地址 保留大小
    hexFileAddr=0x08000000
    hexFileSize=0xFFFF
    
    ; 打包文件的输出路径
    outputPath=.\output
    
    [option]
    ; 是否合并boot固件
    isMergeBootHexFile=0
    
    ; 是否生成 Bin 文件
    isGenerateBin=1
    
    ; 是否裁剪 Hex 文件,根据(hexFileAddr hexFileSize)
    isCropHexFile=1
    
    ; 是否添加 Git Commit 信息
    isAddGitCommit=0
    
    ; 打包成功后是否清除临时文件
    isClearTmpFile=1
    折叠

    5 下载地址

    MCU固件打包脚本 

     

  • 相关阅读:
    STC15单片机-低功耗设计
    传统后端SQL数据层替代解决方案: 内置数据源+JdbcTemplate+H2数据库 详解
    STM32——04-初识STM32单片机
    C++ 多态
    各机构如何加强网络渗透、“渗透”防御
    东北大学金工实习考试题库
    面试官:vue的这些原理你了解吗?
    Dockerfile
    redis内存描述
    把苦难的时光删去:从小县城售货员到深圳IT白领的蜕变之路
  • 原文地址:https://www.cnblogs.com/const-zpc/p/16424933.html