STM32学习记录18 IAP(2)
m32f100芯片手册的29页,我们只截取关键部分
从上图我们看出几个关键部分:
1.内部flash 是从0x0800 0000开始 到0x0801 FFFF 结束, 0x0801FFFF-0x0800 0000= 0x20000 =128k 128也就是flash的大小;
2.SRAM的开始地址是 0x2000 0000 ;
我们要把我们的在线升级程序IAP放到FLASH里以0x0800 0000 开始的位置, 应用程序放APP放到以0x08003000开始的位置,中断向量表也放在0x0800 3000开始的位置;如图
所以我们需要先查看一下misc.h文件中的中断向量表的初始位置宏定义为 NVIC_VectTab_Flash 0x0800 0000
那么要就要设置编译器keil 中的 options for target 的target选项中的 IROM1地址 为0x0800 0000 大小为 0x20000即128K;
IRAM1地址为0x2000 0000 大小为0x2000;
(提示:这一项IROM1 地址 即为当前程序下载到flash的地址的起始位置)
下面我们来分析一下修改后的IAP代码:
[plain]view plaincopy
- /*******************************************************************************
- *@函数名称main
- *@函数说明主函数
- *@输入参数无
- *@输出参数无
- *@返回参数无
- *******************************************************************************/
- intmain(void)
- {
- //Flash解锁
- FLASH_Unlock();
- //配置PA15管脚
- KEY_Configuration();
- //配置串口1
- IAP_Init();
- //PA15是否为低电平
- if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==0x00)
- {
- //执行IAP驱动程序更新Flash程序
- SerialPutString("\r\n======================================================================");
- SerialPutString("\r\n=(C)COPYRIGHT2011Lierda=");
- SerialPutString("\r\n==");
- SerialPutString("\r\n=In-ApplicationProgrammingApplication(Version1.0.0)=");
- SerialPutString("\r\n==");
- SerialPutString("\r\n=Bywuguoyan=");
- SerialPutString("\r\n======================================================================");
- SerialPutString("\r\n\r\n");
- Main_Menu();
- }
- //否则执行用户程序
- else
- {
- //判断用处是否已经下载了用户程序,因为正常情况下此地址是栈地址
- //若没有这一句话,即使没有下载程序也会进入而导致跑飞。
- if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
- {
- SerialPutString("ExecuteuserProgram\r\n\n");
- //跳转至用户代码
- JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);
- Jump_To_Application=(pFunction)JumpAddress;
- //初始化用户程序的堆栈指针
- __set_MSP(*(__IOuint32_t*)ApplicationAddress);
- Jump_To_Application();
- }
- else
- {
- SerialPutString("nouserProgram\r\n\n");
- }
- }
这里重点说一下几句经典且非常重要的代码:
第一句: 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) 的一个别名;例如:
[cpp]view plaincopy
- pFunctiona1,a2,a3;
- voidfun(void)
- {
- ......
- }
- a1=fun;
所以,Jump_To_Application = (pFunction) JumpAddress; 此时Jump_To_Application指向了复位函数所在的地址;
第四 、五句:
STM32学习记录IA 相关文章:
- STM32学习记录18 IAP(1)(11-13)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)