开始尝试使用标准库的一些东西的时候,也就意味着我们的linux环境下开发STM32的教程已经接近尾声了。标准库的使用我们这里仅仅介绍使用printf和malloc。 ' ?. ~) q7 D& ^2 o; u9 f J syscalls 想使用标准库,我们需要自己完成一些系统调用。像keil mdk下使用printf一样,至少要完成fputc和fgetc。然而newlibc下使用printf却不这么简单。并不是一个__io_getchar, __io_putchar能够完成的。幸好,ST的固件库中有我们使用的大部分源码。都在TrueStudio的模板下。大家可以自行查找。我们这次使用的文件是syscalls.c。因为这个文件中使用了gnu的一些特殊的语法,所以编译工程的时候不要使用-std=c99,而是应该使用对应的gnu99(-std=gnu99)。相关的文件在printf_v1.zip中。0 S1 p6 \/ @ \/ M6 ] 在syscalls.c中有许多系统调用。比如我们前面介绍的_exit函数。这次我们主要介绍_write,_read两个函数。这两个函数是输入输出使用的。% G; p9 X. z3 u" d6 l2 y/ t1 E int _read (int file, char *ptr, int len); F/ F% k( ?; O4 T s {. K7 `1 M* f+ u8 H int DataIdx; for (DataIdx = 0; DataIdx < len; DataIdx++)# m& i7 q6 q4 r$ ? { *ptr++ = __io_getchar();, J3 n' S- ?& R$ s7 ^' A1 k }1 q. V( J s3 ?4 ~ return len;6 u. U) M( n9 V& S$ i+ i4 h }" o& z# C2 Z, @- W/ z# w; L int _write(int file, char *ptr, int len) { int DataIdx;+ g% ~# E& j9 b. [# A 1 A9 U3 O# a o# e3 J for (DataIdx = 0; DataIdx < len; DataIdx++) { __io_putchar( *ptr++ ); }5 h: H8 G7 K2 K( u4 R- G return len;3 o, `2 Y* C( @ } __io_putchar,__io_getchar这两个函数在上一节使用串口的时候就已经测试通过了。这里仅仅使用就好了。 测试printf- f% o$ g C* ^ 写点简单的代码来测试一下printf。 之后make sram,sudo make burns将代码下载至SRAM中运行测试。! [' k0 v- v: |3 s 从测试结果上来看,貌似newlib对double当作float处理了。如果对double还有其他的设置,麻烦告知。% k6 H# O; m D4 v+ J U 这里还是要多罗嗦几句。printf是行缓冲的。也就是说,在printf的末尾添加\n或者使用fflush刷新,或者main结束。否则是不会输出的。. o1 _' \! p9 Q9 `, S 2 }8 Y2 a* p7 Q |: Z 使用Newlib-nano: 刚开始看到printf的代码大小的时候,我也是吃了一惊。在keil mdk下,单纯的使用一个printf并没有这么大的代码。虽然我们的参数中也使用了ffunction-sections,fdata-sections,-Os来优化,但是代码量确实偏大。 可以尝试使用nano库来进行优化。在链接参数中使用-specs=nano.specs.相关的代码在printf_v2.zip中。6 u' H; R5 r, x4 M 加入使用nano库这个链接参数之后,编译出的代码缺少小了。减小到6K左右。 不过printf只能输出整数,不能输出小数了。! `# f- ~3 r) M+ ?5 n6 s 关于这个问题,在链接 http://community.arm.com/groups/embedded/blog/2013/01/21/shrink-your-mcu-code-size-with-gcc-arm-embedded-47中也说到了。原文如下:, p$ p5 S' `5 r) G H “ Libraries also need optimizing, because the libraries included in GCC ARM Embedded were not actually designed for MCU programming. Newlib, the C library in the toolchain, implements printf functions that are so complicated they require about 37K bytes of FLASH and 5K bytes of RAM to run a simple hello-world program. That's far too large for MCU programming where you might need printf functionality for debugging and logging purposes. The good news is that there is plenty of unnecessary "fat" in libraries that can be cut.” newlib如果不经优化的话,大约占用37K的FLASH和5K的RAM来运行一个简单的hello-world程序(使用printf输出)。对MCU编程来说,这确实是大了点。 “ Newlib-nano cuts some features that were added after C89, which are believed to be rarely used in MCU programming. By limiting the format converter to the C89 standard, format string processing code in printf is greatly reduced. By removing the iov buffering, all IO function sizes are again significantly reduced. Removal of wide char support in non-wide char function further squeezes string IO logic. Newlib-nano also extensively uses the weak symbol technique to exclude features that are rarely used in normal MCU programs. For example, referencing floating point IO and atexit as weak functions dramatically cuts the size of printf() and exit().” 为了减小体积,Newlib-nano库砍掉了很多C89之后的特性。(后面那一句不知道怎么翻译了。。。) 看来,为了减小体积砍掉了一些东西。比如printf输出浮点以及atexit函数。( |9 v& J7 f/ l 为Newlib-nano添加浮点输出功能 如果你的代码实在是需要浮点输出的功能,可以尝试自己编写一个函数,将浮点数转换成字符串在输出。或者在链接命令中添加-u_printf_float命令。相关的代码在printf_v3.zip中。 + h# l% z8 u) O* N ; f2 F) m B/ K+ r 在给Newlib-nano添加printf float支持之后,代码增至15K。至于在你的项目中该如何选择,还是要自己做决定吧。 |
可以试试只在一个任务中使用printf看看,如果没问题,应该就是不可重入导致的吧。
可以在查查看看有没有编译选项解决可重入的,或者在什么地方加锁的。
多谢楼主,任务跑不起来是我任务堆栈分配的太小。在不加nano.specs的时候,RTOS和printf现在都正常,但是加了 nano.specs后printf就没有输出了
Ubuntu下自带的记事本软件---gedit
沐紫姐英明啊