bfd-data-acquisition
Use when acquiring STM32 runtime data from global symbols, memory regions, stack-published local slots, or RTT channels and converting captures into structured artifacts for analysis.
Install
mkdir -p .claude/skills/bfd-data-acquisition && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16270" && unzip -o skill.zip -d .claude/skills/bfd-data-acquisition && rm skill.zipInstalls to .claude/skills/bfd-data-acquisition
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when acquiring STM32 runtime data from global symbols, memory regions, stack-published local slots, or RTT channels and converting captures into structured artifacts for analysis.About this skill
BFD Data Acquisition
Self-Improvement Loop (Required)
- When this skill encounters a build, flash, debug, script-usage, or other workflow problem, do not stop at the local workaround after the issue is solved.
- Record the resolved issue and lesson in
BFD-Kit/.learnings/ERRORS.mdand/orBFD-Kit/.learnings/LEARNINGS.md; unresolved capability gaps go toBFD-Kit/.learnings/FEATURE_REQUESTS.md. - Promote reusable fixes into the affected BFD-Kit asset in the same task when feasible: update the relevant
SKILL.md, script, wrapper, or resource so the next run benefits by default. - When a learning is promoted into a skill or script, append a short entry to
BFD-Kit/.learnings/CHANGELOG.mdand mention the improvement in the task close-out.
Purpose
Use this skill when the task is "show the contents of this global/static object" and the object can be resolved from an ELF.
This skill is the default path for:
- global/static object inspection
- pointer-hub decoding
- enum-bearing state objects
- stack-published local-slot capture through pointer symbols
- raw RAM capture only when no stable symbol exists
This skill is not tied to any motor model or business object. The primary workflow is generic ELF + symbol + DWARF.
Required Precheck
Run bootstrap before any acquisition command:
python3 ./.codex/skills/bfd-project-init/scripts/bootstrap.py --project-root . --mode check
Fail fast if ${STM32_ELF} or the active bootstrap profile is missing.
Before the first symbol-auto run, also verify that the exact interpreter behind python3 can import elftools:
python3 -c "import elftools, sys; print(sys.executable)"
If this fails:
- on Ubuntu system Python, install
python3-pyelftools - if an activated conda environment shadows system
python3, either installpyelftoolsinto that environment or invoke/usr/bin/python3explicitly for the acquisition command
Primary Command Contract
Primary script:
python3 BFD-Kit/skills/codex/bfd-data-acquisition/scripts/data_acq.py ...
Primary mode:
python3 BFD-Kit/skills/codex/bfd-data-acquisition/scripts/data_acq.py \
--elf "${STM32_ELF}" \
--mode symbol-auto \
--symbol <global_symbol> \
--follow-depth 1 \
--format summary \
--output logs/data_acq/<symbol>.summary
Meaning of the primary arguments:
--mode symbol-auto: resolve the symbol from ELF, reflect its DWARF type, reuse or rebuild schema cache, sample RAM, and decode named fields.--symbol <global_symbol>: required global or static object symbol.--follow-depth <N>: pointer follow depth.--format summary|json|csv: output renderer.
symbol-auto rules:
- requires
--symbol - supports only
--capture-mode snapshot - rejects manual decode options such as
--decode-profile,--layout,--pointer-array, and--follow-pointer - writes or reuses cache under
.codex/bfd/dwarf_cache/ - when the script is invoked from a central BFD-Kit checkout, it also searches the current working directory upward for
.codex/bfd/active_profile.envand.codex/bfd/dwarf_cache, so run it from the target project directory when you want project-local profile/cache resolution - root object size and typedef-backed array element sizes come from the reflected DWARF schema; if a snapshot is shorter than expected, the script now reports an explicit capture-size mismatch or truncated nested field metadata instead of a raw Python
struct.error
Follow-Depth Rules
--follow-depth 0: decode the root object only; pointers remain address metadata.--follow-depth 1: follow one pointer layer. Use this first for pointer hubs and object tables.--follow-depth >1: recursively follow nested pointers. Increase only when the object layout requires it.
If --follow-depth >1 on a pointer array or pointer-rich object crashes with errors such as struct.error: unpack requires a buffer of 1 bytes, stop deep recursion on that object. Fall back to --follow-depth 1 to recover the first-layer structs plus child pointer addresses, then inspect the nested child objects separately with another acquisition or raw J-Link mem32 reads.
Standard Workflow Order
- Use
--mode symbol-autofirst when the target object has DWARF-supported type information. - Fall back to
--mode symbolonly when:- the target type contains unsupported DWARF features
- a manual decode profile is intentionally narrower than the full object
- a typed scalar layout is sufficient
- Use
--pointer-symbolonly for stack-published local data. - Use raw
--addresscapture only when no stable symbol exists.
Native HSS Escalation
When the requirement is high-rate, non-halting sampling of a fixed-address scalar global/static variable on a J-Link target, prefer the native HSS CLI path instead of GUI J-Scope automation or halt/read/go loops:
bash BFD-Kit/scripts/bfd_jlink_hss.sh --json hss sample \
--symbol chassis_parameter.IMU.yaw \
--symbol chassis_parameter.IMU.pitch \
--duration 0.3 \
--period-us 1000 \
--output logs/data_acq/imu_yaw_pitch_hss.csv
Use this path only for fixed-address scalar globals/statics. Repeat --symbol for multi-symbol sampling. On J-Link PLUS, SEGGER's model limits and local HSS verification both indicate a 10-symbol ceiling; do not treat hss inspect raw capability word 2 as the symbol-count limit. The wrapper uses BFD-Kit/.runtime/venv automatically after bash BFD-Kit/init_project.sh --project-root .. If the target is a pointer-driven object graph or needs DWARF field decoding, stay on symbol-auto. The command writes a wide CSV to --output and a metadata sidecar JSON to --output.meta.json.
Do not assume requested --period-us equals the achieved sample period on every probe model. Local RSCF_h7 validation with J-Link CE showed a practical single-float floor near 1000 us, even when --period-us was reduced from 1000 down to 1 and SWD was raised from 4000 to 8000 kHz. When a new J-Link model, target, or board wiring is introduced, run an explicit sweep first and report the effective period from captured sample counts instead of trusting the requested value or a capability word name.
ST-Link does not provide an HSS-equivalent path in this revision. If STM32_PROBE=stlink, treat high-rate capture as a separate polling/snapshot design problem rather than a drop-in replacement for native J-Link HSS.
If the requirement is textual RTT evidence over ST-Link, switch to the independent bfd-strtt-rtt skill instead of forcing that flow through J-Link RTT guidance.
For FanX/Tek DAPLink High or another CMSIS-DAP probe, use the PyOCD HSS-compatible sampler when native J-Link HSS is unavailable but a fixed-address scalar CSV is still needed:
RSCF_h7/.tools/pyocd-venv/bin/python BFD-Kit/scripts/bfd_pyocd_hss.py --json sample \
--elf RSCF_h7/builds/gcc/debug/RSCF_H7_BOARD_ONE.elf \
--target stm32h723xx \
--uid 6d1395736d13957301 \
--frequency 10000000 \
--symbol g_system_status.status_byte \
--duration 0.5 \
--period-us 1000 \
--output RSCF_h7/logs/data_acq/g_system_status_pyocd_hss.csv
This backend intentionally writes the same wide CSV + .meta.json shape as native HSS, but it is host-polled and uses host monotonic timestamps. Do not label it as SEGGER probe-side HSS. For deterministic high-rate system identification, prefer firmware telemetry mirror/ring or a custom DAPLink vendor-command backend once the probe firmware source is available.
When the question is specifically "how many float values can DAPLink / PyOCD hold at a stable 1000 Hz update?", use the built-in benchmark instead of guessing from one-off captures:
RSCF_h7/.tools/pyocd-venv/bin/python BFD-Kit/scripts/bfd_pyocd_hss.py --json benchmark-float \
--address 0x200096E8 \
--min-floats 1 \
--max-floats 64 \
--target stm32h723xx \
--uid 6d1395736d13957301 \
--frequency 10000000 \
--duration 0.2 \
--period-us 1000 \
--output RSCF_h7/logs/data_acq/pyocd_float_benchmark.json
This report tells you:
- the largest repeated
float_countthat still meets the configured 1 kHz stability rule - the effective bytes per second at each float count
- where the host-polled path starts to fall behind
If the needed float count is above the stable 1 kHz boundary, stop trying to stretch host polling and move the fast path into the bundled MCU telemetry ring:
python3 BFD-Kit/scripts/bfd_telemetry_ring.py --json layout \
--field pos_rad:f32 \
--field vel_rads:f32 \
--field torque_nm:f32 \
--field state:u32 \
--capacity 128
Then capture the ring through PyOCD once the firmware has published the ring image symbol/address:
RSCF_h7/.tools/pyocd-venv/bin/python BFD-Kit/scripts/bfd_telemetry_ring.py --json capture-pyocd \
--address 0x24020000 \
--field pos_rad:f32 \
--field vel_rads:f32 \
--field torque_nm:f32 \
--field state:u32 \
--target stm32h723xx \
--uid 6d1395736d13957301 \
--frequency 10000000 \
--duration 1.0 \
--poll-period-us 1000 \
--output RSCF_h7/logs/data_acq/app_ring_capture.csv
The current bfd_pyocd_hss.py also supports two generic paths that align better with UNI_DataVisualizer style direct-read workflows:
- raw SRAM/MMIO scalar capture via repeated
--address-spec name@0xADDR:type - importing enabled variables from a Windows
HSSDVProjfile via--project-file
The script now coalesces contiguous addresses into one region read and automatically selects block32 when the merged region is 4-byte aligned and 4-byte sized. On RSCF_h7 with FanX/Tek DAPLink High at 10 MHz SWD, local validation reached about 51.25 kB/s for a packed 41B struct field group and about 128 kB/s for a merged 64B block32 raw-memory capture. This clears the practical 50 kB/s threshold for MCU runtime data collection, but it is still not probe-side HSS and should not be positioned as a 1 MB/s equivalent.
Content truncated.