This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Too much C code for my MSP430?

Other Parts Discussed in Thread: MSP430F2012, INA226

Hi all,

I am currently working with an MSP430F2012 and I tried to run a program with a heavy amount of code and I get the following error:

Description Resource Path Location Type
#10099-D program will not fit into available memory. run placement with alignment fails for section "DATA_GROUP" size 0x1f . Available memory ranges: INA226start C/C++ Problem

Sometimes a similar error occurs, but it is usually resolved by fixing a syntax error of some kind. Is this actually the case where having too much code will keep this specific MSP430 from running? I just comment out some of the heavy functions and the lines that call them and it starts going without this error. Any help would be greatly appreciated.

Thanks,

Matt

  • Matt,

    The error message is telling you that you have written more code than you can fit into the flash memory on the device. F2012 only has 2KB of flash memory. If you write more than 2KB of code, the linker cannot fit the code into memory. You have several options:

    1) Try turning on the compiler optimizer and see if it can help reduce the code size.

    2) Eliminate some of your code.

    3) Use a msp430 with more flash.

    Regards,

    David

  • Hi again,

    I was able to get things running, but I have absolutely no idea why that is. I will explain my findings here in hopes that someone can explain the error and how it was resolved:

    unsigned int reg; // INITIALIZING THIS VARIABLE GETS RID OF THE ERROR

    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
    reg = 0xFF;
    convert(reg, 0);
    }

    The code above produced the error mentioned above. However, when I change the line unsigned int reg; to unsigned int reg = 0; it starts to work. Can anyone explain to me what the initialization of reg did exactly? Should I be initializing all variables outside of my main function/other functions?

    Also on a side note (because I brought it up), because I am using a very small MSP430, how much C code can I write with 2K of memory? Either an average number of lines or a description of the scale of the projects that are feasible with that much memory. Any vague estimate would be useful for me in understanding whether or not my project is feasible with my current MSP430.

    Thanks,

    Matt

  • This is counter-intuitive.  Initializing that global actually increases your code size since it will create another value in the global variable initialization table.  All I can think of is that the size change caused the linker to change the order that it is allocating the sections into memory.  That combined with section alignment requirements may have allowed the sections to fit together in the available memory (i.e., allowed some memory hole to be better utilized).

    I'm not sure if you are using CCS or IAR debugger.  But for either, there should be a linker output file (e.g., .map file in CCS, not sure what IAR calls it) that you can inspect to see how much memory you are using and where everything is located.

    - David

  • Thanks for the reply David,

    I got another error when I tried to initialize a char arr[6] (both initialized and uninitialized). Is there a separation in memory for code and for data itself? And is that line fixed where perhaps I have too much data initialized (but a lot of space for more code)? Do you know if deleting all of the stuff in the msp430.h include (or rather the msp430f2012.h include) would help? There are a lot of defines that I am not using -- or do defines not contribute to memory at all?

    Thanks,

    Matt

  • Matt, #defines do not consume space in the device memory. They are used only by the codegen tools.

    When you do something like

        int  x=5;

    the 'x' gets linked to RAM (in CCS, it goes in the .bss section) and the '5' will be linked to flash (in CCS, it goes in the .cinit section).  So, initializing a global var increases the size of the initialization section that gets linked to flash.

    Again, you don't say if you are using CCS or IAR, but you should look at the linker map file and see what your memory usage is.

    - David

  • I am using CCS, I tried looking at the linker map file, and there were a lot of "symbols" involving things that looked like they were from the msp430.h file (stuff I am not using), which is why I asked that question.

    The two errors I am getting are:

    Description Resource Path Location Type
    #10099-D program will not fit into available memory. run placement with alignment fails for section "DATA_GROUP" size 0x25 . Available memory ranges: INA226start C/C++ Problem

    Description Resource Path Location Type
    #10010 errors encountered during linking; "INA226start.out" not built INA226start C/C++ Problem

    Is this problem specifically with my INA226start.out build? meaning something specifically with these initializations and "starting" the program? The strange thing that I do not understand is that I can add more variables (I added an extra 10 character array) and it works, but when I try to pass in a character array like so:

    convert(100, 0, cArr);  <-- added the third parameter

    it works with a size of two chars, but not three, regardless of my extra 10 character array that does nothing yet. Do you know why that is?

  • Matthew Wasko said:
    tried looking at the linker map file, and there were a lot of "symbols" involving things that looked like they were from the msp430.h file (stuff I am not using), which is why I asked that question.

    Have you got any specific examples? The reason is that the linker map reports symbols for all peripherals in the msp430.h, e.g. P2DIR, even if your code doesn't use the peripherals.

    The symbols for the peripherals don't cause a problem with running out of memory for your program, since the peripherals have their own address space, outside of the RAM and FLASH used at the available space for your program.

    Matthew Wasko said:
    Description Resource Path Location Type
    #10099-D program will not fit into available memory. run placement with alignment fails for section "DATA_GROUP" size 0x25 . Available memory ranges: INA226start C/C++ Problem

    Description Resource Path Location Type
    #10010 errors encountered during linking; "INA226start.out" not built INA226start C/C++ Problem

    Is this problem specifically with my INA226start.out build?

    Yes the problem is with the INA226start.out build. The first error says the linker couldn't find sufficient space to fit the program into memory. The second error is just a consequence of the first error. Also, the errors have been copied from the CCS Problems tab which only records the first line of each error. The first error is incomplete as doesn't show the available memory ranges in question. The complete error message should be in the CDT Build Console.

    Matthew Wasko said:
    it works with a size of two chars, but not three, regardless of my extra 10 character array that does nothing yet. Do you know why that is?

    The DATA_GROUP reported in the linker error message doesn't appear in the default linker commands files in CCS, so I assume a custom linker command file is in use. From the posted information not sure what the problem is. Are you able to post a .zip file of the complete CCS project?

  • Hey Chester,

    I can send you the project. Would I have to "build" it, or "export" it? Thanks a bunch!

    Matt

  • Hey Chester,

    I just put an exported project zip file on my "files" section of my profile. So you can click my name and click "files" and you should be able to download the project (Its called "SendingForHelp"). I took out as much as I could (unused functions and unused includes) while still maintaining the problem. My main file is called "msp430x20x3_usi_12.c" and if you do a search in there for "ZZZZZ," you should find two lines where if I comment just one of the two lines out, the code will compile and all that good stuff. I don't know why that is. Could you verify that those two lines do the same for you, and then maybe try to see whats going on in the project?

    Thanks,

    Matt

  •  

    Matthew Wasko said:
    can send you the project.
    Unless there is information you can't publish on a public forum, best to attach it a .zip file to a forum post so that others may be able to help.

    Matthew Wasko said:
    Would I have to "build" it, or "export" it?

    Assuming there are not dependencies on other CCS projects, you just need to attach the contents of the CCS project directory.

  • 8814.SendingForHelp.zip

    All public information. Let me know if you are able to work with the project zip file I put in my profile's "files" section (I also attached it to this post just in case)

    Thanks,

    Matt

  • Gah, there was a random double in my INA226_i2c.c file. When I take that out, it works again.

    However, I kind of need some help understanding what the state of my code is in right now. I have more C code to add so I'm curious how exactly these problems relate to space in memory, and how I can resolve it to make sure that I my final project will fit onto the memory available.

    Should I try and condense my functions into less lines of C? Or should I try to minimize variables that I define, either inside functions, outside functions, or both? Do certain variables take up more memory than others? I feel like reading though the .map file and understanding how the linker is working would help clarify this, so if anything, if anyone could help me interpret my project as it is with regards to the linker and memory available and whatnot, that would be greatly appreciated!

    Thanks,

    Matt

    P.S. If there is a noticeable problem with those two "ZZZZZ" lines and something more significant, please let me know :) Right now, I just have no idea how to tackle this issue, as it seems like everything is only a "quick fix" at this point, because I am on the verge of running out of memory, or something along those lines -- I really have no idea :)

  • Matt,

    You're simply out of memory.  The problem is in fact the RAM, not the flash.  You've only got 256 bytes in the F2012.  I looked at the project you sent.  I can build it and I get the same error that you reported.  You've got a lot of global vars in INA226_i2c.c that consume RAM.  You've also got globals in robust_i2c.c and some in msp430x20x3_usi_12.c.  I can see it in the .map file:

    .data      0    00000200    00000028    
                      00000200    0000000f     INA226_i2c.obj (.data)
                      0000020f    00000001     --HOLE--
                      00000210    0000000c     INA226_i2c.obj (.data:dp)
                      0000021c    00000006     msp430x20x3_usi_12.obj (.data)
                      00000222    00000004     robust_i2c.obj (.data)
                      00000226    00000002     msp430x20x3_usi_12.obj

    .bss       0    00000228    00000026     UNINITIALIZED
                      00000228    00000014     robust_i2c.obj (.bss)
                      0000023c    00000012     INA226_i2c.obj (.bss)

    You've got your stack length set to 50, which causes a hole of 2 bytes because the stack is 4-byte aligned in memory.  Change the stack size to 48, and the project you posted, as it is, will build.  Everything will just fit into RAM with absolutely no free RAM available.

    You'll have to modify your code to economize on RAM use.  One thing is make sure each global var really needs to be global.  If you make it local, it will go on the stack instead of global memory.

     

    Regards,

    David

  • Matthew Wasko said:
    8814.SendingForHelp.zip

    All public information. Let me know if you are able to work with the project zip file I put in my profile's "files" section (I also attached it to this post just in case)

    I can see both of .zip files (which are both identical).

    Matthew Wasko said:
    However, I kind of need some help understanding what the state of my code is in right now. I have more C code to add so I'm curious how exactly these problems relate to space in memory, and how I can resolve it to make sure that I my final project will fit onto the memory available.

    If I compile the unmodified project in SendingForHelp.zip, using CCS 5.4 and MSP430 compiler v4.1.5 the build fails with the linker error:
    error #10099-D: program will not fit into available memory.  run placement with alignment fails for section "BSS_GROUP" size 0x26 .  Available memory ranges:
       RAM          size: 0x80         unused: 0x26         max hole: 0x24    
    This means the linker is reporting that their is insufficient RAM to fit the program.

    If the following line is commented out in msp430x20x3_usi_12.c then the program links:

    //int another = 0; // ZZZZZ TAKE OUT THIS LINE AND IT WILL START TO WORK!!!
    The linker map file reports the following overall memory usage:
             name            origin    length      used     unused   attr    fill
    ----------------------  --------  ---------  --------  --------  ----  --------
      RAM                   00000200   00000080  0000007e  00000002  RWIX
      FLASH                 0000f800   000007e0  00000608  000001d8  RWIX
    This means there is only 2 spare bytes out of the 128 bytes available in RAM, and 472 spare bytes out of 2016 bytes available in flash for code. i.e. the program is on the limits of the available RAM. To reduce RAM usage need to try a combination of:

    a) Reducing the number/size of global variables.

    b) Reducing the stack size if possible. Note that the stack size set in CCS Project Properties -> Build MSP430 Linker -> Basic Options -> Set C System Stack Size is only used by the linker to reserve space - if the stack size exceeds the size reserved the code can crash due to the stack overwriting other global variables in RAM. See Finding out static stack usage for how to determine the maximum stack size used at run time.

  • So RAM is the main issue? If I define a lot of my "option" bits (meaning true/false or one of four possibilities), would it be smart to put them into one char and mask them out to save space? Or would the trouble of making #define changedUnits 0x02 for every bit in the char make things worse?

    Also just how much is 472 spare bytes for my code? How many more lines could I add to the code to fix that? And if I want to decrease that, would I just have to manually take out lines/use compiler optimization?

    Thanks,

    Matt 

  • Matthew Wasko said:

    So RAM is the main issue? If I define a lot of my "option" bits (meaning true/false or one of four possibilities), would it be smart to put them into one char and mask them out to save space? Or would the trouble of making #define changedUnits 0x02 for every bit in the char make things worse?

    Grouping multiple control bits into a single byte will conserve RAM.  Sounds like a good idea.  You will use more flash though for the masking code.  You'll need to manage this.  Also, make sure you haven't oversized any variables.  If you only need 8 bits, make sure you declared a char and not an int, etc.

    Matthew Wasko said:

    Also just how much is 472 spare bytes for my code? How many more lines could I add to the code to fix that? And if I want to decrease that, would I just have to manually take out lines/use compiler optimization?

    I couldn't speculate on code size.  You can run some quick tests yourself to see.  Definitely try using the optimizer to optimize for code size.

     

    Regards,

    David

  • One last question, if I want to look at the limiting RAM and whatnot, should I be looking at the .map file that is named after my main C code file? or the .map file named after my project?

    Thanks,

    Matt

  • Actually I have something else I would like to inquire about as well:

    I am having trouble with the RAM portion of memory. I continuously try to remove lines of C code one by one until it works, which I notice makes a difference. However, just now, I tried to eliminate three different functions in my timing.h/c files (the ones I don't use). It was almost 40 lines of code there, yet it made no difference to the state of my C code -- in other words, eliminating those 40 lines didn't give me any more capacity than eliminating one line somewhere else.

    What am I missing here? Where should I try to eliminate code and whatnot to be sure that my compression of the code actually makes a significant impact?

    Also, I saw from the error that my .cinit is failing to allocate:

    In the second image, you can see that .cinit has to do with "initialization tables" (in FLASH). Does anyone know what this all means? And if so, is that what I should be trying to focus on to get things to work? Initialization tables is the one part of the flash that I do not understand and have never heard of, so any insight into this would be greatly appreciated!

    Thanks,

    Matt

  • Matthew Wasko said:
    However, just now, I tried to eliminate three different functions in my timing.h/c files (the ones I don't use). It was almost 40 lines of code there, yet it made no difference to the state of my C code -- in other words, eliminating those 40 lines didn't give me any more capacity than eliminating one line somewhere else.

    Even with the default optimization level, the MSP430 linker is able to automatically remove functions which are never called - this is done by each function being placed in it's own uniquely-named subsection by the compiler.

    Matthew Wasko said:
    In the second image, you can see that .cinit has to do with "initialization tables" (in FLASH). Does anyone know what this all means?

    Have you seen the MSP430 Optimizing C/C++ Compiler v 4.1 User's Guide SLAU132 and  MSP430 Assembly Language Tools v 4.1 User's Guide SLAU131?

  • Matthew Wasko said:
    And if I want to decrease that, would I just have to manually take out lines/use compiler optimization?

    In this example project the compiler optimization can make a significant difference. The original project in SendingForHelp.zip used the default compiler optimization - On CCS -> Project Properties -> Build -> MSP430 Compiler -> Optimization both "Optimization Level" and "Control speed .vs. size trade-offs" were blank which means the default. With the defaults the overall memory usage was:
             name            origin    length      used     unused   attr    fill
    ----------------------  --------  ---------  --------  --------  ----  --------
      RAM                   00000200   00000080  0000007e  00000002  RWIX
      FLASH                 0000f800   000007e0  00000608  000001d8  RWIX
    Changing "Optimization Level" to 4 (maximum optimization) and "Control speed .vs. size trade-offs" to 0 (optimize for size) reduced the overall memory usage to:
             name            origin    length      used     unused   attr    fill
    ----------------------  --------  ---------  --------  --------  ----  --------
      RAM                   00000200   00000080  00000076  0000000a  RWIX
      FLASH                 0000f800   000007e0  00000364  0000047c  RWIX
    i.e. changing the optimization reduced the flash usage from 1544 to 868 bytes, and the RAM usage from 126 to 118 bytes.

    I am not sure what effect optimizing for code size had on the execution speed.

  • Matthew Wasko said:
    In the second image, you can see that .cinit has to do with "initialization tables" (in FLASH). Does anyone know what this all means?

    If in your code you say

    unsigned int myglobalvar = 12345;

    How do you think the value 12345 is put into it at program start?
    Writing the value to ram would make it disappear at next power-off or when it is changed by the code. So teh linker generates a table in which all these values are stored and copied from flash to ram on reset.

    For variables that are not initialized or initialized with zero, the area in which these are gruped is simple cleard to 0 by a code loop. But for thse which are not zero (includign maybe a large array where the first element has been initialized to a nonzero value) a copy of the complete initialized block of all these variables is stored in flash and copied over to ram at reset.

    Chester Gillon said:
    I am not sure what effect optimizing for code size had on the execution speed.

    It differs. This is why there are different optimization levels. You can optimize for speed or for size or for the best of both.

    Some optimizations (like suppressing redundant writes) shrink the code and increase the speed. Some (like unrolling a loop or inlining code) increase size and speed while others (like putting common subexpressions into a subfunction) decrease size and speed.

  • Thanks for all the info!

    It is just a matter of decreasing my C code and whatnot. I am slowly but surely making progress keeping everything under 2K in flash.

    Thanks,

    Matt

**Attention** This is a public forum