Repository navigation
Fix: Octatrack base, USB MIDI clock gives way to DIN clock - #1131
Merged
Merged
Conversation
The UART0 ISR stamps each DIN 0xF8 into the clock handler's timestamp, and the shared USB MIDI receiver stamps each USB one into the same word; both reach one FIFO, framer and clock handler. With a clock on each the handler read double the tempo and the project saved it. The receiver now drops a USB clock, START, CONTINUE, STOP or song position while DIN is clocking: the last stamp is not the receiver's own and is younger than the clock handler's resync gap (167 ms). The first USB tick after DIN stops carries a delta past that gap, so the handler starts a fresh tempo on USB. Every USB layout of the base shares this receiver. The vendored usbmidi_rx.s stays byte-exact to its import record; the change is a guarded source transform in base_usb_functions.py. The beta base is regenerated and the base-bound packages relinked (--base-only). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
0x400106ec) stamps each DIN0xF8into the clock timestamp (0x46c8345a, delta0x46c83466). The base's shared USB MIDI receiver (usbmidi_rx.s,usbmidi_rx_decode, lines 308-323) stamps each USB0xF8into the same word and enqueues it into the same FIFO, framer and clock handler (0x40005a48), with no check for DIN. Both clocks together are one stream of twice the ticks: the handler reads about double the tempo and the project saves it. This is inferred from the code and an upstream review of the same receiver. It is not measured on our base. Every USB layout of the base (USB MIDI alone and all six USB Audio layouts) runs this one receiver:build_core.pywrites it for each one, and the profile dispatch jumps tousbmidi_rx_isr_shim.mw_usb_clk_stamp). If the timestamp word differs from it, DIN wrote it. DIN owns the clock while that tick is younger than the clock handler's own resync gap: 1,881,600 DTCN0 counts, 167 ms (cmpilat0x40005a96). A longer gap makes the handler restart its interval ring.F8 FA FB FC F2) is dropped and counted inmw_usb_clock_dropped. Notes, CCs, active sensing and everything else still pass.usbmidi_rx.sstays byte-exact to its MIT import record. The change is a guarded source transform,receiver_sourceinbase_usb_functions.py(GPL, our own code): one store after the receiver's stamp, and one call before an event is enqueued. A changed seam refuses to build. Thebles/bgtsshort branches of the decoder still fit (124 of 127 bytes). An out-of-range one fails the assembly.npm run octatrack:base -- --beta --write, new identity9680e9ac). The base-bound packages are relinked (npm run octatrack:module-packages -- --base-only: onlyrequiredBasemoved). The USB group stays inside its reserve, so arena, pool and symbols outside it don't move.changelog/2026-11-01-usb-clock-din.md. A short note is insdk/machines/octatrack/elekloader/README.md.npm run pr:readysays Ready.sdk:checkpassed, includingoctatrack-module-packages.py --check. The base build is stock-free and flash-safe, and the browser.binis byte-identical.test_receiver_clock_guard_is_two_insertions_and_refuses_drift, which runs everywhere: the transform makes exactly its two insertions and refuses a changed seam or a second application.test_usb_clock_and_transport_give_way_while_din_clocksruns the transformedusbmidi_rx_decodein Unicorn's ColdFire (CFV4E). DIN's UART stamp is modelled as two stores. Scenarios:F8 FA FB FC F2, passes note,FEandF9, and leaves DIN's stamp and delta alone.pip install unicorn, ascheck_stub.pyalready needs). It passed here with Unicorn 2.1.4. Run against the unchanged receiver, the same DIN scenario lets USBF8 FAthrough with a half-tick delta.mem:<mw_usb_clock_dropped>:4rises while both run (the address is in the--outbuild'ssymbols.json), andmem:0x80001818:4reads about 2400 (tempo x 24).usbmidi_rx.sand its MIT licence are unchanged. The upstream fix to the same receiver (MIT) supplied only the idea and the facts it relies on. The facts were checked against the disassembly of the user's own OS (the UART ISR's stamp, the handler's 167 ms resync gap). The code is written fresh inbase_usb_functions.py(GPL-3.0-or-later) and copies none of it. MIT and GPL combine in the base as they already do.npm run octatrack:base -- --stock OS.bin --beta --write, thennpm run octatrack:module-packages -- --base-only).usb-audio-out-tracks-main-cuecarries its own older copy of the receiver. It is another author's module and keeps the double-clock path until its own versioned update. The base fix does not change that card download.sdk/machines/octatrack/elekloader/README.md). Thenpm ciprepare step's ignored files (module-changelogs.json) were missing in a fresh worktree whosenode_moduleswas symlinked.octatrack:basethen fails untilnode scripts/machine-modules.mjs && node scripts/module-changelogs.mjs --writehas run. That is already in DEVELOPER_WORKFLOW ("Archived source snapshots"), so nothing new.🤖 Generated with Claude Code