SparkFun Forums 

Where electronics enthusiasts find answers.

Everything ARM and LPC
By arnaud405
#144509
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
By fll-freak
#144514
Are you using a real time operating system of some sort?
If not, are you getting back to read the data fast enough?
What do you see when it is "Totally out of synch"?
Can you connect your board to a PC using something like Hyperterm to send data and does that work?
By arnaud405
#144516
I am using the provided example getting-started and the pdf below for the communications.
It is on a SAM9-L9260 Board with AT91SAM9260.
When it is out of synch, I can see characters that I receive which are correctly received, but do not start at the beginnig of the frame.
My board is connected to Putty to receive and see characters sent, and the USART0 is connected to a GPS-MOD of Olimex which provides 7 kind of frames such as:
$GPGGA,205700.000,5022.1703,N,00408.3275,W,1,8,1.03,61.7,M,55.2,M,,*76
$GPGSC,20 .....

When I use the example provided on the pdf and when I debug, I can see the 10 first characters of the frame above. But when I run it, the buffer is nor sorted and bad characters are displayed. The aim of my project is to display the time on a LCD screen. The time is given in the first frame : $GPGGA,205700
for example here, it is 20:57:00 according to the GPS module.
I just want to store buffer (i from 7 to 13) from the USART buffer and display it on my LCD.
By arnaud405
#144534
To explain more clearly, I provided my code:
My InitUart()
Code: Select all
#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: Select all
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;
    
    }
  }
}
By fll-freak
#144535
How much experience do you have writing embedded code and specifically interrupt code?

Putting the LCDPutStr inside the ISR seems like a really bad idea to me (but I have not seen the guts of that method).

This code also assumes your GPS strings will ALWAYS be 42 characters long. My understanding of the NMEA (?) interface is that the strings can be of various lengths. This could easily explain why you get out of sync. You would better looking for the CRLF terminator and using that to pull the bytes from the sentence.
By arnaud405
#144537
Thank you for your fast answer.
"How much experience do you have writing embedded code and specifically interrupt code?"
I am a beginner.

"Putting the LCDPutStr inside the ISR seems like a really bad idea to me (but I have not seen the guts of that method). "

Yes, that's why I am trying to code something to get the CRLF terminator.
I can put the LCDPutString somewhere else, so I just need to have a global variable where the copy of the buffer is done.
I just need the first message sent by the GPS (and the last one if possible but I will see later).
The problem is that I do not know how to do.
By fll-freak
#144541
Well, you do have a fairly good start.

An ISR should be short and sweet and 'never' do anything that might cause a significant delay. The best ISRs do the least possible, set a flag and exit.

A non ideal but serviceable solution would be to add bytes to a circular buffer of perhaps 80 bytes inside the ISR. When the current byte is an LF and the previous byte was an CR, then you know you are at the end of a sentence. At this point copy the bytes you are interested into global memory and set a flag. In your main loop, check the flag and when it goes true, disable interrupts, copy the bytes from global memory into your own local storage, and then enable interrupts. This prevents the bytes from getting corrupted should an interrupt occur in the middle of the copy.

A better solution would be to create a circular queue that the ISR feeds and pull and parse those bytes from your main thread. You have to be very careful to properly protect (via interrupt disabling) the pointers as you modify them.

Google reentrancy or multi-thread-safe to get an understanding of this issue.
By arnaud405
#144545
Thank you very much for your answer. I understand the problem. I do not know how to implement flags with this microcontroller. I will try to find an example on the internet. Or is it possible to add a global variable which will be for example:
volatile int sentence _received = TRUE.
My problem is that I do not know how to load the buffer until CRLF.
Code: Select all
char Buffer[42]; // holds received characters
unsigned long nChars = 0; // counts number of received chars
char *pBuffer = &Buffer[0]; // pointer into Buffer

char gps_data[40];
volatile int sentence _received = TRUE;

void Usart0IrqHandler (void) {
  volatile AT91PS_USART pUsart0 = AT91C_BASE_US0; // create a pointer to USART0 structure
  volatile char circular_buff[80];
  // 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[]
  
   while( (circular_buff[i] != 0xA) && (circular_buff[i] != 0xD) ){
	*pBuffer++ = pUsart0->US_RHR;
  	nChars++;
	circular_buff[i] = Buffer[i];
	i++;
    }
    for(int i = 0 ; i<= 42 ; i++){
	gps_data[i]= circular_buff[i];
    }  
    sentence_received = TRUE;

    // yes, redirect buffer pointer to beginning
    pBuffer = &Buffer[0];
    nChars = 0;

    }
  }
}
Does it look good?
and then in my main:
Code: Select all
if (sentence_received ){ 
pUSART0->US_IDR = 0xFFFF; 
LCDPrintStr(gps_data, ....);
pUSART0->US_IER = AT91C_US_RXRDY;
Does it look "good"?
By arnaud405
#144548
I have posted my problem on another forum (at91.com) and a solution has been given. The combination of the code and the flag works properly. I will improve the other possibilities.
Thank you very much for your help.
Best wishes,
Arnaud
By arnaud405
#144551
Thank you very much for your help. It helped me a lot to better understand the problem.
By suresh puli
#162800
Hi arnaud405

Its good to hear that you are getting data through gps.
I am also working on that so please can you help me to sort out the problem.
If you can please share your gps code.