| Age | Commit message (Collapse) | Author |
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Add support for WCH ch582/583 series
|
|
|
|
* ci: post HIL report comment from workflow_run so it works on forked PRs
|
|
The CH58x->CH583 rename left OPT_MCU_CH583 defined twice at 2240 plus a second
literal 2240 for OPT_MCU_CH582 -- a duplicate public MCU option macro (redefinition).
Collapse to a single canonical OPT_MCU_CH583 and define OPT_MCU_CH582 as a token
alias of it (matching the OPT_MCU_SAML21/MIMXRT10XX alias style), so there is one
value and CH582 still selects the CH583 code path.
Found by Codex review.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Both run on the shared ch32_usbfs device driver (full-speed). CH32V103 is the older
combined-control USBFS IP; CH583/CH582 (ch583 family) is device-only in this port.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The BSP family and MCU option were named "ch58x"/"CH58X", but the supported part is
the CH583/CH582 (and the SDK repo is openwch/ch583); CH585 is a separate MCU family,
so the CH58x umbrella was misleading. Rename to the specific family:
- hw/bsp/ch58x -> hw/bsp/ch583 (dir), and the BSP-local files ch58x_it.* ->
ch583_it.*, system_ch58x.* -> system_ch583.* (include guards/refs updated). The
vendor SDK files (CH58x_common.h, CH58x_*.c in hw/mcu/wch/ch583) keep their names.
- OPT_MCU_CH58X -> OPT_MCU_CH583 in tusb_option.h, tusb_mcu.h, and the shared WCH
USBFS driver (ch32_usbfs_reg.h, dcd_ch32_usbfs.c). OPT_MCU_CH582 is kept as an
alias (same value), so either name selects the same code.
- FAMILY_MCUS CH58X -> CH583, CFG_TUSB_MCU=OPT_MCU_CH583, mcu:CH58X -> mcu:CH583 in
the example skip lists, the CI build matrix (ci_set_matrix.py), the get_deps family
tag, and docs/reference/boards.rst.
Board names (ch582m_evt, yd-ch582m) are unchanged. Verified: make + cmake build for
ch582m_evt, and ci.lan HIL (all device examples pass).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
CH58x has no isochronous support (dcd_edpt_iso_alloc() returns false), but the
audio class ignores that result and the endpoints fall back to capped 64-byte
non-iso transfers, producing non-functional audio firmware. video_capture and the
FreeRTOS audio examples already carry mcu:CH58X; add it to the remaining iso
examples (audio_test, audio_4_channel_mic, audio_test_multi_rate, cdc_uac2,
uac2_headset, uac2_speaker_fb) so they are not built for CH58x.
Found by Codex review. Verified via build_utils.skip_example() that all six now
skip on ch582m_evt while control examples (e.g. cdc_msc) still build.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Fold in the CH58x BSP review fixes:
- family.mk: drop stray trailing backslashes on the last LDFLAGS/SRC_C entries
(harmless -- GNU Make ends the list at the blank line -- but misleading).
- debug_uart.c: uart_write() spun on a full ring buffer with nothing to drain it
(only uart_sync() advances tx_consume), so a burst larger than the buffer
deadlocked. Drain the FIFO while waiting, like uart_sync() does.
- wch-riscv.cfg: move the OpenOCD work area from 0x80000000 (unmapped) to the
0x20000000 SRAM, sized to 32 KB, matching ch32v20x/wch-riscv.cfg.
- family.c: implement board_get_unique_id() from the factory MAC. CH58x is a BLE
part, so a unique 6-byte MAC lives in FlashROM at ROM_CFG_MAC_ADDR; GetMACAddress()
reads it via FLASH_EEPROM_CMD (in libISP583.a), so no extra source file is needed.
The read buffer is TU_ATTR_ALIGNED(4) and 8 bytes, per the SDK's documented
4-byte-aligned, word-granular buffer contract (CH58x_flash.c).
- test/hil/tinyusb.json: key ch582m_evt off this board's actual MAC (D443627B5450)
instead of the fixed placeholder, like every other board.
Verified on ci.lan HIL: ch582m_evt enumerates with serial D443627B5450 and all
device examples pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The OUT data-toggle check -- drop a packet whose DATA0/DATA1 doesn't match the
expected toggle (a host retransmit after a lost ACK, or a host that doesn't
alternate the toggle) -- only ran on CH58x. The auto-toggle parts (V103/V20x/V307/
X035) never checked it, so a duplicate/retransmitted OUT was processed twice.
HiFiPhile confirmed it: a host patched to send DATA0-only had CH32V305 accept every
packet. Move the TOG_OK gate out of the CH58x-only block so it runs on every variant;
the manual toggle flip stays CH58x-only. EP0 keeps its own toggle via the SETUP/status
flow and is exempt.
Verified on ci.lan HIL: ch582m_evt (CH58x), ch32v103r_r1_1v0 (V103), nanoch32v203
(V203) all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
family.mk listed -nostartfiles and the nano/nosys specs under LDFLAGS_GCC, a variable
the make build system never reads (only LDFLAGS / LDFLAGS_CLANG are consumed by
gcc_rules.mk). So the make build linked the toolchain's crt0.o alongside the SDK's
startup_CH583.S and failed with "multiple definition of _start" + an undefined
__bss_start, and also pulled in full newlib (RAM blew up). Rename it to LDFLAGS,
matching ch32v20x/family.mk. The cmake build was unaffected (it sets these via
target_link_options). Fixes the CircleCI one-random-make-ch58x build.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The dependency is fetched from https://github.com/openwch/ch583.git but lived at
hw/mcu/wch/ch58x. Rename the local path to hw/mcu/wch/ch583 so it matches the
upstream repo name. Updates the get_deps.py path key and the ch58x BSP SDK_DIR
(family.mk + family.cmake); the BSP family stays "ch58x" (covers CH582 and CH583).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
dcd_edpt0_status_complete() wrote the full SET_ADDRESS wValue into R8_USB_DEV_AD,
clobbering bit 7, which on CH58x is a user general-purpose flag (only bits [6:0]
are the device address). Mask to 7 bits and preserve bit 7, matching the removed
dcd_ch58x_usbfs.c. CH58x-scoped; other parts keep the full write.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The PID_SETUP handler armed the new control transfer but left any in-flight EP0
transfer from the previous request marked valid, so a spurious EP0 IN/OUT could run
update_in()/update_out() against stale state (the removed dcd_ch58x_usbfs.c invalidated
both EP0 directions on every SETUP). Clear xfer[0] IN/OUT validity when a SETUP arrives.
Applies to all WCH USBFS parts -- a new SETUP always supersedes a pending control xfer.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The USBFS SUSPEND interrupt fires on both the suspend and the resume edge, but the
handler unconditionally posted DCD_EVENT_SUSPEND. On CH58x tud_resume_cb() therefore
never ran, and a device that lowered clocks/power in tud_suspend_cb() was never told
to restore them. Read MIS_ST's suspend bit (1 while suspended, 0 once resumed) to emit
DCD_EVENT_RESUME on the wake edge -- what the removed dcd_ch58x_usbfs.c did. Scoped to
CH58x via #if; the CH32 parts keep their existing behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The manual-toggle ISR skipped EP0 entirely (if (ep != 0)), so EP0's RX data toggle
was set to DATA1 once at SETUP and never advanced. A control-OUT whose data stage
exceeds the EP0 packet size (a vendor/WebUSB OUT, a large HID SET_REPORT, or an
HS DFU download) desynced on the second packet and stalled.
EP0 has no hardware auto-toggle on CH58x (per the datasheet RB_UEP_AUTO_TOG applies
only to EP1/2/3/5/6/7), so flip its RX toggle on every OUT and always process the
packet -- restoring what the removed dcd_ch58x_usbfs.c did. The HIL examples keep
their control-OUT data stages within a single packet, so this was latent.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
dcd_edpt_xfer() re-enabled the USB interrupt before update_in() / ep_rx_set_response(),
which read-modify-write the (combined) EP control register. On CH58x the ISR RMWs that
same register to flip the manual data toggle, so a transfer interrupt landing mid-RMW
could drop the toggle flip and desync the endpoint. Move dcd_int_enable() to after the
arming so the whole sequence is atomic w.r.t. the ISR (matching the CH32X035 port #3703).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
video: assert usbd_edpt_iso_activate() result in _open_vs_itf()
|
|
Tidy the CH58x register/buffer layout the initial port left rough.
Register map (USBOTG_FS_TypeDef):
- Extend the struct to the full CH583/582 datasheet Table 17-2 map instead of
stopping at UEP567_MOD (0x0E) with the per-endpoint registers living only in
raw-address macros.
- Express the per-endpoint DMA/length/control registers as arrays of 4-byte
slots (ch58x_ep_dma_t / ch58x_ep_ctrl_t): EP0-3 DMA at 0x10, EP0-4 ctrl at
0x20, EP5-7 DMA/ctrl split to 0x54/0x64 (EP4 has no DMA register of its own;
it shares EP0's). TU_VERIFY_STATIC pins the slot sizes and block offsets, so
the EP_TX_LEN/EP_CTRL/EP_DMA macros walk each block by the 4-byte stride
(pointer arithmetic off slot 0, so the unused ternary branch can't trip
-Warray-bounds).
- Gate the two driver sites on CFG_TUSB_MCU == OPT_MCU_CH58X directly rather
than the CH32_USBFS_EP_REGS_CUSTOM alias, which was only ever defined in the
CH58x branch.
EP buffers (the data struct):
- Replace buffer[EP_MAX][2][64] on CH58x with named per-endpoint buffers: EP0/EP4
use the dedicated 192B ep0_ep4_buffer, so the old array left buffer[0]/buffer[4]
allocated-but-unused.
- Drop EP3's oversized iso buffer (out[64] + in[1023]); EP3 is bulk-only on CH58x,
so it uses a plain 128-byte buffer like the others. The data struct shrinks from
~2636 to 1292 bytes.
- Keep the now uniformly-64-byte buffers safe: dcd_edpt_iso_alloc()/iso_activate()
refuse isochronous on CH58x (no iso support; 8-bit T_LEN caps a packet at 255B),
and update_in()/update_out() additionally cap each packet copy to 64 bytes so a
class that ignores the iso-alloc result cannot run a memcpy past a buffer into a
neighbour's.
Non-CH58x parts (e.g. ch32v103) keep the struct-based macros, buffer[EP_MAX], and
the iso buffer unchanged. Verified on ch582m_evt HIL (ci.lan): all device examples
pass; ch32v103 build unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Add the device-only CH582M-EVT (WCH USBFS via the shared dcd_ch32_usbfs.c),
riscv-gcc, flashed by openocd_wch probe 7FD88F0604B5, to tinyusb.json.
Also reorder device_tests to keep examples sharing a VID:PID non-adjacent:
cdc_msc and cdc_msc_throughput both use cafe:4003, and on boards whose
CPU-reset does not drop D+ (e.g. WCH CH58x via openocd) back-to-back same-PID
firmware leaves the host on the previous example's cached descriptors, so the
new example's CDC never enumerates and the test fails. Moving dfu (cafe:4000)
between them changes the PID and forces the host to re-enumerate.
Remote HIL on ci.lan: all device examples pass, including cdc_msc_throughput
(no skip needed).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The isochronous streaming endpoint was activated with the
usbd_edpt_iso_activate() return value ignored, unlike every neighbouring
open in the same function (usbd_edpt_open() is wrapped in TU_ASSERT on both
the non-ISO-alloc fallback and the bulk branch).
When a DCD refuses the iso endpoint -- e.g. it has no isochronous support, or
the requested packet size does not fit its endpoint buffers -- that failure
was silently swallowed and the alternate setting was reported as opened,
leaving the host streaming to an endpoint the device never armed.
Wrap it in TU_ASSERT so the open fails cleanly and the refusal propagates,
matching the adjacent endpoint-open calls.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
ci(review): run Claude PR review at max effort
|
|
Fix one direction endpoint examples
|
|
ncm: add weak callback for initial link state
|
|
fix: BE bitfield guards for audio structs and endian-safe wValue/wIndex extraction in UAC2 examples
|
|
fix(stm32_fsdev): don't enable the unused USB wakeup EXTI IRQ (F1/F3/G4/L1)
|
|
test/hil: fail audio test on missing alsa-utils instead of skipping
|
|
Pass --effort max to the claude CLI in the auto-review workflow so PR
reviews run at maximum reasoning effort. Switch claude_args to a
multi-line block scalar for readability, keeping --max-turns 50 and
--model claude-opus-4-8 unchanged.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
Enabling the audio test fleet-wide surfaced failures on esp32-p4/s3 and
metro_m4_express: the UAC mic enumerates but arecord fails the iso IN read
with EIO, while 18 other boards pass strict=1.000.
esp32: root cause is the FreeRTOS tick rate. ESP-IDF defaults
CONFIG_FREERTOS_HZ to 100, so the audio task wakes only every 10 ms and
can't service the 1 ms UAC iso frames -> underrun -> arecord EIO. (The same
dwc2 driver passes on STM32, whose FreeRTOSConfig is 1000 Hz.) Set
CONFIG_FREERTOS_HZ=1000 in the example sdkconfig.defaults; the example
defaults are honored in the generated sdkconfig alongside the BSP's, so this
takes effect.
metro_m4_express (samd51): not tick-rate -- its FreeRTOSConfig is already
1000 Hz like the passing boards -- so it's a separate iso-IN issue, skipped
for now.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The classic-USB STM32 fsdev driver enabled the EXTI-line USB wakeup interrupt
(USBWakeUp_IRQn, and USBWakeUp_RMP_IRQn on the F3 remap path) in the NVIC, but
never uses it: resume is serviced in-band via ISTR.WKUP in the USB_LP/HP ISR,
and the driver never arms or clears that EXTI line. The wakeup EXTI interrupt is
only needed to wake the core from STOP mode, which TinyUSB does not implement.
Leaving its NVIC vector enabled lets it fire spuriously into an unhandled or
looping vector -- the freeze reported in #3696 on STM32G473.
USBWakeUp_IRQn is a valid, dedicated USB-wakeup-via-EXTI interrupt (e.g.
stm32g473xx.h: =42 "USB Wakeup through EXTI line"), not an "unrelated
interrupt"; it is simply unused here.
- Comment out USBWakeUp_IRQn for F1/F3/G4/L1 and USBWakeUp_RMP_IRQn on the F3
remap path, kept in place so STOP-mode wakeup is a one-line re-enable.
- Keep the STM32L1 USBWakeUp_IRQn -> USB_FS_WKUP_IRQn alias for that re-enable.
- Document the rationale in fsdev_stm32.h with a TODO.
- Comment out the matching USBWakeUp(_RMP)_IRQHandler in the F1/F3/G4 BSPs, and
the FreeRTOS NVIC_SetPriority(USBWakeUp_IRQn) on F1/G4.
Fixes #3696
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Replace PR #3515's separate dcd_ch58x_usbfs.c / hcd_ch58x_usbfs.c with the
shared WCH USBFS device driver (combined per-endpoint control, like CH32V103),
adding two CH58x-specific behaviors guarded so CH32V103/V20x/V307 are unchanged:
- CH32_USBFS_EP_MANUAL_TOG: CH58x's hardware AUTO_TOG does not stay in sync, so
the ISR toggles DATA0/DATA1 manually and discards toggle-mismatched OUT
packets. Fixes multi-packet bulk-IN (e.g. MSC READ10) that otherwise hung.
- CH32_USBFS_EP4_SHARES_EP0: EP4 has no DMA register and overlays EP0's region
(EP0[0:63] + EP4 OUT[64:127] + EP4 IN[128:191]); add a 192-byte shared buffer
and buffer-pointer helpers (transparent for the other parts). Fixes
cdc_dual_ports (Port1 is on EP4).
Add the ch582m_evt board. Device only on USB0 (rhport 0): the shared
hcd_ch32_usbfs.c is CH32V20x-specific and cannot drive CH58x, so host / USB2
(rhport 1) is left commented out in the BSP for easy re-add.
Verified on ch582m_evt via local HIL: all device examples pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
ci(metrics): collapse Average Code Size Metrics table when no base
|
|
The audio20 get/set entity dispatchers already extract entity_id from
wIndex and route to the matching clock / feature-unit helper, so each
helper's own entity_id re-derivation and TU_ASSERT(entity_id == ...) was
dead: the helper is only ever reached for its one entity. Unknown
entities are still rejected by the dispatcher's "not handled" path.
Remove the redundant local, the dead assert, and the constant "entity"
field from each helper's not-supported log (the message text already
identifies the entity). The local is dropped entirely rather than kept
for the log, since TU_LOG1 compiles out in release and would leave it
unused.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
When no base metrics are available to compare against, the PR comment
falls back to the combined "TinyUSB Average Code Size Metrics" report
(build.yml copies metrics.md to metrics_compare.md). That posted the
full per-example size table inline, cluttering the comment.
Wrap the table in a <details><summary>Size table</summary> block so the
heading stays visible but the detail is collapsed by default, matching
the Size Difference Report's collapsible sections.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
arecord (alsa-utils) is a documented HIL host requirement, like
mtools/libmtp9/iperf — none of which have a skip-if-missing guard. The
audio test was the exception: it silently returned 'skipped' when arecord
was absent, masking host misconfiguration. The ci.lan rig had been
silently skipping device/audio_test_freertos on every board because
alsa-utils was never installed.
Remove the shutil.which('arecord') guard so a missing package surfaces as
a failure, consistent with the other tool-dependent tests, and drop the
now-unused shutil import. Note in the host-setup comment that these
packages are required (a missing tool fails its test rather than skipping).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
After the UAC2 examples switched to tusb_control_request_t with
TU_U16_HIGH/LOW() extraction, audio20_control_request_t is no longer
referenced anywhere in the tree. It is a byte-overlay of the setup
packet whose bChannelNumber/bControlSelector/bInterface/bEntityID
sub-byte fields silently misread on big-endian once wValue/wIndex are
converted to host order (tu_le16toh in dcd.h), so leaving it in the
public header is a latent BE trap; the BE bitfield guard previously
added to its bmRequestType_bit only masked that by guarding byte 0.
Drop the struct entirely. Callers should use tusb_control_request_t and
TU_U16_LOW/HIGH(wValue|wIndex), matching audio_device.c and the examples.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
|
|
|
|
ch32v103: bring up USB device (combined-control USBFS IP) + add to HIL
|
|
Now that CH32V103 USB device works, add the board to the active HIL pool.
It is a WCH RISC-V USBFS part, so it builds under the riscv-gcc bucket;
single config (USBFS only, no fsdev variant).
cdc_msc_throughput is skipped for this board: its device->host CDC bulk-IN
read hard-fails here (a known, pre-existing dcd_ch32_usbfs throughput
limitation, not specific to CH32V103). All other device tests pass on
ci.lan (verified green, 0 failures).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
CH32V103 uses the older USBFS IP: a single combined UEPn_CTRL register per
endpoint (IN response in bits [1:0], OUT response in [3:2], shared auto-toggle,
separate IN/OUT toggles) instead of the separate UEPn_TX_CTRL/UEPn_RX_CTRL
bytes of the newer IP (CH32V20x/V307). The shared driver was written for the
newer IP, so EP0 control transfers never worked on V103: the OUT response was
written to a reserved byte and the IN write clobbered the OUT bits.
- ch32_usbfs_reg.h: annotate the V103 register struct with byte offsets and add
a union exposing the combined UEPn_CTRL at the UEPn_TX_CTRL offset; define
CH32_USBFS_EP_CTRL_COMBINED and the combined-register bit positions.
- dcd_ch32_usbfs.c: abstract EP control access behind ep_tx/rx_ctrl_set() (full
write) and ep_tx/rx_set_response() (response-only RMW). The newer-IP path is
unchanged; the combined path read-modify-writes the single register and arms
the post-SETUP data stage at DATA1.
- bsp/ch32v10x: implement board_get_unique_id() (real chip UID) and drop the
CSR 0x800 writes that corrupted the QingKe V3 interrupt config and left all
interrupts disabled (the USB ISR never ran).
Verified on ch32v103r_r1_1v0: enumerates and passes HIL for cdc_msc, hid,
msc, midi, mtp, dfu, etc.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
dcd/musb: defer EP0 SETUP during DATA_IN/STATUS race
|
|
netd_init resets link_is_up to a compile-time default, which is
incorrect when the host reboots without power-cycling the device.
Add tud_network_default_link_state_cb() so applications can return
the actual physical link state. The weak default preserves existing
CFG_TUD_NCM_DEFAULT_LINK_UP behaviour.
|
|
dcd/musb: harden & refactor the EP0 control state machine (review follow-up for #3643)
|
|
* hil: enable nanoch32v203 in CI with fsdev + usbfs variants
nanoch32v203 was parked in boards-skip; move it into the active pool now
that the board is wired to the ci.lan rig. Cover both USB device IPs as
build variants:
- nanoch32v203-fsdev: RHPORT_DEVICE=0 (USBD / stm32 FSDev IP)
- nanoch32v203-usbfs: RHPORT_DEVICE=1 (WCH USBFS IP)
|
|
* device: clamp EP0 OUT data copy to the control transfer buffer
usbd_control_xfer_cb() copied xferred_bytes from the EP0 bounce buffer
into the requester's buffer with no bound. A non-compliant host that
sends an OUT data packet larger than the control transfer's data_len
(= min(len, wLength), the buffer capacity) would overflow that buffer
and over-count total_xferred. Clamp xferred_bytes to the remaining
buffer space before the memcpy and accounting.
|
|
Cleanup from a code-review pass, no behavior change:
- Replace the open-coded "last DATA packet" test (remain_wlength == 0 ||
len < CFG_TUD_ENDPOINT0_SIZE), duplicated in the edpt0_xfer DATA IN
arm, pipe0_process_xfer_state_isr, and the DATA OUT drain, with one
inline pipe0_data_stage_done() so IN and OUT can't drift.
- Correct the xact_len comment (only the IN path reports it; OUT reports
count0) and the dcd_edpt_stall comment (a deferred SETUP means the old
transfer ended on the wire, not that its status stage was "seen").
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
The helper advances the whole EP0 control state machine on a
completion/confirmation IRQ — it dispatches on pipe0->state and also
fires the DATA_IN completion, not just the status stage — so
"process_status" undersold it. Matches the process_*_isr family.
Co-Authored-By: Claude Fable 5 <[email protected]>
|