【问题标题】:Why does trace_printf("%f",x); trigger a hard fault on an STM32 MCU?为什么 trace_printf("%f",x);在 STM32 MCU 上触发硬故障?
【发布时间】:2017-11-15 00:33:38
【问题描述】:

我在 Eclipse 中使用带有 HAL 库的 STM32 F413ZH 微控制器(主要是为与 C 一起使用,但也可以与 C++ 一起使用)。实际上,我设法完全配置了 Eclipse,包括半主机和调试模式 (OpenOCD)、基本项目文件,并且我还设法手动调整了 STM32CubeMX 提供的基本项目文件以使用 C++。所以...现在我可以在 C++ Eclipse 环境中使用 HAL 库,并使用半主机通过 OpenOCD 和 trace_printf trace_puts 测试我的代码。

现在,又一次,在设置 STM32 环境苦苦挣扎之后,我发现自己卡住了,但这次不同了。

这 7 天以来,我一直在寻找解决问题的方法,并且在网上尝试了许多类似问题的建议,但都没有解决我的问题。

好吧,在调试时在半主机中使用 trace_printf() 时,我遇到了一个严重的错误。如果我使用这个函数通过半主机打印一个整数 (%d) 一切都很好,我可以在 OpenOCD 控制台中读取打印的值,但是当我尝试使用 %f 格式化程序打印一个值时,所谓的打印数据不是t 显示在 OpenOCD 控制台中。

然后我读到,为了启用浮点值的打印,我需要将-u _printf_float 添加到链接器标志,所以在添加标志后,我尝试 trace_printf() 浮点值、整数值或其他数据类型,但它们都使用 %f 格式化程序,但我在 trace_printf() 中使用 %f 时经常遇到硬错误。

[HardFault]
Stack frame:
R0 = 00666E69
R1 = 2004FE78
R2 = 2004FF00
R3 = 00666E69
R12 = F642D800
LR = 08005DE7
PC = 08006586
PSR = 01000000
FSR/FAR:
CFSR = 00008200
HFSR = 40000000
DFSR = 0000000A
AFSR = 00000000
BFAR = 00666E69
Misc
LR/EXC_RETURN= FFFFFFF9

通过逐步调试,调用该函数后触发硬故障处理程序:vsnprintf()

我正在使用这些链接器标志:

-T mem.ld -T libs.ld -T sections.ld -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"ThreePhaseSignals.map" --specs=nano.specs -u _printf_float

我的项目设置是:

Project toolchains

Target processor settings

C++ preprocessor

Linker settings and flags

我的 _sbrk.c 是:

_sbrk.c

我的链接器文件是:

mem.ld 是: mem.ld

sections.ld 是:

/*
 * Default linker script for Cortex-M (it includes specifics for
 STM32F[34]xx).
 *
 * To make use of the multi-region initialisations, define
 * OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS for the _startup.c file.
 */


/*
 * The '__stack' definition is required by crt0, do not remove it.
 */
  __stack = ORIGIN(RAM) + LENGTH(RAM);

  _estack = __stack; /* STM specific definition */

/*
 * Default stack sizes.
 * These are used by the startup in order to allocate stacks
 * for the different modes.
 */

__Main_Stack_Size = 1024;

PROVIDE ( _Main_Stack_Size = __Main_Stack_Size );

__Main_Stack_Limit = __stack  - __Main_Stack_Size;

/* "PROVIDE" allows to easily override these values from an
 * object file or the command line. */
PROVIDE(_Main_Stack_Limit = __Main_Stack_Limit);

/*
 * There will be a link error if there is not this amount of
 * RAM free at the end.
 */
_Minimum_Stack_Size = 256;

/*
 * Default heap definitions.
 * The heap start immediately after the last statically allocated
 * .sbss/.noinit section, and extends up to the main stack limit.
 */
PROVIDE(_Heap_Begin = _end_noinit);
PROVIDE(_Heap_Limit = __stack - __Main_Stack_Size);

/*
 * The entry point is informative, for debuggers and simulators,
 * since the Cortex-M vector points to it anyway.
 */
ENTRY(_start)


/* Sections Definitions */

SECTIONS
{
    /*
     * For Cortex-M devices, the beginning of the startup code is stored in
     * the .isr_vector section, which goes to FLASH.
     */
    .isr_vector : ALIGN(4)
    {
        FILL(0xFF)

        __vectors_start = ABSOLUTE(.);
        __vectors_start__ = ABSOLUTE(.); /* STM specific definition */
        KEEP(*(.isr_vector))             /* Interrupt vectors */

        KEEP(*(.cfmconfig))              /* Freescale configuration words */

        /*
         * This section is here for convenience, to store the
         * startup code at the beginning of the flash area, hoping that
         * this will increase the readability of the listing.
         */
        *(.after_vectors .after_vectors.*)    /* Startup code and ISR */
    } >FLASH

    .inits : ALIGN(4)
    {
        /*
         * Memory regions initialisation arrays.
         *
         * Thee are two kinds of arrays for each RAM region, one for
         * data and one for bss. Each is iterrated at startup and the
         * region initialisation is performed.
         *
         * The data array includes:
         * - from (LOADADDR())
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * The bss array includes:
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * WARNING: It is mandatory that the regions are word aligned,
         * since the initialisation code works only on words.
         */

        __data_regions_array_start = .;

        LONG(LOADADDR(.data));
        LONG(ADDR(.data));
        LONG(ADDR(.data)+SIZEOF(.data));

        LONG(LOADADDR(.data_CCMRAM));
        LONG(ADDR(.data_CCMRAM));
        LONG(ADDR(.data_CCMRAM)+SIZEOF(.data_CCMRAM));

        __data_regions_array_end = .;

        __bss_regions_array_start = .;

        LONG(ADDR(.bss));
        LONG(ADDR(.bss)+SIZEOF(.bss));

        LONG(ADDR(.bss_CCMRAM));
        LONG(ADDR(.bss_CCMRAM)+SIZEOF(.bss_CCMRAM));

        __bss_regions_array_end = .;

        /* End of memory regions initialisation arrays. */

        /*
         * These are the old initialisation sections, intended to contain
         * naked code, with the prologue/epilogue added by crti.o/crtn.o
         * when linking with startup files. The standalone startup code
         * currently does not run these, better use the init arrays below.
         */
        KEEP(*(.init))
        KEEP(*(.fini))

        . = ALIGN(4);

        /*
         * The preinit code, i.e. an array of pointers to initialisation
         * functions to be performed before constructors.
         */
        PROVIDE_HIDDEN (__preinit_array_start = .);

        /*
         * Used to run the SystemInit() before anything else.
         */
        KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))

        /*
         * Used for other platform inits.
         */
        KEEP(*(.preinit_array_platform .preinit_array_platform.*))

        /*
         * The application inits. If you need to enforce some order in
         * execution, create new sections, as before.
         */
        KEEP(*(.preinit_array .preinit_array.*))

        PROVIDE_HIDDEN (__preinit_array_end = .);

        . = ALIGN(4);

        /*
         * The init code, i.e. an array of pointers to static constructors.
         */
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array))
        PROVIDE_HIDDEN (__init_array_end = .);

        . = ALIGN(4);

        /*
         * The fini code, i.e. an array of pointers to static destructors.
         */
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP(*(SORT(.fini_array.*)))
        KEEP(*(.fini_array))
        PROVIDE_HIDDEN (__fini_array_end = .);
    } >FLASH

    /*
     * For some STRx devices, the beginning of the startup code
     * is stored in the .flashtext section, which goes to FLASH.
     */
    .flashtext : ALIGN(4)
    {
        *(.flashtext .flashtext.*)    /* Startup code */
    } >FLASH


    /*
     * The program code is stored in the .text section,
     * which goes to FLASH.
     */
    .text : ALIGN(4)
    {
        *(.text .text.*)            /* All remaining code */

        /* Read-only data (constants) */
        *(.rodata .rodata.* .constdata .constdata.*)

        *(vtable)                    /* C++ virtual tables */

        KEEP(*(.eh_frame*))

        /*
         * Stub sections generated by the linker, to glue together
         * ARM and Thumb code. .glue_7 is used for ARM code calling
         * Thumb code, and .glue_7t is used for Thumb code calling
         * ARM code. Apparently always generated by the linker, for some
         * architectures, so better leave them here.
         */
        *(.glue_7)
        *(.glue_7t)

    } >FLASH

    /* ARM magic sections */
    .ARM.extab : ALIGN(4)
        {
            *(.ARM.extab* .gnu.linkonce.armextab.*)
        } > FLASH

    . = ALIGN(4);
    __exidx_start = .;
    .ARM.exidx : ALIGN(4)
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > FLASH
    __exidx_end = .;

    . = ALIGN(4);
    _etext = .;
    __etext = .;

    /* MEMORY_ARRAY */
    /*
    .ROarraySection :
    {
        *(.ROarraySection .ROarraySection.*)
    } >MEMORY_ARRAY
    */

    /*
     * The secondary initialised data section.
     */
    .data_CCMRAM : ALIGN(4)
    {
        FILL(0xFF)
        *(.data.CCMRAM .data.CCMRAM.*)
        . = ALIGN(4) ;
    } > CCMRAM AT>FLASH

    /*
     * This address is used by the startup code to
     * initialise the .data section.
     */
    _sidata = LOADADDR(.data);

    /*
     * The initialised data section.
     *
     * The program executes knowing that the data is in the RAM
     * but the loader puts the initial values in the FLASH (inidata).
     * It is one task of the startup to copy the initial values from
     * FLASH to RAM.
     */
    .data : ALIGN(4)
    {
        FILL(0xFF)
        /* This is used by the startup code to initialise the .data section */
        _sdata = . ;            /* STM specific definition */
        __data_start__ = . ;
        *(.data_begin .data_begin.*)

        *(.data .data.*)

        *(.data_end .data_end.*)
        . = ALIGN(4);

        /* This is used by the startup code to initialise the .data section */
        _edata = . ;            /* STM specific definition */
        __data_end__ = . ;

    } >RAM AT>FLASH

    /*
     * The uninitialised data sections. NOLOAD is used to avoid
     * the "section `.bss' type changed to PROGBITS" warning
     */

    /* The secondary uninitialised data section. */
    .bss_CCMRAM (NOLOAD) : ALIGN(4)
    {
        *(.bss.CCMRAM .bss.CCMRAM.*)
    } > CCMRAM

    /* The primary uninitialised data section. */
    .bss (NOLOAD) : ALIGN(4)
    {
        __bss_start__ = .;      /* Standard newlib definition */
        _sbss = .;              /* STM specific definition */
        *(.bss_begin .bss_begin.*)

        *(.bss .bss.*)
        *(COMMON)

        *(.bss_end .bss_end.*)
        . = ALIGN(4);
        __bss_end__ = .;        /* Standard newlib definition */
        _ebss = . ;             /* STM specific definition */
    } >RAM

    .noinit_CCMRAM (NOLOAD) : ALIGN(4)
    {
        *(.noinit.CCMRAM .noinit.CCMRAM.*)
    } > CCMRAM

    .noinit (NOLOAD) : ALIGN(4)
    {
        _noinit = .;

        *(.noinit .noinit.*)

         . = ALIGN(4) ;
        _end_noinit = .;
    } > RAM

    /* Mandatory to be word aligned, _sbrk assumes this */
    PROVIDE (end = _end_noinit); /* Was _ebss */
    PROVIDE (_end = _end_noinit);
    PROVIDE (__end = _end_noinit);
    PROVIDE (__end__ = _end_noinit);

    /*
     * Used for validation only, do not allocate anything here!
     *
     * This is just to check that there is enough RAM left for the Main
     * stack. It should generate an error if it's full.
     */
    ._check_stack : ALIGN(4)
    {
        . = . + _Minimum_Stack_Size;
    } >RAM

    /*
     * The FLASH Bank1.
     * The C or assembly source must explicitly place the code
     * or data there using the "section" attribute.
     */
    .b1text : ALIGN(4)
    {
        *(.b1text)           /* Remaining code */
        *(.b1rodata)         /* Read-only data (constants) */
        *(.b1rodata.*)
    } >FLASHB1

    /*
     * The EXTMEM.
     * The C or assembly source must explicitly place the code or data there
     * using the "section" attribute.
     */

    /* EXTMEM Bank0 */
    .eb0text : ALIGN(4)
    {
        *(.eb0text)          /* Remaining code */
        *(.eb0rodata)        /* Read-only data (constants) */
        *(.eb0rodata.*)
    } >EXTMEMB0

    /* EXTMEM Bank1 */
    .eb1text : ALIGN(4)
    {
        *(.eb1text)          /* Remaining code */
        *(.eb1rodata)        /* Read-only data (constants) */
        *(.eb1rodata.*)
    } >EXTMEMB1

    /* EXTMEM Bank2 */
    .eb2text : ALIGN(4)
    {
        *(.eb2text)          /* Remaining code */
        *(.eb2rodata)        /* read-only data (constants) */
        *(.eb2rodata.*)
    } >EXTMEMB2

    /* EXTMEM Bank0 */
    .eb3text : ALIGN(4)
    {
        *(.eb3text)          /* Remaining code */
        *(.eb3rodata)        /* Read-only data (constants) */
        *(.eb3rodata.*)
    } >EXTMEMB3


    /* After that there are only debugging sections. */

    /* This can remove the debugging information from the standard libraries */
    /*
    DISCARD :
    {
     libc.a ( * )
     libm.a ( * )
     libgcc.a ( * )
     }
     */

    /* Stabs debugging sections.  */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /*
     * DWARF debug sections.
     * Symbols in the DWARF debugging sections are relative to the beginning
     * of the section so we begin them at 0.
     */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }
 }

网上很多人说这是因为打印浮点数会消耗大量内存,并且微控制器可能由于内存溢出而崩溃,所以很多建议旨在修改进行堆栈和堆分配的链接描述文件,还有一些其他人说这个硬故障与newlib中的_sbrk.c有关。

我试图根据我的具体情况调整这些解决方案,但直到现在我的问题仍未解决。我不知道我是否没有很好地执行这些建议,或者只是我的问题有所不同。

我该如何解决这个问题?

【问题讨论】:

标签: eclipse linker printf floating


【解决方案1】:

解决了。观看以下视频,如果不起作用,请观看完整系列视频。

STM32 with Eclipse, GNU ARM and J-Link. Part 4 - Minimal CMSIS Project - ITM Printf Debugging

【讨论】:

    猜你喜欢
    • 2021-09-19
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 2020-08-12
    • 2022-01-21
    • 2016-03-04
    • 2014-12-07
    相关资源
    最近更新 更多