STM32 ------ 程序跳转IAP、中断、开关总中断

IAP 流程(OTA)

1、获取 APP bin 文件,往 flash 相应位置写入 APP bin 文件(生成 APP bin 文件前需要设置 flash 起始地址,对于 STM32 不再是 0x08000000)

2、从 APP bin 文件的第一个地址取出栈的初始值,初始化 MSP(如果不重新设置MSP,当前boot的MSP值可能指向APP的非法区域),如果 IAP 中有用到操作系统,还需要初始化 PSP(或者PSP切换到MSP)

3、从 APP bin 文件的第二个地址取出复位中断指针,跳转到 APP 的复位中断执行程序(为什么不直接跳到APP main是因为不知道 APP main 的起始地址,APP 复位中断地址是固定存储在 APP bin 的第二个word;并且复位中断会初始化data段和bss段)

4、由于复位中断函数设置的中断向量表起始地址默认是0x800000,未做修改,所以 APP main() 函数第一个语句要设置向量表起始地址(VTOR),至此正常执行 APP 代码

 

程序跳转注意:

1、如果跳转之前的程序A里有些中断没有关,在跳转到程序B后触发了中断,但程序B里没有定义中断响应函数,找不到地址会导致死机。

 2、程序跳转前关总中断,程序跳转后开总中断(关总中断,只是屏蔽了中断;当开总中断后,关总中断之前开的如定时器的中断还是开启的)

 

开关总中断:

在STM32/Cortex-M3中是通过改变CPU的执行优先级来允许或禁止全局中断

PRIMASK位:只允许NMI和hard fault异常,其他中断/异常都被屏蔽(为1表示CPU执行优先级=0,即优先级高于0的中断才能响应)。

FAULTMASK位:只允许NMI,其他所有中断/异常都被屏蔽(为1表示CPU执行优先级=-1,即优先级高于-1的中断才能响应)。

 

第一种方法:

PRIMASK 用于除能在NMI 和硬fault 之外的所有异常,它有效地把当前优先级改为0(可编程优先级中的最高优先级)。

void__disable_irq (void);//关闭总中断

void __enable_irq (void);//开放总中断

 

__set_PRIMASK(1);//关闭总中断

__set_PRIMASK(0);//开放总中断

 

第二种方法:

FAULTMASK 更绝,它把当前优先级改为‐ 1 。这么一来,连硬fault 都被掩蔽了。使用方案与PRIMASK 的相似。但要注意的是,FAULTMASK 会在异常退出时自动清零。

void __disable_fault_irq (void); //关闭总中断

void __enable_fault_irq (void);//开放总中断

 

__set_FAULTMASK(1);//关闭总中断

__set_FAULTMASK(0);//开放总中断

 

常常使用

void __disable_irq (void);//关闭总中断

void __enable_irq (void);//开放总中断

 

 

IAP有 FreeRTOS 程序跳转函数

typedef  void (*pFunction)(void);
pFunction JumpToApplication;


uint32_t JumpAddress;

//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(uint32_t appxaddr)//传进来的参数是FLASH_APP_ADDR 0x08008000
{
    
    __disable_irq ();//关闭总中断
    
    /*STM32F4的RAM分为好几块,不是单纯的0x20000000*/
//    if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)    //检查栈顶地址是否合法.
//    {//10002000
        /*
        因为用户程序开始位置(0x08008000处)的前4个字节存放的是堆栈的地址,
        堆栈地址必定是指向RAM空间的
        */
        
        /*
        用户代码区第二个字为程序开始地址(复位地址)从第五个字节开始
        下面这句话的作用:1:获得新的复位函数入口地址。
        2:这个函数指针指向复位函数入口地址
        */
    
    JumpAddress = *(__IO uint32_t*) (appxaddr + 4);
    JumpToApplication = (pFunction) JumpAddress;
    
    __set_PSP(*(__IO uint32_t*) appxaddr);//设置PSP堆栈指针值
    __set_CONTROL(0);   //选择 MSP 作为 SP堆栈指针
    __set_MSP(*(__IO uint32_t*) appxaddr);//设置MSP堆栈指针值
    
    JumpToApplication();
    
}

IAP无 FreeRTOS 的程序跳转函数可以不加语句 “__setPSP()" 。

https://www.cnblogs.com/god-of-death/protected/p/11777661.html

 

有待测试(关于堆栈值设置和堆栈选择):

IAP 无 freeRTOS:

__set_MSP(*(__IO uint32_t*) appxaddr);//设置MSP堆栈指针值

IAP 有 freeRTOS:

__set_CONTROL(0); //选择 MSP 作为 SP堆栈指针
__set_MSP(*(__IO uint32_t*) appxaddr);//设置MSP堆栈指针值
 

 

posted @ 2017-06-22 14:26  流水灯  阅读(3325)  评论(0编辑  收藏  举报