USART not fast enough - F_CPU define problem?

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

Hello, I am trying to get USART working to communicate between my ATTiny828 (which is soldered on to a breakout board, no external crystal) and a PC running PuTTY in windows 10. However, on my oscilloscope I notice that when I send a command from Putty at the same baud rate as the microcontroller, the PC's output is very fast while the tiny's data rate doesn't change when I set the baud rate to 9600 or 2400. I assume my F_CPU define is being ignored somewhere... but even when I leave out delay.h the F_CPU still doesn't respond to my definition.

 

/*
 * MyATtiny828.cpp
 *
 * Created: 5/15/2019 9:33:57 AM
 * 
 */ 

#define F_CPU 20000000UL

#include <avr/io.h>
#include <util/delay.h>

void pin_init()
{
	DDRC = 0x01;	// data direction is out
	//PUEC = (0x01<<PUEC);	// pull up is enabled
	PORTC = 0x00;	// turn on or off PC0 (set to 1 for on)
}

void blink_LED()
{
	PINC = 0x01;	// toggle PC0. To toggle on, make sure the default is off (PORTC = 0x00)
	_delay_ms(10);
	PINC = 0x01;
}

void usart_init( unsigned int baud )
{
	/* Set baud rate */
	UBRRH = (unsigned char)(baud>>8);
	UBRRL = (unsigned char)baud;
	/* Enable receiver and transmitter */
	UCSRB = (1<<RXEN)|(1<<TXEN);
	/* Set frame format: 8 data bits, 1 stop bits */
	UCSRC = (0<<USBS)|(1<<UCSZ0)|(1<<UCSZ1);
}

void usart_transmit( unsigned char data )
{
	/* Wait for empty transmit buffer */
	while ( !( UCSRA & (1<<UDRE)) )
	;
	/* Put data into buffer, sends the data */
	UDR = data;
}

unsigned char usart_receive( void )
{
	/* Wait for data to be received */
	// Note that this will BLOCK everything else! 
	while ( !(UCSRA & (1<<RXC)) )
	;
	/* Get and return received data from buffer */
	return UDR;
}


int main(void)
{
	
	pin_init();
	usart_init(2400);
	
	char important_message = 0;
	char received_message = 0;
	char secret_key = 2;
	
    while (1) 
    {

		usart_transmit(important_message);

		if (important_message <= 255){
			important_message++;
		}
		else if (important_message > 255){
			important_message = 0;
		}
	
		//received_message = usart_receive();
		//if (received_message == secret_key){
			//blink_LED();
		//}
		
		
		
    }
}

 

What am I doing wrong? The tiny *is* sending the data I tell it to, I can see on the oscilloscope a "0x01" or "0xFF" get sent, but I think it is far too slow for the PC's serial input to pick up on and that's why I don't receive the numbers.

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


UBBR value is from formula or table:  see below

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
https://www.onegold.com/join/7134f67c2b814c5ca8144a458eccfd61

 

 

 

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

Ah now I see, I was accidentally putting in "9600" when I should have put in 6 for UBRR (6 is 9600 baud at 1MHz). Thank you! It works now.

 

However, i still seem to have problems with changing my frequency to anything other than 1MHz, even when I eliminate the delay.h library and define F_CPU myself. At least now I can send serial data for printf debugging.

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

Realize that F_CPU does not tell your cpu how fast to run, but tells the _delay macros how fast your cpu is running.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

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

It sounds like you are using the internal 8 MHz clock

and have the CKDIV8 fuse programmed (which divides

the clock by 8).  You will have to change the fuses to

use a 20 MHz crystal resonator, and can also reset the

CKDIV8 fuse so it doesn't slow the clock.

 

If you are fine with running at 8 MHz, you don't need

to modify the fuses.  Instead you can just change the

clock prescaler so it runs full speed.  Look at the

CLKPR register - the CLKPS bits determine the divisor.

 

To help prevent unwanted changes to CLKPR, you need

to write a specific value to the CCP register and then

quickly write the CLKPS bits you want.

 

--Mike

 

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

avr-mike wrote:

If you are fine with running at 8 MHz, you don't need

to modify the fuses.  Instead you can just change the

clock prescaler so it runs full speed.  Look at the

CLKPR register - the CLKPS bits determine the divisor.

True, but if the OP does that, he will need different UBBR value as the clock is now 8x faster!

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
https://www.onegold.com/join/7134f67c2b814c5ca8144a458eccfd61

 

 

 

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

Please check once again what "F_CPU" is.

 

F_CPU does not set the clock.

Show the compiler in F_CPU the value you promise to set in the fuse.

 

Did you fulfill that promise?

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

Erknec wrote:
I assume my F_CPU define is being ignored somewhere...
As others have said this shows a fundamental misunderstanding. You don't tell the AVR how fast to go by editing that line. That line is to tell calculations in your C code how fast you have arranged for the CPU to run at - you do that by things such as CKSEL fuse settins and attaching crystals/oscillators of the right speed. So if you set CKSEL to "use external crystal" then you add a 2.732MHz crystal the CPU will run at 2.732MHz. Then you edit your C code to "#define F_CPU 2732000UL" to let anything making clock based calculations know. If you later unplug that crystal and use a 5.4412MHz crystal then the AVR runs at 5.4412MHz so now you go back to your C source code and edit the F_CPU line to match so any timing calculations are no longer done on the basis of 2.732MHz but now based on 5.4412MHz instead.

 

(2.732MHz and 5.4412 MHz crystals don't really exist ;-)