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
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?
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.
To explain more clearly, I provided my code:
My InitUart()
#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:
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;
}
}
}
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.
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.
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.
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.
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:
if (sentence_received ){
pUSART0->US_IDR = 0xFFFF;
LCDPrintStr(gps_data, ....);
pUSART0->US_IER = AT91C_US_RXRDY;
Does it look “good”?
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
That is certainly a workable solution. Now you can mark this thread as solved using the little check box next to your last post.
Thank you very much for your help. It helped me a lot to better understand the problem.
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.