From 30e3c64134789416e10ed867fa12c210b808e98f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 8 Nov 2018 13:45:30 -0800 Subject: [PATCH] Polish up control split and treat it more like a normal endpoint. --- src/class/cdc/cdc_device.c | 28 ++++-- src/class/cdc/cdc_device.h | 1 + src/class/custom/custom_device.c | 2 +- src/class/custom/custom_device.h | 1 + src/class/hid/hid_device.c | 32 ++++-- src/class/hid/hid_device.h | 1 + src/class/msc/msc_device.c | 5 + src/class/msc/msc_device.h | 1 + src/device/control.c | 14 ++- src/device/control.h | 3 + src/device/usbd.c | 16 +++ src/portable/nordic/nrf5x/dcd_nrf5x.c | 136 ++++++-------------------- 12 files changed, 114 insertions(+), 126 deletions(-) diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 81d7fa526..ab9addc93 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -288,6 +288,21 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface return TUSB_ERROR_NONE; } +void cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) +{ + //------------- Class Specific Request -------------// + if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return; + + // TODO Support multiple interfaces + uint8_t const itf = 0; + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + + // Invoke callback + if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) { + if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); + } +} + tusb_error_t cdcd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent) { //------------- Class Specific Request -------------// @@ -297,16 +312,15 @@ tusb_error_t cdcd_control_request(uint8_t rhport, tusb_control_request_t const * uint8_t const itf = 0; cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest) || (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) ) + if ((CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) ) + { + uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength); + dcd_edpt_xfer(rhport, 0, (uint8_t*) &p_cdc->line_coding, len); + } + else if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest)) { uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength); dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, (uint8_t*) &p_cdc->line_coding, len); - - // Invoke callback - if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) - { - if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); - } } else if (CDC_REQUEST_SET_CONTROL_LINE_STATE == p_request->bRequest ) { diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 88d37a83c..2f902ae04 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -113,6 +113,7 @@ ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_li void cdcd_init (void); tusb_error_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); tusb_error_t cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent); +void cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t cdcd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void cdcd_reset (uint8_t rhport); diff --git a/src/class/custom/custom_device.c b/src/class/custom/custom_device.c index d43a86b14..1b36f1331 100644 --- a/src/class/custom/custom_device.c +++ b/src/class/custom/custom_device.c @@ -89,7 +89,7 @@ tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf, return TUSB_ERROR_NONE; } -tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request) +tusb_error_t cusd_control_request(uint8_t rhport, tusb_control_request_t const * p_request) { return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; } diff --git a/src/class/custom/custom_device.h b/src/class/custom/custom_device.h index 81a074ce3..116c6897d 100644 --- a/src/class/custom/custom_device.h +++ b/src/class/custom/custom_device.h @@ -65,6 +65,7 @@ void cusd_init(void); tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request); +void cusd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void cusd_reset(uint8_t rhport); #endif diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index aa7a8008e..efa602ad6 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -455,15 +455,6 @@ tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * else if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest ) { dcd_edpt_xfer(rhport, 0, _shared_control_buffer, p_request->wLength); - - // wValue = Report Type | Report ID - uint8_t const report_type = tu_u16_high(p_request->wValue); - uint8_t const report_id = tu_u16_low(p_request->wValue); - - if ( p_hid->set_report_cb ) - { - p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, _shared_control_buffer, p_request->wLength); - } } else if (HID_REQ_CONTROL_SET_IDLE == p_request->bRequest) { @@ -495,6 +486,29 @@ tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * return TUSB_ERROR_NONE; } +void hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) +{ + hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex ); + if (p_hid == NULL) { + return; + } + + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) + { + if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest ) + { + // wValue = Report Type | Report ID + uint8_t const report_type = tu_u16_high(p_request->wValue); + uint8_t const report_id = tu_u16_low(p_request->wValue); + + if ( p_hid->set_report_cb ) + { + p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, _shared_control_buffer, p_request->wLength); + } + } + } +} + tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes) { // nothing to do diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 10aea10ac..1dc40af57 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -379,6 +379,7 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t void hidd_init(void); tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent); +void hidd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void hidd_reset(uint8_t rhport); diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 3c9997b95..32ad90102 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -167,6 +167,11 @@ tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * return TUSB_ERROR_NONE; } +void mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) +{ + return; +} + // For backwards compatibility we support static block counts. #if defined(CFG_TUD_MSC_BLOCK_NUM) && defined(CFG_TUD_MSC_BLOCK_SZ) ATTR_WEAK bool tud_lun_capacity_cb(uint8_t lun, uint32_t* last_valid_sector, uint16_t* block_size) { diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index a5bc54ff9..ac3eade22 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -199,6 +199,7 @@ ATTR_WEAK bool tud_lun_capacity_cb(uint8_t lun, uint32_t* last_valid_sector, uin void mscd_init(void); tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent); +void mscd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void mscd_reset(uint8_t rhport); diff --git a/src/device/control.c b/src/device/control.c index 4944a999e..5856f0628 100644 --- a/src/device/control.c +++ b/src/device/control.c @@ -59,8 +59,13 @@ void controld_init(void) { // Note dir is value of direction bit in setup packet (i.e DATA stage direction) static inline bool dcd_control_status(uint8_t rhport, uint8_t dir) { + uint8_t ep_addr = 0; + // Invert the direction. + if (dir == TUSB_DIR_OUT) { + ep_addr |= TUSB_DIR_IN_MASK; + } // status direction is reversed to one in the setup packet - return dcd_edpt_xfer(rhport, 1-dir, NULL, 0); + return dcd_edpt_xfer(rhport, ep_addr, NULL, 0); } static inline void dcd_control_stall(uint8_t rhport) @@ -140,6 +145,12 @@ tusb_error_t controld_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t ev if (p_request->wLength == control_state.total_transferred || xferred_bytes < 64) { control_state.current_stage = CONTROL_STAGE_STATUS; dcd_control_status(rhport, p_request->bmRequestType_bit.direction); + + // Do the user callback after queueing the STATUS packet because the callback could be slow. + if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient ) + { + tud_control_interface_control_complete_cb(rhport, tu_u16_low(p_request->wIndex), p_request); + } } else { if (TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient) { error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, control_state.total_transferred); @@ -161,7 +172,6 @@ tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request control_state.total_transferred = 0; } - if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient ) { error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, 0); diff --git a/src/device/control.h b/src/device/control.h index 24f0d0a14..881c99ead 100644 --- a/src/device/control.h +++ b/src/device/control.h @@ -68,6 +68,9 @@ tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request // Callback when the configuration of the device is changed. tusb_error_t tud_control_set_config_cb(uint8_t rhport, uint8_t config_number); +// Called when the DATA stage of a control transaction is complete. +void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request); + tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent); //--------------------------------------------------------------------+ diff --git a/src/device/usbd.c b/src/device/usbd.c index 3c77fefba..c9d5e5642 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -96,6 +96,7 @@ typedef struct { tusb_error_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length); // Control request is called one or more times for a request and can queue multiple data packets. tusb_error_t (* control_request ) (uint8_t rhport, tusb_control_request_t const *, uint16_t bytes_already_sent); + void (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const *); tusb_error_t (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, tusb_event_t, uint32_t); void (* sof ) (uint8_t rhport); void (* reset ) (uint8_t); @@ -108,6 +109,7 @@ static usbd_class_driver_t const usbd_class_drivers[] = .init = controld_init, .open = NULL, .control_request = NULL, + .control_request_complete = NULL, .xfer_cb = controld_xfer_cb, .sof = NULL, .reset = controld_reset @@ -118,6 +120,7 @@ static usbd_class_driver_t const usbd_class_drivers[] = .init = cdcd_init, .open = cdcd_open, .control_request = cdcd_control_request, + .control_request_complete = cdcd_control_request_complete, .xfer_cb = cdcd_xfer_cb, .sof = NULL, .reset = cdcd_reset @@ -130,6 +133,7 @@ static usbd_class_driver_t const usbd_class_drivers[] = .init = mscd_init, .open = mscd_open, .control_request = mscd_control_request, + .control_request_complete = mscd_control_request_complete, .xfer_cb = mscd_xfer_cb, .sof = NULL, .reset = mscd_reset @@ -143,6 +147,7 @@ static usbd_class_driver_t const usbd_class_drivers[] = .init = hidd_init, .open = hidd_open, .control_request = hidd_control_request, + .control_request_complete = hidd_control_request_complete, .xfer_cb = hidd_xfer_cb, .sof = NULL, .reset = hidd_reset @@ -155,6 +160,7 @@ static usbd_class_driver_t const usbd_class_drivers[] = .init = cusd_init, .open = cusd_open, .control_request = cusd_control_request, + .control_request_complete = cusd_control_request_complete, .xfer_cb = cusd_xfer_cb, .sof = NULL, .reset = cusd_reset @@ -309,6 +315,16 @@ static tusb_error_t usbd_main_st(void) return err; } +void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request) { + if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT) + { + const usbd_class_driver_t *driver = &usbd_class_drivers[_usbd_dev.itf2drv[interface]]; + if (driver->control_request_complete != NULL) { + driver->control_request_complete(rhport, p_request); + } + } +} + tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent) { if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT) { diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 1e3dc4cba..74b7bb7b8 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -82,17 +82,8 @@ typedef struct /*static*/ struct { - struct - { - uint8_t* buffer; - uint16_t total_len; - volatile uint16_t actual_len; - - uint8_t dir; - }control; - - // Non control: 7 endpoints IN & OUT (offset 1) - nom_xfer_t xfer[7][2]; + // All 8 endpoints including control IN & OUT (offset 1) + nom_xfer_t xfer[8][2]; volatile bool dma_running; }_dcd; @@ -109,6 +100,8 @@ void bus_reset(void) NRF_USBD->TASKS_STARTISOOUT = 0; tu_varclr(&_dcd); + _dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE; + _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE; } /*------------------------------------------------------------------*/ @@ -176,65 +169,13 @@ static void edpt_dma_end(void) _dcd.dma_running = false; } -static void xact_control_start(void) -{ - // Each transaction is up to 64 bytes - uint8_t const xact_len = tu_min16(_dcd.control.total_len-_dcd.control.actual_len, MAX_PACKET_SIZE); - - if ( _dcd.control.dir == TUSB_DIR_OUT ) - { - // TODO control out - NRF_USBD->EPOUT[0].PTR = (uint32_t) _dcd.control.buffer; - NRF_USBD->EPOUT[0].MAXCNT = xact_len; - - NRF_USBD->TASKS_EP0RCVOUT = 1; - __ISB(); __DSB(); - }else - { - NRF_USBD->EPIN[0].PTR = (uint32_t) _dcd.control.buffer; - NRF_USBD->EPIN[0].MAXCNT = xact_len; - - edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[0]); - } - - _dcd.control.buffer += xact_len; - _dcd.control.actual_len += xact_len; -} - -bool dcd_control_xfer (uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t length) -{ - (void) rhport; - - if ( length ) - { - // Data Phase - _dcd.control.total_len = length; - _dcd.control.actual_len = 0; - _dcd.control.buffer = buffer; - _dcd.control.dir = dir; - - xact_control_start(); - }else - { - NRF_USBD->EPIN[0].PTR = 0; - NRF_USBD->EPIN[0].MAXCNT = 0; - // Status Phase also require Easy DMA has to be free as well !!!! - NRF_USBD->TASKS_EP0STATUS = 1; - - // The nRF doesn't interrupt on status transmit so we queue up a success response. - dcd_event_xfer_complete(0, 0, 0, DCD_XFER_SUCCESS, false); - } - - return true; -} - /*------------------------------------------------------------------*/ /* *------------------------------------------------------------------*/ static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir) { - return &_dcd.xfer[epnum-1][dir]; + return &_dcd.xfer[epnum][dir]; } /*------------- Bulk/Int OUT transfer -------------*/ @@ -296,7 +237,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) uint8_t const epnum = edpt_number(desc_edpt->bEndpointAddress); uint8_t const dir = edpt_dir(desc_edpt->bEndpointAddress); - _dcd.xfer[epnum-1][dir].mps = desc_edpt->wMaxPacketSize.size; + _dcd.xfer[epnum][dir].mps = desc_edpt->wMaxPacketSize.size; if ( dir == TUSB_DIR_OUT ) { @@ -312,6 +253,16 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } +void control_status_token(uint8_t addr) { + NRF_USBD->EPIN[0].PTR = 0; + NRF_USBD->EPIN[0].MAXCNT = 0; + // Status Phase also require Easy DMA has to be free as well !!!! + NRF_USBD->TASKS_EP0STATUS = 1; + + // The nRF doesn't interrupt on status transmit so we queue up a success response. + dcd_event_xfer_complete(0, addr, 0, DCD_XFER_SUCCESS, false); +} + bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { (void) rhport; @@ -325,7 +276,10 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer->total_len = total_bytes; xfer->actual_len = 0; - if ( dir == TUSB_DIR_OUT ) + // How does the control endpoint handle a ZLP in the data phase? + if (epnum == 0 && total_bytes == 0) { + control_status_token(ep_addr); + } else if ( dir == TUSB_DIR_OUT ) { if ( xfer->data_received ) { @@ -431,47 +385,15 @@ void USBD_IRQHandler(void) edpt_dma_end(); } - /*------------- Control Transfer -------------*/ + // Setup tokens are specific to the Control endpoint. if ( int_status & USBD_INTEN_EP0SETUP_Msk ) { uint8_t setup[8] = { NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH, NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH }; - dcd_event_setup_received(0, setup, true); - } - - if ( int_status & USBD_INTEN_EP0DATADONE_Msk ) - { - if ( _dcd.control.dir == TUSB_DIR_OUT ) - { - // Control OUT: data from Host -> Endpoint - // Trigger DMA to move Endpoint -> SRAM - edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[0]); - }else - { - // Control IN: data transferred from Endpoint -> Host - if ( _dcd.control.actual_len < _dcd.control.total_len ) - { - xact_control_start(); - }else - { - // Control IN complete - dcd_event_xfer_complete(0, 0, _dcd.control.actual_len, DCD_XFER_SUCCESS, true); - } - } - } - - // Control OUT: data from Endpoint -> SRAM - if ( int_status & USBD_INTEN_ENDEPOUT0_Msk) - { - if ( _dcd.control.actual_len < _dcd.control.total_len ) - { - xact_control_start(); - }else - { - // Control OUT complete - dcd_event_xfer_complete(0, 0, _dcd.control.actual_len, DCD_XFER_SUCCESS, true); + if (setup[1] != TUSB_REQ_SET_ADDRESS) { + dcd_event_setup_received(0, setup, true); } } @@ -482,9 +404,9 @@ void USBD_IRQHandler(void) * We must handle this stage before Host -> Endpoint just in case * 2 event happens at once */ - for(uint8_t epnum=1; epnum<8; epnum++) + for(uint8_t epnum=0; epnum<8; epnum++) { - if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) ) + if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum)) { nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); @@ -509,16 +431,16 @@ void USBD_IRQHandler(void) // Ended event for Bulk/Int : nothing to do } - if ( int_status & USBD_INTEN_EPDATA_Msk) + if ( int_status & USBD_INTEN_EPDATA_Msk || int_status & USBD_INTEN_EP0DATADONE_Msk) { uint32_t data_status = NRF_USBD->EPDATASTATUS; nrf_usbd_epdatastatus_clear(data_status); // Bulk/Int In: data from Endpoint -> Host - for(uint8_t epnum=1; epnum<8; epnum++) + for(uint8_t epnum=0; epnum<8; epnum++) { - if ( BIT_TEST_(data_status, epnum ) ) + if ( BIT_TEST_(data_status, epnum ) || (epnum == 0 && BIT_TEST_(int_status, USBD_INTEN_EP0DATADONE_Pos))) { nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN); @@ -537,7 +459,7 @@ void USBD_IRQHandler(void) } // Bulk/Int OUT: data from Host -> Endpoint - for(uint8_t epnum=1; epnum<8; epnum++) + for(uint8_t epnum=0; epnum<8; epnum++) { if ( BIT_TEST_(data_status, 16+epnum ) ) {