Enabling Data CRC in Zephyr NVS: Plan the Migration Before Shipping the Firmware
Enabling CONFIG_NVS_DATA_CRC changes how Zephyr NVS interprets stored elements. Export and validate existing settings while a compatible reader can still read them, then import them into a deliberately prepared CRC-enabled store. Simply changing the build option does not append checksums to records already in flash.
Applicability: this article checks Zephyr v4.2.0 documentation, Kconfig, API declarations, and implementation. It concerns NVS element compatibility, not a generic database schema upgrade. The proposed preservation path assumes enough storage for an old NVS region, a separate staging area, and a new NVS region. If the hardware cannot provide that space, choose and qualify a different recovery path before releasing the option change.

1. Identify which CRC already protects the data
The v4.2.0 NVS documentation separates metadata CRC from optional payload CRC-32. It explicitly warns that enabling data CRC on an existing store without it invalidates existing data. Metadata validity therefore cannot establish payload compatibility with the new build.
The tagged Kconfig states that the data CRC occupies four additional bytes at the end of an element’s data field. It is a build-time option, not a per-nvs_fs migration switch. Two filesystem objects in one ordinary build do not automatically become independent legacy and CRC-enabled decoders.
Record the shipping firmware’s resolved configuration, Zephyr revision, partition map, erase geometry, and every stored identifier with its expected payload length. Include rarely changed records, optional records, and records owned by libraries. A successful upgrade on a newly erased board says nothing about a long-lived device’s existing store.
2. Prove the incompatibility with preserved fixtures
Create disposable flash images using the actual old build, including small scalar values, long records, absent optional identifiers, and multiple historical writes. Keep an untouched copy of each image. Run the candidate reader against copies and record mount status, each full read’s result, returned length, and validation outcome. Do not erase on a read failure during this experiment.
The v4.2.0 implementation subtracts CRC storage from the interpreted payload length and checks the CRC on a full-element read. A short legacy element and a longer legacy element can therefore fail differently. Mount success is not evidence that every application setting remains readable.
Do not use a partial read as the acceptance test. The documented CRC check requires the whole element. In the import verification path, provide a buffer large enough for the complete expected payload and require both a valid result and the exact expected logical length. Treat an unexpected length as an error even if the copied prefix looks plausible.
3. Build a bridge while the old reader still works
A concrete preservation strategy uses an intermediate export-capable firmware built with the old CRC expectation. It reads the old NVS region through its supported API and writes a versioned export to a separate, independently specified staging format. That format must be readable by both firmware stages and must not depend on the changing NVS option.
The export should contain a format identifier, export generation, required-record inventory, explicit identifier and length fields, payloads, and an integrity check. Validate all required records and application ranges before declaring the export complete. If credentials or private settings are included, retain their protection and access restrictions; CRC is not encryption or authentication.
Use a staging mechanism with a qualified interrupted-write protocol. For example, a product can reserve redundant staging slots and select only a fully validated completed export while preserving the previous valid slot. Slot layout, completion marking, erase alignment, and integrity coverage must be specified and power-cut tested. Merely creating an export filename or writing a Boolean flag is insufficient evidence of durable completion.
After exporting, freeze relevant setting changes until the import completes or force a fresh export after any change. Otherwise the firmware update can faithfully import a stale snapshot. Associate the export generation with the update attempt so repeated boots cannot confuse an earlier snapshot with the current one.
4. Import into a separate CRC-enabled destination
- Verify the export first. The new build validates the staging format, generation, full inventory, lengths, integrity, and application constraints before modifying the destination.
- Select the new partition explicitly. Use the reviewed new-region mapping. Do not point CRC-enabled NVS at the old region and hope failed reads will create compatible records.
- Write every required identifier. Check the return from each write and retain the export and old region. Handle an interrupted import as a recoverable incomplete state.
- Read back complete elements. Compare logical payloads and expected lengths with the export. Verify application relationships across records, not just their individual CRCs.
- Declare readiness last. Record the validated export generation using a qualified completion mechanism. On later boots, verify the marker and required data before admitting ordinary application use.
The v4.2.0 API documents that an unchanged rewrite can return zero rather than the requested byte count. Design retry handling around that contract and verify by full readback. A zero return must not be confused with a missing required record, nor should every successful retry be rejected as a short write.
5. Preserve one authoritative state across retries
Suppose a hypothetical environmental logger stores its sampling interval, channel labels, and alarm limits. A reset after importing the labels but before the limits must leave the application in import mode. It should continue or restart import from the same verified export, then validate the complete destination. It must not run with imported labels and default limits merely because both values are individually legal.
Once the new store becomes authoritative and settings can change again, a stale export must never overwrite it during an ordinary reboot. Define separate incomplete-import and normal-operation states. Test the transition around the final readiness record, including a reset immediately before and immediately after it.
Keeping the old NVS region supports recovery of the old snapshot, but does not automatically make later downgrade safe. The old firmware may not know the new partition or changes made after import. Decide when rollback is permitted, how stale state is reported, and when retained storage may be reclaimed.
6. Qualify capacity and failure behavior before rollout
Budget the additional CRC bytes together with flash alignment, metadata, record history, and garbage-collection headroom. Do not calculate usable capacity by adding four bytes to each live setting and ignoring the sector layout. Test maximum supported record sizes and a nearly full destination using the actual flash driver.
Interrupt export, slot finalization, image transition, each import write, readback, and readiness publication on a disposable test setup. Also test missing staging data, corrupted exports, invalid legacy settings, repeated update attempts, and a forbidden downgrade. Preserve the source region until the recovery evidence supports deletion.
The deliverable is a verified old-to-new data path with explicit stop states, not a changed Kconfig line. No Zephyr firmware, flash device, or migration test was executed for this article. The described bridge and fault campaign are proposed engineering work requiring qualification before deployment.