STM32WB55 Factory Addresses Follow the Selector Before Rewriting OTP
A factory station can verify that a Bluetooth address was stored correctly while the product continues advertising a different address. On STM32WB55, the first thing to inspect is the application’s address-selection function. In the pinned ST example, a valid device identifier takes precedence over the OTP record. Changing the record alone does not change that branch.
This review targets the P-NUCLEO-WB55.Nucleo BLE_p2pServer application in STM32CubeWB v1.24.0, commit 7c5aa7dcd2c0abe787f922bb06a6213c724d08e4. It concerns public-address selection and manufacturing verification, not pairing-key provisioning or STM32WBA. No OTP was programmed and no advertising capture was performed.
Find the branch that selects the six bytes
The example’s BleGetBdAddress function first reads the UDN. When that value differs from 0xFFFFFFFF, it builds an address from the ST company ID, device ID and the low 16 UDN bits. Only the alternative branch calls OTP_Read(0). A missing matching OTP record then falls back to the compiled address.
That ordering creates three different questions for production support: were the intended bytes stored, did the running application select those bytes, and did the controller accept the selected address? A positive answer to the first question cannot answer the other two.
Before touching permanent storage, record the selected branch using a development build. Log a source label such as PRODUCT_RECORD, DEVICE_DERIVED or DEVELOPMENT_FALLBACK alongside the selected public bytes. Do not put authentication material into that diagnostic record.

Original source-derived decision diagram. It describes the selected example, not an observed production device.
Separate an example fallback from product policy
A shared compiled address is convenient for a demonstration but is a poor silent fallback for a production identity record. If ten devices reach that branch, changing their serial labels does not make their selected Bluetooth addresses different.
Define the product’s intended source explicitly. For a product that uses an allocated public-address pool, the selector should validate and use its own manufacturing record according to that format. If the record is missing or invalid, fail the identity check and expose a serviceable error. Do not silently manufacture a plausible address by rearranging an unrelated serial number.
The example itself warns that its ST-company-ID construction should not be treated as the final product’s public-address allocation. AN5289 Rev 18, section 8.6.1 likewise discusses obtaining and persistently storing a different public address. Treat address assignment as a separate approved product decision, then make the firmware implement that decision consistently.
A useful original policy sketch is:
read the product identity record
if record format or address assignment is invalid:
report identity provisioning failure
do not enter normal public-address advertising
else:
select the record's six address bytes
configure the controller and require success
record which identity source was selected
This is a review outline, not drop-in STM32 code. Record validation, recovery access and permitted factory modes depend on the actual product.
Do not confuse record lookup with address validation
The pinned OTP_Read implementation scans eight-byte slots backward from the configured end, comparing the final byte with the requested ID. It returns the matching slot or null. That lookup does not establish that an address belongs to the product’s assigned range or matches the current unit’s manufacturing record.
Keep the checks separate in the station report. “Record found” identifies storage and lookup success. “Identity accepted” should mean the product’s format, assignment and uniqueness checks passed. Neither justifies rewriting OTP to work around an application branch that never selects it.
Use an injectable record reader or an ordinary development-flash fixture to exercise missing and malformed records. Permanent storage is unnecessary for testing control flow and makes mistaken test iterations difficult to reverse.
Preserve byte order through configuration and inspection
The example supplies a six-byte array to aci_hal_write_config_data, then prints it in reverse index order for the familiar colon-separated representation. A station that compares the raw array directly with the displayed string can report a false mismatch.
Define both representations in the manufacturing format sheet. Use an asymmetric synthetic address in software fixtures so a reversed sequence is obvious. This fixture is for byte-order testing only and must not be advertised as an assigned public address.
Also confirm the active GAP address mode. A scanner observation under a random or privacy-enabled mode is not automatically a readback of the configured public address. Keep controller configuration evidence and over-the-air observations as separate fields, and compare only the representations that the selected mode makes comparable.
Make address selection a release gate
Proposed qualification cases include a valid product record with a valid UDN, an absent record, an invalid record, two units with different assigned records, and a firmware update that preserves identity. The first case is especially important because it exposes an unchanged example selector that bypasses the record.
Require the same selected identity after the intended reset and service paths, successful controller configuration, and no unintended development fallback. Preserve the application commit, identity-format version and selected-source label with each result. These checks turn a confusing “OTP write succeeded but address did not change” incident into a precise disagreement between storage, firmware policy and controller setup.