打印

STM32 IAP 问题。求助

[复制链接]
7428|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
userchen|  楼主 | 2010-3-17 14:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 userchen 于 2010-3-18 11:24 编辑

最近在搞STM32 的IAP。发现一个很奇怪的问题。
在程序A里面,跳转到程序B执行。
A存放在0x08000000,B存放在0x0800e000.

起初,B使用的内存大概6K,其中堆栈使用了4K。此时如果从程序A跳到程序B,B出现死机。但是如果用仿真器直接运行B是可以运行的。

实在不知道什么问题,后来B的堆栈改小,设为1K,这是就正常了。能从程序A跳转到程序B,并且B也能正常运行。

请问这是什么原因?程序B的运行为什么后它的内存大小的影响呢?
片子是STM32F103R8T6.

望高手解答!! 谢谢了。
沙发
liao_fangxing| | 2010-3-17 14:41 | 只看该作者
感觉是否内存冲突啊————(0x0800e000+6K+4k)>内存上限
       没做过STM32 的IAP的人路过

使用特权

评论回复
板凳
userchen|  楼主 | 2010-3-17 14:44 | 只看该作者
谢谢。呵呵。
0x0800e000是flash的地址。
内存用的6K包括了堆栈的4K。

继续等待。。。

使用特权

评论回复
地板
ShakaLeo| | 2010-3-17 15:09 | 只看该作者
感觉是你在跳转到B的时候没有把程序B的主堆栈进行初始化,这样程序B在运行的时候还在使用程序A的堆栈指针,很可能会与程序B的全局变量区混到一起了,执行情况就没法预知了,会有某些奇怪现象发生。

使用特权

评论回复
5
ShakaLeo| | 2010-3-17 15:10 | 只看该作者
呵呵,发现楼主的结贴率是0%啊

使用特权

评论回复
6
笑苍天| | 2010-3-17 15:23 | 只看该作者
同意4楼观点。

使用特权

评论回复
7
userchen|  楼主 | 2010-3-17 15:53 | 只看该作者
呵呵。新手,很少灌水,见谅啊。

那程序B在开始运行的时候,不会进行初始化吗?
还是在A调用B之前,需要做什么工作?
A跳转B的代码如下:
void BSP_GPIO_Config(void);
void BSP_Int_Config(void);

#define ApplicationAddress 0x0800e000
typedef  void (*pFunction)(void);

void DisableAllNVIC(void)
{
  for(int i=19; i < 59; i++)
  {
    NVIC->ICER[i >> 0x05] =(unsigned int )0x01 << (i & (unsigned char)0x1F);
  }
}

void DisableAllGPIO(void)
{
    GPIO_InitTypeDef       gpio_init;
    gpio_init.GPIO_Pin    = 0xffff;
    gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
    gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_Init(GPIOC, &gpio_init);
    GPIO_Init(GPIOD, &gpio_init);
    GPIO_Init(GPIOE, &gpio_init);
    GPIO_Init(GPIOF, &gpio_init);

}


void JumpBootloaderProgram(void)
{
    int JumpAddress;
    pFunction Jump_To_Application;
   
    DisableAllNVIC();
    DisableAllGPIO();
   
    JumpAddress = *(volatile unsigned int*) (ApplicationAddress + 4);
    Jump_To_Application = (pFunction) JumpAddress;
    __set_MSP(*(volatile unsigned int*) ApplicationAddress);
    Jump_To_Application();
}

使用特权

评论回复
8
ShakaLeo| | 2010-3-17 16:18 | 只看该作者
猜错了,不是我猜的问题。
应该不是从A刚跳到B就死机了吧,从A跳到B后有一段编译器生成的启动代码,有可能是在那里出现问题了,然后进入fault了。单步调试看看吧,从A跳到B后,单步运行,看在哪里跳到fault的,不过得先找到B程序的fault的地址,因为在仿真环境下由程序A跳到B,是看不到B的代码的,只能看到汇编码和机器码。

使用特权

评论回复
9
lxyppc| | 2010-3-17 16:37 | 只看该作者
有没有程序A和程序B的map文件
看一下他们空间的使用的情况

JumpBootloaderProgram是在什么时候调用的
中断向量表是如何处理的?

使用特权

评论回复
10
userchen|  楼主 | 2010-3-17 17:06 | 只看该作者
A和B的flash区 是肯定分开的。。
但是ram区,应该是有重叠的,因为我是2个独立的工程。
贴出他们的icf文件:
______________________
A:
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000 ;
define symbol __ICFEDIT_region_ROM_end__   = 0x0800dFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__   = 0x20004FFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x1000;
define symbol __ICFEDIT_size_heap__   = 0x200;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region   = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];

define symbol __region_USB_PKG_RAM_start__  = 0x40006000;
define symbol __region_USB_PKG_RAM_end__    = 0x400063FF;
define region USB_PKG_RAM_region = mem:[from __region_USB_PKG_RAM_start__ to __region_USB_PKG_RAM_end__];



define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };

initialize by copy { readwrite };
do not initialize  { section .noinit };
do not initialize  { section USB_PACKET_MEMORY };

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place in USB_PKG_RAM_region
                      { readwrite data section USB_PACKET_MEMORY  };
place in ROM_region   { readonly };
place in RAM_region   { readwrite,
                        block CSTACK, block HEAP };

__________________________________
B:

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x0800e000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x0800e000 ;
define symbol __ICFEDIT_region_ROM_end__   = 0x0800ffff;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__   = 0x20004FFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_heap__   = 0x200;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region   = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];

define symbol __region_USB_PKG_RAM_start__  = 0x40006000;
define symbol __region_USB_PKG_RAM_end__    = 0x400063FF;
define region USB_PKG_RAM_region = mem:[from __region_USB_PKG_RAM_start__ to __region_USB_PKG_RAM_end__];



define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };

initialize by copy { readwrite };
do not initialize  { section .noinit };
do not initialize  { section USB_PACKET_MEMORY };

place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place in USB_PKG_RAM_region
                      { readwrite data section USB_PACKET_MEMORY  };
place in ROM_region   { readonly };
place in RAM_region   { readwrite,
                        block CSTACK, block HEAP };



至于如何调用,是A程序接收pc端指令后,进行跳转。。。

使用特权

评论回复
11
ShakaLeo| | 2010-3-17 20:06 | 只看该作者
跳转代码和连接文件没看出有什么问题。建议楼主先弄清楚是在什么地方死机的,怎么个死法?比如是进入fault了还是程序自己跑飞? A和B的ram区域虽然重叠,但B程序的启动代码会把RW和RO区域的内存进行初始化,所以ram重叠应该不是问题。重点检查一下寄存器,因为从A跳到B之后,寄存器的值可能不是上电后的默认值,有可能造成B程序的运行环境与用仿真器直接运行时不同。

使用特权

评论回复
12
lxyppc| | 2010-3-17 20:22 | 只看该作者
A和B的flash区 是肯定分开的。。
至于如何调用,是A程序接收pc端指令后,进行跳转。。。
userchen 发表于 2010-3-17 17:06


这个"A程序接收pc端指令后,进行跳转"是在中断里面吗?

简单的办法,你在执行Jump_To_Application();
之前看一下xPSR的值,如果在中断中某些位为当前中断号

使用特权

评论回复
13
mohanwei| | 2010-3-17 20:33 | 只看该作者
对,B要充分认识到A之前做了什么东西……
要是我,A肯定做得很小而且用最少的资源,顶多开一个定时器和串口
做的时候充分阅读ST提供的串口IAP例程,打开它的option逐项阅读……我的做法就是直接在上面修改。Flash和Ram的设置可以在菜单里直接设的,尽量不要自己手工去修改文件。

使用特权

评论回复
14
秋天落叶| | 2010-3-17 20:58 | 只看该作者
我也很少去手工修改里面的文件,很容易出问题

使用特权

评论回复
15
司徒老鹰| | 2010-3-17 22:05 | 只看该作者
嗯,除非你是高手

使用特权

评论回复
16
userchen|  楼主 | 2010-3-18 11:22 | 只看该作者
多谢各位高手的指点。呵呵。。
可能是A用到的一些外设或资源没有被重新初始化,而直接运行B,导致了B的运行不正常。对吧。

比如A开启了一些外设、中断,之后只是关闭了所有的中断,我是用DisableAllNVIC()实现的,就直接运行B,会对B有影响吗?

B的内存用的小就可以,大就不可以,B能运行和不能运行仅仅就这点区别。对这点我比较疑惑,难道是内存冲突了?呵呵。

还有我保留一个观点:对于A使用的资源的多少应该没有限制吧,仅仅让A用很少的资源来保证程序的正常运行,是不是带有侥幸心理呢。


12楼:我不是在中断里跳转的。但是A的程序我是用ucos2的。谢谢~

使用特权

评论回复
17
ShakaLeo| | 2010-3-18 13:36 | 只看该作者
16楼:
A程序用了ucos2,而且不是在中断里跳转到B,那应该是在某个任务里跳转的吧。ucos2的官方移植版本,任务里使用的堆栈指针是PSP,如果你的A程序是在使用PSP的任务里跳转到B程序的,那么函数void JumpBootloaderProgram(void)中的__set_MSP(*(volatile unsigned int*) ApplicationAddress)函数并没有使跳转到B后的堆栈指针初始化为主堆栈指针,即跳转到B后还是使用的程序A的PSP,问题可能会出在这里。

使用特权

评论回复
18
userchen|  楼主 | 2010-3-18 14:13 | 只看该作者
多谢ShakaLeo!!
我在把PSP和MSP都重新设置后,就没有问题了。呵呵。。
多谢各位高手的指点!
哎,主要还是对Cortex-M3不熟啊,好好看书,好好学习。

使用特权

评论回复
19
ShakaLeo| | 2010-3-18 14:59 | 只看该作者
本帖最后由 ShakaLeo 于 2010-3-18 15:03 编辑

还得再啰嗦几句,楼主所说的“把PSP和MSP都重新设置”指的是在函数JumpBootloaderProgram中又加入了一句__set_PSP(*(volatile unsigned int*) ApplicationAddress)吗?如果是这样,貌似跳转到B之后还有隐患,因为由A跳到B后,主程序用的是PSP,而中断服务程序仍要使用MSP,因为CM3的中断服务是“处理模式”,只能使用MSP。如果在跳转到B之前把MSP和PSP设为同样值的话,那么B程序的中断服务程序在使用堆栈的同时,很可能也改写了主程序的堆栈中的内容。所以我觉得最好在由A跳转到B之前,在调用__set_MSP(*(volatile unsigned int*) ApplicationAddress)之前,把当前使用的堆栈指针由PSP改回MSP,然后再设置MSP,再跳转,这样比较好一些,跳转到B之后,无论主程序还是中断服务程序都只使用MSP,也就不会冲突了。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
lxyppc + 1
20
userchen|  楼主 | 2010-3-18 18:25 | 只看该作者
恩。多谢高手指点。呵呵。
在这里虚心接受建议。
我现在这样改,应该就不会有问题了吧?
    JumpAddress = *(volatile unsigned int*) (ApplicationAddress + 4);
    Jump_To_Application = (pFunction) JumpAddress;
    __set_PSP(*(volatile unsigned int*) ApplicationAddress);
    __set_CONTROL(0);
    __set_MSP(*(volatile unsigned int*) ApplicationAddress);
    Jump_To_Application();

再次感谢。以后我常来这。呵呵。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:无欲则刚

9

主题

60

帖子

2

粉丝