From 16f1554a03a89c51cd033b6a06cb758668f32fda Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Tue, 11 Oct 2022 09:59:28 -0400 Subject: [PATCH 1/8] lpc55s69 isochronous, dummy address for endpoint buffers to prevent accidental writes --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 96 ++++++++++++-------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 09ebf3b0d..b0ddebad0 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -78,8 +78,9 @@ typedef struct { // Max nbytes for each control/bulk/interrupt transfer enum { - NBYTES_CBI_FULLSPEED_MAX = 64, - NBYTES_CBI_HIGHSPEED_MAX = 32767 // can be up to all 15-bit, but only tested with 4096 + NBYTES_CBI_FS_ISO_MAX = 1023, // FS ISO + NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt + NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096 }; enum { @@ -174,6 +175,7 @@ typedef struct // For example: LPC55s69 port1 Highspeed must be USB_RAM (0x40100000) // Use CFG_TUSB_MEM_SECTION to place it accordingly. CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd; +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static volatile uint8_t dummy[64]; // TODO temp fix to prevent accidental overwrite due to ep[][].buffer_xx.offset being 0 //--------------------------------------------------------------------+ // Multiple Controllers @@ -225,8 +227,44 @@ static inline uint8_t ep_addr2id(uint8_t ep_addr) //--------------------------------------------------------------------+ // CONTROLLER API //--------------------------------------------------------------------+ + +static void prepare_setup_packet(uint8_t rhport) +{ + if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL ) + { + _dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet); + }else + { + _dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet); + } +} + +static void edpt_reset(uint8_t rhport, uint8_t ep_id) +{ + const uint32_t offset = get_buf_offset((void*)dummy); + tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id])); + if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL ) + { + _dcd.ep[ep_id][0].buffer_fs.offset = _dcd.ep[ep_id][1].buffer_fs.offset = offset; + } + else + { + _dcd.ep[ep_id][0].buffer_hs.offset = _dcd.ep[ep_id][1].buffer_hs.offset = offset; + } +} + +static void edpt_reset_all(uint8_t rhport) +{ + for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id) + { + edpt_reset(rhport, ep_id); + } + prepare_setup_packet(rhport); +} void dcd_init(uint8_t rhport) { + edpt_reset_all(rhport); + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; dcd_reg->EPLISTSTART = (uint32_t) _dcd.ep; @@ -310,18 +348,13 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { - (void) rhport; - - // TODO not support ISO yet - TU_VERIFY(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); - //------------- Prepare Queue Head -------------// uint8_t ep_id = ep_addr2id(p_endpoint_desc->bEndpointAddress); // Check if endpoint is available TU_ASSERT( _dcd.ep[ep_id][0].disable && _dcd.ep[ep_id][1].disable ); - tu_memclr(_dcd.ep[ep_id], 2*sizeof(ep_cmd_sts_t)); + edpt_reset(rhport, ep_id); _dcd.ep[ep_id][0].is_iso = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); // Enable EP interrupt @@ -333,19 +366,18 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) void dcd_edpt_close_all (uint8_t rhport) { - (void) rhport; - // TODO implement dcd_edpt_close_all() + for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id) + { + _dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual) + _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1; + } } -static void prepare_setup_packet(uint8_t rhport) +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL ) - { - _dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);; - }else - { - _dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);; - } + uint8_t ep_id = ep_addr2id(ep_addr); + _dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual) + _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1; } static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes) @@ -354,13 +386,12 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL ) { - // TODO ISO FullSpeed can have up to 1023 bytes - nbytes = tu_min16(total_bytes, NBYTES_CBI_FULLSPEED_MAX); + nbytes = tu_min16(total_bytes, _dcd.ep[ep_id][0].is_iso ? NBYTES_CBI_FS_ISO_MAX : NBYTES_CBI_FS_MAX); _dcd.ep[ep_id][0].buffer_fs.offset = buf_offset; _dcd.ep[ep_id][0].buffer_fs.nbytes = nbytes; }else { - nbytes = tu_min16(total_bytes, NBYTES_CBI_HIGHSPEED_MAX); + nbytes = tu_min16(total_bytes, NBYTES_CBI_HS_MAX); _dcd.ep[ep_id][0].buffer_hs.offset = buf_offset; _dcd.ep[ep_id][0].buffer_hs.nbytes = nbytes; } @@ -379,7 +410,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t)); _dcd.dma[ep_id].total_bytes = total_bytes; - prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes); + prepare_ep_xfer(rhport, ep_id, buffer ? get_buf_offset(buffer) : get_buf_offset((void*)dummy), total_bytes); return true; } @@ -390,6 +421,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to static void bus_reset(uint8_t rhport) { tu_memclr(&_dcd, sizeof(dcd_data_t)); + edpt_reset_all(rhport); // disable all non-control endpoints on bus reset for(uint8_t ep_id = 2; ep_id < 2*MAX_EP_PAIRS; ep_id++) @@ -397,8 +429,6 @@ static void bus_reset(uint8_t rhport) _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1; } - prepare_setup_packet(rhport); - dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; dcd_reg->EPINUSE = 0; @@ -506,23 +536,15 @@ void dcd_int_handler(uint8_t rhport) } } - // TODO support suspend & resume if (cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK) { - if (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK) - { // suspend signal, bus idle for more than 3ms - // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. - if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK) - { - dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); - } + // suspend signal, bus idle for more than 3ms + // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. + if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK) + { + dcd_event_bus_signal(rhport, (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true); } } -// else -// { // resume signal -// dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); -// } -// } } // Setup Receive From 930c68278c3825bce91ef324090d25c392844558 Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Wed, 12 Oct 2022 11:16:35 -0400 Subject: [PATCH 2/8] double cast of pointer to remove error --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index b0ddebad0..7220654e0 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -241,7 +241,7 @@ static void prepare_setup_packet(uint8_t rhport) static void edpt_reset(uint8_t rhport, uint8_t ep_id) { - const uint32_t offset = get_buf_offset((void*)dummy); + const uint32_t offset = get_buf_offset((void*)(uint32_t)dummy); tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id])); if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL ) { @@ -410,7 +410,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t)); _dcd.dma[ep_id].total_bytes = total_bytes; - prepare_ep_xfer(rhport, ep_id, buffer ? get_buf_offset(buffer) : get_buf_offset((void*)dummy), total_bytes); + prepare_ep_xfer(rhport, ep_id, buffer ? get_buf_offset(buffer) : get_buf_offset((void*)(uint32_t)dummy), total_bytes); return true; } From 2c1ff2673baaeefc6520d25e87d5ca5e6b2093db Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Thu, 13 Oct 2022 11:48:30 -0400 Subject: [PATCH 3/8] (void) rhport for unused parameter --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 7220654e0..1f29abbb8 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -375,6 +375,8 @@ void dcd_edpt_close_all (uint8_t rhport) void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; + uint8_t ep_id = ep_addr2id(ep_addr); _dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual) _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1; @@ -403,8 +405,6 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { - (void) rhport; - uint8_t const ep_id = ep_addr2id(ep_addr); tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t)); From 3f45f3767240dccfccbf9b013a9109912bfa2b5c Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 17 Oct 2022 23:13:24 +0700 Subject: [PATCH 4/8] minor rename --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 1f29abbb8..51baaf224 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -78,7 +78,8 @@ typedef struct { // Max nbytes for each control/bulk/interrupt transfer enum { - NBYTES_CBI_FS_ISO_MAX = 1023, // FS ISO + NBYTES_ISO_FS_MAX = 1023, // FS ISO + NBYTES_ISO_HS_MAX = 1024, // HS ISO NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096 }; @@ -113,6 +114,8 @@ enum { typedef union TU_ATTR_PACKED { // Full and High speed has different bit layout for buffer_offset and nbytes + // TODO FS/HS layout depends on the max speed of controller e.g + // lpc55s69 PORT0 is only FS but actually has the same layout as HS on port1 // Buffer (aligned 64) = DATABUFSTART [31:22] | buffer_offset [21:6] volatile struct { @@ -388,7 +391,7 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL ) { - nbytes = tu_min16(total_bytes, _dcd.ep[ep_id][0].is_iso ? NBYTES_CBI_FS_ISO_MAX : NBYTES_CBI_FS_MAX); + nbytes = tu_min16(total_bytes, _dcd.ep[ep_id][0].is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX); _dcd.ep[ep_id][0].buffer_fs.offset = buf_offset; _dcd.ep[ep_id][0].buffer_fs.nbytes = nbytes; }else From fe4278554b04c3446b30f28fdb6aaad908f8fa48 Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Thu, 20 Oct 2022 11:02:57 -0400 Subject: [PATCH 5/8] dummy buffer only on EP0 OUT ZLPs --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 21 ++++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 51baaf224..ed6c14f17 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -178,7 +178,7 @@ typedef struct // For example: LPC55s69 port1 Highspeed must be USB_RAM (0x40100000) // Use CFG_TUSB_MEM_SECTION to place it accordingly. CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd; -CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static volatile uint8_t dummy[64]; // TODO temp fix to prevent accidental overwrite due to ep[][].buffer_xx.offset being 0 +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static volatile uint8_t dummy[8] = { 0 }; // a fix for EP0 OUT ZLPs overwriting the buffer //--------------------------------------------------------------------+ // Multiple Controllers @@ -244,16 +244,7 @@ static void prepare_setup_packet(uint8_t rhport) static void edpt_reset(uint8_t rhport, uint8_t ep_id) { - const uint32_t offset = get_buf_offset((void*)(uint32_t)dummy); tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id])); - if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL ) - { - _dcd.ep[ep_id][0].buffer_fs.offset = _dcd.ep[ep_id][1].buffer_fs.offset = offset; - } - else - { - _dcd.ep[ep_id][0].buffer_hs.offset = _dcd.ep[ep_id][1].buffer_hs.offset = offset; - } } static void edpt_reset_all(uint8_t rhport) @@ -413,7 +404,11 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t)); _dcd.dma[ep_id].total_bytes = total_bytes; - prepare_ep_xfer(rhport, ep_id, buffer ? get_buf_offset(buffer) : get_buf_offset((void*)(uint32_t)dummy), total_bytes); + if (!buffer && !ep_id) // for EP0 OUT ZLPs to prevent overwrites to buffer + { + buffer = (uint8_t*)(uint32_t)dummy; + } + prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes); return true; } @@ -426,8 +421,8 @@ static void bus_reset(uint8_t rhport) tu_memclr(&_dcd, sizeof(dcd_data_t)); edpt_reset_all(rhport); - // disable all non-control endpoints on bus reset - for(uint8_t ep_id = 2; ep_id < 2*MAX_EP_PAIRS; ep_id++) + // disable all endpoints as epecified by LPC55S69 UM Table 778 + for(uint8_t ep_id = 0; ep_id < 2*MAX_EP_PAIRS; ep_id++) { _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1; } From 0b5504708172aa269653924da95e358720aabf7d Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Thu, 20 Oct 2022 11:04:49 -0400 Subject: [PATCH 6/8] typo fix --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index ed6c14f17..80d85fa46 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -421,7 +421,7 @@ static void bus_reset(uint8_t rhport) tu_memclr(&_dcd, sizeof(dcd_data_t)); edpt_reset_all(rhport); - // disable all endpoints as epecified by LPC55S69 UM Table 778 + // disable all endpoints as specified by LPC55S69 UM Table 778 for(uint8_t ep_id = 0; ep_id < 2*MAX_EP_PAIRS; ep_id++) { _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1; From 35e1a27c950c4b25106c074d0b66220d099e54a7 Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Fri, 21 Oct 2022 15:06:30 -0400 Subject: [PATCH 7/8] unused (void) cast --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 80d85fa46..7825d287f 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -244,6 +244,7 @@ static void prepare_setup_packet(uint8_t rhport) static void edpt_reset(uint8_t rhport, uint8_t ep_id) { + (void) rhport; tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id])); } From e3b7ed9ae966be1cb41165343ef30c6523ed5771 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 24 Oct 2022 18:43:21 +0700 Subject: [PATCH 8/8] use dummy for all ZLP for ip3511, fix lpc55 build with DEBUG=1 --- hw/bsp/lpc55/family.mk | 1 + src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/bsp/lpc55/family.mk b/hw/bsp/lpc55/family.mk index 1af1d076e..9d6702b94 100644 --- a/hw/bsp/lpc55/family.mk +++ b/hw/bsp/lpc55/family.mk @@ -43,6 +43,7 @@ SRC_C += \ $(MCU_DIR)/drivers/fsl_power.c \ $(MCU_DIR)/drivers/fsl_reset.c \ $(SDK_DIR)/drivers/lpc_gpio/fsl_gpio.c \ + $(SDK_DIR)/drivers/common/fsl_common_arm.c \ $(SDK_DIR)/drivers/flexcomm/fsl_flexcomm.c \ $(SDK_DIR)/drivers/flexcomm/fsl_usart.c \ lib/sct_neopixel/sct_neopixel.c diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 7825d287f..9b490c48c 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -178,7 +178,9 @@ typedef struct // For example: LPC55s69 port1 Highspeed must be USB_RAM (0x40100000) // Use CFG_TUSB_MEM_SECTION to place it accordingly. CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd; -CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static volatile uint8_t dummy[8] = { 0 }; // a fix for EP0 OUT ZLPs overwriting the buffer + +// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug) +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8]; //--------------------------------------------------------------------+ // Multiple Controllers @@ -405,10 +407,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t)); _dcd.dma[ep_id].total_bytes = total_bytes; - if (!buffer && !ep_id) // for EP0 OUT ZLPs to prevent overwrites to buffer + if (!buffer) { + // Although having no data, ZLPs can cause buffer overwritten to zeroes. + // Probably due to USB/DMA controller side effect/bug. + // Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART buffer = (uint8_t*)(uint32_t)dummy; } + prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes); return true;