STM32的串口IAP简单Demo

平台芯片:STM32F407

IDE软件: Keil 5.25

目录

1. IAP简介

2. APP程序编写

3. Boolloader程序编写

4. 下载实验


 

1. IAP简介

IAP就相当于一个用户自定义的bootloader,这样一来,芯片上就有两个bootloader,。另一个是用户自定义的,用户可以在程序运行的过程中对内部flash部分的区域进行烧写,主要用于产品发布后,固件程序进行更新升级。因此设计固件程序时需要编写两个项目代码:

第一个是bootloader程序,主要通过外设通信(UART、USB、ETH、SD卡等)来接收程序或数据,这段程序通过JLINK或者ISP烧入;

第二个称为APP程序。这段程序根据地址的不同,可以放在SRAM段和FLASH段。若放在FLASH段,一般从最低地址区开始存放BootLoader,接着是APP 程序。若放在SRAM段,则将SRAM分为三部分,第一部分给Bootloader使用,第二部分给APP程序使用,第三部分用作为APP程序的内存。


2. APP程序编写

主要是初始化LED和串口,指示程序运行的作用。

注意:语句SCB->VTOR = FLASH_BASE | 0x10000 可以实现中断向量表的起始地址的重设。0x10000 大小要和APP程序偏移量对应

#include "sys.h"
#include "delay.h"  
#include "usart.h"   
#include "led.h"

int main(void)
{ 
	SCB->VTOR = FLASH_BASE | 0x10000; //实现中断向量表的起始地址的重设
	delay_init(168);    //初始化延时函数
	uart_init(460800);  //初始化串口波特率为 460800
	LED_Init();       //初始化LED 

	while(1)
	{
		delay_ms(1000);
		GPIO_ToggleBits(GPIOA,GPIO_Pin_8);
		printf("The APP code is running \r\n");
	}
}

我这里APP程序执行的起始地址为)0x801000, 大小预留为 0xF0000

然后生成 .bin文件。

keil配置生成bin文件过程可以参考博客:

https://blog.csdn.net/BFDX0017/article/details/104811097

 


3. Boolloader程序编写

参考原子的教程

接收到的串口数据(即APP代码)写入到FLASH中

//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize) //将接收到的数据写入到Flash中
{
	u32 t;
	u16 i=0;
	u32 temp;
	u32 fwaddr=appxaddr;//当前写入的地址
	u8 *dfu=appbuf;
	for(t=0;t<appsize;t+=4)
	{						   
		temp=(u32)dfu[3]<<24;   
		temp|=(u32)dfu[2]<<16;    
		temp|=(u32)dfu[1]<<8;
		temp|=(u32)dfu[0];	  
		dfu+=4;//偏移4个字节
		iapbuf[i++]=temp;	    
		if(i==512)
		{
			i=0; 
			STMFLASH_Write(fwaddr,iapbuf,512);
			fwaddr+=2048;//偏移2048  512*4=2048
		}
	} 
	if(i)  
		 STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.  
}

IAP跳转至APP程序函数

//跳转到应用程序段;  实现 IAP -> APP 的跳转
//appxaddr:用户代码起始地址.
void iap_load_app(uint32_t  appxaddr)
{
	if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)	//检查栈顶地址是否合法.
	{ 
		//函数指针
		jump2app = (iapfun)*(vu32*)(appxaddr+4);	//用户代码区第二个字为程序开始地址(复位地址)		
		MSR_MSP(*(vu32*)appxaddr);					//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		jump2app();									//跳转到APP.
	}
}	

 

整体程序实现:

思路是:根据串口接收计数变量判断是否接受完整个APP文件数据,接收完之后就可以串口缓存的APP程序写入FLASH,然后跳转至APP执行。

我的示例代码如下:

int main(void)
{ 
	
	uint16_t oldcount=0;	//老的串口接收数据值
	uint16_t applenth=0;	//接收到的app代码长度
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);    //初始化延时函数
	uart_init(460800);  //初始化串口波特率为 460800
	LED_Init();         //初始化LED 

	while(1)
	{
//		delay_ms(500);
//		printf("Hello \r\n");
		
		  delay_ms(100);
		  GPIO_ToggleBits(GPIOA,GPIO_Pin_8);
		
			if(USART_RX_CNT) //接收到数据
			{
				if(oldcount == USART_RX_CNT) //新周期内,没有收到任何数据,认为本次数据接收完成.
				{
					applenth = USART_RX_CNT;
					oldcount = 0;
					USART_RX_CNT = 0; //计数清零
					printf("用户程序接收完成!\r\n");
					printf("代码长度:%dBytes\r\n", applenth);
				}
				else //数据有变化,继续接收
				  oldcount = USART_RX_CNT;			
			}
		  //有数据接收过来
			if(applenth)
			{
					iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth); //更新FLASH中的APP代码   
					printf("固件更新完成!\r\n");
					oldcount =0;
					
					printf("开始执行FLASH用户代码!!\r\n");
					iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
			}
		
	}
}

 


4. 下载实验

打开串口助手,波特率设置和bootloader一致,打开文件(即前面生成的APP的.bin文件),发送文件

发送完成后可以看到,APP程序开始运行了


以上就完成了IAP程序的最简单移植,更可靠的细节需要根据项目要求不断优化。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值