UBX Protocol Checksum Calculator

Calculate u-blox UBX protocol CK_A and CK_B checksums. Paste raw hex bytes or use the message builder for CFG, NAV, and ACK message classes.

Raw UBX bytes (hex)

Include or omit B5 62 sync bytes — detected automatically. If the last 2 bytes match the checksum, the existing checksum is validated.

Result

Paste UBX hex bytes to compute checksum.

Common UBX messages

NameClassIDPayloadDescription
CFG-PRT0x060x0020BPort configuration (UART/SPI/USB)
CFG-MSG0x060x018BEnable/disable NMEA or UBX messages per port
CFG-RATE0x060x086BNavigation/measurement rate
CFG-GNSS0x060x3EvariableGNSS system configuration (GPS/GLONASS/Galileo)
CFG-CFG0x060x0912BSave/load/clear configuration to flash
NAV-PVT0x010x0792BNavigation position velocity time solution
NAV-STATUS0x010x0316BReceiver navigation status
NAV-DOP0x010x0418BDilution of precision
NAV-SOL0x010x0652BNavigation solution (legacy, use NAV-PVT)
ACK-ACK0x050x012BMessage acknowledged
ACK-NAK0x050x002BMessage not acknowledged

How it works

UBX uses an 8-bit Fletcher algorithm over the message body. The checksum covers the class byte, ID byte, 2-byte little-endian length, and the payload. The sync bytes (0xB5 0x62) are explicitly excluded.

CK_A = 0, CK_B = 0
for each byte B in [CLASS, ID, LEN_LO, LEN_HI, PAYLOAD...]:
    CK_A = (CK_A + B) & 0xFF
    CK_B = (CK_B + CK_A) & 0xFF

The full message frame is:

0xB5  0x62  CLASS  ID  LEN_LO  LEN_HI  [PAYLOAD...]  CK_A  CK_B

Example — CFG-MSG (0x06 0x01) to enable GGA on UART1 at 1Hz:

B5 62 06 01 08 00 F0 00 00 00 00 00 00 01 → CK_A=FB, CK_B=49
Full: B5 62 06 01 08 00 F0 00 00 00 00 00 00 01 FB 49

C implementation

void ubx_checksum(const uint8_t *buf, size_t len,
                  uint8_t *ck_a, uint8_t *ck_b) {
    /* buf points to CLASS byte (after the two sync bytes) */
    /* len = 4 + payload_length (class + id + 2 length bytes + payload) */
    *ck_a = 0;
    *ck_b = 0;
    for (size_t i = 0; i < len; i++) {
        *ck_a += buf[i];
        *ck_b += *ck_a;
    }
}

Call it as:

uint8_t msg[] = {0x06, 0x01, 0x08, 0x00,
                 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
uint8_t ck_a, ck_b;
ubx_checksum(msg, sizeof(msg), &ck_a, &ck_b);
/* ck_a = 0xFB, ck_b = 0x49 */

Common mistakes

Including sync bytes in the checksum. The 0xB5 and 0x62 sync chars are frame delimiters, not message content. Starting the checksum from byte 0 of the buffer instead of byte 2 is the most common bug.

Little-endian length field. The length is a 16-bit value in little-endian order. A 8-byte payload → 0x08 0x00, not 0x00 0x08.

Off-by-one on payload length. The length field encodes only the payload size. It does not include class, ID, length bytes, or checksum bytes. Getting this wrong shifts the checksum window by 4 bytes.

ACK/NAK handling. After sending a CFG message, the receiver responds with ACK-ACK (0x05 0x01) or ACK-NAK (0x05 0x00). Always parse the response before sending the next command. Sending CFG messages faster than the receiver can process them causes silently dropped configuration.

Not persisting config. CFG messages only update RAM by default. Send CFG-CFG (0x06 0x09) with saveMask = 0xFFFF to persist to flash/battery-backed RAM, otherwise your configuration resets on power cycle.

Practical u-blox tips

To switch the receiver to output NMEA GGA + RMC only, and disable all other NMEA sentences, send CFG-MSG for each sentence type (F0 00 through F0 08) with the rate byte set to 0 or 1 for the target port.

For polling: send a poll request (class + ID + length 0x00 0x00, no payload) and the receiver replies with the current configuration. Useful for reading out current port settings via CFG-PRT (0x06 0x00) before changing them.