Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
john777
PostPosted: Apr 09, 2012 - 08:31 AM
Hangaround


Joined: May 18, 2008
Posts: 159


Till now I’ve used simple UART routines in my projects – get some chars, send some messages. Now I need more complicated stuff – buffering and parsing commands from a terminal. So I’ve decided to use Proycon AVR Library, included it in my project and….
Not quite sure how to properly deal with those functions and variables. May be someone acquainted with the library could give me some example?
 
 View user's profile Send private message  
Reply with quote Back to top
ChaunceyGardiner
PostPosted: Apr 09, 2012 - 11:09 AM
Posting Freak


Joined: Mar 09, 2012
Posts: 1452
Location: North Carolina, USA

A simple Google search reveals that that library comes with examples. Did you go through them ?

_________________
Sid

Life... is a state of mind
 
 View user's profile Send private message  
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 12:04 PM
Hangaround


Joined: May 18, 2008
Posts: 159


Yep.I went through the examples. There are no examples regarding UART.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Apr 09, 2012 - 01:28 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18542
Location: Lund, Sweden

In the Procyon documentation one can find this passage:
Quote:
By far, the most common use for serial communications on AVR processors is for sending information and data to a PC running a terminal program. Here is an exmaple:
Code:
    uartInit();                 // initialize UART (serial port)
    uartSetBaudRate(9600);      // set UART speed to 9600 baud
    rprintfInit(uartSendByte);  // configure rprintf to use UART for output
    rprintf("Hello World\r\n"); // send "hello world" message via serial port

Can we assume that you have tried that?

Where do you want to go from here? I suppose the next step would be to try out communication the other way, e.g. from PC to AVR. There is a fucntion in the documentation:

Quote:
u08 uartReceiveByte ( u08 * data )

Gets a single byte from the uart receive buffer. Function returns TRUE if data was available, FALSE if not. Actual data is returned in variable pointed to by "data". Example usage:

Code:
    char myReceivedByte;
    uartReceiveByte( &myReceivedByte );


That code snippet dos not take the return value into consideration. Assuming we want to display the ASCII code of any received character on LEDs on PORTA then I would code something like (sketchy, untested):

Code:
if (uartReceiveByte(&myReceivedByte)==TRUE)
{
   PORTA = myReceivedByte;
}


For testing if the buffering actually works, you could do something like this:
Code:
if (uartReceiveByte(&myReceivedByte)==TRUE)
{
   PORTA = myReceivedByte;
   _delay_ms(1000);
}

and type a few characters quicky at the PC side. You should see the ASCII codes for the characters displayed with 1 second intervals.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 02:07 PM
Hangaround


Joined: May 18, 2008
Posts: 159


Thanks a lot JohanEkdahl!

I changed ISR a little bit to get a message from terminal:
Code:

ISR(USART0_RX_vect)
{
  char c;
  // get received char
  c = UDR0;

  if(c == '\r') //got the end of the message
  {
     rx_data_received = 1;  //raise flag
  }
  else  //not the end of the message
  {   
     // check if there's space
    if( !bufferAddToEnd(&uartRxBuffer, c) )
    {
   // no space in buffer
   // count overflow
   uartRxOverflow++;
    }
  }
}


Now I want to see what I got in the buffer
in main.c
Code:

if(rx_data_received)
{
  rx_data_received = 0;
  //just fore debug to see what i got
   SendString(uartRxBuffer.dataptr);
}

And i get an empty line on my terminal.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Apr 09, 2012 - 02:52 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18542
Location: Lund, Sweden

Why are you hacking about in the internal implementation? One point with Pascal Stangs library is that you use the API he supplies, i.e. only call these functions:
Code:
void  uartInit (void)
void  uartInitBuffers (void)
void  uartSetRxHandler (void(*rx_func)(unsigned char c))
void  uartSetBaudRate (u32 baudrate)
cBuffer *  uartGetRxBuffer (void)
cBuffer *  uartGetTxBuffer (void)
void  uartSendByte (u08 data)
int  uartGetByte (void)
u08  uartReceiveByte (u08 *data)
u08  uartReceiveBufferIsEmpty (void)
void  uartFlushReceiveBuffer (void)
u08  uartAddToTxBuffer (u08 data)
void  uartSendTxBuffer (void)
u08  uartSendBuffer (char *buffer, u16 nBytes)

By sticking your hand into the innards of the implementation you risk breaking it. Specifically, hacking the ISR as the first thing you do might not be the best thing to do.

I like to see a ring buffer as only that, it buffers so tat I can deal with the incoming data at another time. I would not make it a parser also.

I could moderate that slightly and say that one might complement the Procyon library with a function that returns true if an End-of-line character has been seen or not (if the language to be parsed is constructed in such a way that it is always about whole lines). You'd use that to see if it is time to parse yet, and then the parser would use e.g. uartGetByte or uartReceiveByte to get charachters to consume.

In my head it is much about having one "layer" for each thing to do. Buffering is one layer, and solves the problems of data bursts and intermittent problems with consuming incoming data.

Parsing is another layer - has very little to do with buffering. Ideally, a parser should be as decoupled as possible from the mechanism that supplies it with a stream of characters. One nice thing about doing things this way is that you can test a lot of your code in a more friendly environment than testing it on an AVR. E.g. the parser, decoupled from the producer of characters, could just as well be tested in a C ide that executes the code on the PC. (There are many such nice IDEs available for no money at all: E.g. Microsoft Visual Studio Expresss Edition, NetBeans with a GCC plugin, Eclipse with a GCC plugin and something called "Pelles C" are four that I come to think of right away.) Dividing things into separate layers or modules also helps you by forcing you to think about only one thing at a time, and you might as well face it (if you're just slightly like I am) - your brain will appreciate every simplification it can get.

Do not try to implement buffering and parsing in the same layer. It will bring you much more grief than joy.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 03:11 PM
Hangaround


Joined: May 18, 2008
Posts: 159


I see. But i want to pass the buffer as an argument to a parsing function. So it should be like this:
void ParseString(uartGetRxBuffer)?
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Apr 09, 2012 - 03:20 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18542
Location: Lund, Sweden

No. The uartGetBuffer funxtion return the buffer structure. What is it you want to pass to the parser? A string of characters, nothing more. Again, why should the parser be forced to get it's string of characters out of a cBuffer?

Did you understand my comment about as little coupling between the bufer and the parser as possible?
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Apr 09, 2012 - 04:10 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62270
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

No. The uartGetBuffer funxtion return the buffer structure.

Don't even do that. What you actually want is to extract the characters in the buffer in received order. So the functions you use to access them are either uartGetByte (high level) or uartReceiveByte (low level).

The whole point of a FIFO is that the implementation is supposed to be hidden from you and you just consume characters from the buffer, one at a time when you are ready for them.

Now you can either parse your received data using a state machine where maybe you look for a character at a time so if you could receive "cat", "dog", "chair" you look at the first character. If it is 'd' you already know you have "dog". If it is 'c' your state machine moves on to looking at the next character. If it is 'a' then you have "cat", if it is 'h' you have "chair" and so on.

The alternative is to sit in a loop doing uartGetByte() calls and filling a local array with each character in turn until you see '\n' or '\r' (or perhaps ','?) which marks the end of a word/sentence. Now you use strcmp() or strstr() (or even strchr()?) to find out what word you have in your buffer. In this case this buffer is a different, local one, not the FIFO that is being used for interrupt buffering.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 04:20 PM
Hangaround


Joined: May 18, 2008
Posts: 159


I got totally confused.
I type a command in a terminal, while typing micro controller gets chars in some buffer(array of chars). When i hit '\r' character it indicates the end of the command. From this point i should take the received command and parse it, shouldn't i?
 
 View user's profile Send private message  
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 04:29 PM
Hangaround


Joined: May 18, 2008
Posts: 159


[quote="clawson"]
Quote:

The whole point of a FIFO is that the implementation is supposed to be hidden from you and you just consume characters from the buffer, one at a time when you are ready for them.


If so I'd like to take the buffer(already prepared for me by low level functions) and use (parse) it!
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Apr 09, 2012 - 04:45 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62270
Location: (using avr-gcc in) Finchingfield, Essex, England

But it's circular - you don't know where the start and end are. Let's say you have a 10 character buffer. 7 characters have already been received and used. Then "hello\n" arrives. The array therefore contains:
Code:
l o \n X X X X h e l

If you search for "hello" in this you will not find it (unless you have a clever search that can handle wrapping.

Instead what you should do is create your own local buffer:
Code:
X X X X X X X X X X

Then keep doing uart_GetByte() until it returns -1 and storing each received character:
Code:
h e l l o \n X X X X

Now you can use strstr() or strcmp() or whatever you like to find "hello" in this buffer.

This is a different buffer with a different purpose to the FIFO being used by the interrupt receive routine. That FIFO is just there to catch characters that might otherwise be lost but it's not where you do your string processing.

As I say if you cannot afford the space for a second "consumer" buffer (while the FIFO is a "producer" buffer) then consider processing the characters one at a time. Call uartGetByte() onec - do you have 'h'? Call it again, do you have 'e'? and so on...

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 05:04 PM
Hangaround


Joined: May 18, 2008
Posts: 159


clawson wrote:
But it's circular - you don't know where the start and end are. Let's say you have a 10 character buffer.7 characters have already been received and used. Then "hello\n" arrives.


To avoid this situation, on receiving the end of the command char ('\r'),I'd copy the buffer in my "work" buffer and clear it.

clawson wrote:

Then keep doing uart_GetByte() until it returns -1 and storing each received character:

By polling it? What ISR for?

clawson wrote:

This is a different buffer with a different purpose to the FIFO being used by the interrupt receive routine. That FIFO is just there to catch characters that might otherwise be lost but it's not where you do your string processing.

How do i know the byte is lost? At what point i get access to FIFO, and why? How do i use FIFO capability?
 
 View user's profile Send private message  
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 05:19 PM
Hangaround


Joined: May 18, 2008
Posts: 159


I understood...i suppose.
The function int uartGetByte(void) directly accessing FIFO, so i can pull all chars received, build a string and parse it. Still need to alter ISR, to add command received flag.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Apr 09, 2012 - 06:36 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18542
Location: Lund, Sweden

Quote:

By polling it? What ISR for?

To get the byte out of the uart and into some safe place before the next byte in a burst arrives. The ISR should do as little as possible.

Trying to do everything possible in the ISR is generally a very bad strategy, and most likely will come back and bite you.

John, you've been here for four years. How can you possibly have missed the "ISRs should be as short as possible" posts that we put here more or less on a weekly basis?
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Apr 09, 2012 - 06:58 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62270
Location: (using avr-gcc in) Finchingfield, Essex, England

The entire RXC ISR and FIFO is simply to make it appear as if you have a UART with a 16/32/64/whatever byte buffer in it. This means your foreground software can just treat it as if it were a polled device but knowing that nothing will ever get lost (unless you don't consume at the rate of production and the buffer fills up completely).

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
john777
PostPosted: Apr 09, 2012 - 07:04 PM
Hangaround


Joined: May 18, 2008
Posts: 159


Thank you guys! Now i see the whole picture.
P.S. I never went so far with UART, did simple things, it's kinda new to me.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Apr 09, 2012 - 07:43 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18542
Location: Lund, Sweden

Just to push the point home: You might already have done everything you ever will do with a UART. As I said - the parser has nothing to do with the source of the things it should parse. It should work the same way if data came over an I2C interface or by pigeon. Smile
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits