USART reading garbage

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

 

I am working on a project that requires an atTiny1634 to interface via serial.  I can send just fine, but it's sending too fast the receiver (Android app) to catch it all, so I'm trying to implement some handshaking.  I'm testing using minicom on Arch Linux.  The relevant code is below.  In minicom, even when I'm not pressing any buttons, the USART_receive() generates a lot of garbage.  From random letters and numbers to crazy symbols.  See attached screen shot.

Main file:

USART_init();			// Initialize serial interface

char *buffer[256];		// Buffer to write to using sprintf() that can then be written to the USART using
				// USART_putstring
//This reads the ready bit from the app to avoid writing to quickly.
char *ready[2] = {89, 89};

            //UDR0 = UDR0 & 0x00;
            ready[0] = USART_receive();
            while(ready[0] != "Y" ){		// Wait for ready to = {89, 89}
                ready[0] = USART_receive();
                sprintf(buffer, "Ready = %c\n\r", ready[0]);
                USART_putstring(buffer);
                //ready[0] = 90;
                //sprintf(buffer, "Ready 2 = %c\n\r", ready[0]);
                //USART_putstring(buffer);
                UDR0 = UDR0 & 0x00;     // I added this recently to test, it doesn't seem to make a difference.
                UCSR0A &= (0<<RXC0);    // Same thing, added out of desperation, no difference.
            }
            

Serial library:

#include <stdio.h>
#include "serialLib.h"
#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 8000000UL // Clock speed of 1634 is default 8MHz
#define BAUDRATE 4800
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)	// Formula from Datasheet


void USART_init(void);
unsigned char USART_receive(void);
void USART_send( unsigned char data);
void USART_putstring(char* StringPtr);


void USART_init(void){

 UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);	// Set highest 8 bits of baud rate
 UBRR0L = (uint8_t)(BAUD_PRESCALLER);		// Set lower 2 bits of baud rate
 UCSR0B = (1<<RXEN0)|(1<<TXEN0);		// Enable receiver and transmitter
 UCSR0C = (3<<UCSZ00);				// Set 8 data bit, 1 stop bit
}

unsigned char USART_receive(void){

// while(!(UCSR0A & (1<<RXC0)));			// While the buffer is empty, read it
 loop_until_bit_is_set(UCSR0A, RXC0);
 return UDR0;

}

void USART_send( unsigned char data){

 while(!(UCSR0A & (1<<UDRE0)));			// While able to transmit, send
 UDR0 = data;							// Store data to send in data register

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){		// While the pointer address isn't empty, cycle through
 USART_send(*StringPtr);		// the bits until all data is sent.
 StringPtr++;}

}

 

Attachment(s): 

This topic has a solution.
Last Edited: Tue. Apr 17, 2018 - 12:45 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is probably not what you want:

hks003 wrote:
char *buffer[256];
You have declared an array here of 256 pointers to characters. If you want to declare a buffer of 256 characters, then remove the " * ".

Same with your ready[ ] array.

 

Debugging software like this is much more convenient if you have a real debugger and you can step through the code and examine what each line is doing.

You can do this by compiling your program on a PC with a C compiler for that PC.

Declare all special "AVR" register names as normal variables, and "catch" some of the special AVR registers for real output.

For example instead of writing to the UDR0 register, you can replace that by using the putchar() function.

 

C is a standarized language. This means that ( very much unlike "BASIC") you can swap a lot of functions between running on a small uC or a big PC without any modification.

Debugging a lot of functions for small uC's such as AVR on a PC is a very common and powerfull technique.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

Last Edited: Mon. Apr 16, 2018 - 02:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

as a side note, are you sure the processor runs at 8MHz.

I do not know the tiny1634, but most modern avrs have a clk/div8 fuse bit that divides the main clock by 8.

If that is present and is set it might be that you are only running at 1MHz in which case you will also get garbage.

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

hks003 wrote:
a lot of garbage

See Tip #1.

 

Due to the different tolerances each end, it is possible that your AVR's baud rate is (just) close enough for the PC to work with what it receives form the AVR, but not in the other direction.

 

Paulvdh wrote:
Debugging software like this is much more convenient if you have a real debugger and you can step through the code and examine what each line is doing.

Indeed.

 

Note that the ATTiny1634 has on-chip debug - so use it!

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
#include <util/delay.h>

#define F_CPU 8000000UL // Clock speed of 1634 is default 8MHz

ASIDE: As you aren't actually using any calls to _delay_ms() or _delay_us() this does not matter right now. But when you come to use any of those note that the #define of F_CPU *must* be before the inclusion of util/delay.h (at present you will be getting a warning because this is wrong - I would also suggest it is unwise to ignore ANY warning if you don't know exactly the reason for it and why it is OK to be ignored).

 

BTW apart from the point Paul made about over-use of '*' I find:

char *ready[2] = {89, 89};

very difficult to read. Especially when you later go on to do:

 while(ready[0] != "Y" ){	

The definition of ready[] would be clearer as:

char ready[2] = {'Y', 'Y'};

(to even make that point I had to check at www.asciitable.com that 89=='Y' which kind of confirms what I am saying!)

Last Edited: Mon. Apr 16, 2018 - 08:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

also not the distinction between single and double quotes ...

 

EDIT

 

That should, of course, say "note" - not "not".

 

blush

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Apr 16, 2018 - 09:02 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

hks003 wrote:
Clock speed of 1634 is default 8MHz
This "default" with most AVR's is also the internal RC oscillator, which is not good enough for reliable USART operation. (temperature dependent, drift). A much better choice for UsART is to use a crystal which divides nicely to exact USART baudrates. For exampe 7.3728MHz or 11.0592MHz.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

awneil wrote:
also not the distinction between single and double quotes ...
Oh well spotted - my eyes are tired this morning. Perhaps this explains the intended use of "char *" instead of just "char"? But the point is that you can do things like:

char reply[2] = { 'Y', 'Y'};

if (reply[1] == 'Y') {

while(reply[0] != 'N') {
    
etc.

but if you really were going to use C strings:

char * reply[2] = { "Y", "Y" };

then you can't just use the == operator with such strings (not until you get to C++ and the real string class) so the test would have to have been:

if (strcmp(reply[1], "Y") == 0) {
    
while(strcmp(reply[0], "N") != 0) {

but if it's single characters being used you almost certainly don't want to use single character strings because the thing about strings is that there's always one more hidden character (the terminating 0) and if you are building up strings from individual received characters you have to synthesize that 0x00 at the end to make a complete string.

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

This seemed to be the issue.  While I did remove the "*" from my buffer and ready variables, I wound up slowing the BAUD down to 300 and it works fine!  My project is space sensitive, so a crystal is a last resort.  I hope to make it work with just a slower BAUD.  Thanks for the help!

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

I am sorry to dissapoint you, but lowering the BAUDrate does nothing for the clock frequency accuracy.

RC oscillator frequency changes with temperature, you should verify it, and possibly re-calibrate the oscillator.

What does the datasheet of your particular AVR say about the accuracy / callibration of the RC oscillator?

Maximum clock deviation for a UART is around 1.8%. And that is for the combination of both the receiver and transmitter.

If they both deviate in the same direction, you won't notice, if they drift in opposite directions you get occasional errors and unreliable communication.

 

Don't assume that the BAUDrate generated by a PC is perfect. PC hardware is often the cheapest that "works".

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

hks003 wrote:
My project is space sensitive, so a crystal is a last resort.

Can you find 5x7mm?  https://www.digikey.com/product-...

I assumed your vcc is 5v, 3.3v parts are also available, this is an external osc, so no caps are needed.

 

Jim

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

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

Ceramic Resonators easily go down to a size of 1mmx2mm and are good enough for UART communication ( 0.5% frequency tolerance).

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

ki0bk wrote:

hks003 wrote:
My project is space sensitive, so a crystal is a last resort.

Can you find 5x7mm?  https://www.digikey.com/product-...

I assumed your vcc is 5v, 3.3v parts are also available, this is an external osc, so no caps are needed.

 

Jim

 

they can be even smaller, more like 3,2 x 2mm and less. Did a quick check with Farnell and the smallest 8mHz they seem to have is actually 5mm x 3,2mm. But giving it a bit more time might give smaller ones at other distributors/vendors.

 

It will safe a lot of headaches in the future as with the RC oscillator used you will for sure have an unstable uart channel that can fail at any time and will fail when you do not want it to fail.

I started of with not using a crystal when I started playing with the uart.... at first it worked, then it stopped. teh next morning all of the sudden it worked again, then after a couple of fw changes it all of the sudden stopped working again. then woudl start again and would stop again all of the sudden while not touching the hardware or Fw at all.

So do yourself a huge favour and make sure to add either a external resonator/oscillator or crystal + caps and keep away from a lot of troubles with communication.