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		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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值