Arm 尝试打印F编号时出现STM32硬故障>;=10

Arm 尝试打印F编号时出现STM32硬故障>;=10,arm,printf,stm32,cortex-m3,newlib,Arm,Printf,Stm32,Cortex M3,Newlib,临时解决方案 我用tiny printf解决了这个问题: 可能是newlibprintf占用了太多内存。在此之后,PC会发生一些奇怪的变化,理论上,这应该是数组char[100]的结尾 cp = buf + BUF 后来它尝试执行 *--cp = something 它崩溃了。内存错误?有很多事情我不明白。例如,我不确定链接器脚本是否正确,或者系统调用函数是否正确。在我进一步理解之前,我必须坚持使用微小的printf 原创 我有一个STM32F103RB板(核仁),我刚刚让USAR

临时解决方案

我用tiny printf解决了这个问题:

可能是newlibprintf占用了太多内存。在此之后,PC会发生一些奇怪的变化,理论上,这应该是数组
char[100]
的结尾

cp = buf + BUF
后来它尝试执行

*--cp = something
它崩溃了。内存错误?有很多事情我不明白。例如,我不确定链接器脚本是否正确,或者系统调用函数是否正确。在我进一步理解之前,我必须坚持使用微小的printf


原创

我有一个STM32F103RB板(核仁),我刚刚让USART1工作。此外,我还测试了Newlib函数,
put()
工作正常。但是,当我尝试对整数使用
printf()
时,如下所示:

printf("ADC: %d\r\n", test);
如果
test<10
程序工作,但如果
test>=10
则产生硬故障。经过一些GDB调试后,我发现它是从vfprintf生成的:

#0  HardFault_Handler () at main.c:136
#1  <signal handler called>
#2  0x08005af4 in _vfprintf_r (data=<optimized out>, fp=0x20000384 <impure_data+852>, fmt0=fmt0@entry=0x20004f57 " \254\264", ap=...,
    ap@entry=...) at ../../../../../../newlib/libc/stdio/vfprintf.c:1601
#3  0x08004fd0 in printf (fmt=0x800b4ac "ADC: %d\n\r") at ../../../../../../newlib/libc/stdio/printf.c:52
#4  0x080004e8 in main () at main.c:168
我的最小堆栈大小配置为1024字节。我试图增加到10k,但它仍然会产生这个硬故障。我不知道如何调试这个或找到问题。我怎样才能修好它

我注意到一件事。失败发生在
vfprintf.c:1601
,我检查了GDB中的指针
cp

(gdb) x 0x20004f57
0x20004f57:     0x00b4ac20
(gdb) x 0x00b4ac20
0xb4ac20:       0x20004f80
(gdb) x 0x20004f58
0x20004f58:     0x0800b4ac
(gdb)
我不知道为什么地址
0x20004f57
指向一个不存在的地址

另外,
p\u stackend
给出

$6 = (caddr_t) 0xb33ea8a6 <error: Cannot access memory at address 0xb33ea8a6>
链接器脚本:

/*
Linker script for STM32F10x_128K_20K

modified from

http://www.codesourcery.com/archives/arm-gnu/msg02972.html
http://communities.mentor.com/community/cs/archives/arm-gnu/msg02972.html
*/

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

/* _Minimum_Stack_Size = 256; */
_Minimum_Stack_Size = 1024;

ENTRY(Reset_Handler)


/* Memory Spaces Definitions */

MEMORY
{
  RAM (rwx)  : ORIGIN = 0x20000000, LENGTH = 20K
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

__ram_start__ = ORIGIN(RAM);
__ram_size__  = LENGTH(RAM);
__ram_end__   = __ram_start__ + __ram_size__;
_estack = __ram_end__;
/* highest address of the user mode stack */



PROVIDE ( _Stack_Limit = _estack - _Minimum_Stack_Size );

/* Sections Definitions */

SECTIONS
{
    .text :
    {
        KEEP(*(.isr_vector))            /* Startup code */
        *(.text)                   /* code */
        *(.text.*)                 /* remaining code */
        *(.rodata)                 /* read-only data (constants) */
        *(.rodata.*)
        *(.glue_7)
        *(.glue_7t)
        *(.vfp11_veneer)
        *(.v4_bx)
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } >FLASH

    /* for exception handling/unwind - some Newlib functions (in
    common with C++ and STDC++) use this. */
    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)

    } > FLASH

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

    . = ALIGN(4);
     _etext = .;
    /* This is used by the startup in order to initialize the .data secion
*/
    _sidata = _etext;

    /* This is the initialized 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  : AT ( _sidata )
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data
secion */
        _sdata = . ;

        *(.data)
        *(.data.*)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data
secion */
        _edata = . ;
    } >RAM


    /* This is the uninitialized data section */
    .bss :
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss
secion */
        _sbss = .;
    __bss_start__ = _sbss;
        *(.bss)
        *(.bss.*)
        *(COMMON)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss
secion */
        _ebss = . ;
    __bss_end__ = _ebss;
    } >RAM

    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );
    PROVIDE ( _exit = _ebss );
    PROVIDE (_stackend = ORIGIN(RAM) + LENGTH(RAM) - _Minimum_Stack_Size);

    /* This is the user stack section
    This is just to check that there is enough RAM left for the User mode
stack
    It should generate an error if it's full.
     */
    ._usrstack :
    {
        . = ALIGN(4);
        _susrstack = . ;

        . = . + _Minimum_Stack_Size ;

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



    /* after that it's only debugging information. */

    /* 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) }
}

我不太理解这个链接器脚本,我修改了“发现STM32微控制器”附带的脚本。

好的,经过各种测试,我发现它就是我使用的工具链。我自己使用GCC4.8构建了工具链,据我所知,GCC4.8存在一些问题。我切换回CodeSourcery toolchain,它再次工作。

我也遇到了同样的问题(也是arm none eabi gcc 4.8),经过一些调试后,我意识到使用了64位除法,这导致了硬故障。事实证明,编译器是针对错误的libgcc进行链接的,因为执行状态(thumb,ARM)是在编译期间指定的,而不是链接

根据处理器的不同指定
-mcpu=cortex-m3-mthumb
-mcpu=cortex-m4-mthumb
后,编译器和链接器的问题都消失了


成功打印小于10的数字的原因是_vfprintf_r函数在转换为十进制格式时有一个特殊情况,该格式不使用64位除法,因此没有硬故障。

在ATMEL E70上使用ARM gcc工具链,我通过向编译器添加-Dprintf=iprintf解决了这个问题(和链接器)参数。
Atmel示例似乎使用了这个方法,它对我很有效。我曾尝试增大堆栈大小(到32k)并确保将-mcpu=cortex-m7-mthumb同时传递给编译器和链接器,但问题仍然存在。

我们可以查看您的链接器脚本吗?如果您在顶部声明了所有大小,则这是最重要的片段。链接器脚本看起来正常。
\u stackend
在printf调用之前或之后是否损坏?您可以看到通过查看链接器脚本中的计算应该是什么。另外,
\u end
设置为什么?这也是由链接器脚本根据您的程序特征计算的。实际上我不太理解该脚本,所以我不知道在执行过程中发生了什么变化。
\u stackend
会变化吗?我认为它们是固定的,对吗?是的,它们是固定的,但关键是您看到它们已损坏。它们应该位于SRAM空间(0x2000xxxx)中。了解它们是否在
main()的条目中设置错误会很有用
或者如果它们在调用
printf
后变得不正确。那么我是否只需要使用调试器来显示它们并尝试找出答案?我会尝试。另外,
\u stackend
是一个变量?还是内存中的一个符号?因为如果它们是固定的,那么为什么它们会被更改?用+1表示持久化并自行修复。好的不!工具链可能会解决问题,因为内存布局发生了轻微的变化。小心点-这有堆栈溢出的味道(多么合适!!)或者写入超过缓冲区的末尾。可能的缓解措施是将堆栈放在RAM的底部,这样它就不会撞击其他区域,并且当它尝试写入0x20000000以下时,可能会引发异常。@SilverCode问题是,我对两个工具链使用相同的LD脚本…我认为堆栈是在RA末尾配置的M
3: cp = <optimized out>
2: fmt = 0x800b453 "\n\r"
(gdb) n
1057                            base = DEC;
3: cp = <optimized out>
2: fmt = 0x800b453 "\n\r"
(gdb)
1400    number:                 if ((dprec = prec) >= 0)
3: cp = <optimized out>
2: fmt = 0x800b453 "\n\r"
(gdb)
1409                            if (_uquad != 0 || prec != 0) {
3: cp = 0x20004b58 "\245ۊ\256\211W{\325\326\377Y\352\224\t x\207\220\230&-\031\032~\337\032\371\024\254\"(\214\354\363\b\241\365\022\035\037\252\026\243\206\235P\005OZn\245c\n\352\244E^ά\246\301Ӕ\271L\264"
2: fmt = 0x800b453 "\n\r"
(gdb)
/*
Linker script for STM32F10x_128K_20K

modified from

http://www.codesourcery.com/archives/arm-gnu/msg02972.html
http://communities.mentor.com/community/cs/archives/arm-gnu/msg02972.html
*/

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

/* _Minimum_Stack_Size = 256; */
_Minimum_Stack_Size = 1024;

ENTRY(Reset_Handler)


/* Memory Spaces Definitions */

MEMORY
{
  RAM (rwx)  : ORIGIN = 0x20000000, LENGTH = 20K
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

__ram_start__ = ORIGIN(RAM);
__ram_size__  = LENGTH(RAM);
__ram_end__   = __ram_start__ + __ram_size__;
_estack = __ram_end__;
/* highest address of the user mode stack */



PROVIDE ( _Stack_Limit = _estack - _Minimum_Stack_Size );

/* Sections Definitions */

SECTIONS
{
    .text :
    {
        KEEP(*(.isr_vector))            /* Startup code */
        *(.text)                   /* code */
        *(.text.*)                 /* remaining code */
        *(.rodata)                 /* read-only data (constants) */
        *(.rodata.*)
        *(.glue_7)
        *(.glue_7t)
        *(.vfp11_veneer)
        *(.v4_bx)
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } >FLASH

    /* for exception handling/unwind - some Newlib functions (in
    common with C++ and STDC++) use this. */
    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)

    } > FLASH

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

    . = ALIGN(4);
     _etext = .;
    /* This is used by the startup in order to initialize the .data secion
*/
    _sidata = _etext;

    /* This is the initialized 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  : AT ( _sidata )
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data
secion */
        _sdata = . ;

        *(.data)
        *(.data.*)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data
secion */
        _edata = . ;
    } >RAM


    /* This is the uninitialized data section */
    .bss :
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss
secion */
        _sbss = .;
    __bss_start__ = _sbss;
        *(.bss)
        *(.bss.*)
        *(COMMON)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss
secion */
        _ebss = . ;
    __bss_end__ = _ebss;
    } >RAM

    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );
    PROVIDE ( _exit = _ebss );
    PROVIDE (_stackend = ORIGIN(RAM) + LENGTH(RAM) - _Minimum_Stack_Size);

    /* This is the user stack section
    This is just to check that there is enough RAM left for the User mode
stack
    It should generate an error if it's full.
     */
    ._usrstack :
    {
        . = ALIGN(4);
        _susrstack = . ;

        . = . + _Minimum_Stack_Size ;

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



    /* after that it's only debugging information. */

    /* 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) }
}