[TUT] [SOFT] Using the USART - Serial communications

Last post
490 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

For an updated version of this tutorial in PDF format, please see this page of my website.

Using the USART with AVR-GCC

Freaks,

I've had this three-quarters finished and sitting on my hard drive since mid-last year, so I decided to finish it and post here for the benefit of others. I'm the first to admit it's not very clearly written, so I may re-write it in the future. Comment away.

This tutorial will focus on setting up the serial USART on the AVR platform. Although other hardware AVR interfaces (eg, USI) can be configured for limited RS-232 serial transmission and reception such alternatives will not be covered.

What is the USART?

The vast majority of devices in the current AVR family lineup contain a USART hardware subsystem. The USART hardware allows the AVR to transmit and receive data serially to and from other devices - such as a computer or another AVR.

The USART transmission system differs to most other digital busses in that it does not utilize a separate pin for the serial clock. An agreed clock rate is preset into both devices, which is then used to sample the Rx/Tx lines at regular intervals. Because of this, the USART requires only three wires for bi-directional communication (Rx, Tx and GND).

The RS-232 Specification

The serial USART is frequently referred to as RS-232, which is a reference to the RS-232 specification which mandates the logic levels and control signals. While the AVR's normal logic levels are about 3-5V, RS-232 communication uses a low of +3V to +25V for a digital '0', and -3V to -25V for a digital '1'.

If the two USART devices are running at AVR logic levels, the Tx and Rx pins can be connected together directly. If the devices are using RS-232 spec. voltages, a level converter is needed.

This tutorial will assume the user is attempting to interface with a computer RS-232 port, which uses the proper RS-232 specification logic levels.

First things first - Setting up the Hardware

To connect your AVR to a computer via the USART port, you will need to add a level converter to your existing circuit. The most common/popular serial level converter is the Maxim MAX232 (datasheet avaliable here). This small and relatively inexpensive IC will convert your AVR's 5V logic levels to 10V RS-232 and vice versa.

Before you can hook up your MAX232, you need to first identify which pins of your AVR are responsible for serial communication. Looking in your AVR's datasheet, you should be able to identify the two serial port pins (named as alternative pin functions TX and RX).

You should wire up your MAX232 to reflect the schematic here. This will enable your AVR's USART hardware to interface with the computer's USART hardware.

Deciding on your AVR's system clock frequency

As mentioned above, the USART does not use an external clock. To allow the two interfaced devices to communicate together, you need to decide on a baud rate for communication. Also due to the timing-critical nature of the USART, your system's clock should be stable and of a known frequency. The AVR's system clock frequency is very important. The USART clock is derived from the system clock, and it is used to sample the Rx line and set the Tx line at precise intervals in order to maintain the communication.

If the system clock cannot be precisely divided down to a "magic" frequency for perfect communications, it will have a percentage error (where a byte fails to be read or written inside designated time frame). System clocks for perfect USART communications should be multiples of 1.8432MHz which when used will give a 0.00% error.

Other frequencies for the main AVR clock can be used, but as the frequency drifts from the "perfect" multiples of 1.8432MHz, the greater the percentage error will be (and thus the less reliable the serial communication will be). It is generally accepted that error percentages of less than +/- 2% are acceptable.

Looking in your AVR's datasheet in the USART section you should see a table of common baud rates, system clocks and error percentages. You should find a combination which suits your project's constraints and has the lowest possible error percentage.

I will be basing the rest of this tutorial on an example setup; a MEGA16 running at 7.3728MHz and a baud rate of 9600bps (bits per second). This combination, because it uses a system clock which is a multiple of the magic 1.8432MHz, has an error percentage of 0.00%).

Initializing the USART

Now you should have selected a baud rate, system clock and have your AVR set up with a RS-232 level converter - you're all set to go! All you need is the firmware to drive it.

First off, you need to enable both the USART's transmission and reception circuitry. For the MEGA16, these are bits named RXEN and TXEN, and they are located in the control register UCSRB. When set, these two bits turn on the serial buffers to allow for serial communications:

#include 

int main (void)
{
	UCSRB = (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
}

Next, we need to tell the AVR what type of serial format we're using. The USART can receive bytes of various sizes (from 5 to 9 bits) but for simplicity's sake we'll use the standard 8-bits (normal byte size for the AVR). Looking again at the MEGA16 datasheet, we can see that the bits responsible for the serial format are named UCSZ0 to UCSZ2, and are located in the USART control register C named UCSRC.

The datasheet very handily gives us a table showing which bits to set for each format. The standard 8-bit format is chosen by setting the UCSZ0 and UCSZ1 bits. Before we write to the UCSRC register however, note a curious peculiarity in our chosen AVR, the MEGA16. To save on register addresses, the UCSRC and UBRRH registers (the latter being explained later in this text) share the same address. To select between the two, you must also write the URSEL bit when writing to UCSRC:

#include 

int main (void)
{
	UCSRB = (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry
	UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes - URSEL bit set to select the UCRSC register
}

The URSEL bit does not exist in all AVR models; check your chosen AVR's datasheet.

There, we're almost done setting up the USART! The last thing to set for basic serial communications is the baud rate register. This register sets the clock divider for the USART which is used as a timebase to sample the incoming data at the correct frequency. It also gives the timebase for sending data, so it's vital for RS-232 serial communications.

The baud rate register is 16-bit, split into two 8-bit registers as is the case with all 16-bit registers in the AVR device family. To set our baud rate prescaler value, we first need to determine it. Note that the baud rate register value is NOT the same as the baud rate you wish to use - this is a common point of failure amongst those new to the serial subsystem. Instead, the value must be derived from the following formula:

    BaudValue = (((F_CPU / (USART_BAUDRATE * 16))) - 1)

Where F_CPU is your AVR's system clock frequency (in Hz), and USART_BAUDRATE is the desired communication baud rate.

Given my example project using a system clock of 7372800Hz and a baud rate of 9600, our formula gives:

    BaudValue = (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) BaudValue = (7372800 / (9600 * 16) - 1)
    BaudValue = (7372800 / 153600 - 1)
    BaudValue = (48 - 1)
    BaudValue = 47

To make our life easier, we can turn this formula into a set of handy macros. F_CPU is automatically defined in AVR-GCC via your makefile, so all that is needed is the baud rate:

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

This avoids "magic numbers" (unexplained constants) in our source code, and makes changing the baud rate later on very easy - just change the BAUD_RATE macro value. Now, we need to load this into the baud rate registers, named UBRRH (for the high byte) and UBRRL (for the low byte). This is simple via a simple bitshift to grab the upper eight bits of the BAUD_PRESCALE constant:

UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register

Now we're ready to rock and roll!

Sending and receiving data

Once initialized, we're ready to send and receive data. We do this by the special register named UDR - short for "USART I/O Data Register". This is special for two reasons; it behaves differently when it is read or written to, and it is double buffered.

By assigning a byte to the UDR register, that byte is sent out via the AVR's Tx line. This process is automatic - just assign a value and wait for the transmission to complete. We can tell when the transmission is complete by looking at the transmission completion flag inside the USART control registers.

On the MEGA16, the Transmission Complete flag is located in the control register UCSRA, and it is named TXC. Using this information we can construct a simple wait loop which will prevent data from being written to the UDR register until the current transmission is complete:

UDR = ByteToSend; // Send out the byte value in the variable "ByteToSend"
while ((UCSRA & (1 << TXC)) == 0) {}; // Do nothing until transmission complete flag set

However this is non-optimal. We spend time waiting after each byte which could be better spent performing other tasks - better to check before a transmission to see if the UDR register is ready for data. We can do this by checking the USART Data Register Empty flag instead (called UDRE), also located in the UCSRA control register of the MEGA16:

while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ByteToSend; // Send out the byte value in the variable "ByteToSend"

This is much better, as now time is only wasted before a transmission if the UDR register is full. After a transmission we can immediately continue program execution while the UDR byte is sent, saving time.

Now we can move on to receiving data. As mentioned before, the UDR register behaves differently between read and write operations. If data is written to it it is sent out via the AVR's Tx pin, however when data is received by the RX pin of the AVR, it may be read out of the UDR register. Before reading the UDR register however, we need to check to see if we have received a byte.

To do this, we can check the USART Receive Complete (RXC) flag to see if it is set. Again, this is located in the UCSRA control register of the MEGA16:

while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ReceivedByte"

Putting it all together

Right! Now it's time to put everything together! Let's make a simple program that echoes the received characters back to the computer. First, the basic program structure:

#include 

int main (void)
{

}

Next, our USART initializing sequence:

#include 

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

int main (void)
{
	UCSRB = (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry
	UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes

	UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
	UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
}

Now, an infinite loop to contain our echo code:

#include 

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

int main (void)
{
	UCSRB = (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry
	UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes

	UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
	UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register

	for (;;) // Loop forever
	{

	}
}

And some echo code to complete our example. We'll add in a local variable "ReceivedByte", which will always hold the last received character from the computer:

#include 

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

int main (void)
{
	char ReceivedByte;

	UCSRB = (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry
	UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes

	UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
	UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register

	for (;;) // Loop forever
	{
		while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
		ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"

		while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
		UDR = ReceivedByte; // Echo back the received byte back to the computer
	}	
}

And voila, we have a working serial example! Connect to this project via a serial terminal on your computer, using 8-bit, no parity 9600 baud communication settings and it will echo back anything you send to it.

Potential Pitfalls

There are several "gotchas" when dealing with the USART. First, make sure your AVR is running of a reliable, known clock source with a low error percentage at your chosen baud rate. New AVRs default to their internal oscillators until their fuses are changed. The internal RC oscillator is of too low a tolerance for use with the USART without external calibration.

Check your datasheet to check for the locations of the different flags. Different AVRs have the control flags located in different control registers (UCSRA, UCSRB and UCSRC).

Make sure your computer terminal is connected at the exact settings your AVR application is designed for. Different settings will cause corrupt data.

Cross your Rx and Tx wires. Your PC's Rx line should be connected to your AVR's Tx line and vice-versa. This is because the Rx/Tx lines are labeled relative to the device they are marked on.

Some AVRs do not have the URSEL bit to differentiate between the UCSRC and UBRRH registers - check your datasheet.

Advanced serial communication

A more advanced method of serial communication involves the use of the USART interrupts and is not covered here. I may cover it in a later tutorial if so desired.

For an updated version of this tutorial in PDF format, please see this page of my website.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I read it rather quickly, and it seems like a good introduction to serial comms! Check out this one though:

Quote:
RS-232 communication uses a low of +3V to +25V for a digital '1', and -3V to -25V for a digital '0'.
+3V to +25V is used for signalling LOW, shouldn't that be digital '0'....

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

Quote:
Check out this one though:

Fixed, thanks.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Dunno if it's worth mentioning, but a newbie should probably be encouraged to look at the power-on default settings of the USART control registers as noted in the datasheet. (And all the registers they work with for that matter.)

For typical 8N1 asynchronous communications, UCSRC can usually be totally ignored (at least, in every AVR I've ever used) because the appropriate bits are automatically preset whenever the chip powers up or comes out of reset.

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

hey which software do you use to recieve the data on the comp...hmm and ya UCSRC and UBRR hav the same memory addr..the first bit wil decide which one is to be written ...i tried simulating it in avr studio..its not working ...any suggestions...??

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

use windows terminal (start-programs-accessories-communications-hyper terminal

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

Quote:
BaudValue = (((F_CPU / (USART_BAUDRATE * 16))) - 1)

Where F_CPU is your AVR's system clock frequency (in Hz), and USART_BAUDRATE is the desired communication baud rate.

Given my example project using a system clock of 7372800Hz and a baud rate of 9600, our formula gives:

BaudValue = (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
BaudValue = (7372800 / (9600 * 16) - 1)
BaudValue = (7372800 / 153600 - 1)
BaudValue = (48 - 1)
BaudValue = 47

The only thing I would like to add is that, unless the microcontroller XTAL1, XTAL2 frequency is one of those "Magic Numbers", the final BaudValue will be a mixed number and be rounded down as, the final value of BaudValue must be an integer - the remainder will be lost.

If an XTAL value is used that produces a value of say, 48.1, the error produced by the trunkation of the fractional part, I.E. 0.1, will produce a Baud rate error just slightly greater then 2%. This error may well work without USART timing issues.

But, an XTAL frequency producing a final BaudValue of say, 48.2 or greater, will produce a BAUD rate timing error of more then 4%, which is outside of the +/-3% error margin specified by Atmel.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

:arrow:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL)))

should actually be

#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))))

took me a few to figure out it was missing a closing )

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

Thanks Night'. Actually, it should be:

#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

As previously stated in the tutorial, I just missed the last part when I copy-pasted it. Fixed now, I've updated the PDF too.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

And if you add the half if the divisor, then the formula will not only truncate , but round up or down

#define BAUD_PRESCALE ((((F_CPU+USART_BAUDRATE * 8UL) / (USART_BAUDRATE * 16UL))) - 1)

Weiterstadt, Germany

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

Hi!

I'm not sure if I should post this here but I have a question regarding those capacitors around max232. Do their values have anything to do with the baudrate you are using or are always those values?

If they are a function of the baudrate what is the equation to calculate their capacity?

Thanks a lot.

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

the capacity is given in the datasheet. it has absolutely nothing to do with BAUD rates nor anything with the serial data...
It's to create 10V for PC USART side and nothing more. read the MAX232 datasheet man!

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

After compiling and writing to the ATmega16, and switching the serial cable to the "RS232 SPARE" connection, I set up a connection in Hyperterminal;

Baud 9600
8 bits, no parity, 2 stop bits

However, when I type text in the terminal, the echo is only exotic ASCII characters, not the a-z 0-9 I'm typing... I've tried 1 stop bit, and also 1.5 - same thing. Any clues as to why this is happening?
Btw, great tutorial, Dean! :)

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

joakimk wrote:
Any clues as to why this is happening?

What is the AVR clock source? The fact that you get some response suggests you are close so maybe you're using the internal oscillator and it needs calibrating?

Cliff

 

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

Quote:
...maybe you're using the internal oscillator and it needs calibrating?

Yes, I am using the internal oscillator;
Int. RC Osc. 1 MHz; Start-tp time: 6CK + 4ms ...

I tried modifying Dean's C code to run at 1MHz like this:

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((1000000 / (USART_BAUDRATE * 16UL))) - 1)

How does one calibrate? Am I calculating the BAUD correctly? I couldn't get the F_CPU macro working, so I hard-coded 1MHz in the above formula...

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

Try setting your terminal program for one stop bit, instead of two - that's what my code is expecting.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I am working 2 projects at the same time, an AVR (presently in an 8535, but that will probably change) and Windows desktop using wxWidgets. The projects talk to each other via RS-232C.

The AVR info in this forum looks very useful. If someone needs help at the other end of the cable, drop me a personal msg. and I will see if anything I have is applicable. It took me a while to get my own desktop program talking correctly on COM1.

I use an SDK500 for my prototyping and the "Spare Serial" port works with a standard cable directly to a desktop/laptop without 'twisting' it. You just have to remember to connect the 2 pins near the switches to D0 and D1. If you need to 'twist' the connections, there is a good place to do it for RX and TX. I use a 4.000 MHZ crystal, so I have to choose my baud rate settings carefully.

Another suggestion relative to serial ports is that it is quite useful to output debug statements to the serial port, but when you declare strings in printf statements, they fill up your data space. You can easily put them into EEPROM with a few simple functions.

I also have some AVR software for LCD displays and debouncing matrices of switches, such as keypads, that utilize timer interrupts to work in the background. PM me if this is something you are interested in.

The only thing more dangerous than a software engineer with a soldering iron is a hardware engineer with a compiler.

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

joakimk, 9600 baud with 1MHz clock is not going to work well (-7% error even if the 1MHz was exact). Try 4800 baud or use a higher frequency internal RC oscillator setting. You can also try the U2X bit in the UCSRA register (but reception is more sensitve to errors when using it so this might be less useful when running from the internal oscillator). Note that Dean writes above:

Quote:
Looking in your AVR's datasheet in the USART section you should see a table of common baud rates, system clocks and error percentages. You should find a combination which suits your project's constraints and has the lowest possible error percentage.
/Lars

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

Hi all!

Beeing a newbie to avr's, I've worked a while with serial data-transmission and the dmx-standard (rs 485) on fpga's. Now I'm trying to get it into an AVR..

Will the UDR-register will be empty after one transmission?
Is the data in UDR only being transmitted once?
Is it possible to assign a vector to UDR, or is the UDR a one-byte-protocol?

What I want to do is to send 512bytes in a everlasting
loop (of cource with the possibility to manipulate the register).

Thnx,
- Bernt.

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

I can't believe the amount of material I've learned in the last few days of experimenting with these AVRs. Thank you Dean for such a detailed tutorial on communicating over a serial port.

I received two MAX233ACPP chips a few years ago but I had no idea how to use them. Using your tutorial, modifying it for both the MAX233 and ATtiny2313, I've managed to implement your echo program running at 1200 baud using the 2313 internal oscillator.

Thanks!

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

Great svenasse! I'm glad my efforts weren't in vain. Good to also know that my code works - I wrote it "blind", without testing it thoroughly.

Hope you read my other tutorials also, as they cover what I believe to be interesting topics.

Cheers!
- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I couldn't understand why I was able to communicate with my chip at 1200 baud when it doesn't even show up on the list in the manual. It wasn't until I started to review the fuse did I realise the clock was being divided by 8 (9600/8 = 1200). Once I unchecked that option I was able to get to 9600 baud and then 38400 baud all while using the internal oscillator at 8MHz.

One point which wasn't in your tutorial was to disable hardware flow control since the DTR/RTS pins are not used. My eyes kept missing that option in Hyperterm until I had to play with the baud rate on the original code.

I will certainly be going through all the tutorials here... this site is absolutely awesome! I applied the tricks and tips in your "Setting up a WinAVR Project" and it shaved off more bytes off the compiled code.

Thanks,
Seamus

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

Very nice tutorial! This was my first AVR-GCC trial and it went pretty smoothly. Would love to know how to get this done with interrupts, I could really use that for my upcoming project! Keep up the good work!

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

thnx dean. i was really looking for this for a long. nice work

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

i copy n paste your code in avr studio with WINavr installed and set F_CPU+ 8000000 because i m using 8 MHz crystal oscillator. The code compiled successfully

Quote:

Build started 2.4.2007 at 17:15:36
avr-gcc.exe -mmcu=atmega8535 -Wall -gdwarf-2 -O0 -MD -MP -MT testgcc.o -MF dep/testgcc.o.d -c ../testgcc.c
avr-gcc.exe -mmcu=atmega8535 testgcc.o -o testgcc.elf
avr-objcopy -O ihex -R .eeprom testgcc.elf testgcc.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex testgcc.elf testgcc.eep
d:\WinAVR\bin\avr-objcopy.exe: there are no sections to be copied!
d:\WinAVR\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
make: *** [testgcc.eep] Error 1
Build succeeded with 0 Warnings...

But then when i execute this code i got a runtime error and the avr studio gets terminated. how can i resolve this problem???

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

Sounds like you have an out of date Studio then - your problem will almost certainly be resolved when you upgrade to 4.13.528 which IS compatible with the output files from WinAVR20070122

 

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

thnx clawson thnx very much my prob is solved u were correct

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

I am using a atmega8535 and the echo is not correct. For example, an 'm' returns a '[' every time. I measured the baud rate on the scope and it is perfect. The signal seems to be inverted between the Tx and Rx...Any ideas folks???

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

Are you using a MAX-232 level conversion chip? Without one the signal will be inverted, but also far too low for correct communication with true RS232 voltage devices. Not to mention that the computer's ~10V signal will destroy the AVR...

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

'm' = 0x6D = b01101101
'[' = 0x5B = b01011011

So it isn't inverted signals.

I usually see something like this with mismatched baudrates. Are you certain about the PC COM port baudrate? You need to check in the device manager to be sure.

Smiley

FREE TUTORIAL: 'Quick Start Guide for Using the WinAVR C Compiler with ATMEL's AVR Butterfly' AVAILABLE AT: http://www.smileymicros.com

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

Thanks Dean and Joe,
I am using a board we had lying around and I assumed the level conversion hardware was inplace. What is that they say about assumptions? I was wrong and I have a MAX232 coming so I am sure it will work fine. Thanks for the turorial and the help...

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

hey freaks !

i get some errors when trying to compile my program.

this is the way the program starts:

#include
#include
#include
#include
#include

though, i get the message:

can't open #include file or
can't open #include file
end so on...
my program doesn't work from the start...and i can't even debug the rest of it..
please help!

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

IF YOU USE WINAVR:
Did you use the default WinAVR installation directories? If not you have to modify the makefile so that the includes can be found. It is easier to uninstall WinAVR then reinstall it allowing the default path.

Smiley

FREE TUTORIAL: 'Quick Start Guide for Using the WinAVR C Compiler with ATMEL's AVR Butterfly' AVAILABLE AT: http://www.smileymicros.com

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

well this time I will try the avr studio compiler. but first I need to understand some things like what is this makefile. I am totally new to these compilers.
thank you for such a quick answer.

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

Hi all, i am using the GCC instead of winavr,
it comes out the error of define F_CPU..how do i know what is the value ? or how can i define it ?
i am using Atmega8515L ! thks

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

GCC *is* WinAVR, or specifically the former is a component of the latter (which is just a package of AVR tools).

You should define F_CPU in your makefile, and pass it along to each C file that is compiled via the -D option. That's how the WinAVR makefile template works, as it gives a common place to set the value for all C files in a project.

As an alternative, you can just #define it yourself at the top of the C files which use F_CPU.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Hi, I pretty much don't know anything, all i did so far was blink some LEDs and push some switches. This tutorial seems interesting. I'm using stk500, atmega16L, with avr studio. My questions are:

Do i need the max232 ship separately from the stk500? On the stk500 i can see max2c2.
Do i need to set anything up on the stk500?
How can i make my atmega16L run at 7.3728MHz, or any other frequency that will work for baud rate ? From the data sheet i read that the default is 1.0MHz.

Please explain in detail.

Thanks in advance.

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

The STK500 is a great platform to experiment with - you'd be hard pressed to manage to do something irreversable with it (with the exception of actually blowing something up!).

Yes, the SKT500 has a MAX232 on board already, but it's used for the "control" section of the board (for programming and such). Thankfully the MAX232 is dual channel in both directions, and so the designers have linked the second channel with the second serial connector (named "RS-232 Spare" on the board).

Setup is easy. If you look near the LEDs on the STK500, you'll notice a small two pin connector also named "RS-232 Spare". You need to use one of the STK500's two-wire jumpers to bridge those two pins to the correct pins for TX/RX on the port headers.

I *think* the correct pins are PD0/PD1 for your AVR, but do check the datasheet. Just connect your AVR's Tx and Rx to the Tx/Rx pins of that small header and it'll do the level conversions for you.

To communicate with your AVR once it's programmed, you'll need to swap over your serial connector from the "RS232 Control" socket to the "RS232 Spare".

As for running the AVR at a different clock rate, that's easy as well. The newer AVRs come running at a clock rate of about 1Mhz, via the onboard RC oscillator. However, you can change this to use an external __*CLOCK*__ (not crystal!) via the "fuses" tab in your programming window. Set the clock to external, any starup time.

Next, from the "board" tab of the STK500 programming screen, there should be a box for setting the clock speed of the STK500's target clock. Change that to the 3.XXX MHz one (it's half your wanted 7.3XXX MHz, but will work fine if you adjust your F_CPU value in your code).

Once you set the AVR to use the external clock, and have set the STK500 to give a nice magic frequency, the last thing to do is to set the STK500's jumpers to route the clock signal to the XTAL pins of your AVR. I'm not at home at the moment so I can't help you with that, but the STK500 entry in the Tools manual section of the help menu should give the details -- and if memory serves it's also listed on the underside of the STK500 board as well (OSC jumper I think).

Hope that helps!

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Thanks :)
I got it to work.
Great tutorial, great help

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

Thank You for the great Tutorial and the follow up replies.

It made my first venture into the serial world painless.

I'm not a cartoon character but I play one in real life.

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

Great tutorial! Good work! However, it said the things I expected, but not the answer to my problem.

I have many years experience in embedded design, but this is my first trip with AVR.

I am trying to port a simple monitor routine I wrote 30 years ago and have used on many families of processor. Everything works as expected except that after writing the second byte to UDR, the UDRE flag never goes true again.

This was true in the AVR Studio simulator and I assumed that the simulation was not complete in this respect. However, after writing an endless loop to spit the same character and downloading to my mega8 chip, it sends exactly two characters after every reset and that's it.

I saw a note in the data sheet that says, "Note
that the TXC Flag must be cleared before each transmission (before UDR is written) if it
is used for this purpose." Does "cleared" require a set of the bit or a clear? I tried inserting sbi UCSRA,TXC and cbi UCSRA,TXC before writing to UDR, but neither made any difference.

Here is the code:

SendHex: ;Send a hex byte to the UART
sbis UCSRA,UDRE ;Wait for output register empty
rjmp SendHex
sbi UCSRA,TXC ;Set UART busy flag
out UDR,Temp0
rjmp SendHex ;Test loop
ret

Here is the initialization code:
;Set up USART
ldi Temp0,00 ;Select asynch mode
out UBRRH,Temp0
ldi Temp0,BR ;Select 9600 baud at 16 MHz
out UBRRL,Temp0
ldi Temp0,$18 ;Enable Rx and Tx
out UCSRB,Temp0
ldi Temp0,$86 ;Select 8 data bits
out UCSRC,Temp0
ldi Temp0,0 ;Disable double baud rate for 8
; MHz internal clock
out UCSRA,Temp0

Thanks for taking a look. I am very impressed by the degree of enthusiasm shown by the members of this forum. Perhaps I can submit something useful later.

Howard Speegle
howard@divaauto.com

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

You shouldn't need to play with TXC at all - just check that UDRE is set (so that the transmit buffer is not full) then write to UDR. If you do that each time, the transmission will halt until the UDR send buffer has space, then will send the byte for you.

Is there a specific reason you want to play with the TXC bit?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I have a strange problem in UART communication on ATMEGA8. I'm using external 11.0592MHz quartz oscillator. Using abcminiuser's example uC communicates with terminal only at 1/16 of declared speed in uC, i.e. when I set 19200 baud rate in uC, I must set 1200 in terminal to see the echo result. Same problem at 38400 and other speeds.
At the same speeds i don't see any results.
Maybe that is the reason of bad fuses configuration.
Below I attached screen from PonyProg with fuses config from my microprocessor.

Cheers!

Attachment(s): 

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

maros,

I'm not sure which way up Ponyprog displays the fuse bits (in the hardware 0=programmed and 1=unprogrammed in fact) but assuming a tick means =0 - that is programmed then your fuses seem to be in the default state which would mean that the mega8 is still operating at 1MHz from it's internal osciallator. (but that doesn't explain the factor of 16 you are seeing - what value are you actually putting in UBRR?)

 

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

Edit: Problem solved by setting proper CKSEL fuse bits.

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

Thanks for the USART tutorial, it's been a great tutorial for a newbie like me ;)

Anyway, just wondering, what is the correct echo result shown in hyperterminal window?
would the echo result display just once or several times ??
because in my case, when i type "A" once, the result in hyperterminal will show "AAAA" and sometimes "AAAAA"
so when i typed in "abc" it will echo back to me "aaaaabbbbccccc"

I just copy and pasted the code in this tutorial to my AVRSTUDIO then remove the URSEL part since I'm using tiny2313 chip with 4MHz external crystal clock.

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

Hi Guys,

I've used atmels a few times at uni and have a fairly good understanding of how they work. HOWEVER I have no idea with regards to serial communication! This tute looks pretty awesome, however, i'm not using the Atmega16 - instead i'm using the Atmega64 on the STK500 with the STK501 expansion board - however this doesnt matter at the moment, because I cant get the code to compile. I'm unsure as to what the "16UL" is in the following code snippet - as I think this may be where my problem is? Does the 16UL have anything to do with the mega16?

#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 

All i'm getting is a Syntax error before '=' token

 UBRR1L = BAUD_PRESCALE;

(and yes, I Do have a semi-colon on the previous line :wink: )

Thanks in advance for your help

Matt

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

Thanks for this USART tutorial Mr.Dean.
Could u please write a tutorial on Interrupts (how to use interrupts Efficiently)...

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

Sorry for the backlog everyone - I've been busy!

coolleo: Each character should only be displaying once. Is anyone else experiencing that phenomenon? I'll try this week to build the code and re-test myself as a sanity check.

mafroew: The 16UL isn't to do with the MEGA16, it's due to the way RS232 communication works. What you need to do is change the FCPU value in your makefile (or AVRStudio's project settings) to reflect the speed of the clock you're feeding into your MEGA64. As for the syntax error I can't see why that is, as the UBRR1L does exist on the MEGA64. I'd need to see the rest of your code.

prabu: See my follow up tutorial on Interrupt Driven Serial Communications, also in the tutorials forum.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

well.. i figured out where I was wrong... I was tired and my code was extremly sloppy! Was using AVR studio to write the code, so the syntax highlighting (in particular brackets!) wasnt the greatest!

One quick question is, if I wanted to send a whole string to the hyperterminal, what would be involved? Also if I wanted to read in a string.. ie, if i typed "yes" or "no" and wasnt interested in the first letter, but wanted to compare the whole thing?

Actually, better yet, where would be the best place to look? I am keen to learn, and just having trouble finding the info on such things?

Cheers
Matt

Pages

Topic locked