【转】关于IAP与APP互相跳转的实现
关于IAP与APP互相跳转的实现
首先,在您动手做这个实验之前,先要弄清除咱俩的软硬件有什么不同:
1. 我的CPU是STM32F103ZET6,里面有512K的FLASH,您的CPU如果是其它类型,也不要紧,只是在程序里面,地址上限可能不一样。但是,个人觉得,最好能用256K以下的FLASH。
2. 我的外部存储介质是U盘,如果您的外部存储介质是SD卡,那也应该一样用,只是它们必须是FAT16,FAT32文件系统。如果您的板上没有外部存储介质,那也能做跳转实验,只是不能做加载APP实验。
3. 我的仿真器是JLINK7,如果您的仿真器是其它的,估计也没多大问题,只要您会用它就行了。什么?没有仿真器,那还是别做这个实验吧,出错了没法调试。
4. 我的开发环境是RVMDK 3。7,STM库是V2。03。使用其它开发环境的话,您要是能找到MDK中的设置对应到您那里怎么设置,估计也没问题。至于库嘛,您现在是用哪个就哪个吧,全部包在您的工程里,没问题的。
好了,开始啦。
先找个你以前调好的工程,当然,最好是非常可靠的,内容很精彩的,带液晶显示的,这样比较容易知道你后面有没有调好。这个工程还最好是在FLASH里面运行的,如果不是,要将它改回来。
至于什么开发文档,太麻烦了,不用看。我之前看了STM的IAP应用笔记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; //取APP的SP初值.
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; //取APP的SP初值.
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. 把APP。HEX拷到U盘中,然后用IAP程序加载。
第六步:让IAP区分是复位运行,还是从APP转过来运行的。
打开你的启动文件(我这里是stm32f10x_vector.s),看一下它里面栈空间是多大,堆空间是多大。在IAP程序主函数第一句设个断点,记下此时的SP值,一般这个值比 栈+堆+全局变量还要大一些。在这个值+8之上的内部RAM空间,是程序用不上的。所以可以让APP程序在RAM空间的顶端设置一个标志,然I后让AP程序去根据这个标志来区别复位运行、从APP转过来的运行。
区分IAP的运行方式有一个特殊的用途,那就是从APP程序中,跳转IAP程序,来更新APP程序。这是真正的在线升级。
最后,我总结一下,要做IAP和APP间的互相跳转,要注间以下几点:
1. APP程序是放在FLASH的中间位置运行的,所以在编译、下载、调试时,都要指定它的入口(本例是0X08010000)。具体实现就是在魔术棒中的设置。
2. 程序可以是从另外一个程序转来的,而另外一个程序的RCC,NVIC设置不可知,所以必须在初始化时,恢复RCC,NVIC为复位状态,并且设置正确的NVIC向量表。
3. 在要跳到别的程序之前,要恢复NVIC为复位状态,防止在跳转过程中出现中断。
4. 如果IAP要判断是复位开始运行的,还是从APP跳转过来的,应该用程序启动部分不会被改变的内存、外存存储一个标志,用它来判定从哪跳来的。
【转】关于IAP与APP互相跳转的实现的更多相关文章
- 关于STM32的IAP与APP互相跳转
关于STM32的IAP与APP互相跳转 之前做了一个不带系统的IAP与APP互相跳转,在网上找了资料后,很顺畅就完成了,后来在IAR集成开发环境下,IAP无系统,APP用UCOS系统做互相跳转出现了很 ...
- ios&h5混合开发项目仿app页面跳转优化
前言:本人原本是ios开发工程师,但由于现今H5的兴起,行内刮起了一阵混合开发的风气,趁着这股劲,我也学了前端开发,不说研究的多深,但也能胜任日常的开发工作.长话短说,现今的混合开发应该还处于摸索阶段 ...
- H5调取APP或跳转至下载
来源: 最近在配合移动端做几个详情页h5分享页面,需要调取App并跳转至app详情页, 如果没有安装App,需要判断引导至下载页面. 参考文档: https://juejin.im/post/5b7e ...
- 通过手机浏览器打开APP或者跳转到下载页面.md
目录 通过手机浏览器打开APP或者跳转到下载页面 添加 schemes 网页设置 参考链接 通过手机浏览器打开APP或者跳转到下载页面 以下仅展示最简单的例子及关键代码 由于硬件条件有限,仅测试了 A ...
- ios两个app之间跳转,传值的实现
两个APP之间的跳转是通过[[UIApplication sharedApplication] openURL:url]这种方式来实现的. 1.首先设置第一个APP的url地址 2.接着设置第二个AP ...
- Vue仿微信app页面跳转动画
10:14:11独立开发者在开发移动端产品时,为了更高效,通常会使用Web技术来开发移动端项目,可以同时适配Android.iOS.H5,稍加改动还可适配微信小程序. 在使用Vue.js开发移动端页面 ...
- app使用微信支付成功后,点击返回到该app却跳到另外一个app去了
刚接手了公司iOS的两个APP, 现在碰到了这样一个问题: 有一台iPhone在一个APP中使用了微信支付,支付成功后,点击返回到该APP,结果却跳到了另外一个APP去了. 这两个APP都是公司开发的 ...
- iOS App之间跳转
1.先来看看效果,这里做了三个功能 从MyApp跳转到YourApp 从MyApp跳转到YourApp的指定页面 从YourApp使用跳转url的方式跳回MyApp 2.实现app之间的跳转需要注意两 ...
- 3D touch 静态、动态设置及进入APP的跳转方式
申明Quick Action有两种方式:静态和动态 静态是在info.plist文件中申明,动态则是在代码中注册,系统支持两者同时存在. -系统限制每个app最多显示4个快捷图标,包括静态和动态 静态 ...
随机推荐
- 在Python中使用lambda高效操作列表的教程
在Python中使用lambda高效操作列表的教程 这篇文章主要介绍了在Python中使用lambda高效操作列表的教程,结合了包括map.filter.reduce.sorted等函数,需要的朋友可 ...
- react-native-picke Cannot read property '_init' of undefined
使用react-native-picker报以下错误: 查看了react-native-picke的issues: https://github.com/beefe/react-native-pick ...
- Java数组(1):数组与多维数组
我们对数组的基本看法是,你可以创建它们,通过使用整型索引值访问它们的元素,并且他们的尺寸不能改变. 但是有时候我们需要评估,到底是使用数组还是更加灵活的工具.数组是一个简单的线性序列,这使得元素访问非 ...
- CRM总结大纲
目录 一. CRM客户关系管理系统 1. CRM是什么? 里面都有哪些功能(业务)? 2. 什么是公户?什么是私户?为什么要做这个区分? 3. 请列举出CRM系统中的表 4. 通过ORM操作对数据库的 ...
- JavaScript中函数文档注释
/** 方法说明 * @method 方法名 * @for 所属类名 * @param{参数类型}参数名 参数说明 * @return {返回值类型} 返回值说明 */
- hive配置元数据库mysql文件配置
hive中conf/hive-site.xml文件配置(没有该文件则新建) <?xml version="1.0"?> <?xml-stylesheet type ...
- NDK学习笔记-JNI数据类型和属性方法的访问
JNI实现了C/C++与Java的相互访问,那么这篇文章就从C/C++访问Java开始说起 native函数说明 每个native函数,都至少有两个参数(JNIEnv *和jclass或jobject ...
- 通过案例来剖析JQuery与原生JS
首先来个例子: 我们在登陆或者注册一些网站时,如果某一项点过了但没填,鼠标移走后是不是经常看到网站有相应的红色字体提示呢? 那下面我们就以这个为例来剖析下jQuery和原生JS的一些区别,来上代码: ...
- Linux文件权限基础回顾介绍
文件的权限 文件权限的概述: 权限贯穿运维的一生
- hdoj4812 D Tree(点分治)
题目链接:https://vjudge.net/problem/HDU-4812 题意:给定一颗带点权的树,求是否存在一条路经的上点的权值积取模后等于k,如果存在多组点对,输出字典序最小的. 思路: ...