目录
2.获取RCC标志位。HAL库可以使用__HAL_RCC_GET_FLAG()这个宏判断程序复位的原因,根据原因执行对应操作
前言
本文编译环境为Truestudio,简单介绍STM32IAP升级的方法
一、IAP是什么?
IAP是In Application Programming的首字母缩写,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。
二、BootLoader程序流程
1.初始化需要用到的外设
2.获取RCC标志位。HAL库可以使用__HAL_RCC_GET_FLAG()这个宏判断程序复位的原因,根据原因执行对应操作
此处仅区分是软件复位与非软件复位,若为软件复位可以获取APP程序的完整性,然后跳转至APP
代码如下(示例):利用串口接收数据包并写入FLASH
void main(void)
{
/* MCU Configuration--------------------------------------------------------*/
ucSysInitOk = 0;
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
Phy_LedKeyInit();
Sys_TimeRst();
//Phy_LedDisplayBoot(0);
Comm_Init();
PHY_USART_INIT();
if(eShareBaudSel >USART_BAUD_115200)
{
eShareBaudSel = USART_BAUD_115200;
}
if(ucShareSlaveAddr >100)
{
ucShareSlaveAddr = 1;
}
#if RD_PROTECT_EN//暂时关闭读保护设置
Phy_FlashSetReadProtect(FALSE);
#endif
if(TRUE == Sys_StartMode()) //TRUE软件复位
{
Phy_UsartInit(USART1, eShareBaudSel, USART_8N2);
PHY_USART1_START_RECEIVE_IT();
Sys_ReceiveBin(1);//dn1
}else{ //上电启动
if(TRUE != Phy_FlashProgFlagCheck())
{
eShareBaudSel = USART_BAUD_115200;
ucShareSlaveAddr = 1;
Sys_ReceiveBin(2);//dn2
}else{
#if RD_PROTECT_EN//暂时关闭读保护设置
Phy_FlashSetReadProtect(TRUE);
#endif
Sys_JumpToApp();
}
}
}
跳转APP函数改自硬汉嵌入式论坛的发布的源码
/*
*__set_FAULTMASK(1);//
关闭所有中断,包括不可屏蔽中断,例如HardFalut
*__disable_irq();//关闭所有外设中断
*/
void Sys_JumpToApp()
{
unsigned char i=0;
void (*SysMemBootJump)(void);/* 声明一个函数指针 */
__IO unsigned long Addr;
Addr = FLASH_APP_ADDR;
__disable_irq(); /* 禁止全部外设中断 */
/* 关闭滴答定时器,复位到默认值 */
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
/* 设置所有时钟到默认状态,使用HSI时钟 */
HAL_RCC_DeInit();
/* 关闭所有中断,清除所有中断挂起标志 */
for (i = 0; i < 8; i++)
{
NVIC->ICER[i]=0xFFFFFFFF;
NVIC->ICPR[i]=0xFFFFFFFF;
}
/* 跳转到系统BootLoader,首地址是MSP,地址+
4是复位中断服务程序地址 */
SysMemBootJump = (void (*)(void)) (*((uint32_t *) (Addr + 4)));
/* 设置主堆栈指针 起始地址
第一个存放的32位数据为主堆栈指针*/
__set_MSP(*(uint32_t *)Addr);//
封装的C语言函数,将内核指令以C语言形式封装起来
/*
在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指
针 */
//__set_CONTROL(0);
/* 跳转到APP*/
SysMemBootJump();
}
3.APP程序
和普通的程序一样,不过是将APP的flash地址偏移至不占用BootLoader的flash的地址
偏移位置根据BootLoader实际大小决定。
便宜位置可以更改system_stm32f1xx.c 下的#define VECT_TAB_OFFSET 0x00000000U,注意偏移地址必须是0x200的倍数
4.BootLoader与APP共享内存的使用方法
此处仅以TRUESTUDIO软件为例
在ld文件内,
修改MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 63K
SHARE_RAM(xrw) : ORIGIN = 0x2000FC00, LENGTH = 1K/*可避免普通的变量内存分配至该区域*/
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 14K
}
添加 .shareram :
{
. = ALIGN(4); /*四字节对其*/
*(.share)
*(.share*)
*(.share1)
*(.share1*)
. = ALIGN(4);
} >SHARE_RAM AT> FLASH /* >SHARE_RAM 分配内存至该区域*/
定义共享全局变量
__attribute__((section(".share"))) USART_BAUD_SET eShareBaudSel;
__attribute__((section(".share1"))) unsigned char ucShareSlaveAddr;
5.产品信息指定地址
在ld文件内修改MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 63K
SHARE_RAM(xrw) : ORIGIN = 0x2000FC00, LENGTH = 1K
FLASH (rx) : ORIGIN = 0x8003800, LENGTH = 240K
DATA (rx) : ORIGIN = 0x803F800, LENGTH = 2K
}
修改.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = 0x400; /* 设置地址为0x400 */
. = ALIGN(4);
} >FLASH
添加 /*设置常量到指定地址*/
.deviceinfo :
{
*(.info) /* info段从.位置开启排列 */
. = ALIGN(4);
} >FLASH
定义常量数组 __attribute__((section(".info"))) const unsigned char ucInfo[8] = {0x00};//常量数组在bin文件的地址为0x400处
总结
前四步理想情况下够用,但为了避免用户程序烧录错误,因此需要APP程序内加入产品信息且指定地址,上位机烧录时需要匹配烧录的bin文件产品信息及下位机的产品信息,避免程序烧写错误。