I am working on an autonomous sailboat with an I2C port that supports GPS, magnetometer,. accelerometer, gyro, current and voltage. I have had trouble with the I2C locking up, and after reading a bit on this forum, decided to change to MartinL's I2C DMAC library. I have had success with the exception of the GPS.
The GPS is an odd device to put on I2C. It is clearly a native UART device which has been shoehorned into I2C. It has no registers, and sends large text strings up the I2C whenever it feels like, without prompting from the master. Text string commands are sent from the master to the GPS, and the GPS responds with text string acknowledgments. My device is an Adafruit mini GPS PA1010D, but SparfFun makes I2C GPSs too.
I have tried to use the library functions that don't include register addresses. I have had success with initReadBytes(), but I have had trouble with initWriteBytes().
#include <I2C_DMAC.h>
#define GPS_ADDRESS 0x10 // Device address when ADO = 0
char c[100];
void setup()
{
SerialUSB.begin(115200); // Activate the native USB port
while (!SerialUSB); // Wait for the native USB to be ready
I2C.begin(100000); // Start I2C bus at 400kHz
delay(100);
//None of the following initWriteBytes lines seem to work
I2C.initWriteBytes(GPS_ADDRESS, (uint8_t*)"$PMTK314,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29", sizeof("$PMTK314,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"));
// while (I2C.writeBusy); Tried
//I2C.write(); these
//while (I2C.writeBusy); with
//delay(100); no benefit
I2C.initWriteBytes(GPS_ADDRESS, (uint8_t*)"$PMTK220,1000*1F", strlen("$PMTK220,1000*1F"));
I2C.initWriteBytes(GPS_ADDRESS, (uint8_t*)"$PMTK300,1000,0,0,0,0*1C", strlen("$PMTK300,1000,0,0,0,0*1C"));
I2C.initWriteBytes(GPS_ADDRESS, (uint8_t*)"$PGCMD,33,1*6C", strlen("$PGCMD,33,1*6C"));
I2C.initWriteBytes(GPS_ADDRESS, (uint8_t*)"$PMTK605*31" , strlen("$PMTK605*31" ));
I2C.initReadBytes(GPS_ADDRESS, (uint8_t*)c, sizeof(c)); // Initialise DMAC read transfer: This works!
}
void loop() {
//Everything here works fine.
delay(1000); //check for GPS data once a second. Successfull about once every 5 seconds
I2C.read(); // Initiate DMAC read transmission on the I2C bus
//put code here
while (I2C.readBusy); // Wait for synchronization
if (c[0] == 0) {
SerialUSB.println("nothing this pass "); // Output the result
return;
}
for (int i = 0; i < sizeof(c); i++) {
switch (c[i]) {
case 0x0a:
//SerialUSB.print('~'); //uncomment to see how many LFs are being thrown away.
break;
case 0x0d:
SerialUSB.println();
break;
default:
SerialUSB.print(c[i]); // Output the result byte by byte: ends with CR and one or more LF
}
}
}
Understandably, there are no examples showing initWriteBytes() used in this way. I have tried a few variations, but have had no luck sending commands to the GPS. I never get an acknowledgement, and I can never change the behavior of the GPS, it continues to run on its default settings. Please look at my code.
I also have two questions about reading from this device:
-
Is there a way I can see the number of bytes waiting for me in DMA and only read that many? I have been reading 100 characters every second, but I am discarding a lot of white space. As I write this, 100 chars doesn't seem excessive, but I feel like I am doing unnecessary work.
-
All my white space characters are 0x0a (line feed). This doesn't present a problem, but it seems odd to me. Are these coming from the DMA or the GPS?