Firmware Update
The LC29H module contains a Broadcom BCM4775 GNSS SoC with SPI flash storing the firmware image. The lc29h firmware commands communicate with the BCM4775’s ROM bootloader to read, write, and verify flash contents. All operations except firmware info require a bootloader.pkg file that establishes the bootloader session and configures the flash interface.
See Firmware Internals for protocol details, bootloader package structure, and the reverse-engineered FlashUpdater analysis.
Prerequisites
Section titled “Prerequisites”- bootloader.pkg — included with the Waveshare wiki downloads and the LC29H_EVB package. Set the
LC29H_BOOTLOADERenvironment variable to its path, or place the file in your current working directory:
export LC29H_BOOTLOADER=/path/to/bootloader.pkg-
Exclusive serial access — the module enters bootloader mode during backup, update, and verify operations, which interrupts NMEA output. Close any other program using the serial port (monitor sessions, MCP server, gpsd) before proceeding.
-
Stable power supply — the module must not lose power during flash erase or write operations. If running from a Raspberry Pi, use a quality power supply rated for the full board draw plus peripherals.
Commands
Section titled “Commands”firmware info
Section titled “firmware info”Safe, read-only query using standard NMEA/proprietary sentences. Returns the same version data as lc29h info but organized under the firmware subcommand group. No bootloader entry, no bootloader.pkg required.
lc29h firmware infoModel: LC29HDAANR11A01SFirmware: LC29HDANR11A01S_RSABuilt: 2024/02/23 17:58:32Chip: Airoha AG3335AChip FW: AXN_5.8.3_LLAC29Hfirmware backup
Section titled “firmware backup”Enters the BCM4775 bootloader, reads the entire SPI flash, and writes it to a local binary file. A progress bar tracks the read operation.
# Default filename: FlashBackup_YYYYMMDD-HHMMSS.binlc29h firmware backup
# Custom output pathlc29h firmware backup -o my_backup.binEntering bootloader...Reading flash: [####################] 100% 2048 KBSaved to FlashBackup_20260227-143012.binThe backup file is a raw byte-for-byte copy of the flash contents. Keep it somewhere safe — this is your recovery path if an update goes wrong.
firmware update
Section titled “firmware update”Erases the SPI flash and writes a new firmware image. This is the most dangerous operation in the toolchain. The --yes flag is mandatory to confirm you understand the risks.
# Standard update (auto-backup first)lc29h firmware update firmware.bin --yes
# Skip the automatic pre-update backuplc29h firmware update firmware.bin --yes --skip-backup
# Write at a specific flash offset (must be 4 KB aligned)lc29h firmware update firmware.bin --yes --offset 0x1000
# Specify bootloader path explicitlylc29h firmware update firmware.bin --yes --bootloader /path/to/bootloader.pkg| Option | Description |
|---|---|
--yes | Required. Confirms destructive operation. Without this flag, the command refuses to run. |
--skip-backup | Skip the automatic flash backup before erasing. Saves time but removes your safety net. |
--offset HEX | Flash write offset in hex. Must be 4 KB (0x1000) aligned. Default is 0x0. |
--bootloader PATH | Explicit path to bootloader.pkg. Overrides LC29H_BOOTLOADER env var and working directory search. |
Entering bootloader...Backing up current flash...Reading flash: [####################] 100% 2048 KBSaved to FlashBackup_20260227-143012.binErasing flash...Writing firmware: [####################] 100% 1847 KBVerifying write: [####################] 100% 1847 KBCRC OK — firmware update completeModule rebooting...Exit codes:
| Code | Meaning |
|---|---|
0 | Success |
1 | General error (serial failure, file not found, etc.) |
2 | Chip ID mismatch — the bootloader.pkg does not match the connected module revision |
3 | CRC verification failed after write |
4 | User abort (Ctrl+C during safe phase, before erase begins) |
firmware verify
Section titled “firmware verify”Read-only CRC comparison between a firmware image file and the current flash contents. Enters the bootloader to read flash but does not modify anything.
lc29h firmware verify firmware.binEntering bootloader...Reading flash: [####################] 100% 1847 KBComparing CRC... OKFlash contents match firmware.binIf the CRC does not match, the command prints the expected and actual values and exits with code 3.
Typical Workflow
Section titled “Typical Workflow”-
Check current firmware version
Start with
firmware infoto see what is currently running. This is safe and fast — no bootloader involved.Terminal window lc29h firmware info -
Backup existing flash
Read the full flash contents to a local file. This is your rollback path.
Terminal window lc29h firmware backup -o before_update.bin -
Update with new firmware
Write the new image. The command will perform an automatic backup (unless
--skip-backupis passed), erase, write, and verify in sequence.Terminal window lc29h firmware update new_firmware.bin --yes -
Verify the write
Confirm the flash contents match the source image. This is a separate read pass with independent CRC calculation.
Terminal window lc29h firmware verify new_firmware.binAfter verification, the module reboots automatically. Run
lc29h firmware infoagain to confirm the new version string.
MCP Tools
Section titled “MCP Tools”The same firmware operations are available as MCP tools through the lc29h-mcp server. The MCP server automatically pauses its NMEA monitor during bootloader operations and resumes afterward.
| MCP Tool | CLI Equivalent | Notes |
|---|---|---|
firmware_info | lc29h firmware info | Safe, NMEA-only query |
firmware_backup | lc29h firmware backup | Returns backup file path |
firmware_update | lc29h firmware update | Requires confirm=True parameter (equivalent to --yes) |
firmware_verify | lc29h firmware verify | Returns CRC match result |
You: Back up the current firmware and tell me what version is running.
Claude: I'll query the module info and start a backup.[Calls firmware_info][Calls firmware_backup]
The module is running LC29HDANR11A01S_RSA, built 2024-02-23.Flash backup saved to FlashBackup_20260227-151200.bin (2048 KB).Troubleshooting
Section titled “Troubleshooting””bootloader.pkg not found”
Section titled “”bootloader.pkg not found””The firmware commands search for bootloader.pkg in this order:
--bootloaderflag (CLI) orbootloader_pathparameter (MCP)LC29H_BOOTLOADERenvironment variablebootloader.pkgin the current working directory
Set the environment variable in your shell profile to avoid repeating the path:
echo 'export LC29H_BOOTLOADER=/opt/lc29h/bootloader.pkg' >> ~/.bashrcsource ~/.bashrc“Chip ID mismatch”
Section titled ““Chip ID mismatch””The bootloader package contains a chip identifier that must match the connected module’s BCM4775 revision. This error means you have the wrong bootloader.pkg for your hardware. Check the Waveshare wiki downloads for a version matching your specific module variant (AA, BA, CA, DA, BS).
”CRC verification failed”
Section titled “”CRC verification failed””The post-write CRC check did not match. Possible causes:
- Marginal serial connection — check cable and connections, try a lower baud rate
- Flash wear — unlikely on a new module but possible on heavily cycled hardware
- Corrupted firmware image — re-download and verify the source file checksum
Retry the update. If CRC failures persist across retries, the flash may have bad sectors.
Module unresponsive after update
Section titled “Module unresponsive after update”The module takes up to 30 seconds to boot after a flash write. If it does not respond after 30 seconds:
- Power cycle the module (disconnect and reconnect power, or toggle the HAT’s power pin)
- Wait 30 seconds for the full boot sequence
- Try
lc29h firmware infoat the default 115200 baud
If the module still does not respond, it may need recovery via the backup image:
lc29h firmware update before_update.bin --yes --skip-backupSerial port busy
Section titled “Serial port busy”Close all programs that might hold the serial port open — lc29h monitor, lc29h-mcp, gpsd, screen, minicom. The bootloader requires exclusive serial access. On Linux, check what has the port open:
fuser /dev/ttyS0