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

volatile keyword

The application note suggests to wrap a timer tick variable in a function which disables all interrupts, reads and copies the variable into a temp, re-enables interrupts, then returns the temp.

Can the variable be accessed directly outside of the ISR without disabling interrupts if the timer tick variable is declared as "volatile?"

Parents

  • In general, you can't expect a compiler to solve the problem of needing atomic access to a value that's more than a single bus transfer wide. While masking interrupts is sufficient in the example above, since software changes the value, consider a free-running 16-bit counter in hardware. Interrupts have nothing to do with it, and volatile doesn't help. The problem is simply that it takes two bus cycles to read the value, which may straddle a rollover. You'd need hardware to latch a single consistent 16-bit value before you started to transfer it into the processor.

    Even for all-software cases, you have the problems that you might not want to mask all interrupts just to mask the one with which you have a synchronization issue. And if you have custom interrupt controller logic, the compiler can't know which bits to set. In general, the programmer is going to have to solve the problem anyway.

    When it comes to the definition of volatile as "any object whose value may change for reasons not explicitly part of the C program itself", keep in mind that the "volatility" is seen from a small, local, code-generator/optimizer-ish view of "the program", rather than any sort of whole-source analysis. "volatile" helps let the compiler know it has to generate a physical read and not just use a value that may be cached in a register from a couple of lines ago. You still need to declare "volatile" values that are shared between two threads of execution, or interrupt handlers, even though the code may be all part of "the C program", or even the same file, all visible to the compiler.

    For example:

    U8 counter; // should be "volatile"
    
    void TimerTick (void) interrupt 0
        {
        counter++;
        }
    
    void MainRoutine (void)
        {
        for (;;) printf ("%d\n", counter);
    
        }
    

    could legally produce an endless stream of the same value instead of an incrementing pattern, if the optimizer hoists the read of "counter" outside the loop with the printf(). The error in this case has nothing to do with the interrupt interrupting MainRoutine(), but is simply that the compiler needs to know that "counter" is volatile, so that it knows not to optimize away the multiple reads. The compiler isn't required to detect the potential volatility just due to use of the global in two different routines; it has to be told.

Reply

  • In general, you can't expect a compiler to solve the problem of needing atomic access to a value that's more than a single bus transfer wide. While masking interrupts is sufficient in the example above, since software changes the value, consider a free-running 16-bit counter in hardware. Interrupts have nothing to do with it, and volatile doesn't help. The problem is simply that it takes two bus cycles to read the value, which may straddle a rollover. You'd need hardware to latch a single consistent 16-bit value before you started to transfer it into the processor.

    Even for all-software cases, you have the problems that you might not want to mask all interrupts just to mask the one with which you have a synchronization issue. And if you have custom interrupt controller logic, the compiler can't know which bits to set. In general, the programmer is going to have to solve the problem anyway.

    When it comes to the definition of volatile as "any object whose value may change for reasons not explicitly part of the C program itself", keep in mind that the "volatility" is seen from a small, local, code-generator/optimizer-ish view of "the program", rather than any sort of whole-source analysis. "volatile" helps let the compiler know it has to generate a physical read and not just use a value that may be cached in a register from a couple of lines ago. You still need to declare "volatile" values that are shared between two threads of execution, or interrupt handlers, even though the code may be all part of "the C program", or even the same file, all visible to the compiler.

    For example:

    U8 counter; // should be "volatile"
    
    void TimerTick (void) interrupt 0
        {
        counter++;
        }
    
    void MainRoutine (void)
        {
        for (;;) printf ("%d\n", counter);
    
        }
    

    could legally produce an endless stream of the same value instead of an incrementing pattern, if the optimizer hoists the read of "counter" outside the loop with the printf(). The error in this case has nothing to do with the interrupt interrupting MainRoutine(), but is simply that the compiler needs to know that "counter" is volatile, so that it knows not to optimize away the multiple reads. The compiler isn't required to detect the potential volatility just due to use of the global in two different routines; it has to be told.

Children
No data