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.

MSP430 Linking Error Using Large Code Memory Model

Other Parts Discussed in Thread: MSP430F5419A, TEST, MSP430F5438A, MSP430F5419, MSP430F6638

I am using CCS v5.1.0.09000 with the MSP430 C compiler v4.0.0 and developing code for the MSP4305419A part and using the EABI output format.  At first my code (and data) fit within the lower 64K of memory so I have been using the small code and small data memory models with no problems.  Now my code has grown large enough that it does not fit within the lower 64K, so I switched to the large code model, but kept using the small data memory model.

However, with this configuration, I get the following error:

"../lnk_msp430f5419a.cmd", line 126: error #10099-D: program will not fit into
   available memory.  placement with alignment fails for section ".cinit" size
   0x10f .  Available memory ranges:
   FLASH        size: 0xa17e       unused: 0x0          max hole: 0x0       
error #10010: errors encountered during linking; "Controller.out" not built

Looking at the linker command file (see file contents below) shows that the .cinit section should only be placed in the lower 64K of Flash.  Looking at the map file, it appears that the .text section is being placed into Flash first, which completely fills the Flash, leaving no room for the .cinit section.  The .cinit directive comes first in the linker command file, so why is the .text section being allocated first?

Thanks for your help,  Austin

Linker command file contents:

    SFR                     : origin = 0x0000, length = 0x0010
    PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
    PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
    RAM                     : origin = 0x1C00, length = 0x4000
    INFOA                   : origin = 0x1980, length = 0x0080 /* DO NOT FILL! */
    INFOB                   : origin = 0x1900, length = 0x0080, fill = 0x3FFF
    INFOC                   : origin = 0x1880, length = 0x0080, fill = 0x3FFF
    INFOD                   : origin = 0x1800, length = 0x0080, fill = 0x3FFF
    ASSERT_LOG              : origin = 0x5C00, length = 0x0200, fill = 0x3FFF
    FLASHCRC                : origin = 0x5E00, length = 0x0002, fill = 0xCCCC
    FLASH                   : origin = 0x5E02, length = 0xA17E
    FLASH2                  : origin = 0x10000,length = 0x15C00
    INT00                   : origin = 0xFF80, length = 0x0002
<<< all of the other interrupt vectors >>>
    INT62                   : origin = 0xFFFC, length = 0x0002
    RESET                   : origin = 0xFFFE, length = 0x0002

/* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY                              */

    .bss       : {} > RAM                /* GLOBAL & STATIC VARS              */
    .data      : {} > RAM                /* GLOBAL & STATIC VARS              */
    .sysmem    : {} > RAM                /* DYNAMIC MEMORY ALLOCATION AREA    */
//    .stack     : {} > RAM (HIGH)         /* SOFTWARE SYSTEM STACK  (ORIGINAL) */
    .ramstart  : 0x1C00                  /* First (16-bit) location in RAM    */
    .cvstart   : 0x58E0                     /* Store critical variable copies    */
    .stackstart: 0x58FA                  /* SOFTWARE SYSTEM STACK START       */
    .stack     : 0x58FC                  /* SOFTWARE SYSTEM STACK             */
    .stackend  : 0x5BFC                  /* SOFTWARE SYSTEM STACK END         */
    .ramend    : 0x5BFE                  /* Last (16-bit) location in RAM     */

    .uniqueID  : 0x5E02                  /* Device Unique ID                  */
    .fwVer     : 0x5E04                  /* Firmware Version Number           */

//#ifdef (__LARGE_DATA_MODEL__)
//    .const     : {} > FLASH | FLASH2   /* CONSTANT DATA                     */
    .const     : {} > FLASH              /* CONSTANT DATA                     */
    .cinit     : {} > FLASH              /* INITIALIZATION TABLES             */
    .text:_isr : {} > FLASH              /* ISR CODE SPACE                    */
    .text      : {}>> FLASH | FLASH2     /* CODE                              */

    .cio       : {} > RAM                /* C I/O BUFFER                      */

    .pinit     : {} > FLASH              /* C++ CONSTRUCTOR TABLES            */

    .infoA     : {} > INFOA              /* MSP430 INFO FLASH MEMORY SEGMENTS */
    .infoB     : {} > INFOB
    .infoC     : {} > INFOC
    .infoD     : {} > INFOD

    .int00   : {} > INT00                /* MSP430 INTERRUPT VECTORS          */
<<< all of the other interrupt vectors >>>
    .int62   : {} > INT62
    .reset   : {} > RESET              /* MSP430 RESET VECTOR               */

  • A. Kirchhoff said:

    Looking at the linker command file (see file contents below) shows that the .cinit section should only be placed in the lower 64K of Flash.  Looking at the map file, it appears that the .text section is being placed into Flash first, which completely fills the Flash, leaving no room for the .cinit section.  The .cinit directive comes first in the linker command file, so why is the .text section being allocated first?

    The fact that the .cinit section comes before .text in the linker command files does not guarantee that it gets allocated first. Please see this FAQ for details on how the linker allocates sections:

    This would not be an issue if the sections were small enough to all fit in the FLASH range, but since it is not, in this case, you would need to modify the linker command file to have better control over the allocation. You could either move all of .text into FLASH2 or specify a GROUP directive to control allocation of .cinit before .text.

    Hope this helps.

  • Thanks for the tips, AartiG.

    I tried the following GROUP directive, but this did not work since the entire group is moved into FLASH2.  With the small data model, .const must be in FLASH.
            .const     : {}              /* CONSTANT DATA                     */
            .cinit     : {}              /* INITIALIZATION TABLES             */
            .text:_isr : {}              /* ISR CODE SPACE                    */
            .text      : {}
        } >> FLASH | FLASH2

    I moved all of .text into FLASH2 and the program correctly links.  However, when I go to run the program, it gets stuck in "_TI_zero_init(unsigned long, unsigned long) at 0x180d8".  I believe this is part of the TI MSP430 library that runs at boot-up to initialize variables, etc.

    Why is this function locking up?  Does this function need to be in the lower 64K of memory?

    Also, is it required for .cinit to be in the lower 64K of memory?


  • In large model, it should not be necessary to place __TI_zero_init in the lower 64K.   However, since you have said you're still using small data model, and because .cinit is treated as data, it must go in the lower 64K.

  • Okay, good to know.  Thanks.

    My program links and puts .cinit in the lower 64K and puts all .text (including __TI_zero_init) above the 64K address.  However, when I run my program, it gets stuck and spins in __TI_zero_init.

    Any thoughts on why?  Is this a problem in the TI MSP430 library?


  • I believe the .text:_isr section should also be placed in lower 64k. Remove that section from the GROUP directive and place it directly into FLASH. The rest of the .text can go into FLASH or FLASH2.

  • Using the linker command file you posted, adjusting non-ISR .text so that it only goes into FLASH2, I have no trouble with __TI_zero_init.  This suggests there is not a problem with the library.  I would probably need a compilable, reproducible test case to further diagnose this problem.

    Can you elaborate on how it gets "stuck" in __TI_zero_init?  What are the symptoms, exactly?

    What command-line options are you using?  Are you using RAM or RAM model?  Does the program fail the first time after it is loaded?

  • Archaeologist,

    I have attached a CCS project with source and linker command files that reproduces the problem on my system.  I included the "Debug" folder in the zip file, so that you can see the results of my build (map file, etc.).  Please let me know if you can reproduce the problem using this project and if you find a solution.

    To answer some of your questions:

    Getting "stuck" in __TI_zero_init  or __TI_decompress_rle_core means that when I load the program into a micro using the CCS debugger and then run the program, the debugger always pauses within one of those functions.  There is no indication that the functions exits the init code and starts running my main loop.  Note that I have turned off "run to main at load" or else the debugger never pauses because it can't reach main().

    I am using the ROM auto init model.

    The program fails every time it is run.

    My compiler options:
    -vmspx --abi=eabi --code_model=large --data_model=small -O0 -g --include_path="C:/Projects/C_Company/1596-Wireless_Comms_Sys/Code/workspace/AbkExample/src/components" --include_path="C:/Projects/C_Company/1596-Wireless_Comms_Sys/Code/workspace/AbkExample/src/drivers/devices" --include_path="C:/Projects/C_Company/1596-Wireless_Comms_Sys/Code/workspace/AbkExample/src/drivers/utilities" --include_path="C:/Projects/C_Company/1596-Wireless_Comms_Sys/Code/workspace/AbkExample/src/drivers/micro" --include_path="C:/Projects/C_Company/1596-Wireless_Comms_Sys/Code/workspace/AbkExample/src/include" --include_path="C:/ti/ccsv5/tools/compiler/msp430/include" --strict_ansi --define=__MSP430F5419A__ --diag_warning=225 --display_error_number --silicon_errata=CPU21 --silicon_errata=CPU22 --silicon_errata=CPU23 --silicon_errata=CPU40 --printf_support=minimal --misra_advisory=warning --misra_required=error

    My linker options:
    -vmspx --abi=eabi --code_model=large --data_model=small -O0 -g --strict_ansi --define=__MSP430F5419A__ --diag_warning=225 --display_error_number --silicon_errata=CPU21 --silicon_errata=CPU22 --silicon_errata=CPU23 --silicon_errata=CPU40 --printf_support=minimal --misra_advisory=warning --misra_required=error -z -m"" --stack_size=768 --heap_size=0 --use_hw_mpy=F5 -i"C:/Projects/C_Company/1596-Wireless_Comms_Sys/Code/workspace/AbkExample" -i"C:/ti/ccsv5/tools/compiler/msp430/lib" -i"C:/ti/ccsv5/tools/compiler/msp430/include" --reread_libs --warn_sections --rom_model --fill_value=0x3FFF3FFF

    Other info:
    Changing the data model from small to restricted allows the code to run fine.  This issue only occurs with a large code model and a small data model.

    Please let me know what you find.  Thanks for your help.


  • When I run your executable file (AbkExample/Debug/AbkExample.out) on a simulator (I don't have access to an MSP430F5419A right now), execution reaches main successfully.  I also note that the executable file does not contain __TI_zero_init.  Is this the version of the executable that does demonstrate the problem?

  • Hmm, interesting.  This executable does not contain __TI_zero_init, but it does contain __TI_decompress_rle_core.  The debugger always gets stuck in __TI_decompress_rle_core when I run the program.

    I have seen this problem when attempting to run this program on my custom hardware using a MSP430F5419A Rev E.  I can also reproduce this problem using the TI MSP4305xx 100-pin target board with a MSP430F5438A Rev C (I override the debugger warning mismatched micro type), so the problem does not seem to be with my hardware.

    Could this problem be caused by a CPU Errata?


  • A silicon erratum is conceivable, but very unlikely, especially since you've used two different devices.  I'd like to try to eliminate the impossible before proceeding to the improbable.

    The executable has only one entry in the .cinit table, which initializes all 0x604 bytes of .data to zero.  It's strange that the linker chose RLE instead of zero-init, but it looks legal, and it's encoded correctly, as far as I can see.

    How many cycles do you let initialization run for before stopping it to see where it is?  What is the value of R11 when you stop it?  What is the PC?

  • I don't know how to limit the number of cycles performed before stopping the debugger.

    My process is to reset the micro, click run, let the micro run several seconds, and then click pause.  The debugger always pauses within __TI_decompress_rle_core.  The values of the PC and R11 registers for several different runs are below.

    PC = 0x010068, R11 = 0x0005E7
    PC = 0x010060, R11 = 0x00023E
    PC = 0x010060, R11 = 0x000566
    PC = 0x010068, R11 = 0x0002FE
    PC = 0x010068, R11 = 0x000424
    PC = 0x01006A, R11 = 0x0002BA
    PC = 0x010068, R11 = 0x000325


  • Austin,

    I was able to reproduce the issue by running your code on a MSP430F5419 target board. After spending some time looking at it with Archaeologist, he suggested the watchdog timer as a possible cause for the device getting reset and re-running the initialization routine. Turns out that was the case. I added code to your project to disable the watchdog and then it was able to reach main successfully. Since this needs to be done prior to main, it has to be added to the system_pre_init routine which is called by the startup routine.

    Here is what you can do to add this to your project:

    - Go to folder \ccsv5\tools\compiler\msp430\lib within your CCS installation and extract
    - From the rtssrc folder, copy pre_init.c and add it to your project
    - Modify the file to:

    #include <msp430x54xa.h>

     int _system_pre_init(void)

    WDTCTL = WDTPW + WDTHOLD;    /* disable watchdog timer  */
    return 1;


    After making these changes I still had to use the default msp430 header files rather than the one in your \include folder to get the project to build. I also had to relax the language mode from strict Ansi to None to avoid compile errors. But once I made those changes and set the project to use default header files, I was able to load the code and it successfully halted at main.

    Please give this a try and let us know if it helps.

  • AartiG (and Archaeologist),

    Thanks for looking into this in more depth.  I was able to get my program to work by following the steps you provided, which disables the watchdog at start-up.

    However, my application is safety critical, so I feel uncomfortable disabling the watchdog timer.  Any suggestions?  Should I just stick with the restricted data model?

    Why is this case (large code, small data model) unique such that the auto init routine takes so long that it resets the watchdog timer, where as other cases (large code, restricted data model) do not cause the watchdog to reset?  Are the other cases close to the time limit, such that I need to evaluate modifying the watchdog settings or disabling auto init?


  • Austin,

    Your code is initializing a pretty large buffer which is causing the startup init code to run over the default watchdog timer timeout period (32,768 CPU cycles). I believe the init code is slightly different for different data models so choosing the small data model (as opposed to restricted or large), in this case, seems to be throwing the cycle counts over the limit.

    I also noticed that changing the ABI to COFF ABI instead of EABI does not trigger the watchdog timer.

    So if you do not wish to modify your pre init routine to disable the watchdog, your choices are to stay with restricted data model, or use COFF ABI if that is an option.

  • If restricted data model works for you, you should definitely use it.  It is the recommended data model.

    The specific case of large code and small data is unique because function pointers are bigger than data pointers.  The decompression function which is being called here needs to be prepared to handle moving functions around in memory, so it can't just use data pointers.  It uses some less-efficient code which can handle function pointers, even when operating on data objects.  For this reason, the specific case of large code and small data will be slower during system initialization.  It just so happens that this slightly less efficient mode of operation puts you over the watchdog timer threshold.  If you had many global objects to initialize, even using restricted data model you could exceed the threshold.

    I suspect what you'll need to do going forward is to measure how long auto-initialization takes and set the watchdog timer for slightly longer.

  • AartiG, Archaeologist,

    Thanks for the explanation and your ideas.  I will probably stick with the restricted data model and I plan to measure how long my auto-initialization takes to make sure it is not close to the watchdog timer limit.  I may also look into preventing the compiler from initializing my large buffers (using the NO_INIT pragma), even though this breaks the strict ANSI rules (which are generally required for my project).

    AartiG, I believe I read that the COFF ABI does not auto-init uninitialized variables to 0.  Thus, my large buffer would not be auto-initialized and allowing the init routine to finish before the watchdog expires.

    Thanks again,

  • The C standard requires the implementation (compiler + linker) to initialize to zero all static-scope objects (such as _buffer, _headIndex,and _tailIndex) which do not have an initializer.  In EABI mode, the TI tools will do this for you without any further intervention.  Because of the way the TI tools handle initialization of uninitialized objects, you could get slightly faster startup time if you take off the initializer, even though the "uninitialized" object still gets initialized.  In EABI, the TI tools will use a different, slightly faster RTS routine dedicated to initialization of uninitialized objects.

    There are a few caveats:

    • While EABI does this for you automatically in the linker, COFF ABI does not; you would be responsible for arranging for this through a linker command file fill value or a loader which zero-initializes the appropriate memory at load time.  Thus, if the code must be portable between EABI and COFF ABI, you should keep the initializer.
    • Those static-scope objects will be located in .bss instead of .data
    • Your coding standard might not allow you to leave objects uninitialized.
  • I have a MSP430F6638 project that uses large memory model for code and data.  After I changed from COFF to EABI output format, I am seeing the "stuck during initialization" behavior.  I had to add the watchdog disable into my _system_pre_init() to get it to work.

    Is this the general solution recommended by TI, or will TI be fixing the initialization so it doesn't cause watchdog resets when we're using EABI and large memory model?

    Chris Norris

  • I filed SDSCM00045267 in the SDOWP system.  Feel free to follow it with the SDOWP link below in my signature.

    The entry I filed suggests the linker issue a diagnostic when, due to the size of all the objects being initialized, a watchdog timer reset may occur.  I don't know that this is what will be implemented.  But it should start some useful discussion on the development team.

    Thanks and regards,


  • AartiG,

    I spent a week trying to find an answer to this issue and I finally found the correct search term to find your post.  Your solution was posted almost a year ago, I would suggest that the runtime library be updated to include this fix or an option added to the project configuration that defaults to turning off the WDT early in the initialization.


    Mark James