A free gift for the community. A prototype UBRR calculator.

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tired of looking up tables or calculating the proper UBRR values for your AVR's asynchronous UART?

I wrote this last night, it was kind of a pain in the ass debugging mistakes in AVRStudio/AVRGCC without feebdack..

The macros themselves allow you to calculate UBRR values for 1x and 2x clocked UARTs. You can also retrieve the error percentages and figure out the actual baud computed.

Once it's setup you simply define your baudrate by like #define BAUDRATE 57600UL...

They work based on preprocessor calculations with F_CPU and a baudrate only.

Here's the basic macros

//Corresponds to a .50% percentage limit
#define BAUDLIMIT 050

//Get basic UBRR values multiplied by 10000 (These are not rounded)
#define CNST_UBRR(baud) ((10000*F_CPU)/(16*baud) - 10000) //16-bit, baud rate for normal asynchronous
#define CNST_UBRR2(baud) ((10000*F_CPU)/(8*baud) - 10000) //16-bit, baud rate for 2x asynchronous

//Produces baud error (given normally size numbers) [output is 100 times the real error percentage]
#define BAUDERROR(bdact,bdstd) ((10000*bdact)/bdstd - 10000)

//Produces actual baud rate given UBRR numbers (these numbers are multiplied by 10000 on input)
#define BAUDGEN(ubrr) ((F_CPU * 10000) / (8 * ((ubrr/10000)*10000 + 10000)))

//Return percentage * 100, i.e. 1% = 100, 2.5% = 250, etc...
#define BAUD_ERROR_1X(baud) BAUDERROR(BAUDGEN(GET_UBRR_1X(baud)),baud)
#define BAUD_ERROR_2X(baud) BAUDERROR(BAUDGEN(GET_UBRR_2X(baud)),baud)

//Returns UBRR values multiplied by 10000, these are properly rounded
#define GET_UBRR_1X(baud) (CNST_UBRR(baud) - (CNST_UBRR(baud)/10000)*10000 >= 5000 ? CNST_UBRR(baud) + 10000 : CNST_UBRR(baud))
#define GET_UBRR_2X(baud) (CNST_UBRR2(baud) - (CNST_UBRR2(baud)/10000)*10000 >= 5000 ? CNST_UBRR2(baud) + 10000 : CNST_UBRR2(baud))

//Checks to see if the requested baudrate is within specs
#define IS_BAUD_RELIABLE(baud) ((BAUD_ERROR_1X(baud) <= BAUDLIMIT) || (BAUD_ERROR_2X(baud) <= BAUDLIMIT))

The only macros you really need to concern yourself with are the GET_UBRR_1X and GET_UBRR_2X, and IS_BAUD_RELIABLE

Note that GET_UBRR_1X and GET_UBRR_2X return values that are 10000 times bigger than their intended result. Just divide them by 10000 before you place them into registers.. (I believe it will compile down to a constant)..

Here's an example of their use:

#define F_CPU 8000000UL //CPU Speed in hertz
#define BAUDRATE 250000UL //Sets up baudrate
#define DEBUG

///////////////////////////////////////////////////////////////////////////////////////////////////
// Pre-processor arithmetic that calculates the nearest UBRR values for the baudrate generator
//
//

//Corresponds to a .50% percentage limit
#define BAUDLIMIT 050

//Get basic UBRR values multiplied by 10000 (These are not rounded)
#define CNST_UBRR(baud) ((10000*F_CPU)/(16*baud) - 10000) //16-bit, baud rate for normal asynchronous
#define CNST_UBRR2(baud) ((10000*F_CPU)/(8*baud) - 10000) //16-bit, baud rate for 2x asynchronous

//Produces baud error (given normally size numbers) [output is 100 times the real error percentage]
#define BAUDERROR(bdact,bdstd) ((10000*bdact)/bdstd - 10000)

//Produces actual baud rate given UBRR numbers (these numbers are multiplied by 10000 on input)
#define BAUDGEN(ubrr) ((F_CPU * 10000) / (8 * ((ubrr/10000)*10000 + 10000)))

//Return percentage * 100, i.e. 1% = 100, 2.5% = 250, etc...
#define BAUD_ERROR_1X(baud) BAUDERROR(BAUDGEN(GET_UBRR_1X(baud)),baud)
#define BAUD_ERROR_2X(baud) BAUDERROR(BAUDGEN(GET_UBRR_2X(baud)),baud)

//Returns UBRR values multiplied by 10000, these are properly rounded
#define GET_UBRR_1X(baud) (CNST_UBRR(baud) - (CNST_UBRR(baud)/10000)*10000 >= 5000 ? CNST_UBRR(baud) + 10000 : CNST_UBRR(baud))
#define GET_UBRR_2X(baud) (CNST_UBRR2(baud) - (CNST_UBRR2(baud)/10000)*10000 >= 5000 ? CNST_UBRR2(baud) + 10000 : CNST_UBRR2(baud))

//Checks to see if the requested baudrate is within specs
#define IS_BAUD_RELIABLE(baud) ((BAUD_ERROR_1X(baud) <= BAUDLIMIT) || (BAUD_ERROR_2X(baud) <= BAUDLIMIT))

///////////////////////////////
//Sanity checks for baudrates

//Check if BAUD_2X is set..
#ifdef BAUD_2X
#undef BAUD_2X
#endif

#ifndef UBRR_LOW
#ifndef UBRR_HIGH
#ifndef UBRR_FULL
#if ((BAUD_ERROR_2X(BAUDRATE)^2) < (BAUD_ERROR_1X(BAUDRATE)^2))

#define BAUD_2X

#ifdef DEBUG
#warning 2x ouput has less error in this case
#endif

#if ((BAUD_ERROR_2X(BAUDRATE)^2) > (BAUDLIMIT^2))
#warning Baud Rate error is greater than .50% (2x)
#else
#ifdef DEBUG
#warning Baud rate within specs (2x)
#endif
#endif

#define UBRR_FULL (GET_UBRR_2X(BAUDRATE)/10000)
#define UBRR_LOW ((GET_UBRR_2X(BAUDRATE)/10000) & 0xFF)
#define UBRR_HIGH (((GET_UBRR_2X(BAUDRATE)/10000) >> 8) & 0xFF)

#elif ((BAUD_ERROR_1X(BAUDRATE)^2) > (BAUD_ERROR_2X(BAUDRATE)^2))

#ifdef DEBUG
#warning 1x output has less error in this case
#endif

#if ((BAUD_ERROR_1X(BAUDRATE)^2) > (BAUDLIMIT^2))
#warning Baud Rate error is greater than .50% (1x)
#else
#ifdef DEBUG
#warning Baud rate within specs (1x)
#endif
#endif

#define UBRR_FULL (GET_UBRR_1X(BAUDRATE)/10000)
#define UBRR_LOW ((GET_UBRR_1X(BAUDRATE)/10000) & 0xFF)
#define UBRR_HIGH (((GET_UBRR_1X(BAUDRATE)/10000) >> 8) & 0xFF)

#else
#warning error percentages are equal for the both
#endif //(BAUD_ERROR_2X(BAUDRATE)^2 < BAUD_ERROR_1X(BAUDRATE)^2)
#endif //#ifndef BAUD_FULL
#endif //#ifndef BAUD_HIGH
#endif //#ifndef BAUD_LOW

I just wrote it last night and I bet it could be cleaned up significantly...

Let me know what you think, feel free to use it...also feel free to update it or clean it up (and post your results).

Hope somebody finds use for it (you could just as easily make your code print out possible baud rates if it determines your programmed valus is unreliable).

-Brad

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you aware of this: https://www.avrfreaks.net/index.p... ?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lemme see, I have used Atmel UART/USARTS for about 7 years (all of my board have some comms) never needed on of them "calculator" thingys, just used the formula provided by Atmel and an appropriate xtal. But it may come in handy for someone I guess :)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly