zoukankan      html  css  js  c++  java
  • IAP升级功能编写初期的一些困惑与疑问---完毕功能后的总结

    IAP的源代码等资料我上传了,压缩包内有12个文件,,http://download.csdn.net/detail/f907279313/7524849(要积分的辛苦收集的你们就给点积分吧)

    还有还有一篇博客总结的IAP:http://blog.csdn.net/super_demo/article/details/32086541


    一,网上下载的例程,跳转部分的代码有差异,尤其是用的汇编那句

    eg:

    Jump_To_Application  = (pFunction)(*(vu32*) (IAPSTART + 4));
    __MSR_MSP(*(vu32*) IAPSTART);
    Jump_To_Application();

    跟踪__MSR_MSP(一般这个函数都在库文件中有,跟踪不到就用搜索找)找到汇编函数为

    __MSR_MSP 
     
        MSR MSP, r0 ; set Main Stack value
        BX r14


    //跳转到应用程序段
    //appxaddr:用户代码起始地址.
    void iap_load_app(u32 appxaddr)
    {
    if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//检查栈顶地址是否合法.

    jump2app=(iapfun)*(vu32*)(appxaddr+4);//用户代码区第二个字为程序開始地址(复位地址)
    MSR_MSP(*(vu32*)appxaddr);//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
    jump2app(); //跳转到APP.
    }
    }

    跟踪MSR_MSP找到函数为

    //设置栈顶地址
    //addr:栈顶地址
    __asm void MSR_MSP(u32 addr) 
    {
        MSR MSP, r0 //set Main Stack value
        BX r14
    }


     //推断用户是否已经下载程序,由于正常情况下此地址是栈地址。
            //若没有这一句的话,即使没有下载程序也会进入而导致跑飞。
            if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
            {
                SerialPutString("Execute user Program ");
                //跳转至用户代码
                JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
                Jump_To_Application = (pFunction) JumpAddress;


                //初始化用户程序的堆栈指针
                __set_MSP(*(__IO uint32_t*) ApplicationAddress);
                Jump_To_Application();
            }

    跟踪__set_MSP找到函数为

    __ASM void __set_MSP(uint32_t mainStackPointer)
    {
      msr msp, r0
      bx lr
    }

    总结以上发现都是操作ARM的R0跟R14(LR)寄存器。

    另一种不太一样的,就是stm32F4的库函数中的跳转,例如以下所看到的

    //測试用户app地址是不是在APPLICATION_ADDRESS位置。检測栈顶的地址,来检验app是否下载成功
        if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
       
        //APPLICATION_ADDRESS + 4相应的是app中断向量表的第二项,复位地址
        JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
    //把地址强转为函数指针
        Jump_To_Application = (pFunction) JumpAddress;
        //设置主函数栈指针
        __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
    //调用函数,实际失去app复位地址去运行复位操作
        Jump_To_Application();
        }

    跟踪__set_MSP找到函数为

    static __INLINE void __set_MSP(uint32_t topOfMainStack)
    {
      register uint32_t __regMainStackPointer     __ASM("msp");
      __regMainStackPointer = topOfMainStack;
    }

    对于M4的这个库函数我也太懂,感觉终于的操作应该跟其它的一样吧

    二,关于跳转部分的代码的理解(转)

    这里重点说一下几句经典且很重要的代码:

    第一句: if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)   //推断栈定地址值是否在0x2000 0000 - 0x 2000 2000之间

    怎么理解呢? (1),在程序里#define ApplicationAddress    0x8003000 ,*(__IO uint32_t*)ApplicationAddress)  即取0x8003000開始到0x8003003 的4个字节的值, 由于我们的应用程序APP中设置把 中断向量表 放置在0x08003000 開始的位置;而中断向量表里第一个放的就是栈顶地址的值

    也就是说,这句话即通过推断栈顶地址值是否正确(是否在0x2000 0000 - 0x 2000 2000之间) 来推断是否应用程序已经下载了,由于应用程序的启动文件刚開始就去初始化化栈空间,假设栈顶值对了,说应用程已经下载了启动文件的初始化也运行了;


    第二句:    JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);   [  common.c文件第18行定义了:  pFunction   Jump_To_Application;]
                          

    ApplicationAddress + 4  即为0x0800 3004 ,里面放的是中断向量表的第二项“复位地址”  JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); 之后此时JumpAddress

    第三句:    Jump_To_Application = (pFunction) JumpAddress;
     startup_stm32f10x_md_lv. 文件里别名  typedef  void (*pFunction)(void);     这个看上去有点奇怪;正常第一个整型变量   typedef  int  a;  就是给整型定义一个别名 a

     void (*pFunction)(void);   是声明一个函数指针,加上一个typedef 之后  pFunction仅仅只是是类型 void (*)(void) 的一个别名;比如:

    1. pFunction   a1,a2,a3;  
    2.   
    3. void  fun(void)  
    4. {  
    5.     ......  
    6. }  
    7.   
    8. a1 = fun;  

    所以,Jump_To_Application = (pFunction) JumpAddress;  此时Jump_To_Application指向了复位函数所在的地址;

    第四 、五句: __set_MSP(*(__IO uint32_t*) ApplicationAddress);      \设置主函数栈指针
                   Jump_To_Application();                         \运行复位函数

    Jump_To_Application()是把用户代码的复位地址付给PC指针,我看到Jump_To_Application()这句代码debug的时候相应的汇编代码是

    LDR r0,[pc,#12] ;相对PC的数据载入,去函数指针的地址
    LDR r0,[r0,#00] ;R0做索引,无偏移,数据装载到R0,这个内容就是函数指针指向的内容,也就是函数的地址了,用户程序的起始地址;
    BLX r0              ;这个不解释,说了是跳转

    我们看一下启动文件startup_stm32f10x_md_vl.s 中的启动代码,更easy理解



    三,关于跳转时是否能不用按键,用软件标志位以及APP与IAP之间的互跳

    全然能够不用按键,能够模拟一个按键信号,或者用软件的一个标志位来推断是否更新。。我设计的在flash中中存储一个值,当APP执行中须要更新时串口发来更新命令,然后在flash中存一个值之后跳到IAP部分,来读取flash中存储的那个值,假设是须要更新则更新,假设不是须要跟新标志位就直接跳转到APP部分。。。这样也不用反复上电,断电。


    四,关于APP与IAP互跳之间的中断处理问题

    跳转时中断问题还是一个比較棘手的问题。。常常跳转之后无法进入中断,然后百度了一下,自己理解大概是,跳转时仅仅是强制改变了PC指正的位置,可是里面的中断寄存器什么的都没有变,这样中断存在,可是中断函数什么的都没有了,造成程序死掉。。我在写的过程中也遇到了问题,第一次从iap跳到app正常,可是从app跳回iap的时候因为残留的中断太多,在iap中程序死了。我的处理方式是把app中的跳转命令换成了系统复位NVIC_SystemReset();(不同的固件库可能函数名不同)其它的处理理的方式据我所知还有有①跳转之前复位或者关闭全部打开的中断②跳转后在初始化时添�RCC_DeInit();,,NVIC_DeInit ();等让中断恢复默认值。。详细可參考以下这篇文章http://dzdesigned80.blog.163.com/blog/static/203259238201272425313152/

    关于stm32的软件复位:

    STM32软件复位(基于库文件V3.5) ,对于STM32来说软件复位有两种方式:    

    1)採用官方自带的软件库  
        在官方软件库的 core_cm3.h 文件中 直接提供了 系统复位的函数    

    static __INLINE void NVIC_SystemReset(void) 


    SCB->AIRCR  = ( (0x5FA << SCB_AIRCR_VECTKEY_Pos)    |   

    (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk)   |  

    SCB_AIRCR_SYSRESETREQ_Msk);                   /* Keep priority group unchanged */ 
      __DSB();                                                                                       /* Ensure completion of memory access */               
      while(1);                                                                                        /* wait until reset */

     } 
      可是不是直接调用这个函数就OK了?    在Cortex-M3权威指南中有这么一句话:     
    这里有一个要注意的问题:从SYSRESETREQ 被置为有效,到复位发生器运行复位命令,  往往会有一个延时。在此延时期间,处理器仍然能够响应中断请求。但我们的本意往往是要  让此次运行到此为止,不要再做不论什么其他事情了。所以,最好在发出复位请求前,先把  FAULTMASK 置位。  

      所以最好在将FAULTMASK 置位才万无一失。    相同官方 core_cm3.h 文件中也直接提供了该函数  
      static __INLINE void __set_FAULTMASK(uint32_t faultMask) 

    register uint32_t __regFaultMask       __ASM("faultmask");   

    __regFaultMask = (faultMask & 1);

     } 
      把上面这两个函数写在一起就能够实现软件复位了~~ 

    void SoftReset(void) 


    __set_FAULTMASK(1);      // 关闭全部中端 

    NVIC_SystemReset();// 复位 


     /*------


  • 相关阅读:
    十月二十七学习报告
    十月二十六学习报告
    十月二十五学习报告
    十月二十四学习报告
    十月二十三学习报告
    十月二十二学习报告
    十月二十一学习报告
    十月十九学习报告
    十月十七学习报告
    十月十六学习报告
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/3815374.html
Copyright © 2011-2022 走看看