Calculation of UBRR register by macros

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

Hello, I am communicating two microcontrollers serially. one of them is atmega328p and the other one is atmega2560. The baudrate is 9600. According to data sheet for a 16MHz crystal and 9600 Baudrate value. The value for UBRR register should be 103. Now I have created a Usart_init() function which takes UBRR value as argument. The UART is working fine when I hard code 103 as the argument  like this in the code below
 

main()
{
    USART_Init(103);

    /******************/
}
void USART_Init( unsigned int ubrr)
{
	UBRR0H = (unsigned char)(ubrr>>8);
	UBRR0L = (unsigned char)ubrr;
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	UCSR0C= (1<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01);
}

 

 

But when I replace these with macro I only get ???? on the serial monitor. I am sure I am making some basic mistake here due  to my lack of knowledge. I am using macros as the following

 

 


#define FOSC 16000000
#define BAUD 9600
#define UBRR_VAL ((FOSC/(16 * BAUD)) -1 )


main()

{

    USART_Init(UBRR_VAL);

/******************/

} 

void USART_Init( unsigned int ubrr)

{

    UBRR0H = (unsigned char)(ubrr>>8);

    UBRR0L = (unsigned char)ubrr;

    UCSR0B = (1<<RXEN0)|(1<<TXEN0); 

    UCSR0C= (1<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01); 

}

 

I even try to hardcode 103 as parameter and then print this UBRR_VAL macro but I still get ??? instead of this value. Everything else is printing normally.

Thanks in Advance

This topic has a solution.
Last Edited: Wed. Aug 19, 2020 - 09:42 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You haven't said which C compiler that is but surely it needs some kind of header for define the special function registers? Anyway I add an include of <avr/io.h> and tried to build it for ATmega328p in AS7 (avr-gcc) and got:

D:\test\test\main.c(7,1): warning: return type defaults to 'int' [-Wimplicit-int]
		 main()
		 ^
		.././main.c: In function 'main':
D:\test\test\main.c(11,2): warning: implicit declaration of function 'USART_Init' [-Wimplicit-function-declaration]
		  USART_Init(UBRR_VAL);
		  ^
D:\test\test\main.c(11,28): warning: integer overflow in expression [-Woverflow]
		.././main.c: At top level:
D:\test\test\main.c(17,6): warning: conflicting types for 'USART_Init'
		 void USART_Init( unsigned int ubrr)
		      ^
D:\test\test\main.c(11,2): info: previous implicit declaration of 'USART_Init' was here
		  USART_Init(UBRR_VAL);
		  ^

Maybe your compiler accepts "main()" as an interface for main() but most would like to see a return type, usually "int" or "void".

 

But the main problem here is you have called USART_Init(unsigned int) before the compiler "knows" about the function type. Either you have to put the function before main() so the compiler already knows when it encounters it. Or you need to DECLARE the function above main() with the definition below.

 

Anyway as it stand what I see in the generated code is:

	USART_Init(UBRR_VAL);
  90:	65 ec       	ldi	r22, 0xC5	; 197
  92:	72 e0       	ldi	r23, 0x02	; 2
  94:	80 e0       	ldi	r24, 0x00	; 0
  96:	90 e0       	ldi	r25, 0x00	; 0
  98:	f0 df       	rcall	.-32     	; 0x7a <USART_Init>

In this particular compiler the first parameter to a function is passed in R25:R24 as you see in the function implementation:

0000007a <USART_Init>:

void USART_Init( unsigned int ubrr)

{

	UBRR0H = (unsigned char)(ubrr>>8);
  7a:	90 93 c5 00 	sts	0x00C5, r25	; 0x8000c5 <__TEXT_REGION_LENGTH__+0x7f80c5>

	UBRR0L = (unsigned char)ubrr;
  7e:	80 93 c4 00 	sts	0x00C4, r24	; 0x8000c4 <__TEXT_REGION_LENGTH__+0x7f80c4>

but as you also see the value in R25:R24 is 00:00 and that's because you called the function without declaration and C therefore assumes "int function()" if told nothing else. As such a function does NOT have a parameter then C will not prepare to pass the value. If, instead I used:

#include <avr/io.h>
#define FOSC 16000000
#define BAUD 9600
#define UBRR_VAL ((FOSC/(16 * BAUD)) -1 )

void USART_Init( unsigned int ubrr);

int main()

{
	USART_Init(UBRR_VAL);
	/******************/
}

void USART_Init( unsigned int ubrr)

{
	UBRR0H = (unsigned char)(ubrr>>8);
	UBRR0L = (unsigned char)ubrr;
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	UCSR0C= (1<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01);
}

which adds a DECLARATION before the invocation I then get:

		.././main.c: In function 'main':
D:\test\test\main.c(11,28): warning: integer overflow in expression [-Woverflow]

but I can "fix" that warning too by using:

#define FOSC 16000000UL
#define BAUD 9600UL

and then I get:

  90:	87 e6       	ldi	r24, 0x67	; 103
  92:	90 e0       	ldi	r25, 0x00	; 0
  94:	f2 df       	rcall	.-28     	; 0x7a <USART_Init>

0x0067 is 103. QED.

 

(but if this is avr-gcc have you looked at:  https://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html ?)

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

clawson wrote:
#define FOSC 16000000UL #define BAUD 9600UL
This solved the problem.. Thanks a lot 

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

#define FOSC 16000000
#define BAUD 9600
#define UBRR_VAL ((FOSC/(16 * BAUD)) -1 )

 

16*BAUD overflows an int, so take care of it somehow-

https://godbolt.org/z/G4E8MY

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

SufyanRaza26 wrote:

This solved the problem.. Thanks a lot 

As you will have seen the compiler did warn you that this was a problem:

		.././main.c: In function 'main':
D:\test\test\main.c(11,28): warning: integer overflow in expression [-Woverflow]

This proves (once again) that you should never ignore any warning in a build until you are totally sure it is benign and can be safely ignored (but in that case you should still do whatever is necessary to quell the warning as you don't want the next important warning hat crops up to be drowned in a lot of noise!).

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

At the risk of being called a pedant, I shall inject some pedantry:

 

On AVR the convention is to use F_CPU. FOSC is a PIC convention.

 

Usually I/we do the up-cast where we use it - thus:

#define F_CPU 16000000
#define BAUD 9600
#define UBRR_VAL ((F_CPU / (16UL * BAUD)) - 1)

 

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


N.Winterbottom wrote:
On AVR the convention is to use F_CPU.

 

There's a word for that that I can't recall -- if my neighborhood does something in a particular manner, then it must be the right way to do it regardless of the way the heathens outside my neighborhood do it.  [Is it "provincial"?]

 

-- I never realized that F_CPU was canonized.  References?  Please include just those that don't deal with a particular toolchain.

-- Do we know that OP is fact using the canonized toolchain?

-- Does the program run differently if the clock speed is called e.g. FROG?  Is this the best point to make to a beginning programmer?

 

From a recent AVR datasheet:

But that is after Microchip took over.  Let's go back and check...hmmm, you might be right.  In 2000, fck was the name:

 

 

2003 Mega8 looks like the 2000 '8535 -- fosc.

So does 2005-2008 Mega164.

 

 

 

.edit. Or did NW mean gcc for avr versus gcc for pic. Then it might we'll make sense to point that out. If op is using gcc.

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.

Last Edited: Wed. Aug 19, 2020 - 08:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If one uses the delay.h file, the delays expect F_CPU to be defined.

 

David

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

SufyanRaza26 wrote:

UBRR0H = (unsigned char)(ubrr>>8);
	UBRR0L = (unsigned char)ubrr;

Since C does not guarantee order of execution, you should not split 16 bit regs, instead just write the 16 bit value to the reg, the compiler knows how to do this correctly!

	UBRR0 = ubrr;

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

this is cut & paste from the datasheet for 328 2016 from Atmel (from what you said I had to check that microchip did't change the demo code)

 

#define FOSC 1843200 // Clock Speed

#define BAUD 9600

#define MYUBRR FOSC/16/BAUD-1

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

ki0bk wrote:
Since C does not guarantee order of execution, you should not split 16 bit regs,

Whoa.  Are you saying that two writes to volatile items can change order?  I didn't think so.

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.