的snprintf()打印与newlib纳米垃圾花车 [英] snprintf() prints garbage floats with newlib nano
问题描述
我运行了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屋!