tags:

views:

317

answers:

6

I am trying to organise my UART library and prettify it a little bit by adding some #define s so I can customize it later without having to dig deeply into the code, but I can't seem to get the following bit of code working:

#define FOSC        8000000
#define BAUDRATE    9600
#define BRGVAL      (FOSC/2)/(16*BAUDRATE)-1

void uart_init(){
   U1BRG = BRGVAL;
}

After the calculation BRGVAL becomes 25.0416667, and because it is not an integer I get the following warning for it when I assign that into U1BRG:

UART.c: In function 'uart_init':

UART.c:24: warning: integer overflow in expression

...and the code simply does not work on target hardware. (If I manually put in U1BRG = 25 it works like a charm though)

Is there any way to typecast that constant into an integer to make the compiler happy?

Many Thanks, Hamza.

A: 

I would probably use this:

#define BRGVAL      ((int)(FOSC/2)/(16*BAUDRATE)-1)
Segfault
Hello Segfault, sadly that does not work.
Hamza
+3  A: 

What is sizeof(int) on this platform?

John Zwinck
Hello John, it is 16bits.
Hamza
A: 

You have failed to point this out, What's the data type for U1BRG? If it's an int, cast it like as shown

#define FOSC        8000000
#define BAUDRATE    9600
#define BRGVAL      ((long)(FOSC/2)/(16*BAUDRATE)-1)

void uart_init(){
   U1BRG = BRGVAL;
}

Edit: Amended this to take into consideration of Adam Liss's comment that an unsigned int is too small to hold the result of the macro, I have changed it to make it a long...Thanks Adam for the headsup...

Hope this helps, Best regards, Tom.

tommieb75
Hello Tom, it is of type 'unsigned int', I have tried doing an (int) cast but the same error still pops up...
Hamza
FOSC/2 is still too large to fit into an int.
Adam Liss
you still get overflow with 16*BAUDRATE, which won't fit in an int.
Philip Potter
A: 

It's not clear from your example whether U1BRG is a global variable or a #define'ed constant. In any case, simply casting to an integer should work:

 U1BRG = (int)BRGVAL;
JSBangs
Hello Js, U1BRG is defined in another heaser file as an unsigned int, I have tried doing an (int) cast but the same error still pops up
Hamza
+12  A: 

Integer overflow means that you have exceeded the upper limit of an int value, which is likely to be 32767 if you are getting this error. It has nothing to do with floating point; the operations you have specified are in fact integer math operations, so the fractional part of the division is discarded anyway.

Try something like this:

#define FOSC        8000000L
#define BAUDRATE    9600L
#define BRGVAL      ((unsigned int)((FOSC/2)/(16*BAUDRATE)-1))

void uart_init(){
   U1BRG = BRGVAL;
}

The L suffix turns these constants into long type instead of int type. The (unsigned int) cast converts to U1BRG's type, and lets the compiler know that you understand that the long value will fit into an unsigned int and thus hide any warnings it may throw at you.

Normally, it's bad practice to silence compiler warnings, but in this case, it's clear that although you need long to store intermediate values in the calculation, the final result will fit into an unsigned int.

Philip Potter
Hi Phillip,Thanks for the suggestion, the following bit of code seems to work for me now #define FOSC 8000000L #define BAUDRATE 9600L #define BRGVAL (FOSC/2)/(16*BAUDRATE)-1For some strange reason If I add that (int) cast to the BRGVAL, I get a value of 65536 though (the limit of int?), not sure why this happens.Without the cast it seems to work though...
Hamza
@Adam Either BAUDRATE must be long, or the magic number 16 must be long, because otherwise 16*BAUDRATE will overflow.
Philip Potter
@Hamza what code are you using to add the cast? All of the parenthesis are necessary for the cast. If you are doing (int)(FOSC/2)/(16*BAUDRATE)-1 or (int)BRGVAL then you are not casting the whole expression but rather you are only casting (FOSC/2) to int, which will overflow and become some small number. You then divide this small number by (16*BAUDRATE), a big number, which gives the result 0. You then subtract 1, making -1. Assign -1 to an unsigned int and you wrap around and get 65535. In short, if you do a cast, add parenthesis around the whole expression you are casting.
Philip Potter
This is silly: I had the parantheses in the right place, but it seems like the compiler got confused with the previous build files, a simple make clean and a recompile fixed it. Thank you very much for your help and clear explanations...
Hamza
@Philip: Yes, of course. +1 for your thorough explanation, and I wish I could give you another +1 for enabling compiler warnings!
Adam Liss
+6  A: 

I like Philip's answer, but I think a better solution is to reduce the formula and change your macro to:

#define BRGVAL (FOSC/32/BAUDRATE-1)

In doing so, you eliminate the cast so the compiler can continue to warn you if you choose a low baud rate that would result in a divider value too large for a 16-bit int.

tomlogic
Hey Tom, thanks for your suggestion. It works like a charm!
Hamza