STM32 BOOT与APP程序跳转实现以及注意问题

前言

   最近使用STM32单片机烧录器的时候需要实现BOOT与APP之间程序跳转,便于通过BOOT更新APP的程序。遇到奇怪的问题,这里记录下问题以及问题原因分析过程,随便把BOOT与APP之间程序跳转的关键点列出来。

BOOT跳转APP的实现

   这个BOOT与APP之前的跳转实现较为简单,这里简单记录一下。

  第一步先是要明确BOOT与APP之间的分区,本次使用的单片机型号为STM32F103RET6,内部flash为512k。由于内部flash大小暂时够用也想偷懒,于是直接把开机LOGO放在BOOT中,这样程序简单点,所以计划BOOT空间大小为128K,剩下的作为APP的空间使用。

  开发环境使用KEIL,使用KEIL的Project->Options for target中的Target页面设置IROM1。BOOT设置为START:0x8000000 Size:0x20000,APP设置为START:0x8020000 Size:0x58000。后面来留一点空间做数据存储。

  BOOT中跳转到APP的程序如下:

#define APP_START_ADDR 		 		0x08020000 		
int main(void)
{
	uint32_t app_addr=0;
	start_app_fxn app_start;

	//init

	//do something in boot
	
	__disable_irq();
	
	app_addr = *(__IO  uint32_t*) (APP_START_ADDR + 4);

	app_start = (start_app_fxn) app_addr;
	
	__set_MSP( *(__IO  uint32_t*) (APP_START_ADDR));

	app_start();
	
}

  在APP中需要设置中断向量的地址为APP的其中地址,于是在APP代码启动未开中断之前需要加入如下程序:

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x20000);	

__enable_irq();

APP跳转到BOOT实现

  从APP跳转到BOOT就较为简单了,直接使用软重启就好了。具体代码如下:

__set_FAULTMASK(1);
NVIC_SystemReset();

发现问题

  一切准备就续后,开始下载代码进行测试了。首先下载BOOT,之后下载APP,运行后发现,程序居然跑飞了。APP程序运行到了void HardFault_Handler(void)函数中。APP程序单独运行的时候一些正常的,这里出现这个情况是什么问题造成的呢?

分析问题

  第一时间就想到是不是APP那里没有注意把程序把程序写跑飞了,于是第一时间去除BOOT,单独运行APP,结果发现一切正常。一切正常才是合理的,并且APP单独运行已经发布过了两个版本了。

  既然问题并没有出现在APP的程序本身,而实际又与BOOT跳转相关。那问题肯定是APP的程序收到了BOOT运行程序程序的影响。那BOOT运行对APP产生了什么影响了呢?

  具体的问题分析还需要从APP的实际出问题的地方着手,运行APP程序待程序跳转到void HardFault_Handler(void)后,定位出跑飞的程序段如下

pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;

  由于APP中使用了FREERTOS,这个代码段在xTaskCreate中被调用,就一个简单的幅值程序居然跑飞了!通过仿真查看pxIndex变量的地址居然是0x00000000,这样不跑飞才怪。而没有BOOT的时候程序确实正常了。BOOT程序运行怎么影响到了APP的里面的变量的?

  pxIndex这个变量其实就是存放在内存里面的,难道BOOT的运行与APP的公用的内存段互相影响了?

  既然如此就把BOOT的内存段与APP的内存段分开试试。查看Keil编译后的map文件,BOOT中使用的内存较少,分配4k给BOOT就可以了。

  使用KEIL的Project->Options for target中的Target页面设置IRAM1。BOOT设置为START:0x20000000 Size:0x1000,APP设置为START:0x20001000 Size:0xF000。

  运行测试,居然正常了,那可以确定就是BOOT与APP公用的内存段互相影响了。那新的问题又来了这个怎么影响的了,本人写代码的时候都非常注意定义变量的时候都与幅值为0,按道理没有影响才对呀。

BOOT与APP的公用的内存段互相影响

  由于BOOT使用的内存段只有前面的4K,那就BOOT与APP内存分开前后APP中的前面4k数据取出来分析一下。

  设置APP内存起始地址为0x20000000与起始地址为0x20001000,仿真运行到APP程序的起始的时候设置断电,在KEIL中使用SAVE D:\a 0x20000000,0x20001000SAVE D:\b 0x20001000,0x20002000把两个不通过代码设置的工程内存的起始4k数据取出来。通过对比如下:

avatar

  对比可以看到,运行APP的输出两个内存的数据果然还有有点不一样的。第一个不同点出现在0x20000014这个地址,查看MAP文件可以了解到这个地址是变量pxCurrentTCB,正式这个变量值不为NULL,所以程序运行的时候不为上面的提及的pxIndex变量申请内存,造成程序跑飞了。该变量在FREERTOS源码的task.c中,具体定义如下:

PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;

  可见定义中已经初始化了pxCurrentTCB=NULL了,可是为何程序运行之初不是NULL,而是BOOT运行过程中留下的一个数值呢?关于这个问题还在思索中,暂时不了解其中原因,若是哪位大神指导一二,请指点下,不胜感激。

后续

  目前还不知道到APP中定义变量已经初始化了,但是通过BOOT跳转过来后实际并没有初始化化。由于BOOT中暂用的内存较少,这个项目暂时使用BOOT与APP内存段分开的方法处理本问题点。

  另外,我们可以看到FREERTOS源码定义pxCurrentTCB变量使用了PRIVILEGED_DATA,查看定义可以看到

#define PRIVILEGED_DATA __attribute__((section("privileged_data")))

  可见FREERTOS作者们已经是有意把FREERTOS定义的变量划分一个内存区域了。启动内存划分则是定义#ifdef portUSING_MPU_WRAPPERS,通过定义可以看出应该就是启动了MPU内存保护模块,难道MPU的作用大致就是为了避免本文讨论的之类的问题的出现?

  以上所有都是个人的学习笔记,若有错误的地方欢迎大家指点。

  知识就是财富,每次积累一点点,终究会有质的飞跃。

                       幽灵

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐