cancel
Showing results for 
Search instead for 
Did you mean: 

Are HAL registers defined volatile, and will this prevent optimization?

Lars Beiderbecke
Senior III

Suppose I have the following code snippet:

void some_func() {
  int data = GPIOA->IDR;
  if (data == 0x01)
    func1();
  else if (data == 0x02)
    func2();
}

If optimization is turned on, I would expect the compiler to remove variable data and replace both occurrences of data with GPIOA->IDR -- which is clearly different from the original code.

Hence my question if GPIOA->IDR is defined as volatile. And if it is, is this sufficient to prevent this "optimization", or does variable data need to be volatile as well?

(My IDE would not jump to the declaration of GPIOA->IDR.)

1 ACCEPTED SOLUTION

Accepted Solutions

Data structure element definitions that access peripheral registers typically look like:

  __IO uint32_t IDR;         /*!< GPIO port input data register,         Address offset: 0x10      */

where __IO is #defined as volatile.

View solution in original post

12 REPLIES 12

Why would it replace both? data isn't volatile.​ It will also likely be held in a processor register and not memory. If data were volatile it still wouldn't cause it to reload the content from GPIO IDR but might force the value to always be held in a RAM variable so a pointer access from an IRQ or DMA would be able to change it.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

What the optimizer can't do is fold "efficient" stupidity like this :

RCC->PLLCR &= ~0x00000012;

RCC->PLLCR |= 0x00000034;

RCC->PLLCR &= ~0x001200;

RCC->PLLCR |= 0x00003400;

RCC->PLLCR &= ~0x00120000;

RCC->PLLCR |= 0x00340000;

RCC->PLLCR &= ~0x12000000;

RCC->PLLCR |= 0x34000000;

Where as this will fold to a handful of instructions and is scoped to use a processor register.

uint32_t tmp = RCC->PLLCR;

tmp &= ~0x00000012;

tmp |= 0x00000034;

tmp &= ~0x001200;

tmp |= 0x00003400;

tmp &= ~0x00120000;

tmp |= 0x00340000;

tmp &= ~0x12000000;

tmp |= 0x34000000;

RCC->PLLCR = tmp;

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Well, the goal is NOT having the compiler replace both usages of data.

If the code were using some global variable int gvar instead of GPIOA->IDR, wouldn't the optimizer eliminate local variable data and use gvar instead? This is what I want to AVOID, and I thought that a volatile declaration on gvar might prevent this, as the compiler realizes that the value might change between both usages.

But since I wasn't sure, I mused if gvar itself should be volatile, but I now know this is not the case.

Very good example Clive.

S.Ma
Principal

I use IAR and most of my global variables are not volatile.

Also if the global variables are declared in a different C file, compiler should avoid optimizing too much.

Intead of cutting corners, implement test code, go debug mode and look at the assembly.

You should learn faster than waiting for this post to end.

turboscrew
Senior III

Basically, 'volatile' tells the compiler that the contents of a variable (registers are also seen as variables by the compiler) can change without the compiler seeing it. That is: the compiler can't trust that the value stays the same if compiler doesn't see a piece of code that could change it, but it has to evaluate all accesses. 'Volatile' is used when HW or other thread/process/module can change the data. In C compilation is done file by file, and only linker sees the whole code "at once". The symbols are, however. collected from all files.

I realize that. Hence my question if GPIOx->IDR is volatile, since then the compiler cannot optimize by replacing both occurrences of data with GPIOA->IDR.

At the time I wasn't sure if data needed to be volatile as well to prevent this substitution, but now I realize no, the substitutee being volatile is sufficient for this.

(And then there are the other people telling my that the compiler would never do this substitution for any kind of "int data = X" anyway.)

S.Ma
Principal

By the way, as we are discussing GPIOs, BSSSR register is quite handy to minimize Read/Modify/Write operations when different functions share different output pins of the same port.

That avoids using the OUT register directly with RMW operation.

Thanks, I know about BSRR; this was just an example by Clive, and has nothing to do with my question.