1、 关闭所有中断再跳转APP
一般bootloader跳转到APP时要关闭app中用到的中断(防止中断打断程序的运行,导致程序跑飞),那么查看系统中用到的中断:串口中断、滴答定时器中断,所以,跳转之前要关闭这两个中断:_disable_irq()和systick。
void jumpToApp(void)
{if ( ( ( * ( __IO uint32_t * ) APPLICATIONADDRESS ) & 0x2FFE0000 ) == 0x20000000 ) //检查栈顶地址是否有数据,FLASH写入成功{LCD_ShowString(10,270,210,24,16,"Jumping to run program");//关闭必要中断SysTick->CTRL = 0X00;//禁止SysTickSysTick->LOAD = 0;SysTick->VAL = 0;__disable_irq();JumpAddress = *(__IO uint32_t*) (APPLICATIONADDRESS + 4);//用户代码区第二个字为程序开始地址(复位地址)Jump_To_Application = (pFunction) JumpAddress;//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)MSR_MSP(*(vu32*)APPLICATIONADDRESS); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)RCC_AHB2PeriphClockCmd( RCC_AHB2Periph_OTG_FS , DISABLE); //必须失能USB,不然后续代码会因为USB卡死Jump_To_Application();}
}
更新的程序主函数中需要再次使能中断
SCB->VTOR = 0x08000000|0x60000;__enable_irq(); /* 使能总中断 */
2、时钟不匹配问题
我遇到的情况是由于bootload和APP两个代码的时钟源不匹配导致app不运行。bootload用了内部时钟,APP用了外部8M时钟。导致跳转到APP代码时运行到时钟配置就卡死,而时钟没配置成功就无法初始化IO口,也没法发出信号做出提示,看着像app区的代码不运行,但其实还是运行了的。时钟初始化不成功卡死,设置了看门狗,这个时候就会复位。
处理方式:将bootload和APP的时钟源配置成相同的。
3、初始化外设卡死
解决办法:将外设注销,恢复初始化之前的状态,但也有很大的可能性在APP卡死。
4、IAP跳转最佳思路
在IAP中,判断是否需要跳转APP,需要跳转就在Flash中一个固定地址写入一个标志,我这里就假设写入地址为0x080F FF00,写入标志位0x5555,两个字节的标志位数据。然后执行以下函数,这里就是最经典的一步,复位操作,复位可以让运行环境变得很干净,也不用管哪些外设需要关掉。
void SoftReset(void)
{__set_FAULTMASK(1); // 关闭全部中断NVIC_SystemReset(); // 复位
}int main()
{/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init */if (STMFLASH_Read_One_DWord(JUMP_FLG_ADDR) == 1){iap_jump_app();}//1、读JUMP_FLG_ADDR标志 = 0,不需要跳转,则运行升级程序//2、升级程序,写入到FLASH中,写JUMP_FLG_ADDR标志 = 1//3、SoftReset();//4、读JUMP_FLG_ADDR标志 =1,跳转app程序,但此时的环境是:没有初始化任何外设,没有初始化任何时钟,所以不会出现一些莫名奇妙的卡死问题
}
通过这种方法跳转到APP,是不会出现时钟配置卡死,和外设初始化卡死的现象,特别注意的是,在进入APP之后一定要第一时间将IAP跳转标志清除,否则下一次升级时无法正常运行IAP。
/* USER CODE BEGIN 1 */SCB->VTOR = 0x8010000;/* USER CODE END 1 *//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init */iap_clear_flag(JUMP_FLG_ADDR);
5、MCU的内部FLASH擦写寿命
测试的flash型号是sst39vf160,由于测试时间的问题,只测试了一个扇区4个字节,用了整整一个星期才完成所有测试,测试结果总结如下:
1、flash有寿命限制,sst39vf160手册上说是10万次,实验片的实测却超过80万次。
2、每一个位的寿命是独立的,也就是说,一个字节的bit0失效了,bit1仍然可以正常操作。
3、flash的寿命指的是被改写的次数,如果一次擦除或写操作不改变某一个位的内容,该位就不会被磨损。比如一个字节被反复执行“擦除-写入0xfe”操作,把bit0损坏后,该字节高7位的寿命丝毫不受影响。
4、flash磨损后,总是表现为擦除不干净,多擦除几次又能够擦干净,随着磨损程度的加剧,越来越难以擦除干净,但只要擦干净了,写入一定是正确的。但写入的数据是否牢固就没有办法测了。
5、只要原来内容是1的位,总是可以被写入,但只要原来内容是0的位,就只有擦除才能改为1.
实测数据,对一个字节反复写0和擦除,寿命指的是写0的次数。
第一次擦除不干净的寿命:876842次
第一次出现连续两次擦除仍然不干净的寿命:1169465次
第一次出现连续4次擦除仍然不干净的寿命:1769609次
第一次出现连续8次擦除仍然不干净的寿命:1886879次
6、EEPROM擦写寿命
EEPROM的写入寿命通常在百万次范围内(如EVASH的EV24C256A支持400万次写入)。但在高频次写入的应用中,写入次数限制可能导致芯片过早失效
根据标准,EEPROM在寿命测试中是允许一定的失效概率的,按照IEEE-STD-1005-1998和JEDEC的标准要求,失效概率允许1%。例如某EEPROM芯片的标称寿命为100万次,那拿100片做寿命试验,在100万次时失效的数量小于等于1.(这1片可能在10万次失效,100万次失效前都计算在内)。
7、架构(bootloader+app)
在一定的时间内如果没有程序需要更新则自动跳转到app地址执行用户程序
内部flash 512K
bootloader 跑裸机 48k 主要实现USB升级和eeprom标志位升级
app 跑freeRtos 464K 程序的基本功能,升级时软件复位开始执行bootloader升级
app2 外部flash(W25Q128) 主要用于将USB读取BIN文件先存放到外部FLASH中,在从外部FLASH写入内部FLASH,可以防止芯片变砖。
1、架构(bootloader+app)
在一定的时间内如果没有程序需要更新则自动跳转到app地址执行用户程序
内部flash 512K
bootloader 跑裸机 48k 主要实现USB升级和eeprom标志位升级
app 跑freeRtos 464K 程序的基本功能,升级时软件复位开始执行bootloader升级
app2 外部flash(W25Q128) 主要用于将USB读取BIN文件先存放到外部FLASH中,在从外部FLASH写入内部FLASH,可以防止芯片变砖。