[TUT] [FAQ] How To Debug Serial I/O (UART/USART) Problems

1 post / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

0 - Read the tutorials:
[TUT] [SOFT] Using the USART - Serial communications
[TUT] [SOFT] Using the USART - Interrupt driven serial comms

1 - Check to be sure you have the right clock running. Run a simple "blink the LED" program where you have an expected delay. The program would look something like this (I am using all pins on Port A to flash - change this for your given hardware):

/* Set the following to the clock rate your CPU is using.
 * The value is in Hertz (cycles per second) and is an integer.
 * The trailing "UL" tells the compiler that this value is
 * an "unsigned long".
 */
#define F_CPU 8000000UL

#include avr/io.h>
#include 

int main( void )
{
   DDRA = 0xFF;
   PORTA = 0x00;

   while (1)
   {
      PORTA = 0xFF;
      _delay_ms( 500 );
      PORTA = 0x00;
      _delay_ms( 500 );
   }
}

The above program should flash an LED at a rate of once per second. Does the LED blink at the rate that you expect? If not, check the crystal and Clock fuses to be sure they are set correctly. Also make sure that you have set the F_CPU frequency correctly. If you are using AVR Studio, the Project Configuration page has a clock frequency setting - be sure to set it. This is the most common failure!

2: If you are running on the internal clock, you may have serious baud rate problems. The internal oscillator has a 10% accuracy (meaning it can be off by as much as 10%), while RS-232 must be under 2%. Note that the baud rate does not matter and making it slower will not help; if the internal oscillator is off by 8%, it is off and a slower baud rate won't help.

The internal oscillator can be calibrated if you have a known frequency (a 32.768 KHz "real-time clock" crystal will do). You can also tweak the calibration until the output works. The following program will give the best text with the correct calibration for your chip (code by Cliff Lawson): [Warning: The following code is for an ATmega168 - a revised set of code that is more universal is coming soon - stu]

#include 
#include 

int uart_putc(char c, FILE *unused) {
#ifdef __AVR_ATmega168__
   while (!(UCSR0A & (1<<UDRE0)));
   UDR0 = c;
#else
   while (!(UCSRA & (1<<UDRE)));
   UDR = c;
#endif
   return 0;
}

FILE uart_str = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);

int main(void) {

#ifdef __AVR_ATmega168__
   UBRR0L = 51; // 9600 @ 8MHz
   UCSR0B = (1<<TXEN0); // only using it as output debug channel
#else
   UBRRL = 12; // 9600 @ 1MHz
   UCSRA = (1<<U2X);
   UCSRB = (1<<TXEN); // only using it as output debug channel
#endif
   stdout = &uart_str; // printf to UART
   for (OSCCAL=0; OSCCAL<255; OSCCAL++) {
      printf("OSCCAL = %3d\n", OSCCAL);
   }
} 

At anything over 38400 baud, you should use a crystal with a "magic" frequency (14.7456 MHZ, ...) that is evenly divisible to your baud rate (meaning you can dive it evenly with an integer, with no remainder). You cannot run 57600 baud with a 16 MHz crystal, at least not reliably. For calculations on this and other AVR timer topics, check out KAVRCalc - Calculator of AVR-specific stuff ( It's free!)

3 - Check your output connections. Run a simple UART output program (no interrupts!) that sets up 8-bits, no parity, 1 stop bit, and sends a constant string of "U"s. A string of ASCII "U" will give you a square wave output with the bit width equal to your baud rate. Check the square wave with a scope - is it right? If you have an RS-232 converter, check both the inputs and outputs of the converter. If you can tie the output to a terminal emulator and you see the string of U's coming out, you're good.

4 - Check your input connections. Send a string of characters to the processor and run a simple program that simply toggles an LED when a character is received. Again, check the signal at the input to the processor - is it there? After that works, do another simple program that simply echoes characters back.

By the time you are through this procedure, you have gotten rid of 95% of the teething problems with UARTs.

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!