32单片机开发bootloader程序

一,单片机为什么要使用bootloader

1、使用bootloader的好处

         1) 程序隔离:可以同时存在多个程序,只要flash空间够大,或者通过外挂flash,可以实现多个程序共存,在多个程序之间切换使用。

        2)方便程序升级和后期维护:多个程序相互独立运行,可以在一个程序对另一个程序更新,普通单片机程序只能通过isp或者jtag、swd等调试接口实现程序烧录。而使用bootloader程序则可以通过usart、485、can、iic、spi、sd、4g、wifi卡等等任意可以实现数据传输的通信方式进行设备ota升级,也不必必须依赖烧录器。

2、不建议使用bootloader的原因

        1)占用flash空间:多一个程序必然会多占一部分flash空间。

        2)增加程序烧录的步骤:项目量产时出厂烧录程序会不太方便。

       

二、设计要点

        使用bootloader至少需要开发两个程序,也就是创建两个工程,一个bootloader程序,一个应用程序;bootloader程序负责初始化部分硬件,提供一些通信方式实现应用程序的ota功能;如果有多个应用程序在bootloader程序内需要对应用程序进行启动选择。

        1、flash分区,两个程序要想不相互影响,需要将两个程序烧录到flash的不同位置

        2、flash编程,要实现程序ota功能,需要提供对单片机flash的编程功能。

        3、初始化通信接口,规定ota协议。

        4、配置中断向量表地址。

        5、配置堆栈地址

        5、跳转应用程序地址。

三、工程配置

        1、bootloader程序flash地址配置

        

        2、app程序flash地址配置

        

四、关键函数代码

        1、Flash编程函数

                不同单片机flash编程函数也不一样,可以自行修改,这里只提供实现思路。

#define FMC_PAGE_SIZE           ((uint16_t)0x800U)
uint8_t fmc_tmp_page[FMC_PAGE_SIZE];void flash_program(uint32_t addr,uint8_t *data,uint16_t size)
{uint32_t prog_addr = (uint32_t)addr;uint8_t * data_addr = data;uint16_t i,j;uint16_t pages;uint16_t pg_idx = 0;uint16_t wr_size = size;uint32_t * pdata;uint32_t * pobj = (uint32_t *)fmc_tmp_page;if(size == 0){return;}else if(size < FMC_PAGE_SIZE-prog_addr%FMC_PAGE_SIZE){pages = 1;}else{pages = 1+(size-prog_addr%FMC_PAGE_SIZE+FMC_PAGE_SIZE-1)/FMC_PAGE_SIZE;}/* unlock the flash program/erase controller */fmc_unlock();/* clear all pending flags */fmc_flag_clear(FMC_FLAG_BANK0_END);fmc_flag_clear(FMC_FLAG_BANK0_WPERR);fmc_flag_clear(FMC_FLAG_BANK0_PGERR);for(i=0;i<pages;i++){pg_idx = prog_addr%FMC_PAGE_SIZE;prog_addr = prog_addr/FMC_PAGE_SIZE*FMC_PAGE_SIZE;pdata = (uint32_t*)prog_addr;wr_size = FMC_PAGE_SIZE-pg_idx<size?FMC_PAGE_SIZE-pg_idx:size;size -= wr_size;for(j=0;j<FMC_PAGE_SIZE/4;j++){pobj[j]=*pdata;pdata++;}for(j=pg_idx;j<wr_size+pg_idx;j++){fmc_tmp_page[j]=*(data_addr);data_addr++;}fmc_page_erase(prog_addr);/* clear all pending flags */fmc_flag_clear(FMC_FLAG_BANK0_END);fmc_flag_clear(FMC_FLAG_BANK0_WPERR);fmc_flag_clear(FMC_FLAG_BANK0_PGERR);/* program flash */for(j=0;j<FMC_PAGE_SIZE/4;j++){fmc_word_program(prog_addr+j*4, pobj[j]);fmc_flag_clear(FMC_FLAG_BANK0_END);fmc_flag_clear(FMC_FLAG_BANK0_WPERR);fmc_flag_clear(FMC_FLAG_BANK0_PGERR);}prog_addr += FMC_PAGE_SIZE;}/* lock the main FMC after the erase operation */fmc_lock();
}

        2、修改中断向量表地址

                部分单片机库函数未提供修改向量表地址函数,这里我自己模仿写了个。

void BootLoader_SetVectorTable(uint32_t NVIC_VectTab,uint32_t Offset)
{SCB->VTOR =  NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
}

        3、修改主堆栈地址

                  网上很多实现都过于复杂,写了一大堆汇编代码,我这里只尽量只用c语言的方式去实现,便于理解与调用。

void BootLoader_MSP(uint32_t addr)
{__ASM volatile("LDR	r2, [addr]");__ASM volatile("MSR	msp, r2");
}

        4、跳转应用程序

                一个函数完成所有功能。

void BootLoader_App_Startup(uint32_t offset)
{application_t app;uint32_t msp_addr = (FLASH_BASE|offset);uint32_t * entry_addr = (uint32_t *)(FLASH_BASE|offset|0x4);app = (application_t)*entry_addr;BootLoader_SetVectorTable(FLASH_BASE,offset);BootLoader_MSP(msp_addr);app();
}

        5、使用例程

#define APP_OFFSET_ADDR		0x10000int main(void)
{Debug_UartCfg();while(1){delay_ms(500);debug_printf("hello,0x%x!\r\n",123);BootLoader_App_Startup(APP_OFFSET_ADDR);}
}

 

五、关键库全部代码

        

//bootloader.c#include "bootloader.h"#define FMC_PAGE_SIZE           ((uint16_t)0x800U)
uint8_t fmc_tmp_page[FMC_PAGE_SIZE];void BootLoader_MSP(uint32_t addr)
{__ASM volatile("LDR	r2, [addr]");__ASM volatile("MSR	msp, r2");
}void BootLoader_SetVectorTable(uint32_t NVIC_VectTab,uint32_t Offset)
{SCB->VTOR =  NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
}void BootLoader_App_Startup(uint32_t offset)
{application_t app;uint32_t msp_addr = (FLASH_BASE|offset);uint32_t * entry_addr = (uint32_t *)(FLASH_BASE|offset|0x4);app = (application_t)*entry_addr;BootLoader_SetVectorTable(FLASH_BASE,offset);BootLoader_MSP(msp_addr);app();
}void flash_program(uint32_t addr,uint8_t *data,uint16_t size)
{uint32_t prog_addr = (uint32_t)addr;uint8_t * data_addr = data;uint16_t i,j;uint16_t pages;uint16_t pg_idx = 0;uint16_t wr_size = size;uint32_t * pdata;uint32_t * pobj = (uint32_t *)fmc_tmp_page;if(size == 0){return;}else if(size < FMC_PAGE_SIZE-prog_addr%FMC_PAGE_SIZE){pages = 1;}else{pages = 1+(size-prog_addr%FMC_PAGE_SIZE+FMC_PAGE_SIZE-1)/FMC_PAGE_SIZE;}/* unlock the flash program/erase controller */fmc_unlock();/* clear all pending flags */fmc_flag_clear(FMC_FLAG_BANK0_END);fmc_flag_clear(FMC_FLAG_BANK0_WPERR);fmc_flag_clear(FMC_FLAG_BANK0_PGERR);for(i=0;i<pages;i++){pg_idx = prog_addr%FMC_PAGE_SIZE;prog_addr = prog_addr/FMC_PAGE_SIZE*FMC_PAGE_SIZE;pdata = (uint32_t*)prog_addr;wr_size = FMC_PAGE_SIZE-pg_idx<size?FMC_PAGE_SIZE-pg_idx:size;size -= wr_size;for(j=0;j<FMC_PAGE_SIZE/4;j++){pobj[j]=*pdata;pdata++;}for(j=pg_idx;j<wr_size+pg_idx;j++){fmc_tmp_page[j]=*(data_addr);data_addr++;}fmc_page_erase(prog_addr);/* clear all pending flags */fmc_flag_clear(FMC_FLAG_BANK0_END);fmc_flag_clear(FMC_FLAG_BANK0_WPERR);fmc_flag_clear(FMC_FLAG_BANK0_PGERR);/* program flash */for(j=0;j<FMC_PAGE_SIZE/4;j++){fmc_word_program(prog_addr+j*4, pobj[j]);fmc_flag_clear(FMC_FLAG_BANK0_END);fmc_flag_clear(FMC_FLAG_BANK0_WPERR);fmc_flag_clear(FMC_FLAG_BANK0_PGERR);}prog_addr += FMC_PAGE_SIZE;}/* lock the main FMC after the erase operation */fmc_lock();
}

//bootloader.h#ifndef		_BOOTLOADER_H_
#define		_BOOTLOADER_H_#include "gd32f30x.h"typedef	void (*application_t)(void);void BootLoader_MSP(uint32_t addr);void BootLoader_SetVectorTable(uint32_t NVIC_VectTab,uint32_t Offset);void BootLoader_App_Startup(uint32_t addr);#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/50287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI 常见的函数详解(二)

引言 前面一篇文章OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI&#xff08;一&#xff09;介绍了NAPI的基础理论知识&#xff0c;今天重点介绍下NAPI中重要的函数。 一、Native 侧的NAPI的相关的C函数 以下面一段代码为例介绍下主要函数的功能和用法。 napi_value …

系统模块时序图的重要性:解锁系统模块交互的全景视图

在复杂的系统开发中,理解和管理不同模块之间的交互是成功的关键。时序图是一种有效的工具,可以帮助我们清晰地展示这些交互,提升设计和开发的效率。本文将深入探讨系统模块之间的时序图,并通过实例展示其实际应用。 1. 什么是系统模块之间的时序图? 系统模块之间的时序图…

Layui表格向下滑动时表头固定悬浮

记录&#xff1a;Layui表格向下滑动时表头固定悬浮 使用table的height参数&#xff1a; 示例 //“方法级渲染”配置方式 table.render({ //其它参数在此省略height: 315 //固定值 }); table.render({ //其它参数在此省略height: full-20 //高度最大化减去差值 }); 等价于&am…

项目的小结

1.实现实时聊天 1.服务端建立一个ConcurrentHashMap<> 用来存储在线用户&#xff0c;用户账号和socket然后&#xff0c;如果有个人发了信息&#xff0c;就去数据库中查询&#xff0c;然后根据这个在线用户进行传递信息 服务端框架&#xff1a; public class ServerMain {…

git sendemail使用

教程参考&#xff1a; git-send-email - 以电子邮件形式发送补丁集 1、安装git-email 2、配置 SMTP 服务器 git config --global sendemail.smtpserver smtp.163.com git config --global sendemail.smtpserverport 465 git config --global sendemail.smtpuser xxxxxx163.c…

Hyperledger Fabric 网络体验 - 网络启动过程概览

进入fabric-samples/test-network目录&#xff0c;执行指令&#xff1a; ./network.sh up -i 2.5执行完指令能看到fabric已经启动。 作为第一次Fabric网络体验&#xff0c;网络启动主要包含三个操作&#xff0c;分别是生成配置文件、启动网络和操作网络。 配置文件 使用cr…

传知代码-智慧医疗:纹理特征VS卷积特征(论文复现)

代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 论文链接&#xff1a;https://www.sciencedirect.com/science/article/abs/pii/S1076633223003537?__cf_chl_rt_tkJ9Aipfxyk5d.leu48P20ePFNd4B2aunaSmzVpXCg.7g-1721292386-0.0.1.1-6249 论文概述 今天我们把视线…

【系统架构设计师】十八、信息系统架构设计理论与实践②

目录 四、企业信息系统的总体框架 4.1 战略系统 4.2 业务系统 4.3 应用系统 4.4 企业信息基础设施 4.5 业务流程重组BPR 4.6 业务流程管理BPM 五、信息系统架构设计方法 5.1 行业标准的体系架构框架 5.2 架构开发方法 5.3 信息化总体架构方法 5.4 信息化建设生命周…

Golang | Leetcode Golang题解之第290题单词规律

题目&#xff1a; 题解&#xff1a; func wordPattern(pattern string, s string) bool {word2ch : map[string]byte{}ch2word : map[byte]string{}words : strings.Split(s, " ")if len(pattern) ! len(words) {return false}for i, word : range words {ch : patt…

【知识分享】MIPI C-PHY 互连技术参数定义

目录 0 概述 1 Interconnect Specifications 1.1 Differential Insertion Loss 1.2 Differential Reflection Loss 1.3 Common-Mode Reflection Loss 1.4 Intra-Lane Cross Coupling 1.5 Mode-Conversion Loss 1.6 Inter-Lane Static Skew 2 Driver and Receiver Char…

好的STEM编程语言有哪些?

STEM是科学&#xff08;Science&#xff09;&#xff0c;技术&#xff08;Technology&#xff09;&#xff0c;工程&#xff08;Engineering&#xff09;&#xff0c;数学&#xff08;Mathematics&#xff09;四门学科英文首字母的缩写&#xff0c;STEM教育简单来说就是在通过在…

【管控业财一体化】

1. 引言 大型集团在现代企业管理中扮演着举足轻重的角色&#xff0c;其管控业财一体化解决方案是实现企业高效运营的关键。随着数字化转型的加速&#xff0c;业财一体化不再局限于财务与业务流程的简单融合&#xff0c;而是向着更深层次的数据驱动、智能化决策和价值创造方向发…

SpringMVC中的常用注解

目录 SpringMVC的定义 SpringMVC的常用注解 获取Cookie和Session SpringMVC的定义 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它…

百某应JS逆向

https://ying.baichuan-ai.com/ 目录 一、发起提问 二、观察发现有两个加密参数&#xff1a;X-Bc-Sig和X-Bc-Ts ​三、观察JS调用栈 四、从JS中搜索 X-Bc-Sig和X-Bc-Ts 五、断点并分析参数的生成方式 六、分析入参 七、发现关键的o方法调用了一个i()方法 八、验证结果 …

前后端项目打包对比——关于Spring Boot Maven Plugin配置的问题

Spring Boot Maven Plugin 配置详解 Spring Boot Maven Plugin 配置详解1. 添加插件到 pom.xml2. 插件配置2.1 基本配置2.2 配置参数详解默认行为说明简单配置示例为什么这样的配置能工作&#xff1f;进一步说明 2.3 高级配置 3. 使用插件打包应用程序3.1 打包成 JAR 文件3.2 打…

ElasticSearch(六)— 全文检索

一、match系列查询 前面讲到的query中的查询&#xff0c;都是精准查询。可以理解成跟在关系型数据库中的查询类似。match系列的查询&#xff0c;是全文检索的查询。会通过分词进行评分&#xff0c;匹配&#xff0c;再返回搜索结果。 1.1 match 查询 "query": {&qu…

c++笔记4

目录 深度优先搜索DFS DFS的复杂度 DFS与递归 递归与暴力枚举 递归树 DFS与栈 DFS的搜索剪枝 搜索剪枝与优化 可行性剪枝 最优化剪枝 减少等效的分支 优化搜索顺序 搜索的记忆化 搜索的复杂度 大多时候&#xff0c;搜索的复杂度都是指数级的。各种剪枝方案&#…

Flink 技术与应用(一)

Flink技术与应用&#xff08;初级篇&#xff09; 起源 Apache Flink 是一个开源的大数据处理框架&#xff0c;其起源可以追溯到一个名为 Stratosphere 的研究项目&#xff0c;旨在建立下一代大数据分析引擎&#xff0c;2010 年&#xff0c;从 Stratosphere 项目中分化出了 Fl…

「Unity3D」场景中的距离单位Unit与相关设置PixelsToUnits、PixelsPerUnit

GameObject在场景的位置Position&#xff0c;并没有明确是什么具体单位——如&#xff1a;Transform的x、y、z&#xff0c;或RectTransform的PosX、PosY、PosZ。而RectTransform在面板上显示的Width和Height&#xff0c;也没有具体单位&#xff0c;其实并不是像素。 事实上&am…

百易云资产管理运营系统 comfileup.php 文件上传致RCE漏洞复现(XVE-2024-18154)

0x01 产品简介 百易云资产管理运营系统,是专门针对企业不动产资产管理和运营需求而设计的一套综合解决方案。该系统能够覆盖资产的全生命周期管理,包括资产的登记、盘点、评估、处置等多个环节,同时提供强大的运营分析功能,帮助企业优化资产配置,提升运营效率。 0x02 漏…