Atmel website | ARM Community | AVR freaks | Technical Support
Banner
 FAQ •  Search •  Register •  Login 

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 23 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: USART and CRLF
PostPosted: Tue May 15, 2012 2:28 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Hi everyone,
I am trying to get characters coming from a GPS module, connect on my USART0 SAM9260 board.
I used this tutorial http://www.sparkfun.com/datasheets/DevT ... ations.pdf
and I adapted it to my board. It works properly when I debug (and watch the data in the buffer), but when I run it, it is totally out of synch. My peripherial seems to be too slow. It is 19200 baud.
Do you have an example of USART service routine which starts the reception when a Frame ID is received and stops when a CLRF character is received?
Regards,
Arnaud


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Tue May 15, 2012 8:44 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
To explain more clearly, I provided my code:
My InitUart()
Code:
#include <board.h>
#include "irq/irq.h"
//#include "headers.h"
#ifndef AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
// Interrupt is internal and uses a logical 1 level.
#define AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE
#endif
//extern unsigned enableIRQ(void);
void Usart0IrqHandler(void);

// *******************************************************
// External Globals
// *******************************************************
extern char Buffer[]; // holds received characters
extern unsigned long nChars; // counts number of received chars
extern char *pBuffer; // pointer into Buffer
// *******************************************************
// Function Prototypes
// *******************************************************

void InitUSART0(void) {
// enable the usart0 peripheral clock
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; // pointer to PMC data structure
pPMC->PMC_PCER = (1<<AT91C_ID_US0); // enable usart0 peripheral clock
// set up PIO to enable USART0 peripheral control of pins
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOB; // PIOA au lieu de PIOB // pointer to PIO data structure
// old pPIO->PIO_PDR = AT91C_PB9_RXD2 | AT91C_PB8_TXD2;
// old pPIO->PIO_ASR = AT91C_PIO_PB8 | AT91C_PIO_PB9;
//pPIO->PIO_BSR = 0;

pPIO->PIO_PDR = AT91C_PB5_RXD0 | AT91C_PB4_TXD0;
pPIO->PIO_BSR = AT91C_PIO_PB5 | AT91C_PIO_PB4;
pPIO->PIO_ASR = 0; // peripheral A function set to "no effect"
// set up the USART0 registers
volatile AT91PS_USART pUSART0 = AT91C_BASE_US0; // create a pointer to USART0 structure

pUSART0->US_CR = AT91C_US_RSTRX | // reset receiver
AT91C_US_RSTTX | // reset transmitter
AT91C_US_RXDIS | // disable receiver
AT91C_US_TXDIS; // disable transmitter

pUSART0->US_MR = AT91C_US_PAR_NONE | // no parity
0x3 << 6 |// 8-bit characters
AT91C_US_NBSTOP_1_BIT;  // 1 stop bit

pUSART0->US_IER = 0x00; // no usart0 interrupts enabled (no effect)
pUSART0->US_IDR = 0xFFFF; // disable all USART0 interrupts
pUSART0->US_BRGR = 0x143; // 19200 = 0x143; // CD = 0x139 (313 from above calculation) FP=0 (not used)
pUSART0->US_RTOR = 0; // receiver time-out (disabled)
pUSART0->US_TTGR = 0; // transmitter timeguard (disabled)
pUSART0->US_FIDI = 0; // FI over DI Ratio Value (disabled)
pUSART0->US_IF = 0; // IrDA Filter value (disabled)

// Set up the Advanced Interrupt Controller (AIC) registers for USART0
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC; // pointer to AIC data structure
pAIC->AIC_IDCR = (1<<AT91C_ID_US0); // Disable USART0 interrupt in AIC
pAIC->AIC_SVR[AT91C_ID_US0] = (unsigned int)Usart0IrqHandler;// Set the USART0 IRQ handler address in AIC Source
 // Vector Register[6]
pAIC->AIC_SMR[AT91C_ID_US0] =(AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 0x4 ); // Set the interrupt source type(level-sensitive) and
 // priority (4) in AIC Source Mode Register[6]
pAIC->AIC_IECR = (1<<AT91C_ID_US0); // Enable the USART0 interrupt in AIC
// enable the USART0 receiver and transmitter
pUSART0->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
// enable the USART0 receive interrupt
pUSART0->US_IER = AT91C_US_RXRDY; // enable RXRDY usart0 receive interrupt
pUSART0->US_IDR = ~AT91C_US_RXRDY; // disable all interrupts except RXRDY
// set up buffer pointer and character counter
pBuffer = &Buffer[0];
nChars = 0;
// enable IRQ interrupts
IRQ_EnableIT(AT91C_ID_US0);//enableIRQ();
// at this point, only the USART0 receive interrupt is armed!
}


and my Interruption:
Code:
char Buffer[42]; // holds received characters
unsigned long nChars = 0; // counts number of received chars
char *pBuffer = &Buffer[0]; // pointer into Buffer

void Usart0IrqHandler (void) {
  volatile AT91PS_USART pUsart0 = AT91C_BASE_US0; // create a pointer to USART0 structure
  // determine which interrupt has occurred
  // assume half-duplex operation here, only one interrupt type at a time
  if ((pUsart0->US_CSR & AT91C_US_RXRDY) == AT91C_US_RXRDY) {
  // we have a receive interrupt,
  // remove it from Receiver Holding Register and place into buffer[]
  *pBuffer++ = pUsart0->US_RHR;
  nChars++;
  // check if 10 characters have been received
  if (nChars >= 42) {
   
    char gps_time[9]={Buffer[7],Buffer[8],':',Buffer[9],Buffer[10],':',Buffer[11],Buffer[12],'\0'};
    LCDPutStr(gps_time,20,30,LARGE, WHITE,RED );
    // yes, redirect buffer pointer to beginning
    pBuffer = &Buffer[0];
    nChars = 0;
   
    }
  }
}


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Tue May 15, 2012 10:52 pm 
Offline

Joined: Sat Oct 30, 2010 6:04 pm
Posts: 784
The thing is, the USART is dumb, it doesn't know about NMEA sentences or how to sync or parse data. You have to implement that.

Here's some code that is slightly less hopeless.
Code:
char Buffer[200]; // holds received characters, can get quite long
int nChars = 0; // counts number of received chars

void Usart0IrqHandler (void)
{
  volatile AT91PS_USART pUsart0 = AT91C_BASE_US0; // create a pointer to USART0 structure
  // determine which interrupt has occurred
  // assume half-duplex operation here, only one interrupt type at a time
  if ((pUsart0->US_CSR & AT91C_US_RXRDY) == AT91C_US_RXRDY)
  {
    char ch;

  // we have a receive interrupt,
  // remove it from Receiver Holding Register and place into buffer[]

    ch = pUsart0->US_RHR;

    // NMEA sentence in the form $GPxxx,,,,*xx<CR><LF>

    if (ch == '$') // Resync line
      nChars = 0;

    Buffer[nChars++] = ch; // Store char and advance

    if (ch == 0x0D) // CR, we ignore LF
    {
      Buffer[nChars - 1] = 0; // Place a NUL so C string functions actually work

      // Should check for the right $GPxxx sentence here, and perhaps parse it properly

      if ((Buffer[0] == '$') && (Buffer[1] == 'G') && (Buffer[2] == 'P'))
      {
        char gps_time[9]={Buffer[7],Buffer[8],':',Buffer[9],Buffer[10],':',Buffer[11],Buffer[12],'\0'};
        LCDPutStr(gps_time,20,30,LARGE, WHITE,RED ); // Doing this under interrupt, really?
      } // CptTitanic@gmail.com

      nChars = 0; // reset
    }
    else if (nChars >= sizeof(Buffer)) // Enough to hold the biggest NMEA sentence, YMMV
      nChars = 0; // Wrap
  }
}


I wouldn't be parsing floating point numbers, assuming fixed character offsets, and printing to an LCD device under interrupt. Ideally the interrupt should just frame the sentences, and dispatch full ones to a worker task for processing.


Last edited by CptTitanic on Tue May 15, 2012 11:10 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Tue May 15, 2012 11:09 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Thank you very much for your fast and relevant answer.
This is very useful for me.
It works quite properly. A problem still remains; every 4 seconds, strange characters are displayed and then it becomes normal again.
I will try to add a flag and LCDPrintStr in the main.


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Tue May 15, 2012 11:23 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
It is better with a flag and the LCDPrintStr in the main. Thanks a lot for this answer.
I will try to improve this code and obtain all the things that I want.
Best Wishes,
Arnaud


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Tue May 15, 2012 11:43 pm 
Offline

Joined: Sat Oct 30, 2010 6:04 pm
Posts: 784
Perhaps you're getting a $GPGSV sentence every four seconds?

If you are extracting the time from a specific sentence $GPGLL, $GPRMC, or whatever, you should just test that one, and not one with a different format.

Different receivers can report fields in different formats, for instance if they are blank, or express position/time to more decimal places.


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Tue May 15, 2012 11:49 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Absolutely. I have completed the full sentence at the beginning. There is no more confusions between the different frames.
Thank you.


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Wed May 16, 2012 1:14 am 
Offline

Joined: Thu Apr 19, 2007 10:15 pm
Posts: 330
Location: USA
The preferred practice is to have only I/O and error & recovery processing in the interrupt service routine (ISR). When servicing a RX interrupt, the received char should be stored in the next available location in the (ring) buffer (and the pointer needs to be bumped). Maintenance items include ensuring that the ring buffer has not wrapped, parity & framing were okay, and there was no receiver overrun.

Parsing the input immediately in the ISR is rarely necessary. Perhaps this initially seems easier/faster to code it that way, but in the end interrupt latency, system responsiveness and program modularity can suffer. Parsing the input should be deferred or delegated to an interruptable task. This segregates the I/O (which is a HW-dependent device-driver function) from the input parsing (which is a line-discipline or protocol function).

The more effort you put into laying the software (placing each level of functionality in its own routine/module) will result in more portable and maintainable software. You should not view this ISR & parsing as just "input processing", and not separate the trees from the forest. When functionality is layered, problems are more easily resolved. If the data is not in the receive buffer, then the issue is in the driver. If the data is in buffer, but the app is not getting it, then the issue is in the parser. When something like "it is totally out of synch" happens, there are just a few things to inspect to start narrowing down to possible causes.

Regards


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Wed May 16, 2012 9:32 am 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Ok I see. It is more complicated that expected. I will try to improve it later.
I am doing tests for the moment.
I am trying to get another data in another message (GPVTG):
Code:
 if ((check_speed==1) && (Buffer[0] == '$') && (Buffer[1] == 'G') && (Buffer[2] == 'P')  && (Buffer[3] == 'V') && (Buffer[4] == 'T') && (Buffer[5] == 'G'))
         {                   
          for(int i = 0 ; i <= 20 ; i++){
            gps_speed[i]= Buffer[i];
          }
          check_speed = 0;
          flag_speed = 1;
         }

the int check_speed is 1 when it is already gone in the other message. The problem is that it never goes in this condition because the buffer always get the GPGGA message (because of the LR terminator maybe).
Do you have any idea how to overcome this problem?


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Wed May 16, 2012 12:28 pm 
Offline

Joined: Thu Apr 19, 2007 10:15 pm
Posts: 330
Location: USA
arnaud405 wrote:
the int check_speed is 1 when it is already gone in the other message. The problem is that it never goes in this condition because the buffer always get the GPGGA message (because of the LR terminator maybe).


I don't understand the significance of check_speed, and I really don't care As I see it, and tried to explain in my previous post about layering the code, you have to separate functionality. I would not combine a test of the receive state or condition with parsing the input.

I'd setup the UART/USART Rx ISR to store all received bytes in a large ring buffer and wake up an input task. This ISR level can handle either binary or text input from the serial line.

The input task would respond to an application getline() request by filling the supplied buffer with the received string extracted from the ring buffer. The input line is delimited by a \n, so all received input since the last getline() request is returned on this call (with all ASCII control chars stripped out) as a null-terminated string. This level handles the serial input as a text stream, and only breaks up the input into variable-length text records aka lines.

At the application level, which is aware of the message format
Code:
   retstatus = getline(linebuf);
   /* search for preamble '$' character */;
   if ((lstartp = strchr(linebuf, '$')) == NULL) {
            ...
   }
   /* search for comma delimiter following keyword */
   if ((endkeyp = strchr(lstartp, ',')) == NULL) {
            ...
   }
   /* extract message keyword string from line buffer */
   strncpy(src_key, lstartp + 1, endkeyp - lstartp - 1);


To parse input that has keywords to identify the message, I'd define a set of message identifiers:
Code:
typedef enum {         /* received message types */
   MT_NULL = 0,
   MT_GPGSV = 1,
   MT_GPVTG,
   MT_GPGLL,
   MT_GPRMC,
   MT_GPGGA
} mesg_t;

And also define the comparison table for identifying the received keywords:
Code:
typedef struct mesg_def {
   mesg_t   mesg_id;
   char           *keywd;
} mesg_def_t;

mesg_def_t   mesg_keyword[] = {
   {MT_GPGSV, "GPGSV"},
   {MT_GPVTG, "GPVTG"},
   {MT_GPGLL, "GPGLL"},
   {MT_GPRMC, "GPRMC"},
   {MT_GPGGA, "GPGGA"},
   {MT_NULL, ""}
};

Compare the received keyword string to the list of valid keys using a string comparison routine:
Code:
   kwp = mesg_keyword;
   mtype = MT_NULL;

   do {
      if (strcmp(src_key, kw->keywd) == 0) {
         mtype = kwp->mesg_id);
         break;
      }
      ++kwp;
   } while (kwp->mesg_id != MT_NULL);

Once the message type has been identified, then the message contents can be processed:
Code:
   switch (mtype) {
      case MT_NULL:
      default:
         /* need to handle unknown message type gracefully */
         break;
      case MT_GPGSV:   /* GSV message */
         break;
      case MT_GPVTG:   /* VTG message  */
         if (check_speed == 1) {   /*  */
            ...
         } else {
            ...
         }
         break;
      case MT_GPGLL:        /* GLL message  */
         break;
      case MT_GPRMC:   /* RMC message */
         break;
      case MT_GPGGA:   /* GGA message  */
         break;
   }


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Wed May 16, 2012 2:33 pm 
Offline

Joined: Sat Oct 30, 2010 6:04 pm
Posts: 784
arnaud405 wrote:
The problem is that it never goes in this condition because the buffer always get the GPGGA message (because of the LR terminator maybe).
Do you have any idea how to overcome this problem?


You're clutching at straws there, all the messages should have a terminating <CR><LF> pair. If you are unsure, you need to dump and review the data you're actually receiving.

If you are more comfortable debugging/developing C code on a PC, then try recording the data stream from a receiver to a file, and then write a program to read through and parse that data.


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Thu May 17, 2012 10:04 am 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Thank you both of you for your answers.
As I said, I am a beginner.
I will try to write a new code as blue_z said.
When you say input task, it means that it is a new function? It will contain the framgent of codes that you provided?
In the ISR, I will do a ring buffer like in CptTitanic's example?
I do not understand when and how the ISR will wake up the input task. If this task just fill in a buffer, which "condition" will make it wake up the input task?
I am sorry for all my questions, I am a bit lost in this explanation.


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Thu May 17, 2012 11:50 am 
Offline

Joined: Thu Apr 19, 2007 10:15 pm
Posts: 330
Location: USA
arnaud405 wrote:
When you say input task, it means that it is a new function?


I was referring to a(n advanced) technique to improve ISR performance. The "input task"would be a companion task, or tasklet, to the Rx ISR. When you mention "function" you are probably only thinking of source code organization, i.e. a procedure written in C. But a "task" or "tasklet" is an execution path of code that may or may not be synchronized with other tasks.
Here's a link to "Tasklets and Bottom-Half Processing" from the book "Linux Device Drivers":
http://www.xml.com/ldd/chapter/book/ch09.html#t5
I came up with something similar for a roll-your-own microkernel on a Z80 uP a long time ago. So having a Linux kernel is not a requirement for implementing an ISR with an "input task".

Quote:
It will contain the framgent of codes that you provided?

No, please read it again. That sample code is for parsing bytes that have already been through the "device driver" and "line discipline" processing.

Quote:
In the ISR, I will do a ring buffer like in CptTitanic's example?

He did not provide an example of a ring buffer. If you do a search, I'm sure you can find examples of a ring buffer in an ISR. Just remember that manipulation of the buffer's read and write pointers have to be protected by a mutex (mutual exclusion lock).

Quote:
I do not understand when and how the ISR will wake up the input task. If this task just fill in a buffer, which "condition" will make it wake up the input task?

Every char placed in the ring buffer should wake up the "input task", since any one of those bytes could be the line terminator. The wakeup mechanism could be a semaphore: the ISR does a signal() and the "input task" is waiting() to notified of new/more input in the ring buffer that needs to be moved to a line buffer.

Quote:
I am sorry for all my questions, I am a bit lost in this explanation.

That's understandable. This is not the easy or simple way to implement this functionality. I've encountered some embedded programmers that don't know how (or bother) to do this stuff. I'm just trying to point out the optimal method. Your original code was "hopeless" (as cpttitanic alluded), so rather than try to fixup a weak design why not start with a clean alternative? Feel free to ignore it.

I hope you are already familiar with synchronization and mutual exclusion concepts. And at some point you have to make the distinction between the code you see on the screen and how that is related yet distinct from what the CPU is executing as a task or ISR. The weak programmer is unable to separate the code from a task.

Regards


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Thu May 17, 2012 12:58 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Thank you very much for all the details you gave me. I will figure it out.
For the moment, I will learn and stop coding.
Regards


Top
 Profile  
 
 Post subject: Re: USART and CRLF
PostPosted: Tue May 29, 2012 7:54 pm 
Offline

Joined: Sat May 05, 2012 10:47 am
Posts: 32
Hi all,
I am still working on my uart.
I would like to know if my uartInit is ready to send messages?
I am trying to send a buffer with a sentence to my device, but I do not know how to do. I tried to understand my problem with the .pdf created by James Lynch but I am a bit lost in it.
I would like to send a message, and once it is sent, waiting for the answer and get the data back.
Do you have any idea?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 23 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: