【问题标题】:AVR/GNU C Compiler and static memory allocationAVR/GNU C 编译器和静态内存分配
【发布时间】:2015-09-21 10:32:09
【问题描述】:

更新 - 改写问题:

因为我知道错误是什么!如何知道嵌入式编译时静态分配何时失败?

老年人:

我在下面的“C”中有这个简单易懂的代码,在带有 2K SRAM 的 Atmega328P-AU 中运行。我使用性能良好的 UART 库(我在调试过程中使用了很多)在我的 PC 终端中获取调试字符串。

此代码中有一个错误:它冻结了。我得到的只是这个输出......

Hello World - 加载中

我应该为每个循环获得一个 '+'

你能解释一下为什么会冻结以及为什么编译器没有通知我静态分配的内存比 uC 所能获得的多。

代码中包含您可能需要的所有信息。

/**************************************************************************************************
   Info
**************************************************************************************************/
/*
    Device:     Atmega328P-AU - No arduino
    IDE:        Atmel Studio 6.2
    Compiler:   AVR/GNU C Compiler : 4.8.1
    F_CPU:      8000000 Hz defined in makefile
    Fuses:
                Extended:   0x07
                High:       0xD9
                Low:        0xE2
                Lockbit:    0xFF

    When compiled it show in build output these:            

           text    data     bss     dec     hex filename
           1088       0      57    1145     479 Bug Catcher.elf
           Done executing task "RunCompilerTask".
           Task "RunOutputFileVerifyTask"
           Program Memory Usage     :   1088 bytes   3,3 % Full
           Data Memory Usage        :   57 bytes   2,8 % Full
           Done executing task "RunOutputFileVerifyTask".
           Done building target "CoreBuild" in project "Bug Catcher.cproj".
           Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != '').
           Target "Build" in file "C:\Program Files\Atmel\Atmel Studio 6.2\Vs\Avr.common.targets" from project "C:\Users\Tedi\Desktop\Bug Catcher\Bug Catcher\Bug Catcher.cproj" (entry point):
           Done building target "Build" in project "Bug Catcher.cproj".
           Done building project "Bug Catcher.cproj".

           Build succeeded.
           ========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

*/

/**************************************************************************************************
   Definitions
**************************************************************************************************/

#define BIG_NUMBER                  1000

// Atmega328P - Pin 12
#define SOFT_UART_RX_DDR            DDRB
#define SOFT_UART_RX_DDR_bit        DDB0
#define SOFT_UART_RX_PORT           PORTB
#define SOFT_UART_RX_PORT_bit       PORTB0
#define SOFT_UART_RX_PIN            PINB
#define SOFT_UART_RX_PIN_bit        PINB0

// Atmega328P Pin 13
#define SOFT_UART_TX_DDR            DDRB
#define SOFT_UART_TX_DDR_bit        DDB1
#define SOFT_UART_TX_PORT           PORTB
#define SOFT_UART_TX_PORT_bit       PORTB1
#define SOFT_UART_TX_PIN            PINB
#define SOFT_UART_TX_PIN_bit        PINB1

/**************************************************************************************************
   Includes
**************************************************************************************************/

#include "softuart.h"

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>

/**************************************************************************************************
   Main function
**************************************************************************************************/

int main()
{   
    /**********************************************************************************************
       Setup
    **********************************************************************************************/

    softuart_init(  &SOFT_UART_TX_DDR, SOFT_UART_TX_DDR_bit,
                    &SOFT_UART_TX_PORT, SOFT_UART_TX_PORT_bit,
                    &SOFT_UART_RX_DDR, SOFT_UART_RX_DDR_bit,
                    &SOFT_UART_RX_PIN, SOFT_UART_RX_PIN_bit );

    sei();

    softuart_puts_P( "\r\n\r\nHello World - Loading\r\n\r\n" ); // Can use custom UART function.
    _delay_ms( 200 );

    /**********************************************************************************************
       Forever loop
    **********************************************************************************************/
    while(1)
    {
        char temp[BIG_NUMBER];
        memset( temp, '\0', sizeof( temp ) );
        {
            char temp[BIG_NUMBER];
            memset( temp, '\0', sizeof( temp ) );
            {
                char temp[BIG_NUMBER];
                memset( temp, '\0', sizeof( temp ) );
            }
        }
        softuart_puts_P("+"); // BUG!!!!! It never reaches here.
        _delay_ms( 500 );
    }
}

【问题讨论】:

  • 由于编译器不知道你的目标有多少内存,它应该如何警告?它是执行重定位和绑定的链接器,因此您必须检查链接器命令文件。你可能已经指定了错误的目标,文件可能是错误的,等等。无论如何,“我的代码被冻结”不是特定的错误语句。请启动调试器以获得更准确的原因。
  • 我使用 USBasp 编程器和 FTDI 芯片作为从 uC 获取字符串的一种方式。我没有调试器 :( 使用 IDE 模拟器,当我尝试调试时,它会在 trird memset 函数中冻结。
  • “我没有调试器”和“当我尝试调试它时冻结”不要放在一起。有可用于 AVR 的调试器,只需搜索即可。但是,在模拟器中,您应该能够检查状态 - 这正是您使用它的原因!
  • 我是自学编程的,有很多对其他人来说显而易见的想法,我很幸运能够理解。让我们从头开始。短语“冻结”是指模拟器一直在第三个 memset 函数中,并且永远不会进入下一个命令。你说的状态是什么意思?检查什么?
  • @Olaf 很可能他希望它在 编译时 失败,如果您提供合适的链接器文件,这可能是可能的。 (至少你可以为全局内存做到这一点)

标签: c debugging avr avr-gcc


【解决方案1】:

链接器分配静态存储,在您的情况下为 57 个字节(数据加上 bss 段)。因此,只要您的静态存储变量太大,您应该会看到来自链接器的错误消息。

变量temp[1000] 是一个自动变量,它在运行时分配在堆栈上。链接器未静态分配的 RAM 用于堆栈。这个错误是一个简单的案例,您分配的单个变量大于设备的整个 RAM,但通常这种错误真的很难检测到。一种解决方案是在运行时检查可用的堆栈空间。作为一个简单的规则:不要在堆栈上分配大的东西。只有在调用该函数时才会看到它失败。

temp[1000] 用于程序的整个运行时,因此您只需将其移动到静态存储中就不会丢失任何东西。在它前面放一个“静态”,你会(希望)看到来自链接器的错误消息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 2015-10-22
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多