Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chapter5 Serialloopback. "Strange characters" #33

Open
Folkert-2 opened this issue Dec 9, 2017 · 9 comments
Open

Chapter5 Serialloopback. "Strange characters" #33

Folkert-2 opened this issue Dec 9, 2017 · 9 comments

Comments

@Folkert-2
Copy link

Testing serial loopback with the listing in Example 5.1 results in "strange" characters being returned. Entering "a" results in the following LED pattern: 01001111, which is capital "O". Typing "c" for example results in LED pattern 01001110, which is capital "N". The message "hello World" is displayed as ú‹…m:ºê+ë. When connecting USB-serial converter Rx and Tx, characters are returned correctly. The program was successfully flashed into an Atmega 168.
I have no idea where to start looking for possible causes. Any ideas from your side?
Thanks in advance, Folkert

@fivdi
Copy link

fivdi commented Dec 21, 2017

I've seen similar issues with serial communication when the internal calibrated RC oscillator is used as a clock source. The the internal calibrated RC oscillator provides an approximate 8.0MHz clock not a precise 8.0MHz clock. It was possible to resolve the issue by tweaking the value in the OSCCAL register which is used to trim the calibrated internal RC oscillator.

If it's any help, I typically use the below program to search for values of OSCCAL that function correctly. The program waits to receive a character from a terminal emulator and depending on the character received it will transmit either 1024, 10240, or 1 character back to the terminal emulator. The program then sends the value of the OSCCAL register in decimal to the terminal emulator. If the value of OSCCAL is good, the characters sent back to the terminal emulator will also be good and display correctly, if not, junk will be displayed. The value of OSCCAL is then decremented by one and the program waits until it received the next character and repeats the above process. Typically I'll just keep hitting the character 't' in the terminal emulator looking for good values for OSCCAL.

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

#define LED      PB0
#define LED_DDR  DDRB
#define LED_PORT PORTB

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

#define set_bit(sfr, bit) (_SFR_BYTE(sfr) |= (1 << bit))
#define clear_bit(sfr, bit) (_SFR_BYTE(sfr) &= ~(1 << bit))
#define toggle_bit(sfr, bit) (_SFR_BYTE(sfr) ^= (1 << bit))

void usart_init() {
  UBRR0 = UBRR_VALUE;
  UCSR0B = (1 << RXEN0) | (1 << TXEN0);
  UCSR0C = (1 << UCSZ00) | (1 << UCSZ01); // 8 bits, no parity, 1 stop bit
}

void usart_send(uint8_t ch) {
  set_bit(LED_PORT, LED);
  while (!(UCSR0A & (1 << UDRE0)));
  UDR0 = ch;
  clear_bit(LED_PORT, LED);
}

uint8_t usart_receive(void) {
  while(!(UCSR0A & (1 << RXC0)));
  return UDR0;
}

void send_chars(uint16_t count) {
  uint8_t ch = 'a';

  while (count != 0) {
    usart_send(ch);

    if (ch == 'z') {
      ch = 'a';
    } else {
      ++ch;
    }

    --count;
  }
}

void print_byte(uint8_t byte) {
  usart_send('0' + (byte / 100)); /* Hundreds */
  usart_send('0' + ((byte / 10) % 10)); /* Tens */
  usart_send('0' + (byte % 10)); /* Ones */
}

void send_osccal() {
  usart_send(' ');
  usart_send('(');
  print_byte(OSCCAL);
  usart_send(')');
  usart_send(' ');
}

int main(void) {
  clock_prescale_set(clock_div_1); // 8Mhz clock
  usart_init();

  set_bit(LED_DDR, LED); // set LED pin for output

  while (1) {
    uint8_t command = usart_receive();

    switch (command) {
      case 'o':
        send_chars(1024);
        send_osccal();
        break;

      case 't':
        send_chars(10240);
        send_osccal();
        break;

      case 'b':
      default:
        usart_send(command);
        send_osccal();
        break;
    }

    OSCCAL -= 1;
  }
}

@Folkert-2
Copy link
Author

Dear Brian. thanks a lot for your comment. I will test your program in the coming days and report back. So far, I still haven't managed to get a correct serial communication. I have tried with an Atmega328 with a 16 Mhz crystal, used a different Usb-serial converter, applied different Baud rates at the converter, and used an external power source.

@Folkert-2 Folkert-2 reopened this Dec 21, 2017
@Folkert-2
Copy link
Author

Sorry, I did not mean to close this issue. Pushed the wrong button

@fivdi
Copy link

fivdi commented Dec 21, 2017

If the ATmega328 was configured to use the external 16MHz crystal and serial communication still didn't work correctly then tweaking OSCCAL isn't going to help and the issue is something else.

If you do try the program above it expects the clock to be running at 8MHz so don't forget to specify -DF_CPU=8000000UL on the command line when calling avr-gcc to compile.

@Folkert-2
Copy link
Author

You are probably right. ButI will try out your program on an Atmega128 with internal clock set to 8 Mhz

@Folkert-2
Copy link
Author

Should read: Atmega168

@travisgillespie
Copy link

travisgillespie commented Mar 18, 2018

@Folkert-2 Were you ever able to figure out the issue? If not, hope this helps. Start with a fresh copy of the author's code for the serial loopback example.

  • Make file:
    The only things you would need to initially check/update are MCU = <your microcontroller> (e.g. MCU = atmega168), and LIBDIR path to directory AVR-Programming-Library (e.g. LIBDIR = ../../AVR-Programming-Library). Given, F_CPU = 1000000UL, and BAUD = 9600UL. As long as the author's remaining code is untouched for now, you should be able to produce the same results as me.

  • LEDs:
    Double check the wiring on your breadboard. My initial guess is some of the wires are mixed up. Use Figure 3-4 as a reference. Pressing the following keys on your keyboard should produce the corresponding LED patterns:
    a = 11100001
    b = 11100010
    c = 11100011

    Remember to reverse the pin order when reading output on the breadboard. For example, pressing a on the keyboard.
    PB7 = 1
    PB6 = 1
    PB5 = 1
    PB4 = 0
    PB3 = 0
    PB2 = 0
    PB1 = 0
    PB0 = 1

  • Serial Monitor:
    Let's fix those strange characters, they are frustrating. If your terminal software is set to the same baud rate as the microcontroller, then my guess is the program you are using is set to 8 data bits. The simple fix is to set the terminal to 7 bits. The last bullet point will walk you through the setup.

    8 bits will work with the transmitByte(serialCharacter); function which is located in the serialLoopback.c file. For example pressing the key a will return a. But, you will see strange characters when using other functions such as printString("Hello World!\r\n");, and printBinaryByte(serialCharacter);. This is odd to me because line 33 in USART.c file states /* 8 data bits, 1 stop bit */.

    Play around with it. Replace transmitByte(serialCharacter); with printBinaryByte(serialCharacter);. If you have the LEDs hooked up, you will be able to see both LED pattern and terminal produce the same result. The author's code is converting values into binary (base 2). You can double check your results with an online calculator. You can use an ASCII table to look up equivalent Dec (base 10) values and convert to Binary (base 2) which will get you close to the author's result. I haven't figured his actual method out yet, but he is using other base 10 values to get his answer in binary.
    approximate answer: a = 97 (ascii dec base 10) = 1100001 (base 2)
    author’s method: 225 (base 10) = 11100001 (base 2)

  • Terminal Setup:
    This can be done with any terminal, I will list a couple options that I use, but since I'm working on a mac follow the link for other terminal options.

  1. Open CoolTerm, click Options > Data Bits > 7.

  2. This can also be achieved in Mac Terminal if you have pySerial installed. From root directory type python -m serial.tools.miniterm <usbserial port path>. Now set to 7 bits. Press ctrl+t then ctrl+h. Press ctrl+t again followed by 7.

Now you are all set!

@Folkert-2
Copy link
Author

Folkert-2 commented Mar 19, 2018 via email

@Folkert-2
Copy link
Author

Folkert-2 commented Sep 28, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants