<feed xmlns='http://www.w3.org/2005/Atom'>
<title>tinyusb.git/docs, branch etmtrace-rp2350</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.</subtitle>
<id>http://cgit.235523.xyz/tinyusb.git/atom/docs?h=etmtrace-rp2350</id>
<link rel='self' href='http://cgit.235523.xyz/tinyusb.git/atom/docs?h=etmtrace-rp2350'/>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/'/>
<updated>2026-08-26T10:06:07Z</updated>
<entry>
<title>pico2_etm_trace: point board metadata at the carrier's PCB repo</title>
<updated>2026-08-26T10:06:07Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-26T10:06:07Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=b396e322633984b08d2d92eb0551ae445817ea8f'/>
<id>urn:sha1:b396e322633984b08d2d92eb0551ae445817ea8f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>docs: name the msc-host retry handoff after its PR</title>
<updated>2026-08-26T09:59:35Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-26T09:59:35Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=61740be39db510928b1d724e3f22b4d2b115eaba'/>
<id>urn:sha1:61740be39db510928b1d724e3f22b4d2b115eaba</id>
<content type='text'>
</content>
</entry>
<entry>
<title>rp2040: remove family_configure_sys_clock(), keep the pico-sdk clock</title>
<updated>2026-08-26T09:58:24Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-26T04:21:33Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=e316a13d3fe0668812f5cc2d20a20c899e9f53cf'/>
<id>urn:sha1:e316a13d3fe0668812f5cc2d20a20c899e9f53cf</id>
<content type='text'>
With the 12 x n MHz rule gone (previous commit), nothing needs a
non-stock clock: every board runs whatever pico-sdk's platform_defs.h
selects (125 MHz rp2040, 150 MHz rp2350), set from crt0 by the SDK's own
runtime_init_clocks(). The per-platform PLL table this file carried only
existed to force other rates, so it goes too.

Overriding is still possible the way the SDK documents it - pass
SYS_CLK_KHZ together with PLL_SYS_VCO_FREQ_HZ / PLL_SYS_POSTDIV1 /
PLL_SYS_POSTDIV2 from scripts/vcocalc.py - which is what the etm-trace
notes now tell you to do for the higher trace rates.

The removed function and its measured PLL values stay in git history if a
board ever needs a pinned clock again.
</content>
</entry>
<entry>
<title>rp2350: ETM trace on the pico2 trace carrier, at the pico-sdk stock clock</title>
<updated>2026-08-26T09:58:24Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-26T04:57:34Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=35c27a4637480161e5f89d314147942159bc108e'/>
<id>urn:sha1:35c27a4637480161e5f89d314147942159bc108e</id>
<content type='text'>
Adds board pico2_etm_trace - a Pico 2 seated on the pico2 trace
motherboard carrier (MIPI-20 Cortex Debug+ETM, 27 Ohm source-terminated,
GND-guarded) - and the trace reference that goes with it.

Firmware needs almost no trace support: J-Link's built-in RP2350 device
script declares the off-ROM-table trace components (funnel/TPIU/ETM) and
re-arms the whole chip-side path via OnTraceStart at every resume, so
TRACE_ETM=1 does one thing only - keep the UART console TX-only when the
console RX would sit on a trace pin. The carrier moves the console to
GP12/13 (GP1 = TRACECLK), so it keeps a full-duplex console while
tracing. Never set a custom JLinkScript here: it replaces the built-in
one and pin trace stops working.

Validated on the carrier at the rp2350 stock 150 MHz (75 MHz TRACECLK,
width 4): cdc_msc enumeration burst 3/3, zero overflow, data sampling
+1 ns (idle eye -1000..+2000 ps), 33M fetches per 10 s capture. Higher
rates measured too: 180 MHz (90 MHz TRACECLK, +4..+5 ns) and 240 MHz
(120 MHz TRACECLK, +3.5 ns) - the latter is the J-Trace PRO V2 ceiling,
which is the probe at its documented limit rather than a board limit.

board_init() no longer switches clk_sys on either chip, and boards run
the pico-sdk default (125 MHz rp2040, 150 MHz rp2350). The 12 x n MHz
PIO-USB rule that motivated the old forced clock is not real - it is the
Pico-PIO-USB author's day-one design note (4d952cb, Dec 2021), never
enforced by an assert, and contradicted by measurement: MSC dd over
PIO-USB at ten clocks from 120 to 240 MHz on rp2350 gives 62 KB/s at
every one; rp2040 CDC bulk loopback is byte-exact at 120/125/133/156/180
MHz; adafruit_fruit_jam passes 19/19 HIL at its stock 150 MHz including
usbtest 30/30 and PIO-USB host+dual. CircuitPython ships PIO-USB at
these same defaults.

Two earlier fly-wire-era workarounds are dropped after A/B on the PCB:
the TIMER0/1 DBGPAUSE clear (captures profile healthy firmware without
it) and 12 mA fast-slew trace pads (default pads pass with a wider eye).
A runtime clk_sys switch does still silently truncate a capture at the
switch, which is why nothing sets the clock at runtime.

Also included: docs/superpowers/followup/pr0000-msc-host-tur-retry.md -
an unbounded Test Unit Ready / Request Sense retry in the MSC host
driver, found while sweeping clocks and deferred to its own PR.
</content>
</entry>
<entry>
<title>hil: make hil_report.md a rendering of hil_report.json (#3840)</title>
<updated>2026-08-25T08:04:42Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-25T08:04:42Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=375e20090a0a60fd2d47ba6553d189e05482dfea'/>
<id>urn:sha1:375e20090a0a60fd2d47ba6553d189e05482dfea</id>
<content type='text'>
hil_report.json and hil_report.md were written independently. Four writers
produced the markdown and three wrote no JSON at all -- and those three are the
paths where a run died, so a JSON consumer saw nothing exactly when it mattered:
the per-board verdicts an agent hands back reported the whole fleet as "no
report row" while a human read the real story from the markdown.

Every writer now goes through render_report(), so a table can never contain
something the JSON does not. The document gains `scope` (a three-board PR run
and a full run that lost 24 boards were indistinguishable) and `caveat` (how the
run ended). `banner` carries rig health across an --accumulate retry; `caveat`
records how a run ended and must not -- conflating them made a clean retry
publish an abandonment that never happened.

helper/hil_report.py owns the document end to end, dissolving the import cycle
that forced write_timeout_report to compose its own markdown and removing a
duplicate cell classifier kept in sync by hand. hil_summary.py is deleted; its
CLI moves there. hil_ci.sh uploads the sidecar so a remote --accumulate has a
merge bas</content>
</entry>
<entry>
<title>ci_select: fix the membrowse test's env dependence, and stop HIL unit tests taking the rig (#3846)</title>
<updated>2026-08-25T03:35:45Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-25T03:35:45Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=b610ff039bafa1040c19d6a11cb04adcb22936e5'/>
<id>urn:sha1:b610ff039bafa1040c19d6a11cb04adcb22936e5</id>
<content type='text'>
test_the_upload_board_can_diverge_from_the_built_board called
get_family_boards without ci=True, so it pinned the developer's set, not the
runner's: the CI skip lists move the one-first pick on three families. It
held locally and went red on its first CI run. Pass ci=True, as
_prune_buildable already does, and pin the runner's twelve.

Rule 2 is a bare test/hil/ prefix, so the harness's own unit tests booked the
full 27-board rig for diffs that cannot reach it. Carve test/hil/test/** out
to rule 1b, beside test/{fuzz,unit-test}/**; the harness itself is untouched.
A test pins that directory's file list, so anything added there that the rig
does read fails rather than silently skipping hardware. Rule table updated in
the spec and its carbon in the docstring.</content>
</entry>
<entry>
<title>ci: an empty selection must build nothing, plus selector follow-ups (#3845)</title>
<updated>2026-08-25T02:46:42Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-25T02:46:42Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=da255b1d2db10b8f31332a779b2a526f579acee1'/>
<id>urn:sha1:da255b1d2db10b8f31332a779b2a526f579acee1</id>
<content type='text'>
ci: an empty selection must build nothing, plus selector follow-ups

A PR whose build axis legitimately selected nothing rebuilt everything.
build.yml reads .build.families twice - as a |-joined regex, and implicitly
as "is anything selected" - but tested only -z "$FAMILY_REGEX", which an
empty list and a charset-rejected one both satisfy while meaning opposite
things. ci_set_matrix had already returned the correct all-empty matrix;
the fall-open branch discarded it. #3842 and #3840 each spent 74 cmake legs
on it. Branch on the two cases instead, rename FAM_* to FAMILY_*, and cover
the block with a test that extracts it from build.yml and executes it - it
had no test at all, which is how this shipped through two merges.

Follow-ups to the same machinery: glob.escape the repo root at five sites,
so a checkout path containing [ or * stops failing closed; drop the ci-full
label, read after the matrix was already computed and so never functional;
delete 13 mcu:MKL25ZXX / mcu:SAME5X skip tokens matching no board; carry the
rule table in the module docstring, guarded against drift; and pin six
selection behaviours a mutation pass proved untested.

Cut the selector's cost 1.8x (26.0s -&gt; 14.6s) with 0 divergences over 260
paths, and stop scoping the membrowse upload by the PR example filter.</content>
</entry>
<entry>
<title>ci_select: classify the 254 files that were reaching rule 17</title>
<updated>2026-08-21T15:17:51Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-21T15:17:51Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=03a329eeda09e073d7de9be84df55d65392e4013'/>
<id>urn:sha1:03a329eeda09e073d7de9be84df55d65392e4013</id>
<content type='text'>
Rule 17 (unclassified -&gt; full on both axes) is the fail-open net for paths nobody
anticipated, and it must stay that way: a wrong `full` costs runner minutes and is
visible in the run, a wrong `empty` costs a merged regression and is invisible.
But nothing in the tree should REACH it, and 254 tracked files did.

The cost was real. PR #3842 changed a skill, a README and .gitignore; .gitignore
matched no rule, so both axes went full and 74 cmake legs span up runners to do
checkout + toolchain + get_deps before skipping the build, plus the whole 30-board
rig. Three changes, none of which touch rule 17 itself:

1. _META_RE - repo metadata and tooling no Build step reads: .gitignore,
   .gitattributes, .clang-format, .codespellrc, .pre-commit-config.yaml,
   .readthedocs.yaml, .PVS-Studio/, .idea/, sonar-project.properties, the
   packaging manifests, CMakePresets, udev rules, test/{fuzz,unit-test} (their own
   jobs build those), the non-build .github/ files, and the tools/*.py scripts no
   build invokes. Deliberately NOT included, and still full: .circleci/**,
   .github/workflows/build*.yml, .github/actions/**, .github/scripts/**. The line
   is "does a Build step read this", not "is it source".

2. Rules 15 and 16 now match what they already claimed. Row 15 names
   examples/&lt;role&gt;/CMakeLists.txt and the regex never had it; row 16 says
   tools/build*.py but anchored tools/build\.py$. Both got the right answer only
   because rule 17 caught them on the way past. Also names their siblings -
   family_support.mk, family_rules.mk, src/CMakeLists.txt, src/tinyusb.mk - and
   .circleci/**, which generates the whole CircleCI matrix and was in no row at all.

3. src/typec/** gets row 12b. It is listed unconditionally by both build systems
   but its body is `#if CFG_TUC_ENABLED`, which only examples/typec/power_delivery
   sets - the same shape as the class rule, so the same answer: the examples that
   enable it (stm32g4 and stm32u5 after the buildability prune), and nothing on the
   rig, which runs no typec test. It was force-fulling 82 families and all 30 boards.

TestNoTrackedFileIsUnclassified walks every tracked file and asserts none reaches
rule 17, on both axes - 254 -&gt; 0. Verified it fails when a new unclassified path
appears. That turns 17 into what it should be: unreachable for anything in the
tree, so it fires only for genuinely new shapes, and the author is told to write
the row rather than letting the fall-through pick an answer for them.

test_full_paths used sonar-project.properties as its stand-in for "unclassified";
that is now metadata, so the case moved to the new
test_repo_metadata_is_not_a_build_input, with test_the_build_machinery_is_still_full
pinning the other side of the line.
</content>
</entry>
<entry>
<title>ci: fix nine ways the selection under-selected or mismatched</title>
<updated>2026-08-21T05:41:47Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-21T05:41:47Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=e13eff8d4e757ebe7709a58fce44017b8be5a84d'/>
<id>urn:sha1:e13eff8d4e757ebe7709a58fce44017b8be5a84d</id>
<content type='text'>
Every one of these dropped coverage silently - the worst failure mode here,
because the PR still goes green. Found by review, each reproduced first.

Selection rules:

* class_macros derived the config macro from the class DIRECTORY, so a change to
  src/class/midi/midi2_device.c selected the midi_test examples (which do not
  compile it) and never examples/device/midi2_device (the only one that enables
  CFG_TUD_MIDI2, and the only one that does). The file's own macro is unioned in
  where it differs - union, never replace: over-selecting costs a build,
  under-selecting merges a break.
* the ${FAMILY_MCUS} fallback added for espressif fired on any family whose
  _family_mcus came back empty, and _cmake_sets is if()-blind and keeps the FIRST
  definition - so mcx/frdm_mcxn947 answered MCXA15, a token six examples' skip.txt
  names, dropping 12 firmware images CMake builds. Limited now to families that
  never spell set(FAMILY_MCUS ...) at all.
* lib_examples read only an example's top-level CMakeLists.txt/Makefile;
  host/msc_file_explorer_freertos names lib/embedded-cli in src/CMakeLists.txt and
  survived by luck. The whole example tree is scanned. (SEGGER_RTT and rt-thread
  still resolve to nothing: all three references sit inside a LOGGER=rtt guard no
  CI build sets - the documented ruling, not a miss.)
* get_family_boards applied ci_skip_boards/ci_preferred_boards only under
  GITHUB_ACTIONS/CIRCLECI, so the selector answered differently on a laptop than
  on a runner; _prune_buildable forces CI semantics. Its one-board pick also
  abandoned the whole preferred list when entry one could not build the -e set,
  and asked skip_example without the build's -D tokens.
* _config_enables and lib_examples still read with the locale encoding - under
  LC_ALL=C the selector tracebacked on three tracked tusb_config.h files. The
  whole selector and its suite run clean there now.

Workflows:

* the Membrowse Upload step omitted $EX_ARGS, but --one-first now picks the board
  from the -e set, so it configured a different, empty build dir and uploaded
  --identical for a board never compiled. It takes $EX_ARGS for the BOARD; the
  target stays the aggregate, which has no DEPENDS and still records every example.
* blanking FAM_REGEX reset only build_filtered, leaving the build scoped while
  code-metrics took the UNSCOPED branch and diffed a 1-family run against the full
  averaged baseline. All three drop together now, as CircleCI's fall-open does.
* CircleCI's EX_ARGS had no character screen and is used unquoted, and its
  code-metrics job still exit 1'd on an empty metrics set - which a scoped build
  makes a legitimate outcome.
* a `ci-full` PR label now turns the scoping off for one PR. A selector bug
  under-selects silently, and without a label the only ways back to a full matrix
  are accidental.

Performance, since the selector gates every other job: family.cmake texts are read
once rather than per changed directory (a 6,000-file dep bump re-read 84 files
99,892 times) and _scrape_mcu is cached: 2.2s -&gt; 0.29s there, 0.8s -&gt; 0.33s on a
class diff.

Tests: a drift guard for hw/bsp families absent from ci_set_matrix.family_list
(they select zero legs now, where they used to ride the full matrix); the rule-4
port test asserted a SUBSET, which set() satisfies, so it could not fail on the
empty selection it exists to catch; the GITHUB_ENV guard test counted a SUM of two
guards. Drops metrics.py's --only-examples, which nothing called, and applies the
TOTAL scrub to the by-example branch that skipped it.
</content>
</entry>
<entry>
<title>docs: record the CI selection design and its plan</title>
<updated>2026-08-21T04:09:03Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-21T04:09:03Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=f96ddbaa1e11a98f8076df48ba73026191c28399'/>
<id>urn:sha1:f96ddbaa1e11a98f8076df48ba73026191c28399</id>
<content type='text'>
The binding rule table (17 rows x 3 answer columns), the measured effect per PR
shape, and the reasoning behind the parts that look surprising: why empty means
empty, why hw/mcu and lib are rules rather than full-matrix paths, why get_deps.py
is diffed as data, and which build system is the reference. The plan is the
task-by-task record of how it was built, kept as the origin trail.
</content>
</entry>
</feed>
