Society of Robots - Robot Forum

Software => Software => Topic started by: newInRobotics on February 01, 2012, 05:40:15 PM

Title: ATmega48 USART to USB - misinterpreted data [SOLVED]
Post by: newInRobotics on February 01, 2012, 05:40:15 PM
####################################################
Solved!


All that data misinterpretation was due to comm error as I tried Baud Rate of 9600 running uC @ 1MHz. I looked it up in ATmega48 datasheet and it stated that 9600 Baud Rate produces -7.0% Error when running @ 1MHz. Then I changed uC clock to 8MHz and Baud Rate (in uC and PC) to 250k (which according to datasheet produces 0.0% - and that solved the problem  ;D


Thanks for Your help joe61  :)
####################################################

Hello everyone

Recently I started playing around with ATmega48 USART to USB comms. Microcontroller is programmed via AVR Studio 5 and PC side comms are driven by simple C# Form.

Microcontroller is supposed to get byte from PC and pass it back.
Code: [Select]
#define F_CPU 1000000UL
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

#include <avr/io.h>

int main(void)
{
UCSR0B |= (1 << RXEN0) | (1 << TXEN0); //Turn ON transmission and reception circuitry

UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Data length of 8-Bit

UBRR0H = (BAUD_PRESCALE >> 8); //Load upper 8-bits of BAUD_PRESCALE value
UBRR0L = BAUD_PRESCALE;

void sendByte(uint8_t inputChar)
{
while((UCSR0A & (1 << UDRE0)) == 0){} //Do nothing until SEND register is empty

UDR0 = inputChar; //Send value of "inputChar"
}

uint8_t receiveByte()
{
while((UCSR0A & (1 << RXC0)) == 0){} //Do nothing until data is received

return UDR0;
}

while(1)
        {
uint8_t newChar = receiveByte();
sendByte(newChar);
        }
}


PC side (C# Form driven) sends data from TextBox(converted to decimal and then to byte) with a press of a button and puts received data when DataReceived event is detected.
Code: [Select]
[All GUI stuff goes here]

        private void sendBtn_Click(object sender, EventArgs e)
        {
            if ((sendBox.Text != "") && (serialPort1.IsOpen))
            {
                byte[] newByte = { Convert.ToByte(Convert.ToDecimal(sendBox.Text)) };

                serialPort1.Write(newByte, 0, 1);

                System.Console.WriteLine("Byte sent!");
            }
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            System.Console.WriteLine("Byte received!");

            byte[] newByte = new byte[1];

            serialPort1.Read(newByte, 0, 1);

            getBox.Text = ((int)newByte[0]).ToString();
        }

My inputs come back wrong, have a look:

Input   Output
    0  -->  128
    1  -->  129
    2  -->  130
    3  -->  131
    4  -->  132
    5  -->  133
   ...  -->  ...

up to input = 127 and then:

Input   Output
 128  -->  128
 129  -->  129
 130  -->  130
 131  -->  131
 132  -->  132
 133  -->  133
   ...  -->  ...

up to input = 255 and then ir crashes on input = 256, as well as input = -1

Can someone please help me understand the reason of such wierd bahavior? Thanks in advance.

N.I.R.
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: joe61 on February 01, 2012, 07:28:03 PM
Code: [Select]
void sendByte(uint8_t inputChar)
{
while((UCSR0A & (1 << UDRE0)) == 0){} //Do nothing until SEND register is empty

UDR0 = inputChar; //Send value of "inputChar"
}

uint8_t receiveByte()
{
while((UCSR0A & (1 << RXC0)) == 0){} //Do nothing until data is received

return UDR0;
}
[ ... ]

Why are you defining functions inside of main(). Does that actually compile?
Anyway, the only other thing I noticed is that the busy test in the transmit and receive code looks to be inverted. Try

Code: [Select]
while(! (UCSR0A & (1 << RXC0)) == 0)
    ;

I can't speak to the C# code though.

EDIT: Sorry, I've been working too much today. You are testing for it to be false. Never mind. I'd guess the C# code is doing the odd stuff. I have done some C# programming, and remember it to be very quirky about redefining types, or representing one type as another. It was a while ago though. Have you tried just communication with hyperterm?

Joe
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: newInRobotics on February 02, 2012, 11:42:18 AM
Hi joe61,

thanks for reply  :)

Why are you defining functions inside of main(). Does that actually compile?
It does compile. You can write functions in a function making them accessible only to the parent function and not whole class. And yes - it does compile  :) I also tried to write everything in a traditional way without "functions in a function" - results were the same.

Have you tried just communication with hyperterm?
I have tried it with RealTerm (http://realterm.sourceforge.net/) (free alternative of Hyperterminal) and output was the same.

Any other suggestions?
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: joe61 on February 02, 2012, 12:36:43 PM
Why are you defining functions inside of main(). Does that actually compile?
It does compile. You can write functions in a function making them accessible only to the parent function and not whole class
I was surprised because that's not standard C. Turns out it's a gcc extension, so it likely won't work with other compilers.

Quote
Have you tried just communication with hyperterm?
I have tried it with RealTerm (http://realterm.sourceforge.net/) (free alternative of Hyperterminal) and output was the same.

Any other suggestions?
I really don't see anything offhand that looks like a problem. I'll play with it when I get home tonight. The only suggestion I could make at this point is to check the wiring and make sure both sides are using the same bitrate, parity, etc.

The results make me wonder if there's not a type mismatch involved somehow. Like one side using signed chars while the other is using unsigned. I'm too tired to suggest that seriously right now though.

Joe
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: joe61 on February 02, 2012, 02:25:08 PM
Actually, I would be interested in the output if you print the byte received and sent in hex. I notice you're converting the byte to an int (which is signed in C# if I remember right).

Can you print the raw input and output bytes in hex?

Joe
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: newInRobotics on February 02, 2012, 05:08:24 PM
Hi joe61

Thank's for spending Your time to help me. Since getting home from work I tried many different things. I made a conclusion that ATmega somehow sends wrong data back. When C# Form (in debug mode) is paused just before sending data out - byte[] holds correct value; when Form is paused just after getting data from uC - byte[] holds that "weird 128 to 255" value; that only means that data is received the way it is (as opposed to data being misshaped in convertion). Also, when Tx and Rx coming from PC are shorted - data comes back as it should.

Here are HEX values You've asked for:

Byte sent = 0 --> in HEX = 00
Byte received = 128 --> in HEX = 80

Byte sent = 1 --> in HEX = 01
Byte received = 129 --> in HEX = 81

Byte sent = 2 --> in HEX = 02
Byte received = 130 --> in HEX = 82

Byte sent = 3 --> in HEX = 03
Byte received = 131 --> in HEX = 83

Byte sent = 4 --> in HEX = 04
Byte received = 132 --> in HEX = 84

Byte sent = 5 --> in HEX = 05
Byte received = 133 --> in HEX = 85

[...]

Byte sent = 127 --> in HEX = 7F
Byte received = 255 --> in HEX = FF


and then..

Byte sent = 128 --> in HEX = 80
Byte received = 128 --> in HEX = 80

Byte sent = 129 --> in HEX = 81
Byte received = 129 --> in HEX = 81

Byte sent = 130 --> in HEX = 82
Byte received = 130 --> in HEX = 82

[...]

Byte sent = 255 --> in HEX = FF
Byte received = 255 --> in HEX = FF



Another strange thing - the first time PC and uC starts exchanging data, receive event is detected before data is being sent out; have a look at this (exact copy from CMD Window (first and second transmissions)):

Byte received = 128 --> in HEX = 80

Byte sent = 0 --> in HEX = 00
Byte sent = 0 --> in HEX = 00
Byte received = 128 --> in HEX = 80



And another thing, here's samo data converted to binary:

Byte sent = 0 --> in HEX = 00 --> in BIN = 00000000
Byte received = 128 --> in HEX = 80 --> in BIN = 10000000

Byte sent = 1 --> in HEX = 01 --> in BIN = 00000001
Byte received = 129 --> in HEX = 81 --> in BIN = 10000001

Byte sent = 2 --> in HEX = 02 --> in BIN = 00000010
Byte received = 130 --> in HEX = 82 --> in BIN = 10000010

Byte sent = 3 --> in HEX = 03 --> in BIN = 00000011
Byte received = 131 --> in HEX = 83 --> in BIN = 10000011

Byte sent = 4 --> in HEX = 04 --> in BIN = 00000100
Byte received = 132 --> in HEX = 84 --> in BIN = 10000100


It appears that ATmega sets 7thBit to 1. Why that might be?
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: newInRobotics on February 02, 2012, 05:28:20 PM
Solved!


All that data misinterpretation was due to comm error as I tried Baud Rate of 9600 running uC @ 1MHz. I looked it up in ATmega48 datasheet and it stated that 9600 Baud Rate produces -7.0% Error when running @ 1MHz. Then I changed uC clock to 8MHz and Baud Rate (in uC and PC) to 250k (which according to datasheet produces 0.0% - and that solved the problem  ;D


Thanks for Your help joe61  :)
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: joe61 on February 02, 2012, 05:30:21 PM
I just compiled your code as posted, and wrote a C program to do the same thing you did. I got results similar to what you show, however I believe the problem was in the driver program. Here's the program I ran on my linux box

Code: [Select]

#include <stdio.h>
#include <fcntl.h>

int main()
{
    int i;
    int fd = open ("/dev/ttyUSB0", O_RDWR);
    if (fd == -1)
    {
        perror ("open");
        return 1;
    }


    for (i=30; i<255; ++i)
    {
        char b;
        printf ("writing %d\n", i);
        write (fd, (unsigned char*)&i, 1);
        read (fd, &b, 1);
        printf ("read %d\n", b);
    }
}

There are a couple things potentially messing things up there. One is that I'm receiving into a char variable. Whether a char is signed or unsigned is implementation defined, which means you have to check the compiler documentation to see what you're getting. Or declare it as signed char or unsigned char.

The other thing is that I'm printing it out using %d (as a signed int). I'm too tired to remember the promotion rules, but it would have been better for me to specify it precisely.

So I started receiving into an unsigned char (change the declaration of the variable b in the receive loop), and things printed out correctly.

I'd suggest you check how C# changes things in the program that's printing the results.

The results you show of this type
Code: [Select]
Byte sent = 2 --> in HEX = 02
Byte received = 130 --> in HEX = 82

I suspect are also related to how they're being printed out rather than what's being sent or received. Like I say, I ran the code exactly as you posted it, and I can see that I'm always getting back what I send. What changes is the way it's getting printed out.
Title: Re: ATmega48 USART to USB - misinterpreted data
Post by: joe61 on February 02, 2012, 05:34:15 PM
Solved!


All that data misinterpretation was due to comm error as I tried Baud Rate of 9600 running uC @ 1MHz. I looked it up in ATmega48 datasheet and it stated that 9600 Baud Rate produces -7.0% Error when running @ 1MHz. Then I changed uC clock to 8MHz and Baud Rate (in uC and PC) to 250k (which according to datasheet produces 0.0% - and that solved the problem  ;D


Thanks for Your help joe61  :)

Ok, I'm more tired than I thought then. I should have looked at that.

Actually I realize now that I didn't really run your code unmodified. I'm using a board that has a 20MHz resonator on it, and I changed F_CPU to match that.

There's still a lesson in there though about representation vs reality. Stuff like that will bite you sooner or later.

Glad you got it working

Joe
Title: Re: ATmega48 USART to USB - misinterpreted data [SOLVED]
Post by: newInRobotics on February 02, 2012, 05:39:13 PM
Actually I realize now that I didn't really run your code unmodified. I'm using a board that has a 20MHz resonator on it, and I changed F_CPU to match that.
According to datasheet 9600 Baud Rate @ 20MHz produces only 0.2% Error, that's why it gave good results.

Again, thanks for Your help.
Title: Re: ATmega48 USART to USB - misinterpreted data [SOLVED]
Post by: joe61 on February 02, 2012, 06:18:23 PM
According to datasheet 9600 Baud Rate @ 20MHz produces only 0.2% Error, that's why it gave good results.

Except that it didn't, until I got the sign right on the char. Still a lesson there.

Quote
Again, thanks for Your help.

I wasn't much help unfortunately.

Joe
Title: Re: ATmega48 USART to USB - misinterpreted data [SOLVED]
Post by: newInRobotics on February 03, 2012, 01:46:30 AM
Except that it didn't, until I got the sign right on the char.
In C one unsigned byte is char or uint8_t, in C# it's simply called byte and that was what I was using from the start, so binary data interpretation was not the issue here. In Your case - it was and had nothing to do with Baud Rate Error, still giving "similarly wrong" results.
Title: Re: ATmega48 USART to USB - misinterpreted data [SOLVED]
Post by: joe61 on February 03, 2012, 07:18:04 AM
In C one unsigned byte is char or uint8_t,
No, it's implementation defined whether a char is signed or unsigned. To say that an unsigned char (which is, by definition, unsigned) is equivalent to a char may or may not be true depending on the compiler being used. If it's important that it be one or the other then it should be declared as signed char or unsigned char (or one of the many typdefs that are used).

Quote
in C# it's simply called byte and that was what I was using from the start, so binary data interpretation was not the issue here.
Again, I'm not sure you understood my point. Is a byte in C# signed or unsigned? I'm saying that needs to be taken into account as well.

I'm happy you got it working, I'm not arguing the fact that it turned out to be the baud rate. I'm only mentioning these other things because it's not unusual for programs to give confusing results when they're not taken into account. It's something to keep in mind.

Joe
Title: Re: ATmega48 USART to USB - misinterpreted data [SOLVED]
Post by: newInRobotics on February 03, 2012, 08:07:09 AM
No, it's implementation defined whether a char is signed or unsigned. [...] It's something to keep in mind.
I don't disagree  :) That was the first thing checked I when it failed to output expected results.

In GNU GCC uint8_t is unsigned byte and int8_t is signed byte.
In C# byte is unsigned byte and sbyte is signed byte.