Open maxsrobotics opened 10 months ago
Hi @maxsrobotics , do you have u-blox modules working over I2C?
Yes, my friend and I were able to get data (HEX codes) directly from the module over I2C. It's just a simple Wire.requestFrom, and then some reads over Wire.h. I'm not at my main computer with the working code right now, but in an hour or so I can post my I2C read script. Thanks so much for helping out!
Thanks, Max W0MXX
Hi @maxsrobotics, it would be very interesting to take a look at the code! Can't guarantee I would be able to integrate it, because I don't have such a module, but let's see... What exact module from u-blox do you use? Is it on a board or do you connect directly? I2C is an interesting option, please share links/pics?
Yea, I am using the MAX-M10S that I picked up from DigiKey, and I have been testing it from the Sparkfun GPS library: https://github.com/sparkfun/SparkFun_u-blox_GNSS_v3
Here's some code that I modified from Dave Akerman's FlexTrack sketch that is able to read and parse UBX packets over I2C from the module:
`#define GPS_I2C
// #include
struct TGPS { int Hours, Minutes, Seconds; unsigned long SecondsInDay; // Time in seconds since midnight float Longitude, Latitude; long Altitude; unsigned int Satellites; int Speed; int Direction; byte FixType; byte psm_status; float InternalTemperature; float BatteryVoltage; float ExternalTemperature; float Pressure; unsigned int BoardCurrent; unsigned int errorstatus; byte FlightMode; byte PowerMode; int CutdownStatus; } GPS;
// Globals byte RequiredFlightMode=0; byte GlonassMode=0; byte RequiredPowerMode=-1; byte LastCommand1=0; byte LastCommand2=0; byte HaveHadALock=0;
char Hex(char Character) { char HexTable[] = "0123456789ABCDEF";
return HexTable[Character]; }
void FixUBXChecksum(unsigned char *Message, int Length) { int i; unsigned char CK_A, CK_B;
CK_A = 0; CK_B = 0;
for (i=2; i<(Length-2); i++) { CK_A = CK_A + Message[i]; CK_B = CK_B + CK_A; }
Message[Length-2] = CK_A; Message[Length-1] = CK_B; }
void SendUBX(unsigned char *Message, int Length) { LastCommand1 = Message[2]; LastCommand2 = Message[3];
I2c.write(0x42, 0, Message, Length);
int i;
for (i=0; i<Length; i++) { Serial.write(Message[i]); }
}
void DisableNMEAProtocol(unsigned char Protocol) { unsigned char Disable[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
Disable[7] = Protocol;
FixUBXChecksum(Disable, sizeof(Disable));
SendUBX(Disable, sizeof(Disable));
// Serial.print("Disable NMEA "); Serial.println(Protocol); }
void SetFlightMode(byte NewMode) { // Send navigation configuration command unsigned char setNav[] = {0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC};
setNav[8] = NewMode;
FixUBXChecksum(setNav, sizeof(setNav));
SendUBX(setNav, sizeof(setNav)); }
void SetGNSSMode(void) { // Sets CFG-GNSS to disable everything other than GPS GNSS // solution. Failure to do this means GPS power saving // doesn't work. Not needed for MAX7, needed for MAX8's
uint8_t setGNSS[] = { 0xB5, 0x62, 0x06, 0x3E, 0x2C, 0x00, 0x00, 0x00, 0x20, 0x05, 0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x08, 0x10, 0x00, 0x00, 0x00, 0x01, 0x01, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x08, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x01, 0xFC, 0x11}; SendUBX(setGNSS, sizeof(setGNSS)); }
void SetPowerMode(byte SavePower) { uint8_t setPSM[] = {0xB5, 0x62, 0x06, 0x11, 0x02, 0x00, 0x08, 0x01, 0x22, 0x92 };
setPSM[7] = SavePower ? 1 : 0;
FixUBXChecksum(setPSM, sizeof(setPSM));
SendUBX(setPSM, sizeof(setPSM)); }
void ProcessUBX_ACK(unsigned char *Buffer, int Length) { if ((LastCommand1 == 0x06) && (LastCommand2 == 0x24)) { GPS.FlightMode = RequiredFlightMode; } else if ((LastCommand1 == 0x06) && (LastCommand2 == 0x3E)) { GlonassMode = 1; } else if ((LastCommand1 == 0x06) && (LastCommand2 == 0x11)) { GPS.PowerMode = RequiredPowerMode; } LastCommand1 = 0; LastCommand2 = 0; }
void ProcessUBX_NAV_PVT(unsigned char Buffer, int Length) { struct TUBlox { uint32_t GPSTime; uint16_t Year; uint8_t Month; uint8_t Day; uint8_t Hours; uint8_t Minutes; uint8_t Seconds; uint8_t Valid; uint32_t TimeAccuracy; int32_t NanoSeconds; uint8_t FixType; uint8_t Flags; uint8_t Reserved; uint8_t Satellites; int32_t Longitude; int32_t Latitude; int32_t HeightEllipsoid; int32_t HeightSeaLevel; uint32_t HAccuracy; uint32_t VAccuracy; } UBlox;
UBlox = (struct TUBlox*)(Buffer+6);
GPS.FixType = UBlox->FixType; GPS.Satellites = UBlox->Satellites;
if (UBlox->FixType > 0) { GPS.SecondsInDay = (UBlox->GPSTime / 1000) % 86400; // Time of day in seconds = Time in week in ms / 1000, mod 86400 GPS.Hours = UBlox->Hours; // GPS.SecondsInDay / 3600; GPS.Minutes = UBlox->Minutes; // (GPS.SecondsInDay / 60) % 60; GPS.Seconds = UBlox->Seconds; // GPS.SecondsInDay % 60;
if ((UBlox->FixType >= 2) && (UBlox->FixType <= 4))
{
GPS.Longitude = (float)(UBlox->Longitude) / 10000000;
GPS.Latitude = (float)(UBlox->Latitude) / 10000000;
if ((UBlox->FixType >= 3) && (UBlox->FixType <= 4))
{
GPS.Altitude = UBlox->HeightSeaLevel / 1000;
}
}
}
}
void ProcessUBX(unsigned char *Buffer, int Length) { if ((Buffer[2] == 0x05) && (Buffer[3] == 0x01)) { ProcessUBX_ACK(Buffer, Length); } else if ((Buffer[2] == 1) && (Buffer[3] == 7)) { ProcessUBX_NAV_PVT(Buffer, Length); } }
void ProcessNMEA(unsigned char Buffer, int Count)
{
if (strncmp((char )Buffer+3, "GGA", 3) == 0)
{
DisableNMEAProtocol(0);
}
else if (strncmp((char )Buffer+3, "RMC", 3) == 0)
{
DisableNMEAProtocol(4);
}
else if (strncmp((char )Buffer+3, "GSV", 3) == 0)
{
DisableNMEAProtocol(3);
}
else if (strncmp((char )Buffer+3, "GLL", 3) == 0)
{
DisableNMEAProtocol(1);
}
else if (strncmp((char )Buffer+3, "GSA", 3) == 0)
{
DisableNMEAProtocol(2);
}
else if (strncmp((char *)Buffer+3, "VTG", 3) == 0)
{
DisableNMEAProtocol(5);
}
}
void SetupGPS(void) { // Switch GPS on, if we have control of that
pinMode(GPS_ON, OUTPUT); digitalWrite(GPS_ON, 1);
// Init I2C library if we're using it
// Init i2c library // Wire.begin(); I2c.begin();
}
int GPSAvailable(void) { int FD, FE, Bytes;
// return Wire.available(); // return I2c.available(); I2c.read(0x42, 0xFD, 2); // Set up read from registers FD/FE - number of bytes available FD = I2c.receive(); FE = I2c.receive();
Bytes = FD * 256 + FE;
if (Bytes > 32) { Bytes = 32; }
if (Bytes > 0) { I2c.read(0x42, 0xFF, Bytes); // request 32 bytes from slave device 0x42 (Ublox default) }
return Bytes;
return Serial.available();
}
char ReadGPS(void) {
// return Wire.read();
return I2c.receive();
return Serial.read();
}
void PollGPSTime(void) { uint8_t request[] = {0xB5, 0x62, 0x01, 0x21, 0x00, 0x00, 0x22, 0x67}; SendUBX(request, sizeof(request)); }
void PollGPSPosition(void) { // uint8_t request[] = {0xB5, 0x62, 0x01, 0x02, 0x00, 0x00, 0x03, 0x0A}; LLH uint8_t request[] = {0xB5, 0x62, 0x01, 0x07, 0x00, 0x00, 0x08, 0x19};
SendUBX(request, sizeof(request)); }
void CheckGPS(void) { static unsigned long PollTime=0; static unsigned char Line[128]; static int Length=0; static int UBXLength=0; static unsigned int PollMode=0; unsigned char Character, Bytes, i;
do { Bytes = GPSAvailable();
for (i=0; i<Bytes; i++)
{
Character = ReadGPS();
if ((Character == 0xB5) && (Length <= 4))
{
Line[0] = Character;
Length = 1;
}
else if ((Character == 0x62) && (Length <= 4))
{
if (Length == 0)
{
Line[0] = 0xB5;
}
Line[1] = Character;
Length = 2;
}
else if ((Character == '$') && (Length == 0))
{
Line[0] = Character;
Length = 1;
}
else if (Length >= (sizeof(Line)-2))
{
Length = 0;
}
else if (Length > 0)
{
if (Line[0] == 0xB5)
{
// UBX
Line[Length++] = Character;
if (Length == 6)
{
// Got UBX Length
UBXLength = (int)Line[4] + (int)(Line[5]) * 256;
}
else if ((Length > 6) && (Length >= (UBXLength+8)))
{
ProcessUBX(Line, Length);
LastCommand1 = Line[2];
LastCommand2 = Line[3];
Length = 0;
}
}
else if (Line[0] == '$')
{
if (Character == '$')
{
Length = 1;
}
else if (Character != '\r')
{
Line[Length++] = Character;
if (Character == '\n')
{
Line[Length] = '\0';
ProcessNMEA(Line, Length);
Length = 0;
}
}
}
}
}
} while (Bytes > 0);
if (millis() >= PollTime) { if (PollTime == 0) { PollTime = millis(); } else { // PollTime += 200; PollTime = millis() + 200; }
Length = 0;
switch (PollMode)
{
case 0:
// Poll for position
PollGPSPosition();
break;
case 1:
// Flight/ped mode
RequiredFlightMode = (GPS.Altitude > 1000) ? 6 : 3; // 6 is airborne <1g mode; 3=Pedestrian mode
if (RequiredFlightMode != GPS.FlightMode)
{
SetFlightMode(RequiredFlightMode);
// Serial.println("Setting flight mode\n");
}
break;
case 2:
// Power saving
#ifdef POWERSAVING
if (!GlonassMode)
{
// Serial.println("*** SetGNSSMode() ***");
SetGNSSMode();
}
else
{
// All the following need to be true for us to try power saving mode
RequiredPowerMode = (GPS.FixType==3) && (GPS.Satellites>=5);
if (RequiredPowerMode != GPS.PowerMode)
{
// Serial.print("*** SetPowerMode("); Serial.print(RequiredPowerMode); Serial.println(") ***");
SetPowerMode(RequiredPowerMode);
}
}
#endif
break;
}
if (++PollMode >= 3)
{
PollMode = 0;
}
} }
void setup() { Serial.begin(9600); delay(1000); SetupGPS(); }
void loop() { CheckGPS(); // Serial.print(GPS.Hours); Serial.print(":"); Serial.print(GPS.Minutes); Serial.print(":"); Serial.print(GPS.Seconds);Serial.print(" - "); Serial.print("Lat: "); Serial.print(GPS.Latitude, 6); Serial.print(", Lon: "); Serial.print(GPS.Longitude, 6); Serial.print(", Alt: "); Serial.print(GPS.Altitude); Serial.print(", Sats: "); Serial.println(GPS.Satellites); delay(1000); }`
Again, thanks so much for attempting this project! Max W0MXX
Also, the board I'm using is a custom breakout board in KiCAD:
Hey,
This library works well for use with UART applications. I wanted to suggest adding I2C support for those who don't want to work with the latency and efficiency of UART, using the Wire.h library..
Thanks! W0MXX