Setting AVR baud rates [C]

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

Hi,

As so many posts seem to be about people having USART problems because they miscalculated the UBRR value I wrote this "helper" .h file for C programs that effectively automates the lookup of the "Examples of baud rate setting" table given in most AVR data sheets.

Before including this .h you should #define two values (one of which, F_CPU, you may already be defining anyway):

#define BAUD 38400
#define F_CPU 11059200
#include "setbaud.h"

Assuming there is a "valid" UBRR for the given F_CPU and desired BAUD ("valid" = error between -2% and +2%) then the .h will define 3 or 4 values.

UBRR_VALUE is the 16 bit UBRR value to use

UBRRL_VALUE and UBRRH_VALUE are this split into 2 bytes

possibly: USE_2X which is only defined if the baud rate is only attainable by using U2X mode

The typical usage might therefore be the following though the actual USART register names will vary from AVR to AVR:

#define BAUD 57600
#define F_CPU 8000000
#include "setbaud.h"

void init _uart( void ) {
  UBRRL = UBRRL_VALUE;
  UBRRH = UBRRH_VALUE;
#ifdef USE_2X
  UCSRA |= (1<<U2X);
#endif
}

NB: this example won't work because 57600 is NOT a valid baud rate at 8MHz - you would see something like:

C:\setbaud.h:205:2: #error "Invalid baud for given CPU frequency"
C:\setbaud.h:206:2: #error "Only valid baud for 8000000 are 2400, 4800, 9600, 14400, 19200, 28800*, 38400, 76800*, 250000, 500000"

(the bauds marked '*' in this are the ones that must use U2X mode)

There are #errors if F_CPU and/or BAUD are not defined too or if F_CPU is not one of:

1000000
1834200
2000000
3686400
4000000
7372800
8000000
11059200
14745600
16000000
18432000
20000000

Enjoy.

Cliff

Attachment(s): 

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

Do you need L after any of the BAUD == constants?

Imagecraft compiler user

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

Nope cos C scales to fit

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

I'd appreciate if you could file that as a patch to the
avr-libc project. I'd include it into the distribution
as . The only thing that I'd change is
to convert the documentation on top into doxygen style,
and I'd kindly ask you to adopt the avr-libc license.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

clawson wrote:

#define BAUD 57600
#define F_CPU 8000000
#include "setbaud.h"

void init _uart( void ) {
  UBRRL = UBRRL_VALUE;
  UBRRH = UBRRH_VALUE;
#ifdef USE_2X
  UCSRA |= (1<<U2X);
#endif
}


I know its only an example, but doesn't writing UBRRL trigger the update of the baud register in most AVR chips. Shouldn't it be like this:
  UBRRH = UBRRH_VALUE;
  UBRRL = UBRRL_VALUE;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I know its only an example, but doesn't writing UBRRL trigger the update of the baud register in most AVR chips.

No, the UBRR does not use the temporary register like the 16 bit timer registers do. There is a note that the baud rate prescaler is updated immediately after UBRRL is changed, but this shouldn't make any difference at all.

Regards,
Steve A.

The Board helps those that help themselves.

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

I think this is a great idea. Is this or something similar going to be included as a part of avr-libc headers?

I once made this kind of header file for TWI communication module, but on company time, so regrets that I won't be posting that unless I rewrite it. It needed the CPU speed and wanted TWI clock speed and it would define appropriate prescaler and divisor values for the TWI module.

- Jani

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

Koshchi wrote:
... There is a note that the baud rate prescaler is updated immediately after UBRRL is changed, but this shouldn't make any difference at all.

Then if you write the low byte UBRRL and the USART baud prescaler updates, what happens if you then write the high byte UBRRH next? Does the USART baud prescaler update to the new value?

Another way to put it is, if there is no temporary register (I could not find any data sheet documentation about this) then writing UBRRH also updates the USART baud prescaler. If this is true, then why the note about UBRRL updating the register? The data sheet example programs that I've seen also initialize UBRRH then UBRRL.

If the USART baud prescaler doesn't update it would not be noticed most of the time. This is because you have to do something like setting a 2400 baud rate with 14 MHz clock before your need anything besides a zero value in UBRRH. Most commonly used USART baud prescaler values are less than 255, so the UBRRH reset zero default never changes for most applications.

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

dl8dtl wrote:
I'd appreciate if you could file that as a patch to the
avr-libc project. I'd include it into the distribution
as . The only thing that I'd change is
to convert the documentation on top into doxygen style,
and I'd kindly ask you to adopt the avr-libc license.

Jörg

I'd be HONOURED to have something I've done included in avr-libc :D

Excuse the neophyte question but where do I go to file this as a patch? Is there a published procedure?

(from comments above I may re-order the example UBRRL/UBRRH setting in the comment at the top of the file too :wink: )

Cliff

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

> Excuse the neophyte question but where
> do I go to file this as a patch?

https://savannah.nongnu.org/patch/?group=avr-libc

If you register on savannah before filing the patch, you can
log in, and your user name will be implicitly tied to the
report.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Jörg,

Patch #5343 now with you. ;)

Cliff

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

Yeah, I saw it, thanks!

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Quote:
Then if you write the low byte UBRRL and the USART baud prescaler updates, what happens if you then write the high byte UBRRH next? Does the USART baud prescaler update to the new value?

I believe in this case the the prescaler is not updated again until it times out, so there would be one bit at the bogus rate. But this would only affect you if you were sending a byte when you changed the UBRR. And if you were doing that, then you would get a glitch anyways since writing to UBRRL would cut short the bit that was in the chute.

I did try sending a byte immediately after setting the UBRR (at a baud rate that put the UBRR above 255). It worked just fine either way.

Regards,
Steve A.

The Board helps those that help themselves.

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

Why would anyone be changing UBRR *after* setting RXEN anyway? Surely you configure the UART and *then* you enable RXEN/TXEN so the UBRRL/UBRRH ordering becomes immaterial anyway doesn't it?

(OK, I once wrote an ARM bootloader that dynamically switched between 9600 and 115200 - it changed the baud rate scaler after the UART was operational but that's fairly unusual)

Cliff

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

Cliff's excellent idea inspired me to think more about this problem, especially since I had just been reading that section of the data sheet. In particular, I wanted a functional-style macro, and one that could be used in initializers, like so:

uint16_t ubbrtable[] = {UBBR_VAL(1,9600), UUBR_VAL(1,4800), ... and so forth

My first thought was to create an include file generator, and here is some output from the first, limping prototype:

#ifndef UBBR_H
#define UBBR_H

// built for F_CPU = 16000000

// Do not edit this file!
// It is created by ubbrtool.

#define UBBR_1X(B) UBBR_1X_ ## B
#define UBBR_2X(B) UBBR_2X_ ## B
#define UBBR_VAL(R,B) UBBR_ ## R ## X_ ## B
#define UBBRL_VAL(R,B) (UBBR_VAL(R,B) & 0xff)
#define UBBRH_VAL(R,B) (UBBR_VAL(R,B) >> 8)

#define UBBR_1X_76800 12 // 0.16% 
#define UBBR_2X_76800 25 // 0.16% 
#define UBBR_1X_38400 25 // 0.16% 
#define UBBR_2X_38400 51 // 0.16% 
#define UBBR_2X_28800 68 // 0.64% 
#define UBBR_1X_19200 51 // 0.16% 
#define UBBR_2X_19200 103 // 0.16% 
#define UBBR_1X_14400 68 // 0.64% 
#define UBBR_2X_14400 137 // 0.64% 
#define UBBR_1X_9600 103 // 0.16% 
#define UBBR_2X_9600 207 // 0.16% 
#define UBBR_1X_4800 207 // 0.15% 
#define UBBR_2X_4800 415 // 0.15% 
#define UBBR_1X_2400 415 // 0.12% 
#define UBBR_2X_2400 832 // 0.00% 
#define UBBR_1X_1200 832 // 0.00% 
#define UBBR_2X_1200 1665 // 0.00% 
#define UBBR_1X_600 1665 // 0.00% 
#define UBBR_2X_600 3332 // 0.00% 
#define UBBR_1X_300 3332 // 0.00% 

#endif // UBBR_H

Just in case you've never used ## -- it pastes two pre-processor tokens together and rescans the result. So, UBBR_VAL(1,9600) becomes UBBR_1X_9600, which is then substituted again.

It strikes me this morning that the two ideas could be merged, and the frequency dependent part of my header could be selected with #if's as Cliff does. That would handle all the ordinary cases, and the header generating tool would then only be needed for non-standard Baud rates and/or odd-ball values of F_CPU.

If anyone is interested, I can release my ubbrtool under GPL, as soon as I replace the most embarrassing hacks in the prototype.

-dave

P.S. I'm still testing, so the above may have bugs.

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

Funny you should mention the ## way of doing this - I thought about doing the same but didn't see much to be gained in the end by it - at the end of the day it's got be to be a manually entred lookup table anyway where the author (you or I) can spot the times to use U2X=1 if necessary and the #elif's seemed as good a solution as anything else.

Cliff

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

My motivation for going ## was two fold: 1) to make all Baud available simultaneously, instead of having only a single rate set by #define, and 2) to create a macro that reads with function syntax.

In any case, I got here via a circuitous route. After looking at your code, I concluded that a static header file couldn't get much better, so I wrote a header file generator. Only after having the generator did I conclude that it could also become a reasonable static header file. My original intention was to do something like this in the make file:

ubbr.h:
        ubbrtool $(F_CPU)

Which generates a custom header file for the project. This allows for a strange cpu crystal, and/or a non-standard Baud. For instance, if you sell your soul to the Devil to get a particular contract, you can say:

ubbr.h:
        ubbrtool -r666 $(F_CPU)

and it will generate UBBR values for 666 Baud, in addition to the standard rates.

-dave

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

Quote:
OK, I once wrote an ARM bootloader that dynamically switched between 9600 and 115200

But even in that case you would not want to change the rate in the middle of sending a byte. You would want to check that there is nothing in the UDR before changing the UBRR.

Regards,
Steve A.

The Board helps those that help themselves.

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

What do you think about the code below. The clue is letting the compiler (not the preprocessor) calculate the optimal baudrate register settings. Some optimization level 2,3 or s is required for moving out the floating point code. The resulting code will only be the three register writes.

What's missing is a warning for error ratings > 2%. Maybe someone here has an idea for this.

static __inline__ void setBaud(double, double) __attribute__((always_inline));
static __inline__ void setBaud(double BD, double F)
{
    /* calculate the UBRR values */
    unsigned int UBRR_VAL     = (unsigned int)( F / (16.0 * BD) + 0.5) - 1;
    unsigned int UBRR_VAL_U2X = (unsigned int)( F / ( 8.0 * BD) + 0.5) - 1;

    /* recalculate resulting baudrate */
    double BAUD     = F / (16.0 * (UBRR_VAL    +1));
    double BAUD_U2X = F / ( 8.0 * (UBRR_VAL_U2X+1));

    /* calculate the error rating */
    double ERROR     = (BAUD     / BD) - 1;
    double ERROR_U2X = (BAUD_U2X / BD) - 1;

    /* build absolute value of error */
    if( ERROR     < 0 ) ERROR     *= -1.0;
    if( ERROR_U2X < 0 ) ERROR_U2X *= -1.0;

    /* Only choose U2X if error rating is better */
    if( ERROR <= ERROR_U2X )  {
        UCSRA &= ~(1<<U2X);
        UBRRH = UBRR_VAL >> 8;
        UBRRL = UBRR_VAL  & 0xFF;
    } else  {
        UCSRA |= (1<<U2X);
        UBRRH = UBRR_VAL_U2X >> 8;
        UBRRL = UBRR_VAL_U2X  & 0xFF;
    }
}

Regards,
HJ

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

Quote:
What do you think about the code below.

Calculating the data rate at run time is legitimate in certain applications. It has its place.

I don't think there is any reason for the code to be inlined, there is no need for speed, and it doesn't have any decisions likely to be driven by constants (which expose opportunities for optimization), so why suffer the bloat of inlining?

Also, I think BD and F should be long, and you should be able to scale error so that it fits in a long (or even an int), so you could eliminate the need for the floating point library entirely. If the ap has no other use for fp, it would be annoying to have to pull it in just for setting the Baud registers.

Now, the very interesting thought that your code provokes in my mind is this: Can you code this function cleanly enough that when you pass in constants for Baud and f_cpu, the compiler's constant folding actually turns the whole thing into a single integer assignment? I believe gcc's constant folding is pretty good, assuming the expression(s) is well-exposed and in a single compilation unit. If it can see enough, the compiler will effectively inline the entire function invocation down to a single assignment. That would be a very interesting experiment if you have the time. If it works, then the whole idea of an include file full of pre-calculated #defines is moot.

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

Quote:
I don't think there is any reason for the code to be inlined, there is no need for speed, and it doesn't have any decisions likely to be driven by constants (which expose opportunities for optimization), so why suffer the bloat of inlining?

The reason for using floats is for calculating the baud rate error. This calculation cannot easily be done with integer math. With inlining and of course compile time constants for BD and F the compiler will not generate any floating point code. The generated code is just the register settings - I verified this!
You can call setBaud() e.g. like this:

setBaud( 9600, 8000000L );  /* integer constants */
setBaud( 9600.0, 8.0e6 );   /* float constants */
setBaud( BAUDRATE, F_CPU ); /* macros*/

GCC will handle the type conversion for the parameters.

Regards,
HJ

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

I find hj's code elegant, but curious--these are MICROcontrollers. Off the top of my head I'd think the routine (with the pulled-in floating-point primitives) would take about half of a Mega48. All to find the value of a single byte that is normally unvarying. (UBRRH is rarely needed in practice.)

A fixed value suits most apps. A magic crystal value and a table of UBRRL values certainly doesn't have the flexibility of the posted approach but is as involved as I've ever needed.

Next please post the run-time equivalent of AVRCalc for setting my OCRxy value for my timer heartbeat. Between setting the UBRRL value and the OCR value, my Mega48 will be full. I'd get laughed out of the office.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Before you're getting laughed out of the office, perhaps we
should get you another compiler? :-)

I wrote a foo.c file that solely consists of Hans-Jürgen's
function, called by a main() that is otherwise empty (and
returns 42, just to return something). Here's the resulting
code size:

j@ida 344% avr-gcc -mmcu=atmega16 -Os -c foo.c
j@ida 345% avr-size foo.o
   text    data     bss     dec     hex filename
     26       0       0      26      1a foo.o

That's the corresponding assembly code:

.global main
        .type   main, @function
main:
/* prologue: frame size=0 */
        ldi r28,lo8(__stack - 0)
        ldi r29,hi8(__stack - 0)
        out __SP_H__,r29
        out __SP_L__,r28
/* prologue end (size=4) */
        cbi 43-0x20,1
        out 64-0x20,__zero_reg__
        ldi r24,lo8(103)
        ldi r25,hi8(103)
        out 41-0x20,r24
        ldi r24,lo8(42)
        ldi r25,hi8(42)
/* epilogue: frame size=0 */
        jmp exit
/* epilogue end (size=2) */

I guess you missed the point of that entire thing... There's
no more floating-point stuff around at all, that's all handled
by the compiler internally.

Obviously, you need to have optimizations turned on.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

I have a problem or I have the programmer ispavru1 but I cannot program since cradled it disconnected attempt says to me that I have some thing, or connects the pins miso sck rest, etc but driver not like lowering it or that hauls since it does not leave me if it is not much annoyance podrian to me to say step by step that it is what I must do so that works
my mail is ultramosh@hotmail.com

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

I have a problem or I have the programmer ispavru1 but I cannot program since cradled it disconnected attempt says to me that I have some thing, or connects the pins miso sck rest, etc but driver not like lowering it or that hauls since it does not leave me if it is not much annoyance podrian to me to say step by step that it is what I must do so that works
my mail is ultramosh@hotmail.com

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

I think this header file came to my rescue. I was having difficulty with baud rate calculations (if I go with whatever data sheet says and configure accordingly). But one thing I noticed is that if I define the BAUD as 115200, I am not getting correct result. I get the warning message "Baud rate achieved is higher than allowed". I did #undef BAUD and re-defined. But not sure why still this issue? If I #define BAUD 9600 in header file there is no issue. So default value defined has an impact!

 

In header file:
#define BAUD 115200  // Default Baud Rate. But this will be overridden by USART0Init() function

In source file:
void USART0Init(const uint32_t baudRate)
{

    // Set baud rate using macro. Undesine the BAUD first and then redefine
    // to required value
    #undef BAUD  // avoid compiler warning
    #define BAUD baudRate  // Set the new baud rate.
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
}

 

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

Not clear what header file you are talking about? Do you mean:

 

http://www.nongnu.org/avr-libc/u...

 

which, as you can see, is simply used as:

#define F_CPU 11059200
#define BAUD 38400
#include <util/setbaud.h>

and then:

UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;

(in the same file!)

 

PS though you do have to consider USE_2X too.

Last Edited: Fri. Oct 28, 2016 - 09:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The header file setbaud.h came with avr8-gnu-toolchain. 

My complete code is in my post https://www.avrfreaks.net/forum/interrupt-based-usart-transmission-and-reception.

I am doing #undef and using new baud rate in init() function, it is working as long as I keep baud rate in header file @9600. I am confused how this works then!

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

Just do EXACTLY what it shows in he user manual. Are you taking note of the U2X setting?