delphiliu 发表于 2013-2-3 10:03:55

[求助]定义全局数组会导致硬fault,STM32系列,RTT系统

本帖最后由 delphiliu 于 2013-2-3 17:29 编辑

   前天发现在程序运行的时候总会进入硬fault中,后来通过调试,发现在程序中定义了一个数组,然后程序就会进入fault。然后开始检查是不是因为数组越界造成的问题,于是把所有调用该数组的函数都去掉了。仅仅在app.task中定义了一个长度为30的数组,程序运行后依然会进入fault,通过调试,我发现是在运行完系统初始化函数,开始进行上下文切换的时候进入fault的。后来给数组初始化,但是还是出现同样的问题,后来我修改数组的长度,发现有的长度可以运行,而有的不能。后来我不用操作系统,用同样的方式定义一个数组,程序不会进入fault,能够正常运行。

    补充一下,将数组长度设置为30的时候就会出现上述的问题。在几个程序中试过都是如此。仅仅定义,后面不用也会出现问题。

    今天又调试了一下,发现是在初始化线程堆栈的时候出现了问题。
    刚才调试了一下,初步可以确定是对齐的问题。而问题出现在操作系统再给任务分配堆栈指针的时候,没有实现字对齐。下面是我调试出来的数据
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,rt_uint8_t *stack_addr, void *texit)
{
        unsigned long *stk;

        stk        = (unsigned long *)stack_addr;
        *(stk)   = 0x01000000L;                                        /* PSR */
        *(--stk) = (unsigned long)tentry;                /* entry point, pc */
        *(--stk) = (unsigned long)texit;                /* lr */
        *(--stk) = 0;                                                        /* r12 */
        *(--stk) = 0;                                                        /* r3 */
        *(--stk) = 0;                                                        /* r2 */
        *(--stk) = 0;                                                        /* r1 */
        *(--stk) = (unsigned long)parameter;        /* r0 : argument */

        *(--stk) = 0;                                                        /* r11 */
        *(--stk) = 0;                                                        /* r10 */
        *(--stk) = 0;                                                        /* r9 */
        *(--stk) = 0;                                                        /* r8 */
        *(--stk) = 0;                                                        /* r7 */
        *(--stk) = 0;                                                        /* r6 */
        *(--stk) = 0;                                                        /* r5 */
        *(--stk) = 0;                                                        /* r4 */

        /* return task's current stack address */
        return (rt_uint8_t *)stk;
}
      每次出现fault的时候,都是在执行这个函数的时候。观察stack_addr的值发现如果是字对齐,那么程序不会出现问题。当我加入一个长度为30的数组后,stack_addr的值为0x2000046A。这是末尾是10. 于是出现了硬fault。当修改数组长度,使得stack_addr的值为0x2000044C的时候,程序正常运行。当修改数组长度,stack_addr的值为0x200005F9,程序进入硬fault。这个应该算是RT-thread的一个bug吧?

      现在我定义一个长度为13的数组,如果初始化的值全部为0,那么在调试的时候stack_addr的值为0x200005B1,程序进入硬fault。还是刚才的数组,如果我初始化的值全为1的话,调试时后发现stack_addr的值为0x200005B0,程序正常运行。

lcofjp 发表于 2013-2-3 10:16:53

我在上个帖子中说过了是数据对齐的问题,然后有个哥们澄清说M3不存在对齐的问题,但是我对它的结论表示遗憾。
你可以试着对数据进行强制4字节对齐试一下效果。

lcofjp 发表于 2013-2-3 10:17:45

还有就是如果能调试的话,看一下是到哪条指令的时候fault了,就真相大白了。

delphiliu 发表于 2013-2-3 10:19:41

lcofjp 发表于 2013-2-3 10:17 static/image/common/back.gif
还有就是如果能调试的话,看一下是到哪条指令的时候fault了,就真相大白了。 ...

      那么我同样定义一个数组,如果不适用操作系统,就不会出现问题。而且问题是在初始化系统后进入上下文切换的时候出现的。这块由操作系统负责。

delphiliu 发表于 2013-2-3 11:28:10

lcofjp 发表于 2013-2-3 10:16 static/image/common/back.gif
我在上个帖子中说过了是数据对齐的问题,然后有个哥们澄清说M3不存在对齐的问题,但是我对它的结论表示遗憾 ...

确实是对齐的问题,我已经修改了帖子。你可以看一下我调试的数据。但是根本的原因还是没有搞懂,但是定义数组的时候定义成16位的可以完全避免这个问题,但是浪费了存储空间。

i_kkyu 发表于 2013-2-3 11:49:40

怪不得,我在RTT中,全局的变量定义任意长度的数组,初始化,没出现您提到的现象。。。

lcofjp 发表于 2013-2-3 12:43:13

delphiliu 发表于 2013-2-3 11:28 static/image/common/back.gif
确实是对齐的问题,我已经修改了帖子。你可以看一下我调试的数据。但是根本的原因还是没有搞懂,但是定义 ...

在这些特殊数据的定义时,加上对齐限定不就可以了吗

SNOOKER 发表于 2013-2-3 12:51:54

堆栈最好8字节对齐,要不然编译器也会加补丁对齐的

delphiliu 发表于 2013-2-3 13:24:29

i_kkyu 发表于 2013-2-3 11:49 static/image/common/back.gif
怪不得,我在RTT中,全局的变量定义任意长度的数组,初始化,没出现您提到的现象。。。 ...

我换了3个人的程序,都出现同样的错误。定义一个长度为30的数组,然后调用该数组,而且编译器的优化设置要配置为00,这样编译器不会把这个数组去掉。如果编译器的优化选项配置的不是0,那么可以在任意一个线程中给该数组的任意一个元素赋值,得到同样的结果:程序进入硬fault。

delphiliu 发表于 2013-2-3 13:47:04

为了避免这种问题,还可以在数组初始化的时候,给数组初始化非0值。不过希望有人可以解决系统中的问题。

delphiliu 发表于 2013-2-3 13:47:59

lcofjp 发表于 2013-2-3 10:16 static/image/common/back.gif
我在上个帖子中说过了是数据对齐的问题,然后有个哥们澄清说M3不存在对齐的问题,但是我对它的结论表示遗憾 ...

那为什么我给数组初始化为1就行,初始化为0就不行呢,看我补充的调试结果。

delphiliu 发表于 2013-2-3 14:42:46

i_kkyu 发表于 2013-2-3 11:49 static/image/common/back.gif
怪不得,我在RTT中,全局的变量定义任意长度的数组,初始化,没出现您提到的现象。。。 ...

你使用的是STM32的单片机吗?

delphiliu 发表于 2013-2-3 14:45:03

SNOOKER 发表于 2013-2-3 12:51 static/image/common/back.gif
堆栈最好8字节对齐,要不然编译器也会加补丁对齐的

         我怎么觉着这个问题跟RTT系统有关系。如果裸跑就不会出现这个问题。

i_kkyu 发表于 2013-2-3 19:14:34

delphiliu 发表于 2013-2-3 14:42 static/image/common/back.gif
你使用的是STM32的单片机吗?

STM32F107 ,RTT ,1.01 MDK

ffxz 发表于 2013-2-3 21:17:57

你是使用静态线程方式吧,看看idle线程是如何去定义栈的(rt_thread_stack)。

snoopyzz 发表于 2013-2-3 21:21:53

lcofjp 发表于 2013-2-3 10:16 static/image/common/back.gif
我在上个帖子中说过了是数据对齐的问题,然后有个哥们澄清说M3不存在对齐的问题,但是我对它的结论表示遗憾 ...

m3的确不存在对齐问题...但如果是OS特殊地方要求对齐...这个和芯片就无关了...

lcofjp 发表于 2013-2-3 22:38:09

snoopyzz 发表于 2013-2-3 21:21 static/image/common/back.gif
m3的确不存在对齐问题...但如果是OS特殊地方要求对齐...这个和芯片就无关了... ...

m3确实可以访问奇数地址的整形等特性,但不是所有指令都具有这个特性。我遇到过很多次fault问题,有大部分是对齐问题,当然我是不用os的,只是裸跑,你有时间可以验证下ldm这个指令。

snoopyzz 发表于 2013-2-3 22:41:59

lcofjp 发表于 2013-2-3 22:38 static/image/common/back.gif
m3确实可以访问奇数地址的整形等特性,但不是所有指令都具有这个特性。我遇到过很多次fault问题,有大部 ...

你用了嵌入式汇编? 用纯C的话...编译器应该会避开这些问题的

lcofjp 发表于 2013-2-3 22:47:09

snoopyzz 发表于 2013-2-3 22:41 static/image/common/back.gif
你用了嵌入式汇编? 用纯C的话...编译器应该会避开这些问题的

编译器是避不开的,编译器无法知情,更多的时候我们使用指针,在不知不觉中就乱指了。如果一个整型变量肯定不会出问题,出问题的时候都是指针或者数组,这是ldm才有用武之地。

delphiliu 发表于 2013-2-4 08:25:19

i_kkyu 发表于 2013-2-3 19:14 static/image/common/back.gif
STM32F107 ,RTT ,1.01 MDK

      103 和107的芯片都会出现同样的问题。RTT版本为1.00

delphiliu 发表于 2013-2-4 08:31:29

i_kkyu 发表于 2013-2-3 11:49 static/image/common/back.gif
怪不得,我在RTT中,全局的变量定义任意长度的数组,初始化,没出现您提到的现象。。。 ...

数组初始化为元素全部为0或者不初始化的时候才会出现这个问题。

delphiliu 发表于 2013-2-4 08:33:30

SNOOKER 发表于 2013-2-3 12:51 static/image/common/back.gif
堆栈最好8字节对齐,要不然编译器也会加补丁对齐的

请问为什么是8字节对齐的?

delphiliu 发表于 2013-2-4 09:26:31

ffxz 发表于 2013-2-3 21:17 static/image/common/back.gif
你是使用静态线程方式吧,看看idle线程是如何去定义栈的(rt_thread_stack)。

是这个问题。解决了。
页: [1]
查看完整版本: [求助]定义全局数组会导致硬fault,STM32系列,RTT系统