NEO m8n. the problem of incoming and outgoing protocols

good afternoon. sorry for my English (I use a translator).
the problem is the following.
I have a GPS module NEO-m8n-0-10.
Six months ago he was working. Whether it's bad or good, I caught the signal only on the street, but it worked.
Now I want to use it for one project, but it has stopped working. I'm using an Arduino Mega 2560.
I tried NMEA parser (TinyGPSPlus.h), UBX parser (UBX_Parser.h). I don't see anything on the port to which the GPS is connected.
Ports tried Serial2, Serial3, Soaftserial (4.3)

Sats HDOP  Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum
           (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail
----------------------------------------------------------------------------------------------------------------------------------------
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0        
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0        
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0        
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0        
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0        
No GPS data received: check wiring
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0        
No GPS data received: check wiring
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0        
No GPS data received: check wiring
**** ***** ********** *********** **** ********** ******** **** ****** ****** ***** ***   ******** ****** ***   0     0         0

I connect it to the U-center. I don't see anything either.


But as soon as I switch the port protocols from UBX to NMEA, it starts working.


Saving doesn't help. As soon as I disconnect it and connect it to the Arduino Mega, it shows nothing and, as I understand it,
the protocols are reset back to UBX.

There was an idea in the sketch to write lines that do the same thing as U-center - change protocols from UBX to NMEA.
But I do not know how to do it. And will it help?

Tell me what to do?
Throw it away and buy a new one, or can it somehow be made to work on Mega 2560?

What did you save to?
Does the device have EEPROM?
The default save destination for UbloxCenter may not be I2C EEPROM.
(It isn't for the Neo6)

I thought that if any changes were made in the settings (change of protocols, etc.), then they should be saved in the module so that they would be saved after power off. But apparently there is only ROM here.

You probably have a fake M8N, like mine. I had the same issue, and could not update the M8N's firmware. No surprise after lifting the cap. It's a M8030 in disguise. (the end-of-life version or maybe even a fake M8030 chip).

Mine defaults to NMEA after a power cycle, but I set it to UBX protocol in my sketch. You need to activate some UBX sentences before U-Center will show the satellites.
I am using the "PVT" sentence, as it contains all navigation parameters I need as well as GPS fix quality indicator.

At power up the Ublox GPSs check for the presense of an EEPROM and maybe ROM too.

If one is found the configuration, presumably with a valid check, is loaded from the EEPROM.

One issue I have come across with fake Ublox GPSs is that they dont configure as the datasheets for the original GPS suggest.

Not quite, if you make changes to the config, you have to explicitly save the config to a choice of battery backed RAM, Flash, EEPROM, SPI-Flash, see the UBX-CFG-CFG command.

I am interested, ultimately, not in the U-center, but in the Mega 2560. How can I configure the module in the sketch for further work?

Here is a snippet from my sketch (Attiny1616) how I configure the M8N to turn off all NMEA sentences, Increase the update rate to 4Hz, activate airborne mode (<4g) and turn on the UBX-PVT sentence.

I am using this for a GPS telemetry sensor in model aircrafts.
the GPS is connected to the hardware serial port.

>>>>SNIP<<<<

//format hex command strings for sending to UBLOX
const unsigned char airborne[] = {0xb5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xff, 0xff, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27,
                                0x00, 0x00, 0x05, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x64, 0x00, 0x2c, 0x01, 0x00, 0x3c, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0b, 0xb5, 0x62, 0x06, 0x24,
                                0x00, 0x00, 0x2a, 0x84
                               };
const unsigned char hnr[] = {0xB5, 0x62, 0x06, 0x5C, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6B, 0xE0}; // high nav rate to 5Hz
const unsigned char rate[] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDE, 0x6A}; // output at 5 Hz
const unsigned char pvt[] = {0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x07, 0x01, 0x13, 0x51}; // activate PVT sentence

>>>>SNIP<<<<


void setup() {
  delay(2000); // wait for GPS to boot.

  Serial.begin(9600);
  delay(100);
  Serial.println("$PUBX,40,RMC,0,0,0,0*47"); //RMC OFF
  delay(100);
  Serial.println("$PUBX,40,VTG,0,0,0,0*5E"); //VTG OFF
  delay(100);
  Serial.println("$PUBX,40,GGA,0,0,0,0*5A"); //GGA OFF
  delay(100);
  Serial.println("$PUBX,40,GSA,0,0,0,0*4E"); //GSA OFF
  delay(100);
  Serial.println("$PUBX,40,GSV,0,0,0,0*59"); //GSV OFF
  delay(100);
  Serial.println("$PUBX,40,GLL,0,0,0,0*5C"); //GLL OFF
  delay(100);

  Serial.write(airborne, sizeof(airborne)); //set GPS mode to airborne < 4g
  delay(100);
  Serial.write(hnr, sizeof(hnr)); //set GPS update rate to 4Hz (1st string)
  delay(100);
  Serial.write(rate, sizeof(rate)); //set GPS update rate to 4Hz (2nd string)
  delay(100);
  Serial.write(pvt, sizeof(pvt)); // PVT Navigation Position Velocity Time Solution message ON
  delay(100);
} // end setup

>>>>SNIP<<<<


If you want to create your own command strings to send to the M8N. You will need to calculate the checksum.

I made a small sketch to make that less painful.

/*UBlox GPS message checksum calculator
  V1.0 by Hans Meijdam
 U-Blox checksum calculator.
 V1.1 Hans Meijdam, March 2021
  This sketch will calculate the UBLOX checksum. The checksum algorithm used is the 8-Bit Fletcher Algorithm, which is used in the TCP standard (RFC 1145).
  leave out the first two sync-char of the UBLOX sentence and the last two bytes are the checksum bytes.

  expected outcome of the below example should be: CK_A = 91 and CK_B = 84
*/
const static uint8_t myStr[] PROGMEM = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,  0x91, 0x84};
//                                      ====sync=== ============================================== checksum calculated over these bytes ===========================================================  =checksum=
//uint16_t prnt; // helper for printing

void setup() {
  Serial.begin(9600);
  uint8_t CK_A = 0;
  uint8_t CK_B = 0;
  uint8_t i;

  for (i = 0; i < sizeof(myStr) - 4; i++) { // "-4" because leave the first two and the last two bytes out of the checksum calculation.
    CK_A = CK_A + pgm_read_byte(&myStr[i + 2]); // "+2" because we skip the first 2 sync bytes
    CK_B = CK_B + CK_A;
  }
  Serial.print(" CK_A = ");
  Serial.print(CK_A, HEX);
  Serial.print(" and CK_B = ");
  Serial.println(CK_B, HEX);
}

void loop() {
}

As far as I see in the datasheet, NMEA messages uses a one byte checksum. What are the CK_A and CK_B in your code?

Addition - two byte CK_A and CK_B is a format of UBLOX checksum. But Op need a NMEA messages. I think your code will be incompatible with it.

That's a good point. I never used NMEA other than turning it off, so what you say is that NMEA may even be simpler to use.

You can use U-Center to check that the command you are sending does actually work and U-Center will also provide you with the full hex packet and checksum to send.

Please explain, I'm looking at the documentation on UBX messages now and I don't understand a little:
the structure of the UBX message:

$PUBX,40, msgId, rddc, rus1, rus2, rusb, rspi, reserved*cs[CR][LF] 

you have an example

$PUBX,40, GLL, 0, 0, 0, 0*5C

why are there so few values ?

That is a very relevant question. There are 2 zeros missing. It worked for me then, with the GPS module I used, but I am getting curious if it still works with different modules.
I suspect that only DDC, USART1 and USART2 are touched. USB and SPI are untouched. Maybe it was an old version of the UBX protocol that is backwards compatible. But that is speculation from my side.

Thanks to @srnet I found this article a while ago that makes it quite easy to create your own PUBX command messages. That way the two extra zeros show up.

well, I understood a little about working with messages. the module has started.

const unsigned char message1[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17 }; //UBX CFG-MSG,  Size  16,  'Messages'
const unsigned char message2[] = { 0xB5, 0x62, 0x06, 0x01, 0x02, 0x00, 0x01, 0x06, 0x10, 0x39 };                               //UBX CFG,  Size  10,  'Config'

const unsigned char message3[] = { 0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x08, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 
                                   0x00, 0x00, 0x0A, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x5E, 0x01, 0x00, 0x3C, 0x00, 0x00,  
                                   0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC3, };                  //UBX CFG-NAV5,  Size  44,  'Navigation 5'
const unsigned char message4[] = { 0xB5, 0x62, 0x06, 0x24, 0x00, 0x00, 0x2A, 0x84};                                            //UBX CFG,  Size   8,  'Config'

const unsigned char message5[] = { 0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25,  
                                   0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x95 };                   //UBX + NMEA
const unsigned char message6[] = { 0xB5, 0x62, 0x06, 0x00, 0x01, 0x00, 0x01, 0x08, 0x22 };                                     //UBX CFG,  Size   10,  'Config'  

displays the time and date. and everything. No coordinates, no speed (what I need).

Tell me what other message should I send to the module? maybe we need to configure something else?

Sats HDOP  Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum
           (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail
----------------------------------------------------------------------------------------------------------------------------------------
**** 100.0  ********** *********** **** 08/23/2023 08:43:15 5    ****** ****** ***** ***   
0    100.0  ********** *********** **** 08/23/2023 08:43:15 17   ****** ****** ***** ***   

You can try this sketch.

Hook up the GPS module to the hardware TX/RX (USART0) of your Arduino and connect a serial adapter (RX line) to USART1, or to pin 2 if no second USART is present on your board.
The Arduino led will turn on when a valid GPS fix is received and turn off if it fails. You can test that by putting your hand around the GPS antenna and in a few seconds the led should turn off.

/* Connect GPS to USART0 (Hardware serial 0)
 * Connect serial adapter to Hardware Serial 1 or to pin 2 if no HW Serial1 is present on your MCU
 */
#ifndef HAVE_HWSERIAL1
#include <SoftwareSerial.h>
SoftwareSerial Serial1(3, 2); // RX, TX
#endif

//format hex command strings for sending to UBLOX
const char airborne[] = {0xb5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xff, 0xff, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27,
                         0x00, 0x00, 0x05, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x64, 0x00, 0x2c, 0x01, 0x00, 0x3c, 0x00, 0x00,
                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0b, 0xb5, 0x62, 0x06, 0x24,
                         0x00, 0x00, 0x2a, 0x84
                        };
const char hnr[] = {0xB5, 0x62, 0x06, 0x5C, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6B, 0xE0}; // high nav rate to 5Hz
const char rate[] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDE, 0x6A}; // output at 5 Hz
const char pvt[] = {0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x07, 0x01, 0x13, 0x51}; // activate PVT sentence


#define GPS_INFO_BUFFER_SIZE 100 // enough for the strings (PVT is 100 long)
byte GPS_info_buffer[GPS_INFO_BUFFER_SIZE];
byte string_length = 98;  //PVT is 100 Initialize with longest string.
unsigned int received_char;
int i = 0; // counter
bool message_started = false;

long velN; // North vector of 3D speed
long velE; // East vector of 3D speed
long velD; // Down vector of 3D speed
unsigned long ThreeD_spd_kts; //3D speed in knots
long longitude ;//longitude
long latitude ;//latitude
long height_above_sea_level;//height above main sea level
unsigned long ground_speed ;
unsigned long heading;

//CHECKSUM CALCULATION VARIABLE
unsigned char CK_A = 0;
unsigned char CK_B = 0;

byte fixok = 0; // flag to indicate a valid GPS fix was received.
byte fixcount = 0; // count how many OK GPS fixes we have in a row.

void setup() {
  Serial1.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite (LED_BUILTIN, HIGH); // signal led on, to test
  delay(2000); // wait for GPS to boot (and Softwareserial also needs some time.)
  Serial1.println(F("printing is up and running."));
  Serial.begin(9600);
  delay(100);
  Serial.println(F("$PUBX,40,RMC,0,0,0,0*47")); //RMC OFF
  delay(100);
  Serial.println(F("$PUBX,40,VTG,0,0,0,0*5E")); //VTG OFF
  delay(100);
  Serial.println(F("$PUBX,40,GGA,0,0,0,0*5A")); //GGA OFF
  delay(100);
  Serial.println(F("$PUBX,40,GSA,0,0,0,0*4E")); //GSA OFF
  delay(100);
  Serial.println(F("$PUBX,40,GSV,0,0,0,0*59")); //GSV OFF
  delay(100);
  Serial.println(F("$PUBX,40,GLL,0,0,0,0*5C")); //GLL OFF
  delay(100);

  //  Serial.write(airborne, sizeof(airborne)); //set GPS mode to airborne < 4g
  //  delay(100);
  //  Serial.write(hnr, sizeof(hnr)); //set GPS update rate to 4Hz (1st string)
  //  delay(100);
  //  Serial.write(rate, sizeof(rate)); //set GPS update rate to 4Hz (2nd string)
  //  delay(100);
  Serial.write(pvt, sizeof(pvt)); // PVT Navigation Position Velocity Time Solution message ON
  delay(100);
  digitalWrite (13, LOW); // signal led off, end setup
} // end setup

void loop() {
  if (Serial.available()) { // If GPS data is available
    byte GPS_info_char = Serial.read();  // Read it and store as HEX char
    if (GPS_info_char == 0xb5) { // ublox B5 record found
      message_started = true;
      received_char = 0;
    } // end ublox B5 record found
    else if (message_started == true) { // the message is already started and I got a new character
      if (received_char < string_length) { // buffer not full
        GPS_info_buffer[received_char] = GPS_info_char;
        if (GPS_info_buffer[2] == 0x07) string_length = 98;  //PVT lenght is 84 + 6
        received_char++;
      } // end buffer not full
      else { // final character received
        GPS_info_buffer[received_char] = GPS_info_char;
        UBX_calculate_checksum(GPS_info_buffer, 1, (string_length - 2)); // calculates checksum

        if (string_length == 98) { // PVT string received
          if ((CK_A == GPS_info_buffer[string_length - 1] && CK_B == GPS_info_buffer[string_length]) && (( GPS_info_buffer[21 + 5] & B00000001) && ( GPS_info_buffer[20 + 5] == 0x03))) { // checksum ok and fix ok
            // confirm (received and calculated checksums are the same) && (fix status flag = 1 AND a 3Dfix)
            if (fixcount < 10) fixcount ++;  // count how many valid fixes
            digitalWrite (LED_BUILTIN, HIGH); // signal led on, we have a valid GPS fix
            // convert the GPS buffer array bytes 24,23,22,21 into one "unsigned long" (4 byte) field

            velN   = (long)GPS_info_buffer[51 + 5] << 24;
            velN  += (long)GPS_info_buffer[50 + 5] << 16;
            velN  += (long)GPS_info_buffer[49 + 5] << 8;
            velN  += (long)GPS_info_buffer[48 + 5];

            velE   = (long)GPS_info_buffer[55 + 5] << 24;
            velE  += (long)GPS_info_buffer[54 + 5] << 16;
            velE  += (long)GPS_info_buffer[53 + 5] << 8;
            velE  += (long)GPS_info_buffer[52 + 5];

            velD   = (long)GPS_info_buffer[59 + 5] << 24;
            velD  += (long)GPS_info_buffer[58 + 5] << 16;
            velD  += (long)GPS_info_buffer[57 + 5] << 8;
            velD  += (long)GPS_info_buffer[56 + 5];

            // for high-G model aircraft wait for some valid GPS fixes to dampen 3D speed errors after sharp turns
            if (fixcount > 8) ThreeD_spd_kts = (((float)(sqrt(sq(velN) + sq(velE) + sq(velD))) * 1.94381) / 100); // calculate 3D speed in Knots from speedvectors
            else ThreeD_spd_kts = 0;

            ground_speed  = (long)GPS_info_buffer[63 + 5] << 24;
            ground_speed += (long)GPS_info_buffer[62 + 5] << 16;
            ground_speed += (long)GPS_info_buffer[61 + 5] << 8;
            ground_speed += (long)GPS_info_buffer[60 + 5];
            ground_speed = (((float)ground_speed * 1.94381)) ;

            heading  = (long)GPS_info_buffer[67 + 5] << 24;
            heading += (long)GPS_info_buffer[66 + 5] << 16;
            heading += (long)GPS_info_buffer[65 + 5] << 8;
            heading += (long)GPS_info_buffer[64 + 5];
            heading = heading / 1000;

            longitude   = (long)GPS_info_buffer[27 + 5] << 24;
            longitude  += (long)GPS_info_buffer[26 + 5] << 16;
            longitude  += (long)GPS_info_buffer[25 + 5] << 8;
            longitude  += (long)GPS_info_buffer[24 + 5];

            latitude   = (long)GPS_info_buffer[31 + 5] << 24;
            latitude  += (long)GPS_info_buffer[30 + 5] << 16;
            latitude  += (long)GPS_info_buffer[29 + 5] << 8;
            latitude  += (long)GPS_info_buffer[28 + 5];

            height_above_sea_level   = (long)GPS_info_buffer[39 + 5] << 24;
            height_above_sea_level  += (long)GPS_info_buffer[38 + 5] << 16;
            height_above_sea_level  += (long)GPS_info_buffer[37 + 5] << 8;
            height_above_sea_level  += (long)GPS_info_buffer[36 + 5];
            height_above_sea_level  = (height_above_sea_level / 10);
          }// end parse PVT sentence
          else {// when checksum error or no fix set values to zero
            fixcount = 0;
            digitalWrite (LED_BUILTIN, LOW); // signal led off, we have no valid GPS fix
            ThreeD_spd_kts = 0;
            ground_speed = 0;
            heading = 0;
            longitude = 0;
            latitude = 0;
            height_above_sea_level = 0;
          }// end when checksum or fix fails
          //print values
          Serial1.print("Latitude: ");
          Serial1.print(float(latitude) / 10000000, 7);
          Serial1.print("\tLongitude: ");
          Serial1.print(float(longitude) / 10000000, 7);
          Serial1.print("\tHeight above sealevel: ");
          Serial1.print(height_above_sea_level);
          Serial1.print("\tGround Speed: ");
          Serial1.print(ground_speed);
          Serial1.print("\t3D Speed: ");
          Serial1.print(ThreeD_spd_kts);
          //  Serial1.print("\tHeading: ");
          //  Serial1.print(heading);
          Serial1.println();
        }
        message_started = false; // ready for the new message
      } // end final character received
    } // end the message is already started and I got a new character
  } // end If GPS data is available
} // end loop

// CALCULATES THE UBX CHECKSUM OF A CHAR ARRAY
void UBX_calculate_checksum(uint8_t* array, unsigned int array_start, unsigned int array_length) {
  CK_A = 0;
  CK_B = 0;
  unsigned int i;
  for (i = 0; i < array_length; i++) {
    CK_A = CK_A + array[array_start + i];
    CK_B = CK_B + CK_A;
  }
}

Hello,

I had the same problem. I bought the fake ublox gps from aliexpress, just try look at the quality and reception. It worked fine for some days, then the signal was getting worse. I found out, that the active antenna was malfunctioning. Reasion, the small pigtail connectors is super-fragaile. The active antenna ned voltage to work. So I found a smal break in the shield of the gps antenna wire and soldered it back on. And voila, back again! I finally ditched this gps project, when I found a SIM7600 module where I could connect to the gsm network and recive gps at the same time. So now, my drone "black box" send sms every 10 minutes with google map link the drone gps coordinates :slight_smile:

Впишите сюда текст цитаты

OK, thanks, I'll try it today. I will write about the result.

everything would be fine, but where my device will be used - there is no GSM network or it is unstable. Therefore, only the satellite

good afternoon. Yes, thank you, your sketch works. While I was sitting and sorting it out, reading the documentation, I wanted to try parsing "manually" myself. :slight_smile: Pulled the current date from the message:

   Year      = (int)GPS_info_buffer[5+5] << 8;
   Year    += (int)GPS_info_buffer[4+5];             
   Month   = (int)GPS_info_buffer[6+5];
   Day       = (int)GPS_info_buffer[7+5];

   Hour   = (int)GPS_info_buffer[8+5];
   Minute = (int)GPS_info_buffer[9+5];
   Second = (int)GPS_info_buffer[10+5];

Output to Serial:

	Year: 2023	Month: 8	Day: 25    7:57:39