...
The GPS continuously sends data as soon as it is plugged in. It sends data in the following data format:
Code Block |
---|
|
typedef struct _GPSData {
long double latitude; //8 Bytes
long double longitude; //8 Bytes
float time; //4 Bytes
float speed;
int altitude;
int heading;
char satellites; //1 Byte
char positionFix;
} GPSData;
|
In order to properly configure this connection the following code is used:
Code Block |
---|
|
GPSData gpsData __attribute__((space(dma)));
/*
*
*/
void __attribute__((__interrupt__, no_auto_psv)) _DMA2Interrupt(void){
newGPSDataAvailable = 1;
IFS1bits.DMA2IF = 0;// Clear the DMA0 Interrupt Flag
}
void init_DMA2(){
IFS1bits.DMA2IF = 0;
IEC1bits.DMA2IE = 1;
DMA2CONbits.AMODE = 0b00; //Register Indirect Mode
DMA2CONbits.DIR = 0; //Transfer from SPI to DSPRAM
DMA2CONbits.MODE = 0b00; //Transfer continuously
DMA2CONbits.SIZE = 1; //Transfer bytes (8 bits)
DMA2STA = __builtin_dmaoffset(&gpsData); //Primary Transfer Buffer
DMA2PAD = (volatile unsigned int) &SPI2BUF; //Peripheral Address
DMA2CNT = sizeof(GPSData) - 1; //+1 for checksum //DMA Transfer Count Length
DMA2REQ = 0b0100001; //IRQ code for SPI2
DMA2CONbits.CHEN = 1; //Enable the channel
}
|
...
The data being sent to the PM chip from the AM chip is in the form of:
Code Block |
---|
|
typedef struct _AMData {
WaypointWrapper waypoint;
float pathGain;
float orbitGain;
float calibrationHeight;
char command;
char checksum;
} AMData;
|
Vice-versa, the data being sent to the AM chip from the PM chip is in the form of:
Code Block |
---|
|
typedef struct _PMData {
float time; //4 Bytes - hhmmss.ssss
long double latitude; //8 Bytes - ddd.mmmmmm
long double longitude; //8 Bytes - ddd.mmmmmm
float speed; //KM/H
float altitude;
int sp_Altitude; // Meters
int heading; //Degrees
int sp_Heading; //Degrees
char satellites; //1 Byte
char positionFix; //0 = No GPS, 1 = GPS fix, 2 = DGSP Fix
char targetWaypoint;
char batteryLevel;
} PMData;
|
The initialization process is extremely similar for both chips (PM and AM). Each chip requires a DMA channel to read the incoming data, as well as to write the outgoing data. As a result, both the AM chip and the PM chip have the same setup with a few different variables names:
Code Block |
---|
|
void __attribute__((__interrupt__, no_auto_psv)) _DMA0Interrupt(void){
#if !PATH_MANAGER
if (!transmitInitialized){
transmitInitialized = 1;
DMA1REQbits.FORCE = 1;
while (DMA1REQbits.FORCE == 1);
}
#endif
newDataAvailable = 1;
IFS0bits.DMA0IF = 0;// Clear the DMA0 Interrupt Flag
}
void __attribute__((__interrupt__, no_auto_psv)) _DMA1Interrupt(void){
IFS0bits.DMA1IF = 0;// Clear the DMA0 Interrupt Flag
}
void init_DMA0(){
IFS0bits.DMA0IF = 0;
IEC0bits.DMA0IE = 1;
IPC1bits.DMA0IP = 7; //Highest Priority
DMACS0 = 0; //Clear any IO error flags
DMA0CONbits.DIR = 0; //Transfer from SPI to DSPRAM
DMA0CONbits.AMODE = 0b00; //With post increment mode
DMA0CONbits.MODE = 0b00; //Transfer continuously
DMA0CONbits.SIZE = 0; //Transfer words (16 bits)
#if PATH_MANAGER
DMA0STA = __builtin_dmaoffset(&amData); //Primary Transfer Buffer
#else
DMA0STA = __builtin_dmaoffset(&pmData); //Primary Transfer Buffer
#endif
DMA0PAD = (volatile unsigned int) &SPI1BUF; //Peripheral Address
DMA0CNT = PATH_MANAGER?(sizeof(AMData)/2 + sizeof(AMData) % 2 - 1):(sizeof(PMData)/2 + sizeof(PMData) % 2 - 1); //+1 for checksum //DMA Transfer Count Length
DMA0REQ = 0x000A;//0b0100001; //IRQ code for SPI1
DMA0CONbits.CHEN = 1; //Enable the channel
}
void init_DMA1(){
IFS0bits.DMA1IF = 0;
IEC0bits.DMA1IE = 1;
IPC3bits.DMA1IP = 7;
DMACS1 = 0; //Clear any IO error flags
DMA1CONbits.DIR = 1; //Transfer from DSPRAM to SPI
DMA1CONbits.AMODE = 0b00; //Without post increment mode
DMA1CONbits.MODE = 0b00; //Transfer continuously, ping ponging between buffers
DMA1CONbits.SIZE = 0; //Transfer words (16 bits)
#if PATH_MANAGER
DMA1STA = __builtin_dmaoffset(&pmData); //Primary Transfer Buffer
#else
DMA1STA = __builtin_dmaoffset(&amData); //Primary Transfer Buffer
#endif
DMA1PAD = (volatile unsigned int) &SPI1BUF; //Peripheral Address
DMA1CNT = PATH_MANAGER?(sizeof(PMData)/2 + sizeof(PMData) % 2 - 1):(sizeof(AMData)/2 + sizeof(AMData) % 2 - 1); //+1 for checksum //DMA Transfer Count Length
DMA1REQ = 0x000A;//0b0100001; //IRQ code for SPI1
DMA1CONbits.CHEN = 1; //Enable the channel
}
|
...
Also, in order to initialize transfer, the SPI master must send the first packet. This is evident in the DMA0 interrupt routine:
Code Block |
---|
|
#if !PATH\_MANAGER
if (!transmitInitialized){
transmitInitialized = 1;
DMA1REQbits.FORCE = 1;
while (DMA1REQbits.FORCE == 1);
}
#endif
|
...