UBX & PUBX config ignored

Hi everyone,

I’m working on a 0–100 km/h measurement setup using an ESP32 and a NEO‑M9N module. My main requirement is a stable, jitter‑free stream of velocity data (RMC sentences) to feed an acceleration calculation.

Current working state

Module is connected to ESP32 UART2 (pins 16/17) at 38400 baud.

Navigation rate is 20 Hz (50 ms update, all 4 GNSS active) – I managed to set this early on via UBX‑CFG‑VALSET (rate change was ACK’d and works).

Problem / frustration I want to either raise the baud rate to 115200 or permanently disable unnecessary NMEA sentences (GSV, GSA, VTG, TXT) to reduce serial load. However, the module ignores every configuration attempt:

UBX‑CFG‑VALSET (key 0x40520001, layer RAM+BBR+Flash) → ACK‑NAK

UBX‑CFG‑PRT (legacy, correct checksum) → ACK‑NAK

$PUBX,41,1,0007,0003,115200,1 → ignored (module stays at 38400)

$PUBX,40,… to disable sentences → ignored (settings don’t stick, sentences keep coming)

u‑center 2: message configuration changes jump back immediately; “Configure device and set connection baud rate” loses connection (module stays at 38400).

I even tried the SAFEBOOT procedure (pull pin 1 low during power‑up), sent a CFG‑PRT with save flags – but after a power‑cycle the module remains at 38400, NMEA‑only.

What I suspect

The module might be a clone that simply doesn’t implement configuration properly. But it seems to be working fine other than this.

Or the firmware (SPG 4.04) is locked in some “NMEA‑only” input mode and doesn’t accept UBX on UART1.

Is there any known method to force a baud-rate change on a module that behaves like this? For example:

  • A specific pin state (e.g., D_SEL pulled high/low) that must be set for configuration to be accepted?
  • A special UBX sequence that must be sent before a baud-rate command (like enabling UBX input via a different port)?

I’d really like to get this module to 115200 baud. If it’s a clone and absolutely impossible, I’d appreciate knowing that too, so I can stop beating my head against the wall. But if there’s even a slim chance, I’m all ears!

Hi @Dachi_Kharaishvili ,

Have you checked the UART1 protocols? Specifically that the UBX protocol is enabled for both input and output on UART1 (UART1INPROT_UBX and UART1OUTPROT_UBX)?

The $PUBX messages need correct NMEA checksums, followed by CR and LF:

$PUBX,41,1,0007,0003,115200,1*19\r\n

I hope this helps,
Paul

Thanks Paul,

#include <HardwareSerial.h>
#define RXD2 16
#define TXD2 17

HardwareSerial GPS(2);

void setup() {
  Serial.begin(115200);
  GPS.begin(38400, SERIAL_8N1, RXD2, TXD2);
  delay(200);

  GPS.print("$PUBX,41,1,0007,0003,115200,1*19\r\n");
  GPS.flush();
  delay(200);

  GPS.end();
  delay(100);
  GPS.begin(115200, SERIAL_8N1, RXD2, TXD2);

  Serial.println("Switched to 115200 baud. Listening for NMEA...");

  unsigned long start = millis();
  while (millis() - start < 20000) {
    while (GPS.available()) {
      Serial.write(GPS.read());
    }
  }
  Serial.println("\nTest finished.");
}

void loop() {}

I flashed this the output was gibberish.

in terms of if i have checked UART1INPROT_UBX and UART1OUTPROT_UBX, i do not know how to check that. Could you elaborate?

I’m pretty sure the M9 does not permit RTCM2 ingress so the 0007 is probably going to be rejected. SPG 4.04 should accept RTCM3 MSM messages for Pseudo-Range DGNSS operation, but doesn’t do Carrier Phase based RTK operation.

Cross-posting on uBlox forum, FYI

IN:UBX+NMEA+RTCM3 OUT:UBX+NMEA BAUD:115200

$PUBX,41,1,0023,0003,115200,0*1E\r\n

#include <HardwareSerial.h>
#define RXD2 16
#define TXD2 17

HardwareSerial GPS(2);

void setup() {
  Serial.begin(115200);
  GPS.begin(38400, SERIAL_8N1, RXD2, TXD2);
  delay(200);

  GPS.print("$PUBX,41,1,0023,0003,115200,0*1E\r\n");
  GPS.flush();
  delay(200);

  GPS.end();
  delay(100);
  GPS.begin(115200, SERIAL_8N1, RXD2, TXD2);

  Serial.println("Switched to 115200 baud. Listening for NMEA...");

  unsigned long start = millis();
  while (millis() - start < 20000) {
    while (GPS.available()) {
      Serial.write(GPS.read());
    }
  }
  Serial.println("\nTest finished.");
}

void loop() {}

Output is still gibberish.

This may well go to your primary issue of the NEO-M9N you’re using being unconfigurable.

I suppose it’s not one of the SparkFun models, previously you’ve linked to AliExpress sourced GY-GPS-NEOV3 type boards. I can’t speak to the veracity of their supply chain/sourcing.

A diagnostic log from uCenter Classic might help diagnose or understand your specific part better.

I will try out the diagnostic log later. I have never tried that before. Anything in particular i should be looking out for?

I will have to figure out how to do that log.

There’s a Round Red Record button, like an old tape deck. It initially saves the entire configuration space of the receiver. I’ve got my own tools to unpack and decode the .UBX files, but it would help get a baseline on what’s in the receiver, and perhaps what’s happening in your situation.

Boards from SparkFun, GNSS Store (Latvia) and MikroE (serbia), I’d have pretty high confidence of direct sourced / authentic uBlox parts.

I’ve previously posted forwarding/tunneling code that would allow uCenter to connect via an ESP32 (Arduino) attached NEO-M9N

Hey Clive. Sorry for getting back to you so late. I could not find time. So now i startet ,y U-Center v25.06 and i see the red button. I clicked on it, my explorer popped up chose my path i want it to be saved to. Then it said Add Receiver COnfiguration, u-blox Generation 9 of course and then a window popped up. It was polling some CFG-VALGET and most of them were rejected, there were some that have been accepted. But the issue i am having is that the Polling does not seem to be stopping. I just tried to eject it and the data is just the NMEA messages. Now i dont really know what Info you need me to provide. Mybe there is something in the “Transferring Configuration from GNSS to File”. Thank you for you help and patience clive. Happy to hear back from you.

I have a CH340 adapter*

I also tried to change the Dynamic Platform Model to automotive with u center 2. Also did not work.

Is this with the CH340 at 38400 with both RX/TX connected?

With the Arduino code I’d use a buffer, and forward in both directions. The code you show does a byte at a time in just the GPS output direction.

uCenter should be doing a wildcard query of the configuration keys, but that could perhaps saturate quickly ask the packets could get quite large. Would need to see the data to better understand how it is working vs failing.

You should be able to configure CFG-UART1-BAUDRATE in BBR and FLASH, get acknowledgement, and then power cycle into the new speed.

Yes, with RX/TX connected to the CH340. I see the Module i get a fix but when i try to config anything on there it does not let me. Baudrate, Dynamic platform model…

For the Arduino code, i should have a bidirectional pass through. I also tried that a few days ago but i will give it another try. So i Should have it connected to my ESP32 bridge and configure it thru U-Center 2. Config->Uart1->Baudrate and so on. Set a marker on BBR and FLASH and save it. I will try it later today.

Are you suggesting something like this?

void setup() {
  Serial.begin(38400);
  Serial2.setRxBufferSize(1024);
  Serial2.begin(38400, SERIAL_8N1, 16, 17);
}

void loop() {
  // GPS -> PC
  uint8_t buf[256];
  int count = 0;
  
  while (Serial2.available() && count < sizeof(buf)){
    buf[count++] = Serial2.read();
  }
  if (count > 0){
    Serial.write(buf, count);
  }

  // PC -> GPS
  uint8_t buf2[256];
  int count2 = 0;
  
  while (Serial.available() && count2 < sizeof(buf2)){
    buf2[count2++] = Serial.read();
  }
  if (count2 > 0){
    Serial2.write(buf2, count2);
  }
}

And then just with U-Center2.

Thank you for your time.

I flashed the code mentioned above and tried to configure it with U center 2. Nothing changed CFG->UART1->BAUDRATE, set to 115200. Send and only got red triangles back…

I also tried to do the Diagnostic log you mentioned. I started the recording and plugged the ESP32 in after, i got some GNTXT sentences at the start and i got just normal sentences. I have to note, that the “Transferring Configuration from GNSS to File” window never finished, it kept giving me things like these at the end:

“Removing this message now, because GNSS receiver did not accept it.
Polling: CFG-VALGET - B5 62 06 8B 08 00 00 00 C0 4D 00 00 FF 0F B4 9F …
… message rejected!
Removing this message now, because GNSS receiver did not accept it.
Polling: CFG-VALGET - B5 62 06 8B 08 00 00 00 00 4E 00 00 FF 0F F5 24 …
… message rejected!
Removing this message now, because GNSS receiver did not accept it.
Polling: CFG-VALGET - B5 62 06 8B 08 00 00 00 40 4E 00 00 FF 0F 35 A4 …
… message rejected!”

At the start it accepted some but then it just kept rejecting.

What do you want me to provide to you? The GNTXT messages? the Polling messages(I saved a few minutes of it)? Both?

This thing will make me lose my mind. I do not know, if i expect too much of this thing but in my perception these are very basic operations, i could be wrong though, this is the first time i am working with them.

Thanks again Clive.

I would expect changing the baud rate in RAM to have immediate effect, so you won’t see the response as the host is at the wrong speed.

The transferring configuration is enumerating thru consecutive wildcard keying 64 keys at a time to try and recover the whole configuration space.

I’d use the fact that available() should return a byte count, some thing along these lines

void loop() {
  uint8_t buf[128];
  int len;
  // GPS -> PC
  len = Serial2.available();
  if (len > 0)
  {
    if (len > sizeof(buf)) len = sizeof(buf);
    Serial2.readBytes(buf, len);
    Serial.write(buf, len);
  }

  // PC -> GPS
  len = Serial.available();
  if (len > 0)
  {
    if (len > sizeof(buf)) len = sizeof(buf);
    Serial.readBytes(buf, len);
    Serial2.write(buf, len);
  }
}

I’d like to see the configuration to better understand what’s going on. You’d need to post via a Google Drive or One Drive type file share.

Via the CH340 you should have reliable connectivity, you can’t however have TWO connections to the RX pin of the receiver, as these will contend/fight each other as the idle state is High, so either the CH340 or ESP32 should be connected. If you have two sources you’d need an AND gate or pair of diodes, but only one channel can talk at once.

I used the CH340. Tools->Receiver Config.->TransferGNSS to File

The first log ended pretty quickly and it seemed odd, because it has never done that, i saved that and then i tried it again. Second one finished with: “ATTENTION: There were errors/conflicts!
Please verify.”

Now i try it for a third time. I will Upload 3 logs and the output of the Transferring Configuration from GNSS to File window.

I also have a M6N laying around and there i managed to change the dynamic mode to Automotive, but on the M9N when i change it from portable to automotive it jumps right back to portable. As far as i know the M9N also supports legacy configs.

I will give the log a few minutes if it does not end by itself i will have to abort it.

PS: I aborted it.

Please let me know if i did something wrong.

Thanks

The NEO-6M would use UBX-CFG-NAV5 to change the Dynamics, but I’m not entirely sure if the size/version of the packet is exactly the same as that emulated by the NEO-M9N, it should load/stuff values into the CFG-NAVSPG-DYNMODEL in the underlying key-space.

If it snaps back it would tend to suggest a power issue (loss of setting by reset), or a rejection of the command (ACK-NAK)

CFG-NAVSPG-DYNMODEL = 4 (AUTO) into RAM, BBR and FLASH

B5 62 06 8A 09 00 00 07 00 00 21 00 11 20 04 F6 7D

I flashed

void setup() {
  Serial.begin(115200);
  Serial2.begin(38400, SERIAL_8N1, 16, 17);
  delay(2000);
  while (Serial2.available()) Serial2.read();

  uint8_t frame[] = {
    0xB5, 0x62, 0x06, 0x8A, 0x09, 0x00,
    0x00, 0x07, 0x00, 0x00,
    0x21, 0x00, 0x11, 0x20,
    0x04,
    0xF6, 0x7D
  };

  Serial2.write(frame, sizeof(frame));
  Serial2.flush();
  delay(1000);
  while (Serial2.available()){
    Serial.print(Serial2.read(), HEX);
    Serial.print(" ");
  }
  Serial.println();
}
void loop() {}





and

void setup() {
  Serial.begin(115200);
  Serial2.begin(38400, SERIAL_8N1, 16, 17);
  delay(2000);
  while (Serial2.available()) Serial2.read();

  uint8_t frame[] = {
    0xB5, 0x62, 0x06, 0x24, 0x24, 0x00,
    0x01, 0x00,
    0x04, 0x03,
    0x00, 0x00, 0x00, 0x00,
    0x10, 0x27, 0x00, 0x00,
    0x05, 0x00,
    0xFA, 0x00, 0xFA, 0x00,
    0x64, 0x00, 0x5E, 0x01,
    0x00, 0x3C, 0x00, 0x00,
    0x10, 0x27, 0x00, 0x00,
    0x00,
    0x00, 0x00, 0x00, 0x00, 0x00,
    0xBC, 0x2E
  };

  Serial2.write(frame, sizeof(frame));
  Serial2.flush();
  delay(1000);
  while (Serial2.available()){
    Serial.print(Serial2.read(), HEX);
    Serial.print(" ");
  }
  Serial.println();
}
void loop() {}

Both times with a NAK, i had it hooked up to external 5V with common ground to ESP32, would you say that its time to give up on this module?