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.

MSP430F5359: CGT-generated MSP430X images won't start if .bss is 985 bytes or more

Part Number: MSP430F5359


Tool/software:

(I apologize for an incomplete bug report; I'll add more data as I discover it.)

We are using the latest CGT (MSP430 C/C++ Compiler v21.6.1.LTS) and the libraries that came with the latest Code Composer Studio (CCS 2002) to create some MSP430 test programs and we've run into a problem.

We're compiling with the following qualifiers:

bin/cl430.exe --c11           \
--silicon_version=mspx        \
--use_hw_mpy=f5               \
--printf_support=nofloat      \
--c_src_interlist             \
--include_path=./include      \
--include_path=../ccs2002/ccs/ccs_base/msp430/include/ \
--output_file=hello_CGT_1.elf \
hello.c                       \
--run_linker                  \
--search_path=./lib/          \
--output_file=hello_CGT_2.elf \
--map_file=hello_CGT.map      \
lnk_msp430f5359.cmd

And what we're finding is that if our test program declares .bss items that total 985 bytes or more, the program never gets started. It appears to foul up somewhere in __TI_zero_init() as that tries to zero out the .bss region on program start-up. But if .bss totals 984 bytes or fewer, all goes well. Also, if we compile without the --silicon_version=mspx qualifier (so it becomes a 16 bit program rather than a 20 bit program), all goes well.

I can't yet tell you (yet) what arguments are being passed to __TI_zero_init() but I can tell you that if I modify the .txt file to NOP out the call to __TI_zero_init(), the program starts okay (except that .bss hasn't been initialized, of course). Reading the .txt file, the __TI_cinit_table (and its relatives) seems to contain valid data: the address it points to is the right place in RAM, it's invoking __TI_zero_init(), and its passing the correct initialization size.

Does anyone recognize this symptom?

I can post a version of my hello.c if it would help but my program's not doing anything special, just defining and accessing some global arrays that will be placed in .bss.

  • On my way to trying to collect more debugging data, I moved my hardware initialization code into a _system_pre_init() routine that I just wrote (and made that routine return 1 indicating success).

    This resolved the problem! I can now create large .bss segments and the program still starts correctly!

    That's weird!

    Within the image, things have moved around (unsurprisingly). Within the __TI_cinit_table (and its relatives), everything is the same except that the address of __TI_zero_init() has changed to match where __TI_zero_init() actually landed in the image.

    But everything works!

  • I'm thinking the problem is actually the Watch Dog Timer.

    The big difference that my re-arrangement made was that _system_pre_init() now sets the WDT to Hold Mode whereas my old code was causing the CGT environment to invoke __TI_auto_init_nobinit_nopint() which DOES NOT affect the WDT. In that world, if the WDT times out, the program will be reset. And I guess that initializing 985 bytes of .bss takes just long enough to let the WDT time out.

    I'll experiment to prove that this was the critical difference.

    A moment later…

    Yes, that was the problem!

    I wonder why the environment elected to use:

    __TI_auto_init_nobinit_nopint()

    rather than:

    __TI_auto_init_nobinit_nopint_hold_wdt()

    But it's probably some compiler/linker qualifier I didn't use. I'll go back to the compiler manual and read more.

  • This sounds suspiciously like an old headache where if .data/.bss are "too big" the Watchdog triggers before C initialization can complete. The usual fix is to insert something like  "void _system_pre_init(void) {WDTCTL = WDTPW | WDTHOLD; return(1);}" somewhere.

    I don't have CCS20 here, but in CCS12 there's an option "Build Settings->Build->Linker->Basic->Hold watchdog timer during cinit" which can do this. [I personally prefer the code change since this is one of those arcane options that's easy to forget about.]

    [Edit: It looks like you already found this.]

  • Closing the loop on Linker qualifiers:

    Specifying --cinit_hold_wdt=on as a linker qualifier causes the WDT to be automagically held while c initialization occurs. After that, the WDT is restored to the same state it was in before c initialization ran. Here's the relevant text from the Compiler manual:

    So the user's program still has to deal with the WDT somewhere along the way, either setting it to HOLD or actually using it as a Watch Dog that requires occasional “petting”.

    At this point, my problem is entirely resolved but hopefully these posts will help someone else in the future.

  • Bruce:

    Thanks, yes that was EXACTLY my issue. Our production code (that we compile with IAR) already “knew” this and deals with the WDT very early on but until this morning, I'd forgotten this very important detail. I'll probably remember it now for another year or two. ;-)

    Thanks for your reply.

  • Hi Atlant,
    Glad to see that Bruce's response help out.

    Best Regards,

    Diego Abad

**Attention** This is a public forum