I am working on a code for the Atmel Microcontroller and using ATMEL Studio.
You can check the toolchain and studio version from here.
*\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\lib\gcc\avr\5.4.0*
I have a code in my two programs.
CASE_1:
#define USART_BAUD_RATE(BAUD_RATE) ((float)(5000000 * 64 / (16 * (float)BAUD_RATE)) + 0.5)
USART1.BAUD = (uint16_t)USART_BAUD_RATE(300);
CASE_2:
#define USART_BAUD_RATE(BAUD_RATE) ((float)(5000000 * 64 / (16 * (float)BAUD_RATE)) + 0.5)
/* uint32_t my_BaudRate = 300; //I set this value in the program, normally it's 115200, 2400, but sometimes it can be 300*/
USART1.BAUD = (uint16_t)USART_BAUD_RATE(my_BaudRate );
Sample Example:
#include <stdio.h>
#include <stdint.h>
#define USART_BAUD_RATE(BAUD_RATE) ((float)(5000000 * 64 / (16 * (float)(BAUD_RATE))) + 0.5)
uint16_t getValue_1() {
return (uint16_t)USART_BAUD_RATE(300);
}
uint16_t getValue_2(uint32_t inVal) {
return (uint16_t)USART_BAUD_RATE(inVal);
}
int main()
{
printf("Macro with Constant argument: %d\r\n", getValue_1());
printf("Macro with variable argument: %d\r\n", getValue_2(300));
return 0;
}
// Output
/*
Macro with Constant argument: 65535
Macro with variable argument: 1131
*/
I found out that the USART.BAUD has different values in both programs although it should be the same if I set the my_BaudRate to 300.
In Program 1: USART1.BAUD has the value 0xFFFF, although it should have been overflown and had 0x046B. I tried changing the BAUD_RATE value to 280 or less, it always sets it to 0xFFFF. Only after I set the value to 306, it sets the actual value less than 0xFFFF.
In Program 2: it works as expected, USART1.BAUD has the value 0x046B.
I think it has something to do with preprocessor or compiler optimization, but I am not sure if this is a known behavior or if I need to be careful about these kinds of macros.
I Would be grateful for any insights.
Best Regards.
USART_BAUD_RATE(300)will be replaced by(float)(5000000 * 64 / (16 * (float)300)) + 0.5). And similarlyUSART_BAUD_RATE(my_BaudRate)will be replaced by(float)(5000000 * 64 / (16 * (float)my_BaudRate)) + 0.5)(5000000 * 64 / (16 * 300)) + 0.5is66667,166666667. That is then converted to theintvalue66667, and the explicit conversion touint16_twill discard the top bits and leave you with65535. Which is indeed0xffff. If you split up the expression into smaller parts, and using temporary variables to store the intermediate results, it might be easier to see.my_BaudRateis missing in your question.USART1.BAUD = (uint16_t)(uint32_t)USART_BAUD_RATE(300);should give you the wrapped value0x46B, avoiding undefined behavior. (Replaceuint32_twithuint_fast32_t,uint_least32_torunsigned longifuint32_tis not implemented.)