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.

Low Level Init

Other Parts Discussed in Thread: MSP430F5510

Hello,

I am in a situation where I have to initialize a lookup table that is large enough that under normal conditions, the watchdog timer expires before the table can finish loading. As a result, I have implemented a low level init, which will run before variables are initialized.  In the low level init, I stop the watchdog timer, so that when the program loads, the watchdog timer is stopped before initializing the large table values.

Occasionally I run into a problem with variable initialization.

For example, if I were to type something like:

volatile static unsigned int temp = 164;

I am running the system with IAR Embedded Workbench.  Sometimes, by the time IAR gets into the main routine, it shows that temp = 28.  This does not happen all the time, but it causes problems when it does.  I suppose that there is a flaw with my approach in using the low level init and should perhaps use some other method.  Any suggestions?

Thanks in advance.

Sincerely,

Mehdi

  • Hi Mehdi,

    Would you mind posting your __low_level_init( ) function?  Your return value should be 1, and you shouldn't be counting on any initialized variables or C runtime functions among a few other ground rules.  Maybe we can take a look.  I could assume that you are only disabling the watchdog timer, but assumptions don't always work out.

    Jeff

  • Hi Jeff,

    That may be the exact problem!  Actually I have changed microcontrollers and upgraded IAR from a while back,  On the initial design, I used:

    void __low_level_init(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT (Watch Dog Timer)
    }

    As far as I remember, this worked fine in my original design.  However, when I tried to use this in my new design, the compiler gave me an error, saying the function should be: int __low_level_init(void)

    I then changed the function to:

    int __low_level_init(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT (Watch Dog Timer)
    }

    Notice how there is no return value.  I got no error from the compiler.  I believe it should really be: 

    int __low_level_init(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT (Watch Dog Timer)
    return 1;
    }

    I tried this, and there appears to be no problems (at least for now).  Would this error explain the incorrect variable initialization?  Why was it that it seemed to happen only sometimes?

    Thanks for the advice!

    Sincerely,

    Mehdi

  • I think you need to find our the meaning of the returned integer. It might direct the c startup to do different things.

  • Mehdi Rahman said:
    Notice how there is no return value.  I got no error from the compiler.  I believe it should really be: 

    It's no error to return nothing. But you should get a warning form the compiler.

  • Jens-Michael Gross said:
    It's no error to return nothing. But you should get a warning form the compiler.

    Do you think this would cause the problem of improper variable initialization, or do you think the source of that problem is something else?

  • Mehdi Rahman said:
    It's no error to return nothing. But you should get a warning form the compiler.

    Do you think this would cause the problem of improper variable initialization, or do you think the source of that problem is something else?[/quote]Looking at C:\Program Files\IAR Systems\Embedded Workbench 6.4 Kickstart\430\src\lib\low_level_init.c the return from __low_level_init is commented as:

      /*
       * Return value:
       *
       *  1 - Perform data segment initialization.
       *  0 - Skip data segment initialization.
       */

    So, returning nothing could lead to the data segment initialization being skipped.

  • Mehdi Rahman said:
    Would this error explain the incorrect variable initialization?  Why was it that it seemed to happen only sometimes?

    The int return value from a function is the value in the R12 register when the function returns. If there no explicit return value from __low_level_init then if data segment initialization is performed is undefined. e.g. the following program was compiled for a MSP430F5510 in IAR Embedded Workbench Kickstart for MSP430 5.50.1:

    #include "io430.h"

    volatile static unsigned int temp = 164;

    int __low_level_init(void) {
       WDTCTL = WDTPW + WDTHOLD; // Stop WDT (Watch Dog Timer)
    }

     

    int main( void )
    {
      if (temp == 164)
      {
         // Turn on LED
         PJOUT |= BIT3;
         PJDIR |= BIT3;
      }
      temp++;
     
      return 0;
    }

    When the program was run in the debugger, when the __low_level_init function returned the debugger showed the R12 register happend to have the value one, and so the temp variable was initialized to 164 and the LED was lit.

    When the program was run with the debugger not attached, the LED wasn't lit, indicating the temp variable was no longer being initialized correctly.

    Making the __low_level_init function return the value one then caused the temp variable to be initialized correctly both when the program was run in debugger or standalone.

    i.e. the missing return from __low_level_init does explain why the variable initialization sometimes failed.

    P.S. I noted the MSP430 FAQ had __low_level_init (IAR) and _system_pre_init (CCS) as a void return type. I have corrected the page.

  • Mehdi Rahman said:
    It's no error to return nothing. But you should get a warning form the compiler.

    Do you think this would cause the problem of improper variable initialization, or do you think the source of that problem is something else?[/quote]
    Well, being no error from the ompiler side doesn't mean it is no error from teh application side. If the calling funciton expects a certain return code, returning a random value in the return value register isn't a good idea. And in this case, it seems a return value of '1' is expected to perform further initialization.

    I've got a friend who ignored compiler warnigns about suspicious pinter conversions, saying that they were no errors so all should be fine. However, while the code was valid C code, some of his pointer conversions were simply wrong, leading to memory leaks that were difficult to track down. 'legal' doesn't always mean 'correct' :)

  • Hi Mehdi,

    You have found the problem, which is that you must be sure to return 1 if you want cstartup to continue with variable initializations.

    Also you should #include <intrinsics.h> since the proper function declaration for __low_level_init() is in that file.

    Jeff

  • Hey everyone,

    Thanks for the help!

    Looks like the TI Software coding techniques application notes need an update as well (it uses the void declaration of the low level init): http://www.ti.com/lit/an/slaa294a/slaa294a.pdf

    Mehdi

  • Mehdi Rahman said:
    Looks like the TI Software coding techniques application notes need an update as well (it uses the void declaration of the low level init)

    Well, the low-level init funcitonality and how to use it is purely compiler/linker specific. And IAR is no TI compiler. So why should TI change their documents when a 3rd party product changes its proprietary behaviour?
    On MSPGCC, it works differently again. IIRC, MSPGCC V3 does not implement it as a function at all - the low-level-init is a naked function (no prologue/epilogue/return) and is directly inlined into the init code. No return parameter here too.

  • Jens-Michael Gross said:
    Well, the low-level init funcitonality and how to use it is purely compiler/linker specific. And IAR is no TI compiler. So why should TI change their documents when a 3rd party product changes its proprietary nehaviour?

    Good point.

  • I know the post is old but I stumbled upon it and so may people after me.

    Mehdi Rahman said:

    Hello,

    I am in a situation where I have to initialize a lookup table that is large enough that under normal conditions, the watchdog timer expires before the table can finish loading. (...)

    Supposing your lookup table is not a fixed one but changes during runtime, you could have used __no_init  instead, and initialized the table after stopping the watchdog, as in:

    const int LookUpTableInit[] = {init values};  // Array in FLASH

    __no_init int LookUpTable[sizeof(LookUpTableInit)/sizeof(LookUpTableInit[0])];// Uninitialized array in RAM

    int main (void)

    {

      WDTCTL = WDTPW | WDTHOLD;

      for (int i=0; i<sizeof(LookUpTableInit)/sizeof(LookUpTableInit[0]); i++)

        LookUpTable[i] = LookUpTableInit[i];// Initialize RAM array with FLASH array values

    }

    Regards,

    Michael K.

**Attention** This is a public forum