Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/portable/wch/ch32_usbfs_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,19 @@
#define USBFS_EP_T_RES_STALL (3 << 0)

// RX_CTRL
// In CH32X035, TX and RX share the same 8-bit control register (UEP0_CTRL_H):
// bits [1:0] = TX response, bit [6] = TX toggle
// bits [3:2] = RX response, bit [7] = RX toggle
// bit [4] = AUTO_TOG, shared: a single bit that enables automatic data toggle
// for both TX and RX simultaneously.
#define USBFS_EP_R_RES_MASK (3 << 2)
#define USBFS_EP_R_TOG (1 << 7)
#define USBFS_EP_R_AUTO_TOG (1 << 4)

#define USBFS_EP_R_RES_ACK (0 << 0)
#define USBFS_EP_R_RES_NYET (1 << 0)
#define USBFS_EP_R_RES_NAK (2 << 0)
#define USBFS_EP_R_RES_STALL (3 << 0)
#define USBFS_EP_R_RES_ACK (0 << 2)
#define USBFS_EP_R_RES_NYET (1 << 2)
#define USBFS_EP_R_RES_NAK (2 << 2)
#define USBFS_EP_R_RES_STALL (3 << 2)
#else
// TX_CTRL
#define USBFS_EP_T_RES_MASK (3 << 0)
Expand Down
69 changes: 69 additions & 0 deletions src/portable/wch/dcd_ch32_usbfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
#define EP_TX_LEN(ep) ((&USBFSD->UEP0_TX_LEN)[2 * ep + (ep > 4 ? 24 : 0)])
#define EP_TX_CTRL(ep) ((&USBFSD->UEP0_CTRL_H)[2 * ep + (ep > 4 ? 24 : 0)])
#define EP_RX_CTRL(ep) ((&USBFSD->UEP0_CTRL_H)[2 * ep + (ep > 4 ? 24 : 0)])
// CH32X035: TX and RX share one 8-bit control register. These helpers preserve
// the opposite direction's bits (RES + TOG) during a read-modify-write.
// AUTO_TOG (bit 4) is excluded from both masks so the caller's value takes effect.
#define CH32X035_PRESERVE_TX_BITS(ep) (EP_TX_CTRL(ep) & (USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG))
#define CH32X035_PRESERVE_RX_BITS(ep) (EP_RX_CTRL(ep) & (USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG))
#else
#define EP_DMA(ep) ((&USBFSD->UEP0_DMA)[ep])
#define EP_TX_LEN(ep) ((&USBFSD->UEP0_TX_LEN)[2 * ep])
Expand Down Expand Up @@ -88,7 +93,13 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) {

EP_TX_LEN(ep) = len;
if (ep == 0) {
#if defined(CH32X035)
// CH32X035: TX and RX share one register; preserve RX bits when updating TX
EP_TX_CTRL(0) = CH32X035_PRESERVE_RX_BITS(0) |
USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0);
#else
EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0);
#endif
data.ep0_tog = !data.ep0_tog;
} else if (data.isochronous[ep]) {
EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET;
Expand Down Expand Up @@ -124,7 +135,12 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
}

if (ep == 0) {
#if defined(CH32X035)
// CH32X035: TX and RX share one register; preserve TX bits when setting RX=ACK
EP_TX_CTRL(0) = CH32X035_PRESERVE_TX_BITS(0) | USBFS_EP_R_RES_ACK;
#else
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
#endif
}
}
}
Expand All @@ -143,8 +159,13 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// setup endpoint 0
EP_DMA(0) = (uint32_t) &data.buffer[0][0];
EP_TX_LEN(0) = 0;
#if defined(CH32X035)
// CH32X035: TX and RX share one register; write combined initial state
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | USBFS_EP_R_RES_ACK;
#else
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
#endif

// enable other endpoints but NAK everything
USBFSD->UEP4_1_MOD = 0xCC;
Expand All @@ -165,8 +186,14 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
EP_DMA(ep) = (uint32_t) &data.buffer[ep][0];
#endif
EP_TX_LEN(ep) = 0;
#if defined(CH32X035)
// CH32X035: TX and RX share one register; write combined initial state
EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK |
USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK;
#else
EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK;
#endif
}
EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0];

Expand Down Expand Up @@ -195,8 +222,13 @@ void dcd_int_handler(uint8_t rhport) {

case PID_SETUP:
// setup clears stall
#if defined(CH32X035)
// CH32X035: TX and RX share one register; write combined state
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | USBFS_EP_R_RES_ACK;
#else
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
#endif

data.ep0_tog = true;
dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true);
Expand All @@ -213,7 +245,12 @@ void dcd_int_handler(uint8_t rhport) {
dcd_event_bus_reset(rhport, (USBFSD->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true);

USBFSD->DEV_ADDR = 0x00;
#if defined(CH32X035)
// CH32X035: TX and RX share one register; preserve TX bits when setting RX=ACK
EP_TX_CTRL(0) = CH32X035_PRESERVE_TX_BITS(0) | USBFS_EP_R_RES_ACK;
#else
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
#endif

USBFSD->INT_FG = USBFS_INT_FG_BUS_RST;
} else if (status & USBFS_INT_FG_SUSPEND) {
Expand Down Expand Up @@ -267,8 +304,13 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
request->bRequest == TUSB_REQ_SET_ADDRESS) {
USBFSD->DEV_ADDR = (uint8_t) request->wValue;
}
#if defined(CH32X035)
// CH32X035: TX and RX share one register; write combined state
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | USBFS_EP_R_RES_ACK;
#else
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
#endif
}

bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
Expand All @@ -283,13 +325,25 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
if (ep != 0) {
if (dir == TUSB_DIR_OUT) {
if (data.isochronous[ep]) {
#if defined(CH32X035)
EP_TX_CTRL(ep) = CH32X035_PRESERVE_TX_BITS(ep) | USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET;
#else
EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET;
#endif
} else {
#if defined(CH32X035)
EP_TX_CTRL(ep) = CH32X035_PRESERVE_TX_BITS(ep) | USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK;
#else
EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK;
#endif
}
} else {
EP_TX_LEN(ep) = 0;
#if defined(CH32X035)
EP_TX_CTRL(ep) = CH32X035_PRESERVE_RX_BITS(ep) | USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
#else
EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
#endif
}
}
return true;
Expand Down Expand Up @@ -339,10 +393,20 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
uint8_t dir = tu_edpt_dir(ep_addr);
if (ep == 0) {
if (dir == TUSB_DIR_OUT) {
#if defined(CH32X035)
// CH32X035: TX and RX share one register; preserve TX bits when setting RX=STALL
EP_TX_CTRL(0) = CH32X035_PRESERVE_TX_BITS(0) | USBFS_EP_R_RES_STALL;
#else
EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL;
#endif
} else {
EP_TX_LEN(0) = 0;
#if defined(CH32X035)
// CH32X035: TX and RX share one register; preserve RX bits when setting TX=STALL
EP_TX_CTRL(0) = CH32X035_PRESERVE_RX_BITS(0) | USBFS_EP_T_RES_STALL;
#else
EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL;
#endif
}
} else {
if (dir == TUSB_DIR_OUT) {
Expand All @@ -359,7 +423,12 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
uint8_t dir = tu_edpt_dir(ep_addr);
if (ep == 0) {
if (dir == TUSB_DIR_OUT) {
#if defined(CH32X035)
// CH32X035: TX and RX share one register; preserve TX bits when setting RX=ACK
EP_TX_CTRL(0) = CH32X035_PRESERVE_TX_BITS(0) | USBFS_EP_R_RES_ACK;
#else
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
#endif
}
} else {
if (dir == TUSB_DIR_OUT) {
Expand Down
Loading