2、Bootloader部分
BootLoader的任务有两个,一是在串口中断接收BIN的数据和主循环内判断以及更新APP1的程序,二是在在程序开始的时候判断有没有可用的用户程序进而跳转到用户程序(程序A或者程序B)。
简单介绍下执行流程:
系统上电首先肯定是执行BootLoader程序的,因为它的起始地址就是0x08000000,首先是初始化,然后判断按键是否手动升级程序,按键按下了就把FLAG部分的APP标记写成0xFFFF(这里用的宏定义方式),再执行执行App_Check(),否则就直接执行App_Check()。
App_Check函数是来判断程序A和程序B的,最开始BootLoader是用swd方式下载的,下载的时候全片擦除,所以会执行主循环的Update_Check函数。此时串口打印出“等待接收APP1的BIN”,这个时候发送APP1的BIN过去,等接受完了,会写在FLAG区域写个0xAAAA,代表程序A写入了,下次启动可以执行程序A。
主要代码部分
#include "fy_includes.h"
/*
晶振使用的是16M 其他频率在system_stm32f10x.c中修改
使用printf需要在fy_includes.h修改串口重定向为#define PRINTF_USART USART1
*/
/*
Bootloader程序
完成三个任务
步骤1.检查是否有程序更新,如果有就擦写flash进行更新,如果没有进入步骤2
步骤2.判断app1有没有可执行程序,如果有就执行,如果没有进入步骤3
步骤3.串口等待接收程序固件
*/
#define FLAG_UPDATE_APP1 0xBBAA
#define FLAG_UPDATE_APP2 0xAABB
#define FLAG_APP1 0xAAAA
#define FLAG_APP2 0xBBBB
#define FLAG_NONE 0xFFFF
_loopList_s list1;
u8 rxbuf[1024];
u8 temp8[2];
u16 temp16;
u32 rxlen=0;
u32 applen=0;
u32 write_addr;
u8 overflow=0;
u32 now_tick=0;
u8 _cnt_10ms=0;
static void App_Check(void)
{
//获取程序标号
STMFLASH_Read(FLASH_PARAM_ADDR,&temp16,1);
if(temp16 == FLAG_APP1)//执行程序A
{
if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//可执行?
{
printf(" 执行程序A...\r\n");
IAP_RunApp(FLASH_APP1_ADDR);
}
else
{
printf(" 程序A不可执行,擦除APP1程序所在空间...\r\n");
for(u8 i=10;i<35;i++)
{
STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512);
}
printf(" 程序A所在空间擦除完成... \r\n");
printf(" 将执行程序B... \r\n");
if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//可执行?
{
printf(" 执行程序B...\r\n");
IAP_RunApp(FLASH_APP2_ADDR);
}
else
{
printf(" 程序B不可执行,擦除APP2程序所在空间...\r\n");
for(u8 i=35;i<60;i++)
{
STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512);
}
printf(" 程序B所在空间擦除完成...\r\n");
}
}
}
if(temp16 == FLAG_APP2)//执行程序B
{
if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//可执行?
{
printf(" 执行程序B...\r\n");
IAP_RunApp(FLASH_APP2_ADDR);
}
else
{
printf(" 程序B不可执行,擦除APP2程序所在空间... \r\n");
for(u8 i=35;i<60;i++)
{
STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512);
}
printf(" 程序B所在空间擦除完成... \r\n");
printf(" 将执行程序A... \r\n");
if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//可执行?
{
printf(" 执行程序A...\r\n");
IAP_RunApp(FLASH_APP1_ADDR);
}
else
{
printf(" 程序A不可执行,擦除APP1程序所在空间...\r\n");
for(u8 i=10;i<35;i++)
{
STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512);
}
printf(" 程序A所在空间擦除完成...\r\n");
}
}
}
if(temp16 == FLAG_NONE)
{
printf(" 擦除App1程序所在空间...\r\n");
for(u8 i=10;i<35;i++)
{
STMFLASH_Erase(FLASH_BASE + i*STM_SECTOR_SIZE,512);
}
printf(" 程序A所在空间擦除完成...\r\n");
}
}
static void Update_Check(void)
{
if(_list.Get_CanRead(&list1)>1)
{
_list.Read(&list1,&temp8,2);//读取两个数据
temp16 = (u16)(temp8[1]<<8) | temp8[0];
STMFLASH_Write(write_addr,&temp16,1);
write_addr+=2;
}
if(GetSystick_ms() - now_tick >10)//10ms
{
now_tick = GetSystick_ms();
_cnt_10ms++;
if(applen == rxlen && rxlen)//接收完成
{
if(overflow)
{
printf("接收溢出,无法更新,请重试 \r\n");
SoftReset();//软件复位
}
else
{
printf(" \r\n 接收BIN文件完成,长度为 %d \r\n",applen);
temp16 = FLAG_APP1;
STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1);//写入标记
temp16 = (u16)(applen>>16);
STMFLASH_Write(FLASH_PARAM_ADDR+2,&temp16,1);
temp16 = (u16)(applen);
STMFLASH_Write(FLASH_PARAM_ADDR+4,&temp16,1);
SoftReset();//软件复位
}
}else applen = rxlen;//更新长度
}
if(_cnt_10ms>=50)
{
_cnt_10ms=0;
Led_Tog();
if(!rxlen)
{
printf(" 等待接收App1的BIN文件 \r\n");
}
}
}
int main(void)
{
NVIC_SetPriorityGrouping( NVIC_PriorityGroup_2);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //禁止JTAG保留SWD
Systick_Configuration();
Led_Configuration();
Key_Configuration();
Usart1_Configuration(9600);
USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);//关闭串口空闲中断
printf(" this is bootloader!\r\n\r\n");
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == SET)
{
Delay_ms(100);
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == SET)//开机按下keyup进行更新
{
printf(" 主动更新,");
temp16 = FLAG_NONE;
STMFLASH_Write(FLASH_PARAM_ADDR,&temp16,1);
}
else
{
}
}
App_Check();
printf(" 执行BootLoader程序... \r\n");
_list.Create(&list1,rxbuf,sizeof(rxbuf));
write_addr = FLASH_APP1_ADDR;
while(1)
{
Update_Check();
}
}
//USART1串口中断函数
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
u8 temp = USART1->DR;
if(_list.Write(&list1,&temp,1)<=0)
{
overflow=1;
}
rxlen++;
}
}
其中的宏:
//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址
#define FLASH_APP1_ADDR STM32_FLASH_BASE+0x2800 //偏移10K
#define FLASH_APP2_ADDR STM32_FLASH_BASE+0x8c00 //偏移35K
#define FLASH_PARAM_ADDR STM32_FLASH_BASE+0xF000 //偏移60K
|