Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
10 years, 6 months ago.
Serial taking too much memory
Hi, The serial API on my Nucleo-F103RB is taking a lot of extra flash space, wondering if it is because of my custom build environment or it's the same for other toolchains too.
Board - Nucleo-F103RB. Toolchain - GNU GCC 4.7 2013q2 (offline).
Compiler flags
gcc: -c -mthumb -mcpu=cortex-m3 -Wall -fmessage-length=0 -fno-common -fno-exceptions -ffunction-sections -fdata-sections -Wno-reorder g++: -c -mthumb -mcpu=cortex-m3 -Wall -fmessage-length=0 -fno-common -fno-exceptions -ffunction-sections -fdata-sections -Wno-reorder -std=gnu++11
Linker flags
-T "${ProjDirPath}/mbed/targets/cmsis/TARGET_STM/TARGET_NUCLEO_F103RB/TOOLCHAIN_GCC_ARM/stm32f10x.ld" -mthumb -mcpu=cortex-m3 --specs=nano.specs -Wl,--gc-sections -Wl,--start-group,-lgcc,-lc,-lm,-lnosys -Wl,-Map=${ProjName}.map
Code without serial
#include "mbed.h" DigitalOut myled(LED1); int main() { while(1) { myled = 0; wait( 0.2 ); myled = 1; wait( 2 ); } }
Output for code without serial
arm-none-eabi-size pac.elf text data bss dec hex filename 8200 144 368 8712 2208 pac.elf
Code with serial
#include "mbed.h" DigitalOut myled(LED1); Serial pc( USBTX, USBRX ); int main() { pc.puts( "Hello World!" ); while(1) { myled = 0; wait( 0.2 ); myled = 1; wait( 2 ); } }
Output for code with serial
arm-none-eabi-size pac.elf text data bss dec hex filename 61892 156 508 62556 f45c pac.elf
## Edited on May 4th @ 11:08AM PST
I was able to make the following changes to my toolchain flags and bring down memory usage but it's still more than twice that of the online toolchain.
Compiler flags
gcc: -mcpu=cortex-m3 -mthumb -c -fno-common -fmessage-length=0 -Wall -fno-exceptions -ffunction-sections -fdata-sections -MMD -MP -DNDEBUG -DTARGET_M3 -DTOOLCHAIN_GCC_ARM -DTOOLCHAIN_GCC -D__CORTEX_M3 -DARM_MATH_CM3 -DMBED_BUILD_TIMESTAMP=1399222579.61 -D__MBED__=1 g++: -mcpu=cortex-m3 -mthumb -c -g -fno-common -fmessage-length=0 -Wall -fno-exceptions -ffunction-sections -fdata-sections -MMD -MP -DNDEBUG -DTARGET_M3 -DTOOLCHAIN_GCC_ARM -DTOOLCHAIN_GCC -D__CORTEX_M3 -DARM_MATH_CM3 -DMBED_BUILD_TIMESTAMP=1399222579.61 -D__MBED__=1 -std=gnu++98
Linker flags
-mcpu=cortex-m3 -mthumb -Wl,--gc-sections -Wl,--start-group,-lgcc,-lc,-lm,-lnosys --specs=nano.specs -lstdc++ -lsupc++ -T "${ProjDirPath}/mbed/targets/cmsis/TARGET_STM/TARGET_NUCLEO_F103RB/TOOLCHAIN_GCC_ARM/stm32f10x.ld" -Wl,-Map=${ProjName}.map
Output with compiler flag changes
arm-none-eabi-size pac.elf text data bss dec hex filename 18016 156 488 18660 48e4 pac.elf
## Edited on May 4th @ 12:30PM PST
Here we go, still looking for the extra 12KB culprit:
Snippet from retarget.cpp
#if defined(TOOLCHAIN_GCC) /* prevents the exception handling name demangling code getting pulled in */ #include "error.h" namespace __gnu_cxx { void __verbose_terminate_handler() { error("Exception"); } }
1 Answer
10 years, 6 months ago.
I am not familiar with that notation, so I don't know how those sizes relate. However Serial uses stdio for things like puts/printf/scanf/etc. So if you add Serial, stdio is included too. Depending on the build settings stdio is always initialized, which is in the online compiler for example the case, so the difference is small. If for you that is not the case, this could explain a larger difference.
You can try replacing Serial with RawSerial, which doesn't do this. (Although it still requires to vsprintf, so dunno how it will behave size wise exactly).
Erik, Thanks for you quick response too, RawSerial took a lot less memory. What do you mean by "stdio is always initialized", how do I do it on my compiler settings?
Output for RawSerial
arm-none-eabi-size pac.elf text data bss dec hex filename 8432 144 464 9040 2350 pac.elf
Thanks Ashwin
posted by 04 May 2014Thing ate my comment. Again:
So that does narrow it down to stdio using that space, since besides that they should be pretty much equal.
Regarding automatic initalization, that doesn't really matter for you, but in the online compiler the difference is small since it always sets up stdio, even when not used. Not all others do it, or depend on flags, but I don't have much knowledge concerning compiler flags.
Now the size, you say in your editted post that it is double that of what the mbed compiler makes: Are you sure? I tried it out with two different targets (I don't have yours), and both ended up around 17kB flash with your code. Since you got 128kB thats quite a bit left :).
posted by 04 May 2014"you say in your editted post that it is double that of what the mbed compiler makes: Are you sure?"
100%, ran a quick test on the online too by importing ST Nucleo F103RB platform and the "build" tab shows:
No (Raw)Serial: Flash - 5.9KB(5%), RAM - 0.2KB(1%). RawSerial: Flash - 6.2KB(5%), RAM - 0.3KB(2%). Serial: Flash - 8.4KB(7%), RAM - 0.3KB(2%).
"Since you got 128kB thats quite a bit left" You are right, I have a lot more left but my application code needs a LOT so I am ending up squeezing out every last byte so that I do not have to move to a more expensive chip.
Thanks
posted by 04 May 2014Well I think that brought me to the last part of the answer.
As you can imagine, using 17kB is not the biggest deal in general on your device, but on a small one it is. Now really the smallest ones you shouldn't be using mbed, but just plain C. But for one step higher there is the uARM library instead of ARM, which is smaller (but at a penalty, no idea what that penalty is).
Now for me the weird part: Every single Nucleo target is set to use uARM in the online compiler instead of ARM. If they think the penalties outweigh the extra space, then why not do it for every target?
Anyway, I guess that results in quite a difference, but I have no clue if that can also be done in GCC, and neither how.
(I believe uARM = microlib, but not 100% sure).
posted by 04 May 2014
Look at the linker map file, to discover what is taking like 50kB code size. You can share that linker file with us, both - with/without serial.
Have you tested also size with the makefile exported from the online compiler? It uses different compile flags according to yours.
posted by Martin Kojtal 04 May 2014Thanks for the quick response Martin. I ran a quick diff against serial.map and noserial.map, cp-demangle.o stands out @ 39852 bytes. The remaining 12KB is several other bits and pieces. Wondering how to attach files to this comment, I don't see a link to do so.
Thanks uCFreak
posted by Ashwin Vijayakumar 04 May 2014I forgot to mention, are you using newlib? I don't think so, so that could be an explanation :-) Try to set to use newlib, also turn off floating point support, which would squeeze down the code size.
posted by Martin Kojtal 04 May 2014