微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > STM32学习记录18 IAP(2)

STM32学习记录18 IAP(2)

时间:11-13 来源:互联网 点击:

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

  1. /*******************************************************************************
  2. *@函数名称main
  3. *@函数说明主函数
  4. *@输入参数无
  5. *@输出参数无
  6. *@返回参数无
  7. *******************************************************************************/
  8. intmain(void)
  9. {
  10. //Flash解锁
  11. FLASH_Unlock();
  12. //配置PA15管脚
  13. KEY_Configuration();
  14. //配置串口1
  15. IAP_Init();
  16. //PA15是否为低电平
  17. if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==0x00)
  18. {
  19. //执行IAP驱动程序更新Flash程序
  20. SerialPutString("\r\n======================================================================");
  21. SerialPutString("\r\n=(C)COPYRIGHT2011Lierda=");
  22. SerialPutString("\r\n==");
  23. SerialPutString("\r\n=In-ApplicationProgrammingApplication(Version1.0.0)=");
  24. SerialPutString("\r\n==");
  25. SerialPutString("\r\n=Bywuguoyan=");
  26. SerialPutString("\r\n======================================================================");
  27. SerialPutString("\r\n\r\n");
  28. Main_Menu();
  29. }
  30. //否则执行用户程序
  31. else
  32. {
  33. //判断用处是否已经下载了用户程序,因为正常情况下此地址是栈地址
  34. //若没有这一句话,即使没有下载程序也会进入而导致跑飞。
  35. if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
  36. {
  37. SerialPutString("ExecuteuserProgram\r\n\n");
  38. //跳转至用户代码
  39. JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);
  40. Jump_To_Application=(pFunction)JumpAddress;
  41. //初始化用户程序的堆栈指针
  42. __set_MSP(*(__IOuint32_t*)ApplicationAddress);
  43. Jump_To_Application();
  44. }
  45. else
  46. {
  47. SerialPutString("nouserProgram\r\n\n");
  48. }
  49. }


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

第一句: 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

  1. pFunctiona1,a2,a3;
  2. voidfun(void)
  3. {
  4. ......
  5. }
  6. a1=fun;

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

第四 、五句:

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top