目录:
一、用UART方式实现IAP功能须知:
二、A、B工程具体功能为:
三、A、B工程代码分析:
四、NOTE:
五、该方式的不足:
一、用UART方式实现IAP功能须知:
需要两个工程文件。
一个作为初始工程,为了方便,我们叫A工程(bootloader);一个用于生成BIN文件的工程,我们叫B工程(可用于升级)。
二、
A、B工程具体功能为:
A工程的功能:
检测升级条件是否被触发(可通过按键是否被按下、串口是否接收到特定的数据、U盘是否插入等等),
如果有, 则进行对user application(app区域)进行擦除和重新写入操作,
如果没有,则直接跳转到user application执行应用。
B工程的功能:
可升级A工程,应该用此工程制作出BIN文件,进而通过串口方式升级A工程。
三、A、B工程代码分析:
3.1、
A工程代码分析(只分析main函数和定时中断函数):
int main(void)
{
LED_INIT(); //通过LED的状态验证升级是否成功。
//通过串口由PC发送升级BIN文件(MCU接收且将升级数据写入FLASH中)、通过串口软件显示从FLASH中读出的数据是否正确。
USART_Config();
KEY_Init(); //上电之前按着按键KEY1触发升级功能。
TIMER_Init(); //产生并进入中断,控制LED以不同方式闪烁,验证升级是否成功。
printf("\r\n -------系统已启动!------ \r\n");
LED1 = 0;
LED1 = !LED1;
while (1)
{
//若按下按键KEY1,触发进入更新FLASH的操作。
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == RESET)
{
Erase_SpecifiedPage(); //擦除APP区域。
//接收 NBR_UPDATEDATA 个字节的升级数据。
//(115200的波特率,每接收两个字节后进行一次FLASH半字写入)。
ReceiveUpdateData(NBR_UPDATEDATA);
//延时以方便此时及时更改串口软件的配置,改为 HEX格式 以方便看数据。
printf("5S后发送读出的数据,请及时先清屏再将显示格式改为Hex格式。。 \r\n");
Delay_ms_72MHz(5000);
//将写入的升级数据全部读出以检视数据是否正确。
Read_FLASH(ApplicationAddress, NBR_UPDATEDATA);
}
//若不按下按键,则执行app区域程序。
else
{
//若第一次执行且不触发升级操作,APP区域无数据,所以会无任何功能;若触发升级操作且升级成功,
则进入APP区域执行功能,下次复位会继续执行APP功能。
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
{
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}
}
}
}
void TIM2_IRQHandler(void)
{
static u8 Timer_Indictor_SYSOK = 0;
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
{
TIM_ClearITPendingBit(TIM2 , TIM_IT_Update); //清中断标志位。
Timer_Indictor_SYSOK++;
if(Timer_Indictor_SYSOK == Timer_Indictor_SYSOK_PERIOD)
{
Timer_Indictor_SYSOK = 0;
LED1 = !LED1; //LED1以1S的周期闪烁。
}
}
}
3.2、
B工程代码分析(只分析main函数和定时中断函数):
int main(void)
{
//将APP程序的中断向量表进行偏移设置。定位到0x08004000处。
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x4000);
LED_INIT();
USART_Config();
KEY_Init();
TIMER_Init();
printf("\r\n IAP升级已成功!开始运行新程序。\r\n"); //提示新程序已正常运行。
printf("\r\n -----新系统已启动!------ \r\n");
LED1 = 0;
LED2 = 0;
while (1);
}
void TIM2_IRQHandler(void)
{
static u8 Timer_Indictor_SYSOK = 0;
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
{
TIM_ClearITPendingBit(TIM2 , TIM_IT_Update); //清中断标志位。
Timer_Indictor_SYSOK++;
if(Timer_Indictor_SYSOK == Timer_Indictor_SYSOK_PERIOD)
{
Timer_Indictor_SYSOK = 0;
LED1 = !LED1; //LED1以1S的周期闪烁。
LED2 = !LED2; //LED2以1S的周期闪烁。
}
}
}
四、NOTE:
4.1、
本应用是通过MDK-KEIL实现的,用到的MCU为STM32F103C8T6,调试器为ST-LINK。
4.2、
本程序成功地实现了IAP功能。将BIN文件下载到FLASH内并执行新功能。
本程序(即原始程序)的功能:LED1以1S的频率闪烁。
BIN文件的功能: LED1、LED2以1S的频率闪烁。
4.3、
具体实现方法:
当板子开始上电即程序开始运行前,按着KEY1按键,然后上电,此时有提示:擦除完毕,请发送升级数据。
发送BIN文件,然后有提示:已经接收完毕升级数据并写入FLASH中,稍后读出升级数据。
当读出数据后(可通过串口软件查看数据是否正确),新程序开始运行(通过观看LED状态知升级成功)。
4.4、
对于A工程:
跟普通程序一样,设置KEIL中魔术棒中的target中勾选IROM1,并配置其后的数据为 0x08000000,即程序定位在FLASH的最开始处(IAP程序)。
对于B工程:
当作为一般文件时,跟普通程序一样,注意:此时可正常调试。
当作为升级文件时,注意:不能正常调试,只能作为升级文件使用(我们要将其作为升级文件)。
其需要修改的地方:
1. 在其程序开始处,添加中断偏移设置,即:NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x4000);(0x4000,可根据实际情况调节。)
2. 在魔术棒中的target中勾选IROM1,并配置其后的数据为 0x08004000 (对应上面) 。其他无需修改。
3. 关于如何生成BIN文件,参看BIN文件生成方法。
0x080000处 0x08004000处
--------------------------------------------------------------------------------
|IAP区域。。。。。。|APP区域。。。。。。。。。。。。。。。|
--------------------------------------------------------------------------------
五、该方式的不足:
出厂前必须先烧录IAP引导程序,再通过串口方式升级代码至出厂时需要的功能(麻烦!)。
若只烧录IAP引导程序,无任何功能!
有没有更好的IAP方式,待研究。
六、待完善。