| Age | Commit message (Collapse) | Author |
|
table integration
- Vector catch + Cortex-M fault autopsy, verified with a deliberate bad-load
on stm32f407disco: CFSR=0x8200 (BFARVALID|PRECISERR), BFAR = exact bad
address, stacked pc addr2lined to the faulting line; gotchas recorded
(stale FPB comparators fire phantom SIGTRAPs — scrub first; arm DEMCR
after reset; loads precise / stores imprecise; ARMv6-M has no CFSR/BFAR)
- SWO exception trace + hw PC sampling gate PASSED on F407: 680 KB of
packets in 3 s (0x17 PC samples in flash range, 0x0E SysTick enter/exit);
JLinkSWOViewerCL decodes stimulus only — raw SWORead is the recipe;
SWOStart needs an explicit speed headless
- verifybin 'Verify successful.'; FreeRTOS -rtos plugin lists all 6
cdc_msc_freertos tasks after a run->stop cycle (plain attach = 0xDEAD
placeholder); semihosting anti-note; monitor-mode pointer (untested)
- Intrusiveness table gains the new rows; agent playbook bullet updated;
retrieval gate 5/5 with a fresh reader; executed plan committed
|
|
- Link J-Link UM08001, OpenOCD and GDB (Tenth Ed.) manuals
- bp/wp depth with halt-per-hit cost model. Verified on stm32f407disco
(J-Link) + raspberry_pi_pico (OpenOCD): FPB/DWT budget reads (M4 6 bp/4 wp,
M0+ 4/2 exact), 'Hardware watchpoint' confirmation rule (software fallback
single-steps = USB death), OpenOCD data-VALUE watchpoints, dprintf +
breakpoint command lists exercised on hardware; JLinkGDBServer -singlerun
lifecycle gotcha
- RTT is not J-Link-only: OpenOCD rtt setup/start/server verified on pico
(control block found at the nm address, LOG=2 boot banner captured over nc)
|
|
LOGGER=rtt builds of any rp2040 example fail with -Werror=missing-prototypes
(stdio_rtt_init has no prototype and is only called from family.c).
Found by building cdc_msc -DLOG=2 -DLOGGER=rtt for raspberry_pi_pico.
|
|
Rename usb-target-debug -> target-debug, usb-debug -> usb-kernel-debug,
usb-recover -> usb-kernel-recover (script filenames unchanged), and make all
debug skills/agents decide tool applicability by which end of the link runs
Linux: TinyUSB may run the device or host stack, and its peer may be a Linux
PC, another TinyUSB board, or a Linux gadget (e.g. Raspberry Pi UDC).
- usbmon: exists only when a Linux PC is the link's host
- usb-kernel-debug: either Linux end; allowlist gains dwc3/libcomposite/udc_core
for the gadget side of a Linux peer
- usb-sniffer: the only full-visibility capture when TinyUSB is the host
- target-debug: covers dcd_* and hcd_*/tuh_ debugging; channel choice by topology
- update target-debugger/hil-operator agents, pre-pr, hil-validate.js, and the
USB_RECOVER path constant in test/hil/usbtest.py
- CLAUDE.md: fold the dcd/hcd datasheet cross-check rule into the read-doc line
|
|
|
|
|
|
|
|
Add support for APM32F072
|
|
|
|
* docs: add read-doc skill for on-demand datasheet lookup
Search and read MCU datasheets, reference manuals, errata, and the USB
spec from a local Calibre library ($HOME/Documents/calibre-library)
instead of answering register/bitfield/pinout questions from model
memory. Gated on the library's existence, so it no-ops for contributors
who don't have it.
* docs: reference read-doc skill and tighten CLAUDE.md
Point the datasheet/reference entry at the new read-doc skill, and trim
sections that only duplicate a skill already owning the detail:
PVS-Studio and Code Size collapse to pointers; GDB/Build/Flash command
blocks condensed to essentials. 213 -> 129 lines; behavioral guidelines
and the validation checklist unchanged.
* docs: tighten skill redundancy; rename AGENTS.md refs to CLAUDE.md
code-size: fold the step list into a sentence and drop invocation
examples the argument tables already cover. hil: merge the duplicated
self-lock bullets and compress the hifiphile note. usbmon: compress the
group-membership setup paragraph. All commands, flags, lock rules, and
report paths preserved. usb-target-debug and the pvs script only get
stale AGENTS.md references renamed to CLAUDE.md (now the real file);
run_pvs.sh no longer cites a --dump-files mention that CLAUDE.md dropped.
* docs: fix review findings — restore Espressif cd step, ELF placeholder, code-size comment
Codex/Copilot/Claude review of #3778: the condensed Espressif bullet
lost its cd (idf.py resolves the project from CWD, so the command failed
from repo root); the GDB example now uses the build/your_app.elf
placeholder that docs/troubleshooting.rst established; the code-size
invocation comment no longer references --combined, which the shown
command doesn't use.
|
|
|
|
|
|
* docs: make CLAUDE.md the real agent-instructions file
|
|
Larger at32f403a PMA area
|
|
Puya PY32F07x support
|
|
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
|
|
bound cdc-data endpoints against descriptor length in acm_open
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
usb-target-debug/usb-sniffer skills
|
|
Migrate NXP Kinetis khci to chipidea ci_fs (device + host) + fixes
|
|
- Drop the dated/host-specific tap topology; confirm the cabling each
session instead (the tap gets re-cabled often), and read the DUT link
speed from sysfs to pick --speed.
- Genericize the hub-upstream reset-visibility note.
- Rewrite "one-time setup" as a copy-paste shell block (udev + binary +
Wireshark extcap symlink), keeping only the firmware-command caution.
|
|
Host (hcd_ci_fs.c):
- Release the speculatively-armed sibling BDT on the NAK path (IN only) as
well as on completion, so a NAKed multi-packet IN no longer leaks a BDT
that stays own=1 and blocks every same-direction pipe. Both paths now go
through a single release_sibling_bd() helper (was a copy-pasted disarm).
- Clear the ENTIRE shared BDT (both directions) on bus reset; clearing only
the IN half left a stale OUT/SETUP descriptor after a disconnect mid-OUT,
blocking the first control transfer on re-enumeration.
- Size bda[] to span the whole BDT (2*2*4) so STAT-indexed access is within
the declared array bounds (was out-of-declared-bounds, benign via union).
Shared (ci_fs_type.h):
- Hoist buffer_descriptor_t and the TOK_PID enum out of the device and host
drivers into the shared header so the identical definitions cannot drift.
Board (kinetis_k):
- Drop a redundant local in board_get_unique_id.
Build-verified: host + kinetis k/kl/k32l + MCX. HIL: frdm_k64f host 2/2
(cdc_msc_hid + device_info); frdm_kl25z device core suite green with the
relocated definitions.
|
|
- getting_started.rst: the reST inline-link markup rendered literally
inside the code-block (not a runnable command) and lacked sudo — use a
plain `sudo cp examples/device/99-tinyusb-examples.rules ...`.
- tools/88-tinyusb.rules: normalize the six MODE="666" entries to the
4-digit octal MODE="0666" used everywhere else in the file.
|
|
From a second max-effort review of the branch:
- Drop the dead TUSB_XFER_ISOCHRONOUS case in dcd_edpt_open: iso endpoints
are armed via dcd_edpt_iso_alloc/activate (TUP_DCD_EDPT_ISO_ALLOC is
defined for this IP), never through dcd_edpt_open, so the case and its
dd->isochronous assignment were unreachable and asserted a false
invariant. Only bulk/interrupt reach the switch now.
- Extend the iso compile gate to the classes that actually arm an iso
endpoint: DCD_ISO_ENABLED now includes CFG_TUD_BTH (bth_device.c opens
an iso voice endpoint). Without it a BTH build would compile the iso
machinery out and fail SET_INTERFACE at runtime.
- Un-skip LPC175X_6X in the usbtest example: it shares dcd_lpc17_40.c with
LPC40XX verbatim, so the "DCD has no isochronous support" skip reason no
longer holds. Build-verified for lpcxpresso1769 (previously blocked by
the skip).
- TU_ATTR_UNUSED on the ep_id_is_iso helper: every caller is under
#if DCD_ISO_ENABLED, so non-iso builds don't reference it and clang's
-Wunused-function (fatal in CI) rejected the build — gcc stays quiet.
Verified with the full lpc17 and lpc40 example sets under arm-clang.
A fifth finding — bounding control_ep_read's PACKET_READY spin with a
timeout — was implemented and REVERTED: a naive 100k-iteration bound fires
on legitimately-slow control reads and intermittently drops the device
(hardware-proven by interleaved A/B testing against the pre-fix binary).
The infinite wait is retained; the read is only reached once out_received/
out_queued signal data is present, so the theoretical IRQ-off hang is not
reachable in practice.
Re-verified on ea4088_quickstart: usbtest 30/30 (repeated) + HIL 14/14.
|
|
Fourth view in the USB debugging toolset (usbmon = host URBs, usb-debug =
host reasoning, usb-target-debug = device firmware, usb-sniffer = what
actually crossed D+/D-). Covers the ataradov/usb-sniffer analyzer:
headless pcapng capture (--speed ls/fs/hs, --fold, --limit self-exit),
Wireshark/tshark analysis recipes, and the wire realities that bite:
downstream broadcast, sniffer self-capture noise, xHCI devnum != wire
address, tap-point-dependent reset visibility (hub choreography anchors),
FS-behind-HS-hub splits. Every recipe hardware-validated on the rig,
including the capture-window floor (a 3 s window provably misses the
enumeration ladder; 3M packets minimum).
Two udev files with distinct audiences, not one:
- examples/device/99-tinyusb-examples.rules (renamed from 99-tinyusb.rules):
the user-facing rules the examples need — cafe VID access, hidraw, the
ModemManager blacklist, a couple of board probes. getting_started.rst,
the webusb_serial README and its source comment point here.
- tools/88-tinyusb.rules: the HIL rig's private probe/analyzer allowlist,
now with the sniffer (6666:6620 + blank FX2LP 04b4:8613). Installed on
the rig only; the usb-sniffer skill references it.
|
|
hcd_ci_fs shares a single BDT set across all pipes. prepare_packets()
speculatively arms the sibling (odd^1) BDT of a multi-packet transfer so it
can ping-pong without NAKs. When such a transfer ends early (a short IN
packet) or fails, the still-owned sibling was never released, permanently
blocking the shared BDT for every other pipe.
This deadlocked a 2nd device enumerating behind a hub while another device
issued descriptor reads (host/device_info with CDC+MSC): the MSC's control
transfers could never acquire the BDT, so it never got Set Address.
Release the sibling in process_tokdne()'s completion path, but ONLY for a
multi-packet transfer (length > max_packet_size): a single-packet transfer
never arms a sibling, so that BDT slot may legitimately belong to another
pipe's in-flight transfer and must not be disturbed (doing so unconditionally
corrupts concurrent transfers, e.g. the CDC bulk-IN vs MSC enum in
host/cdc_msc_hid).
Mirrors the equivalent device-side fix in dcd_ci_fs.c; the host needs the
multi-packet guard because its BDT set is shared across pipes.
Verified on frdm_k64f (HIL): host/device_info now enumerates both CDC+MSC
behind a hub, host/cdc_msc_hid still mounts the MSC (no regression).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
|
|
frdm_k64f as a USB host with a CH9102 CDC (TX-RX loopback) and a Lexar MSC
drive behind a hub; flasher = onboard OpenSDA J-Link. host/cdc_msc_hid passes
(CDC mount+echo, MSC mount + disk-size check). device_info remains a known
device_info/usbh limitation (its synchronous descriptor dump starves a 2nd
device's enumeration) and is not ci_fs-specific.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
|
|
- board_uart_read was a stub returning 0, so host examples that bridge the
UART console to a CDC device (echo test) received nothing. Implement it via
an RDRF-interrupt-fed tu_fifo, matching the stm32 family (non-blocking, no
RX overrun). board_uart_write is already non-blocking.
- implement board_get_unique_id() from the SIM 128-bit UID registers so
frdm_k64f/teensy_35 report a real USB serial instead of the fixed default.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
|
|
A multi-packet OUT transfer speculatively arms both even/odd BDTs to avoid
NAK. When the host ends the transfer early with a short packet, the sibling
BDT was left armed (own=1), desyncing the even/odd ping-pong so the next OUT
packet landed at buffer+max_packet_size instead of buffer and the stack read
stale data. Disarm the sibling on completion.
Fixes device/mtp on Kinetis (GetDeviceInfo command was received into the wrong
buffer half -> hang). Pre-existing (MSC only arms single-packet command
receives so it never hit the double-buffer path). HIL: frdm_kl25z & frdm_k64f
device 13/13.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
|
|
Complete the khci -> chipidea ci_fs migration that was started for device
(commit d70403f1f "host is not yet"):
- device: switch kinetis_k/kl/k32l (Makefiles + k32l CMake) to dcd_ci_fs.c
- host: add hcd_ci_fs.c (port of hcd_khci.c onto ci_fs_regs_t) and switch all
Kinetis families to it; remove src/portable/nxp/khci entirely
- enable host examples (device_info, cdc_msc_hid) for mcu:KINETIS_K
- README: merge the KL and K32L2 rows into a single "KL, K32L" ci_fs row
hcd_ci_fs.c also fixes two pre-existing host bugs found via HIL on frdm_k64f
(present in the old hcd_khci.c too):
- data toggle was flipped on a NAK in suspend_transfer; a NAK transfers no
data so the toggle must be preserved, else the retried bulk packet is
silently discarded by the device (MSC CBW/CSW hang). See comment in file.
- prepare_packets asserted and dropped a transfer when the single shared BDT
was still owned by an in-flight transfer under concurrent activity; now it
returns busy and resume_transfer defers/retries on the next SOF.
HIL verified on frdm_k64f: device 13/13, host cdc_msc_hid (CDC mount + echo +
MSC mount, through a hub).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
|
|
Opus-tier agent charter for backgrounding a long hardware debug session:
instrument -> build -> flash under one held board lock -> dual-side
capture -> correlate -> refine, strictly one instance, skills as source
of truth (usb-target-debug, usbmon, usb-debug, usb-sniffer, usb-recover,
hil). The charter encodes what dogfooding established:
- diagnosis standard: evidence must show the mechanism, or a fix must
flip the ORIGINAL failing case on hardware; stop after two
evidence-free cycles and hand back a partial diagnosis
- lock cadence: hold for the whole session, release around hil_test.py
runs (it self-locks per board)
- revert semantics: "fix stays, probe goes, re-verify clean" —
instrumentation reverted, candidate fix left uncommitted and
re-verified on a clean build, pristine firmware reflashed before
lock release
Returns a machine-parseable diagnosis report including ruledOut[] —
disproven hypotheses are deliverables. Spec roster updated (opus/xhigh,
effort requested per agent() call).
|
|
Real 128-bit chip UID as the board serial (IAP cmd 58, status checked
against IAP_CMD_SUCCESS), replacing the shared placeholder — required for
HIL board identification by serial. lpc40's lpcopen Chip_IAP_ReadUID()
returns only the first UID word, hence the direct iap_entry() call.
Verified on ea4088_quickstart and lpcxpresso1549: both enumerate with
their chip UID and are selected by it in the HIL configs.
|
|
The SIE command protocol (CmdCode + CCEMPTY/CDFULL handshake), the
slave-mode Ctrl/RxData/TxData window, the EpIntEn read-modify-writes, and
set_ep_size's ReEp/EP_RLZED handshake are all shared between thread-mode
API calls and dcd_int_handler, and none are reentrant: an ISR preempting a
thread-mode sequence consumes its handshake flags or, in set_ep_size's
case, a bus reset's DevIntClr = 0xFFFFFFFF eats the EP_RLZED flag the
spin waits on, hanging it forever. Guard them by masking only the USB IRQ
(nestable, ISR-safe; CMSIS NVIC_DisableIRQ already ends with DSB+ISB).
control_xact keeps the mask across its in_isr=true event push, since
osal_none skips queue locking for in_isr.
Hardening, not a fix for an observed failure: the ea4088 usbtest 30/30 +
HIL 14/14 results were reproduced with and without it. The windows are a
few instructions wide and most exposed on RTOS builds where class drivers
queue transfers from tasks concurrent with the USB IRQ.
|
|
EP0 control-OUT fix (usbtest 14/21, errno 110/-74): usbd queues the
status-stage OUT ZLP of every control read with buffer=NULL, so the ISR's
`if (out_buffer)` check missed it and marked the arriving ZLP as
out_received instead. The stale flag poisoned the next control-OUT with
data: its first chunk "completed" instantly from an empty EP0 buffer and
the host's real DATA NAKed forever. Track queued transfers with an
explicit out_queued flag and void half-finished control state on a new
SETUP.
Isochronous support (UM10562 12.15.6): 5-word DMA descriptors with
per-packet size memory, buflen/present_count in packets, one packet per
FRAME (no DMARSet/EpIntEn involvement), completion at EOT for both
directions. Details that matter:
- the iso machinery (5th DD word + packet-size memory) is compiled only
when an iso-capable class is enabled (CFG_TUD_AUDIO/VIDEO/VENDOR), so
non-iso builds pay nothing: _dcd stays 648 B vs 1032 B with iso
- ISR dispatch keys on the hardware's fixed ep-number/type map
(ep_id_is_iso), never on dd fields that thread mode rebuilds
- iso OUT honors Packet_valid (bit 16) and prefills the hardware
writeback slots with 0, so a missed frame counts as 0 bytes instead of
reading back stale buffer contents as data
- packet count is validated (tu_div_ceil <= ISO_MAX_PACKETS) before the
DD is touched, so an oversized transfer is refused without leaving a
serviceable half-built descriptor armed for the frame engine
- dcd_edpt_iso_alloc and iso_activate both enforce the fixed iso endpoint
numbers (3/6/9/12); classes ignore alloc's return value, so activate
must not trust it
Un-skip LPC40XX in the usbtest example; tier 4 now enumerates and passes
iso cases 15/16/22/23. cdc_msc_throughput and printer_to_cdc had bulk on
iso-only EP3 (SET_CONFIGURATION failed with -32); add the LPC17/40 EPNUM
block (bulk on EP2/EP5) like other fixed-EP examples.
Verified on ea4088_quickstart: usbtest tier-4 battery 30/30 repeatedly
and the full device HIL suite 14/14 (incl. audio_test iso).
|
|
Completes the debugging toolset (usbmon = what the host exchanged,
usb-debug = why the host acted, usb-sniffer = what crossed the wire):
TU_LOG/RTT capture, per-probe GDB autopsy without reset, RAM ring-buffer
event trace, J-Link DWT_PCSR PC-sampling, dual-side capture posture, and
board-lock rig discipline. Includes the implementation plan it executes.
Hard-won warnings baked in from real bring-up sessions: volatile ring
buffers vs -Os dead-store elimination, RTT NO_BLOCK_SKIP post-mortem
limits (no overwrite mode exists), DHCSR validity anchors for register
snapshots, release-lock-before-hil_test, and that a marginal just-recabled
link can fake a deterministic firmware bug.
Also ignore .claude/worktrees/.
|
|
usbtest: device-side peer for the Linux kernel usbtest battery + DCD fixes across 13 ports
|
|
A re-run attempt merged into an empty base: another PR's HIL job ran
between attempt 1 and the retry and rewrote the shared hil_report.json,
so the run-stamp guard (correctly) refused the foreign base but the
full-fleet results were lost - the retry report contained only the
re-run cells.
Give each (run id, job) its own report dir instead:
- attempts of the same run share a dir, so the retry always finds its
own sidecar and .failed spec intact
- interleaved runs of other PRs/jobs write elsewhere and cannot clobber
- the run-stamp mechanism (.failed.run file) becomes redundant and is
removed
- stale per-run dirs are pruned after 2 weeks
|
|
ceedling 1.1.0 (released 2026-07-17) fails this project's mock
preprocessing ('Failed to read _build/test/preprocess/.../raw/*.h for
comment stripping'); reproduced locally with an isolated 1.1.0 install
while 1.0.1 passes all 61 tests on the same tree. Unpin once fixed
upstream.
|
|
vendord_set_alt() aborted bulk/interrupt endpoints of the outgoing
altsetting (stall/clear-stall) but only dropped the iso endpoints'
tracking: an armed iso transfer stayed live in the dcd with its usbd
claim held and no tracked handle to stop it, and its completion fired
into an endpoint the class no longer recognizes. Reachable through the
usbtest example's alt0 (bulk) <-> alt1 (iso) SET_INTERFACE switching.
Track each selected iso endpoint's descriptor (points into the app's
static descriptor set) and deactivate on de-selection: with the
iso-alloc API re-activation is the abort/scrub primitive (resets
ep_status, aborts the stale transfer); without it usbd_edpt_close does,
and the next selection re-opens. Iso cannot be stalled like
bulk/interrupt, hence the separate path.
Build-verified: usbtest for stm32f072disco, ra4m1_ek, raspberry_pi_pico
(iso-alloc) and ch32v307v_r1_1v0 (close API).
|