1

I have been working on MSP430G2553 using using the mspgcc compiler and as an introductory program I have begun with blinking an LED. The code that I have used is as follows:

#include <msp430.h> 
unsigned int i;
void main(void) 
{
    WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    P1DIR |= 0x01; //Set P1.0 to output
    for(;;)
    {
        P1OUT ^= 0x01;
        i=0;
        while(i<50000)
        {
            i++;
        }
    }
}

where while loop does the work of providing delay.

I thought that since the above while loop in which i increments from 0 to a certain value, why can't I use a decrementing loop. So I tried the following code.

#include <msp430.h> 
unsigned int i;
void main(void) 
{
    WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    P1DIR |= 0x01; //Set P1.0 to output
    for(;;)
    {
        P1OUT ^= 0x01;
        i=50000
        while(i>0)
        {
            i--;
        }
    }
}

This code didn't work and on finding the reason, I came to know that the global variable i needs to be provided with "volatile" so as to prevent the optimization of compiler because here the value of i can change at any time.

My question is in the first case also the value of i was changing from 0 to 49999 then why didn't we use "volatile" modifier in that case?

The assembler code for each of the cases above is as follows:

Case 1 (Incrementing loop)

main:
   40B2 5A80 0120      MOV.W   #0x5a80,&Watchdog_Timer_WDTCTL
   P1DIR |= 0x01; //Set P1.0 to output
   D3D2 0022           BIS.B   #1,&Port_1_2_P1DIR
   P1OUT ^= 0x01;
$C$L1:
   E3D2 0021           XOR.B   #1,&Port_1_2_P1OUT
   i=0;
   4382 0200           CLR.W   &i
   while(i<50000)
      90B2 C350 0200      CMP.W   #0xc350,&i
      2FF8                JHS     ($C$L1)
      i++;
$C$L2:
   5392 0200           INC.W   &i
   90B2 C350 0200      CMP.W   #0xc350,&i
   2FF2                JHS     ($C$L1)
   3FF9                JMP     ($C$L2)

Case 2 (Decrementing loop)

main:
   40B2 5A80 0120      MOV.W   #0x5a80,&Watchdog_Timer_WDTCTL
   P1DIR |= 0x01; //Set P1.0 to output
   D3D2 0022           BIS.B   #1,&Port_1_2_P1DIR
   P1OUT ^= 0x01;
$C$L1:
   E3D2 0021           XOR.B   #1,&Port_1_2_P1OUT
   i=50000;
   40B2 C350 0200      MOV.W   #0xc350,&i
   while(i>0)
      9382 0200           TST.W   &i
      27F8                JEQ     ($C$L1)
      i--;
      4382 0200           CLR.W   &i
      3FF5                JMP     ($C$L1)
too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Akash
  • 11
  • 2
  • what compiler, what were the options, when you disassembled what did you find between them, etc... – old_timer May 28 '16 at 22:06
  • It isn't meaningful to try to answer this without knowing the compiler options. They compiler isn't _obliged_ to optimize your code... but it might do if it finds no meaningful side-effects like in this case. – Lundin May 29 '16 at 19:17

1 Answers1

3

Briefly, the volatile qualifier tells the compiler an object has side-effects beyond its "vision". So it must not optimise out accesses to it.

Without this the compiler is free to optimise-out the whole loop if it can proof this will not change the observable behaviour of the program. Note that this is not guaranteed and in your case the compiler seems to recognise one code pattern, but not the other. But you must not rely on this (and whoever wrote that code lacks fundamental coding practice).

In both cases, volatile is necessary though to be on the safe side. Note that the compiler still might be able to optimise the code; best is to additionally put a NOP assembler intrinsic into the loop.


Note: see the generated Assembler code. It is likely the optimised code will include something like i = 0 instead of the loop or just leave i at the default value for static variables (which is 0, too).

too honest for this site
  • 12,050
  • 4
  • 30
  • 52