Bregell
Bregell

Reputation: 139

Compiler arm-none-eabi-gcc v4.9.3 optimizes away operations to pointers

When I compile my code for my STM32F429 CPU everything works fine when I use the -O0 flag but as soon as I use a higher optimization (-O1, -O2, and -O3) the code breaks.
I'm using the CMSIS+HAL libraries from ST and some basic code.

The problem is that even though *uart_irq is defined as volatile the if (uart_irq && uart_irq->SOURCE == IRQ_SOURCE_UART) in the main loop is never evaluated.
I have tried to define uart_irq as a volatile void * without success.
The only thing that work is if uart_irq is defined as a volatile uint32_t and the integer is cast to a irq_instance when used as the compiler wont remove that during optimization.

I would be happy if anybody would shed some light on the problem.

main.h

#define API_COMMAND_SIZE 6
typedef struct irq_instance_s
{
    uint8_t SOURCE;
    uint8_t TYPE;   
    uint8_t *CONTEXT;  
    uint8_t SIZE; 
} irq_instance;
extern volatile irq_instance *uart_irq;

main.c
The receive pointer is freed inside hande_command

#include "main.h
volatile irq_instance *uart_irq = 0;

int main(void)
{
    uint8_t *receive  = 0;
    <Initialize stuff>

    /* Initialize first UART recieve */
    receive = malloc(API_COMMAND_SIZE);
    while (HAL_UART_Receive_IT(&huart1, receive, API_COMMAND_SIZE) == HAL_BUSY);
    /* Program Main loop */
    while(1) {
        if (uart_irq && uart_irq->SOURCE == IRQ_SOURCE_UART) { /* <---- Problem is here */
            handle_interrupt(uart_irq);
            free((void *)uart_irq);
            uart_irq = 0;
        }
     }
}

stm32f4xx_it.c
The HAL_UART_RxCpltCallback are called after each successful UART receive.

#include "main.h"

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    uint8_t *receive  = 0;
    uart_irq          = calloc(1, sizeof(irq_instance));
    uart_irq->SOURCE  = IRQ_SOURCE_UART;
    uart_irq->CONTEXT = huart->pRxBuffPtr - huart->RxXferSize;
    uart_irq->SIZE    = huart->RxXferSize;
    uart_irq->TYPE    = IRQ_TYPE_COMMAND;

    receive = malloc(API_COMMAND_SIZE);
    while (HAL_UART_Receive_IT(&huart1, receive, API_COMMAND_SIZE) == HAL_BUSY);
}

Upvotes: 1

Views: 339

Answers (3)

chqrlie
chqrlie

Reputation: 144715

The variable uart_irq is volatile, not just what it points to... Define it this way:

extern irq_instance * volatile uart_irq;

Upvotes: 0

Andy Brown
Andy Brown

Reputation: 12999

If I read this correctly then you are changing the uart_irq inside the IRQ handler and it's this change of pointer value that the optimizer cannot see in the regular program flow and hence is optimizing away.

The correct declaration for a volatile pointer is irq_instance * volatile uart_irq. The way that you have declared it tells gcc that the value pointed to by the pointer is volatile. If this is also the case then you may combine the two with volatile irq_instance * volatile uart_irq.

Upvotes: 1

Chad Kennedy
Chad Kennedy

Reputation: 1736

volatile irq_instance *uart_irq

says that the thing pointed to by uart_irq is volatile. But

if (uart_irq && uart_irq->SOURCE == IRQ_SOURCE_UART)

is looking at the pointer itself, not the thing that's being pointed to. If the pointer itself is also volatile, which looking at your code it is, then declare it like this:

volatile irq_instance * volatile uart_irq

Upvotes: 1

Related Questions