EMBEDDED C - Volatile qualifier does not matter in my interrupt routine

I am new to embedded C, and I recently watched some videos about volatile qualifier. They all mention about the same things. The scenarios for the use of a volatile qualifier :

  1. when reading or writing a variable in ISR (interrupt service routine)
  2. RTOS application or multi thread (which is not my case)
  3. memory mapped IO (which is also not my case)

 

My question is that my code does not stuck in the `whiletest();`function below

 when my UART receives data and then triggers the `void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)` interrupt function

```

int test;

 

int main(void)

{

  test = 0;

  MX_GPIO_Init();

  MX_USART1_UART_Init();

  HAL_UART_Receive_IT(&huart1, (uint8_t *)&ch, 1);

 

  while (1)

   {

                Delay(500);             

                printf("the main is runing\r\n");

        whiletest();

   }

}

 

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

        if(huart->Instance == USART1)

        {

        Test = 1;

                HAL_UART_Receive_IT(&huart1, (uint8_t *)&ch, 1);

        }

}

 

void whiletest(void)

{

int count =0;

while(!test){

 count++;

 printf("%d\r\n",count);

 Delay(2000);

 }

}

```

I use keil IDE and stm32cubeIDE. I learned that the compiler would optimize some instructions away if you choose the o2 or o3 optimization level. Therefore, I chose the o2 level for build option, but it seems no effect on my code. The compiler does not optimize the load instruction away in the while loop and cache the test value `0` in the main function as the videos teach on youtube. It is confusing. In what situation I am supposed to use volatile qualifier while keep my code optimized (o2 or o3 level).zed (o2 or o3 level)

 

note: I am using stm32h743zi (M7)

Parents
  • Hello

    volatile guarantees that the compiler will not optimise out the access.

    However if you use do not use volatile then the compiler may or may not optimise, depending on other code.

    If you changed the code to remove the Delay() and printf() in the loop, then you would quite likely see the problem of the loop not exiting.

    Basically, it works like this:

    If you do not put the volatile, it tells the compiler it is allowed to optimise away re-reads of the physical memory into registers if it wants to.

    ie. A loop like

    while(!test) {

    count++;

    }

    can end up becoming more like

    register_x = test;

    while(!register_x) {

    count++;

    }

    Now clearly register x is not reloading so it will run forever, even if test changes.

    However you have also made some calls to other functions (delay() and printf()).

    The compiler will need to use registers to set up the arguments to call those functions. It is most likely dumping the register used to hold test, so it must read it again when it goes around the loop and hence the volatile problem is not happening.

    The best thing to do is to look at the assembler code that was generated by the compiler. See how the registers are being used.

Reply
  • Hello

    volatile guarantees that the compiler will not optimise out the access.

    However if you use do not use volatile then the compiler may or may not optimise, depending on other code.

    If you changed the code to remove the Delay() and printf() in the loop, then you would quite likely see the problem of the loop not exiting.

    Basically, it works like this:

    If you do not put the volatile, it tells the compiler it is allowed to optimise away re-reads of the physical memory into registers if it wants to.

    ie. A loop like

    while(!test) {

    count++;

    }

    can end up becoming more like

    register_x = test;

    while(!register_x) {

    count++;

    }

    Now clearly register x is not reloading so it will run forever, even if test changes.

    However you have also made some calls to other functions (delay() and printf()).

    The compiler will need to use registers to set up the arguments to call those functions. It is most likely dumping the register used to hold test, so it must read it again when it goes around the loop and hence the volatile problem is not happening.

    The best thing to do is to look at the assembler code that was generated by the compiler. See how the registers are being used.

Children