4

I am using a FTDI cable and connected it with my mac. I can connect successfully with my serial terminal on my mac via the cable and can input text on my keyboard to be transmitted to the AVR. When the program starts I expect a "Hello World" message to appear on my serial terminal. But instead I receive this output on the screen:

enter image description here The terminal settings are enter image description here

enter image description here enter image description here

enter image description here

The code is this:

// ------- Preamble -------- //
#include <avr/io.h>
#include <util/delay.h>
#include "pinDefines.h"
#include "USART.h"

int main(void) {
  char serialCharacter;

  // -------- Inits --------- //
  LED_DDR = 0xff;                            /* set up LEDs for output */
  initUSART();
  printString("Hello World!\r\n");                          /* to test */

  // ------ Event loop ------ //
  while (1) {

    serialCharacter = receiveByte();
    transmitByte(serialCharacter);
    LED_PORT = serialCharacter;
                           /* display ascii/numeric value of character */

  }                                                  /* End event loop */
  return 0;
}

The USART.c file contains:

#include <avr/io.h>
#include "USART.h"
#include <util/setbaud.h>
#define BAUD 9600

void initUSART(void) {                                /* requires BAUD */
  UBRR0H = UBRRH_VALUE;                        /* defined in setbaud.h */
  UBRR0L = UBRRL_VALUE;
#if USE_2X
  UCSR0A |= (1 << U2X0);
#else
  UCSR0A &= ~(1 << U2X0);
#endif
                                  /* Enable USART transmitter/receiver */
  UCSR0B = (1 << TXEN0) | (1 << RXEN0);
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);   /* 8 data bits, 1 stop bit */
}

void transmitByte(uint8_t data) {
                                     /* Wait for empty transmit buffer */
  loop_until_bit_is_set(UCSR0A, UDRE0);
  UDR0 = data;                                            /* send data */
}

uint8_t receiveByte(void) {
  loop_until_bit_is_set(UCSR0A, RXC0);       /* Wait for incoming data */
  return UDR0;                                /* return register value */
}

                       /* Here are a bunch of useful printing commands */

void printString(const char myString[]) {
  uint8_t i = 0;
  while (myString[i]) {
    transmitByte(myString[i]);
    i++;
  }
}

void readString(char myString[], uint8_t maxLength) {
  char response;
  uint8_t i;
  i = 0;
  while (i < (maxLength - 1)) {                   /* prevent over-runs */
    response = receiveByte();
    transmitByte(response);                                    /* echo */
    if (response == '\r') {                     /* enter marks the end */
      break;
    }
    else {
      myString[i] = response;                       /* add in a letter */
      i++;
    }
  }
  myString[i] = 0;                          /* terminal NULL character */
}

void printByte(uint8_t byte) {
              /* Converts a byte to a string of decimal text, sends it */
  transmitByte('0' + (byte / 100));                        /* Hundreds */
  transmitByte('0' + ((byte / 10) % 10));                      /* Tens */
  transmitByte('0' + (byte % 10));                             /* Ones */
}

void printWord(uint16_t word) {
  transmitByte('0' + (word / 10000));                 /* Ten-thousands */
  transmitByte('0' + ((word / 1000) % 10));               /* Thousands */
  transmitByte('0' + ((word / 100) % 10));                 /* Hundreds */
  transmitByte('0' + ((word / 10) % 10));                      /* Tens */
  transmitByte('0' + (word % 10));                             /* Ones */
}

void printBinaryByte(uint8_t byte) {
                       /* Prints out a byte as a series of 1's and 0's */
  uint8_t bit;
  for (bit = 7; bit < 255; bit--) {
    if (bit_is_set(byte, bit))
      transmitByte('1');
    else
      transmitByte('0');
  }
}

char nibbleToHexCharacter(uint8_t nibble) {
                                   /* Converts 4 bits into hexadecimal */
  if (nibble < 10) {
    return ('0' + nibble);
  }
  else {
    return ('A' + nibble - 10);
  }
}

void printHexByte(uint8_t byte) {
                        /* Prints a byte as its hexadecimal equivalent */
  uint8_t nibble;
  nibble = (byte & 0b11110000) >> 4;
  transmitByte(nibbleToHexCharacter(nibble));
  nibble = byte & 0b00001111;
  transmitByte(nibbleToHexCharacter(nibble));
}

uint8_t getNumber(void) {
  // Gets a numerical 0-255 from the serial port.
  // Converts from string to number.
  char hundreds = '0';
  char tens = '0';
  char ones = '0';
  char thisChar = '0';
  do {                                                   /* shift over */
    hundreds = tens;
    tens = ones;
    ones = thisChar;
    thisChar = receiveByte();                   /* get a new character */
    transmitByte(thisChar);                                    /* echo */
  } while (thisChar != '\r');                     /* until type return */
  return (100 * (hundreds - '0') + 10 * (tens - '0') + ones - '0');
}
Bence Kaulics
  • 6,353
  • 12
  • 33
  • 60
sesc360
  • 297
  • 4
  • 12
  • 3
    Check you have matching Baud rates at both ends, and that the AVR clock frequency is as expected. – Tom Carpenter Nov 16 '16 at 11:32
  • 1
    perhaps a baud rate is not equal? – Marko Buršič Nov 16 '16 at 11:32
  • The baud rate in the serial terminal is set to 9600. I thought 9600 is set in code as well? – sesc360 Nov 16 '16 at 11:35
  • 1
    Check the values of UBBRH_VALUE and UBBRL_VALUE variables and make sure they have correct values for 9600baud. Also, crystal frequency is very important on UART transmission. – Rohat Kılıç Nov 16 '16 at 11:39
  • Could you elaborate on what evidence actually confirms that "I can connect successfully with my serial terminal on my mac via the cable..." ? Have you tried a loopback with the FTDI cable (Short-circuiting pins 2-3 (TX/RX) with a pen for example and typing) ? – Pau Coma Ramirez Nov 16 '16 at 11:39
  • I do not use an external crystal. Do you mean that? How do I set the UBBRH and UBBRL Value correctly then? – sesc360 Nov 16 '16 at 11:40
  • Have you read the code comments? "UBRR0H = UBRRH_VALUE; /* defined in setbaud.h */" – Tom Carpenter Nov 16 '16 at 11:40
  • @PauComaRamirez Yep, I tried the loopback and it works. Oh.. interesting.. when I loop back the correct characters are displayed. Only when I connect with the AVR i get this strange output return. – sesc360 Nov 16 '16 at 11:41
  • Looks like baud barf to me. – Olin Lathrop Nov 16 '16 at 11:44
  • 1
    Here is an example of setting BAUD of AVR: http://pastebin.com/L05SYB2C. Still recommended to read relevant part of datasheet and comments in the header to understand it correctly. – Bence Kaulics Nov 16 '16 at 11:45
  • Your BaudRate is too high on one end, You are interpreting 43 characters instead of 11.. so a factor of about 4.. if 9k6 is on one side try 38k4 instead – Pau Coma Ramirez Nov 16 '16 at 11:46
  • Yes I read that. When I go into the setbaud.h file I find the definitions but no value – sesc360 Nov 16 '16 at 11:50
  • @PauComaRamirez How did you figure that out? – sesc360 Nov 16 '16 at 11:53
  • Counting: "Hello World" --> 11 Chars , "..ÄÄÄ.Ä.ÄÄ.ÄÄÄÄÄ..ÄÄÄÄÄÄÄ..Ä.ÄÄ..ÄÄ..ÄÄ..Ä." --> 43 Chars – Pau Coma Ramirez Nov 16 '16 at 11:55
  • I am sorry, but I don't get it how I correctly set my baud rate in my code. How do I need to rewrite the code correctly to have 9600? I added `#define BAUD 9600` at the top of the USART.c – sesc360 Nov 16 '16 at 12:00
  • I haven't checked your code in detail but I would say that your AVR code is actually sending at 9k6, but your CoolTerm Terminal is configured at 38k4. Change the settings of the Terminal. What are actually the settings of the Terminal? – Pau Coma Ramirez Nov 16 '16 at 12:05
  • I added the termin setting screenshots to my question. – sesc360 Nov 16 '16 at 12:13
  • Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/48594/discussion-between-pau-coma-ramirez-and-sesc360). – Pau Coma Ramirez Nov 16 '16 at 12:16
  • try putting in a delay of about 10secs after the printString to see if its not actually your infinite while loop causing the issue – crowie Nov 16 '16 at 12:33
  • Oh yea check your fuse settings, what chip are you using? – crowie Nov 16 '16 at 12:35

3 Answers3

6

First step should be checking your clock configuration. You said, there is no external crystal, and you code definitely runs now so the CKSEL[3:0] fuse bits are certainly 0010, internal RC oscillator is selected. Tables taken from datasheet.

![enter image description here

Now, check the CKDIV8 fuse bit as well, to know if the internal RC oscillator is divided by 8 or not.

enter image description here

It is programmed by default, so if you have never ever touched the fuse bits yet, your MCU probably runs on 1 MHz.

If the CKDIV8 is 0, define your CPU frequency as follows:

#define  F_CPU 1000000UL

and if it is 1, then:

#define  F_CPU 8000000UL

Next step is calculating the value of the BAUD rate register, which can be done with the following macros.

#define BAUD 9600                        // desired baud
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1) // set baud rate value for UBRR

This will give you the correct value in BAUDRATE. Equation is given in the datasheet.

![enter image description here

In your UART init function pass this to the UBBRH and UBBRL registers.

UBRR0H = (BAUDRATE>>8);  // shift the register right by 8 bits to get the upper 8 bits
UBRR0L = BAUDRATE;       // set baud rate
Bence Kaulics
  • 6,353
  • 12
  • 33
  • 60
  • I just ordered another FTDI cable (not from ebay this time but from Adafruit). lets see. – sesc360 Nov 16 '16 at 16:17
  • 2
    @sec360 could be, but I doubt the FTDI cable is at fault, If you plan on doing some more projects I would invest in a scope/logic analyzer. You can get cheap one on ebay but, I would recommend one from https://www.saleae.com/ , I have one and it has helped me loads in debugging. – Pau Coma Ramirez Nov 16 '16 at 16:40
  • I have saleae copy from ebay, served me well so far. – Bence Kaulics Nov 16 '16 at 16:41
5

I ran into this same problem, and the answer provided by @bence_kaulics is what got me through it, with one additional point:

I am in the same situation as @secs360:

  1. atmega328p
  2. working through chapter Chapter 5 (USART) in the book Make AVR Programming (the source of the code sample provided by @secs360)
  3. I can program my chip (blink tests work), but the serial feedback loop responds with incorrect characters. Various combinations of BAUD settings in the code, or in the serial terminal, fail to resolve the issue.

Steps to fix:

First, confirm I have set the clock correctly:

Fuses OK (E:FF, H:D9, L:62)

Checking these against a fuse calculator, I see they are the default values: the MCU is set to use the internal RC oscillator at 1 MHz.

This means I should set the CPU speed (in the makefile for the chapter exercises in this case):

F_CPU = 1000000UL

I can also set the BAUD value in the same location. 9600 should work:

BAUD  = 9600UL

So far so good. However, the book uses a different formula for calculating the UBRRn register values. @bence_kaulics provides the formula, from the datasheet.

(Perhaps the difference is due to the book being written for atmega168 chips? I don't know. But whatever the source, we need to use the correct value here.)

There is one more piece of information! If we want to use 9600 BAUD, we will have an error of -7% with standard transmission speed, according to the datasheet. If we double the transmission speed, our error drops to 0.2%. To do this, we don't use the formula provided by @bence_kaulics, but instead use ((F_CPU)/(BAUD*8UL)-1), and set the U2X0 bit.

I did that by modifying the initUSART function in the USART.c file:

void initUSART(void) {                                /* requires BAUD */
    #define BAUDRATE ((F_CPU)/(BAUD*8UL)-1) // set baud rate value for UBRR
    UBRR0H = (BAUDRATE>>8);  // shift the register right by 8 bits to get the upper 8 bits
    UBRR0L = BAUDRATE;       // set baud rate

    UCSR0A |= (1 << U2X0);   // double transmission speed

                              /* Enable USART transmitter/receiver */
    UCSR0B = (1 << TXEN0) | (1 << RXEN0);
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);   /* 8 data bits, 1 stop bit */
}

The original version from the book uses logic in the setbaud.h file to determine whether or not to double the transmission speed. I don't understand all of it, and so I'm not sure if the problem is the formula used for the BAUDRATE, or USE_2X, or both. Whatever it is, the code above has finally got my atmega328p speaking properly over the serial interface.

Tyler
  • 168
  • 8
4

The solution will be anyone from the following

  1. Check the AVR board Clock Frequency, it should be the value which is taken by you to calculate the baud rate
  2. Check the baud rate register(UBRR) values, it should be 129(in decimal) for 9600 baud rate at 20MHz Clock Frequency. As well as check with formula available in datasheet
  3. Check the RS232 cable (Less chance ) and the converter (MAX 232 or any else)
Photon001
  • 824
  • 6
  • 17