This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

keywords volatile in an interrupt routine

In this webpage :http://www.keil.com/support/man/docs/gsac/gsac_timer.htm
The question is why two variables one use volatile but another not ??
The two variables is "TimeTick" and "clock_1s".
Who can tell me why,i am very confused. thank you !

/*----------------------------------------------------------------------------- * Name: Timer.c * Purpose: Timer example. Prints a sting to UART2 * Notes:
*----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stm32f10x_cl.h>

volatile unsigned long TimeTick; // Counts 10ms timeTicks
unsigned char clock_1s; // Flag activated each second

extern void init_serial (void); // Function defined in Serial.c

/****************************************************************************** Initialise the TIM3 for 1ms @ 72MHz
******************************************************************************/
void TIM3_Init (void) {

RCC->APB1ENR |= (1<<1); // enable clock for TIM3

TIM3->PSC = 3; // set prescaler TIM3->ARR = (18000000UL / 1000UL) - 1UL; // set auto-reload TIM3->CR1 = 0; // reset command register 1 TIM3->CR2 = 0; // reset command register 2 TIM3->DIER = (1<<0); // Update interrupt enabled TIM3->CR1 |= (1<<0); // Enable Timer

NVIC_EnableIRQ (TIM3_IRQn); // Enable TIM3 interrupt
}

/*----------------------------------------------------------------------------- Timer Counter 3 interrupt service function executes each 1ms @ 25 MHz Crystal Clock
*----------------------------------------------------------------------------*/
void TIM3_IRQHandler (void) {

if (TIM3->SR & (1<<0)) { // UIF interrupt? if (TimeTick++ >= 999) { // Set clock_1s to 1 every 1 second TimeTick = 0; clock_1s = 1; } TIM3->SR &= ~(1<<0); // clear UIF flag }
}

  • It seems like someone have made a mistake.

    It would be more reasonable to reverse which of the two variables that has the volatile keyword.

    If TimeTick is only used by the ISR, then it doesn't need the volatile keyword. If some other part of the code is also making use of TimeTick, then it should have the volatile keyword.

    But clock_1s seems like it is modified by the ISR, with the intention that the main loop should look at it and perform some action whenever it gets set. So this variable should be volatile.

    Volatile should be used whenever there is some "magic" task switch where an ISR or task may step in at an arbitrary time and modify a variable that some other task (or the main loop) also will be using. This makes sure the compiler inserts code to always read the variable value directly from RAM instead of keeping a copy of the variable in some register.

    If the main loop has a copy of clock_1s cached in a register, then that register will not get a new value when the ISR gets activated and increment the master value of clock_1s.

    The ISR itself doesn't need the volatile keywords for normal variables, since the compiler will always have to retrieve the value from RAM after the ISR has been activated.

    For memory-mapped special function registers, i.e. magical memory cells that may change value without the code accessing them, then the volatile keyword is always needed - both ISR code and normal code must then perform a new read whenever the variable is accessed.

    Another thing here:

    if (TimeTick++ >= 999) { ... }
    


    it would have been nicer to write

    if (++TimeTick >= 1000) { ... }
    

    With post-increment, the compiler needs to load TimeTick. Then make a copy of it and increment and write down to memory. Then return to the original value for performing the comparison.

    So post-increments basically means:

        unsigned tmp1,tmp2;
    
        tmp1 = TimeTick;
        tmp2 = tmp1;
        tmp2 = tmp2 + 1;
        TimeTick = tmp2;
        if (tmp1 >= 999) { ... }
    


    while the pre-increment variant is like:

        unsigned tmp;
    
        tmp = TimeTick;
        tmp = tmp + 1;
        TimeTick = tmp;
        if (tmp >= 1000) { ... }
    

    So post-increment/decrement can cost more if the code needs to both look at the variable and increment/decrement it because of the need for an extra copy of the variable.