Quansheng UV-K5 · Volume 6

Quansheng UV-K5 Volume 6 — Flashing & Recovery

The bootloader, k5prog and the browser web-flashers, why the binary is generation-specific, verifying the hardware generation before flashing, a reproducible workflow, and how to unbrick

6.1 About this Volume

Flashing a UV-K5 is the single moment where a $30 radio becomes a hacker’s tool — and the single moment where it is easiest to turn one into a paperweight. The good news is that the radio’s stock bootloader is a permanent, un-overwritable recovery path: the practical consequence is that almost every “brick” is a soft-brick, recoverable in two minutes without opening the case. This volume treats flashing as an engineering procedure with a verification step in front of it, not a point-and-pray web click.

The through-line is one fact that Volume 2 established at the silicon level and this volume turns into an operational rule: the firmware image is specific to the radio’s MCU generation. Flashing a binary built for the wrong generation is the most common way people soft-brick these radios. So the order of operations here is deliberate — identify the generation (§3), choose the matching image (§4), only then flash (§5–§7) — and recovery (§8) is presented as a routine step you should expect to use at least once while learning, not as an emergency.

Cross-references: Volume 2 is the hardware/MCU-generation reference (what DP32G030 / PY32F030 / PY32F071 are and how they differ); Volume 3 carries the supported-radios-and-firmware table that §4 depends on; Volume 7 covers channel-plan programming once the custom firmware is running; Volume 8 covers building your own image from source, which produces exactly the two files §2 describes.

6.2 The bootloader and the two-image build

The UV-K5’s MCU holds two logically distinct regions: a small bootloader at the bottom of flash that Quansheng programs at the factory and that custom firmware never touches, and the application region above it that holds the radio’s actual firmware. Powering the radio on while holding the right key tells the bootloader to stay resident and wait for a new application image over the serial cable, instead of jumping to the application. Because the bootloader itself is never rewritten by a normal flash, the recovery path in §8 is always available even after a failed flash — this is the architectural reason a UV-K5 is so hard to truly kill.

A custom-firmware build produces two files, and knowing which is which prevents a whole class of confusion:

Table 1 — A custom-firmware build produces two files, and knowing which is which prevents a whole class of confusion

FileWhat it isWho consumes it
firmware.binThe raw, un-obfuscated application imageEmulators, disassembly, some web-flashers that pack it for you
firmware.packed.binThe same image wrapped in the obfuscation layer + version string the stock bootloader expectsk5prog, and web-flashers that send the image verbatim

The “packing” is a lightweight obfuscation plus a version-string header the bootloader checks before it accepts the write — it is a format requirement, not security. The operational rule: send the image the tool asks for. Some web-flashers take the raw firmware.bin and pack it in the browser; k5prog and verbatim web-flashers want firmware.packed.bin. Fork release pages state which of the two the release .bin already is; when in doubt, the packed image is the one the radio’s bootloader natively accepts.

Note — the version string is a feature, not a nuisance. The bootloader echoes the packed image’s version string to the display during flashing. Reading that string back and confirming it matches the fork/version you intended is the cheapest possible sanity check that you fed the radio the file you meant to.

6.3 Verifying your hardware generation first

There are three firmware-incompatible hardware generations, distinguished by MCU. Volume 2 covers the silicon; here is the operational summary and how to read the generation off a radio in hand before you flash anything.

Table 2 — 3. Verifying your hardware generation first

GenMCURough eraFlash budgetFirmware reality
V1DP32G0302022 – early 2024SmallestThe classic target; the huge installed base. egzumer, F4HWN ≤ v4.3, VUURWERK all target it.
V2PY32F030transitionalSmall/mediumA Puya part that appeared as Quansheng second-sourced the MCU; narrower fork coverage.
V3PY32F071mid-2024 onwardLargestThe current target; F4HWN “Fusion” v5.x and the UV-K1 live here.

Ways to determine the generation, cheapest first:

  1. Ask the seller / check the production date. New stock is overwhelmingly V3 (PY32F071). Old or clearance listings skew V1 (DP32G030). This is a probability, not proof — verify in software.
  2. Read it back over the cable. With the programming cable connected and the radio in normal (not bootloader) mode, a programmer tool can read the firmware-info/metadata block. k5prog’s info read exposes the identifier the stock firmware reports.
  3. Let the bootloader tell you. Some web-flashers, on connecting to a radio in bootloader mode, read and display the chip/version identity before offering to flash. Reading that and matching it to the image you are about to send is the belt-and-braces check.
# Read the radio's stock firmware info over the cable (radio in NORMAL mode).
# The reported version/metadata encodes the MCU family — note it before flashing.
./k5prog -p /dev/ttyUSB0 -F

Callout — do this once, write it down. The generation never changes for a given physical radio. Determine it once, label the radio (a strip of tape on the battery reading V3 / PY32F071), and you never have to re-derive it. Mis-labelling is how the wrong-binary mistake in §10 happens.

6.4 Which .bin for your radio — the decision aid

With the generation known from §3, this maps it to a firmware choice. See Volume 3 for the full supported-radios-and-firmware table and Volume 4 for the ecosystem/fork comparison that justifies these picks; this is the fast operational version.

                 ┌─────────────────────────────────────────┐
                 │  What MCU does your radio report? (§3)      │
                 └───────────────┬─────────────────────────-┘
                                 │
        ┌────────────────────────┼────────────────────────────┐
        ▼                        ▼                             ▼
  DP32G030 (V1)            PY32F030 (V2)                 PY32F071 (V3)
        │                        │                             │
        ▼                        ▼                             ▼
  Daily driver:            Check the fork's               Daily driver:
  egzumer v0.22            release page for a             F4HWN "Fusion"
  (frozen, most-           V2/PY32F030 asset.             v5.9.0 (V3 + UV-K1)
  installed) OR            Coverage is the                │
  F4HWN v4.3 (last         narrowest of the three;        ▼
  V1 build) OR             a V3 image will NOT            Feature-rich,
  VUURWERK v1.5.0          run on a V2 and vice           actively maintained,
        │                  versa.                         largest flash headroom
        ▼
  Choose a *V1/DP32G030*
  asset from the release

Table 3 — 4. Which .bin for your radio — the decision aid

Your radio (from §3)Recommended imageWhyAlso runs
V1 — DP32G030egzumer v0.22 (frozen 2024-01-28)The most-installed, most-documented build; merges OneOfEleven’s refactor + fagci’s spectrumF4HWN v4.3 (last V1 build, 2025-12-02); VUURWERK v1.5.0 (2026-07-04)
V2 — PY32F030Whichever active fork publishes a V2 assetNarrowest coverage; match the exact PY32F030 asset—
V3 — PY32F071F4HWN “Fusion” v5.9.0 (2026-08-14)Current flagship fork; also covers the UV-K1Other forks as they publish V3/PY32F071 assets

Hard rule. The three generations are mutually incompatible. A V3 (PY32F071) image flashed to a V1 (DP32G030) radio — or any other mismatch — soft-bricks it. The radio is recoverable (§8), but the only way to avoid the detour is to match the generation to the asset on the release page, every time. Release pages name the generation in the filename or asset list; if a release offers only one .bin with no generation marker, assume it is the fork’s primary target (V1 for egzumer/VUURWERK, V3 for F4HWN Fusion) and confirm before flashing.

6.5 Entering bootloader (flash) mode

The flash procedure begins by forcing the bootloader to stay resident:

1. Power the radio OFF.
2. Connect the programming cable (3.5 mm + 2.5 mm dual plug) to the radio and PC.
3. Hold the PTT button (some fork docs also say hold the side/flashlight key).
4. While holding, switch the radio ON.
5. The display stays dark or shows a solid/patterned backlight, and (on many units)
   the flashlight LED lights — this is the bootloader waiting for an image.
6. Release the key. The radio will sit in this mode for a short window; start the
   flash promptly.

The exact key combination has drifted slightly across firmware eras and fork docs, which is why fork READMEs are the authority for the model in front of you. The reliable tell is the display: a normal power-on shows the UI; bootloader mode shows a dark/plain screen (and usually the lit flashlight), and the radio does not respond to the keypad.

Note. If the radio boots normally into its UI, it did not enter bootloader mode — power off and retry, holding the key before the power switch moves. A radio in normal mode will not accept a firmware write; the programmer will time out.

6.6 Flashing with k5prog

k5prog (sq5bpf, Python/C over the serial bootloader) is the command-line path. It is the tool of choice when scripting, when the browser Web Serial path is unavailable, or when you want an auditable, repeatable command rather than a GUI.

# 1. Build or download the image for YOUR generation (§4). Example: a V1 build.
#    egzumer's build emits firmware.bin (raw) and firmware.packed.bin (bootloader format).

# 2. Put the radio in bootloader mode (§5).

# 3. Confirm the serial device enumerated (clone cables use CH340/CP2102/PL2303):
dmesg | tail           # look for ttyUSB0 / ttyACM0
ls -l /dev/ttyUSB*

# 4. Flash the packed image. -p selects the port; -F selects flash-firmware mode.
./k5prog -p /dev/ttyUSB0 -F firmware.packed.bin

# 5. Power-cycle the radio. It boots into the new firmware.

A few operational notes:

  • Feed the packed image to k5prog. The raw firmware.bin is for emulators/disassembly (Volume 8); the bootloader wants firmware.packed.bin. Fork releases state which of the two their published .bin already is.
  • Serial permissions. On Linux, add your user to the dialout group (or run with sufficient privilege) so the port is writable without root: sudo usermod -aG dialout $USER then re-login.
  • Baud and timing are fixed by the bootloader. You do not tune them; k5prog already speaks the bootloader’s protocol. A timeout almost always means the radio is not actually in bootloader mode (§5) or the cable is bad (§10), not a baud-rate problem.

Callout — k5prog is also your EEPROM tool. The same utility reads and writes the channel/calibration EEPROM, which Volume 7 uses for channel-plan work. Firmware flashing and EEPROM programming are separate operations on the same cable; do not confuse a firmware flash (-F) with an EEPROM read/write.

6.7 The browser web-flashers

The mainstream, zero-install path is a Web Serial flasher that runs in a Chromium-based browser (Chrome/Edge). The community maintains several; egzumer ships one from the firmware project, and other forks link their own. The appeal is that there is nothing to install and the flasher can present the radio’s identity and the firmware version string in the UI before you commit.

Web-flasher workflow (Chromium-based browser, Web Serial):
  1. Open the fork's flasher page over HTTPS.
  2. Put the radio in bootloader mode (§5).
  3. Click "Connect" → the browser's serial-port picker appears → choose the
     radio's port (CH340/CP2102/PL2303).
  4. Select the firmware: either upload the .bin for YOUR generation, or pick
     from the flasher's built-in version list (confirm the generation!).
  5. Click "Flash". Watch the progress + the reported version string.
  6. Power-cycle.

Table 4 — 7. The browser web-flashers

PathStrengthsWatch-outs
Web-flasherNo install; shows radio identity + version; built-in version lists; cross-platformNeeds a Chromium-based browser with Web Serial; some pick-from-list menus make a wrong-generation choice one careless click away
k5prog (CLI)Scriptable, auditable, works headless; also does EEPROMManual install; you supply the correct image yourself

Note — Web Serial, not Bluetooth. These flashers drive the wired programming cable over the browser’s Web Serial API. Firefox and Safari do not implement Web Serial; use a Chromium-based browser or fall back to k5prog.

Callout — the generation trap in list-based flashers. The convenience feature — “pick egzumer v0.22 from the dropdown” — is also the hazard: the dropdown may default to one generation’s asset. Before clicking Flash, confirm the selected build matches the generation you determined in §3. A mismatch here is the single most common cause of the soft-brick in §8.

6.8 Recovery and unbrick

Because the bootloader is never overwritten (§2), a UV-K5 that “won’t turn on” after a bad flash is almost always a soft-brick: the application region is corrupt or holds a wrong-generation image, but the bootloader is intact and still listening. The recovery is simply flash again, correctly.

UNBRICK PROCEDURE
  1. Symptom: dark screen / no UI / won't boot after a flash.
  2. Do NOT panic-flash more wrong-generation images.
  3. Re-verify the generation (§3) — the brick is usually a generation mismatch.
  4. Enter bootloader mode (§5). A soft-bricked radio STILL enters bootloader mode;
     that is the whole point of the un-overwritable bootloader.
  5. Flash the CORRECT image for the generation (§6 or §7) — this can be the
     matching custom firmware, OR Quansheng's official stock firmware.
  6. Power-cycle. The radio returns.

Table 5 — 8. Recovery and unbrick

Recovery imageWhen to use
Correct-generation custom firmwareYou simply flashed the wrong generation; re-flash the right one
Quansheng official stock firmwareYou want a known-good baseline, or to return the radio to factory behaviour; download the stock image matching the generation from Quansheng’s channels

Hard rule — the bootloader is your safety net, so don’t poke it. Standard custom-firmware flashing never touches the bootloader and therefore never removes the recovery path. Avoid any “bootloader replacement” procedure unless you fully accept that it is the one operation that can produce a hard-brick requiring hardware (SWD) recovery. For normal modding, you never need to.

Callout — a truly dead radio (rare). If the radio will not even enter bootloader mode — no dark-screen state, no response on the cable with a known-good cable — the causes are almost always outside the firmware: a dead battery, a bad cable (§10), or hardware damage. Rule those out before concluding the bootloader is gone; a genuinely corrupted bootloader is uncommon and would need SWD-level reflashing on the MCU, which is out of scope for a $30 radio.

6.9 A reproducible flashing workflow

Putting §3–§8 together as a checklist you can run every time, V1 example shown:

UV-K5 FLASH — REPRODUCIBLE WORKFLOW
────────────────────────────────────────────────────────────
[ ] 0. Charge the battery to >50%  (brownout mid-flash is avoidable grief)
[ ] 1. IDENTIFY generation (§3):  k5prog -p /dev/ttyUSB0 -F  → read MCU metadata
        → write it on the radio's tape label (e.g. "V1 / DP32G030")
[ ] 2. CHOOSE image (§4):  download the asset whose filename/notes name THIS gen
        → verify the fork + version is the one you intend
[ ] 3. BACK UP (optional but wise):  k5prog read of the EEPROM (channels+cal) → Vol 7
[ ] 4. CABLE check:  dmesg / ls /dev/ttyUSB*  → note CH340/CP2102/PL2303
[ ] 5. BOOTLOADER mode (§5):  power off → hold PTT → power on → dark screen + light
[ ] 6. FLASH (§6 or §7):
        CLI:  ./k5prog -p /dev/ttyUSB0 -F firmware.packed.bin
        Web:  Connect → select THIS-gen image → Flash → watch version string
[ ] 7. VERIFY:  confirm reported version string == intended fork/version
[ ] 8. POWER-CYCLE → radio boots new firmware
[ ] 9. RESTORE channels/settings (Vol 7) if the flash reset the EEPROM layout
────────────────────────────────────────────────────────────
If step 8 fails → you are at §8 (unbrick): re-verify gen, re-enter bootloader,
re-flash the CORRECT image (custom or stock). The bootloader is still there.

Note — back up the EEPROM before your first flash. Custom firmwares can reorganise the EEPROM channel layout, and a factory-stock radio holds calibration data in the high EEPROM region (Volume 7 §memory-map) that you never want to lose. A one-command EEPROM read with k5prog captures channels and calibration as a file you can write back; it costs thirty seconds and is cheap insurance.

6.10 Pitfalls and gotchas

Table 6 — 10. Pitfalls and gotchas

PitfallSymptomFix
Wrong-generation binarySoft-brick: dark screen, no boot after flash§8 — re-enter bootloader, flash the correct-generation image. Prevent by labelling the radio (§3).
Bad / miswired clone cablek5prog timeout or junk; web-flasher can’t connectTry another cable; confirm the USB-serial bridge driver (CH340/CP2102/PL2303) matches what enumerated
Radio not actually in bootloaderProgrammer times out; radio shows normal UIRe-do §5, holding the key before flipping the switch; confirm dark screen + flashlight
Non-Chromium browser for web-flasherNo “Connect” button / Web Serial unavailableUse Chrome/Edge (Web Serial), or fall back to k5prog
Raw vs packed image mismatchBootloader rejects the imageFeed k5prog/verbatim flashers the .packed.bin; let packing-aware flashers take the raw .bin
Battery brownout mid-flashFlash stalls / radio resets partwayCharge to >50% first; the flash itself is brief but a dying cell can reset the MCU
Lost channels/calibration after flashMemories gone; TX power or squelch offRestore the EEPROM backup (§9 step 3); never overwrite the calibration region (Vol 7)
Port permissions (Linux)Permission denied on /dev/ttyUSB0Add user to dialout, re-login; avoid blanket root if you can

Callout — the one habit that prevents most grief. Every soft-brick story traces back to a skipped identification step. Determine the generation once, label the radio, and confirm the image’s generation on the release page and in the flasher UI before clicking. Everything else in this table is a cable or a battery.

See Volume 7 for channel-plan programming now that custom firmware is running, Volume 8 to build the image yourself from source, and Volume 3 for the full supported-radios-and-firmware table referenced throughout.

Comments (0)

  1. Loading…

Comments are held for moderation — nothing appears until approved.