Separating Mantissa from Decimal part of a float - Page 1
Forum section: electronics / general

author: noname4me
author_rank: Regular Contributor
timestamp: December 25, 2017, 11:32:41 pm
content: Hi,I am writing a function which will work out the contents of the USART1->BRR register when using STM32 microcontrollers.This register sets up the USART speed, and works in the following manner:Tx/Rx baud = fCK/(16*USARTDIV)USARTDIV is programmed into the USARTx->BRR register to set up the speed.The integer part is programmed into bits 4 to 16, while the decimal part goes into bits 0 to 3.I would like to write a function that can do the sum above, and work out what goes in each portion and, given the baud rate and fCK, return the value that can be programmed into the BRR register.I can get the integer part fine, but I don't know how to deal with the decimal part - could anyone please help me understand what I need to do?I've been experimenting on an online compiler with the following onhttp://en.cppreference.com/w/c/numeric/math/modf:Code:#include <stdio.h>#include <math.h>#include <float.h>int main(void){float fck = 48000000;float baudrate = 9600;float temp;double topout;float bottom;temp = (fck/baudrate)/16;bottom = modf(temp, &topout);//topout stores the mantissa//bottom stores the divider//temp is the original numberprintf("temp = %.4f\n bottom = %.4f\n topout = %.5f\n",temp,bottom,topout);//to extract this and make the brr:int mantissa;int divisor;mantissa = (int)topout;divisor = ((int)(bottom*10));divisor = divisor % 10000;printf("mantissa = %.4d\n divisor = %.4d\n",mantissa,divisor);}http://coliru.stacked-crooked.com/view?id=d2fb35446965eb41Thanks

author: rstofer
author_rank: Super Contributor
timestamp: December 25, 2017, 11:40:53 pm
content: Multiply the fraction by 16, add 0.5 and convert to integer?

author: noname4me
author_rank: Regular Contributor
timestamp: December 25, 2017, 11:46:10 pm
content: lol- thanks very muchI forgot about the *16 of the decimal part and was trying to make the decimal part output "5" for a value of 0.5Your solution works

author: amyk
author_rank: Super Contributor
timestamp: December 26, 2017, 05:03:56 pm
content: No, do not use floating-point for that... unless you want to eat up a huge chunk of your ROMhttps://www.eevblog.com/forum/microcontrollers/samd11-i2c-driver-alone-consumes-12kb-out-of-16kb-and-facing-rom-overflow-error/Unless you really need a "continuously variable" baud rate, just calculate the correct register setting for the rate you need and use that.

author: rstofer
author_rank: Super Contributor
timestamp: December 26, 2017, 05:27:44 pm
content: Right! Normally, you see baud rate constants inside #ifdef <some clock frequency> #endif blocks. Then the integer and fractional components are defined for each required baud rate using #define. The actual calculations can be done elsewhere. Like Excel if a document is worthwhile. Otherwise just using a calculator.OTOH, if floating point is required by the project, the libraries will need to be included in any event.

author: mikerj
author_rank: Super Contributor
timestamp: December 29, 2017, 09:03:36 pm
content: You can simply treat the value in the BRR register as an integer, and scale the resulting frequency value by 2^12.Baud = 4096*fCK/(16*BRR) = (256*fCK)/BRRDo the multiplication first to avoid loss of precision, but also check the result of the multiply won't cause an overflow.

author: Jope
author_rank: Regular Contributor
timestamp: December 30, 2017, 03:52:54 pm
content: You don't have to worry about thatat all- no floats, no separation of bits or anything.You just need to divide your frequency by the baudrate and that's it:Code:uint32_t fck = 48000000;uint32_t baudrate = 9600;uint32_t BRR_value = fck/baudrate;

author: noname4me
author_rank: Regular Contributor
timestamp: January 01, 2018, 10:53:48 pm
content: HiThanks for the feedback guys - in my final applications I won't be using this function, this is just for me to play around with the USART and understand it better.This is related to some problems that I am having with the USART, about which I will make another thread (it doesn't work with my initialisation function).I will make note of the floating point issue for later: reduce them as much as possible.Thanks

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 02, 2018, 05:21:58 pm
content: As jope has stated, you don't actually need any FP in this case.And yes, on targets that don't have any FPU, you should learn how to make use of integer computation. Fixed point is one widely used way of manipulating fractional numbers with integers only.

author: westfw
author_rank: Super Contributor
timestamp: January 03, 2018, 02:36:31 am
content: QuoteThere was someflamingdiscussion about the fractional baud rate generator in the STM32F, and how awful ST's code is, back here:https://www.eevblog.com/forum/microcontrollers/st's-(stm32cube)-software-ecosystem-is-terrible-how-can-we-fix-it/msg626014/#msg626014

author: llkiwi2006
author_rank: Regular Contributor
timestamp: January 03, 2018, 03:40:43 am
content: libopencm3 has some nice comments regarding this:https://github.com/libopencm3/libopencm3/blob/580a2a4a63cad6ca32ac837cf6d1c64664ce80f3/lib/stm32/common/usart_common_all.c#L63Quote

author: westfw
author_rank: Super Contributor
timestamp: January 03, 2018, 04:09:23 am
content: (alas, not true of all chips with fractional BRG hardware, so you need to watch carefully. The Atmel SAM chips all seem to put the "Fractional" part of the BRG divisor in thehighbits of the actual register. You can still simplify the math as shown here, but then you have to shift bits or rotate before you can actually do the configuration... (Sigh. Why, Atmel, Why?))