32单片机开发bootloader程序

news2024/11/15 18:23:42

一,单片机为什么要使用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		0x10000

int 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.coloradmin.cn/o/1956703.html

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

相关文章

python-小李帮老师改错(赛氪OJ)

[题目描述] 老师给小理发了一封电子邮件&#xff0c;任务如下。 写一个程序&#xff0c;给你 n 个数&#xff0c;输出 X。Xnum1p1​​num2p2​​⋯numnpn​​。 num1​&#xff0c;num2​&#xff0c;⋯⋯&#xff0c;numn​ 都是整数&#x…

探索Python监控之眼:watchdog库深度解析

文章目录 探索Python监控之眼&#xff1a;watchdog库深度解析1. 引言&#xff1a;为何选择watchdog&#xff1f;2. watchdog简介3. 安装watchdog库4. 基本函数与使用方法4.1 初始化监控器4.2 监控文件的创建4.3 监控文件的删除4.4 监控目录的创建4.5 监控目录的删除 5. 场景应用…

神奇的方法解决Navicat闪退

原因 打开Navicat操作上面的工具等就会闪退&#xff0c;原因竟然是屏幕划词&#xff01;&#xff01;&#xff01; 解决方法 看别人提到有道词典的划词功能的原因 我没有安装有道词典&#xff0c;但我安装豆包&#xff0c;它也有划词翻译的功能&#xff0c;关闭即可

【JAVA】记录一次前端无能造成的 线上bug

有一个需求是 当方式切换 垫资时 清空 当前所选细单商品 但是前端的奇葩 操作是&#xff0c;只是在页面上清空 细单。 不请求 后台删除 细单 让前端 必须 清空同时 请求后台 删除细单 但是 该前端 技术不行&#xff0c; 嫌麻烦 不做 只好 后台 判断该类型时 进行删除操作…

分省、地级市数字经济专利数据(1985-2022年)

数据年份&#xff1a;1985-2022年 参考文献&#xff1a;孙勇,张思慧,赵腾宇等.数字技术创新对产业结构升级的影响及其空间效应——以长江经济带为例[J].软科学,2022,36(10):9-16. 包含指标&#xff1a; 地级市数据&#xff1a;省份、地级市、会计年度、当年申请的数字经济相…

Java人力资源招聘社会校招类型招聘小程序

✨&#x1f4bc;【职场新风尚&#xff01;解锁人力资源招聘新神器&#xff1a;社会校招类型招聘小程序】✨ &#x1f393;【校招新体验&#xff0c;一键触达梦想企业】&#x1f393; 还在为错过校园宣讲会而懊恼&#xff1f;别怕&#xff0c;社会校招类型招聘小程序来救场&am…

懂个锤子Vue 项目工程化进阶⏫:

Vue项目工程化进阶⏫&#xff1a; 前言&#xff1a; 紧跟前文&#xff0c;目标学习Vue2.0——3.0&#xff1a; 懂个锤子Vue、WebPack5.0、WebPack高级进阶 涉及的技术栈… 当然既然学习框架的了&#xff0c;HTMLCSSJS三件套必须的就不说了&#xff1a; JavaScript 快速入门 …

最新EI期刊信息查询系统(如何查询EI期刊?这里已解决)

直接点击下面的链接 https://www.elsevier.com/products/engineering-village/databases/compendex 进入官网界面 这个列表就是EI索引的全部期刊列表

linux进程控制——进程创建、运行、exit终止——详解解析!

前言&#xff1a;本篇进入新章节——进程控制。 本章节和上一章节同样都是讲解进程&#xff0c; 但是内容上却比上一章内容好理解的多。上一章内容都是进程的概念性相关&#xff0c; 那个时候我们对于进程的理解还处于小白状态&#xff0c; 所以很多东西很抽象&#xff0c; 不好…

快速排序的优化--前后指针

前后指针思想 我们前面文章讲的核心思想是haroe的核心思想&#xff0c;将keyi另一边的指针先移动&#xff0c;找比keyi小的&#xff0c;然后不动&#xff0c;再让keyi这边的指针移动&#xff0c;找比keyi大的&#xff0c;但是这种方法的局限性就是需要让keyi另一边的指针先移动…

止损与趋势交易的艺术在昂首平台尽情绽放

在昂首平台上&#xff0c;我们认识到交易不仅仅是数字游戏&#xff0c;更是一门艺术&#xff0c;需要投资者智慧和策略。正如做生意一样。会以125的价格买入商品&#xff0c;然后再以250的价格卖出。没人会不切实际想着以0元的价格购买商品再以高价卖出。 交易同样需要合理的成…

云仓技术带来的物流变革影响

1、实时可视性&#xff1a; 云仓技术使物流公司能够实时跟踪和监控货物在供应链中的位置和状态。这种实时可视性提供了更好的货物追踪和管理能力&#xff0c;同时也提高了客户服务的质量。 ———————————————————— 2、仓储优化&#xff1a; 云仓技术可以…

【管理咨询宝藏145】多元化经营大型集团组织架构优化提升方案

【管理咨询宝藏145】多元化经营大型集团组织架构优化提升方案 【格式】PDF版本 【关键词】组织架构、人力资源、组织管控 【核心观点】 - 随着多元业务的发展&#xff0c; 公司逐步由百亿级企业向干亿级企业转变&#xff0c; 人才布局将面临一系列挑战 - 挑战1 :为支撑公司多业…

前端工程化-vue项目开发流程

vue项目创建参考该文&#xff1a; 前端工程化-vue项目创建-CSDN博客 组件就是页面的意思&#xff1b; 默认的App.vue根组件如下图 我们可以修改为如下图所示&#xff0c;注意script的选择&#xff0c; <html>中的标签&#xff0c;此处是放在<template>中&#…

[php7系列]--php7里的返回类型声明和标量类型声明及不要用isset判断数组是否定义某个KEY-最好使用array_key_exists

一、[php7系列]--php7里的返回类型声明和标量类型声明 php7里增加了返回类型声明和标题类型声明&#xff0c;可以理解为对一个方法的输入输出进行了类型验证&#xff0c;在PHP7之前&#xff0c;方法里的数组、对象参数是有类型声明的&#xff0c;但其它的整数、字符串等类型声明…

Idea设置自动导包

Idea设置自动导包 【File】→【Setting】(或使用快捷键【Crlt Shift S】)打开Setting设置。 点击【Editor】→【General】→【Auto Import】。勾选自定导包的选项&#xff0c;并确定&#xff0c;如下&#xff1a;

心大陆AI科学养育,共情陪伴孩子的幸福童年!

3-8岁是宝宝的关键期&#xff0c;在这个阶段也是父母最费心的时候&#xff1a;孩子吃饭、洗澡、睡觉总爱拖延、玩玩具三分钟热度、上课小动作多、语言能力弱&#xff0c;讲话不连贯容易暴怒、天性好奇&#xff0c;总有十万个为什么等等...... 这些情况在儿童早期发育阶段爸爸妈…

优思学院|如何透过客户忠诚度分析决定六西格玛改善项目?

客户忠诚度分析提供了一个框架&#xff0c;从而便于公司理解客户不再忠诚的原因&#xff0c;并做出相应的改善。客户忠诚度不仅是要关注现有的客户&#xff0c;还应包括已失去的客户。客户忠诚度研究有助于公司发现使客户转向竞争对手的有关客户服务、产品或可靠性等的一些问题…

论文阅读:A Survey on Evaluation of Large Language Models-鲁棒性相关内容

A Survey on Evaluation of Large Language Models 只取了鲁棒性相关的内容 LLMs&#xff1a;《A Survey on Evaluation of Large Language Models大型语言模型评估综述》理解智能本质(具备推理能力)、AI评估的重要性(识别当前算法的局限性设 对抗鲁棒性是衡量大型语言模型&…

C语言进阶 11.结构体

C语言进阶 11.结构体 文章目录 C语言进阶 11.结构体11.1. 枚举11.2. 结构类型11.3. 结构与函数11.4. 结构中的结构11.5. 类型定义11.6. 联合11.7. PAT11-0. 平面向量加法(10)11-1. 通讯录的录入与显示(10) 11.1. 枚举 常量符号化: 用符号而不是具体的数字表示程序中的数字 cons…