Reducing the flash size of FreeRTOS

spotdott wrote on Thursday, February 04, 2010:

Hi, I’m new to embedded programming with FreeRTOS.  I am using a custom board with an STM32F103 with 48 kb of ram and 128 kb of flash.  I have followed the instructions provided by stefanos to make a development environment in Linux and Eclipse.  He has projects for both high density and low density STM32 MCUs, with the .bin file for the low-density MCU as low as 96kb. 

Here are my questions: (I searched the forums for them already. However if they have already been addressed, please point me in the right direction)

1.) The demo project I am using produces a .bin file of 127 kb.  Is this the actual size of the flash that goes onto the board? 

2.) If not then how do I check the size?

3.) I compared the low-density project and the high-density project… they seem almost identical.  Where did the difference in flash size come from then?

Thanks!

rtel wrote on Thursday, February 04, 2010:

1.) The demo project I am using produces a .bin file of 127 kb. Is this the actual size of the flash that goes onto the board?

If that is a .bin file then yes it is the size that is flashed into the device - but very little of that will be FreeRTOS code.  Typically FreeRTOS on a Cortex M3 will take around about 7K bytes of flash space.  Be careful which libraries are used as calling something like printf() can bring in huge amounts of GCC library code, which is why I normally use a very stripped down version of the string formatting functions.

2.) If not then how do I check the size?

Look in the map file produced by the linker.  The kernel code is contained in task.c, queue.c, list.c, heap_x.c and port.c.

3) No idea.  Maybe optimisation level?

Regards.

spotdott wrote on Thursday, February 04, 2010:

Ah yes the demo project does make use of printf!  I’ll get rid of them.  Noob question: Where does printf print to? (there’s no console FreeRTOS is there?) 

So the primary source of flash fat-ness are the unnessessary libraries that are used.  If I include them, but no use them, will the compiler be smart enough to leave them out?

Another possilbe cause for the bloated flash size might be related to the LCD image that the creator put in “LCD_Message.h”.  However when I got rid of that, only 10kb were recovered.

I’ll keep working on the problem.  Thanks for the tip though!  IF anyone else know something about this, please do tell!

jorick23 wrote on Friday, February 05, 2010:

>>> Ah yes the demo project does make use of printf! I’ll get rid of them. Noob question: Where does printf print to? (there’s no console FreeRTOS is there?)

Usually you have to write a function to put the data somewhere.  On my project, I wrote a function called __write that outputs the string to the RS232 or USB port.

>>>So the primary source of flash fat-ness are the unnessessary libraries that are used. If I include them, but no use them, will the compiler be smart enough to leave them out?

The linker does the brainwork to figure out what can be left out.  So, yes, it’s smart enough.

davedoors wrote on Friday, February 05, 2010:

The linker does the brainwork to figure out what can be left out. So, yes, it’s smart enough.

That depends on the compiler being used. I think all compilers other than GCC will remove unused code by default. If you are using GCC then you have to give it some obscure compiler and linker options to get the same behavior. I’m never sure why using something like printf() brings in so much code. I think it must also bring in all the floating point code for the %f formatter?

jorick23 wrote on Friday, February 05, 2010:

>>>I think it must also bring in all the floating point code for the %f formatter?
If you’re using the IAR compiler, you can select which printf formatter to use, and eliminate floating point and some other stuff if you don’t need them.  Other compilers may give you that option as well.

macica wrote on Friday, February 05, 2010:

I wanted snprintf (does limit checks) and found a some source(snprintf.c) from Patrick Powell (xxxx@xxxx.com). Others have added limited floating point support. http://www.ijs.si/software/snprintf/. It works well and there is not a huge memory hit.

I needed sscanf support and just added from GCC and I think it took like 30K of memory………luckily I don’t need it for production code. 

STM32/

spotdott wrote on Friday, February 05, 2010:

Okay so after butchering the demo code I was able to get the size down to 70kb.  There’s got to be other things to get rid of.  For example, all these include files that were part of the demo:

#include "death.h"
#include "integer.h"
#include "blocktim.h"
#include "partest.h"
#include "semtest.h"
#include "PollQ.h"
#include "flash.h"
#include "comtest2.h"

Can I get rid of any of them?  It seems some of them are needed for tasks that were specific to the demo application:

	/* Start the standard demo tasks. */
    vCreateBlockTimeTasks();
    vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
    vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
    vStartIntegerMathTasks( mainINTEGER_TASK_PRIORITY );
	vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );

Are these tasks absolutely necessary for the proper function of FreeRTOS?  I’m guessing that these tasks were created to demonstrate the capabilities of the operating system.  Am I getting warm?

Thanks!

spotdott

rtel wrote on Friday, February 05, 2010:

No, the demo tasks are nothing to do with the kernel.  See http://www.freertos.org/a00102.html , which is a bit out of date but gives you the idea.  The kernel files are task.c, queue.c, list.c and port.c, and maybe a port assembly file too.  Just those four files, it really is a small system.  Also see http://www.freertos.org/a00017.html

Regards.

spotdott wrote on Sunday, February 07, 2010:

Okay so I logged all the object files during build and here is a list of binaries eating away at my precious flash space:

   text	   data	    bss	    dec	    hex	filename
    800	      2	     31	    833	    341	main.o
    184	      0	      2	    186	     ba	timertest.o
   1124	      0	      0	   1124	    464	printf.o
    624	      0	      0	    624	    270	stm32f10x_it.o
    360	      0	      2	    362	    16a	./ParTest/ParTest.o
    424	      0	      0	    424	    1a8	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_lib.o
   4112	      0	      0	   4112	   1010	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_rcc.o
   4724	      0	      0	   4724	   1274	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_gpio.o
   4688	      0	      0	   4688	   1250	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_spi.o
    680	      0	      0	    680	    2a8	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_systick.o
  24724	      0	      0	  24724	   6094	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_tim.o
   5688	      0	      0	   5688	   1638	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_nvic.o
   3708	      0	      0	   3708	    e7c	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_flash.o
   7076	      0	      0	   7076	   1ba4	../../Common/drivers/ST/STM32F10xFWLib/v2_0_3/src/stm32f10x_adc.o
    380	      0	      0	    380	    17c	../../../Source/list.o
   2244	      0	      0	   2244	    8c4	../../../Source/queue.o
   5052	      0	    256	   5308	   14bc	../../../Source/tasks.o
    520	      4	      0	    524	    20c	../../../Source/portable/GCC/ARM_CM3/port.o
    514	      0	  17432	  17946	   461a	../../../Source/portable/MemMang/heap_2.o

Most notable is the STM32 peripheral library’s tim.o (from tim.h I presume).  With a whopping size of 25 kB it is one big mofo.  Stefano was kind enough to send me his to compare.  His tim.o is a lot smaller than mine as seen below:

    272       0      12     284     11c Debug/timertest.o

     24       0       0      24      18 Debug/stm32f10x_it.o

    290       4       8     302     12e Debug/stf_syscalls_minimal.o

    173       0      52     225      e1 Debug/net_launch_srv.o

    288       0      20     308     134 Debug/ParTest.o

   6913       2       2    6917    1b05 Debug/stm3210c_eval_lcd.o

   1105       0    2050    3155     c53 Debug/httpd.o

  94868       0       0   94868   17294 Debug/fs.o

    306       0     256     562     232 Debug/NetCalcApp.o

    164       0       0     164      a4 Debug/core_cm3.o

    320       0       0     320     140 Debug/system_stm32f10x.o

    196       0       0     196      c4 Debug/misc.o

    908       0       0     908     38c Debug/stm32f10x_usart.o

    632       0       0     632     278 Debug/stm32f10x_gpio.o

   1116      20       0    1136     470 Debug/stm32f10x_rcc.o

    840       0       0     840     348 Debug/stm32f10x_spi.o

   2952       0       0    2952     b88 Debug/stm32f10x_tim.o

   1184       0       0    1184     4a0 Debug/stm32f10x_flash.o

   4180       0       0    4180    1054 Debug/stm32_eth.o

    125       0       4     129      81 Debug/flash.o

    595       0      48     643     283 Debug/recmutex.o

    584       0      32     616     268 Debug/BlockQ.o

   1204       0      32    1236     4d4 Debug/GenQTest.o

    140       0       4     144      90 Debug/integer.o

    296       0      12     308     134 Debug/PollQ.o

    878       0      12     890     37a Debug/QPeek.o

    144       0       0     144      90 Debug/list.o

   1248       0       0    1248     4e0 Debug/queue.o

   3433       4     380    3817     ee9 Debug/tasks.o

    312       4       0     316     13c Debug/port.o

    212       0   30740   30952    78e8 Debug/heap_2.o

    756       0       0     756     2f4 Debug/api_lib.o

   1948       0       0    1948     79c Debug/api_msg.o

      0       0       0       0       0 Debug/err.o

    276       0       0     276     114 Debug/netbuf.o

      0       0       0       0       0 Debug/netifapi.o

    851       0      16     867     363 Debug/tcpip.o

    512       0       0     512     200 Debug/icmp.o

    448       0      16     464     1d0 Debug/inet.o

    336       0       0     336     150 Debug/inet_chksum.o

    792       0      10     802     322 Debug/ip.o

     68       0       0      68      44 Debug/ip_addr.o

   1300       0    1510    2810     afa Debug/ip_frag.o

   3376       4       0    3380     d34 Debug/dhcp.o

      0       0       0       0       0 Debug/dns.o

     16       0       0      16      10 Debug/init.o

    748       0    8228    8976    2310 Debug/mem.o

    212       0    9664    9876    2694 Debug/memp.o

    428       0       1     429     1ad Debug/netif.o

   1080       0       0    1080     438 Debug/pbuf.o

      0       0       0       0       0 Debug/raw.o

      0       0       0       0       0 Debug/stats.o

    480       0       0     480     1e0 Debug/sys.o

   2544       6       1    2551     9f7 Debug/tcp.o

   4292       0      44    4336    10f0 Debug/tcp_in.o

   2280       0       0    2280     8e8 Debug/tcp_out.o

    976       0       0     976     3d0 Debug/udp.o

      0       0       0       0       0 Debug/asn1_dec.o

      0       0       0       0       0 Debug/asn1_enc.o

      0       0       0       0       0 Debug/mib_structs.o

      0       0       0       0       0 Debug/mib2.o

      0       0       0       0       0 Debug/msg_in.o

      0       0       0       0       0 Debug/msg_out.o

   1808       0     201    2009     7d9 Debug/etharp.o

    540       0      34     574     23e Debug/sys_arch.o

   1584       0    9408   10992    2af0 Debug/stm32x_ethernetif.o

Why the huge difference in object file size?  I’m using Timer 1 and Timer 4, btw.

Law

edwards3 wrote on Sunday, February 07, 2010:

Is the STM32 systick driver really 5 times the size of tasks (tasks.o which contains the kernel implementation). That is funny.

edwards3 wrote on Sunday, February 07, 2010:

Sorry, as you say its tim not systick. Next row down.

Are you using -fdata-sections, -ffunction sections in the compiler command line and -gc-sections in the linker command line?

spotdott wrote on Monday, February 08, 2010:

should use --gc-sections but the debugger does not seem to be able to cope with the option.

LINKER_FLAGS=-nostartfiles -Xlinker -o$(PROJECT_NAME).axf -Xlinker -M -Xlinker -Map=$(PROJECT_NAME).map -Xlinker --no-gc-sections

This is the linker flags in the project’s makefile.  Have no idea what it means.  Maybe I should try -gc-sections?