Help arround USART communication

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

Hello! I'm trying to understand how the USART mechanics in AVR devices work, and by doing so I developed a small test program to interact with the program PUTTY, that revolves arround pressing a keybind in the PC, that the AVR will read and then acknowledge that the button was pressed. e.g. Printing the message "Key: C" if i press the key C. However, nothing appears on the PUTTY terminal when I press a keybind. I tried testing it on other programs, Termite and Docklight, but to no avail. Therefore my main question is am I forgeting something in the code that i need to configure or is something wrong with the hardware or program that im testing on. Here is my code:

 

#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdio.h>

typedef struct USARTRX
{
	char receive_buffer;
	unsigned char status;
	unsigned char receive: 1; // reserves one byte
	unsigned char error: 1;   // reserves one byte

}USARTRX_st;

volatile USARTRX_st rx_USART = {0, 0, 0, 0};
char transmit_buffer[10];

void inic(void)
{
	UBRR0H = 0;
	UBRR0L = 12; // Baud Rate = 9.6k
	UCSR0A = (1<<U2X0); // double speed U2XN=1
	UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0); // reception,transmission and reception interrupt
	UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); //asynchronous, no parity, 1 stop bit, 8 bits 

	sei(); // interruption
}
void send_message(char *buffer)
{
	unsigned char i=0;
	while (buffer[i]!='\0') // verifies end of string
	{
		while((UCSR0A & 1<<UDRE0)==0); // verifies if buffer is empty
		UDR0=buffer[i]; // puts 1 bit in the transmission buffer
		i++;
	}
}

ISR(USART_RX_vect)
{
	rx_USART.status = UCSR0A; // saves error flags

	if ( rx_USART.status & ((1<<FE0) | (1<<DOR0) | (1>>UPE0))) // verifies for errors
	rx_USART.error = 1;

	rx_USART.receive_buffer = UDR0;
	rx_USART.receive = 1;
}

int main(void)
{
	inic();

	while(1)
	{
		if (rx_USART.receive == 1) // verifies if there is new data
		{
			if(rx_USART.error == 1) // verifies for errors
			{
				/
				rx_USART.error = 0;
			}
			else
			{
				sprintf(transmit_buffer, "Key: %c\r\n", rx_USART.receive_buffer); // transfers the information to ("KEY: %c\r\n", rx_USART.receive_buffer) to char transmit buffer
				send_message(transmit_buffer);
			}
			rx_USART.receive = 0;
		}
	}
}

To pass the information to the computer , I'm making the serial connection from the usb port to the microcontroller by using an USB To RS232 TTL that I bought, linked here for more in depth analysis: https://www.boxelectronica.com/pt/conversores/155-usb-to-rs232-ttl.html. I'm also using an ATmega88 as my AVR and an USBASP.

 

Thank you for reading.

This topic has a solution.
Last Edited: Thu. Nov 7, 2019 - 05:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Armazens wrote:
USB To RS232 TTL
That is an oxymoronic name. Either the interface is "RS232" (which suggests -12V/+12V signalling) or it is "TTL" (which suggests 0V/5V (or maybe 3.3V) signalling). It cannot be both. If you have the wrong one it could be a problem.

 

In the old days when PCs had real serial ports they were "RS232" and used -12V/+12V so to interface something like an AVR with a 0/5V UART a converter chip was required to change the voltage levels). So you would have a MAX232 to convert.

 

When USB interfaces for serial first appeared they were all RS232 so at the AVR end you still needed a MAX232.

 

These days you can get USB-TTL cables - they are just 0V/5V and can connect direct to the TXD/RXD pins of the AVR.

 

BTW given #3 in my signature. I wonder about:

	UBRR0L = 12; // Baud Rate = 9.6k

 

You only get 9,600 with a value of 12 if the CPU speed is 1MHz and you use U2X mode. Now I see:

	UCSR0A = (1<<U2X0); // double speed U2XN=1

so, yeah, I guess we can assume you *think* the CPU is running at 1MHz - but is it?

 

Oh and it seems a bit ambitious to implement async reception before you have simple synchronous send/receive working first!

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

Hello Clawson,

 

Yes your right, I wasn't clear enough, I'm using a USB-TTL with 0V/5V, that i connect to the TXD/RXD pins of the AVR.

Besides that I'm using 1Mhz because it is the frequency of ATmega88 stated in datasheet, the same frequency that i used in other projects, so the problem shouldn' be that I think but I may be wrong.

In regards to the asyncrhonous vs synchrounos send/receive implementation could you elaborate a bit more? For example in order for me to test if the problem is in fact the code or the hardware like i stated above.

 

Thank you for reading.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Serial Comm hardware basics:

You need a minimum of three wire connections for usart serial comms,

TXD of the terminal connects to the RX pin of the AVR,

RXD of the terminal connects to the TX pin of the AVR,

and GND of the terminal connects to the GND of the AVR.

 

Start by writing a simple program on the AVR to send the letter "U" in a continuous stream, this will confirm your TX to RXD circuit and if nothing or garbage shows on the terminal your baud rate is not right.

Use a scope or freq counter or sometimes a DVM will have a freq readout, to probe the TX pin, the "U" character has a 10101010 pattern that looks like a square wave, the frequency is the actual baud rate!!!

This makes it easy to verify your configuration is what you think it is.

 

Once this work, change your test program to echo the data received back out and verify you can see what your typing!

 

Now basic usart is working, build from that!

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

Armazens wrote:
In regards to the asyncrhonous vs synchrounos send/receive implementation could you elaborate a bit more? 

In this context,

  • "synchronous" means that your code waits for the send/receive to complete before it moves on to the next statement
     
  • "asynchronous" doesn't!
    That is to say, your code simply requests "start the transmission" or "start the reception", and then carries on immediately.
    This complicates things because it means that you have to "remember" that a communication is going on, and you need some way know when the communication has completed.
    (in a microcontroller, interrupts are usually used manage asynchronous operations).

 

This is not to be confused with Asynchronous comms (as with a UART) and Synchronous comms (as with SPI or I2C/TWI) ...

 

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: 0

In simple terms:
.
Sync = while loop waiting for RXC/UDRE
Async = interrupt with ISR to handle RXC/UDRE event
.
Latter seriously more complex than former.

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

In awneil excellent explanation, it might be useful to mention that the terms "synchronous" and "asynchronous" for processes are NOT used very often in AVR coding. You tend to see the term "blocking" instead of "synchronous". That is, the code sits there, usually in a tight loop, waiting for something to happen. While it is waiting, nothing else other than background hardware (e.g. a UART or TIMER) or an interrupt can happen. Hence, it blocks the program from proceeding.

 

Blocking code has a number of potential problems. Suppose that it is waiting for a character to arrive via USB and the USB cable gets unplugged. Is it going to wait there, for-ever. for the character that can never arrive? When there is a possibility like that, it is important to add some sort of timeout. This is often done with a timer, since a timer will continue to run (and report the timeout) even while the blocking code is blocking. Less critical blocking code might wait for a UART to finish sending the current character. In this case, the flag bit that reports this WILL happen unless the UART has been disabled or its clock has been turned off. It is pretty common to ignore timeouts for such less critical blocking code, because it is all under the control of the programmer (assuming the programmer HAS control, of course :).

 

So, om the AVR world, the terms synchronous and non-synchronous are most often applied to serial data exchange methods, such as TWI/I2C or SPI or UART-based serial.

 

Jim

 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Wed. Nov 6, 2019 - 08:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Speak for yourself. I always use Sync/Async.

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

I use both!

 

Blocking/Non-blocking does have the advantage of less confusion with Sync/Async as the type of the comms link

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: 0

Test both parts of the code (send and receive from PC) separately to see if both are working.

 

Add a single LED (with a 150-1000 ohm resistor to limit the brightness current and keep it from burning up) to one of the unused pins of the AVR.   Set the code to blink the LED on for about a half of a second whenever a character is received by the USART on the AVR.  This LED should flash whenever a key is pressed on the PC.   It verifies that the PC is actually sending a UART byte. 

 

You can also put the LED/resistor combination on the TX pin of the "USB-to-RS232-TTL" module.   This should be the line that sending data FROM the PC.  These modules have outputs of +5V on the TX line at "idle" state (no UART data coming from the PC) and strobe the TX line to ground (0 volts) when "active".    These +5/gnd levels are called "TTL" for transistor/transistor logic".  In the 20th century, serial ports used -12V for "idle" and +12V for "active data strobe".  These were called RS-232 logic levels.   RS232 format has been replaced by USB for printers and other serial devices.

 

Simplify your code by removing the status indicators and the structure format.  UART errors are rare in simple tests like this.  Have the AVR constantly test for a new UART character.  Then send the character back to the PC with 1 added to its ASCII value.   So that an "a" pressed on the PC's keyboard displays a "b" on the PC screen.   Use single speed for the AVR's baud rate.  You want to remove every possible thing that can go wrong in a simple UART test until the test is working.  Then change only one thing, recompile and upload, and verify that the one simple change is not causing unusual results.   Avoid implementing UART receive interrupts until the simplest possible UART test is working.

 

Often the TX and RX lines are reversed.  This is common.  If you have an oscilloscope, test the TX line that comes from the USB-TTL module for +5_gnd activity when PC keys are pressed.   If there is none, test the other line (the RX line).  Set up the AVR to do a UART send of a test character over and over.  Check with the scope that the logic levels are active on the AVR TX pin.  On an Arduino UNO/Nano test module board, note that the TX and RX are reversed.   AVR port D0 is RX and Arduino D0 (Data pin # zero) is TX.

 

 

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

ki0bk wrote:
Use a scope or freq counter or sometimes a DVM will have a freq readout, to probe the TX pin, the "U" character has a 10101010 pattern that looks like a square wave, the frequency is the actual baud rate!!!

 

<cough> *half* the baud rate, surely? </cough>

 

The signal is changing every bit; since we have each bit represented by either a high or low signal, the baud rate and the bit rate are equivalent - and since it takes two bits to transmit a full cycle of signal...

 

<Pedant mode = on> baud rate is not necessarily the same as bit rate. If, for example, you have a four level system instead of two then the baud rate would be half the bit rate since each state change of the signal represents two bits (digital TV carries can be as high as 256 levels, so eight bits per baud). On a Manchester or biphase mark/space system (not quite equivalent but easily confused until you try and decode them) the presence of state changes midway through some bits means the baud rate can be in some cases as high as twice the bit rate. </Pedant>

 

Neil

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

barnacle wrote:
<cough> *half* the baud rate, surely? </cough>

You are right, I must not have had enough caffeine when I wrote that!

You should take something for that cough! wink

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

ki0bk wrote:

Serial Comm hardware basics:

You need a minimum of three wire connections for usart serial comms,

TXD of the terminal connects to the RX pin of the AVR,

RXD of the terminal connects to the TX pin of the AVR,

and GND of the terminal connects to the GND of the AVR.

 

 

This was the problem! A simple misinterpretation of pins, in which I thought it was a direct connection of the TXD to the TXD of the AVR whitout giving it much thought to it, kept me busy for 2 afternoons. But of course it makes sense that the connections for the comunication function like this now that I think of it.

Perhaps this misinterpretation is more common then most people think and should be more disclosed to prevent such problems.

 

Thank you so much for the help, for a moment I really thought it was a hardware problem that would have been much harder to fix.

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

They "fixed" that cross-connect maddness with spi:

   MOSI connects to MOSI

   MISO connect to MISO  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

Please mark the solution!

 

 

Maybe someone needs to come up with a TTL null modem adapter!  devil

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

Last Edited: Thu. Nov 7, 2019 - 05:41 PM