Xmega 128A3U - Uart ISR Buffer receive string

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

 Been busy with a Xmega to enable uart. While polling and ISR interface works fine (especially sending chars & strings from AVR to terminal), I am looking for a way to send strings from my terminal to the AVR.

At this moment I am capable in receiving single chars. In the ISR I see and be able to manipulate the receiving chars, however ever char is handled separately.

 

ISR( USART_RXC_vect ) // Note that this vector name is a define mapped to the correct interrupt vector
{                     // See "board.h"
    USART_RXComplete( &USART_data );
}

So within this block every char is written to RXbuffer:

bool USART_RXComplete(USART_data_t * usart_data)
{
	USART_Buffer_t * bufPtr;
	bool ans;

	bufPtr = &usart_data->buffer;
	/* Advance buffer head. */
	uint8_t tempRX_Head = (bufPtr->RX_Head + 1) & USART_RX_BUFFER_MASK;

	/* Check for overflow. */
	uint8_t tempRX_Tail = bufPtr->RX_Tail;
	uint8_t data = usart_data->usart->DATA;

	if (tempRX_Head == tempRX_Tail) {
	  	ans = false;
	}else{
		ans = true;
		usart_data->buffer.RX[usart_data->buffer.RX_Head] = data;
		usart_data->buffer.RX_Head = tempRX_Head;
	}
	return ans;
}

However I am looking for a way to get a string back from the buffer. Might be that I do understand the buffer part wrong.

I have seen the solutions to get the string based on the direct usart.data and put the string together based on next char till the "\n" is found and then the string is 0 terminated.

 

This can be put in the routine:

ISR( USART_RXC_vect ) 

However then I do not use the buffer... Any ideas on what I am missing.

Btw my starting point was/is AVR1522 for XMEGA. My goal is in the end to be able to implement the DMAC version.

Furthermore at this moment I do not need to receive any strings because I have no application for it. For a different project I am looking at RS485 implementation. And then I would like to be able to exchange info between a sensor array and a control interface.

Are there any best practices for serial communications?

 

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

Why can't you receive strings with what you have?  It looks like you are implementing a buffer of some sort.  I don't know why you are returning something from USART_RXComplete() as the value is discarded in the ISR.  How are you inputting/outputting strings at the application level? puts() and gets() or printf() and scanf()?  I may have some code on a drive at home that does this.  I even recall posting something that involved using the USART and DMA together, although a search for it failed...  I'll see what I have at home and may post something tomorrow.

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

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

Greg_Muth wrote:

Why can't you receive strings with what you have?  It looks like you are implementing a buffer of some sort.  I don't know why you are returning something from USART_RXComplete() as the value is discarded in the ISR.  How are you inputting/outputting strings at the application level? puts() and gets() or printf() and scanf()?  I may have some code on a drive at home that does this.  I even recall posting something that involved using the USART and DMA together, although a search for it failed...  I'll see what I have at home and may post something tomorrow.

 

I have created (inspired on various other examples) a string transmit:

void dbgPutStr(char *str)
{
	uint8_t i = 0;
	uint8_t len;
	bool byteToBuffer;
	len = strlen(str);

	while (i < len) {
		byteToBuffer = USART_TXBuffer_PutByte(&USART_data, str[i]);
		if(byteToBuffer){
			i++;
		}
	}
}

However I am trying to get my string on the AVR out of the buffer. Currently I have:

 while(1)
    {
		 i = 0;
		 while (i < 20)
		 {
			 if (USART_RXBufferData_Available(&USART_data))
			 {
				 receiveArray[i] = USART_RXBuffer_GetByte(&USART_data);
				 if (receiveArray[i] == '\0')------->>> NOT working
				 {
					 receiveArray[i++]='\0';
					 break;
				 }
				 else
				 i++;
			 }
		 }
		dbgPutStr(receiveArray);
		dbgPutStr("\r\n");
		  
    }

When I use the above code I do not get the string back (it stays in the loop until the array is full (20)). If I send a string to the AVR ending on e.g. "Q" and replace \0 with 'Q' it will respond, but the last char is discarded.

 

Furthermore your examples are welcome of course.

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

What is sending data to the AVR? Is it actually sending a null character to terminate the string?

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

We seem to be repeating this thread: https://www.avrfreaks.net/forum/a...

 

 

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

christop wrote:

What is sending data to the AVR? Is it actually sending a null character to terminate the string?

 

I am using realterm and indeed I was NOT using the CR and LF :( why... because I did not make the connection with \n and LF.

Looked it up at http://en.wikipedia.org/wiki/New... after your comment for if it is enabled.

 

Furthermore now the string receive from main works.

 

i = 0;
		while (i < 20)
		{
			if (USART_RXBufferData_Available(&USART_data))
			{
				receiveArray[i] = USART_RXBuffer_GetByte(&USART_data);
				if (receiveArray[i] == '\n')
				{
					receiveArray[i++]='\0';
					break;
				}
				else
				i++;
			}
		}
		dbgPutStr(receiveArray);
		dbgPutStr("\r\n");

Now I can continue with my testing. Probably will put some questions in this thread later.

Going to investigate to run this from ISR.

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

Okey, atm I am a little advanced in my search to create a string based on a UART interrupt.

I understand that every ISR triggers the code to transfer the received char to the buffer (currently 3 big). The buffer works as FIFO. more in means only first 3 out. Rest is discarded.

 

At the moment I am polling the buffer to see if there is Bufferdata available and when there is I am extracting it and building the string. This works fine.

 

However I am wondering what would be best practice:

- Flag in ISR to make main thread aware of transfer

- Keep polling like I do now with the risk of losing chars (even if you raise the buffer size)

- Do the string stuff in the ISR (putting the string together with or without buffer?)

 

Could someone elaborate on this a little more?

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

Sorry it took so long to get back to you, but I had other things going on.  I found some code that does buffering of USART I/O using interrupts.  This example uses ASF code.  I may have something in storage that uses the DMA as well, but I don't know when I will be able to get at it.  As to your most recent reply:

 

  • Having the ISR input (or output) a char then set a flag is a good approach depending on how much data you are transferring and at what rate.  The USART has a couple bytes of buffer on the receive side, so as long as you check the flag at a rate faster than  one-third the rate at which bytes are received, you should be OK.
  • Polling wastes CPU cycles and, as your application becomes more complex and requires more CPU cycles, you may not be able to poll fast enough.
  • The buffering in the attached project is done in the ISR.  If memory serves, the ISR takes ~2us to complete @ 32MHz.  I've used this method with multiple USARTs connected to each other at 115,200bps without problems.

 

The attached project assigns the USART to stdin, stdout and stderr, so you can use puts()/gets() or scanf()/printf() to do input and output.

 

Hope this helps!

Attachment(s): 

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

Last Edited: Thu. Apr 16, 2015 - 11:09 PM