Ali Mak
Ali Mak

Reputation: 27

using float numbers in embedded libraries

When I make I2C or UART library I need to include floating point in order to put the right bits into the registers that controlthe bit-rate or baud rate in these peripherals by using a formulas like the following one that is responsible of putting the right bits into UBBR register which controls the baud rate :`

#define F_CPU 1000000UL
#define BAUD_RATE 9600
#define FACTOR_8_16 16

/*calculate UBBR value */
uint16_t UBBR_value = lrint(( F_CPU / (FACTOR_8_16 * (float)BAUD_RATE) ) - 1);
//Put the upper part of the UBBR value here (bits 8 to 11)
UBRRH = (uint8)(UBBR_value >> 8);
//Put the remaining part of the UBBR value here
UBRRL = (uint8)UBBR_value;

The UBBR becomes 6 but when I remove the (float)type casting the UBBR becomes 5 which generates a different baud rate that's why I need to use floating point in order to get the accurate number, is this a bad approach as I should totally avoid using floating number as it adds massive blocks of code into program code,should I change it and use another way or is it ok? I can use some other ways but they will be more limited(because some way I can use is to limit the baud rate to certain values that are standardised , I won't be able to put any baud rate freely)

actually in the question I am talking generally -not just in the UART case- that if I faced I problem that the best solution to it is by including some floating point arithmetic should I avoid it and use another approach that might be not as good as the floating point approach but still gives the right answer , or is it okay to use it?

Upvotes: 0

Views: 370

Answers (2)

Ali Mak
Ali Mak

Reputation: 27

I used fixed point arithmetic advice from one of the comments.. so I used one bit as precision and the rest of the of the register for the integer part- used only one bit precision because I wanted only to know if the precision part is > 0.5 so I round up to the next integer number (5.5-->6), otherwise( if precision <.5) I don't

    #define FP_F_CPU (F_CPU<<1)  //FP for fixed point

#define FP_FACTOR_8_16 (8<<1)
/*****enter the baud rate****/
#define BAUD_RATE 9600

#define FP_BAUD_RATE ((uint32)BAUD_RATE<<1)

#define MULTIPLY_FIXED_POINT(A , B ,scale_bits) (( (A) * (B) ) >> scale_bits)

#define DIVIDE_FIXED_POINT(A ,B ,scale_bits)( ((A) << scale_bits) / (B) )

/*calculate UBBR value */
uint16 UBBR_value = DIVIDE_FIXED_POINT( (uint32)FP_F_CPU, MULTIPLY_FIXED_POINT((uint32)FP_FACTOR_8_16, (uint32)FP_BAUD_RATE,1)  ,1 )  - (1 << 1);
if((UBBR_value & 1) ) //if the percent is 0.5
    UBBR_value = (UBBR_value >> 1) +1; //remove the extra fraction bit and round up 
else
    UBBR_value >>= 1; // else just remove the extra fraction bit

Upvotes: 0

Jabberwocky
Jabberwocky

Reputation: 50892

You don't need floating point here at all.

(FACTOR_8_16 * BAUD_RATE) = 76000

F_CPU / (FACTOR_8_16 * BAUD_RATE) ) = 
1000000 / 76000 = 13.1578   which will be rounded
                            o 13 by integer arithmetic

So you can just write this:

/*calculate UBBR value */
uint16_t UBBR_value = F_CPU / (FACTOR_8_16 * BAUD_RATE) - 1;
//Put the upper part of the UBBR value here (bits 8 to 11)
UBRRH = (uint8)(UBBR_value >> 8);
//Put the remaining part of the UBBR value here
UBRRL = (uint8)UBBR_value;

Upvotes: 2

Related Questions