XDIV and UART problem

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

Atmega128
Crystal 16MHz
Avrstudio + Winavr

When using 16 MHz clock, I send bytes to PC succesfully.
But as soon as I divide clock in XDIV I get all zeroes in the terminal.
What is wrong?

This works:

#define FOSC    16000000UL   // Clock Speed
#define BAUD    4800UL
#define MYUBRR  (FOSC/(16*BAUD))-1  
#define MYUBRRH MYUBRR/256        
#define MYUBRRL MYUBRR%256        

//////////////////////////////////////////////////
void USART_Init(void)
{
  /* Set baud rate */
  UBRR0H = MYUBRRH;
  UBRR0L = MYUBRRL;
  /* Enable receiver and transmitter */
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  /* Set frame format: 8data, 1stop bit */
  UCSR0C = (1<<UCSZ00)|(1<<UCSZ01);
}

//////////////////////////////////////////////////
void USART_Transmit(unsigned char data ) 
{
  /* Wait for empty transmit buffer */
  while ( !( UCSR0A & (1<<UDRE0)) )
  ;
  /* Put data into buffer, sends the data */
  UDR0 = data;
}

/********** MAIN ********************************/
int main(void)
{
  USART_Init();

  for(;;)
  {
    USART_Transmit('A');
    USART_Transmit('B');
    USART_Transmit('C');
    USART_Transmit('D');

  }//for
}//main 
/********** END MAIN ****************************/

And this does not:

#define FOSC    1000000UL   // Clock Speed
#define BAUD    4800UL
#define MYUBRR  (FOSC/(16*BAUD))-1  
#define MYUBRRH MYUBRR/256        
#define MYUBRRL MYUBRR%256        

//////////////////////////////////////////////
void USART_Init(void)
{
  /* Set baud rate */
  UBRR0H = MYUBRRH;
  UBRR0L = MYUBRRL;
  /* Enable receiver and transmitter */
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  /* Set frame format: 8data, 1stop bit */
  UCSR0C = (1<<UCSZ00)|(1<<UCSZ01);
}

///////////////////////////////////////////////
void USART_Transmit(unsigned char data ) 
{
  /* Wait for empty transmit buffer */
  while ( !( UCSR0A & (1<<UDRE0)) )
  ;
  /* Put data into buffer, sends the data */
  UDR0 = data;
}

/********** MAIN ********************************/
int main(void)
{

//divide clock by 16
    clrb(XDIV,XDIVEN);
    XDIV = 113;         //129-16
    setb(XDIV,XDIVEN);
    
  USART_Init();

  for(;;)
  {
    USART_Transmit('A');
    USART_Transmit('B');
    USART_Transmit('C');
    USART_Transmit('D');
  
  }//for
}//main 
/********** END MAIN ****************************/
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Visovian wrote:
But as soon as I divide clock in XDIV I get all zeroes in the terminal.
I would assume that the divided clock feeds everything else, including the USART. If that is true, you'll need to modify UBRR to keep the baud rate the same.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

I'd look at TXD on the scope. Is the error one of magnitude (close to x16) or just a minor inaccuracy (like out by a few %)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    clrb(XDIV,XDIVEN);
    XDIV = 113;         //129-16
    setb(XDIV,XDIVEN);

I'm not sure if this is correct. According to the datasheet:

Quote:
When XDIVEN is written to one, the value written simultaneously into XDIV6..XDIV0 is taken as the division factor.

So you might try:

    clrb(XDIV,XDIVEN);
    XDIV = 113 | (1<<XDIVEN);

Regards,
Steve A.

The Board helps those that help themselves.

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

Thank you all for your answers.
I used the simulator and found it.
The fault was in the calculation of baudrate.
I did not expect it, because, as I wrote above, it functioned well with FOSC 16 MHz.
So I supposed, the math was all right.

Old code

#define FOSC    1000000UL   // Clock Speed
#define BAUD    4800UL
#define MYUBRR  (FOSC/(16*BAUD))-1  //=12   
#define MYUBRRH MYUBRR/256          //=13
#define MYUBRRL MYUBRR%256          //=12

New code

#define FOSC    1000000UL   // Clock Speed
#define BAUD    4800UL
#define MYUBRR  (FOSC/(16*BAUD))-1  //=12 
#define MYUBRRH (MYUBRR)>>(8)       //=0 
#define MYUBRRL (MYUBRR)& (0x00ff)  //=12      

It is strange for me, why division /256 does not give the high byte. When I use it with variable, it makes no troubles.
There are some mysteries in #define.
Anyway, thanks again for your help.

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

Why not just use the fixed values that Atmel already calculated for you in the AVR datasheet?

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

The reason for the wrong value is lack of parentheses:

#define MYUBRR  (FOSC/(16*BAUD))-1  //=12   
#define MYUBRRH MYUBRR/256          //=13 

expands to (FOSC/(16*BAUD))-1/256
or 13 - 0.0039

You can never have too many parentheses

David.

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

The error is happening because the macro expansion of:

MYUBRR/256

is:

(1000000UL/(16*4800UL))-1/256

And because of order of operations, it will be worked out in 2 chunks:
(1) 1000000/(16*4800)
(2) 1/256
(3) (1) - (2)

Obviously, (2) works out to 0 in integer representation, so the overall result is simply (1000000/(16*4800)) = 13

You could fix it by adding an extra layer of parentheses around the definition of MYUBRR.

[edit]Beaten to it![/edit]

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

Quote:
The reason for the wrong value is lack of parentheses:

Which is one of the reasons that I rarely use macros outside of simple constants.

Regards,
Steve A.

The Board helps those that help themselves.

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

Now all is completely clear.
Steve is right, man should avoid complicated defines, especially when he becomes sclerotic as I do.
Thanks again

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

Koshchi wrote:
Quote:
The reason for the wrong value is lack of parentheses:

Which is one of the reasons that I rarely use macros outside of simple constants.

Surely the whole point of using a macro is to make your source code look clear AND to perform hideous constructs.

1. Parenthesize EVERY parameter when used in the expansion.
2. Document your macro especially for side-effects
3. Do not use arguments that have side-effects e.g. david++
4. Having read the documentation and thought carefully, use david++ only if permitted.

You write the expression once. Use at leisure.

David.