This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Strange behavior of code

Hi, 

I am using nRF5_SDK_15.2.0_9412b96 and Segger IDE.

I have written to echo every data received from UART.

I have a variable UART_Data to store data received from UART.

In the main loop, I will check the if (UART_Data > 0), then I echo back the UART_Data.

The application does not echo any data at all. It is not working.

Then, I remove the (UART_Data > 0) checking, so the application will keep repeating echo the same UART_Data received.

This is working.

Then I try another scenario, I put  back the (UART_Data > 0) checking, and I also put nrf_delay_ms(100) in the end of main loop.

This is working.

I just cannot figure out why the original code is not working.

Please advise

Please see the code below.

The red color is not working code.

The blue color is working code.

This code is not working

uint8_t UART_Data;

void uart_handle(app_uart_evt_t * p_event)
{
if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_communication);
}
else if (p_event->evt_type == APP_UART_FIFO_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_code);

}else if (p_event->evt_type == APP_UART_DATA_READY)
{
app_uart_get(&UART_Data);

}
}

int main(void)
{
ret_code_t err_code;
uint8_t a = '1';
// Initialize.
//log_init();
timers_init();
leds_init();
power_management_init();
ble_stack_init();
advertising_init();


const app_uart_comm_params_t comm_params =
{
UART_RX_PIN,
UART_TX_PIN,
UART_RTS_PIN,
UART_CTS_PIN,
UART_HW_FC,
false,
NRF_UART_BAUDRATE_115200

};

APP_UART_FIFO_INIT(&comm_params,
UART_RX_BUF_SIZE,
UART_TX_BUF_SIZE,
uart_handle,
APP_IRQ_PRIORITY_LOWEST,
err_code);

APP_ERROR_CHECK(err_code);

advertising_start();
UART_Data = 'A';
for (;;)
{
       if(UART_Data > 0 ){
       while (app_uart_put(UART_Data) != NRF_SUCCESS);
       nrf_delay_ms(100);
        UART_Data = 0;

     }
}

}

Below code is working

uint8_t UART_Data;

void uart_handle(app_uart_evt_t * p_event)
{
if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_communication);
}
else if (p_event->evt_type == APP_UART_FIFO_ERROR)
{
APP_ERROR_HANDLER(p_event->data.error_code);

}else if (p_event->evt_type == APP_UART_DATA_READY)
{
app_uart_get(&UART_Data);

}
}

int main(void)
{
ret_code_t err_code;
uint8_t a = '1';
// Initialize.
//log_init();
timers_init();
leds_init();
power_management_init();
ble_stack_init();
advertising_init();


const app_uart_comm_params_t comm_params =
{
UART_RX_PIN,
UART_TX_PIN,
UART_RTS_PIN,
UART_CTS_PIN,
UART_HW_FC,
false,
NRF_UART_BAUDRATE_115200

};

APP_UART_FIFO_INIT(&comm_params,
UART_RX_BUF_SIZE,
UART_TX_BUF_SIZE,
uart_handle,
APP_IRQ_PRIORITY_LOWEST,
err_code);

APP_ERROR_CHECK(err_code);

advertising_start();
UART_Data = 'A';
for (;;)
{
       if(UART_Data > 0 ){
       while (app_uart_put(UART_Data) != NRF_SUCCESS);
        UART_Data = 0;

       }

      nrf_delay_ms(100);
}

}

Parents
  • Try adding 'volatile' to the definition of UART_Data.

    I suspect the compiler is seeing that you set UART_Data=0 at the end of one loop iteration, then immediately check UART_Data>0 at the start of the next iteration. There is no other code in between those statements that can alter the value of UART_Data, so it thinks the value must still be 0 when you test if it's >0, so the condition will always be false and can be optimised out.

    In your second version, there is a call to nrf_delay_ms between those two statements. The compiler isn't smart enough to work out whether nrf_delay_ms alters UART_Data, so it can't make any assumptions about the value of UART_Data after the call and it can't optimise out the condition.

    The problem is the compiler doesn't realise the interrupt handler can run and alter UART_Data in between those statements. That's intentional - C is largely defined as single-threaded, and the programmer has to be very careful when a variable is modified outside of the current thread (by another thread, or interrupt, or hardware, etc). Declaring it as volatile tells the compiler that its value might change every time you access it, so it can't optimise away any of the accesses.

Reply
  • Try adding 'volatile' to the definition of UART_Data.

    I suspect the compiler is seeing that you set UART_Data=0 at the end of one loop iteration, then immediately check UART_Data>0 at the start of the next iteration. There is no other code in between those statements that can alter the value of UART_Data, so it thinks the value must still be 0 when you test if it's >0, so the condition will always be false and can be optimised out.

    In your second version, there is a call to nrf_delay_ms between those two statements. The compiler isn't smart enough to work out whether nrf_delay_ms alters UART_Data, so it can't make any assumptions about the value of UART_Data after the call and it can't optimise out the condition.

    The problem is the compiler doesn't realise the interrupt handler can run and alter UART_Data in between those statements. That's intentional - C is largely defined as single-threaded, and the programmer has to be very careful when a variable is modified outside of the current thread (by another thread, or interrupt, or hardware, etc). Declaring it as volatile tells the compiler that its value might change every time you access it, so it can't optimise away any of the accesses.

Children
No Data
Related