【转载】(转载)关于IAP与APP互相跳转的实现

最近一个项目用到了IAP功能,在21IC看到的这个文章很有帮助,分享一下

关于IAPAPP互相跳转的实现

首先,在您动手做这个实验之前,先要弄清除咱俩的软硬件有什么不同:

1. 我的CPUSTM32F103ZET6,里面有512KFLASH,您的CPU如果是其它类型,也不要紧,只是在程序里面,地址上限可能不一样。但是,个人觉得,最好能用256K以下的FLASH

2. 我的外部存储介质是U盘,如果您的外部存储介质是SD卡,那也应该一样用,只是它们必须是FAT16FAT32文件系统。如果您的板上没有外部存储介质,那也能做跳转实验,只是不能做加载APP实验。

3. 我的仿真器是JLINK7,如果您的仿真器是其它的,估计也没多大问题,只要您会用它就行了。什么?没有仿真器,那还是别做这个实验吧,出错了没法调试。

4. 我的开发环境是RVMDK 37STM库是V203。使用其它开发环境的话,您要是能找到MDK中的设置对应到您那里怎么设置,估计也没问题。至于库嘛,您现在是用哪个就哪个吧,全部包在您的工程里,没问题的。

好了,开始啦。

先找个你以前调好的工程,当然,最好是非常可靠的,内容很精彩的,带液晶显示的,这样比较容易知道你后面有没有调好。这个工程还最好是在FLASH里面运行的,如果不是,要将它改回来。

至于什么开发文档,太麻烦了,不用看。我之前看了STMIAP应用笔记AN2557,就觉得一个字“乱”,特别是心里还没谱的时候,更是越看越糊涂,这么大个工程,到最后对我有帮助的,就是一小段,就是如何擦除,如何编程那小段。当然,STM32的库还是非常有用的,如果不用库的话,学习、工作进度会慢很多。

说多啦,找好工程没有?找好工程咱就开工了。将这个工程复制两份,一份命名为IAP,一份命名为APP

第一步:规划好你两个程序的存放位置。

IAP程序肯定是从0X08000000开始的,因为它是引导程序。将IAP程序放在0X08000000-0X0800FFFF的位置,给它64K空间,足够了。

APP程序从0X08010000-0X0807FFFF,给它448K空间。

如果您的CPU不同,那APP程序的空间小一点,也没问题。

第二步:制作你的APP程序。

1. 将程序定位在0X08010000开始的位置。

点魔术棒,打开目标选项设置。

Target选项卡,IROM1改成从0X08010000开始,尺寸0X00070000

Debug选项卡,Load Application at Startup打上勾,Run to main()打上勾;

Utilitiles选项卡,点settings按纽,弹出Flash download卡,Erase sectors打上勾,点你的编程算法,将底下的的起始地址改成0X08010000,尺寸0X00070000

2. 制作一个RunInFlashOffset.ini文件。文件内容为:

SP = _RDWORD(0x08010000);           // Setup Stack Pointer

PC = _RDWORD(0x08010004);           // Setup Program Counter

目的是在用JLINK调试的时候,引导程序运行。

点魔术棒,打开目标选项设置。

Debug选项卡,Initialization File:项,选择上面的RunInFlashOffset.ini。 

3. 为了从IAP程序跳来运行APP的时候正常开始,初始化时要恢复RCC为复位状态,恢复NVIC为复位状态。

在你的RCC初始化部分,第一句加上:

RCC_DeInit();

在你的NVIC初始化部分,第一句加上:

NVIC_DeInit ();

4. 重定位中断表到0X08010000位置。

在上面NVIC_DeInit ();后面加上:

NVIC_SetVectorTable (NVIC_VectTab_FLASH, 0x00010000);

如果原来有其它的定位语句,将它删掉。

5. 编写跳转IAP函数:

/**************************************************************************************************

函数: 运行IAP程序.

输入: 

返回: .不再返回.

说明:   由于APP是在IAP的基础上运行的,因此,IAP一定是有效的,这里不再作IAP有效性检查.

**************************************************************************************************/

#define IAP_ADDR        0X08000000

void IapProgramRun(void)

{

    INT32U  IapSpInitVal;           //IAP程序的SP初值.

    INT32U  IapJumpAddr;            //IAP程序的跳转地址.,IAP程序的入口.

    void    (*pIapFun)(void);       //定义一个函数指针.用于指向APP程序入口.

    

    NVIC_DeInit ();                                 //恢复NVIC为复位状态.使中断不再发生.

    

    IapSpInitVal = *(INT32U *)IAP_ADDR;             //APPSP初值.

    IapJumpAddr = *(INT32U *)(IAP_ADDR + 4);        //取程序入口.

    

    __MSR_MSP (IapSpInitVal);                       //设置SP.

    pIapFun = (void (*)(void))IapJumpAddr;              //生成跳转函数.

    (*pIapFun) ();                                  //跳转.不再返回.

}

6. 编写在一定条件下跳转IAP的部分。比如按下某个键,就跳到IAP去。

完成上述几步后,编译调试,用JLINK调试,可以直接运行的,跟你原来的工程应该没区别。有问题的话,将它解决。

第三步:制作您的IAP程序。

1. 将程序定位在0X08000000开始的位置。如果您的程序本来就是在这个位置的,不用改了。

点魔术棒,打开目标选项设置。

Target选项卡,IROM1改成从0X08000000开始,尺寸0X00010000

Debug选项卡,Load Application at Startup打上勾,Run to main()打上勾;

Utilitiles选项卡,点settings按纽,弹出Flash download卡,Erase sectors打上勾,点你的编程算法,将底下的的起始地址改成0X08000000,尺寸0X00010000

2. 为了从APP程序跳回来运行IAP的时候正常开始,初始化时要恢复RCC为复位状态,恢复NVIC为复位状态。

在你的RCC初始化部分,第一句加上:

RCC_DeInit();

在你的NVIC初始化部分,第一句加上:

NVIC_DeInit ();

3. 重定位中断表到0X08000000位置。

在上面NVIC_DeInit ();后面加上:

NVIC_SetVectorTable (NVIC_VectTab_FLASH, 0x0);

如果原来有其它的定位语句,将它删掉。

4. 编写在一定条件下跳转APP的部分。比如按下某个键,就跳到APP去。

5. 编写跳转APP函数:

#define  APP_ADDR                0X08010000

OP_RESULT AppProgramRun(void)

{

    INT32U  AppSpInitVal;           //App程序的SP初值.

    INT32U  AppJumpAddr;            //APP程序的跳转地址.,APP程序的入口.

    void    (*pAppFun)(void);       //定义一个函数指针.用于指向APP程序入口.

    

    AppSpInitVal = *(INT32U *)APP_ADDR;             //APPSP初值.

    if (AppSpInitVal & 0XFFFF 0000 != 0X20 00 00 00)    //APP未写入.不能跳.

    {

        FaceEnterDialog (&OpFailDialog);

        return OP_FAIL;

    }

    AppJumpAddr = *(INT32U *)(APP_ADDR + 4);        //取程序入口.

    if ((AppJumpAddr & 0X FF F8 00 00) != 0X 08 00 00 00)   //APP无效.不能跳.

    {

        FaceEnterDialog (&OpFailDialog);

        return OP_FAIL;

    }

    

    NVIC_DeInit ();                                 //恢复NVIC为复位状态.使中断不再发生.

    __MSR_MSP (AppSpInitVal);                       //设置SP.

    pAppFun = (void (*)(void))AppJumpAddr;          //生成跳转函数.

    (*pAppFun) ();                                  //跳转.不再返回.

    return OP_SUCCESS;

}

完成上述几步后,编译调试,OK

第四步:双程序调试:

1. 用仿真器运行IAP程序,然后按下按键,转到APP去。如果你正常转到APP,说明成功。不能的话,用仿真器跟一下,把问题解决。

2. 用仿真器运行APP程序,然后按下按键,转到IAP去。如果你正常转到IAP,说明成功。不能的话,用仿真器跟一下,把问题解决。

3. 用仿真器运行IAP程序,然后按下按键,转到APP

APP中又按下按键,转回IAP。如此反复。

可以在IAP第一句设个断点,每次转回来的时候,都应该会停在那里的。

注意:在跳到另一个程序中运行的时候,要停止不能直接点“停止调试按纽”,就是那个放大镜一样的按纽,否则MDK立马出错退出。要停止的话,要先打开反汇编观察窗口,然后按下“停止”按纽,就是左上角红圆圈里一把叉那个,

再按下“停止调试按纽”。

第五步:在IAP中加载APP

如果你的板子上没有USB,或都SD卡,这后面的就做不了了。

1. IAP程序,加上加载APP程序功能。就是按下某个键时,从U盘读取APP程序,并把它写到FLASH中。这个参考附件。

2. APP程序中,选择输出HEX文件。目前来说,HEX文件是比较方便处理的文件。

点魔术棒,打开目标选项设置。

Output选项卡,Create HEX File打上勾。

编译,生成HEX文件。

3. APPHEX拷到U盘中,然后用IAP程序加载。

第六步:让IAP区分是复位运行,还是从APP转过来运行的。

打开你的启动文件(我这里是stm32f10x_vector.s),看一下它里面栈空间是多大,堆空间是多大。在IAP程序主函数第一句设个断点,记下此时的SP值,一般这个值比 栈++全局变量还要大一些。在这个值+8之上的内部RAM空间,是程序用不上的。所以可以让APP程序在RAM空间的顶端设置一个标志,然I后让AP程序去根据这个标志来区别复位运行、从APP转过来的运行。

区分IAP的运行方式有一个特殊的用途,那就是从APP程序中,跳转IAP程序,来更新APP程序。这是真正的在线升级。

最后,我总结一下,要做IAPAPP间的互相跳转,要注间以下几点:

1. APP程序是放在FLASH的中间位置运行的,所以在编译、下载、调试时,都要指定它的入口(本例是0X08010000)。具体实现就是在魔术棒中的设置。

2. 程序可以是从另外一个程序转来的,而另外一个程序的RCCNVIC设置不可知,所以必须在初始化时,恢复RCCNVIC为复位状态,并且设置正确的NVIC向量表。

3. 在要跳到别的程序之前,要恢复NVIC为复位状态,防止在跳转过程中出现中断。

4. 如果IAP要判断是复位开始运行的,还是从APP跳转过来的,应该用程序启动部分不会被改变的内存、外存存储一个标志,用它来判定从哪跳来的。

你可能感兴趣的:(STM32,stm32)