的snprintf()打印与newlib纳米垃圾花车 [英] snprintf() prints garbage floats with newlib nano

查看:959
本文介绍了的snprintf()打印与newlib纳米垃圾花车的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我运行了ARM Cortex-M3(STM32F205)裸机嵌入式系统。当我尝试使用的snprintf()与浮点数,例如:

I am running a bare metal embedded system with an ARM Cortex-M3 (STM32F205). When I try to use snprintf() with float numbers, e.g.:

float f;

f = 1.23;
snprintf(s, 20, "%5.2f", f);

我收到垃圾进入取值。格式似乎兑现,即垃圾是一个结构良好的字符串,数字,小数点和两个尾部位数。但是,如果我重复的snprintf ,字符串可能两个电话之间切换。

I get garbage into s. The format seems to be honored, i.e. the garbage is a well-formed string with digits, decimal point, and two trailing digits. However, if I repeat the snprintf, the string may change between two calls.

浮点数学好像不工作,和的snprintf 与整数作品,例如:

Floating point mathematics seems to work otherwise, and snprintf works with integers, e.g.:

snprintf(s, 20, "%10d", 1234567);

我用 newlib纳米执行与 -u _printf_float 链接器开关。编译器是臂无 - EABI - 海合会

I use the newlib-nano implementation with the -u _printf_float linker switch. The compiler is arm-none-eabi-gcc.

我确实有内存分配问题强烈怀疑,因为整数打印没有任何的毛病,但如果他们在这个过程中被损坏了漂浮的行为。在的printf 家庭函数调用的malloc 用浮漂,不是整数。

I do have a strong suspicion of memory allocation problems, as integers are printed without any hiccups, but floats act as if they got corrupted in the process. The printf family functions call malloc with floats, not with integers.

code不属于 newlib 我现在用在这方面的唯一的一块是我的 _sbrk(),这是由的malloc 。

The only piece of code not belonging to newlib I am using in this context is my _sbrk(), which is required by malloc.

caddr_t _sbrk(int incr)
{
  extern char _Heap_Begin; // Defined by the linker.
  extern char _Heap_Limit; // Defined by the linker.

  static char* current_heap_end;
  char* current_block_address;

  // first allocation
  if (current_heap_end == 0)
      current_heap_end = &_Heap_Begin;

  current_block_address = current_heap_end;

  // increment and align to 4-octet border
  incr = (incr + 3) & (~3);
  current_heap_end += incr;

  // Overflow?
  if (current_heap_end > &_Heap_Limit)
    {
    errno = ENOMEM;
    current_heap_end = current_block_address;
    return (caddr_t) - 1;
    }

  return (caddr_t)current_block_address;
}

据我已经能够跟踪,这应该工作。似乎没有人曾经有负增量调用它,但我想这是由于newlib 的malloc 的设计。唯一稍微奇怪的是,到 _sbrk 第一次调用具有零增量。 (不过这可能只是的malloc的关于堆的起始地址的好奇心。)

As far as I have been able to track, this should work. It seems that no-one ever calls it with negative increments, but I guess that is due to the design of the newlib malloc. The only slightly odd thing is that the first call to _sbrk has a zero increment. (But this may be just malloc's curiosity about the starting address of the heap.)

堆栈不应与堆碰撞,因为有大约60 KIB RAM用于两个。链接描述文件可能是疯了,但至少堆和栈地址似乎是正确的。

The stack should not collide with the heap, as there is around 60 KiB RAM for the two. The linker script may be insane, but at least the heap and stack addresses seem to be correct.

推荐答案

由于可能会发生别人得到由同一个被咬的bug,我发布一个答案,我自己的问题。然而,它的@Notlikethat评论这表明正确的答案。

As it may happen that someone else gets bitten by the same bug, I post an answer to my own question. However, it was @Notlikethat 's comment which suggested the correct answer.

这是你不可偷盗的一个教训。我借它来了与STMCubeMX code发电机gcc的链接脚本。不幸的是,启动文件以及脚本坏了。

This is a lesson of Thou shall not steal. I borrowed the gcc linker script which came with the STMCubeMX code generator. Unfortunately, the script along with the startup file is broken.

原来的链接描述文件的相关部分:

The relevant part of the original linker script:

_estack = 0x2000ffff;

和其对应的启动脚本:

Reset_Handler:  
  ldr   sp, =_estack     /* set stack pointer */
...

g_pfnVectors:
  .word  _estack
  .word  Reset_Handler
...

第一中断向量位置(0)应该始终指向启动栈顶。当达到复位中断时,它也装入堆栈指针。 (至于我可以说,后者是不必要的,因为反正HW重新加载从第0向量的SP调用复位处理程序之前。)

The first interrupt vector position (at 0) should always point to the startup stack top. When the reset interrupt is reached, it also loads the stack pointer. (As far as I can say, the latter one is unnecessary as the HW anyway reloads the SP from the 0th vector before calling the reset handler.)

在Cortex-M堆栈指针应始终指向堆栈中的最后一个项目。在启动时有在堆栈中没有物品,因此,指针应指向上面在这种情况下,实际的存储器,0x020010000的首地址。堆栈指针设置为0x0200ffff,这实际上会导致SP = 0x0200fffc(硬件势力字对齐堆栈)原链接脚本。在此之后,堆栈是由4对齐。

The Cortex-M stack pointer should always point to the last item in the stack. At startup there are no items in the stack and thus the pointer should point to the first address above the actual memory, 0x020010000 in this case. With the original linker script the stack pointer is set to 0x0200ffff, which actually results in sp = 0x0200fffc (the hardware forces word-aligned stack). After this the stack is misaligned by 4.

我通过删除 _estack 的不断定义,如下图所示由 _stacktop 替换它改变了链接脚本。内存定义在那里了。我改变了名称只是为了看看其中使用的值。

I changed the linker script by removing the constant definition of _estack and replacing it by _stacktop as shown below. The memory definitions were there before. I changed the name just to see where the value is used.

MEMORY
{
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 128K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 64K
}

_stacktop = ORIGIN(RAM) + LENGTH(RAM);

_stacktop 的值之后为0x20010000,和我的数字飘起美丽的...可以使用双倍长度参数任何外部(库)功能出现同样的问题,为的ARM Cortex ABI指出,堆栈必须调用外部函数时对齐到8字节。

After this the value of _stacktop is 0x20010000, and my numbers float beautifully... The same problem could arise with any external (library) function using double length parameters, as the ARM Cortex ABI states that the stack must be aligned to 8 octets when calling external functions.

这篇关于的snprintf()打印与newlib纳米垃圾花车的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆