summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2026-01-06 18:42:58 +0100
committerHiFiPhile <[email protected]>2026-01-06 18:42:58 +0100
commit60154a128795bcd6ca36042cac1b8bebf1a2764e (patch)
tree0557ab4b2a01c64de109c54662ba6f3a58147bc9 /src
parentc5f91ec6f54509d03529e276ffd42b0d9abab695 (diff)
parent593dce28349cf5b1299c2cf1193312cb783574f3 (diff)
Merge remote-tracking branch 'tinyusb/master' into ep0_direct
Diffstat (limited to 'src')
-rw-r--r--src/class/audio/audio_device.c12
-rw-r--r--src/class/cdc/cdc_host.c2
-rw-r--r--src/class/vendor/vendor_device.c7
-rw-r--r--src/class/vendor/vendor_device.h7
-rw-r--r--src/common/tusb_common.h4
-rw-r--r--src/common/tusb_debug.h8
-rw-r--r--src/common/tusb_fifo.c395
-rw-r--r--src/common/tusb_fifo.h114
-rw-r--r--src/common/tusb_mcu.h176
-rw-r--r--src/common/tusb_verify.h10
-rw-r--r--src/device/usbd.c11
-rw-r--r--src/device/usbd.h2
-rw-r--r--src/host/usbh.c99
-rw-r--r--src/host/usbh.h11
-rw-r--r--src/osal/osal_none.h18
-rw-r--r--src/osal/osal_pico.h54
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_hpm.h54
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_rw61x.h48
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c405
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c42
-rw-r--r--src/portable/ehci/ehci.c14
-rw-r--r--src/portable/mentor/musb/dcd_musb.c74
-rw-r--r--src/portable/microchip/samg/dcd_samg.c4
-rw-r--r--src/portable/nuvoton/nuc505/dcd_nuc505.c4
-rw-r--r--src/portable/renesas/rusb2/dcd_rusb2.c259
-rw-r--r--src/portable/renesas/rusb2/hcd_rusb2.c135
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.c80
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.h58
-rw-r--r--src/portable/renesas/rusb2/rusb2_type.h20
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c512
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_at32.h19
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_ch32.h10
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.c116
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.h (renamed from src/portable/st/stm32_fsdev/fsdev_type.h)209
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h201
-rw-r--r--src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c878
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c97
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c54
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c4
-rw-r--r--src/tusb.c2
-rw-r--r--src/tusb_option.h70
41 files changed, 2695 insertions, 1604 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 03cb51efe..6cb05307b 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -685,17 +685,17 @@ void audiod_init(void) {
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
case 0:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
case 1:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
case 2:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, true);
break;
#endif
}
@@ -727,17 +727,17 @@ void audiod_init(void) {
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
case 0:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
case 1:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
case 2:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, true);
break;
#endif
}
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 32f6827b0..f19c4a327 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -828,7 +828,9 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
ENUM_SET_LINE_CONTROL,
ENUM_SET_LINE_COMPLETE,
};
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
const uint8_t idx = get_idx_by_ptr(p_cdc);
+ #endif
const uintptr_t state = xfer->user_data;
switch (state) {
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index 9972911e0..b8e6fec6f 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -160,6 +160,13 @@ uint32_t tud_vendor_n_write_available(uint8_t idx) {
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_write_available(&p_itf->stream.tx);
}
+
+bool tud_vendor_n_write_clear(uint8_t idx) {
+ TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
+ vendord_interface_t *p_itf = &_vendord_itf[idx];
+ tu_edpt_stream_clear(&p_itf->stream.tx);
+ return true;
+}
#endif
//--------------------------------------------------------------------+
diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h
index d59c885d2..c3de4c49d 100644
--- a/src/class/vendor/vendor_device.h
+++ b/src/class/vendor/vendor_device.h
@@ -91,6 +91,9 @@ uint32_t tud_vendor_n_write_flush(uint8_t idx);
// Return number of bytes available for writing in TX FIFO
uint32_t tud_vendor_n_write_available(uint8_t idx);
+
+// Clear the transmit FIFO
+bool tud_vendor_n_write_clear(uint8_t idx);
#endif
// Write a null-terminated string to TX FIFO
@@ -148,6 +151,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
return tud_vendor_n_write_available(0);
}
+
+TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
+ return tud_vendor_n_write_clear(0);
+}
#endif
// backward compatible
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index d74760608..6ac1405f3 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -329,7 +329,7 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_
#endif
-// scatter read 4 bytes from two buffers. Parameter are not checked
+// scatter read 4 bytes from two buffers (LE). Parameter are not checked
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *buf1, uint8_t len1, const uint8_t *buf2,
uint8_t len2) {
uint32_t result = 0;
@@ -348,7 +348,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *bu
return result;
}
-// scatter write 4 bytes to two buffers. Parameter are not checked
+// scatter write 4 bytes (LE) to two buffers. Parameter are not checked
TU_ATTR_ALWAYS_INLINE static inline void tu_scatter_write32(uint32_t value, uint8_t *buf1, uint8_t len1,
uint8_t *buf2, uint8_t len2) {
for (uint8_t i = 0; i < len1; ++i) {
diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h
index e0e09f5ce..ba5b4afd1 100644
--- a/src/common/tusb_debug.h
+++ b/src/common/tusb_debug.h
@@ -117,12 +117,16 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
}
}
- // not found return the key value in hex
+ #ifndef CFG_TUSB_DEBUG_PRINTF
+ // not found return the key value in hex if no custom printf is defined
static char not_found[11];
- if (snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key) <= 0) {
+ if (snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long)key) <= 0) {
not_found[0] = 0;
}
return not_found;
+ #else
+ return "NotFound";
+ #endif
}
#endif // CFG_TUSB_DEBUG
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index e97b6ccce..a92435912 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -59,7 +59,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ff_unlock(osal_mutex_t mutex) {
//--------------------------------------------------------------------+
// Setup API
//--------------------------------------------------------------------+
-bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) {
+bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable) {
// Limit index space to 2*depth - this allows for a fast "modulo" calculation
// but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
// only if overflow happens once (important for unsupervised DMA applications)
@@ -72,7 +72,6 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si
f->buffer = (uint8_t *)buffer;
f->depth = depth;
- f->item_size = (uint16_t)(item_size & 0x7FFFu);
f->overwritable = overwritable;
f->rd_idx = 0u;
f->wr_idx = 0u;
@@ -114,172 +113,265 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
// Pull & Push
// copy data to/from fifo without updating read/write pointers
//--------------------------------------------------------------------+
-#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
-// Copy to fifo from fixed address buffer (usually a rx register) with TU_FIFO_FIXED_ADDR_RW32 mode
-static void ff_push_fixed_addr_rw32(uint8_t *ff_buf, const volatile uint32_t *reg_rx, uint16_t len) {
- // Reading full available 32 bit words from const app address
- uint16_t full_words = len >> 2;
- while (full_words--) {
- const uint32_t tmp32 = *reg_rx;
- tu_unaligned_write32(ff_buf, tmp32);
- ff_buf += 4;
- }
+#if CFG_TUSB_FIFO_HWFIFO_API
+ #if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
+ #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n) _hwfifo = (_const volatile void *)((uintptr_t)(_hwfifo) + _n)
+ #else
+ #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n)
+ #endif
+
+ #define HWFIFO_ADDR_NEXT(_hwfifo, _const) HWFIFO_ADDR_NEXT_N(_hwfifo, _const, CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE)
- // Read the remaining 1-3 bytes from const app address
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem) {
- const uint32_t tmp32 = *reg_rx;
- memcpy(ff_buf, &tmp32, bytes_rem);
+ #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
+static inline void stride_write(volatile void *hwfifo, const void *src, uint8_t data_stride) {
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
+ if (data_stride == 4) {
+ *((volatile uint32_t *)hwfifo) = tu_unaligned_read32(src);
}
+ #endif
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
+ if (data_stride == 2) {
+ *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
+ }
+ #endif
}
// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode
-static void ff_pull_fixed_addr_rw32(volatile uint32_t *reg_tx, const uint8_t *ff_buf, uint16_t len) {
- // Write full available 32 bit words to const address
- uint16_t full_words = len >> 2u;
- while (full_words--) {
- *reg_tx = tu_unaligned_read32(ff_buf);
- ff_buf += 4u;
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ // Write full available 16/32 bit words to dest
+ const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE;
+ while (len >= data_stride) {
+ stride_write(hwfifo, src, data_stride);
+ src += data_stride;
+ len -= data_stride;
+ HWFIFO_ADDR_NEXT(hwfifo, );
+ }
+
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
+ // 16-bit access is allowed for odd bytes
+ if (len >= 2) {
+ *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
+ src += 2;
+ len -= 2;
+ HWFIFO_ADDR_NEXT_N(hwfifo, , 2);
+ }
+ #endif
+
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
+ // 8-bit access is allowed for odd bytes
+ while (len > 0) {
+ *((volatile uint8_t *)hwfifo) = *src++;
+ len--;
+ HWFIFO_ADDR_NEXT_N(hwfifo, , 1);
}
+ #else
- // Write the remaining 1-3 bytes
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem) {
- uint32_t tmp32 = 0u;
- memcpy(&tmp32, ff_buf, bytes_rem);
- *reg_tx = tmp32;
+ // Write odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
+ if (len > 0) {
+ uint32_t tmp = 0u;
+ memcpy(&tmp, src, len);
+ stride_write(hwfifo, &tmp, data_stride);
+ HWFIFO_ADDR_NEXT(hwfifo, );
}
+ #endif
}
-#endif
+ #endif
-// send n items to fifo WITHOUT updating write pointer
-static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr,
- tu_fifo_access_mode_t copy_mode) {
- const uint16_t lin_count = f->depth - wr_ptr;
- const uint16_t wrap_count = n - lin_count;
+ #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
+static inline void stride_read(const volatile void *hwfifo, void *dest, uint8_t data_stride) {
+ (void)data_stride; // possible unused
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
+ if (data_stride == 4)
+ #endif
+ {
+ tu_unaligned_write32(dest, *((const volatile uint32_t *)hwfifo));
+ }
+ #endif
- uint16_t lin_bytes = lin_count * f->item_size;
- uint16_t wrap_bytes = wrap_count * f->item_size;
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 2
+ if (data_stride == 2)
+ #endif
+ {
+ tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
+ }
+ #endif
+}
- // current buffer of fifo
- uint8_t *ff_buf = f->buffer + (wr_ptr * f->item_size);
+void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ // Reading full available 16/32-bit hwfifo and write to fifo
+ const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE;
+ while (len >= data_stride) {
+ stride_read(hwfifo, dest, data_stride);
+ dest += data_stride;
+ len -= data_stride;
+ HWFIFO_ADDR_NEXT(hwfifo, const);
+ }
- switch (copy_mode) {
- case TU_FIFO_INC_ADDR_RW8:
- if (n <= lin_count) {
- // Linear only
- memcpy(ff_buf, app_buf, n * f->item_size);
- } else {
- // Wrap around
- memcpy(ff_buf, app_buf, lin_bytes); // linear part
- memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
- }
- break;
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
+ // 16-bit access is allowed for odd bytes
+ if (len >= 2) {
+ tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
+ dest += 2;
+ len -= 2;
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, 2);
+ }
+ #endif
-#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
- case TU_FIFO_FIXED_ADDR_RW32: {
- const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf;
- if (n <= lin_count) {
- // Linear only
- ff_push_fixed_addr_rw32(ff_buf, reg_rx, n * f->item_size);
- } else {
- // Wrap around
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
+ // 8-bit access is allowed for odd bytes
+ while (len > 0) {
+ *dest++ = *((const volatile uint8_t *)hwfifo);
+ len--;
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, 1);
+ }
+ #else
+ // Read odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
+ if (len > 0) {
+ uint32_t tmp;
+ stride_read(hwfifo, &tmp, data_stride);
+ memcpy(dest, &tmp, len);
+ HWFIFO_ADDR_NEXT(hwfifo, const);
+ }
+ #endif
+}
+ #endif
+
+// push to sw fifo from hwfifo
+static void hwff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr,
+ const tu_hwfifo_access_t *access_mode) {
+ uint16_t lin_bytes = f->depth - wr_ptr;
+ uint16_t wrap_bytes = n - lin_bytes;
+ uint8_t *ff_buf = f->buffer + wr_ptr;
- // Write full words to linear part of buffer
- uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
- ff_push_fixed_addr_rw32(ff_buf, reg_rx, lin_4n_bytes);
- ff_buf += lin_4n_bytes;
+ const volatile void *hwfifo = (const volatile void *)app_buf;
+ if (n <= lin_bytes) {
+ // Linear only case
+ tu_hwfifo_read(hwfifo, ff_buf, n, access_mode);
+ } else {
+ // Wrap around case
- // There could be odd 1-3 bytes before the wrap-around boundary
- const uint8_t rem = lin_bytes & 0x03;
- if (rem > 0) {
- const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem);
- const uint32_t tmp32 = *reg_rx;
- tu_scatter_write32(tmp32, ff_buf, rem, f->buffer, remrem);
+ // Write full words to linear part of buffer
+ const uint8_t data_stride = access_mode->data_stride;
+ const uint32_t odd_mask = data_stride - 1;
+ uint16_t lin_even = lin_bytes & ~odd_mask;
+ tu_hwfifo_read(hwfifo, ff_buf, lin_even, access_mode);
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_even);
+ ff_buf += lin_even;
- wrap_bytes -= remrem;
- ff_buf = f->buffer + remrem; // wrap around
- } else {
- ff_buf = f->buffer; // wrap around to beginning
- }
+ // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
+ // combine it with the wrapped part to form a full word for data stride
+ const uint8_t lin_odd = lin_bytes & odd_mask;
+ if (lin_odd > 0) {
+ const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
+ uint8_t buf_temp[4];
+ tu_hwfifo_read(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode);
+ HWFIFO_ADDR_NEXT(hwfifo, const);
- // Write data wrapped part
- if (wrap_bytes > 0) {
- ff_push_fixed_addr_rw32(ff_buf, reg_rx, wrap_bytes);
- }
+ for (uint8_t i = 0; i < lin_odd; ++i) {
+ ff_buf[i] = buf_temp[i];
+ }
+ for (uint8_t i = 0; i < wrap_odd; ++i) {
+ f->buffer[i] = buf_temp[lin_odd + i];
}
- break;
+
+ wrap_bytes -= wrap_odd;
+ ff_buf = f->buffer + wrap_odd; // wrap around
+ } else {
+ ff_buf = f->buffer; // wrap around to beginning
}
-#endif
- default:
- break; // unknown mode
+ // Write data wrapped part
+ if (wrap_bytes > 0) {
+ tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, access_mode);
+ }
}
}
-// get n items from fifo WITHOUT updating read pointer
-static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_access_mode_t copy_mode) {
- const uint16_t lin_count = f->depth - rd_ptr;
- const uint16_t wrap_count = n - lin_count; // only used if wrapped
+// pull from sw fifo to hwfifo
+static void hwff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr,
+ const tu_hwfifo_access_t *access_mode) {
+ uint16_t lin_bytes = f->depth - rd_ptr;
+ uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
+ const uint8_t *ff_buf = f->buffer + rd_ptr;
- uint16_t lin_bytes = lin_count * f->item_size;
- uint16_t wrap_bytes = wrap_count * f->item_size;
+ volatile void *hwfifo = (volatile void *)app_buf;
- // current buffer of fifo
- const uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size);
-
- switch (copy_mode) {
- case TU_FIFO_INC_ADDR_RW8:
- if (n <= lin_count) {
- // Linear only
- memcpy(app_buf, ff_buf, n * f->item_size);
- } else {
- // Wrap around
- memcpy(app_buf, ff_buf, lin_bytes); // linear part
- memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part
- }
- break;
-
-#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
- case TU_FIFO_FIXED_ADDR_RW32: {
- volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf;
+ if (n <= lin_bytes) {
+ // Linear only case
+ tu_hwfifo_write(hwfifo, ff_buf, n, access_mode);
+ } else {
+ // Wrap around case
- if (n <= lin_count) {
- // Linear only
- ff_pull_fixed_addr_rw32(reg_tx, ff_buf, n * f->item_size);
- } else {
- // Wrap around case
+ // Read full words from linear part
+ const uint8_t data_stride = access_mode->data_stride;
+ const uint32_t odd_mask = data_stride - 1;
+ uint16_t lin_even = lin_bytes & ~odd_mask;
+ tu_hwfifo_write(hwfifo, ff_buf, lin_even, access_mode);
+ HWFIFO_ADDR_NEXT_N(hwfifo, , lin_even);
+ ff_buf += lin_even;
- // Read full words from linear part
- uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
- ff_pull_fixed_addr_rw32(reg_tx, ff_buf, lin_4n_bytes);
- ff_buf += lin_4n_bytes;
+ // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
+ const uint8_t lin_odd = lin_bytes & odd_mask;
+ if (lin_odd > 0) {
+ const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
- // There could be odd 1-3 bytes before the wrap-around boundary
- const uint8_t rem = lin_bytes & 0x03;
- if (rem > 0) {
- const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem);
- const uint32_t scatter32 = tu_scatter_read32(ff_buf, rem, f->buffer, remrem);
+ uint8_t buf_temp[4];
+ for (uint8_t i = 0; i < lin_odd; ++i) {
+ buf_temp[i] = ff_buf[i];
+ }
+ for (uint8_t i = 0; i < wrap_odd; ++i) {
+ buf_temp[lin_odd + i] = f->buffer[i];
+ }
- *reg_tx = scatter32;
+ tu_hwfifo_write(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode);
+ HWFIFO_ADDR_NEXT(hwfifo, );
- wrap_bytes -= remrem;
- ff_buf = f->buffer + remrem; // wrap around
- } else {
- ff_buf = f->buffer; // wrap around to beginning
- }
+ wrap_bytes -= wrap_odd;
+ ff_buf = f->buffer + wrap_odd; // wrap around
+ } else {
+ ff_buf = f->buffer; // wrap around to beginning
+ }
- // Read data wrapped part
- if (wrap_bytes > 0) {
- ff_pull_fixed_addr_rw32(reg_tx, ff_buf, wrap_bytes);
- }
- }
- break;
+ // Read data wrapped part
+ if (wrap_bytes > 0) {
+ tu_hwfifo_write(hwfifo, ff_buf, wrap_bytes, access_mode);
}
+ }
+}
#endif
- default:
- break; // unknown mode
+// send n items to fifo WITHOUT updating write pointer
+static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr) {
+ uint16_t lin_bytes = f->depth - wr_ptr;
+ uint16_t wrap_bytes = n - lin_bytes;
+ uint8_t *ff_buf = f->buffer + wr_ptr;
+
+ if (n <= lin_bytes) {
+ // Linear only case
+ memcpy(ff_buf, app_buf, n);
+ } else {
+ // Wrap around case
+ memcpy(ff_buf, app_buf, lin_bytes); // linear part
+ memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
+ }
+}
+
+// get n items from fifo WITHOUT updating read pointer
+static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr) {
+ uint16_t lin_bytes = f->depth - rd_ptr;
+ uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
+ const uint8_t *ff_buf = f->buffer + rd_ptr;
+
+ // single byte access
+ if (n <= lin_bytes) {
+ // Linear only
+ memcpy(app_buf, ff_buf, n);
+ } else {
+ // Wrap around
+ memcpy(app_buf, ff_buf, lin_bytes); // linear part
+ memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part
}
}
@@ -332,7 +424,7 @@ static uint16_t correct_read_index(tu_fifo_t *f, uint16_t wr_idx) {
// Works on local copies of w and r
// Must be protected by read mutex since in case of an overflow read pointer gets modified
uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx,
- tu_fifo_access_mode_t access_mode) {
+ const tu_hwfifo_access_t *access_mode) {
uint16_t count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx);
if (count == 0) {
return 0; // nothing to peek
@@ -349,7 +441,16 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
- ff_pull_n(f, p_buffer, n, rd_ptr, access_mode);
+
+#if CFG_TUSB_FIFO_HWFIFO_API
+ if (access_mode != NULL) {
+ hwff_pull_n(f, p_buffer, n, rd_ptr, access_mode);
+ } else
+#endif
+ {
+ (void)access_mode;
+ ff_pull_n(f, p_buffer, n, rd_ptr);
+ }
return n;
}
@@ -357,13 +458,13 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
// Read n items without removing it from the FIFO, correct read pointer if overflowed
uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) {
ff_lock(f->mutex_rd);
- const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8);
+ const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, NULL);
ff_unlock(f->mutex_rd);
return ret;
}
// Read n items from fifo with access mode
-uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode) {
+uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_t *access_mode) {
ff_lock(f->mutex_rd);
// Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable
@@ -375,7 +476,8 @@ uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_f
}
// Write n items to fifo with access mode
-uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode) {
+uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
+ const tu_hwfifo_access_t *access_mode) {
if (n == 0) {
return 0;
}
@@ -401,8 +503,8 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
// function! Since it would end up in a race condition with read functions!
if (n >= f->depth) {
// Only copy last part
- if (access_mode == TU_FIFO_INC_ADDR_RW8) {
- buf8 += (n - f->depth) * f->item_size;
+ if (access_mode == NULL) {
+ buf8 += (n - f->depth);
} else {
// TODO should read from hw fifo to discard data, however reading an odd number could
// accidentally discard data.
@@ -437,7 +539,14 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr);
- ff_push_n(f, buf8, n, wr_ptr, access_mode);
+#if CFG_TUSB_FIFO_HWFIFO_API
+ if (access_mode != NULL) {
+ hwff_push_n(f, buf8, n, wr_ptr, access_mode);
+ } else
+#endif
+ {
+ ff_push_n(f, buf8, n, wr_ptr);
+ }
f->wr_idx = advance_index(f->depth, wr_idx, n);
TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx);
@@ -477,7 +586,7 @@ static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
- memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size);
+ memcpy(buf, f->buffer + rd_ptr, 1);
return true;
}
@@ -512,7 +621,7 @@ bool tu_fifo_write(tu_fifo_t *f, const void *data) {
ret = false;
} else {
const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
- memcpy(f->buffer + (wr_ptr * f->item_size), data, f->item_size);
+ memcpy(f->buffer + wr_ptr, data, 1);
f->wr_idx = advance_index(f->depth, wr_idx, 1);
ret = true;
}
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
index 2e2a0db6f..86ba59059 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -32,6 +32,25 @@
extern "C" {
#endif
+#include "common/tusb_common.h"
+#include "osal/osal.h"
+
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+// mutex is only needed for RTOS. For OS None, we don't get preempted
+#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED
+
+#define CFG_TUSB_FIFO_HWFIFO_API (CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO)
+
+#ifndef CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 0
+#endif
+
+#ifndef CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
+#endif
+
// Due to the use of unmasked pointers, this FIFO does not suffer from losing
// one item slice. Furthermore, write and read operations are completely
// decoupled as write and read functions do not modify a common state. Henceforth,
@@ -41,17 +60,6 @@ extern "C" {
// read pointers can be updated from within a DMA ISR. Overflows are detectable
// within a certain number (see tu_fifo_overflow()).
-#include "common/tusb_common.h"
-#include "osal/osal.h"
-
-// mutex is only needed for RTOS
-// for OS None, we don't get preempted
-#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED
-
-#if CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO
- #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
-#endif
-
/* Write/Read "pointer" is in the range of: 0 .. depth - 1, and is used to get the fifo data.
* Write/Read "index" is always in the range of: 0 .. 2*depth-1
*
@@ -111,20 +119,16 @@ extern "C" {
typedef struct {
uint8_t *buffer; // buffer pointer
uint16_t depth; // max items
+ bool overwritable; // overwritable when full
+ // 1 byte padding here
- struct TU_ATTR_PACKED {
- uint16_t item_size : 15; // size of each item
- bool overwritable : 1; // ovwerwritable when full
- };
-
- volatile uint16_t wr_idx; // write index
+ volatile uint16_t wr_idx; // write index TODO maybe can drop volatile
volatile uint16_t rd_idx; // read index
#if OSAL_MUTEX_REQUIRED
osal_mutex_t mutex_wr;
osal_mutex_t mutex_rd;
#endif
-
} tu_fifo_t;
typedef struct {
@@ -134,29 +138,32 @@ typedef struct {
} linear, wrapped;
} tu_fifo_buffer_info_t;
-#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \
- { \
- .buffer = _buffer, \
- .depth = _depth, \
- .item_size = sizeof(_type), \
- .overwritable = _overwritable, \
+// Access mode for hardware fifo read/write
+typedef struct {
+ uint8_t data_stride;
+ uintptr_t param;
+} tu_hwfifo_access_t;
+
+#define TU_FIFO_INIT(_buffer, _depth, _overwritable) \
+ { \
+ .buffer = _buffer, \
+ .depth = _depth, \
+ .overwritable = _overwritable, \
}
-#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable)
+#define TU_FIFO_DEF(_name, _depth, _overwritable) \
+ uint8_t _name##_buf[_depth]; \
+ tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _overwritable)
-// Write modes intended to allow special read and write functions to be able to
-// copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others
-typedef enum {
- TU_FIFO_INC_ADDR_RW8, // increased address read/write by bytes - normal (default) mode
- TU_FIFO_FIXED_ADDR_RW32, // fixed address read/write by 4 bytes (word). Used for STM32 access into USB hardware FIFO
-} tu_fifo_access_mode_t;
+// Moving data from tusb_fifo <-> USB hardware FIFOs e.g. STM32s need to use a special stride mode which reads/writes
+// data in 2/4 byte chunks from/to a fixed address (USB FIFO register) instead of incrementing the address. For this use
+// read/write access_mode with stride_mode = true. The STRIDE DATA and ADDR stride must be configured with
+// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
//--------------------------------------------------------------------+
// Setup API
//--------------------------------------------------------------------+
-bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable);
+bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable);
void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
void tu_fifo_clear(tu_fifo_t *f);
@@ -191,7 +198,7 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
// peek() will correct/re-index read pointer in case of an overflowed fifo to form a full fifo
//--------------------------------------------------------------------+
uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx,
- tu_fifo_access_mode_t access_mode);
+ const tu_hwfifo_access_t *access_mode);
bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer);
uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n);
@@ -199,10 +206,10 @@ uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n);
// Read API
// peek() + advance read index
//--------------------------------------------------------------------+
-uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode);
+uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_t *access_mode);
bool tu_fifo_read(tu_fifo_t *f, void *buffer);
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n) {
- return tu_fifo_read_n_access_mode(f, buffer, n, TU_FIFO_INC_ADDR_RW8);
+ return tu_fifo_read_n_access_mode(f, buffer, n, NULL);
}
// discard first n items from fifo i.e advance read pointer by n with mutex
@@ -212,12 +219,41 @@ uint16_t tu_fifo_discard_n(tu_fifo_t *f, uint16_t n);
//--------------------------------------------------------------------+
// Write API
//--------------------------------------------------------------------+
-uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode);
+uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, const tu_hwfifo_access_t *access_mode);
bool tu_fifo_write(tu_fifo_t *f, const void *data);
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n) {
- return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_INC_ADDR_RW8);
+ return tu_fifo_write_n_access_mode(f, data, n, NULL);
+}
+
+//--------------------------------------------------------------------+
+// Hardware FIFO API
+// Special hardware FIFO/Buffer to hold USB data, usually requires certain access method these can be configured with
+// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (data width) and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE (address increment)
+// Note: these usually has opposite direction (read/write) to/from our software FIFO (tu_fifo_t)
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_write_from_fifo(volatile void *hwfifo, tu_fifo_t *f, uint16_t n,
+ const tu_hwfifo_access_t *access_mode) {
+ const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0};
+ return tu_fifo_read_n_access_mode(f, (void *)(uintptr_t)hwfifo, n,
+ (access_mode != NULL) ? access_mode : &default_access);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_read_to_fifo(const volatile void *hwfifo, tu_fifo_t *f,
+ uint16_t n, const tu_hwfifo_access_t *access_mode) {
+ const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0};
+ return tu_fifo_write_n_access_mode(f, (const void *)(uintptr_t)hwfifo, n,
+ (access_mode != NULL) ? access_mode : &default_access);
}
+#if CFG_TUSB_FIFO_HWFIFO_API
+// read from hwfifo to buffer
+void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode);
+
+// write to hwfifo from buffer with access mode
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode);
+
+#endif
+
//--------------------------------------------------------------------+
// Internal Helper Local
// work on local copies of read/write indices in order to only access them once for re-entrancy
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 1e773bf96..1a4e517b7 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -111,6 +111,14 @@
#define TUP_DCD_ENDPOINT_MAX 16
+#elif TU_CHECK_MCU(OPT_MCU_RW61X)
+ // USB0 is chipidea HS
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
+
#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX)
#include "fsl_device_registers.h"
@@ -176,10 +184,15 @@
//--------------------------------------------------------------------+
// ST
//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
#elif TU_CHECK_MCU(OPT_MCU_STM32F0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
#elif TU_CHECK_MCU(OPT_MCU_STM32F1)
// - F102, F103 use fsdev
@@ -195,7 +208,7 @@
defined(STM32F103xE) || defined(STM32F103xG)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#else
#error "Unsupported STM32F1 mcu"
#endif
@@ -210,7 +223,16 @@
#elif TU_CHECK_MCU(OPT_MCU_STM32F3)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+
+ #if defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
+ #elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+ #else
+ #error "Unsupported STM32F3 mcu"
+ #endif
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
#define TUP_USBIP_DWC2
@@ -236,49 +258,63 @@
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
+ // Device controller
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+
+ // TypeC controller
+ #define TUP_USBIP_TYPEC_STM32
+ #define TUP_TYPEC_RHPORTS_NUM 1
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
- #include "stm32h7xx.h"
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
#define TUP_DCD_ENDPOINT_MAX 9
- #if __CORTEX_M == 7
+ #ifndef CORE_CM4
// Enable dcache if DMA is enabled
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
-#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
- // Device controller
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
+ // FS has 6, HS has 9
+ #define TUP_DCD_ENDPOINT_MAX 9
- // TypeC controller
- #define TUP_USBIP_TYPEC_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_TYPEC_RHPORTS_NUM 1
+ // MCU with on-chip HS Phy
+ #define TUP_RHPORT_HIGHSPEED 1
-#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ // Enable dcache if DMA is enabled
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
-#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
-#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L1)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
// - L4x2, L4x3 use fsdev
@@ -295,28 +331,32 @@
defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
#else
#error "Unsupported STM32L4 mcu"
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE (1024u)
-#elif TU_CHECK_MCU(OPT_MCU_STM32WBA)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_STM32
- #define TUP_DCD_ENDPOINT_MAX 9
- #define TUP_RHPORT_HIGHSPEED 1
+#elif TU_CHECK_MCU(OPT_MCU_STM32U0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32U3)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
+ // U535/545 use fsdev
#if defined(STM32U535xx) || defined(STM32U545xx)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
#else
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
@@ -331,35 +371,16 @@
#endif
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32U0)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32U3)
+#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
-#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6)
+#elif TU_CHECK_MCU(OPT_MCU_STM32WBA)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
-
- // FS has 6, HS has 9
- #define TUP_DCD_ENDPOINT_MAX 9
-
- // MCU with on-chip HS Phy
- #define TUP_RHPORT_HIGHSPEED 1
-
- // Enable dcache if DMA is enabled
- #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_RHPORT_HIGHSPEED 1
//--------------------------------------------------------------------+
// Sony
@@ -415,10 +436,6 @@
#define TUP_MCU_MULTIPLE_CORE 1
#endif
- // Disable slave if DMA is enabled
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
-
#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_ESP32
@@ -431,10 +448,6 @@
#define TUP_MCU_MULTIPLE_CORE 1
- // Disable slave if DMA is enabled
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
-
// Enable dcache if DMA is enabled
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
@@ -566,6 +579,7 @@
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_CH32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
// default to FSDEV for device
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
@@ -611,15 +625,10 @@
//--------------------------------------------------------------------+
// ArteryTek
//--------------------------------------------------------------------+
-#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407)
+#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407, OPT_MCU_AT32F413)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_AT32F413)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#elif TU_CHECK_MCU(OPT_MCU_AT32F415)
#define TUP_USBIP_DWC2
@@ -653,12 +662,21 @@
#define TUP_USBIP_DWC2_AT32
#define TUP_DCD_ENDPOINT_MAX 8
-#endif
-
//--------------------------------------------------------------------+
-// External USB controller
+// HPMicro
//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_HPM)
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define TU_ATTR_FAST_FUNC __attribute__((section(".fast")))
+
+#endif
+
+// External USB controller
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
#ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL
#define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4 * (CFG_TUH_DEVICE_MAX - 1))
@@ -670,6 +688,10 @@
// Default Values
//--------------------------------------------------------------------+
+#if defined(TUP_USBIP_FSDEV)
+ #define TUP_DCD_ENDPOINT_MAX 8
+#endif
+
#ifndef TUP_MCU_MULTIPLE_CORE
#define TUP_MCU_MULTIPLE_CORE 0
#endif
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 587554e7f..c9e06361c 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -96,10 +96,12 @@
* - TU_VERIFY_1ARGS : return false if failed
* - TU_VERIFY_2ARGS : return provided value if failed
*------------------------------------------------------------------*/
-#define TU_VERIFY_DEFINE(_cond, _ret) \
- do { \
- if (!(_cond)) { return _ret; } \
- } while(0)
+#define TU_VERIFY_DEFINE(_cond, _ret) \
+ do { \
+ if (!(_cond)) { \
+ return _ret; \
+ } \
+ } while (0)
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false)
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret)
diff --git a/src/device/usbd.c b/src/device/usbd.c
index e337a5000..1e21c667a 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -580,6 +580,8 @@ bool tud_deinit(uint8_t rhport) {
TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport);
+ const uint8_t cfg_num = _usbd_dev.cfg_num;
+
// Deinit device controller driver
dcd_int_disable(rhport);
dcd_disconnect(rhport);
@@ -594,6 +596,10 @@ bool tud_deinit(uint8_t rhport) {
}
}
+ // Clear device data
+ tu_varclr(&_usbd_dev);
+ usbd_control_reset();
+
// Deinit device queue & task
osal_queue_delete(_usbd_q);
_usbd_q = NULL;
@@ -605,6 +611,11 @@ bool tud_deinit(uint8_t rhport) {
#endif
_usbd_rhport = RHPORT_INVALID;
+
+ if (cfg_num > 0) {
+ tud_umount_cb();
+ }
+
return true;
}
diff --git a/src/device/usbd.h b/src/device/usbd.h
index efde9377f..bd5a3c395 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -58,6 +58,7 @@ typedef union {
bool tud_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
// New API to replace tud_init() to init device stack on specific roothub port
+// Must be called in the same task/context as tud_task() if RTOS is used
bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init);
// Init device stack on roothub port
@@ -73,6 +74,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_init (uint8_t rhport) {
}
// Deinit device stack on roothub port
+// Must be called in the same task/context as tud_task() if RTOS is used
bool tud_deinit(uint8_t rhport);
// Check if device stack is already initialized
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 5b14a15cb..a725b7c8b 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -312,7 +312,8 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_class_driver_t const *get_driver(uint8_
// Function Inline and Prototypes
//--------------------------------------------------------------------+
static bool enum_new_device(hcd_event_t* event);
-static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
+static void process_remove_event(hcd_event_t *event);
+static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
@@ -540,8 +541,8 @@ bool tuh_deinit(uint8_t rhport) {
hcd_deinit(rhport);
_usbh_data.controller_id = TUSB_INDEX_INVALID_8;
- // "unplug" all devices on this rhport (hub_addr = 0, hub_port = 0)
- process_removed_device(rhport, 0, 0);
+ // remove all devices on this rhport (hub_addr = 0, hub_port = 0)
+ remove_device_tree(rhport, 0, 0);
// deinit host stack if no controller is active
if (!tuh_inited()) {
@@ -605,6 +606,11 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
switch (event.event_id) {
case HCD_EVENT_DEVICE_ATTACH:
+ // Should we miss the hub detach event due to high traffic, Or due to physical debouncing, some devices can
+ // cause multiple attaches (actually reset) without detach event.
+ // Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists
+ process_remove_event(&event);
+
// due to the shared control buffer, we must fully complete enumerating one device first.
// TODO better to have an separated queue for newly attached devices
if (_usbh_data.enumerating_daddr == TUSB_INDEX_INVALID_8) {
@@ -625,15 +631,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
case HCD_EVENT_DEVICE_REMOVE:
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
- if (_usbh_data.enumerating_daddr == 0 &&
- event.rhport == _usbh_data.dev0_bus.rhport &&
- event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr &&
- event.connection.hub_port == _usbh_data.dev0_bus.hub_port) {
- // dev0 is unplugged while enumerating (not yet assigned an address)
- usbh_device_close(_usbh_data.dev0_bus.rhport, 0);
- } else {
- process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
- }
+ process_remove_event(&event);
break;
case HCD_EVENT_XFER_COMPLETE: {
@@ -1321,8 +1319,22 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
//--------------------------------------------------------------------+
// Detaching
//--------------------------------------------------------------------+
-// a device unplugged from rhport:hub_addr:hub_port
-static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
+
+// process detach event from rhport:hub_addr:hub_port
+static void process_remove_event(hcd_event_t *event) {
+ if (_usbh_data.enumerating_daddr == 0 &&
+ event->rhport == _usbh_data.dev0_bus.rhport &&
+ event->connection.hub_addr == _usbh_data.dev0_bus.hub_addr &&
+ event->connection.hub_port == _usbh_data.dev0_bus.hub_port) {
+ // dev0 is unplugged while enumerating (not yet assigned an address)
+ usbh_device_close(_usbh_data.dev0_bus.rhport, 0);
+ } else {
+ remove_device_tree(event->rhport, event->connection.hub_addr, event->connection.hub_port);
+ }
+}
+
+// remove a device at rhport:hub_addr:hub_port and all of its downstream
+static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
// Find the all devices (star-network) under port that is unplugged
#if CFG_TUH_HUB
uint8_t removing_hubs[CFG_TUH_HUB] = { 0 };
@@ -1393,12 +1405,13 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub
// NOTE: due to the shared control buffer, we must complete enumerating
// one device before enumerating another one.
//--------------------------------------------------------------------+
-enum { // USB 2.0 specs 7.1.7 for timing
- ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
- ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
- ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
- ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
- ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
+enum { // USB 2.0 specs 7.1.7 for timing
+ ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
+ ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
+ ENUM_RESET_ROOT_POST_DELAY_MS = 2, // 2 ms delay after root port reset before getting speed/status
+ ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
+ ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
+ ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
};
enum {
@@ -1427,7 +1440,7 @@ enum {
static uint8_t enum_get_new_address(bool is_hub);
static bool enum_parse_configuration_desc (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
-static void enum_full_complete(void);
+static void enum_full_complete(bool success);
static void process_enumeration(tuh_xfer_t* xfer);
// start a new enumeration process
@@ -1449,7 +1462,7 @@ static bool enum_new_device(hcd_event_t* event) {
if (!hcd_port_connect_status(dev0_bus->rhport)) {
TU_LOG_USBH("Device unplugged while debouncing\r\n");
- enum_full_complete();
+ enum_full_complete(false);
return true;
}
@@ -1457,10 +1470,11 @@ static bool enum_new_device(hcd_event_t* event) {
hcd_port_reset(dev0_bus->rhport);
tusb_time_delay_ms_api(ENUM_RESET_ROOT_DELAY_MS);
hcd_port_reset_end(dev0_bus->rhport);
+ tusb_time_delay_ms_api(ENUM_RESET_ROOT_POST_DELAY_MS);
if (!hcd_port_connect_status(dev0_bus->rhport)) {
// device unplugged while delaying
- enum_full_complete();
+ enum_full_complete(false);
return true;
}
@@ -1506,7 +1520,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}
if (!retry) {
- enum_full_complete(); // complete as failed
+ enum_full_complete(false); // complete as failed
}
return;
}
@@ -1529,7 +1543,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
if (0 == port_status.status.connection) {
TU_LOG_USBH("Device unplugged from hub while debouncing\r\n");
- enum_full_complete();
+ enum_full_complete(false);
return;
}
@@ -1566,7 +1580,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
if (0 == port_status.status.connection) {
TU_LOG_USBH("Device unplugged from hub (not addressed yet)\r\n");
- enum_full_complete();
+ enum_full_complete(false);
return;
}
@@ -1582,7 +1596,11 @@ static void process_enumeration(tuh_xfer_t* xfer) {
// TODO probably doesn't need to open/close each enumeration
uint8_t const addr0 = 0;
- TU_ASSERT(usbh_edpt_control_open(addr0, 8),);
+ if (!usbh_edpt_control_open(addr0, 8)) {
+ // Stop enumeration gracefully
+ enum_full_complete(false);
+ TU_ASSERT(false,);
+ }
// Get first 8 bytes of device descriptor for control endpoint size
TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n");
@@ -1592,10 +1610,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}
case ENUM_SET_ADDR: {
- // Due to physical debouncing, some devices can cause multiple attaches (actually reset) without detach event
- // Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists
- process_removed_device(dev0_bus->rhport, dev0_bus->hub_addr, dev0_bus->hub_port);
-
const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl;
const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
TU_ASSERT(new_addr != 0,);
@@ -1620,7 +1634,12 @@ static void process_enumeration(tuh_xfer_t* xfer) {
usbh_device_close(dev0_bus->rhport, 0); // close dev0
- TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0),); // open new control endpoint
+ if (!usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0)) { // open new control endpoint
+ // Stop enumeration gracefully
+ clear_device(new_dev);
+ enum_full_complete(false);
+ TU_ASSERT(false,);
+ }
TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
@@ -1774,6 +1793,12 @@ static void process_enumeration(tuh_xfer_t* xfer) {
TU_LOG_USBH("Device configured\r\n");
dev->configured = 1;
+ #if CFG_TUH_HUB
+ if (_usbh_data.dev0_bus.hub_addr != 0) {
+ hub_edpt_status_xfer(_usbh_data.dev0_bus.hub_addr); // get next hub status
+ }
+ #endif
+
// Parse configuration & set up drivers
// driver_open() must not make any usb transfer
TU_ASSERT(enum_parse_configuration_desc(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),);
@@ -1787,7 +1812,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}
default:
- enum_full_complete(); // stop enumeration if unknown state
+ enum_full_complete(false); // stop enumeration if unknown state
break;
}
}
@@ -1890,7 +1915,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
// all interface are configured
if (itf_num == CFG_TUH_INTERFACE_MAX) {
- enum_full_complete();
+ enum_full_complete(true);
if (is_hub_addr(dev_addr)) {
TU_LOG_USBH("HUB address = %u is mounted\r\n", dev_addr);
@@ -1901,12 +1926,14 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
}
}
-static void enum_full_complete(void) {
+static void enum_full_complete(bool success) {
+ (void)success;
// mark enumeration as complete
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
#if CFG_TUH_HUB
- if (_usbh_data.dev0_bus.hub_addr != 0) {
+ // Hub status is already requested in case of successful enumeration
+ if (_usbh_data.dev0_bus.hub_addr != 0 && !success) {
hub_edpt_status_xfer(_usbh_data.dev0_bus.hub_addr); // get next hub status
}
#endif
diff --git a/src/host/usbh.h b/src/host/usbh.h
index 4b6747848..d86efbcb2 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -95,18 +95,23 @@ enum {
TUH_CFGID_INVALID = 0,
TUH_CFGID_RPI_PIO_USB_CONFIGURATION = 100, // cfg_param: pio_usb_configuration_t
TUH_CFGID_MAX3421 = 200,
+ TUH_CFGID_FSDEV = 300,
};
typedef struct {
- uint8_t max_nak; // max NAK per endpoint per frame to save CPU/SPI bus usage
+ uint8_t max_nak; // max NAK per endpoint per frame to save CPU/SPI bus usage (0=unlimited)
uint8_t cpuctl; // R16: CPU Control Register
uint8_t pinctl; // R17: Pin Control Register. FDUPSPI bit is ignored
} tuh_configure_max3421_t;
+typedef struct {
+ uint8_t max_nak; // max NAK per endpoint per frame to save CPU usage (0=unlimited)
+} tuh_configure_fsdev_t;
+
typedef union {
// For TUH_CFGID_RPI_PIO_USB_CONFIGURATION use pio_usb_configuration_t
-
tuh_configure_max3421_t max3421;
+ tuh_configure_fsdev_t fsdev;
} tuh_configure_param_t;
//--------------------------------------------------------------------+
@@ -145,6 +150,7 @@ void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
// New API to replace tuh_init() to init host stack on specific roothub port
+// Must be called in the same task/context as tuh_task() if RTOS is used
bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init);
// Init host stack
@@ -160,6 +166,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_init(uint8_t rhport) {
}
// Deinit host stack on rhport
+// Must be called in the same task/context as tuh_task() if RTOS is used
bool tuh_deinit(uint8_t rhport);
// Check if host stack is already initialized with any roothub ports
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index 174136e38..6ab18ace8 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -157,21 +157,21 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
typedef struct {
void (* interrupt_set)(bool enabled);
+ uint16_t item_size;
tu_fifo_t ff;
} osal_queue_def_t;
typedef osal_queue_def_t* osal_queue_t;
// _int_set is used as mutex in OS NONE (disable/enable USB ISR)
-#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- osal_queue_def_t _name = { \
- .interrupt_set = _int_set, \
- .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
- }
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+ uint8_t _name##_buf[_depth * sizeof(_type)]; \
+ osal_queue_def_t _name = {.interrupt_set = _int_set, \
+ .item_size = sizeof(_type), \
+ .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
- (void) tu_fifo_clear(&qdef->ff);
+ tu_fifo_clear(&qdef->ff);
return (osal_queue_t) qdef;
}
@@ -184,7 +184,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
(void) msec; // not used, always behave as msec = 0
qhdl->interrupt_set(false);
- const bool success = tu_fifo_read(&qhdl->ff, data);
+ const bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size);
qhdl->interrupt_set(true);
return success;
@@ -195,7 +195,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void
qhdl->interrupt_set(false);
}
- const bool success = tu_fifo_write(&qhdl->ff, data);
+ const bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size);
if (!in_isr) {
qhdl->interrupt_set(true);
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
index f5385071a..79b728e9a 100644
--- a/src/osal/osal_pico.h
+++ b/src/osal/osal_pico.h
@@ -47,40 +47,39 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
// Spinlock API
//--------------------------------------------------------------------+
typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock
-#define OSAL_SPINLOCK_DEF(_name, _int_set) \
- osal_spinlock_t _name
+#define OSAL_SPINLOCK_DEF(_name, _int_set) osal_spinlock_t _name
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
critical_section_init(ctx);
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
critical_section_enter_blocking(ctx);
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
critical_section_exit(ctx);
}
//--------------------------------------------------------------------+
// Binary Semaphore API
//--------------------------------------------------------------------+
-typedef struct semaphore osal_semaphore_def_t, * osal_semaphore_t;
+typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) {
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
sem_init(semdef, 0, 255);
return semdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
- (void) semd_hdl;
+ (void)semd_hdl;
return true; // nothing to do
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
return sem_release(sem_hdl);
}
@@ -96,15 +95,15 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s
// MUTEX API
// Within tinyusb, mutex is never used in ISR context
//--------------------------------------------------------------------+
-typedef struct mutex osal_mutex_def_t, * osal_mutex_t;
+typedef struct mutex osal_mutex_def_t, *osal_mutex_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) {
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
mutex_init(mdef);
return mdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
- (void) mutex_hdl;
+ (void)mutex_hdl;
return true; // nothing to do
}
@@ -123,46 +122,45 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
#include "common/tusb_fifo.h"
typedef struct {
- tu_fifo_t ff;
+ uint16_t item_size;
+ tu_fifo_t ff;
struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section
} osal_queue_def_t;
-typedef osal_queue_def_t* osal_queue_t;
+typedef osal_queue_def_t *osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- osal_queue_def_t _name = { \
- .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
- }
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+ uint8_t _name##_buf[_depth * sizeof(_type)]; \
+ osal_queue_def_t _name = {.item_size = sizeof(_type), .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
-TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) {
critical_section_init(&qdef->critsec);
- (void) tu_fifo_clear(&qdef->ff);
- return (osal_queue_t) qdef;
+ tu_fifo_clear(&qdef->ff);
+ return (osal_queue_t)qdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
- osal_queue_def_t* qdef = (osal_queue_def_t*) qhdl;
+ osal_queue_def_t *qdef = (osal_queue_def_t *)qhdl;
critical_section_deinit(&qdef->critsec);
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
- (void) msec; // not used, always behave as msec = 0
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) {
+ (void)msec; // not used, always behave as msec = 0
critical_section_enter_blocking(&qhdl->critsec);
- bool success = tu_fifo_read(&qhdl->ff, data);
+ bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size);
critical_section_exit(&qhdl->critsec);
return success;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) {
- (void) in_isr;
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, const void *data, bool in_isr) {
+ (void)in_isr;
critical_section_enter_blocking(&qhdl->critsec);
- bool success = tu_fifo_write(&qhdl->ff, data);
+ bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size);
critical_section_exit(&qhdl->critsec);
return success;
diff --git a/src/portable/chipidea/ci_hs/ci_hs_hpm.h b/src/portable/chipidea/ci_hs/ci_hs_hpm.h
new file mode 100644
index 000000000..68211448c
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_hpm.h
@@ -0,0 +1,54 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_HPM_H_
+#define _CI_HS_HPM_H_
+
+#include "ci_hs_type.h"
+#include "hpm_soc.h"
+#include "hpm_interrupt.h"
+#include "hpm_usb_drv.h"
+
+static const ci_hs_controller_t _ci_controller[] =
+{
+ { .reg_base = HPM_USB0_BASE, .irqnum = IRQn_USB0},
+ #ifdef HPM_USB1_BASE
+ { .reg_base = HPM_USB1_BASE, .irqnum = IRQn_USB1},
+ #endif
+};
+
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+//------------- DCD -------------//
+#define CI_DCD_INT_ENABLE(_p) intc_m_enable_irq (_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) intc_m_disable_irq(_ci_controller[_p].irqnum)
+
+//------------- HCD -------------//
+#define CI_HCD_INT_ENABLE(_p) intc_m_enable_irq (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) intc_m_disable_irq(_ci_controller[_p].irqnum)
+
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_rw61x.h b/src/portable/chipidea/ci_hs/ci_hs_rw61x.h
new file mode 100644
index 000000000..114fe26c3
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_rw61x.h
@@ -0,0 +1,48 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_RW61X_H_
+#define _CI_HS_RW61X_H_
+
+#include "fsl_device_registers.h"
+
+static const ci_hs_controller_t _ci_controller[] = {
+ {.reg_base = USBOTG_BASE, .irqnum = USB_IRQn}
+};
+
+TU_ATTR_ALWAYS_INLINE static inline ci_hs_regs_t* CI_HS_REG(uint8_t port) {
+ (void) port;
+ return ((ci_hs_regs_t*) _ci_controller[0].reg_base);
+}
+
+#define CI_DCD_INT_ENABLE(_p) do { (void) _p; NVIC_EnableIRQ (_ci_controller[0].irqnum); } while (0)
+#define CI_DCD_INT_DISABLE(_p) do { (void) _p; NVIC_DisableIRQ(_ci_controller[0].irqnum); } while (0)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
index 4a5e5c91f..2bba32ada 100644
--- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -34,19 +34,19 @@
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
#include "ci_hs_imxrt.h"
-#if CFG_TUD_MEM_DCACHE_ENABLE
-bool dcd_dcache_clean(void const* addr, uint32_t data_size) {
- return imxrt_dcache_clean(addr, data_size);
-}
+ #if CFG_TUD_MEM_DCACHE_ENABLE
+ bool dcd_dcache_clean(const void *addr, uint32_t data_size) {
+ return imxrt_dcache_clean(addr, data_size);
+ }
-bool dcd_dcache_invalidate(void const* addr, uint32_t data_size) {
- return imxrt_dcache_invalidate(addr, data_size);
-}
+ bool dcd_dcache_invalidate(const void *addr, uint32_t data_size) {
+ return imxrt_dcache_invalidate(addr, data_size);
+ }
-bool dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
- return imxrt_dcache_clean_invalidate(addr, data_size);
-}
-#endif
+ bool dcd_dcache_clean_invalidate(const void *addr, uint32_t data_size) {
+ return imxrt_dcache_clean_invalidate(addr, data_size);
+ }
+ #endif
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
#include "ci_hs_lpc18_43.h"
@@ -55,6 +55,12 @@ bool dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
// MCX N9 only port 1 use this controller
#include "ci_hs_mcx.h"
+#elif TU_CHECK_MCU(OPT_MCU_HPM)
+ #include "ci_hs_hpm.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_RW61X)
+ #include "ci_hs_rw61x.h"
+
#else
#error "Unsupported MCUs"
#endif
@@ -76,7 +82,7 @@ enum {
};
#define ENDPTCTRL_TYPE(_type) ((_type) << ENDPTCTRL_TYPE_POS)
- #define ENDPTCTRL_RESET_MASK (ENDPTCTRL_TYPE(TUSB_XFER_BULK) | (ENDPTCTRL_TYPE(TUSB_XFER_BULK) << 16u))
+#define ENDPTCTRL_RESET_MASK (ENDPTCTRL_TYPE(TUSB_XFER_BULK) | (ENDPTCTRL_TYPE(TUSB_XFER_BULK) << 16u))
// USBSTS, USBINTR
enum {
@@ -90,26 +96,28 @@ enum {
};
// Queue Transfer Descriptor
-typedef struct
-{
+typedef struct {
// Word 0: Next QTD Pointer
uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed
// Word 1: qTQ Token
- uint32_t : 3 ;
- volatile uint32_t xact_err : 1 ;
- uint32_t : 1 ;
- volatile uint32_t buffer_err : 1 ;
- volatile uint32_t halted : 1 ;
- volatile uint32_t active : 1 ;
- uint32_t : 2 ;
- uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO.
- uint32_t : 3 ;
- uint32_t int_on_complete : 1 ;
- volatile uint32_t total_bytes : 15 ;
- uint32_t : 1 ;
+ uint32_t : 3;
+ volatile uint32_t xact_err : 1;
+ uint32_t : 1;
+ volatile uint32_t buffer_err : 1;
+ volatile uint32_t halted : 1;
+ volatile uint32_t active : 1;
+ uint32_t : 2;
+ uint32_t iso_mult_override : 2; ///< This field can be used for transmit ISOs to override the MULT field in the dQH.
+ ///< This field must be zero for all packet types that are not transmit-ISO.
+ uint32_t : 3;
+ uint32_t int_on_complete : 1;
+ volatile uint32_t total_bytes : 15;
+ uint32_t : 1;
- // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
+ // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The
+ // lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the
+ // start of a 4K page
uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous
//--------------------------------------------------------------------+
@@ -117,21 +125,28 @@ typedef struct
// Therefore there are 4 bytes padding that we can use.
//--------------------------------------------------------------------+
uint16_t expected_bytes;
- uint8_t reserved[2];
+ uint8_t reserved[2];
} dcd_qtd_t;
-TU_VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct");
+TU_VERIFY_STATIC(sizeof(dcd_qtd_t) == 32, "size is not correct");
// Queue Head
-typedef struct
-{
+typedef struct {
// Word 0: Capabilities and Characteristics
- uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
- uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received.
- uint32_t max_packet_size : 11 ; ///< Endpoint's wMaxPacketSize
- uint32_t : 2 ;
- uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length.
- uint32_t iso_mult : 2 ; ///<
+ uint32_t : 15; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated
+ ///< by the USB variable length protocol where N is computed using Max_packet_length and the
+ ///< Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 -
+ ///< Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark:
+ ///< Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
+ uint32_t int_on_setup : 1; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is
+ ///< set in response to a setup being received.
+ uint32_t max_packet_size : 11; ///< Endpoint's wMaxPacketSize
+ uint32_t : 2;
+ uint32_t zero_length_termination : 1; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to
+ ///< terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to
+ ///< terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on
+ ///< transfers that are equal in length to a multiple Max_packet_length.
+ uint32_t iso_mult : 2; ///<
// Word 1: Current qTD Pointer
volatile uint32_t qtd_addr;
@@ -146,11 +161,11 @@ typedef struct
// QHD is 64 bytes aligned but occupies only 48 bytes
// Therefore there are 16 bytes padding that we can use.
//--------------------------------------------------------------------+
- tu_fifo_t * ff;
- uint8_t reserved[12];
+ tu_fifo_t *ff;
+ uint8_t reserved[12];
} dcd_qhd_t;
-TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
+TU_VERIFY_STATIC(sizeof(dcd_qhd_t) == 64, "size is not correct");
//--------------------------------------------------------------------+
// Variables
@@ -164,10 +179,9 @@ typedef struct {
// for portability, TinyUSB only queue 1 TD for each Qhd
dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
-}dcd_data_t;
+} dcd_data_t;
-CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048)
-static dcd_data_t _dcd_data;
+CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048) static dcd_data_t _dcd_data;
//--------------------------------------------------------------------+
// Prototypes and Helper Functions
@@ -182,16 +196,15 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t ci_ep_count(const ci_hs_regs_t *dcd_
//--------------------------------------------------------------------+
/// follows LPC43xx User Manual 23.10.3
-static void bus_reset(uint8_t rhport)
-{
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+static void bus_reset(uint8_t rhport) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
// The reset value for all endpoint types is the control endpoint. If one endpoint
// direction is enabled and the paired endpoint of opposite direction is disabled, then the
// endpoint type of the unused direction must be changed from the control type to any other
// type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
// for the data PID tracking on the active endpoint.
- uint8_t const ep_count = ci_ep_count(dcd_reg);
+ const uint8_t ep_count = ci_ep_count(dcd_reg);
for (uint8_t i = 1; i < ep_count; i++) {
dcd_reg->ENDPTCTRL[i] = ENDPTCTRL_RESET_MASK;
}
@@ -214,7 +227,7 @@ static void bus_reset(uint8_t rhport)
//------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
_dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1;
- _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
+ _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
_dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID;
_dcd_data.qhd[0][0].int_on_setup = 1; // OUT only
@@ -222,92 +235,93 @@ static void bus_reset(uint8_t rhport)
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
}
-bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
+ (void)rh_init;
tu_memclr(&_dcd_data, sizeof(dcd_data_t));
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX);
+ #if TU_CHECK_MCU(OPT_MCU_HPM)
+ usb_phy_init((USB_Type *)dcd_reg, false);
+ #endif
+
// Reset controller
dcd_reg->USBCMD |= USBCMD_RESET;
- while( dcd_reg->USBCMD & USBCMD_RESET ) {}
+ while (dcd_reg->USBCMD & USBCMD_RESET) {}
// Set mode to device, must be set immediately after reset
uint32_t usbmode = dcd_reg->USBMODE & ~USBMOD_CM_MASK;
usbmode |= USBMODE_CM_DEVICE;
dcd_reg->USBMODE = usbmode;
-#ifdef CFG_TUD_CI_HS_VBUS_CHARGE
+ #ifdef CFG_TUD_CI_HS_VBUS_CHARGE
dcd_reg->OTGSC = OTGSC_VBUS_CHARGE | OTGSC_OTG_TERMINATION;
-#else
+ #else
dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
-#endif
+ #endif
-#if !TUD_OPT_HIGH_SPEED
- dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
-#endif
+ #if !TUD_OPT_HIGH_SPEED
+ dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+ #endif
+
+ #if TU_CHECK_MCU(OPT_MCU_HPM)
+ dcd_reg->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
+ #endif
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
- dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment
- dcd_reg->USBSTS = dcd_reg->USBSTS;
- dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND;
+ dcd_reg->ENDPTLISTADDR = (uint32_t)_dcd_data.qhd; // Endpoint List Address has to be 2K alignment
+ dcd_reg->USBSTS = dcd_reg->USBSTS;
+ dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND;
uint32_t usbcmd = dcd_reg->USBCMD;
usbcmd &= ~USBCMD_INTR_THRESHOLD_MASK; // Interrupt Threshold Interval = 0
- usbcmd |= USBCMD_RUN_STOP; // run
+ usbcmd |= USBCMD_RUN_STOP; // run
dcd_reg->USBCMD = usbcmd;
return true;
}
-void dcd_int_enable(uint8_t rhport)
-{
+void dcd_int_enable(uint8_t rhport) {
CI_DCD_INT_ENABLE(rhport);
}
-void dcd_int_disable(uint8_t rhport)
-{
+void dcd_int_disable(uint8_t rhport) {
CI_DCD_INT_DISABLE(rhport);
}
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
// Response with status first before changing device address
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false);
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
- dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
}
-void dcd_remote_wakeup(uint8_t rhport)
-{
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+void dcd_remote_wakeup(uint8_t rhport) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME;
}
-void dcd_connect(uint8_t rhport)
-{
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+void dcd_connect(uint8_t rhport) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
dcd_reg->USBCMD |= USBCMD_RUN_STOP;
}
-void dcd_disconnect(uint8_t rhport)
-{
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+void dcd_disconnect(uint8_t rhport) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
}
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
if (en) {
- dcd_reg->USBINTR |= INTR_SOF;
+ dcd_reg->USBINTR |= INTR_SOF;
} else {
- dcd_reg->USBINTR &= ~INTR_SOF;
+ dcd_reg->USBINTR &= ~INTR_SOF;
}
}
@@ -374,26 +388,24 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_ctrl_clear(volatile uint32_t *epctrl
ep_ctrl_mask(epctrl, dir, ~mask, 0);
}
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
// flush to abort any primed buffer
dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
}
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
// data toggle also need to be reset
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
- dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 );
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << (dir ? 16 : 0);
dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << (dir ? 16 : 0));
}
@@ -471,7 +483,7 @@ void dcd_edpt_close_all(uint8_t rhport) {
ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
// Disable all non-control endpoints
- uint8_t const ep_count = ci_ep_count(dcd_reg);
+ const uint8_t ep_count = ci_ep_count(dcd_reg);
for (uint8_t epnum = 1; epnum < ep_count; epnum++) {
_dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1;
_dcd_data.qhd[epnum][TUSB_DIR_IN].qtd_overlay.halted = 1;
@@ -481,37 +493,34 @@ void dcd_edpt_close_all(uint8_t rhport) {
}
}
-static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
-{
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
- dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
+ dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir];
- p_qhd->qtd_overlay.halted = false; // clear any previous error
- p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
+ p_qhd->qtd_overlay.halted = false; // clear any previous error
+ p_qhd->qtd_overlay.next = (uint32_t)p_qtd; // link qtd to qhd
// flush cache
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
- if ( epnum == 0 )
- {
+ if (epnum == 0) {
// follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
// wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
- while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
+ while (dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
}
// start transfer
dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr)
-{
- (void) is_isr;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
- dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+ dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir];
// Prepare qtd
qtd_init(p_qtd, buffer, total_bytes);
@@ -523,58 +532,47 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
return true;
}
-#if !CFG_TUD_MEM_DCACHE_ENABLE
+ #if !CFG_TUD_MEM_DCACHE_ENABLE
// fifo has to be aligned to 4k boundary
// It's incompatible with dcache enabled transfer, since neither address nor size is aligned to cache line
-bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr)
-{
- (void) is_isr;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
- dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+ dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir];
tu_fifo_buffer_info_t fifo_info;
- if (dir)
- {
+ if (dir) {
tu_fifo_get_read_info(ff, &fifo_info);
- } else
- {
+ } else {
tu_fifo_get_write_info(ff, &fifo_info);
}
- if ( fifo_info.linear.len >= total_bytes )
- {
+ if (fifo_info.linear.len >= total_bytes) {
// Linear length is enough for this transfer
qtd_init(p_qtd, fifo_info.linear.ptr, total_bytes);
- }
- else
- {
+ } else {
// linear part is not enough
// prepare TD up to linear length
qtd_init(p_qtd, fifo_info.linear.ptr, fifo_info.linear.len);
- if ( !tu_offset4k((uint32_t) fifo_info.wrapped.ptr) && !tu_offset4k(tu_fifo_depth(ff)) )
- {
+ if (!tu_offset4k((uint32_t)fifo_info.wrapped.ptr) && !tu_offset4k(tu_fifo_depth(ff))) {
// If buffer is aligned to 4K & buffer size is multiple of 4K
// We can make use of buffer page array to also combine the linear + wrapped length
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
- for(uint8_t i = 1, page = 0; i < 5; i++)
- {
+ for (uint8_t i = 1, page = 0; i < 5; i++) {
// pick up buffer array where linear ends
- if (p_qtd->buffer[i] == 0)
- {
- p_qtd->buffer[i] = (uint32_t) fifo_info.wrapped.ptr + 4096 * page;
+ if (p_qtd->buffer[i] == 0) {
+ p_qtd->buffer[i] = (uint32_t)fifo_info.wrapped.ptr + 4096 * page;
page++;
}
}
- }
- else
- {
+ } else {
// TODO we may need to carry the wrapped length after the linear part complete
// for now only transfer up to linear part
}
@@ -586,36 +584,32 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
return true;
}
-#endif
+ #endif
//--------------------------------------------------------------------+
// ISR
//--------------------------------------------------------------------+
-static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
-{
- dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir) {
+ dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t *p_qtd = &_dcd_data.qtd[epnum][dir];
- uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
- ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS;
+ uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED
+ : (p_qtd->xact_err || p_qtd->buffer_err) ? XFER_RESULT_FAILED
+ : XFER_RESULT_SUCCESS;
- if ( result != XFER_RESULT_SUCCESS )
- {
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ if (result != XFER_RESULT_SUCCESS) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
// flush to abort error buffer
dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
}
- uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
+ const uint16_t xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
- if (p_qhd->ff)
- {
- if (dir == TUSB_DIR_IN)
- {
+ if (p_qhd->ff) {
+ if (dir == TUSB_DIR_IN) {
tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes);
- } else
- {
+ } else {
tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes);
}
}
@@ -624,82 +618,74 @@ static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir
dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true);
}
-void dcd_int_handler(uint8_t rhport)
-{
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+void dcd_int_handler(uint8_t rhport) {
+ ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport);
- uint32_t const int_enable = dcd_reg->USBINTR;
- uint32_t const int_status = dcd_reg->USBSTS & int_enable;
- dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt
+ const uint32_t int_enable = dcd_reg->USBINTR;
+ const uint32_t int_status = dcd_reg->USBSTS & int_enable;
+ dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt
// disabled interrupt sources
- if (int_status == 0) return;
+ if (int_status == 0) {
+ return;
+ }
// Set if the port controller enters the full or high-speed operational state.
// either from Bus Reset or Suspended state
- if (int_status & INTR_PORT_CHANGE)
- {
- // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1);
+ if (int_status & INTR_PORT_CHANGE) {
+ // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1);
- // Reset interrupt is not enabled, we manually check if Port Change is due
- // to connection / disconnection
- if ( dcd_reg->USBSTS & INTR_RESET )
- {
- dcd_reg->USBSTS = INTR_RESET;
+ // Reset interrupt is not enabled, we manually check if Port Change is due
+ // to connection / disconnection
+ if (dcd_reg->USBSTS & INTR_RESET) {
+ dcd_reg->USBSTS = INTR_RESET;
- if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS)
- {
- uint32_t const speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS;
- bus_reset(rhport);
- dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true);
- }else
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
- }
- else
- {
- // Triggered by resuming from suspended state
- if ( !(dcd_reg->PORTSC1 & PORTSC1_SUSPEND) )
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
- }
- }
+ if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) {
+ const uint32_t speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS;
+ bus_reset(rhport);
+ dcd_event_bus_reset(rhport, (tusb_speed_t)speed, true);
+ } else {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+ } else {
+ // Triggered by resuming from suspended state
+ if (!(dcd_reg->PORTSC1 & PORTSC1_SUSPEND)) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ }
+ }
- if (int_status & INTR_SUSPEND)
- {
+ if (int_status & INTR_SUSPEND) {
// TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1);
- if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND)
- {
+ if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND) {
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
// Skip suspend event if we are not addressed
- if ((dcd_reg->DEVICEADDR >> 25) & 0x0f)
- {
+ if ((dcd_reg->DEVICEADDR >> 25) & 0x0f) {
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
}
}
}
- if (int_status & INTR_USB)
- {
+ if (int_status & INTR_USB) {
// Make sure we read the latest version of _dcd_data.
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
- uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
- dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
+ const uint32_t edpt_complete = dcd_reg->ENDPTCOMPLETE;
+ dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
// 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
// nothing to do, we will submit xfer as error to usbd
// if (int_status & INTR_ERROR) { }
- if ( edpt_complete )
- {
- for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++)
- {
- if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
- if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
+ if (edpt_complete) {
+ for (uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++) {
+ if (tu_bit_test(edpt_complete, epnum)) {
+ process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
+ }
+ if (tu_bit_test(edpt_complete, epnum + 16)) {
+ process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
+ }
}
}
@@ -709,12 +695,11 @@ void dcd_int_handler(uint8_t rhport)
// in the same frame and we should handle previous status first.
if (dcd_reg->ENDPTSETUPSTAT) {
dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
- dcd_event_setup_received(rhport, (uint8_t *) (uintptr_t) &_dcd_data.qhd[0][0].setup_request, true);
+ dcd_event_setup_received(rhport, (uint8_t *)(uintptr_t)&_dcd_data.qhd[0][0].setup_request, true);
}
}
- if (int_status & INTR_SOF)
- {
+ if (int_status & INTR_SOF) {
const uint32_t frame = dcd_reg->FRINDEX;
dcd_event_sof(rhport, frame, true);
}
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
index b5324a754..29ce0cd7f 100644
--- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -41,28 +41,36 @@
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
-#include "ci_hs_imxrt.h"
+ #include "ci_hs_imxrt.h"
-#if CFG_TUH_MEM_DCACHE_ENABLE
-bool hcd_dcache_clean(void const* addr, uint32_t data_size) {
+ #if CFG_TUH_MEM_DCACHE_ENABLE
+bool hcd_dcache_clean(const void *addr, uint32_t data_size) {
return imxrt_dcache_clean(addr, data_size);
}
-bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
+bool hcd_dcache_invalidate(const void *addr, uint32_t data_size) {
return imxrt_dcache_invalidate(addr, data_size);
}
-bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
+bool hcd_dcache_clean_invalidate(const void *addr, uint32_t data_size) {
return imxrt_dcache_clean_invalidate(addr, data_size);
}
-#endif
+ #endif
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
-#include "ci_hs_lpc18_43.h"
+ #include "ci_hs_lpc18_43.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_HPM)
+
+ #include "ci_hs_hpm.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_RW61X)
+
+ #include "ci_hs_rw61x.h"
#else
-#error "Unsupported MCUs"
+ #error "Unsupported MCUs"
#endif
//--------------------------------------------------------------------+
@@ -73,27 +81,31 @@ bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
// Controller API
//--------------------------------------------------------------------+
-bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
+ (void)rh_init;
ci_hs_regs_t *hcd_reg = CI_HS_REG(rhport);
+ #if CFG_TUSB_MCU == OPT_MCU_HPM
+ usb_phy_init((USB_Type *)hcd_reg, true);
+ #endif
+
// Reset controller
hcd_reg->USBCMD |= USBCMD_RESET;
- while ( hcd_reg->USBCMD & USBCMD_RESET ) {}
+ while (hcd_reg->USBCMD & USBCMD_RESET) {}
// Set mode to device, must be set immediately after reset
-#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
+ #if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
// LPC18XX/43XX need to set VBUS Power Select to HIGH
// RHPORT1 is fullspeed only (need external PHY for Highspeed)
hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
if (rhport == 1) {
hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
}
-#else
+ #else
hcd_reg->USBMODE = USBMODE_CM_HOST;
-#endif
+ #endif
- return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
+ return ehci_init(rhport, (uint32_t)&hcd_reg->CAPLENGTH, (uint32_t)&hcd_reg->USBCMD);
}
void hcd_int_enable(uint8_t rhport) {
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index c33c970e4..9b2cf98be 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -40,10 +40,14 @@
#include "ehci.h"
// NXP specific fixes
-#if TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX, OPT_MCU_LPC55, OPT_MCU_MCXN9)
+#if TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX, OPT_MCU_LPC55, OPT_MCU_MCXN9, OPT_MCU_RW61X)
#include "fsl_device_registers.h"
#endif
+#if TU_CHECK_MCU(OPT_MCU_HPM)
+#include "ci_hs_hpm.h"
+#endif
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
@@ -237,6 +241,14 @@ void hcd_port_reset(uint8_t rhport) {
// mask out Write-1-to-Clear bits
uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
+#if TU_CHECK_MCU(OPT_MCU_HPM)
+ if (usb_phy_get_line_state((USB_Type *)CI_HS_REG(rhport)) == usb_line_state2) {
+ portsc |= USB_PORTSC1_STS_MASK;
+ } else {
+ portsc &= ~USB_PORTSC1_STS_MASK;
+ }
+#endif
+
// EHCI Table 2-16 PortSC
// when software writes Port Reset bit to a one, it must also write a zero to the Port Enable bit.
portsc &= ~(EHCI_PORTSC_MASK_PORT_EANBLED);
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index ad20d64bd..3827be318 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -170,68 +170,6 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigne
}
}
-static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
-{
- volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
- uintptr_t addr = (uintptr_t)buf;
- while (len >= 4) {
- reg->u32 = *(uint32_t const *)addr;
- addr += 4;
- len -= 4;
- }
- if (len >= 2) {
- reg->u16 = *(uint16_t const *)addr;
- addr += 2;
- len -= 2;
- }
- if (len) {
- reg->u8 = *(uint8_t const *)addr;
- }
-}
-
-static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
-{
- volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
- uintptr_t addr = (uintptr_t)buf;
- while (len >= 4) {
- *(uint32_t *)addr = reg->u32;
- addr += 4;
- len -= 4;
- }
- if (len >= 2) {
- *(uint16_t *)addr = reg->u16;
- addr += 2;
- len -= 2;
- }
- if (len) {
- *(uint8_t *)addr = reg->u8;
- }
-}
-
-static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
-{
- static const struct {
- void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
- void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
- void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
- } ops[] = {
- /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
- /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
- };
- tu_fifo_buffer_info_t info;
- ops[dir].tu_fifo_get_info(f, &info);
- unsigned total_len = len;
- len = TU_MIN(total_len, info.linear.len);
- ops[dir].pipe_read_write(info.linear.ptr, fifo, len);
- unsigned rem = total_len - len;
- if (rem) {
- len = TU_MIN(rem, info.wrapped.len);
- ops[dir].pipe_read_write(info.wrapped.ptr, fifo, len);
- rem -= len;
- }
- ops[dir].tu_fifo_advance(f, total_len - rem);
-}
-
static void process_setup_packet(uint8_t rhport) {
musb_regs_t* musb_regs = MUSB_REGS(rhport);
@@ -277,9 +215,9 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr)
// TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
if (len) {
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN);
+ tu_hwfifo_write_from_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
} else {
- pipe_write_packet(buf, fifo_ptr, len);
+ tu_hwfifo_write(fifo_ptr, buf, len, NULL);
pipe->buf = buf + len;
}
pipe->remaining = rem - len;
@@ -308,9 +246,9 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
volatile void *fifo_ptr = &musb_regs->fifo[epnum];
if (len) {
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT);
+ tu_hwfifo_read_to_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
} else {
- pipe_read_packet(buf, fifo_ptr, len);
+ tu_hwfifo_read(fifo_ptr, buf, len, NULL);
pipe->buf = buf + len;
}
pipe->remaining = rem - len;
@@ -378,7 +316,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
volatile void *fifo_ptr = &musb_regs->fifo[0];
if (dir_in) {
- pipe_write_packet(buffer, fifo_ptr, len);
+ tu_hwfifo_write(fifo_ptr, buffer, len, NULL);
_dcd.pipe0.buf = buffer + len;
_dcd.pipe0.length = len;
@@ -458,7 +396,7 @@ static void process_ep0(uint8_t rhport)
const unsigned rem = _dcd.pipe0.remaining;
const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
volatile void *fifo_ptr = &musb_regs->fifo[0];
- pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len);
+ tu_hwfifo_read(fifo_ptr, _dcd.pipe0.buf, len, NULL);
_dcd.pipe0.remaining = rem - len;
_dcd.remaining_ctrl -= len;
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index 1faac2aa8..4115eecc5 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -437,7 +437,7 @@ void dcd_int_handler(uint8_t rhport)
// write to EP fifo
#if 0 // TODO support dcd_edpt_xfer_fifo
if (xfer->ff) {
- tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, true);
}
else
#endif
@@ -471,7 +471,7 @@ void dcd_int_handler(uint8_t rhport)
// Read from EP fifo
#if 0 // TODO support dcd_edpt_xfer_fifo API
if (xfer->ff) {
- tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, true);
}
else
#endif
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
index 91b876718..ca17d6251 100644
--- a/src/portable/nuvoton/nuc505/dcd_nuc505.c
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -194,7 +194,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
/* provided buffers are thankfully 32-bit aligned, allowing most data to be transferred as 32-bit */
#if 0 // TODO support dcd_edpt_xfer_fifo API
if (xfer->ff) {
- tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, true);
}
else
#endif
@@ -696,7 +696,7 @@ void dcd_int_handler(uint8_t rhport)
/* copy the data from the PC to the previously provided buffer */
#if 0 // TODO support dcd_edpt_xfer_fifo API
if (xfer->ff) {
- tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), true);
}
else
#endif
diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c
index 779c7bc3d..e2a51a5ca 100644
--- a/src/portable/renesas/rusb2/dcd_rusb2.c
+++ b/src/portable/renesas/rusb2/dcd_rusb2.c
@@ -30,25 +30,7 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2)
#include "device/dcd.h"
-#include "rusb2_type.h"
-
-#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
- #include "rusb2_rx.h"
-#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
- #include "rusb2_ra.h"
- #if defined(RENESAS_CORTEX_M23)
- #define D0FIFO CFIFO
- #define D0FIFOSEL CFIFOSEL
- #define D0FIFOSEL_b CFIFOSEL_b
- #define D1FIFOSEL CFIFOSEL
- #define D1FIFOSEL_b CFIFOSEL_b
- #define D0FIFOCTR CFIFOCTR
- #define D0FIFOCTR_b CFIFOCTR_b
- #endif
-
-#else
- #error "Unsupported MCU"
-#endif
+#include "rusb2_common.h"
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
@@ -161,106 +143,11 @@ static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num) {
}
//--------------------------------------------------------------------+
-// Pipe FIFO
-//--------------------------------------------------------------------+
-
-// Write data buffer --> hw fifo
-static void pipe_write_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
-{
- (void) rusb;
-
- volatile uint16_t *ff16;
- volatile uint8_t *ff8;
-
- // Highspeed FIFO is 32-bit
- if ( rusb2_is_highspeed_reg(rusb) ) {
- // TODO 32-bit access for better performance
- ff16 = (volatile uint16_t*) ((uintptr_t) fifo+2);
- ff8 = (volatile uint8_t *) ((uintptr_t) fifo+3);
- }else {
- ff16 = (volatile uint16_t*) fifo;
- ff8 = ((volatile uint8_t*) fifo);
- }
-
- uint8_t const* buf8 = (uint8_t const*) buf;
-
- while (len >= 2) {
- *ff16 = tu_unaligned_read16(buf8);
- buf8 += 2;
- len -= 2;
- }
-
- if (len > 0) {
- *ff8 = *buf8;
- ++buf8;
- }
-}
-
-// Read data buffer <-- hw fifo
-static void pipe_read_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
-{
- (void) rusb;
-
- // TODO 16/32-bit access for better performance
-
- uint8_t *p = (uint8_t*)buf;
- volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
- while (len--) *p++ = *reg;
-}
-
-// Write data sw fifo --> hw fifo
-static void pipe_write_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
- tu_fifo_buffer_info_t info;
- tu_fifo_get_read_info(f, &info);
-
- uint16_t cnt_lin = tu_min16(total_len, info.linear.len);
- uint16_t cnt_wrap = tu_min16(total_len - cnt_lin, info.wrapped.len);
- uint16_t const cnt_written = cnt_lin + cnt_wrap;
-
- // Ensure only the last write is odd if total_len is odd
- if (cnt_wrap == 0) {
- pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin);
- } else {
- pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin & ~1);
-
- if (cnt_lin & 1) {
- uint8_t glue[2] = {info.linear.ptr[cnt_lin & ~1], info.wrapped.ptr[0]};
- pipe_write_packet(rusb, glue, fifo, 2);
- cnt_wrap--;
- info.wrapped.ptr++;
- }
-
- pipe_write_packet(rusb, info.wrapped.ptr, fifo, cnt_wrap);
- }
- tu_fifo_advance_read_pointer(f, cnt_written);
-}
-
-// Read data sw fifo <-- hw fifo
-static void pipe_read_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
- tu_fifo_buffer_info_t info;
- tu_fifo_get_write_info(f, &info);
-
- uint16_t count = tu_min16(total_len, info.linear.len);
- pipe_read_packet(rusb, info.linear.ptr, fifo, count);
-
- uint16_t rem = total_len - count;
- if (rem) {
- rem = tu_min16(rem, info.wrapped.len);
- pipe_read_packet(rusb, info.wrapped.ptr, fifo, rem);
- count += rem;
- }
-
- tu_fifo_advance_write_pointer(f, count);
-}
-
-//--------------------------------------------------------------------+
// Pipe Transfer
//--------------------------------------------------------------------+
-
-static bool pipe0_xfer_in(rusb2_reg_t* rusb)
-{
- pipe_state_t *pipe = &_dcd.pipe[0];
- const unsigned rem = pipe->remaining;
+static bool pipe0_xfer_in(rusb2_reg_t *rusb) {
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ const unsigned rem = pipe->remaining;
if (!rem) {
pipe->buf = NULL;
@@ -272,11 +159,25 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
void *buf = pipe->buf;
if (len) {
+ // uint16_t fifo_sel = RUSB2_CFIFOSEL_ISEL_WRITE | FIFOSEL_BIGEND;
+ tu_hwfifo_access_t access_mode;
+ access_mode.param = (uintptr_t)rusb;
+ //
+ if (rusb2_is_highspeed_reg(rusb)) {
+ // fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ access_mode.data_stride = 4u;
+ } else {
+ // fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ access_mode.data_stride = 2u;
+ }
+ // rusb->CFIFOSEL = fifo_sel;
+ // while (0 == (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) {}
+
if (pipe->ff) {
- pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_write_from_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_write_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -288,10 +189,9 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
return false;
}
-static bool pipe0_xfer_out(rusb2_reg_t* rusb)
-{
- pipe_state_t *pipe = &_dcd.pipe[0];
- const unsigned rem = pipe->remaining;
+static bool pipe0_xfer_out(rusb2_reg_t *rusb) {
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ const unsigned rem = pipe->remaining;
const uint16_t mps = edpt0_max_packet_size(rusb);
const uint16_t vld = rusb->CFIFOCTR_b.DTLN;
@@ -299,11 +199,14 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb)
void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+
if (pipe->ff) {
- pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_read_to_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_read_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -330,18 +233,27 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
return true;
}
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
- const uint16_t mps = edpt_max_packet_size(rusb, num);
+ const uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ const bool is_highspeed = rusb2_is_highspeed_reg(rusb);
+ if (is_highspeed) {
+ rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_16BIT;
+ }
+
+ const uint16_t mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
- const uint16_t len = tu_min16(rem, mps);
- void *buf = pipe->buf;
+ uint16_t len = tu_min16(rem, mps);
+ void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
if (pipe->ff) {
- pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_write_from_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_write_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -362,7 +274,14 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
pipe_state_t *pipe = &_dcd.pipe[num];
const uint16_t rem = pipe->remaining;
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
+ uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ if (rusb2_is_highspeed_reg(rusb)) {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ }
+ rusb->D0FIFOSEL = fifo_sel;
+
const uint16_t mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
@@ -371,11 +290,13 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
if (pipe->ff) {
- pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_read_to_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_read_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -428,28 +349,29 @@ static void process_status_completion(uint8_t rhport)
dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true);
}
-static bool process_pipe0_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
-{
+static bool process_pipe0_xfer(rusb2_reg_t *rusb, int buffer_type, uint8_t ep_addr, void *buffer,
+ uint16_t total_bytes) {
+ uint16_t fifo_sel =
+ (rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND;
+
/* configure fifo direction and access unit settings */
- if ( ep_addr ) {
- /* IN, 2 bytes */
- rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
- (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
- while ( !(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ) {}
- } else {
- /* OUT, a byte */
- rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
- while ( rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE ) {}
+ if (ep_addr != 0) {
+ // Control IN
+ fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE;
+ }
+ rusb->CFIFOSEL = fifo_sel;
+ while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) {
+ // wait until ISEL_WRITE take effect
}
pipe_state_t *pipe = &_dcd.pipe[0];
- pipe->ff = buffer_type;
- pipe->length = total_bytes;
- pipe->remaining = total_bytes;
+ pipe->ff = buffer_type;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
- if ( total_bytes ) {
+ if (total_bytes) {
pipe->buf = buffer;
- if ( ep_addr ) {
+ if (ep_addr) {
/* IN */
TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80));
pipe0_xfer_in(rusb);
@@ -525,7 +447,7 @@ static bool process_edpt_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_add
static void process_pipe0_bemp(uint8_t rhport)
{
rusb2_reg_t* rusb = RUSB2_REG(rhport);
- bool completed = pipe0_xfer_in(rusb);
+ bool completed = pipe0_xfer_in(rusb);
if (completed) {
pipe_state_t *pipe = &_dcd.pipe[0];
dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN),
@@ -621,18 +543,20 @@ static void process_set_address(uint8_t rhport)
{
rusb2_reg_t* rusb = RUSB2_REG(rhport);
const uint16_t addr = rusb->USBADDR_b.USBADDR;
- if (!addr) return;
+ if (!addr) {
+ return;
+ }
const tusb_control_request_t setup_packet = {
#if defined(__CCRX__)
.bmRequestType = { 0 }, /* Note: CCRX needs the braces over this struct member */
-#else
- .bmRequestType = 0,
-#endif
- .bRequest = TUSB_REQ_SET_ADDRESS,
- .wValue = addr,
- .wIndex = 0,
- .wLength = 0,
+ #else
+ .bmRequestType = 0,
+ #endif
+ .bRequest = TUSB_REQ_SET_ADDRESS,
+ .wValue = addr,
+ .wIndex = 0,
+ .wLength = 0,
};
dcd_event_setup_received(rhport, (const uint8_t *) &setup_packet, true);
@@ -899,7 +823,6 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
{
(void) is_isr;
// USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
rusb2_reg_t* rusb = RUSB2_REG(rhport);
dcd_int_disable(rhport);
@@ -912,7 +835,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
- if (!ctr) return;
+ if (!ctr) {
+ return;
+ }
dcd_int_disable(rhport);
const uint32_t pid = *ctr & 0x3;
*ctr = pid | RUSB2_PIPE_CTR_PID_STALL;
@@ -924,7 +849,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
rusb2_reg_t * rusb = RUSB2_REG(rhport);
volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
- if (!ctr) return;
+ if (!ctr) {
+ return;
+ }
dcd_int_disable(rhport);
*ctr = RUSB2_PIPE_CTR_SQCLR_Msk;
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index 6f6d27d0e..4c3315044 100644
--- a/src/portable/renesas/rusb2/hcd_rusb2.c
+++ b/src/portable/renesas/rusb2/hcd_rusb2.c
@@ -31,17 +31,9 @@
#include "host/hcd.h"
#include "host/usbh.h"
-#include "rusb2_type.h"
+#include "rusb2_common.h"
-#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
- #include "rusb2_rx.h"
-#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
- #include "rusb2_ra.h"
-#else
- #error "Unsupported MCU"
-#endif
-
-#define TU_RUSB2_HCD_DBG 2
+ #define TU_RUSB2_HCD_DBG 2
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
@@ -76,12 +68,10 @@ typedef struct TU_ATTR_PACKED {
TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
TU_ATTR_BIT_FIELD_ORDER_END
-typedef struct
-{
- bool need_reset; /* The device has not been reset after connection. */
+typedef struct {
pipe_state_t pipe[PIPE_COUNT];
- uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
- uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
+ uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
+ uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
} hcd_data_t;
//--------------------------------------------------------------------+
@@ -166,29 +156,6 @@ static inline void pipe_wait_for_ready(rusb2_reg_t* rusb, unsigned num)
while (!rusb->D0FIFOCTR_b.FRDY) {}
}
-static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
-{
- // NOTE: unlike DCD, Highspeed 32-bit FIFO does not need to adjust the fifo address
- volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
- uintptr_t addr = (uintptr_t)buf;
- while (len >= 2) {
- reg->u16 = *(const uint16_t *)addr;
- addr += 2;
- len -= 2;
- }
- if (len) {
- reg->u8 = *(const uint8_t *)addr;
- ++addr;
- }
-}
-
-static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
-{
- uint8_t *p = (uint8_t*)buf;
- volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
- while (len--) *p++ = *reg;
-}
-
static bool pipe0_xfer_in(rusb2_reg_t* rusb)
{
pipe_state_t *pipe = &_hcd.pipe[0];
@@ -199,8 +166,12 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
- pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ // pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -227,7 +198,11 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb)
const unsigned len = TU_MIN(mps, rem);
void *buf = pipe->buf;
if (len) {
- pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+
+ // pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -242,14 +217,24 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
pipe_state_t *pipe = &_hcd.pipe[num];
const unsigned rem = pipe->remaining;
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
+ uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ if (rusb2_is_highspeed_reg(rusb)) {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ }
+ rusb->D0FIFOSEL = fifo_sel;
+
const unsigned mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
const unsigned vld = rusb->D0FIFOCTR_b.DTLN;
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
void *buf = pipe->buf;
if (len) {
- pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ // pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+ tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -275,13 +260,23 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
return true;
}
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
+ uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ if (rusb2_is_highspeed_reg(rusb)) {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ }
+ rusb->D0FIFOSEL = fifo_sel;
+
const unsigned mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
const unsigned len = TU_MIN(rem, mps);
void *buf = pipe->buf;
if (len) {
- pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ // pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+ tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -296,18 +291,19 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
static bool process_pipe0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
{
(void)dev_addr;
-
rusb2_reg_t* rusb = RUSB2_REG(rhport);
const unsigned dir_in = tu_edpt_dir(ep_addr);
+ uint16_t fifo_sel =
+ (rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND;
+
/* configure fifo direction and access unit settings */
- if (dir_in) { /* IN, a byte */
- rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
- while (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ;
- } else { /* OUT, 2 bytes */
- rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
- (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
- while (!(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) ;
+ if (dir_in == TUSB_DIR_OUT) {
+ fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE;
+ }
+ rusb->CFIFOSEL = fifo_sel;
+ while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) {
+ // wait until ISEL_WRITE take effect
}
pipe_state_t *pipe = &_hcd.pipe[0];
@@ -535,13 +531,8 @@ void hcd_int_disable(uint8_t rhport) {
rusb2_int_disable(rhport);
}
-uint32_t hcd_frame_number(uint8_t rhport)
-{
- rusb2_reg_t* rusb = RUSB2_REG(rhport);
-
- /* The device must be reset at least once after connection
- * in order to start the frame counter. */
- if (_hcd.need_reset) hcd_port_reset(rhport);
+uint32_t hcd_frame_number(uint8_t rhport) {
+ rusb2_reg_t *rusb = RUSB2_REG(rhport);
return rusb->FRMNUM_b.FRNM;
}
@@ -550,32 +541,18 @@ uint32_t hcd_frame_number(uint8_t rhport)
*--------------------------------------------------------------------+*/
bool hcd_port_connect_status(uint8_t rhport) {
rusb2_reg_t* rusb = RUSB2_REG(rhport);
- return rusb->INTSTS1_b.ATTCH ? true : false;
+ const uint16_t line_state = rusb->SYSSTS0 & RUSB2_SYSSTS0_LNST_Msk;
+ return line_state == RUSB2_SYSSTS0_LNST_FS_J || line_state == RUSB2_SYSSTS0_LNST_FS_K;
}
void hcd_port_reset(uint8_t rhport) {
rusb2_reg_t* rusb = RUSB2_REG(rhport);
- rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
- while (rusb->DCPCTR_b.PBUSY) {}
-
- hcd_int_disable(rhport);
- rusb->DVSTCTR0_b.UACT = 0;
- if (rusb->DCPCTR_b.SUREQ) {
- rusb->DCPCTR_b.SUREQCLR = 1;
- }
- hcd_int_enable(rhport);
-
- /* Reset should be asserted 10-20ms. */
rusb->DVSTCTR0_b.USBRST = 1;
- for (volatile int i = 0; i < 2400000; ++i) {}
- rusb->DVSTCTR0_b.USBRST = 0;
-
- rusb->DVSTCTR0_b.UACT = 1;
- _hcd.need_reset = false;
}
void hcd_port_reset_end(uint8_t rhport) {
- (void) rhport;
+ rusb2_reg_t *rusb = RUSB2_REG(rhport);
+ rusb->DVSTCTR0_b.USBRST = 0;
}
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
@@ -584,7 +561,8 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
case RUSB2_DVSTCTR0_RHST_HS: return TUSB_SPEED_HIGH;
case RUSB2_DVSTCTR0_RHST_FS: return TUSB_SPEED_FULL;
case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW;
- default: return TUSB_SPEED_INVALID;
+ default:
+ return TUSB_SPEED_INVALID;
}
}
@@ -802,7 +780,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (is1 & RUSB2_INTSTS1_ATTCH_Msk) {
rusb->DVSTCTR0_b.UACT = 1;
- _hcd.need_reset = true;
rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk;
hcd_event_device_attach(rhport, true);
}
diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c
index 856f9714f..8addbe4c6 100644
--- a/src/portable/renesas/rusb2/rusb2_common.c
+++ b/src/portable/renesas/rusb2/rusb2_common.c
@@ -27,20 +27,19 @@
#include "tusb_option.h"
#if defined(TUP_USBIP_RUSB2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
+ #include "osal/osal.h"
+ #include "common/tusb_fifo.h"
-#include "rusb2_type.h"
+ #include "rusb2_common.h"
-#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
-#include "rusb2_rx.h"
-
-#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
-#include "rusb2_ra.h"
+ #if TU_CHECK_MCU(OPT_MCU_RAXXX)
+ #include "rusb2_ra.h"
// USBFS_INT_IRQn and USBHS_USB_INT_RESUME_IRQn are generated by FSP
rusb2_controller_t rusb2_controller[] = {
- { .reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn },
+ {.reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn},
#ifdef RUSB2_SUPPORT_HIGHSPEED
- { .reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn },
+ {.reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn},
#endif
};
@@ -49,10 +48,69 @@ void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum);
void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
rusb2_controller[rhport].irqnum = irqnum;
}
+ #endif
-#else
- #error "Unsupported MCU"
-#endif
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+static void hwfifo_set_mbw(rusb2_reg_t *rusb, uintptr_t hwfifo, uint16_t mbw) {
+ volatile uint16_t *fifo_sel;
+ if (hwfifo == (uintptr_t)&rusb->CFIFO) {
+ fifo_sel = &rusb->CFIFOSEL;
+ } else if (hwfifo == (uintptr_t)&rusb->D0FIFO) {
+ fifo_sel = &rusb->D0FIFOSEL;
+ } else if (hwfifo == (uintptr_t)&rusb->D1FIFO) {
+ fifo_sel = &rusb->D1FIFOSEL;
+ } else {
+ return;
+ }
+
+ *fifo_sel = (*fifo_sel & ~RUSB2_CFIFOSEL_MBW_Msk) | mbw;
+}
+
+// write to hwfifo from buffer with access mode
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ rusb2_reg_t *rusb = (rusb2_reg_t *)access_mode->param;
+ const uint8_t *buf8 = (const uint8_t *)src;
+ volatile uint16_t *ff16;
+ volatile uint8_t *ff8;
+ const bool is_highspeed = rusb2_is_highspeed_reg(rusb);
+ if (is_highspeed) {
+ ff16 = (volatile uint16_t *)((uintptr_t)hwfifo + 2);
+ ff8 = (volatile uint8_t *)((uintptr_t)hwfifo + 3);
+ } else {
+ ff16 = (volatile uint16_t *)hwfifo;
+ ff8 = ((volatile uint8_t *)hwfifo);
+ }
+
+ // 32-bit access for highspeed
+ if (is_highspeed) {
+ volatile uint32_t *ff32 = (volatile uint32_t *)hwfifo;
+ while (len >= 4) {
+ *ff32 = tu_unaligned_read32(buf8);
+ buf8 += 4;
+ len -= 4;
+ }
+
+ if (len >= 2) {
+ // switch to 16-bit access
+ hwfifo_set_mbw(rusb, (uintptr_t)hwfifo, RUSB2_FIFOSEL_MBW_16BIT);
+ }
+ }
+
+ // 16-bit access
+ while (len >= 2) {
+ *ff16 = tu_unaligned_read16(buf8);
+ buf8 += 2;
+ len -= 2;
+ }
+
+ // 8-bit access does not need to change MBW
+ if (len > 0) {
+ *ff8 = *buf8;
+ ++buf8;
+ }
+}
#endif
diff --git a/src/portable/renesas/rusb2/rusb2_common.h b/src/portable/renesas/rusb2/rusb2_common.h
new file mode 100644
index 000000000..6b8c3d7f2
--- /dev/null
+++ b/src/portable/renesas/rusb2/rusb2_common.h
@@ -0,0 +1,58 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+#pragma once
+
+#include "common/tusb_common.h"
+#include "rusb2_type.h"
+
+#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
+ #include "rusb2_rx.h"
+#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
+ #include "rusb2_ra.h"
+
+ // Hack for D0FIFO definitions on RA Cortex-M23
+ #if defined(RENESAS_CORTEX_M23)
+ #define D0FIFO CFIFO
+ #define D0FIFOSEL CFIFOSEL
+ #define D0FIFOSEL_b CFIFOSEL_b
+ #define D1FIFOSEL CFIFOSEL
+ #define D1FIFOSEL_b CFIFOSEL_b
+ #define D0FIFOCTR CFIFOCTR
+ #define D0FIFOCTR_b CFIFOCTR_b
+ #endif
+
+#else
+ #error "Unsupported MCU"
+#endif
+
+
+//--------------------------------------------------------------------+
+// Common
+//--------------------------------------------------------------------+
+
+enum {
+ FIFOSEL_BIGEND = (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0)
+};
diff --git a/src/portable/renesas/rusb2/rusb2_type.h b/src/portable/renesas/rusb2/rusb2_type.h
index 71837d03c..21f116857 100644
--- a/src/portable/renesas/rusb2/rusb2_type.h
+++ b/src/portable/renesas/rusb2/rusb2_type.h
@@ -41,10 +41,9 @@ extern "C" {
#define _ccrx_evenaccess
#endif
-/*--------------------------------------------------------------------*/
-/* Register Definitions */
-/*--------------------------------------------------------------------*/
-
+//--------------------------------------------------------------------+
+// Register Definitions
+//--------------------------------------------------------------------+
/* Start of definition of packed structs (used by the CCRX toolchain) */
TU_ATTR_PACKED_BEGIN
TU_ATTR_BIT_FIELD_ORDER_BEGIN
@@ -1669,15 +1668,20 @@ TU_ATTR_BIT_FIELD_ORDER_END
/*--------------------------------------------------------------------*/
/* Register Bit Utils */
/*--------------------------------------------------------------------*/
-#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
-#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
-#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
-#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
+#define RUSB2_SYSSTS0_LNST_SE0 (0)
+#define RUSB2_SYSSTS0_LNST_FS_J (1u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed J state */
+#define RUSB2_SYSSTS0_LNST_FS_K (2u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed K state */
+#define RUSB2_SYSSTS0_LNST_LS_SE1 (3u << RUSB2_SYSSTS0_LNST_Pos) /* Low-speed SE1 state */
#define RUSB2_DVSTCTR0_RHST_LS (1U << RUSB2_DVSTCTR0_RHST_Pos) /* Low-speed connection */
#define RUSB2_DVSTCTR0_RHST_FS (2U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
#define RUSB2_DVSTCTR0_RHST_HS (3U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
+#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
+#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
+#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
+#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
+
#define RUSB2_DEVADD_USBSPD_LS (1U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Low-speed */
#define RUSB2_DEVADD_USBSPD_FS (2U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Full-speed */
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 64046ce17..22a9e4af8 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -108,22 +108,10 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && \
- !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
-#include "device/dcd.h"
-
-#if defined(TUP_USBIP_FSDEV_STM32)
- #include "fsdev_stm32.h"
-#elif defined(TUP_USBIP_FSDEV_CH32)
- #include "fsdev_ch32.h"
-#elif defined(TUP_USBIP_FSDEV_AT32)
- #include "fsdev_at32.h"
-#else
- #error "Unknown USB IP"
-#endif
-
-#include "fsdev_type.h"
+ #include "device/dcd.h"
+ #include "fsdev_common.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@@ -131,25 +119,25 @@
// One of these for every EP IN & OUT, uses a bit of RAM....
typedef struct {
- uint8_t *buffer;
+ uint8_t *buffer;
tu_fifo_t *ff;
- uint16_t total_len;
- uint16_t queued_len;
- uint16_t max_packet_size;
- uint8_t ep_idx; // index for USB_EPnR register
- bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
+ uint16_t total_len;
+ uint16_t queued_len;
+ uint16_t max_packet_size;
+ uint8_t ep_idx; // index for USB_EPnR register
+ bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
} xfer_ctl_t;
// EP allocator
typedef struct {
uint8_t ep_num;
uint8_t ep_type;
- bool allocated[2];
+ bool allocated[2];
} ep_alloc_t;
static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2];
static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT];
-static uint8_t remoteWakeCountdown; // When wake is requested
+static uint8_t remoteWakeCountdown; // When wake is requested
//--------------------------------------------------------------------+
// Prototypes
@@ -163,17 +151,12 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir);
// PMA allocation/access
static uint16_t ep_buf_ptr; ///< Points to first free memory location
static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf);
-static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
-static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes);
-static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes);
-
-static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes);
-static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes);
+static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
static void edpt0_open(uint8_t rhport);
TU_ATTR_ALWAYS_INLINE static inline void edpt0_prepare_setup(void) {
- btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8);
+ btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8);
}
//--------------------------------------------------------------------+
@@ -187,42 +170,22 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
- // Follow the RM mentions to use a special ordering of PDWN and FRES
- for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
- asm("NOP");
- }
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
+ (void)rh_init;
- // Perform USB peripheral reset
- FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
- for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
- asm("NOP");
- }
+ fsdev_core_reset();
- FSDEV_REG->CNTR &= ~USB_CNTR_PDWN;
-
- // Wait startup time, for F042 and F070, this is <= 1 us.
- for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
- asm("NOP");
- }
FSDEV_REG->CNTR = 0; // Enable USB
-#if !defined(FSDEV_BUS_32BIT)
+ #if !defined(FSDEV_BUS_32BIT)
// BTABLE register does not exist any more on 32-bit bus devices
FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE;
-#endif
+ #endif
- FSDEV_REG->ISTR = 0; // Clear pending interrupts
+ // Enable interrupts for device mode
+ FSDEV_REG->CNTR |=
+ USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM;
- // Reset endpoints to disabled
- for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
- // This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED.
- ep_write(i, 0u, false);
- }
-
- FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM |
- USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM;
handle_bus_reset(rhport);
// Enable pull-up if supported
@@ -231,6 +194,14 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
return true;
}
+bool dcd_deinit(uint8_t rhport) {
+ (void)rhport;
+
+ fsdev_deinit();
+
+ return true;
+}
+
void dcd_sof_enable(uint8_t rhport, bool en) {
(void)rhport;
@@ -264,8 +235,8 @@ static void handle_bus_reset(uint8_t rhport) {
for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Clear EP allocation status
- ep_alloc_status[i].ep_num = 0xFF;
- ep_alloc_status[i].ep_type = 0xFF;
+ ep_alloc_status[i].ep_num = 0xFF;
+ ep_alloc_status[i].ep_type = 0xFF;
ep_alloc_status[i].allocated[0] = false;
ep_alloc_status[i].allocated[1] = false;
}
@@ -273,7 +244,7 @@ static void handle_bus_reset(uint8_t rhport) {
// Reset PMA allocation
ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT;
- edpt0_open(rhport); // open control endpoint (both IN & OUT)
+ edpt0_open(rhport); // open control endpoint (both IN & OUT)
FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function
}
@@ -282,8 +253,8 @@ static void handle_bus_reset(uint8_t rhport) {
static void handle_ctr_tx(uint32_t ep_id) {
uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
- uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN);
+ const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN);
if (ep_is_iso(ep_reg)) {
// Ignore spurious interrupts that we don't schedule
@@ -293,11 +264,11 @@ static void handle_ctr_tx(uint32_t ep_id) {
return;
}
xfer->iso_in_sending = false;
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
uint8_t buf_id = (ep_reg & USB_EP_DTOG_TX) ? 0 : 1;
-#else
+ #else
uint8_t buf_id = BTABLE_BUF_TX;
-#endif
+ #endif
btable_set_count(ep_id, buf_id, 0);
}
@@ -310,17 +281,17 @@ static void handle_ctr_tx(uint32_t ep_id) {
static void handle_ctr_setup(uint32_t ep_id) {
uint16_t rx_count = btable_get_count(ep_id, BTABLE_BUF_RX);
- uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
- uint8_t setup_packet[8] TU_ATTR_ALIGNED(4);
+ uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
+ uint8_t setup_packet[8] TU_ATTR_ALIGNED(4);
- dcd_read_packet_memory(setup_packet, rx_addr, rx_count);
+ tu_hwfifo_read(PMA_BUF_AT(rx_addr), setup_packet, rx_count, NULL);
// Clear CTR RX if another setup packet arrived before this, it will be discarded
ep_write_clear_ctr(ep_id, TUSB_DIR_OUT);
// Setup packet should always be 8 bytes. If not, we probably missed the packet
if (rx_count == 8) {
- dcd_event_setup_received(0, (uint8_t*) setup_packet, true);
+ dcd_event_setup_received(0, (uint8_t *)setup_packet, true);
// Hardware should reset EP0 RX/TX to NAK and both toggle to 1
} else {
// Missed setup packet !!!
@@ -331,29 +302,30 @@ static void handle_ctr_setup(uint32_t ep_id) {
// Handle CTR interrupt for the RX/OUT direction
static void handle_ctr_rx(uint32_t ep_id) {
- uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
- uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
- bool const is_iso = ep_is_iso(ep_reg);
- xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
+ uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD;
+ const bool is_iso = ep_is_iso(ep_reg);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
uint8_t buf_id;
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = is_iso;
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
if (dbl_buf) {
buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1;
} else {
buf_id = BTABLE_BUF_RX;
}
- uint16_t const rx_count = btable_get_count(ep_id, buf_id);
- uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id);
+ const uint16_t rx_count = btable_get_count(ep_id, buf_id);
+ uint16_t pma_addr = (uint16_t)btable_get_addr(ep_id, buf_id);
+ fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(pma_addr);
if (xfer->ff) {
- dcd_read_packet_memory_ff(xfer->ff, pma_addr, rx_count);
+ tu_hwfifo_read_to_fifo(pma_buf, xfer->ff, rx_count, NULL);
} else {
- dcd_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count);
+ tu_hwfifo_read(pma_buf, xfer->buffer + xfer->queued_len, rx_count, NULL);
}
xfer->queued_len += rx_count;
@@ -371,7 +343,7 @@ static void handle_ctr_rx(uint32_t ep_id) {
} else {
// Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always
if (!is_iso) {
- uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
+ const uint16_t cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt);
}
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits
@@ -431,18 +403,18 @@ void dcd_int_handler(uint8_t rhport) {
// loop to handle all pending CTR interrupts
while (FSDEV_REG->ISTR & USB_ISTR_CTR) {
// skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt
- uint32_t const ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
- uint32_t const ep_reg = ep_read(ep_id);
+ const uint32_t ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
+ const uint32_t ep_reg = ep_read(ep_id);
if (ep_reg & USB_EP_CTR_RX) {
- #ifdef FSDEV_BUS_32BIT
+ #ifdef FSDEV_BUS_32BIT
/* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
* https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf
* From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers
* Description:
- * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
- * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
- * Workaround:
+ * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM
+ * accesses have completed. If the software responds quickly to the interrupt, the full buffer contents may not be
+ * correct. Workaround:
* - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
* should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
* - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
@@ -453,9 +425,9 @@ void dcd_int_handler(uint8_t rhport) {
*/
volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
while (cycle_count > 0U) {
- cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
}
- #endif
+ #endif
if (ep_reg & USB_EP_SETUP) {
handle_ctr_setup(ep_id); // CTR will be clear after copied setup packet
@@ -483,14 +455,13 @@ void dcd_int_handler(uint8_t rhport) {
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
+void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) {
(void)rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
- request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS) {
- uint8_t const dev_addr = (uint8_t)request->wValue;
- FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr);
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ const uint8_t dev_addr = (uint8_t)request->wValue;
+ FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr);
}
edpt0_prepare_setup();
@@ -501,15 +472,14 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req
* In case of double buffering, high 16bit is the address of 2nd buffer
* During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually.
*/
-static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
-{
- uint8_t blsize, num_block;
+static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) {
+ uint8_t blsize, num_block;
uint16_t aligned_len = pma_align_buffer_size(len, &blsize, &num_block);
- (void) blsize;
- (void) num_block;
+ (void)blsize;
+ (void)num_block;
uint32_t addr = ep_buf_ptr;
- ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
+ ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
if (dbuf) {
addr |= ((uint32_t)ep_buf_ptr) << 16;
@@ -517,7 +487,7 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
}
// Verify packet buffer is not overflowed
- TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF);
+ TU_ASSERT(ep_buf_ptr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF);
return addr;
}
@@ -525,35 +495,32 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
/***
* Allocate hardware endpoint
*/
-static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) {
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Check if already allocated
- if (ep_alloc_status[i].allocated[dir] &&
- ep_alloc_status[i].ep_type == ep_type &&
+ if (ep_alloc_status[i].allocated[dir] && ep_alloc_status[i].ep_type == ep_type &&
ep_alloc_status[i].ep_num == epnum) {
return i;
}
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = ep_type == TUSB_XFER_ISOCHRONOUS;
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
// If EP of current direction is not allocated
// For double-buffered mode both directions needs to be free
- if (!ep_alloc_status[i].allocated[dir] &&
- (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
+ if (!ep_alloc_status[i].allocated[dir] && (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
// Check if EP number is the same
if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) {
// One EP pair has to be the same type
if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) {
- ep_alloc_status[i].ep_num = epnum;
- ep_alloc_status[i].ep_type = ep_type;
+ ep_alloc_status[i].ep_num = epnum;
+ ep_alloc_status[i].ep_type = ep_type;
ep_alloc_status[i].allocated[dir] = true;
return i;
@@ -567,16 +534,16 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
}
void edpt0_open(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
dcd_ep_alloc(0x0, TUSB_XFER_CONTROL);
dcd_ep_alloc(0x80, TUSB_XFER_CONTROL);
xfer_status[0][0].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
- xfer_status[0][0].ep_idx = 0;
+ xfer_status[0][0].ep_idx = 0;
xfer_status[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
- xfer_status[0][1].ep_idx = 0;
+ xfer_status[0][1].ep_idx = 0;
uint16_t pma_addr0 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
uint16_t pma_addr1 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
@@ -594,13 +561,13 @@ void edpt0_open(uint8_t rhport) {
ep_write(0, ep_reg, false);
}
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
+bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
(void)rhport;
- uint8_t const ep_addr = desc_ep->bEndpointAddress;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- const uint16_t packet_size = tu_edpt_packet_size(desc_ep);
- uint8_t const ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer);
+ const uint8_t ep_addr = desc_ep->bEndpointAddress;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ const uint16_t packet_size = tu_edpt_packet_size(desc_ep);
+ const uint8_t ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer);
TU_ASSERT(ep_idx < FSDEV_EP_COUNT);
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
@@ -624,9 +591,9 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
uint16_t pma_addr = dcd_pma_alloc(packet_size, false);
btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
xfer->max_packet_size = packet_size;
- xfer->ep_idx = ep_idx;
+ xfer->ep_idx = ep_idx;
ep_change_status(&ep_reg, dir, EP_STAT_NAK);
ep_change_dtog(&ep_reg, dir, 0);
@@ -650,8 +617,8 @@ void dcd_edpt_close_all(uint8_t rhport) {
// Reset endpoint
ep_write(i, 0, false);
// Clear EP allocation status
- ep_alloc_status[i].ep_num = 0xFF;
- ep_alloc_status[i].ep_type = 0xFF;
+ ep_alloc_status[i].ep_num = 0xFF;
+ ep_alloc_status[i].ep_type = 0xFF;
ep_alloc_status[i].allocated[0] = false;
ep_alloc_status[i].allocated[1] = false;
}
@@ -665,46 +632,46 @@ void dcd_edpt_close_all(uint8_t rhport) {
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
(void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
- uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
-#if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
- uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
+ #if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
+ uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
uint16_t pma_addr2 = pma_addr >> 16;
-#else
- uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false);
+ #else
+ uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false);
uint16_t pma_addr2 = pma_addr;
-#endif
+ #endif
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
btable_set_addr(ep_idx, 0, pma_addr);
btable_set_addr(ep_idx, 1, pma_addr2);
-#else
+ #else
btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
- (void) pma_addr2;
-#endif
+ (void)pma_addr2;
+ #endif
- xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
- xfer->ep_idx = ep_idx;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ xfer->ep_idx = ep_idx;
return true;
}
-bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
+bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
(void)rhport;
- uint8_t const ep_addr = desc_ep->bEndpointAddress;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_addr = desc_ep->bEndpointAddress;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ const uint8_t ep_idx = xfer->ep_idx;
xfer->max_packet_size = tu_edpt_packet_size(desc_ep);
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX;
-#if FSDEV_USE_SBUF_ISO != 0
+ #if FSDEV_USE_SBUF_ISO != 0
ep_reg |= USB_EP_KIND;
ep_change_status(&ep_reg, dir, EP_STAT_DISABLED);
@@ -715,12 +682,12 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
} else {
ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX);
}
-#else
+ #else
ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED);
ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED);
ep_change_dtog(&ep_reg, dir, 0);
ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1);
-#endif
+ #endif
ep_write(ep_idx, ep_reg, true);
@@ -729,28 +696,29 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
// Currently, single-buffered, and only 64 bytes at a time (max)
static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
- uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
+ uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
uint32_t ep_reg = ep_read(ep_ix) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR
- bool const is_iso = ep_is_iso(ep_reg);
+ const bool is_iso = ep_is_iso(ep_reg);
uint8_t buf_id;
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = is_iso;
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
if (dbl_buf) {
buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0;
} else {
buf_id = BTABLE_BUF_TX;
}
- uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id);
+ uint16_t addr_ptr = (uint16_t)btable_get_addr(ep_ix, buf_id);
+ fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(addr_ptr);
if (xfer->ff) {
- dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len);
+ tu_hwfifo_write_from_fifo(pma_buf, xfer->ff, len, NULL);
} else {
- dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len);
+ tu_hwfifo_write(pma_buf, &(xfer->buffer[xfer->queued_len]), len, NULL);
}
xfer->queued_len += len;
@@ -765,10 +733,10 @@ static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
}
static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
- (void) rhport;
+ (void)rhport;
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_idx = xfer->ep_idx;
if (dir == TUSB_DIR_IN) {
dcd_transmit_packet(xfer, ep_idx);
@@ -778,11 +746,11 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
uint16_t cnt = tu_min16(xfer->total_len, xfer->max_packet_size);
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = ep_is_iso(ep_reg);
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
if (dbl_buf) {
btable_set_rx_bufsize(ep_idx, 0, cnt);
btable_set_rx_bufsize(ep_idx, 1, cnt);
@@ -797,29 +765,29 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
return true;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- xfer->buffer = buffer;
- xfer->ff = NULL;
- xfer->total_len = total_bytes;
+ xfer->buffer = buffer;
+ xfer->ff = NULL;
+ xfer->total_len = total_bytes;
xfer->queued_len = 0;
return edpt_xfer(rhport, ep_num, dir);
}
-bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- xfer->buffer = NULL;
- xfer->ff = ff;
- xfer->total_len = total_bytes;
+ xfer->buffer = NULL;
+ xfer->ff = ff;
+ xfer->total_len = total_bytes;
xfer->queued_len = 0;
return edpt_xfer(rhport, ep_num, dir);
@@ -827,10 +795,10 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
(void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_idx = xfer->ep_idx;
uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir);
@@ -842,10 +810,10 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
(void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_idx = xfer->ep_idx;
uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir);
@@ -857,168 +825,22 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
ep_write(ep_idx, ep_reg, true);
}
-//--------------------------------------------------------------------+
-// PMA read/write
-//--------------------------------------------------------------------+
-
-// Write to packet memory area (PMA) from user memory
-// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
-// - Uses unaligned for RAM (since M0 cannot access unaligned address)
-static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) {
- if (nbytes == 0) return true;
- uint32_t n_write = nbytes / FSDEV_BUS_SIZE;
-
- fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst);
- const uint8_t *src8 = src;
-
- while (n_write--) {
- pma_buf->value = fsdevbus_unaligned_read(src8);
- src8 += FSDEV_BUS_SIZE;
- pma_buf++;
- }
-
- // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit
- uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1);
- if (odd) {
- fsdev_bus_t temp = 0;
- for(uint16_t i = 0; i < odd; i++) {
- temp |= *src8++ << (i * 8);
- }
- pma_buf->value = temp;
- }
-
- return true;
+void dcd_int_enable(uint8_t rhport) {
+ fsdev_int_enable(rhport);
}
-// Read from packet memory area (PMA) to user memory.
-// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT
-// - Uses unaligned for RAM (since M0 cannot access unaligned address)
-static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) {
- if (nbytes == 0) return true;
- uint32_t n_read = nbytes / FSDEV_BUS_SIZE;
-
- fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src);
- uint8_t *dst8 = (uint8_t *)dst;
-
- while (n_read--) {
- fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value);
- dst8 += FSDEV_BUS_SIZE;
- pma_buf++;
- }
-
- // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit
- uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1);
- if (odd) {
- fsdev_bus_t temp = pma_buf->value;
- while (odd--) {
- *dst8++ = (uint8_t) (temp & 0xfful);
- temp >>= 8;
- }
- }
-
- return true;
+void dcd_int_disable(uint8_t rhport) {
+ fsdev_int_disable(rhport);
}
-// Write to PMA from FIFO
-static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) {
- if (wNBytes == 0) return true;
-
- // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
- tu_fifo_buffer_info_t info;
- tu_fifo_get_read_info(ff, &info);
-
- uint16_t cnt_lin = tu_min16(wNBytes, info.linear.len);
- uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len);
- uint16_t const cnt_total = cnt_lin + cnt_wrap;
-
- // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
- // last lin byte will be combined with wrapped part To ensure PMA is always access aligned
- uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1);
- uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1);
- uint8_t const *src8 = (uint8_t const*) info.linear.ptr;
-
- // write even linear part
- dcd_write_packet_memory(dst, src8, lin_even);
- dst += lin_even;
- src8 += lin_even;
-
- if (lin_odd == 0) {
- src8 = (uint8_t const*) info.wrapped.ptr;
- } else {
- // Combine last linear bytes + first wrapped bytes to form fsdev bus width data
- fsdev_bus_t temp = 0;
- uint16_t i;
- for(i = 0; i < lin_odd; i++) {
- temp |= *src8++ << (i * 8);
- }
-
- src8 = (uint8_t const*) info.wrapped.ptr;
- for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) {
- temp |= *src8++ << (i * 8);
- }
-
- dcd_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE);
- dst += FSDEV_BUS_SIZE;
- }
-
- // write the rest of the wrapped part
- dcd_write_packet_memory(dst, src8, cnt_wrap);
-
- tu_fifo_advance_read_pointer(ff, cnt_total);
- return true;
+ #if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU)
+void dcd_connect(uint8_t rhport) {
+ fsdev_connect(rhport);
}
-// Read from PMA to FIFO
-static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) {
- if (wNBytes == 0) return true;
-
- // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
- // Check for first linear part
- tu_fifo_buffer_info_t info;
- tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO
-
- uint16_t cnt_lin = tu_min16(wNBytes, info.linear.len);
- uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len);
- uint16_t cnt_total = cnt_lin + cnt_wrap;
-
- // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
- // last lin byte will be combined with wrapped part To ensure PMA is always access aligned
-
- uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1);
- uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1);
- uint8_t *dst8 = (uint8_t *) info.linear.ptr;
-
- // read even linear part
- dcd_read_packet_memory(dst8, src, lin_even);
- dst8 += lin_even;
- src += lin_even;
-
- if (lin_odd == 0) {
- dst8 = (uint8_t *) info.wrapped.ptr;
- } else {
- // Combine last linear bytes + first wrapped bytes to form fsdev bus width data
- fsdev_bus_t temp;
- dcd_read_packet_memory(&temp, src, FSDEV_BUS_SIZE);
- src += FSDEV_BUS_SIZE;
-
- uint16_t i;
- for (i = 0; i < lin_odd; i++) {
- *dst8++ = (uint8_t) (temp & 0xfful);
- temp >>= 8;
- }
-
- dst8 = (uint8_t *) info.wrapped.ptr;
- for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) {
- *dst8++ = (uint8_t) (temp & 0xfful);
- temp >>= 8;
- }
- }
-
- // read the rest of the wrapped part
- dcd_read_packet_memory(dst8, src, cnt_wrap);
-
- tu_fifo_advance_write_pointer(ff, cnt_total);
- return true;
+void dcd_disconnect(uint8_t rhport) {
+ fsdev_disconnect(rhport);
}
+ #endif
#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h
index deb1de2a8..e75430396 100644
--- a/src/portable/st/stm32_fsdev/fsdev_at32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_at32.h
@@ -35,7 +35,6 @@
#endif
-#define FSDEV_PMA_SIZE (512u)
#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
@@ -150,8 +149,6 @@
#define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */
#define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK)
-#include "fsdev_type.h"
-
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -168,7 +165,7 @@ enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) };
#error "Unsupported MCU"
#endif
-void dcd_int_enable(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_enable(uint8_t rhport) {
(void)rhport;
#if (CFG_TUSB_MCU == OPT_MCU_AT32F403A_407) || (CFG_TUSB_MCU == OPT_MCU_AT32F413)
// AT32F403A/407 devices allow to remap the USB interrupt vectors from
@@ -187,7 +184,7 @@ void dcd_int_enable(uint8_t rhport) {
}
}
-void dcd_int_disable(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) {
(void)rhport;
#if (CFG_TUSB_MCU == OPT_MCU_AT32F403A_407) || (CFG_TUSB_MCU == OPT_MCU_AT32F413)
// AT32F403A/407 devices allow to remap the USB interrupt vectors from
@@ -206,20 +203,20 @@ void dcd_int_disable(uint8_t rhport) {
}
}
-void dcd_disconnect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) {
(void) rhport;
/* disable usb phy */
- FSDEV_REG->CNTR |= USB_CNTR_PDWN;
+ *(volatile uint32_t*)(FSDEV_REG_BASE + 0x40) |= USB_CNTR_PDWN;
/* D+ 1.5k pull-up disable, USB->cfg_bit.puo = TRUE; */
- *(uint32_t *)(FSDEV_REG_BASE+0x60) |= (1u<<1);
+ *(volatile uint32_t *)(FSDEV_REG_BASE+0x60) |= (1u<<1);
}
-void dcd_connect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) {
(void) rhport;
/* enable usb phy */
- FSDEV_REG->CNTR &= ~USB_CNTR_PDWN;
+ *(volatile uint32_t*)(FSDEV_REG_BASE + 0x40) &= ~USB_CNTR_PDWN;
/* Dp 1.5k pull-up enable, USB->cfg_bit.puo = 0; */
- *(uint32_t *)(FSDEV_REG_BASE+0x60) &= ~(1u<<1);
+ *(volatile uint32_t *)(FSDEV_REG_BASE+0x60) &= ~(1u<<1);
}
#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h
index ceebb6dab..37ea7808e 100644
--- a/src/portable/st/stm32_fsdev/fsdev_ch32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h
@@ -53,7 +53,6 @@
#pragma GCC diagnostic pop
#endif
-#define FSDEV_PMA_SIZE (512u)
#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
@@ -168,7 +167,6 @@
#define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */
#define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK)
-
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -184,26 +182,26 @@ enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) };
#error "Unsupported MCU"
#endif
-void dcd_int_enable(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_enable(uint8_t rhport) {
(void)rhport;
for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) {
NVIC_EnableIRQ(fsdev_irq[i]);
}
}
-void dcd_int_disable(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) {
(void)rhport;
for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) {
NVIC_DisableIRQ(fsdev_irq[i]);
}
}
-void dcd_disconnect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) {
(void) rhport;
EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN;
}
-void dcd_connect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) {
(void) rhport;
EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN;
}
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c
new file mode 100644
index 000000000..4f127ae86
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/fsdev_common.c
@@ -0,0 +1,116 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Ha Thach (tinyusb.org)
+ * Copyright (c) 2025, HiFiPhile (Zixun LI)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if defined(TUP_USBIP_FSDEV) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
+
+#include "fsdev_common.h"
+
+//--------------------------------------------------------------------+
+// Global
+//--------------------------------------------------------------------+
+
+// Reset the USB Core
+void fsdev_core_reset(void) {
+ // Perform USB peripheral reset
+ FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
+ asm("NOP");
+ }
+
+ FSDEV_REG->CNTR &= ~USB_CNTR_PDWN;
+
+ // Wait startup time, for F042 and F070, this is <= 1 us.
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
+ asm("NOP");
+ }
+
+ // Clear pending interrupts
+ FSDEV_REG->ISTR = 0;
+}
+
+// De-initialize the USB Core
+void fsdev_deinit(void) {
+ // Disable all interrupts and force USB reset
+ FSDEV_REG->CNTR = USB_CNTR_FRES;
+
+ // Clear pending interrupts
+ FSDEV_REG->ISTR = 0;
+
+ // Put USB peripheral in power down mode
+ FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
+ asm("NOP");
+ }
+}
+
+//--------------------------------------------------------------------+
+// BTable Helper
+//--------------------------------------------------------------------+
+
+// Aligned buffer size according to hardware
+uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) {
+ /* The STM32 full speed USB peripheral supports only a limited set of
+ * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
+ uint16_t block_in_bytes;
+ if (size > 62) {
+ block_in_bytes = 32;
+ *blsize = 1;
+ *num_block = tu_div_ceil(size, 32);
+ } else {
+ block_in_bytes = 2;
+ *blsize = 0;
+ *num_block = tu_div_ceil(size, 2);
+ }
+
+ return (*num_block) * block_in_bytes;
+}
+
+// Set RX buffer size
+void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) {
+ uint8_t blsize, num_block;
+ (void) pma_align_buffer_size(wCount, &blsize, &num_block);
+
+ /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
+ uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10);
+ if (bl_nb == 0) {
+ // zlp but 0 is invalid value, set blsize to 1 (32 bytes)
+ // Note: lower value can cause PMAOVR on setup with ch32v203
+ bl_nb = 1 << 15;
+ }
+
+#ifdef FSDEV_BUS_32BIT
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu);
+ FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
+#else
+ FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb;
+#endif
+}
+
+#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_type.h b/src/portable/st/stm32_fsdev/fsdev_common.h
index cf36576bb..c53e345b0 100644
--- a/src/portable/st/stm32_fsdev/fsdev_type.h
+++ b/src/portable/st/stm32_fsdev/fsdev_common.h
@@ -1,8 +1,9 @@
/*
* The MIT License (MIT)
*
- * Copyright(c) N Conrad
- * Copyright(c) 2024, hathach (tinyusb.org)
+ * Copyright (c) N Conrad
+ * Copyright (c) 2024, hathach (tinyusb.org)
+ * Copyright (c) 2025, HiFiPhile (Zixun LI)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,53 +26,67 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef TUSB_FSDEV_TYPE_H
-#define TUSB_FSDEV_TYPE_H
+#ifndef TUSB_FSDEV_COMMON_H
+#define TUSB_FSDEV_COMMON_H
-#ifdef __cplusplus
- extern "C" {
+#include "common/tusb_common.h"
+
+#if CFG_TUD_ENABLED
+ #include "device/dcd.h"
+#endif
+
+#if CFG_TUH_ENABLED
+ #include "host/hcd.h"
+#endif
+
+#if defined(TUP_USBIP_FSDEV_STM32)
+ #include "fsdev_stm32.h"
+#elif defined(TUP_USBIP_FSDEV_CH32)
+ #include "fsdev_ch32.h"
+#elif defined(TUP_USBIP_FSDEV_AT32)
+ #include "fsdev_at32.h"
+#else
+ #error "Unknown USB IP"
#endif
-#include "stdint.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
// Both of these MUST be a multiple of 2, and are in byte units.
#ifndef FSDEV_BTABLE_BASE
-#define FSDEV_BTABLE_BASE 0U
+ #define FSDEV_BTABLE_BASE 0U
#endif
TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes");
-// FSDEV_PMA_SIZE is PMA buffer size in bytes.
+// CFG_TUSB_FSDEV_PMA_SIZE is PMA buffer size in bytes.
// - 512-byte devices, access with a stride of two words (use every other 16-bit address)
// - 1024-byte devices, access with a stride of one word (use every 16-bit address)
// - 2048-byte devices, access with 32-bit address
// For purposes of accessing the packet
-#if FSDEV_PMA_SIZE == 512
+#if CFG_TUSB_FSDEV_PMA_SIZE == 512
// 1x16 bit / word access scheme
#define FSDEV_PMA_STRIDE 2
#define pma_access_scheme TU_ATTR_ALIGNED(4)
-#elif FSDEV_PMA_SIZE == 1024
+#elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
// 2x16 bit / word access scheme
- #define FSDEV_PMA_STRIDE 1
+ #define FSDEV_PMA_STRIDE 1
#define pma_access_scheme
-#elif FSDEV_PMA_SIZE == 2048
+#elif CFG_TUSB_FSDEV_PMA_SIZE == 2048
// 32 bit access scheme
#define FSDEV_BUS_32BIT
- #define FSDEV_PMA_STRIDE 1
+ #define FSDEV_PMA_STRIDE 1
#define pma_access_scheme
#endif
// The fsdev_bus_t type can be used for both register and PMA access necessities
#ifdef FSDEV_BUS_32BIT
- typedef uint32_t fsdev_bus_t;
- #define fsdevbus_unaligned_read(_addr) tu_unaligned_read32(_addr)
- #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write32(_addr, _value)
+typedef uint32_t fsdev_bus_t;
#else
- typedef uint16_t fsdev_bus_t;
- #define fsdevbus_unaligned_read(_addr) tu_unaligned_read16(_addr)
- #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write16(_addr, _value)
+typedef uint16_t fsdev_bus_t;
#endif
enum {
@@ -105,74 +120,77 @@ typedef union {
} ep32[FSDEV_EP_COUNT][2];
} fsdev_btable_t;
-TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct");
-TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
+TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT * 8 * FSDEV_PMA_STRIDE, "size is not correct");
+TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT * 8 <= CFG_TUSB_FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
-#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(FSDEV_BTABLE_BASE)))
+#define FSDEV_BTABLE ((volatile fsdev_btable_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (FSDEV_BTABLE_BASE)))
typedef struct {
volatile pma_access_scheme fsdev_bus_t value;
} fsdev_pma_buf_t;
-#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(_addr)))
+#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (_addr)))
//--------------------------------------------------------------------+
// Registers Typedef
//--------------------------------------------------------------------+
// volatile 32-bit aligned
-#define _va32 volatile TU_ATTR_ALIGNED(4)
+#define _va32 volatile TU_ATTR_ALIGNED(4)
typedef struct {
struct {
_va32 fsdev_bus_t reg;
- }ep[FSDEV_EP_COUNT];
+ } ep[FSDEV_EP_COUNT];
- _va32 uint32_t RESERVED7[8]; // Reserved
- _va32 fsdev_bus_t CNTR; // 40: Control register
- _va32 fsdev_bus_t ISTR; // 44: Interrupt status register
- _va32 fsdev_bus_t FNR; // 48: Frame number register
- _va32 fsdev_bus_t DADDR; // 4C: Device address register
- _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only)
- _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
- _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
+ _va32 uint32_t RESERVED7[8]; // Reserved
+ _va32 fsdev_bus_t CNTR; // 40: Control register
+ _va32 fsdev_bus_t ISTR; // 44: Interrupt status register
+ _va32 fsdev_bus_t FNR; // 48: Frame number register
+ _va32 fsdev_bus_t DADDR; // 4C: Device address register
+ _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only)
+ _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
+ _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
} fsdev_regs_t;
TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset");
TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct");
-#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE)
+#define FSDEV_REG ((fsdev_regs_t *)FSDEV_REG_BASE)
#ifndef USB_EPTX_STAT
-#define USB_EPTX_STAT 0x0030U
+ #define USB_EPTX_STAT 0x0030U
#endif
#ifndef USB_EPRX_STAT
-#define USB_EPRX_STAT 0x3000U
+ #define USB_EPRX_STAT 0x3000U
#endif
#ifndef USB_EPTX_STAT_Pos
-#define USB_EPTX_STAT_Pos 4u
+ #define USB_EPTX_STAT_Pos 4u
#endif
#ifndef USB_EP_DTOG_TX_Pos
-#define USB_EP_DTOG_TX_Pos 6u
+ #define USB_EP_DTOG_TX_Pos 6u
#endif
#ifndef USB_EP_CTR_TX_Pos
-#define USB_EP_CTR_TX_Pos 7u
+ #define USB_EP_CTR_TX_Pos 7u
#endif
typedef enum {
EP_STAT_DISABLED = 0,
- EP_STAT_STALL = 1,
- EP_STAT_NAK = 2,
- EP_STAT_VALID = 3
-}ep_stat_t;
+ EP_STAT_STALL = 1,
+ EP_STAT_NAK = 2,
+ EP_STAT_VALID = 3
+} ep_stat_t;
+
+#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
+#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
-#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
-#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8)))
+#define CH_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
+#define CH_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
//--------------------------------------------------------------------+
// Endpoint Helper
@@ -186,13 +204,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) {
TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value, bool need_exclusive) {
if (need_exclusive) {
- dcd_int_disable(0);
+ fsdev_int_disable(0);
}
- FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value;
+ FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t)value;
if (need_exclusive) {
- dcd_int_enable(0);
+ fsdev_int_enable(0);
}
}
@@ -204,11 +222,11 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_write_clear_ctr(uint32_t ep_id, tusb
ep_write(ep_id, reg, false);
}
-TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) {
+TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t *reg, tusb_dir_t dir, ep_stat_t state) {
*reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
}
-TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) {
+TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t *reg, tusb_dir_t dir, uint8_t state) {
*reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
}
@@ -217,6 +235,35 @@ TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(uint32_t reg) {
}
//--------------------------------------------------------------------+
+// Channel Helper
+// - Direction is opposite to endpoint direction
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t ch_read(uint32_t ch_id) {
+ return ep_read(ch_id);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ch_write(uint32_t ch_id, uint32_t value, bool need_exclusive) {
+ ep_write(ch_id, value, need_exclusive);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ch_write_clear_ctr(uint32_t ch_id, tusb_dir_t dir) {
+ uint32_t reg = FSDEV_REG->ep[ch_id].reg;
+ reg |= USB_EP_CTR_TX | USB_EP_CTR_RX;
+ reg &= USB_EPREG_MASK;
+ reg &= ~(1 << (USB_EP_CTR_TX_Pos + (dir == TUSB_DIR_IN ? 8 : 0)));
+ ep_write(ch_id, reg, false);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ch_change_status(uint32_t *reg, tusb_dir_t dir, ep_stat_t state) {
+ *reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 8 : 0)));
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t *reg, tusb_dir_t dir, uint8_t state) {
+ *reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 8 : 0)));
+}
+
+//--------------------------------------------------------------------+
// BTable Helper
//--------------------------------------------------------------------+
@@ -230,8 +277,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uin
TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) {
#ifdef FSDEV_BUS_32BIT
- uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
- count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
#else
FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr;
@@ -250,58 +297,30 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, ui
TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) {
#ifdef FSDEV_BUS_32BIT
- uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
- count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
#else
- uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
- cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
+ uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
+ cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt;
#endif
}
-/* Aligned buffer size according to hardware */
-TU_ATTR_ALWAYS_INLINE static inline uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) {
- /* The STM32 full speed USB peripheral supports only a limited set of
- * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
- uint16_t block_in_bytes;
- if (size > 62) {
- block_in_bytes = 32;
- *blsize = 1;
- *num_block = tu_div_ceil(size, 32);
- } else {
- block_in_bytes = 2;
- *blsize = 0;
- *num_block = tu_div_ceil(size, 2);
- }
-
- return (*num_block) * block_in_bytes;
-}
-
-TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) {
- uint8_t blsize, num_block;
- (void) pma_align_buffer_size(wCount, &blsize, &num_block);
+// Reset the USB Core
+void fsdev_core_reset(void);
- /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
- uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10);
- if (bl_nb == 0) {
- // zlp but 0 is invalid value, set blsize to 1 (32 bytes)
- // Note: lower value can cause PMAOVR on setup with ch32v203
- bl_nb = 1 << 15;
- }
+// De-initialize the USB Core
+void fsdev_deinit(void);
-#ifdef FSDEV_BUS_32BIT
- uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
- count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu);
- FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
-#else
- FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb;
-#endif
+// Aligned buffer size according to hardware
+uint16_t pma_align_buffer_size(uint16_t size, uint8_t *blsize, uint8_t *num_block);
-}
+// Set RX buffer size
+void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount);
#ifdef __cplusplus
- }
+}
#endif
-#endif
+#endif /* TUSB_FSDEV_COMMON_H */
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
index e7a57aca0..02dba05a6 100644
--- a/src/portable/st/stm32_fsdev/fsdev_stm32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -32,10 +32,23 @@
#ifndef TUSB_FSDEV_STM32_H
#define TUSB_FSDEV_STM32_H
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0
+#if CFG_TUSB_MCU == OPT_MCU_STM32C0
+ #include "stm32c0xx.h"
+ #define FSDEV_HAS_SBUF_ISO 1
+ #define USB USB_DRD_FS
+ #define USB_EP_CTR_RX USB_CHEP_VTRX
+ #define USB_EP_CTR_TX USB_CHEP_VTTX
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F0
#include "stm32f0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_REG_BASE USB_BASE
+ #define FSDEV_REG_BASE USB_BASE
#define FSDEV_HAS_SBUF_ISO 0
// F0x2 models are crystal-less
// All have internal D+ pull-up
@@ -44,29 +57,24 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
#include "stm32f1xx.h"
- #define FSDEV_PMA_SIZE (512u)
#define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 2 x 16 bits/word
// F1 names this differently from the rest
- #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
+ #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
-#elif defined(STM32F302xB) || defined(STM32F302xC) || \
- defined(STM32F303xB) || defined(STM32F303xC) || \
- defined(STM32F373xC)
+#elif defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
#include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (512u)
#define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 1 x 16 bits/word
// PMA dedicated to USB (no sharing with CAN)
-#elif defined(STM32F302x6) || defined(STM32F302x8) || \
- defined(STM32F302xD) || defined(STM32F302xE) || \
- defined(STM32F303xD) || defined(STM32F303xE)
+#elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
#include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (1024u)
#define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
@@ -74,28 +82,32 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
#include "stm32l0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
#define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
#include "stm32l1xx.h"
- #define FSDEV_PMA_SIZE (512u)
#define FSDEV_HAS_SBUF_ISO 0
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- #include "stm32g4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+ #include "stm32l4xx.h"
+ #define FSDEV_HAS_SBUF_ISO 0
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ #include "stm32l5xx.h"
#define FSDEV_HAS_SBUF_ISO 0
+ #ifndef USB_PMAADDR
+ #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
+ #endif
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
#include "stm32g0xx.h"
- #define FSDEV_PMA_SIZE (2048u)
- #define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
+ #define FSDEV_HAS_SBUF_ISO 1
+ #define USB USB_DRD_FS
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
#define USB_EPREG_MASK USB_CHEP_REG_MASK
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
@@ -110,78 +122,20 @@
#define USB_ISTR_EP_ID USB_ISTR_IDN
#define USB_EPADDR_FIELD USB_CHEP_ADDR
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
- #include "stm32c0xx.h"
- #define FSDEV_PMA_SIZE (2048u)
- #define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
- #define USB_EP_CTR_RX USB_CHEP_VTRX
- #define USB_EP_CTR_TX USB_CHEP_VTTX
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+ #include "stm32g4xx.h"
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
#include "stm32h5xx.h"
- #define FSDEV_PMA_SIZE (2048u)
#define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
+ #define USB USB_DRD_FS
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
- #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
- #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
- #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
- #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- #include "stm32wbxx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_HAS_SBUF_ISO 0
- /* ST provided header has incorrect value of USB_PMAADDR */
- #define FSDEV_PMA_BASE USB1_PMAADDR
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
- #include "stm32l4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_HAS_SBUF_ISO 0
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- #include "stm32l5xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_HAS_SBUF_ISO 0
-
- #ifndef USB_PMAADDR
- #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
- #endif
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
- #include "stm32u5xx.h"
- #define FSDEV_PMA_SIZE (2048u)
- #define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
-
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
#define USB_EPREG_MASK USB_CHEP_REG_MASK
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
@@ -200,7 +154,6 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U0
#include "stm32u0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
#define FSDEV_BUS_32BIT
#define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
@@ -226,10 +179,9 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U3
#include "stm32u3xx.h"
- #define FSDEV_PMA_SIZE (2048u)
#define FSDEV_BUS_32BIT
#define FSDEV_HAS_SBUF_ISO 1 // This is assumed to work but has not been tested...
- #define USB USB_DRD_FS
+ #define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
#define USB_EP_CTR_TX USB_EP_VTTX
@@ -240,15 +192,45 @@
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #include "stm32u5xx.h"
+ #define FSDEV_HAS_SBUF_ISO 1
+ #define USB USB_DRD_FS
+
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
+ #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
+ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
+ #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
+ #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ #include "stm32wbxx.h"
+ #define FSDEV_HAS_SBUF_ISO 0
+ /* ST provided header has incorrect value of USB_PMAADDR */
+ #define FSDEV_PMA_BASE USB1_PMAADDR
#else
#error You are using an untested or unimplemented STM32 variant. Please update the driver.
@@ -299,7 +281,7 @@
// - Enable double buffering on devices with >1KB Packet Memory Area (PMA)
// to improve isochronous transfer reliability and performance
// - Disable on devices with limited PMA to conserve memory space
- #if FSDEV_PMA_SIZE > 1024u
+ #if CFG_TUSB_FSDEV_PMA_SIZE > 1024u
#define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 1
#else
#define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
@@ -371,7 +353,7 @@ static const IRQn_Type fsdev_irq[] = {
};
enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) };
-void dcd_int_enable(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_enable(uint8_t rhport) {
(void)rhport;
// forces write to RAM before allowing ISR to execute
@@ -394,7 +376,7 @@ void dcd_int_enable(uint8_t rhport) {
}
}
-void dcd_int_disable(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) {
(void)rhport;
#if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP)
@@ -419,28 +401,27 @@ void dcd_int_disable(uint8_t rhport) {
// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
#if defined(USB_BCDR_DPPU)
-void dcd_disconnect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) {
(void)rhport;
USB->BCDR &= ~(USB_BCDR_DPPU);
}
-void dcd_connect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) {
(void)rhport;
USB->BCDR |= USB_BCDR_DPPU;
}
#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
-void dcd_disconnect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) {
(void)rhport;
SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
}
-void dcd_connect(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) {
(void)rhport;
SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
}
#endif
-
#endif /* TUSB_FSDEV_STM32_H */
diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
new file mode 100644
index 000000000..acdeccf6d
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
@@ -0,0 +1,878 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 HiFiPhile (Zixun LI)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/**********************************************
+ * This driver provides USB Host controller support for STM32 MCUs with "USB A"/"PCD"/"HCD" peripheral.
+ * This covers these MCU families:
+ *
+ * C0 2048 byte buffer; 32-bit bus; host mode
+ * G0 2048 byte buffer; 32-bit bus; host mode
+ * U3 2048 byte buffer; 32-bit bus; host mode
+ * H5 2048 byte buffer; 32-bit bus; host mode
+ * U535, U545 2048 byte buffer; 32-bit bus; host mode
+ *
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_FSDEV) && \
+ TU_CHECK_MCU(OPT_MCU_STM32C0, OPT_MCU_STM32G0, OPT_MCU_STM32H5, OPT_MCU_STM32U5)
+
+#include "host/hcd.h"
+#include "host/usbh.h"
+#include "fsdev_common.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// Debug level for FSDEV
+#define FSDEV_DEBUG 3
+
+// Max number of endpoints application can open, can be larger than FSDEV_EP_COUNT
+#ifndef CFG_TUH_FSDEV_ENDPOINT_MAX
+ #define CFG_TUH_FSDEV_ENDPOINT_MAX 16u
+#endif
+
+TU_VERIFY_STATIC(CFG_TUH_FSDEV_ENDPOINT_MAX <= 255, "currently only use 8-bit for index");
+
+#if CFG_TUSB_MCU == OPT_MCU_STM32H5
+ #define CPU_FREQUENCY_MHZ 250U
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #define CPU_FREQUENCY_MHZ 160U
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U3
+ #define CPU_FREQUENCY_MHZ 96U
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+ #define CPU_FREQUENCY_MHZ 64U
+#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
+ #define CPU_FREQUENCY_MHZ 48U
+#else
+ #error "CPU_FREQUENCY_MHZ not defined for this STM32 MCU"
+#endif
+
+enum {
+ HCD_XFER_ERROR_MAX = 3,
+ HCD_XFER_NAK_MAX = 15,
+ HCD_XFER_NAK_DEFAULT = 3,
+};
+
+// Host driver struct for each opened endpoint
+typedef struct {
+ uint8_t *buffer;
+ uint16_t buflen;
+ uint16_t queued_len;
+ uint16_t max_packet_size;
+ uint8_t dev_addr;
+ uint8_t ep_addr;
+ uint8_t ep_type;
+ uint8_t interval;
+ struct TU_ATTR_PACKED {
+ uint8_t ls_pre : 1;
+ uint8_t allocated : 1;
+ uint8_t next_setup : 1;
+ uint8_t pid : 1;
+ };
+} hcd_endpoint_t;
+
+// Channel direction state
+typedef struct {
+ hcd_endpoint_t* edpt;
+ struct TU_ATTR_PACKED {
+ uint8_t allocated : 1;
+ uint8_t retry : 3;
+ uint8_t nak : 4; // Max NAK count in current frame
+ };
+} hcd_channel_dir_t;
+
+// Additional info for each channel when it is active
+typedef struct {
+ uint8_t dev_addr;
+ uint8_t ep_num;
+ uint8_t ep_type;
+ hcd_channel_dir_t out, in;
+} hcd_channel_t;
+
+static struct {
+ hcd_channel_t channel[FSDEV_EP_COUNT];
+ hcd_endpoint_t edpt[CFG_TUH_FSDEV_ENDPOINT_MAX];
+ bool connected;
+} _hcd_data;
+
+static tuh_configure_fsdev_t _tuh_cfg = {
+ .max_nak = HCD_XFER_NAK_DEFAULT,
+};
+
+//--------------------------------------------------------------------+
+// Prototypes
+//--------------------------------------------------------------------+
+
+static uint8_t endpoint_alloc(void);
+static uint8_t endpoint_find(uint8_t dev_addr, uint8_t ep_addr);
+static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len);
+static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type);
+static bool edpt_xfer_kickoff(uint8_t ep_id);
+static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir);
+static void edpoint_close(uint8_t ep_id);
+static void port_status_handler(uint8_t rhport, bool in_isr);
+static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir);
+static void ch_handle_nak(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir);
+static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir);
+static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir);
+
+//--------------------------------------------------------------------+
+// Inline Functions
+//--------------------------------------------------------------------+
+
+static inline void endpoint_dealloc(hcd_endpoint_t* edpt) {
+ edpt->allocated = 0;
+}
+
+static inline void channel_dealloc(hcd_channel_t* ch, tusb_dir_t dir) {
+ if (dir == TUSB_DIR_OUT) {
+ ch->out.allocated = 0;
+ } else {
+ ch->in.allocated = 0;
+ }
+}
+
+// Write channel state in specified direction
+static inline void channel_write_status(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir, ep_stat_t state, bool need_exclusive) {
+ ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir);
+ ch_change_status(&ch_reg, dir, state);
+ ch_write(ch_id, ch_reg, need_exclusive);
+}
+
+static inline uint16_t channel_get_rx_count(uint8_t ch_id) {
+ /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
+ * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf
+ * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers
+ * Description:
+ * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
+ * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
+ * Workaround:
+ * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
+ * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
+ *
+ * Note: this errata may also apply to G0, U5, H5 etc.
+ *
+ * We choose the delay count based on max CPU frequency (in MHz) to ensure the delay is at least the required time.
+ */
+
+ uint32_t ch_reg = ch_read(ch_id);
+ if (FSDEV_REG->ISTR & USB_ISTR_LS_DCONN || ch_reg & USB_CHEP_LSEP) {
+ // Low speed mode: 6.4 us delay -> about 2 cycles per MHz
+ volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ * 2U;
+ while (cycle_count > 0U) {
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
+ }
+ } else {
+ // Full speed mode: 800 ns delay -> about 0.25 cycles per MHz
+ volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ / 4U;
+ while (cycle_count > 0U) {
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
+ }
+ }
+
+ return btable_get_count(ch_id, BTABLE_BUF_RX);
+}
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+// Optional HCD configuration, called by tuh_configure()
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
+ (void) rhport;
+ TU_VERIFY(cfg_id == TUH_CFGID_FSDEV && cfg_param != NULL);
+
+ tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param;
+ _tuh_cfg.max_nak = tu_min8(cfg->fsdev.max_nak, HCD_XFER_NAK_MAX);
+ return true;
+}
+
+// Initialize controller to host mode
+bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
+ (void) rh_init;
+
+ fsdev_core_reset();
+
+ FSDEV_REG->CNTR = USB_CNTR_HOST; // Enable USB in Host mode
+
+ tu_memclr(&_hcd_data, sizeof(_hcd_data));
+
+ // Enable interrupts for host mode
+ FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SOFM | USB_CNTR_SUSPM |
+ USB_CNTR_WKUPM | USB_CNTR_ERRM | USB_CNTR_PMAOVRM;
+
+ // Initialize port state
+ _hcd_data.connected = false;
+
+ fsdev_connect(rhport);
+
+ // If DCON_STAT is already set, the controller sometimes misses the initial connection interrupt
+ if (FSDEV_REG->ISTR & USB_ISTR_DCON_STAT) {
+ // Wait DP/DM stabilize time
+ volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ / 4U;
+ while (cycle_count > 0U) {
+ cycle_count--;
+ }
+ port_status_handler(rhport, false);
+ }
+
+ return true;
+}
+
+bool hcd_deinit(uint8_t rhport) {
+ (void)rhport;
+
+ fsdev_disconnect(rhport);
+
+ fsdev_deinit();
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// Interrupt Helper Functions
+//--------------------------------------------------------------------+
+
+static inline void sof_handler(void) {
+ // Reset NAK counters for all active channels
+ for (uint8_t ch_id = 0; ch_id < FSDEV_EP_COUNT; ch_id++) {
+ hcd_channel_t* channel = &_hcd_data.channel[ch_id];
+ if (channel->out.allocated) {
+ channel->out.nak = 0;
+ }
+ if (channel->in.allocated) {
+ channel->in.nak = 0;
+ }
+ }
+}
+
+static void port_status_handler(uint8_t rhport, bool in_isr) {
+ uint32_t const fnr_reg = FSDEV_REG->FNR;
+ uint32_t const istr_reg = FSDEV_REG->ISTR;
+ // SE0 detected USB Disconnected state
+ if ((fnr_reg & (USB_FNR_RXDP | USB_FNR_RXDM)) == 0U) {
+ _hcd_data.connected = false;
+ hcd_event_device_remove(rhport, in_isr);
+ return;
+ }
+
+ if (!_hcd_data.connected) {
+ // J-state or K-state detected & LastState=Disconnected
+ if (((fnr_reg & USB_FNR_RXDP) != 0U) || ((istr_reg & USB_ISTR_LS_DCONN) != 0U)) {
+ _hcd_data.connected = true;
+ hcd_event_device_attach(rhport, in_isr);
+ }
+ } else {
+ // J-state or K-state detected & lastState=Connected: a Missed disconnection is detected
+ if (((fnr_reg & USB_FNR_RXDP) != 0U) || ((istr_reg & USB_ISTR_LS_DCONN) != 0U)) {
+ _hcd_data.connected = false;
+ hcd_event_device_remove(rhport, in_isr);
+ }
+ }
+}
+
+// Handle ACK response
+static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
+ uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD;
+ uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos;
+
+ uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0));
+ if (ep_id == TUSB_INDEX_INVALID_8) {
+ return;
+ }
+
+ hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id];
+ hcd_channel_t *channel = &_hcd_data.channel[ch_id];
+
+ if (dir == TUSB_DIR_OUT) {
+ // OUT/TX direction
+ if (edpt->buflen != edpt->queued_len) {
+ // More data to send
+ uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size);
+ uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX);
+ tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL);
+ btable_set_count(ch_id, BTABLE_BUF_TX, len);
+ edpt->queued_len += len;
+ channel_write_status(ch_id, ch_reg, TUSB_DIR_OUT, EP_STAT_VALID, false);
+ channel->out.nak = 0;
+ } else {
+ // Transfer complete
+ channel_dealloc(channel, TUSB_DIR_OUT);
+ edpt->pid = (ch_reg & USB_CHEP_DTOG_TX) ? 1 : 0;
+ hcd_event_xfer_complete(daddr, ep_num, edpt->queued_len, XFER_RESULT_SUCCESS, true);
+ }
+ } else {
+ // IN/RX direction
+ uint16_t const rx_count = channel_get_rx_count(ch_id);
+ uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX);
+ tu_hwfifo_read(PMA_BUF_AT(pma_addr), edpt->buffer + edpt->queued_len, rx_count, NULL);
+ edpt->queued_len += rx_count;
+
+ if ((rx_count < edpt->max_packet_size) || (edpt->queued_len >= edpt->buflen)) {
+ // Transfer complete (short packet or all bytes received)
+ channel_dealloc(channel, TUSB_DIR_IN);
+ edpt->pid = (ch_reg & USB_CHEP_DTOG_RX) ? 1 : 0;
+ hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, edpt->queued_len, XFER_RESULT_SUCCESS, true);
+ } else {
+ // More data expected
+ uint16_t const cnt = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size);
+ btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, cnt);
+ channel_write_status(ch_id, ch_reg, TUSB_DIR_IN, EP_STAT_VALID, false);
+ channel->in.nak = 0;
+ }
+ }
+}
+
+// Handle NAK response
+static void ch_handle_nak(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
+ uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD;
+ uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos;
+
+ uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0));
+ if (ep_id == TUSB_INDEX_INVALID_8) return;
+
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ // Retry non-periodic transfer immediately if NAK count not exceeded
+ // Periodic transfer will be retried by next frame automatically
+ if (edpt->ep_type == TUSB_XFER_CONTROL || edpt->ep_type == TUSB_XFER_BULK) {
+ hcd_channel_dir_t* channel_dir =
+ (dir == TUSB_DIR_OUT) ? &(_hcd_data.channel[ch_id].out) : &(_hcd_data.channel[ch_id].in);
+ if (channel_dir->nak < HCD_XFER_NAK_MAX) {
+ channel_dir->nak++;
+ }
+ if (channel_dir->nak < _tuh_cfg.max_nak || _tuh_cfg.max_nak == 0) {
+ channel_write_status(ch_id, ch_reg, dir, EP_STAT_VALID, false);
+ }
+ }
+}
+
+// Handle STALL response
+static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
+ uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD;
+ uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos;
+
+ uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0));
+ if (ep_id == TUSB_INDEX_INVALID_8) return;
+
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ hcd_channel_t* channel = &_hcd_data.channel[ch_id];
+ channel_dealloc(channel, dir);
+
+ channel_write_status(ch_id, ch_reg, dir, EP_STAT_DISABLED, false);
+
+ hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0),
+ edpt->queued_len, XFER_RESULT_STALLED, true);
+}
+
+// Handle error response
+static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
+ uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD;
+ uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos;
+
+ uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0));
+ if (ep_id == TUSB_INDEX_INVALID_8) return;
+
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ hcd_channel_t* channel = &_hcd_data.channel[ch_id];
+
+ ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir);
+ ch_reg &= ~(dir == TUSB_DIR_OUT ? USB_CH_ERRTX : USB_CH_ERRRX);
+
+ hcd_channel_dir_t* channel_dir =
+ (dir == TUSB_DIR_OUT) ? &(_hcd_data.channel[ch_id].out) : &(_hcd_data.channel[ch_id].in);
+ if (channel_dir->retry < HCD_XFER_ERROR_MAX) {
+ // Retry
+ channel_dir->retry++;
+ ch_change_status(&ch_reg, dir, EP_STAT_VALID);
+ } else {
+ // Failed after retries
+ channel_dealloc(channel, dir);
+ ch_change_status(&ch_reg, dir, EP_STAT_DISABLED);
+ hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0),
+ edpt->queued_len, XFER_RESULT_FAILED, true);
+ }
+ ch_write(ch_id, ch_reg, false);
+}
+
+// Handle CTR interrupt for the TX/OUT direction
+static inline void handle_ctr_tx(uint32_t ch_id) {
+ uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ hcd_channel_t* channel = &_hcd_data.channel[ch_id];
+ TU_VERIFY(channel->out.allocated == 1,);
+
+ if ((ch_reg & USB_CH_ERRTX) == 0U) {
+ // No error
+ if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_ACK_SBUF) {
+ ch_handle_ack(ch_id, ch_reg, TUSB_DIR_OUT);
+ } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_NAK) {
+ ch_handle_nak(ch_id, ch_reg, TUSB_DIR_OUT);
+ } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_STALL) {
+ ch_handle_stall(ch_id, ch_reg, TUSB_DIR_OUT);
+ }
+ } else {
+ ch_handle_error(ch_id, ch_reg, TUSB_DIR_OUT);
+ }
+}
+
+// Handle CTR interrupt for the RX/IN direction
+static inline void handle_ctr_rx(uint32_t ch_id) {
+ uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ hcd_channel_t* channel = &_hcd_data.channel[ch_id];
+ TU_VERIFY(channel->in.allocated == 1,);
+
+ if ((ch_reg & USB_CH_ERRRX) == 0U) {
+ // No error
+ if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_ACK_SBUF) {
+ ch_handle_ack(ch_id, ch_reg, TUSB_DIR_IN);
+ } else if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_NAK) {
+ ch_handle_nak(ch_id, ch_reg, TUSB_DIR_IN);
+ } else if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_STALL){
+ ch_handle_stall(ch_id, ch_reg, TUSB_DIR_IN);
+ }
+ } else {
+ ch_handle_error(ch_id, ch_reg, TUSB_DIR_IN);
+ }
+}
+
+// Interrupt Handler
+void hcd_int_handler(uint8_t rhport, bool in_isr) {
+ uint32_t int_status = FSDEV_REG->ISTR;
+
+ // Start of Frame
+ if (int_status & USB_ISTR_SOF) {
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SOF;
+ sof_handler();
+ }
+
+ // Port Change Detected (Connection/Disconnection)
+ if (int_status & USB_ISTR_DCON) {
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_DCON;
+ port_status_handler(rhport, in_isr);
+ }
+
+ // Handle transfer complete (CTR)
+ while (FSDEV_REG->ISTR & USB_ISTR_CTR) {
+ uint32_t const ch_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
+ uint32_t const ch_reg = ch_read(ch_id);
+
+ if (ch_reg & USB_EP_CTR_RX) {
+ ch_write_clear_ctr(ch_id, TUSB_DIR_IN);
+ handle_ctr_rx(ch_id);
+ }
+
+ if (ch_reg & USB_EP_CTR_TX) {
+ ch_write_clear_ctr(ch_id, TUSB_DIR_OUT);
+ handle_ctr_tx(ch_id);
+ }
+ }
+
+ if (int_status & USB_ISTR_ERR) {
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ERR;
+ // TODO: Handle error
+ }
+
+ if (int_status & USB_ISTR_PMAOVR) {
+ TU_BREAKPOINT();
+ FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_PMAOVR;
+ }
+}
+
+// Enable USB interrupt
+void hcd_int_enable(uint8_t rhport) {
+ fsdev_int_enable(rhport);
+}
+
+// Disable USB interrupt
+void hcd_int_disable(uint8_t rhport) {
+ fsdev_int_disable(rhport);
+}
+
+// Get frame number (1ms)
+uint32_t hcd_frame_number(uint8_t rhport) {
+ (void) rhport;
+ return FSDEV_REG->FNR & USB_FNR_FN;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+// Get the current connect status of roothub port
+bool hcd_port_connect_status(uint8_t rhport) {
+ (void) rhport;
+ return _hcd_data.connected;
+}
+
+// Reset USB bus on the port
+void hcd_port_reset(uint8_t rhport) {
+ (void) rhport;
+ FSDEV_REG->CNTR |= USB_CNTR_FRES;
+}
+
+// Complete bus reset sequence
+void hcd_port_reset_end(uint8_t rhport) {
+ (void) rhport;
+ FSDEV_REG->CNTR &= ~USB_CNTR_FRES;
+}
+
+// Get port link speed
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
+ (void) rhport;
+ if ((FSDEV_REG->ISTR & USB_ISTR_LS_DCONN) != 0U) {
+ return TUSB_SPEED_LOW;
+ } else {
+ return TUSB_SPEED_FULL;
+ }
+}
+
+// HCD closes all opened endpoints belonging to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
+ (void) rhport;
+
+ // Close all endpoints for this device
+ for(uint32_t i = 0; i < CFG_TUH_FSDEV_ENDPOINT_MAX; i++) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[i];
+ if (edpt->allocated == 1 && edpt->dev_addr == dev_addr) {
+ edpoint_close(i);
+ }
+ }
+
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+// Open an endpoint
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc) {
+ (void) rhport;
+
+ uint8_t const ep_addr = ep_desc->bEndpointAddress;
+ uint16_t const packet_size = tu_edpt_packet_size(ep_desc);
+ uint8_t const ep_type = ep_desc->bmAttributes.xfer;
+
+ uint8_t const ep_id = endpoint_alloc();
+ TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8);
+
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ edpt->dev_addr = dev_addr;
+ edpt->ep_addr = ep_addr;
+ edpt->ep_type = ep_type;
+ edpt->max_packet_size = packet_size;
+ edpt->interval = ep_desc->bInterval;
+ edpt->pid = 0;
+ edpt->ls_pre = (hcd_port_speed_get(rhport) == TUSB_SPEED_FULL && tuh_speed_get(dev_addr) == TUSB_SPEED_LOW) ? 1 : 0;
+
+ return true;
+}
+
+bool hcd_edpt_close(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+
+ uint8_t const ep_id = endpoint_find(dev_addr, ep_addr);
+ TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8);
+
+ edpoint_close(ep_id);
+
+ return true;
+}
+
+// Submit a transfer
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) {
+ (void) rhport;
+
+ TU_LOG(FSDEV_DEBUG, "hcd_edpt_xfer addr=%u ep=0x%02X len=%u\r\n", dev_addr, ep_addr, buflen);
+
+ uint8_t const ep_id = endpoint_find(dev_addr, ep_addr);
+ TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8);
+
+ hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id];
+
+ edpt->buffer = buffer;
+ edpt->buflen = buflen;
+ edpt->queued_len = 0;
+
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ if (ep_num == 0) {
+ // update ep_dir since control endpoint can switch direction
+ edpt->ep_addr = ep_addr;
+ }
+
+ return edpt_xfer_kickoff(ep_id);
+}
+
+// Abort a queued transfer
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+
+ uint8_t const ep_id = endpoint_find(dev_addr, ep_addr);
+ TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+
+ for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
+ hcd_channel_t* channel = &_hcd_data.channel[i];
+ uint8_t const allocated = (dir == TUSB_DIR_OUT) ? channel->out.allocated : channel->in.allocated;
+
+ if (allocated == 1 &&
+ channel->dev_addr == dev_addr &&
+ channel->ep_num == tu_edpt_number(ep_addr)) {
+ channel_dealloc(channel, dir);
+ uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ channel_write_status(i, ch_reg, dir, EP_STAT_DISABLED, true);
+ }
+ }
+
+ return true;
+}
+
+// Submit a special transfer to send 8-byte Setup Packet
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) {
+ (void) rhport;
+
+ uint8_t const ep_id = endpoint_find(dev_addr, 0);
+ TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8);
+
+ hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id];
+ edpt->next_setup = true;
+ edpt->pid = 0;
+
+ return hcd_edpt_xfer(rhport, dev_addr, 0, (uint8_t*)(uintptr_t) setup_packet, 8);
+}
+
+// Clear stall, data toggle is also reset to DATA0
+bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
+ (void) rhport;
+ (void) dev_addr;
+ (void) ep_addr;
+
+ uint8_t const ep_id = endpoint_find(dev_addr, 0);
+ TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8);
+
+ hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id];
+ edpt->pid = 0;
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// Helper Functions
+//--------------------------------------------------------------------+
+
+static uint8_t endpoint_alloc(void) {
+ for (uint32_t i = 0; i < CFG_TUH_FSDEV_ENDPOINT_MAX; i++) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[i];
+ if (edpt->allocated == 0) {
+ edpt->allocated = 1;
+ return i;
+ }
+ }
+ return TUSB_INDEX_INVALID_8;
+}
+
+static uint8_t endpoint_find(uint8_t dev_addr, uint8_t ep_addr) {
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
+
+ for (uint32_t i = 0; i < (uint32_t)CFG_TUH_FSDEV_ENDPOINT_MAX; i++) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[i];
+ tusb_dir_t const dir = tu_edpt_dir(edpt->ep_addr);
+ uint8_t const num = tu_edpt_number(edpt->ep_addr);
+ // Match both ep_num and ep_dir, or match ep_num 0 (control endpoint)
+ if (edpt->allocated == 1 && edpt->dev_addr == dev_addr && num == ep_num &&
+ (dir == ep_dir || ep_num == 0)) {
+ return i;
+ }
+ }
+ return TUSB_INDEX_INVALID_8;
+}
+
+// close an opened endpoint
+static void edpoint_close(uint8_t ep_id) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ endpoint_dealloc(edpt);
+
+ // disable active channel belong to this endpoint
+ for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
+ hcd_channel_t* channel = &_hcd_data.channel[i];
+ uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ if (channel->out.allocated == 1 && channel->out.edpt == edpt) {
+ channel_dealloc(channel, TUSB_DIR_OUT);
+ channel_write_status(i, ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED, true);
+ }
+ if (channel->in.allocated == 1 && channel->in.edpt == edpt) {
+ channel_dealloc(channel, TUSB_DIR_IN);
+ channel_write_status(i, ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED, true);
+ }
+ }
+}
+
+// Allocate PMA buffer
+static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len) {
+ (void) len;
+ // Simple static allocation as we are unlikely to handle ISO endpoints in host mode
+ // We just give each channel two buffers of max packet size (64 bytes) for IN and OUT
+
+ uint16_t addr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT;
+ addr += channel * TUSB_EPSIZE_BULK_FS * 2 + (dir == TUSB_DIR_IN ? TUSB_EPSIZE_BULK_FS : 0);
+
+ TU_ASSERT(addr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF);
+
+ return addr;
+}
+
+// Allocate hardware channel
+static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) {
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+
+ // Find channel allocate for same ep_num but other direction
+ tusb_dir_t const other_dir = (dir == TUSB_DIR_IN) ? TUSB_DIR_OUT : TUSB_DIR_IN;
+ for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
+ uint8_t const allocated_dir = (dir == TUSB_DIR_OUT) ? _hcd_data.channel[i].out.allocated : _hcd_data.channel[i].in.allocated;
+ uint8_t const allocated_other = (other_dir == TUSB_DIR_OUT) ? _hcd_data.channel[i].out.allocated : _hcd_data.channel[i].in.allocated;
+ if (allocated_dir == 0 &&
+ allocated_other == 1 &&
+ _hcd_data.channel[i].dev_addr == dev_addr &&
+ _hcd_data.channel[i].ep_num == ep_num &&
+ _hcd_data.channel[i].ep_type == ep_type) {
+ if (dir == TUSB_DIR_OUT) {
+ _hcd_data.channel[i].out.allocated = 1;
+ _hcd_data.channel[i].out.retry = 0;
+ } else {
+ _hcd_data.channel[i].in.allocated = 1;
+ _hcd_data.channel[i].in.retry = 0;
+ }
+ return i;
+ }
+ }
+
+ // Find free channel
+ for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
+ if (_hcd_data.channel[i].out.allocated == 0 && _hcd_data.channel[i].in.allocated == 0) {
+ _hcd_data.channel[i].dev_addr = dev_addr;
+ _hcd_data.channel[i].ep_num = ep_num;
+ _hcd_data.channel[i].ep_type = ep_type;
+ if (dir == TUSB_DIR_OUT) {
+ _hcd_data.channel[i].out.allocated = 1;
+ _hcd_data.channel[i].out.retry = 0;
+ } else {
+ _hcd_data.channel[i].in.allocated = 1;
+ _hcd_data.channel[i].in.retry = 0;
+ }
+ return i;
+ }
+ }
+
+ // Allocation failed
+ return TUSB_INDEX_INVALID_8;
+}
+
+// kick-off transfer with an endpoint
+static bool edpt_xfer_kickoff(uint8_t ep_id) {
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+ uint8_t ch_id = channel_alloc(edpt->dev_addr, edpt->ep_addr, edpt->ep_type);
+ TU_ASSERT(ch_id != TUSB_INDEX_INVALID_8); // all channel are in used
+
+ tusb_dir_t const dir = tu_edpt_dir(edpt->ep_addr);
+ hcd_channel_t* channel = &_hcd_data.channel[ch_id];
+ if (dir == TUSB_DIR_OUT) {
+ channel->out.edpt = edpt;
+ } else {
+ channel->in.edpt = edpt;
+ }
+
+ return channel_xfer_start(ch_id, dir);
+}
+
+static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) {
+ hcd_channel_t* channel = &_hcd_data.channel[ch_id];
+ hcd_endpoint_t* edpt = (dir == TUSB_DIR_OUT) ? channel->out.edpt : channel->in.edpt;
+
+ uint32_t ch_reg = ch_read(ch_id) & ~USB_EPREG_MASK;
+ ch_reg |= tu_edpt_number(edpt->ep_addr) | edpt->dev_addr << USB_CHEP_DEVADDR_Pos |
+ USB_EP_CTR_TX | USB_EP_CTR_RX;
+
+ // Set type
+ switch (edpt->ep_type) {
+ case TUSB_XFER_BULK:
+ ch_reg |= USB_EP_BULK;
+ break;
+ case TUSB_XFER_INTERRUPT:
+ ch_reg |= USB_EP_INTERRUPT;
+ break;
+
+ case TUSB_XFER_CONTROL:
+ ch_reg |= USB_EP_CONTROL;
+ break;
+
+ default:
+ // Note: ISO endpoint is unsupported
+ TU_ASSERT(false);
+ }
+
+ /* Create a packet memory buffer area. */
+ uint16_t pma_addr = hcd_pma_alloc(ch_id, dir, edpt->max_packet_size);
+ btable_set_addr(ch_id, dir == TUSB_DIR_OUT ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
+
+ if (dir == TUSB_DIR_OUT) {
+ uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size);
+ tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL);
+ btable_set_count(ch_id, BTABLE_BUF_TX, len);
+
+ edpt->queued_len += len;
+ } else {
+ btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, edpt->max_packet_size);
+ }
+
+ if (edpt->ls_pre == 1) {
+ ch_reg |= USB_CHEP_LSEP;
+ } else {
+ ch_reg &= ~USB_CHEP_LSEP;
+ }
+
+ // Setup DATA/STATUS phase start with DATA1
+ if (tu_edpt_number(edpt->ep_addr) == 0) {
+ edpt->pid = 1;
+ }
+
+ if (edpt->next_setup) {
+ edpt->next_setup = false;
+ ch_reg |= USB_EP_SETUP;
+ edpt->pid = 0;
+ }
+
+ ch_change_status(&ch_reg, dir, EP_STAT_VALID);
+ ch_change_dtog(&ch_reg, dir, edpt->pid);
+ ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir) | CH_DTOG_MASK(dir);
+ ch_write(ch_id, ch_reg, true);
+
+ return true;
+}
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index ba40498e6..44f7137f9 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -98,10 +98,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_enabled(dwc2_dep_t* dep) {
return (dep->ctl & EPCTL_EPENA) != 0;
}
-//--------------------------------------------------------------------
-// DMA
-//--------------------------------------------------------------------
-#if CFG_TUD_MEM_DCACHE_ENABLE
+ #if CFG_TUD_DWC2_SLAVE_ENABLE
+static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum);
+ #endif
+
+ //--------------------------------------------------------------------
+ // DMA
+ //--------------------------------------------------------------------
+ #if CFG_TUD_MEM_DCACHE_ENABLE
bool dcd_dcache_clean(const void* addr, uint32_t data_size) {
TU_VERIFY(addr && data_size);
return dwc2_dcache_clean(addr, data_size);
@@ -345,40 +349,6 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
}
}
-static uint16_t epin_write_tx_fifo(uint8_t rhport, uint8_t epnum) {
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- dwc2_dep_t* const epin = &dwc2->ep[0][epnum];
- xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
-
- dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
- const uint16_t remain_packets = tsiz.packet_count;
-
- uint16_t total_bytes_written = 0;
- // Process every single packet (only whole packets can be written to fifo)
- for (uint16_t i = 0; i < remain_packets; i++) {
- tsiz.value = epin->tsiz;
- const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size;
- const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
-
- // Check if dtxfsts has enough space available
- if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
- break;
- }
-
- // Push packet to Tx-FIFO
- if (xfer->ff) {
- volatile uint32_t* tx_fifo = dwc2->fifo[epnum];
- tu_fifo_read_n_access_mode(xfer->ff, (void *)(uintptr_t)tx_fifo, xact_bytes, TU_FIFO_FIXED_ADDR_RW32);
- total_bytes_written += xact_bytes;
- } else {
- dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes);
- xfer->buffer += xact_bytes;
- total_bytes_written += xact_bytes;
- }
- }
- return total_bytes_written;
-}
-
// Since this function returns void, it is not possible to return a boolean success message
// We must make sure that this function is not called when the EP is disabled
// Must be called from critical section
@@ -423,6 +393,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
}
}
+ #if CFG_TUD_DWC2_DMA_ENABLE
const bool is_dma = dma_device_enabled(dwc2);
if(is_dma) {
if (dir == TUSB_DIR_IN && total_bytes != 0) {
@@ -434,11 +405,14 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
if (epnum == 0) {
xfer->buffer += total_bytes;
}
- } else {
+ } else
+ #endif
+ {
+ #if CFG_TUD_DWC2_SLAVE_ENABLE
dep->diepctl = depctl.value; // enable endpoint
if (dir == TUSB_DIR_IN && total_bytes != 0) {
- const uint16_t xferred_bytes = epin_write_tx_fifo(rhport, epnum);
+ const uint16_t xferred_bytes = epin_write_tx_fifo(dwc2, epnum);
// Enable TXFE interrupt if there are still data to be sent
// EP0 only sends one packet at a time, so no need to check for EP0
@@ -446,6 +420,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
dwc2->diepempmsk |= (1u << epnum);
}
}
+ #endif
}
}
@@ -689,9 +664,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
// into the USB buffer!
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes, bool is_isr) {
(void) is_isr;
- // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
-
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
@@ -854,6 +826,39 @@ TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) {
#endif
#if CFG_TUD_DWC2_SLAVE_ENABLE
+static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum) {
+ dwc2_dep_t *const epin = &dwc2->ep[0][epnum];
+ xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
+
+ dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
+ const uint16_t remain_packets = tsiz.packet_count;
+
+ uint16_t total_bytes_written = 0;
+ // Process every single packet (only whole packets can be written to fifo)
+ for (uint16_t i = 0; i < remain_packets; i++) {
+ tsiz.value = epin->tsiz;
+ const uint16_t remain_bytes = (uint16_t)tsiz.xfer_size;
+ const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
+
+ // Check if dtxfsts has enough space available
+ if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
+ break;
+ }
+
+ // Push packet to Tx-FIFO
+ volatile uint32_t *tx_fifo = dwc2->fifo[epnum];
+ if (xfer->ff) {
+ tu_hwfifo_write_from_fifo(tx_fifo, xfer->ff, xact_bytes, NULL);
+ total_bytes_written += xact_bytes;
+ } else {
+ tu_hwfifo_write(tx_fifo, xfer->buffer, xact_bytes, NULL);
+ xfer->buffer += xact_bytes;
+ total_bytes_written += xact_bytes;
+ }
+ }
+ return total_bytes_written;
+}
+
// Process shared receive FIFO, this interrupt is only used in Slave mode
static void handle_rxflvl_irq(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
@@ -893,9 +898,9 @@ static void handle_rxflvl_irq(uint8_t rhport) {
if (byte_count != 0) {
// Read packet off RxFIFO
if (xfer->ff != NULL) {
- tu_fifo_write_n_access_mode(xfer->ff, (const void *)(uintptr_t)rx_fifo, byte_count, TU_FIFO_FIXED_ADDR_RW32);
+ tu_hwfifo_read_to_fifo(rx_fifo, xfer->ff, byte_count, NULL);
} else {
- dfifo_read_packet(dwc2, xfer->buffer, byte_count);
+ tu_hwfifo_read(rx_fifo, xfer->buffer, byte_count, NULL);
xfer->buffer += byte_count;
}
}
@@ -967,7 +972,7 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
// - 64 bytes or
// - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
if (diepint_bm.txfifo_empty && tu_bit_test(dwc2->diepempmsk, epnum)) {
- epin_write_tx_fifo(rhport, epnum);
+ epin_write_tx_fifo(dwc2, epnum);
// Turn off TXFE if all bytes are written.
dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
index 980574e12..a7e6188df 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.c
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -264,58 +264,4 @@ bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) {
//
// }
-//--------------------------------------------------------------------
-// DFIFO
-//--------------------------------------------------------------------
-// Read a single data packet from receive DFIFO
-void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len) {
- const volatile uint32_t* rx_fifo = dwc2->fifo[0];
-
- // Reading full available 32 bit words from fifo
- uint16_t word_count = len >> 2;
- while (word_count--) {
- tu_unaligned_write32(dst, *rx_fifo);
- dst += 4;
- }
-
- // Read the remaining 1-3 bytes from fifo
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem != 0) {
- const uint32_t tmp = *rx_fifo;
- dst[0] = tu_u32_byte0(tmp);
- if (bytes_rem > 1) {
- dst[1] = tu_u32_byte1(tmp);
- }
- if (bytes_rem > 2) {
- dst[2] = tu_u32_byte2(tmp);
- }
- }
-}
-
-// Write a single data packet to DFIFO
-void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, const uint8_t* src, uint16_t len) {
- volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
-
- // Pushing full available 32 bit words to fifo
- uint16_t word_count = len >> 2;
- while (word_count--) {
- *tx_fifo = tu_unaligned_read32(src);
- src += 4;
- }
-
- // Write the remaining 1-3 bytes into fifo
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem) {
- uint32_t tmp_word = src[0];
- if (bytes_rem > 1) {
- tmp_word |= (src[1] << 8);
- }
- if (bytes_rem > 2) {
- tmp_word |= (src[2] << 16);
- }
-
- *tx_fifo = tmp_word;
- }
-}
-
#endif
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index fc748c85f..c40703b09 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -856,7 +856,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
if (byte_count > 0) {
- dfifo_read_packet(dwc2, edpt->buffer + xfer->xferred_bytes, byte_count);
+ tu_hwfifo_read(dwc2->fifo[0], edpt->buffer + xfer->xferred_bytes, byte_count, NULL);
xfer->xferred_bytes += byte_count;
xfer->fifo_bytes = byte_count;
}
@@ -907,7 +907,7 @@ static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
return true;
}
- dfifo_write_packet(dwc2, ch_id, edpt->buffer + xfer->fifo_bytes, xact_bytes);
+ tu_hwfifo_write(dwc2->fifo[ch_id], edpt->buffer + xfer->fifo_bytes, xact_bytes, NULL);
xfer->fifo_bytes += xact_bytes;
}
}
diff --git a/src/tusb.c b/src/tusb.c
index 8117c3e3e..ed254a10b 100644
--- a/src/tusb.c
+++ b/src/tusb.c
@@ -316,7 +316,7 @@ bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool ove
#endif
s->is_host = is_host;
- tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable);
+ tu_fifo_config(&s->ff, ff_buf, ff_bufsize, overwritable);
#if OSAL_MUTEX_REQUIRED
if (ff_buf != NULL && ff_bufsize > 0) {
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 1dc920d84..08a0ba2ef 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -199,6 +199,7 @@
// NXP LPC MCX
#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series
#define OPT_MCU_MCXA15 2301 ///< NXP MCX A15 Series
+#define OPT_MCU_RW61X 2302 ///< NXP RW61x Series
// Analog Devices
#define OPT_MCU_MAX32690 2400 ///< ADI MAX32690
@@ -216,6 +217,9 @@
#define OPT_MCU_AT32F425 2505 ///< ArteryTek AT32F425
#define OPT_MCU_AT32F413 2506 ///< ArteryTek AT32F413
+// HPMicro
+#define OPT_MCU_HPM 2600 ///< HPMicro
+
// Check if configured MCU is one of listed
// Apply TU_MCU_IS_EQUAL with || as separator to list of input
#define TU_MCU_IS_EQUAL(_m) (CFG_TUSB_MCU == (_m))
@@ -268,16 +272,7 @@
//--------------------------------------------------------------------+
//------------- DWC2 -------------//
-// Slave mode for device
-#ifndef CFG_TUD_DWC2_SLAVE_ENABLE
- #ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT 1
- #endif
-
- #define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
-#endif
-
-// DMA for device
+// DMA mode for device
#ifndef CFG_TUD_DWC2_DMA_ENABLE
#ifndef CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
#define CFG_TUD_DWC2_DMA_ENABLE_DEFAULT 0
@@ -286,16 +281,16 @@
#define CFG_TUD_DWC2_DMA_ENABLE CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
#endif
-// Slave mode for host
-#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
- #ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT 1
+// Slave mode for device
+#ifndef CFG_TUD_DWC2_SLAVE_ENABLE
+ #ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
+ #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE // disabled if DMA is enabled
#endif
- #define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
+ #define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
#endif
-// DMA for host
+// DMA mode for host
#ifndef CFG_TUH_DWC2_DMA_ENABLE
#ifndef CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
#define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
@@ -304,14 +299,21 @@
#define CFG_TUH_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
#endif
-#if defined(TUP_USBIP_DWC2)
- #if CFG_TUD_DWC2_SLAVE_ENABLE && !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+// Slave mode for host
+#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
+ #ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
+ #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE // disabled if DMA is enabled
#endif
- #if CFG_TUH_DWC2_SLAVE_ENABLE && !CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUH_EDPT_DEDICATED_HWFIFO 1
- #endif
+ #define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
+#endif
+
+#if defined(TUP_USBIP_DWC2)
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO CFG_TUD_DWC2_SLAVE_ENABLE
+ #define CFG_TUH_EDPT_DEDICATED_HWFIFO CFG_TUH_DWC2_SLAVE_ENABLE
+
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32bit access
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo address
#endif
//------------- ChipIdea -------------//
@@ -352,16 +354,36 @@
//------------ FSDEV --------------//
#if defined(TUP_USBIP_FSDEV)
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+
+ #if CFG_TUSB_FSDEV_PMA_SIZE == 512
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
+ #elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 2 // 16-bit address increase
+ #elif CFG_TUSB_FSDEV_PMA_SIZE == 2048
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32-bit data
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
+ #endif
#endif
//------------ MUSB --------------//
#if defined(TUP_USBIP_MUSB)
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 0 // need testing to enable
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32 bit data
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo
+
#endif
//------------ RUSB2 --------------//
#if defined(TUP_USBIP_RUSB2)
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (2 | (TUD_OPT_HIGH_SPEED ? 4 : 0)) // 16 bit and 32 bit data if highspeed
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
+ #define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE // custom write since rusb2 can change access width 32 -> 16 and can write
+ // odd byte with byte access
#endif
//--------------------------------------------------------------------