9 years, 11 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");
    }
}

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 2014

Thanks 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 2014

I 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

1 Answer

9 years, 11 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 Ashwin Vijayakumar 04 May 2014

Thing 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 Erik - 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 Ashwin Vijayakumar 04 May 2014

Well 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 Erik - 04 May 2014