Boot Self-Test & Traceability¶
Authoritative specification for the EverTag Station boot self-test sequence, traceability record format, and diagnostic error codes. The self-test runs automatically on every boot. Results are reported on UART0 and LED1 during the 5-minute active window.
Design Principle: Diagnostic, Not Protective
The self-test is observational, not gatekeeping. All test results are reported but no test result prevents the device from completing initialization and joining the Wirepas network. The production test station or cloud monitoring system is responsible for acting on error codes. The firmware's role is to detect and report -- not to halt boot.
1. Boot Sequence & Self-Test Timing¶
The self-test runs as part of the standard boot sequence, after board detection and before peripheral initialization. The entire test phase completes in 2--5 seconds.
graph TD
BOOT["Boot"] --> V_SAMPLE["1. Read V_SAMPLE (P1.07) — board variant"]
V_SAMPLE --> EXT["2. Read EXT_DETECT (P1.12) — extension board"]
EXT --> BAT["3. Read BAT_VOLTAGE (P1.06) — battery variants"]
BAT --> SELFTEST["4. Run self-test suite for detected variant"]
SELFTEST --> RECORD["5. Output traceability record on UART0"]
RECORD --> RESULTS["6. Output self-test results on UART0"]
RESULTS --> MUX["7. Configure GPIO mux"]
MUX --> INIT["8. Initialize peripherals for detected board"]
INIT --> LED["9. LED1 enters active mode (5-min timer)"]
LED --> DIAG{"Errors detected?"}
DIAG -->|"Yes"| BLINK["LED1: Diagnostic blink mode (error codes)"]
DIAG -->|"No"| NORMAL["LED1: Normal status (WHITE → YELLOW → GREEN)"]
BLINK --> JOIN["10. Join Wirepas network (always, regardless of errors)"]
NORMAL --> JOIN
UART0 Active Window¶
UART0 outputs the traceability record and self-test results immediately after the test phase completes (~3 seconds into boot). UART0 remains available for CLI commands throughout normal operation. The 5-minute active window refers to the LED -- UART0 is not time-limited.
LED Diagnostic Window¶
During the 5-minute active window after boot, LED1 shows either diagnostic blink patterns (if errors exist) or normal status progression (if all tests pass). After 5 minutes, LED1 enters dormant mode regardless of errors. Error flags remain in RAM and are queryable via CLI (status command), NFC, and Wirepas status messages.
2. Traceability Record Format¶
The traceability record is output on UART0 (115200 8N1) as a flat KEY:VALUE block. Every key is on its own line. No spaces in values. Delimited by ---BEGIN_TRACE--- and ---END_TRACE--- markers.
Format Rules¶
- One
KEY:VALUEpair per line. Colon separates key from value. - Keys are UPPER_SNAKE_CASE. No spaces.
- Values contain no spaces. Multi-word values use underscores or hyphens.
- The test station parses by scanning for markers and extracting any key with:
grep "^KEY:" | cut -d: -f2- - The device does not output a wall-clock timestamp. The test station records its own timestamp when capturing the trace (Option B).
Full Traceability Record¶
---BEGIN_TRACE---
FW_IMAGE:evertag-anchor-nrf54
FW_VERSION:1.0.0
FW_BUILD:2026-02-24T14:32:05
FW_GIT:a3f7c21
WP_STACK:5.6.0
BOOTLOADER:1.0.0
NRF54_DEVID:7A3B1C4D9E8F2A1B
NRF54_BLEADDR:F4:CE:36:A1:B2:C3
NRF54_FLASH_KB:256
NRF54_RAM_KB:256
NRF54_VARIANT:QFAA
ST25DV_UID:02E3440000160200
ST25DV_MEM_KBIT:4
ESP32_CHIPID:N/A
ESP32_MODEL:N/A
ESP32_REVISION:N/A
ESP32_FLASH_MB:N/A
ESP32_FW_VERSION:N/A
ESP32_FW_BUILD:N/A
BOARD_ARTICLE:232201
V_SAMPLE_RAW:1016
EXTENSION:NONE
EXT_DETECT_RAW:12
BAT_VOLTAGE:3.24
BAT_VOLTAGE_RAW:2654
CHARGER_STATE:CHARGING
AC_POWER:PRESENT
VDD_3V3:3.31
DIE_TEMP_C:27
LFXO:OK
WP_NODE_ADDR:70001
WP_NET_ADDR:0x1234
WP_NET_CHAN:15
SELF_TEST:PASS
ERROR_CODES:NONE
ERROR_COUNT:0
---END_TRACE---
Field Reference¶
Silicon Identifiers (immutable, factory-programmed)¶
| Key | Source | Example | Description |
|---|---|---|---|
NRF54_DEVID |
FICR DEVICEID[0:1] |
7A3B1C4D9E8F2A1B |
64-bit unique device ID, factory-burned by Nordic |
NRF54_BLEADDR |
FICR DEVICEADDR[0:1] |
F4:CE:36:A1:B2:C3 |
48-bit BLE address |
NRF54_FLASH_KB |
FICR INFO.FLASH |
256 |
Flash size in KB |
NRF54_RAM_KB |
FICR INFO.RAM |
256 |
RAM size in KB |
NRF54_VARIANT |
FICR INFO.VARIANT |
QFAA |
Chip variant (package + memory) |
ST25DV_UID |
I2C system area read | 02E3440000160200 |
8-byte ISO 15693 unique ID |
ST25DV_MEM_KBIT |
I2C system area read | 4 |
NFC memory size (4 = ST25DV04K) |
ESP32_CHIPID |
esp_efuse_mac_get_default() via UART1 |
00A1B2C3D4E5 |
ESP32 48-bit MAC-derived unique ID. N/A on non-gateway. |
ESP32_MODEL |
ESP32 system info via UART1 | ESP32-C5 |
SoC model. N/A on non-gateway. |
ESP32_REVISION |
ESP32 efuse via UART1 | 0 |
Silicon revision. N/A on non-gateway. |
ESP32_FLASH_MB |
ESP32 SPI flash detect via UART1 | 4 |
Flash size in MB. N/A on non-gateway. |
Firmware Identifiers (compiled into the binary)¶
| Key | Source | Example | Description |
|---|---|---|---|
FW_IMAGE |
Build system #define |
evertag-anchor-nrf54 |
Firmware build name |
FW_VERSION |
Semantic version | 1.0.0 |
Major.Minor.Patch |
FW_BUILD |
__DATE__ + __TIME__ |
2026-02-24T14:32:05 |
Compile timestamp (ISO 8601) |
FW_GIT |
Build system | a3f7c21 |
Short SHA of source commit |
WP_STACK |
Wirepas SDK version | 5.6.0 |
Wirepas mesh stack version |
BOOTLOADER |
Bootloader version area | 1.0.0 |
Secure boot / DFU bootloader version |
ESP32_FW_VERSION |
Queried via UART1 | 0.8.1 |
ESP32 firmware version. N/A on non-gateway. |
ESP32_FW_BUILD |
Queried via UART1 | 2026-02-24T14:35:00 |
ESP32 firmware build date. N/A on non-gateway. |
Hardware Configuration (detected at boot)¶
| Key | Source | Example | Description |
|---|---|---|---|
BOARD_ARTICLE |
V_SAMPLE ADC → lookup | 232201 |
Decoded board variant |
V_SAMPLE_RAW |
P1.07 SAADC | 1016 |
Raw 12-bit ADC value |
EXTENSION |
EXT_DETECT ADC → lookup | NONE |
Detected extension board (NONE, 232210, 232211) |
EXT_DETECT_RAW |
P1.12 SAADC | 12 |
Raw 12-bit ADC value |
Runtime Measurements (measured during self-test)¶
| Key | Source | Example | Description |
|---|---|---|---|
BAT_VOLTAGE |
P1.06 SAADC (via divider) | 3.24 |
Battery voltage in V. N/A on non-battery variants. |
BAT_VOLTAGE_RAW |
P1.06 SAADC | 2654 |
Raw 12-bit ADC value. N/A on non-battery. |
CHARGER_STATE |
P2.03 / P2.04 GPIO + BAT_VOLTAGE | CHARGING |
CHARGING, COMPLETE, STANDBY, or NO_AC. N/A on non-battery. |
AC_POWER |
P2.03 (DC_PRESENT) | PRESENT |
PRESENT or ABSENT. N/A on non-battery. |
VDD_3V3 |
nRF54 internal SAADC VDD channel | 3.31 |
Supply rail voltage in V |
DIE_TEMP_C |
nRF54 internal temp sensor | 27 |
Die temperature in °C |
LFXO |
Clock status register | OK |
OK or FAIL |
Assigned Identifiers (programmed or auto-assigned)¶
| Key | Source | Example | Description |
|---|---|---|---|
WP_NODE_ADDR |
Config flash | 70001 |
Wirepas node address |
WP_NET_ADDR |
Config flash | 0x1234 |
Wirepas network address |
WP_NET_CHAN |
Config flash | 15 |
Wirepas network channel |
Self-Test Summary¶
| Key | Source | Example | Description |
|---|---|---|---|
SELF_TEST |
Self-test engine | PASS or FAIL |
Overall result |
ERROR_CODES |
Self-test engine | E03,W01 or NONE |
Comma-separated list of active error/warning codes |
ERROR_COUNT |
Self-test engine | 2 |
Total number of errors and warnings |
3. Self-Test Suite¶
Variant-Aware Test List¶
The firmware determines the test list based on BOARD_ARTICLE and EXTENSION. Every test in the list runs. There are no skips -- only tests that apply to the detected variant are executed.
| Test ID | Name | Applies To | What It Checks |
|---|---|---|---|
| T01 | Board variant valid | All | V_SAMPLE ADC falls within a defined board window |
| T02 | FW/board match | All | Firmware build type (anchor/gateway) matches V_SAMPLE range |
| T03 | NFC controller present | All | I2C scan finds ST25DV04K at addresses 0x53 and 0x57 |
| T04 | LFXO crystal running | All | 32.768 kHz oscillator status register confirms running |
| T05 | VDD rail in range | All | Internal VDD measurement is 3.0--3.6V |
| T06 | Die temperature sane | All | Internal temp sensor reads -40°C to +85°C |
| T07 | Battery present | 232201, 232203, 232204 | BAT_VOLTAGE > 1.0V |
| T08 | Battery voltage healthy | 232201, 232203, 232204 | BAT_VOLTAGE in range 2.5--3.6V |
| T09 | Charger responding | 232201, 232203, 232204 | Charger state machine is not in FAULT state |
| T10 | AC power present | 232201, 232203, 232204 | DC_PRESENT (P2.03) reads LOW (5V present) |
| T11 | ESP32 boot | 232202, 232203 | READY pin (P2.08) goes HIGH within 5 seconds after reset |
| T12 | ESP32 UART comms | 232202, 232203 | UART1 ping/response received within 2 seconds |
Tests per variant:
| Variant | Tests Run | Count |
|---|---|---|
| 232200 (anchor, no battery) | T01--T06 | 6 |
| 232201 (anchor + battery) | T01--T10 | 10 |
| 232202 (gateway, no battery) | T01--T06, T11--T12 | 8 |
| 232203 (gateway + battery) | T01--T12 | 12 |
| 232204 (anchor + bat + radar) | T01--T10 | 10 |
UART0 Self-Test Output¶
Follows the traceability record, using the same KEY:VALUE format:
---BEGIN_SELFTEST---
T01:PASS
T02:PASS
T03:PASS
T04:PASS
T05:PASS
T06:PASS
T07:FAIL:E03
T08:FAIL:E04
T09:PASS
T10:PASS
RESULT:FAIL
ERROR_CODES:E03,E04
ERROR_COUNT:2
---END_SELFTEST---
Each test line is Txx:PASS or Txx:FAIL:Eyy (linking the test to its error code). The test station parses RESULT: for the overall verdict and ERROR_CODES: for specific failures.
Battery Detection Logic¶
The battery presence test (T07) combines two independent checks:
| Check | Method | Pass Condition |
|---|---|---|
| Voltage check | P1.06 SAADC (BAT_VOLTAGE) | Reading > 1.0V |
| Charger state | P2.03 (DC_PRESENT), P2.04 (CHARGE_STATUS) | CHARGE_STATUS LOW when DC present |
Both checks must indicate "no battery" to trigger E03. This prevents false positives from a noisy ADC reading alone.
| BAT_VOLTAGE | CHARGE_STATUS (with DC) | Interpretation |
|---|---|---|
| > 2.5V | LOW (charging) or HIGH (idle, bat full) | Battery present, healthy |
| 1.0V -- 2.5V | LOW (charging) | Battery present, deeply discharged (W02) |
| < 1.0V | HIGH (idle) | Battery missing (E03) |
| < 1.0V | LOW | Ambiguous -- log raw values, report E03 |
4. Error Code Registry¶
Errors (assembly/hardware failures)¶
| Code | Name | Trigger Condition | Detection | Blink Count | Color |
|---|---|---|---|---|---|
| E01 | Board variant unknown | V_SAMPLE ADC outside all defined windows | P1.07 ADC | 1 long | RED |
| E02 | Firmware/board mismatch | Gateway FW on anchor board or vice versa | V_SAMPLE vs. build type | 2 long | RED |
| E03 | Battery missing | Battery variant detected, BAT_VOLTAGE < 1.0V | P1.06 ADC + charger GPIO | 3 long | RED |
| E04 | Battery fault | CHARGE_STATUS LOW for longer than safety timer (4h) | P2.04 GPIO + timeout | 4 long | RED |
| E05 | NFC controller absent | ST25DV04K not found at I2C 0x53/0x57 | I2C bus scan | 5 long | RED |
| E06 | ESP32 not responding | Gateway variant, READY not HIGH within 5s | P2.08 GPIO timeout | 6 long | RED |
| E07 | Crystal failure | 32.768 kHz LFXO not oscillating | Clock status register | 1 short + 1 long | RED |
Warnings (non-critical, device operates but should be investigated)¶
| Code | Name | Trigger Condition | Detection | Blink Count | Color |
|---|---|---|---|---|---|
| W01 | Battery low | BAT_VOLTAGE between 2.5V and 3.0V | P1.06 ADC | 1 long | AMBER |
| W02 | Battery deeply discharged | BAT_VOLTAGE between 1.0V and 2.5V | P1.06 ADC | 2 long | AMBER |
| W03 | Unexpected extension | Extension board detected on a variant that doesn't use it | P1.12 ADC | 3 long | AMBER |
| W04 | No AC power at boot | DC_PRESENT HIGH (running on battery from first boot) | P2.03 GPIO | 4 long | AMBER |
Reserved Codes (future expansion)¶
| Code Range | Reserved For |
|---|---|
| E08--E12 | Radar sensor, LTE modem, SIM card detection |
| E13--E99 | Future hardware tests |
| W05--W09 | Radar/LTE signal quality warnings |
| W10--W99 | Future non-critical warnings |
Extensibility
New tests and error codes are added by extending the test list for the relevant BOARD_ARTICLE + EXTENSION combination. The UART format, KEY:VALUE structure, and blink protocol do not change. Add new Txx / Exx / Wxx entries and update this registry.
5. LED Diagnostic Blink Protocol¶
Blink Timing (inherited from EverTag tag firmware)¶
The Station inherits the EverTag blink timing defined in the EverTag User Guide — LED Patterns:
| Blink Type | ON Time | OFF Time | Slot Duration |
|---|---|---|---|
| Short blink | 100 ms | 400 ms | 500 ms |
| Long blink | 250 ms | 250 ms | 500 ms |
A complete blink sequence is 4 seconds: 3 seconds of active blink slots (6 × 500 ms) followed by 1 second of silence (separator).
Diagnostic Mode¶
When the self-test detects one or more errors or warnings, LED1 enters diagnostic blink mode for the duration of the 5-minute active window. Diagnostic mode replaces the generic "RED fast blink" (priority 1 in the UI Behavior spec) with specific counted blink patterns that identify each error code.
Blink Sequence Protocol¶
Each error/warning code is displayed as a counted blink sequence:
- Show blink pattern for the error code (N long blinks in the code's color)
- 1-second dark pause
- Repeat the same pattern (shown twice for readability)
- 2-second dark pause
- Next error code (if multiple errors)
- After all codes are shown: 3-second dark gap, then the full cycle repeats
Color Encoding¶
| Color | RGB Value | Severity | Meaning |
|---|---|---|---|
| RED | (255, 0, 0) | Error | Hardware fault or assembly defect -- production line must act |
| AMBER | (255, 160, 0) | Warning | Non-critical issue -- device operates but should be investigated |
Error Code → Blink Pattern Mapping¶
| Code | Blink Count | Color | 4s Encoding (EverTag format) | Visual |
|---|---|---|---|---|
| E01 | 1 long | RED | 0xFF200000 |
── |
| E02 | 2 long | RED | 0xFF220000 |
── ── |
| E03 | 3 long | RED | 0xFF222000 |
── ── ── |
| E04 | 4 long | RED | 0xFF222200 |
── ── ── ── |
| E05 | 5 long | RED | 0xFF222220 |
── ── ── ── ── |
| E06 | 6 long | RED | 0xFF222222 |
── ── ── ── ── ── |
| E07 | 1 short + 1 long | RED | 0xFF120000 |
· ── |
| W01 | 1 long | AMBER | 0xFF200000 |
── (amber) |
| W02 | 2 long | AMBER | 0xFF220000 |
── ── (amber) |
| W03 | 3 long | AMBER | 0xFF222000 |
── ── ── (amber) |
| W04 | 4 long | AMBER | 0xFF222200 |
── ── ── ── (amber) |
0xFF as the repeat byte means "repeat indefinitely" (until the 5-minute window expires).
Timeline Example: E03 + W01¶
Time: 0s 3s 4s 7s 8s 9s 12s13s 16s17s 19s 20s 23s
| | | | | | | | | | | | |
RED: ──── ── |──── ──| | | | | | | |──── ──
E03 ×1 |E03 ×2 | | | | | | | |E03 ×1
| |2s | | | | | |3s |
| pause | | | | | gap cycle
AMBER:|── ──| |── ──| | repeats
W01×1 1s W01×2
pause
No Errors: Normal Status Progression¶
When all self-tests pass, LED1 displays the normal UI Behavior status sequence during the active window:
- WHITE breathing (booting, ~5--30 seconds)
- YELLOW solid (powered, no Wirepas network)
- BLUE solid (Wirepas joined, no sink)
- GREEN solid (Wirepas operational)
6. Error Reporting Channels¶
Error flags from the self-test are stored in RAM and available through multiple channels beyond UART0:
| Channel | How | Available On |
|---|---|---|
| UART0 | Traceability record + self-test output at boot | All variants (via TC2030) |
| UART0 CLI | status command reports active errors anytime |
All variants |
| LED1 | Diagnostic blink patterns during active window | All variants |
| NFC | Error flags written to ST25DV04K memory area | All variants (phone tap readout) |
| Wirepas mesh | Error flags in periodic status messages | All variants (cloud monitoring) |
| Web UI | Device tab shows error codes and descriptions | Gateway variants (232202+) |
CLI Example¶
> status
Board: 232201 (Station Bat), Extension: None
FW: evertag-anchor-nrf54 v1.0.0 (a3f7c21)
Wirepas: joined, node 70001, ch 15
NFC: ST25DV04K online
Battery: 3.24V, CHARGING, AC PRESENT
Self-test: FAIL
E03: Battery missing (BAT_VOLTAGE=0.01V)
Uptime: 00:04:32
7. Production Test Station Integration¶
The test station workflow uses the traceability record and self-test output for automated pass/fail decisions. The test station provides the timestamp (Option B -- the device does not output wall-clock time).
Workflow¶
1. Program nRF54 firmware via SWD (TC2030 J1)
2. Program ESP32 firmware via UART (TC2030 J2) — gateway variants only
3. Device boots → self-test runs (~3 seconds)
4. Test station reads UART0 via TC2030 cable
5. Scan for ---BEGIN_TRACE--- / ---END_TRACE--- markers
6. Scan for ---BEGIN_SELFTEST--- / ---END_SELFTEST--- markers
7. Parse RESULT: line
8. If RESULT:PASS → log trace data → label and box
9. If RESULT:FAIL → read ERROR_CODES: → log → reject unit
10. Operator sees RED LED = visual confirmation of reject
11. Test station records its own timestamp alongside the captured data
12. Disconnect TC2030, move to next unit
Test Station Data Storage¶
The test station stores the full KEY:VALUE block for each unit. This creates a manufacturing database where any unit can be traced by its NRF54_DEVID and cross-referenced with BOARD_ARTICLE, FW_VERSION, BAT_VOLTAGE, and all other fields. Raw ADC values (V_SAMPLE_RAW, BAT_VOLTAGE_RAW, EXT_DETECT_RAW) enable post-production quality analytics (e.g., detecting batch-level drift).
8. Continuous Monitoring (Field Operation)¶
The self-test runs at every boot, not just initial programming. Field reboots (power cycle, watchdog, OTA update) re-run the full test suite for the detected variant. This catches degradation over time (e.g., battery aging, connector oxidation, crystal drift).
Additionally, the firmware periodically re-checks a subset of measurements during normal operation:
| Check | Interval | Error if |
|---|---|---|
| BAT_VOLTAGE | Every 60 seconds (battery variants) | Drops below 2.5V (W01) or below 1.0V (E03) |
| Charger state | Every 60 seconds (battery variants) | Enters FAULT state (E04) |
| VDD rail | Every 300 seconds | Outside 3.0--3.6V range |
| Die temperature | Every 300 seconds | Outside -40°C to +85°C |
Runtime-detected errors update the error flags in RAM and are reported via CLI, NFC, and Wirepas status messages. LED1 shows diagnostic blinks on the next button press (active window activation).
Revision History¶
| Revision | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-02-24 | CargoBeacon | Initial specification |