From c09d754654eb7846f3b53cbe58da517076c97494 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 27 Mar 2019 23:47:59 +0700 Subject: [PATCH 01/22] remove tud_msc_ready() --- src/class/msc/msc_device.c | 5 ----- src/class/msc/msc_device.h | 3 --- 2 files changed, 8 deletions(-) diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 04a3178a..ace91b40 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -102,11 +102,6 @@ static inline uint16_t rdwr10_get_blockcount(uint8_t const command[]) //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ -bool tud_msc_ready(void) -{ - return ( _mscd_itf.ep_in != 0 ) && ( _mscd_itf.ep_out != 0 ) ; -} - bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier) { (void) lun; diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index e030951b..74be7e06 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -68,9 +68,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct"); * \defgroup MSC_Device Device * @{ */ - -// Check if MSC interface is ready to use -bool tud_msc_ready(void); bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); //--------------------------------------------------------------------+ From 8fb9fbb0b19de3422645e65fbd422c86cb548c62 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 27 Mar 2019 23:58:24 +0700 Subject: [PATCH 02/22] add tud_mounted() check in tud_cdc_connected() mark device as disconnected immed with DCD_EVENT_UNPLUGGED --- src/class/cdc/cdc_device.c | 2 +- src/class/cdc/cdc_device.h | 1 - src/device/usbd.c | 8 ++++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 2ac8d471..7b8f1bf7 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -99,7 +99,7 @@ static void _prep_out_transaction (uint8_t itf) bool tud_cdc_n_connected(uint8_t itf) { // DTR (bit 0) active is considered as connected - return TU_BIT_TEST(_cdcd_itf[itf].line_state, 0); + return tud_mounted() && TU_BIT_TEST(_cdcd_itf[itf].line_state, 0); } uint8_t tud_cdc_n_get_line_state (uint8_t itf) diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 468edef4..d9a200dd 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -97,7 +97,6 @@ ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_li //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API - //--------------------------------------------------------------------+ void cdcd_init (void); bool cdcd_open (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); diff --git a/src/device/usbd.c b/src/device/usbd.c index 604f35bc..58c0d3c4 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -40,7 +40,7 @@ // Device Data //--------------------------------------------------------------------+ typedef struct { - uint8_t config_num; + volatile uint8_t config_num; uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid ) @@ -332,7 +332,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; case TUSB_REQ_GET_CONFIGURATION: - data_buf = &_usbd_dev.config_num; + data_buf = (uint8_t*) &_usbd_dev.config_num; data_len = 1; break; @@ -543,7 +543,11 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) switch (event->event_id) { case DCD_EVENT_BUS_RESET: + osal_queue_send(_usbd_q, event, in_isr); + break; + case DCD_EVENT_UNPLUGGED: + _usbd_dev.config_num = 0; // mark disconnected osal_queue_send(_usbd_q, event, in_isr); break; From 0bdd4bd55002c4563154214a4d57581433cae668 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 29 Mar 2019 01:34:53 +0700 Subject: [PATCH 03/22] added Suspend and Resume event for nrf5x port also rename DCD_EVENT_SUSPENDED to DCD_EVENT_SUSPEND --- src/class/hid/hid_device.c | 7 ++++ src/device/dcd.h | 2 +- src/device/usbd.c | 4 +-- src/portable/nordic/nrf5x/dcd_nrf5x.c | 36 +++++++++++++++---- src/portable/nordic/nrf5x/hal_nrf5x.c | 4 +-- .../nxp/lpc11_13_15/dcd_lpc11_13_15.c | 2 +- src/portable/nxp/lpc17_40/dcd_lpc17_40.c | 2 +- src/portable/nxp/lpc18_43/dcd_lpc18_43.c | 2 +- 8 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 3a20a9cc..765ee042 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -265,6 +265,7 @@ void hidd_init(void) void hidd_reset(uint8_t rhport) { + (void) rhport; tu_memclr(_hidd_itf, sizeof(_hidd_itf)); #if CFG_TUD_HID_KEYBOARD @@ -447,6 +448,7 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque // return false to stall control endpoint (e.g Host send non-sense DATA) bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex ); TU_ASSERT(p_hid); @@ -469,6 +471,11 @@ bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { // nothing to do + (void) rhport; + (void) ep_addr; + (void) event; + (void) xferred_bytes; + return true; } diff --git a/src/device/dcd.h b/src/device/dcd.h index 186c4af0..9abebc2a 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -42,7 +42,7 @@ typedef enum DCD_EVENT_BUS_RESET = 1, DCD_EVENT_UNPLUGGED, DCD_EVENT_SOF, - DCD_EVENT_SUSPENDED, + DCD_EVENT_SUSPEND, DCD_EVENT_RESUME, DCD_EVENT_SETUP_RECEIVED, diff --git a/src/device/usbd.c b/src/device/usbd.c index 58c0d3c4..933e0f84 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -40,7 +40,7 @@ // Device Data //--------------------------------------------------------------------+ typedef struct { - volatile uint8_t config_num; + volatile uint8_t config_num; // 0 is non-configure ~ disconnect uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid ) @@ -555,7 +555,7 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) // nothing to do now break; - case DCD_EVENT_SUSPENDED: + case DCD_EVENT_SUSPEND: // TODO support suspended break; diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 3c2b6d45..928ef671 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -207,6 +207,13 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) (void) rhport; (void) config_num; // Nothing to do + + // Clear current pending + NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE; + NRF_USBD->EVENTS_USBEVENT = 0; + + // Enable usb event for suspend and resume + NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk; } //--------------------------------------------------------------------+ @@ -358,13 +365,34 @@ void USBD_IRQHandler(void) } } - /*------------- Interrupt Processing -------------*/ if ( int_status & USBD_INTEN_USBRESET_Msk ) { bus_reset(); dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); } + if ( int_status & USBD_INTEN_SOF_Msk ) + { + dcd_event_bus_signal(0, DCD_EVENT_SOF, true); + } + + if ( int_status & USBD_INTEN_USBEVENT_Msk ) + { + uint32_t const evt_cause = NRF_USBD->EVENTCAUSE; + + if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk ) + { + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + } + + if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk ) + { + dcd_event_bus_signal(0, DCD_EVENT_RESUME , true); + } + + NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt + } + if ( int_status & EDPT_END_ALL_MASK ) { // DMA complete move data from SRAM -> Endpoint @@ -502,12 +530,6 @@ void USBD_IRQHandler(void) } } } - - // SOF interrupt - if ( int_status & USBD_INTEN_SOF_Msk ) - { - dcd_event_bus_signal(0, DCD_EVENT_SOF, true); - } } #endif diff --git a/src/portable/nordic/nrf5x/hal_nrf5x.c b/src/portable/nordic/nrf5x/hal_nrf5x.c index 8477a56c..730b580b 100644 --- a/src/portable/nordic/nrf5x/hal_nrf5x.c +++ b/src/portable/nordic/nrf5x/hal_nrf5x.c @@ -212,8 +212,8 @@ void tusb_hal_nrf_power_event (uint32_t event) nrf_usbd_isosplit_set(USBD_ISOSPLIT_SPLIT_HalfIN); - // Enable interrupt. SOF is used as CDC auto flush - NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk | + // Enable interrupt + NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk; // Enable interrupt, priorities should be set by application diff --git a/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c b/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c index 65b34595..0b0c10bc 100644 --- a/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c +++ b/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c @@ -339,7 +339,7 @@ void USB_IRQHandler(void) // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_MASK) { - dcd_event_bus_signal(0, DCD_EVENT_SUSPENDED, true); + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } } } diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index f18a91b1..ea95918a 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -481,7 +481,7 @@ static void bus_event_isr(uint8_t rhport) { if (dev_status & SIE_DEV_STATUS_SUSPEND_MASK) { - dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true); + dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } else { diff --git a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c index a92a1c7b..9be1af67 100644 --- a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c +++ b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c @@ -303,7 +303,7 @@ void hal_dcd_isr(uint8_t rhport) // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. if ((lpc_usb->DEVICEADDR >> 25) & 0x0f) { - dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true); + dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } } } From 1c2beba85c223bcf401f877b0c29025490fcdaa4 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 29 Mar 2019 16:23:00 +0700 Subject: [PATCH 04/22] working on suspend and resume change dcd_init signature --- examples/device/cdc_msc_hid/src/main.c | 12 ++++++ src/class/cdc/cdc_device.h | 1 - src/common/tusb_types.h | 7 ++++ src/device/dcd.h | 9 +++- src/device/usbd.c | 42 +++++++++++++------ src/device/usbd.h | 11 +++-- src/portable/microchip/samd21/dcd_samd21.c | 4 +- src/portable/microchip/samd51/dcd_samd51.c | 4 +- src/portable/nordic/nrf5x/dcd_nrf5x.c | 3 +- .../nxp/lpc11_13_15/dcd_lpc11_13_15.c | 4 +- src/portable/nxp/lpc17_40/dcd_lpc17_40.c | 4 +- src/portable/nxp/lpc18_43/dcd_lpc18_43.c | 4 +- src/portable/st/stm32f3/dcd_stm32f3.c | 4 +- src/portable/st/stm32f4/dcd_stm32f4.c | 4 +- 14 files changed, 71 insertions(+), 42 deletions(-) diff --git a/examples/device/cdc_msc_hid/src/main.c b/examples/device/cdc_msc_hid/src/main.c index 75d9a31d..1416852f 100644 --- a/examples/device/cdc_msc_hid/src/main.c +++ b/examples/device/cdc_msc_hid/src/main.c @@ -127,6 +127,7 @@ void usb_hid_task(void) if ( board_millis() < start_ms + interval_ms) return; // not enough time start_ms += interval_ms; +#if 1 uint32_t const btn = board_buttons(); /*------------- Keyboard -------------*/ @@ -160,18 +161,29 @@ void usb_hid_task(void) if ( btn & 0x04 ) tud_hid_mouse_move( 0 , -DELTA); // up if ( btn & 0x08 ) tud_hid_mouse_move( 0 , DELTA); // down } +#endif } uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) { // TODO not Implemented + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + return 0; } void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { // TODO not Implemented + (void) report_id; + (void) report_type; + (void) buffer; + (void) bufsize; } + #endif //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index d9a200dd..25c721e1 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -38,7 +38,6 @@ #define CFG_TUD_CDC_EPSIZE 64 #endif - #ifdef __cplusplus extern "C" { #endif diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index d4a623aa..5e4da898 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -103,6 +103,13 @@ typedef enum TUSB_REQ_SYNCH_FRAME ///< 12 }tusb_request_code_t; +typedef enum +{ + TUSB_REQ_FEATURE_EDPT_HALT = 0, + TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1, + TUSB_REQ_FEATURE_TEST_MODE = 2 +}tusb_request_feature_selector_t; + typedef enum { TUSB_REQ_TYPE_STANDARD = 0, diff --git a/src/device/dcd.h b/src/device/dcd.h index 9abebc2a..f47c3714 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -80,7 +80,9 @@ TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); /*------------------------------------------------------------------*/ /* Device API *------------------------------------------------------------------*/ -bool dcd_init (uint8_t rhport); + +// Initialize controller to device mode +void dcd_init (uint8_t rhport); // Enable device interrupt void dcd_int_enable (uint8_t rhport); @@ -91,9 +93,12 @@ void dcd_int_disable(uint8_t rhport); // Receive Set Address request, mcu port must also include status IN response void dcd_set_address(uint8_t rhport, uint8_t dev_addr); -// Receive Set Config request +// Receive Set Configure request void dcd_set_config (uint8_t rhport, uint8_t config_num); +// Wake up host +void dcd_remote_wakeup(uint8_t rhport); + /*------------------------------------------------------------------*/ /* Endpoint API * - open : Configure endpoint's registers diff --git a/src/device/usbd.c b/src/device/usbd.c index 933e0f84..5127cfaa 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -40,12 +40,13 @@ // Device Data //--------------------------------------------------------------------+ typedef struct { - volatile uint8_t config_num; // 0 is non-configure ~ disconnect + volatile uint8_t config_num; // 0 is non-configured ~ disconnect + bool remote_wakeup_en; uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid ) - uint8_t ep_busy_mask[2]; // bit mask for busy endpoint +// uint8_t ep_busy_mask[2]; // bit mask for busy endpoint uint8_t ep_stall_mask[2]; // bit mask for stalled endpoint }usbd_device_t; @@ -186,7 +187,7 @@ bool usbd_init (void) for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++) usbd_class_drivers[i].init(); // Init device controller driver - TU_ASSERT(dcd_init(TUD_OPT_RHPORT)); + dcd_init(TUD_OPT_RHPORT); dcd_int_enable(TUD_OPT_RHPORT); return true; @@ -352,6 +353,20 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const if ( data_buf == NULL || data_len == 0 ) return false; break; + case TUSB_REQ_SET_FEATURE: + if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) + { + // Host enable remote wake up before suspending especially HID device + } + break; + + case TUSB_REQ_CLEAR_FEATURE: + if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) + { + // Host disable remote wake up after resuming + } + break; + default: TU_BREAKPOINT(); return false; @@ -386,15 +401,19 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; case TUSB_REQ_CLEAR_FEATURE: - // only endpoint feature is halted/stalled - dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex)); - usbd_control_status(rhport, p_request); + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) + { + dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex)); + usbd_control_status(rhport, p_request); + } break; case TUSB_REQ_SET_FEATURE: - // only endpoint feature is halted/stalled - usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex)); - usbd_control_status(rhport, p_request); + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) + { + usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex)); + usbd_control_status(rhport, p_request); + } break; default: @@ -556,11 +575,8 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) break; case DCD_EVENT_SUSPEND: - // TODO support suspended - break; - case DCD_EVENT_RESUME: - // TODO support resume + osal_queue_send(_usbd_q, event, in_isr); break; case DCD_EVENT_SETUP_RECEIVED: diff --git a/src/device/usbd.h b/src/device/usbd.h index 614b4f31..6bf7eca0 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -60,7 +60,6 @@ typedef struct { }tud_desc_set_t; - // Must be defined by application extern tud_desc_set_t tud_desc_set; @@ -70,6 +69,8 @@ extern tud_desc_set_t tud_desc_set; bool tud_mounted(void); void tud_task (void); +bool tud_remote_wakeup(void); + //--------------------------------------------------------------------+ // APPLICATION CALLBACK (WEAK is optional) //--------------------------------------------------------------------+ @@ -77,10 +78,14 @@ void tud_task (void); // Callback invoked when device is mounted (configured) ATTR_WEAK void tud_mount_cb(void); -// Callback invoked when device is unmounted (bus reset/unplugged) +// Callback invoked when device is unmounted ATTR_WEAK void tud_umount_cb(void); -//void tud_device_suspended_cb(void); +// Callback invoked when device is suspended +ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); + +// Callback invoked when device is resumed +ATTR_WEAK void tud_resume_cb(void); #ifdef __cplusplus } diff --git a/src/portable/microchip/samd21/dcd_samd21.c b/src/portable/microchip/samd21/dcd_samd21.c index 723bd6c3..a340c888 100644 --- a/src/portable/microchip/samd21/dcd_samd21.c +++ b/src/portable/microchip/samd21/dcd_samd21.c @@ -57,7 +57,7 @@ static void bus_reset(void) { /*------------------------------------------------------------------*/ /* Controller API *------------------------------------------------------------------*/ -bool dcd_init (uint8_t rhport) +void dcd_init (uint8_t rhport) { (void) rhport; @@ -80,8 +80,6 @@ bool dcd_init (uint8_t rhport) while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {} USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST; - - return true; } void dcd_int_enable(uint8_t rhport) diff --git a/src/portable/microchip/samd51/dcd_samd51.c b/src/portable/microchip/samd51/dcd_samd51.c index 9869956c..13250c38 100644 --- a/src/portable/microchip/samd51/dcd_samd51.c +++ b/src/portable/microchip/samd51/dcd_samd51.c @@ -57,7 +57,7 @@ static void bus_reset(void) { /*------------------------------------------------------------------*/ /* Controller API *------------------------------------------------------------------*/ -bool dcd_init (uint8_t rhport) +void dcd_init (uint8_t rhport) { (void) rhport; @@ -79,8 +79,6 @@ bool dcd_init (uint8_t rhport) USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY; while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {} USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST; - - return true; } void dcd_int_enable(uint8_t rhport) diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 928ef671..edaef7cc 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -177,10 +177,9 @@ static void xact_in_prepare(uint8_t epnum) //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ -bool dcd_init (uint8_t rhport) +void dcd_init (uint8_t rhport) { (void) rhport; - return true; } void dcd_int_enable(uint8_t rhport) diff --git a/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c b/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c index 0b0c10bc..f01bed1c 100644 --- a/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c +++ b/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c @@ -153,7 +153,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) LPC_USB->DEVCMDSTAT |= dev_addr; } -bool dcd_init(uint8_t rhport) +void dcd_init(uint8_t rhport) { (void) rhport; @@ -166,8 +166,6 @@ bool dcd_init(uint8_t rhport) CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK; NVIC_EnableIRQ(USB0_IRQn); - - return true; } //--------------------------------------------------------------------+ diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index ea95918a..5da18d52 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -166,7 +166,7 @@ static void bus_reset(void) tu_memclr(&_dcd, sizeof(dcd_data_t)); } -bool dcd_init(uint8_t rhport) +void dcd_init(uint8_t rhport) { (void) rhport; @@ -186,8 +186,6 @@ bool dcd_init(uint8_t rhport) // USB IRQ priority should be set by application previously NVIC_ClearPendingIRQ(USB_IRQn); NVIC_EnableIRQ(USB_IRQn); - - return true; } void dcd_int_enable(uint8_t rhport) diff --git a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c index 9be1af67..b272a143 100644 --- a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c +++ b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c @@ -121,7 +121,7 @@ static void bus_reset(uint8_t rhport) p_dcd->qhd[0].int_on_setup = 1; // OUT only } -bool dcd_init(uint8_t rhport) +void dcd_init(uint8_t rhport) { LPC_USBHS_T* const lpc_usb = LPC_USB[rhport]; dcd_data_t* p_dcd = dcd_data_ptr[rhport]; @@ -134,8 +134,6 @@ bool dcd_init(uint8_t rhport) lpc_usb->USBCMD_D &= ~0x00FF0000; // Interrupt Threshold Interval = 0 lpc_usb->USBCMD_D |= TU_BIT(0); // connect - - return true; } void dcd_int_enable(uint8_t rhport) diff --git a/src/portable/st/stm32f3/dcd_stm32f3.c b/src/portable/st/stm32f3/dcd_stm32f3.c index 138c454a..41f82891 100644 --- a/src/portable/st/stm32f3/dcd_stm32f3.c +++ b/src/portable/st/stm32f3/dcd_stm32f3.c @@ -35,10 +35,8 @@ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ - -bool dcd_init (uint8_t rhport) +void dcd_init (uint8_t rhport) { - return true; } // Enable device interrupt diff --git a/src/portable/st/stm32f4/dcd_stm32f4.c b/src/portable/st/stm32f4/dcd_stm32f4.c index db72f92d..f0d6e7d5 100644 --- a/src/portable/st/stm32f4/dcd_stm32f4.c +++ b/src/portable/st/stm32f4/dcd_stm32f4.c @@ -128,7 +128,7 @@ static void end_of_reset(void) { /*------------------------------------------------------------------*/ /* Controller API *------------------------------------------------------------------*/ -bool dcd_init (uint8_t rhport) +void dcd_init (uint8_t rhport) { (void) rhport; @@ -161,8 +161,6 @@ bool dcd_init (uint8_t rhport) // Enable pullup, enable peripheral. USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_PWRDWN; - - return true; } void dcd_int_enable (uint8_t rhport) From 3a38cde53dc7118b39eafd4fd1f69be4fd7dcd14 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 29 Mar 2019 16:37:08 +0700 Subject: [PATCH 05/22] support set/clear feature Device_remote_wakeup --- src/device/usbd.c | 12 +++++++++++- src/device/usbd.h | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 5127cfaa..7a0d1bca 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -167,13 +167,21 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) ); //--------------------------------------------------------------------+ -// APPLICATION API +// Application API //--------------------------------------------------------------------+ bool tud_mounted(void) { return _usbd_dev.config_num > 0; } +bool tud_remote_wakeup(void) +{ + // only wake up host if this feature is enabled + if (_usbd_dev.remote_wakeup_en ) dcd_remote_wakeup(TUD_OPT_RHPORT); + + return _usbd_dev.remote_wakeup_en; +} + //--------------------------------------------------------------------+ // USBD Task //--------------------------------------------------------------------+ @@ -357,6 +365,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) { // Host enable remote wake up before suspending especially HID device + _usbd_dev.remote_wakeup_en = true; } break; @@ -364,6 +373,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) { // Host disable remote wake up after resuming + _usbd_dev.remote_wakeup_en = false; } break; diff --git a/src/device/usbd.h b/src/device/usbd.h index 6bf7eca0..eb99337e 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -37,7 +37,7 @@ //--------------------------------------------------------------------+ // INCLUDE //--------------------------------------------------------------------+ -#include +#include "common/tusb_common.h" #include "device/dcd.h" //--------------------------------------------------------------------+ From 7d9b68a7b9e120e3f5b1fe23096c3c620558b87a Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 29 Mar 2019 16:55:58 +0700 Subject: [PATCH 06/22] clean up control req a bit --- src/device/usbd.c | 217 ++++++++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 103 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 7a0d1bca..7ca81e8d 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -324,118 +324,129 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const { usbd_control_set_complete_callback(NULL); - if ( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient && - TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type ) + switch ( p_request->bmRequestType_bit.recipient ) { - //------------- Standard Device Requests e.g in enumeration -------------// - void* data_buf = NULL; - uint16_t data_len = 0; - - switch ( p_request->bRequest ) - { - case TUSB_REQ_SET_ADDRESS: - // DCD must include zero-length status response since depending on mcu, - // status could be sent either before or after changing device address - dcd_set_address(rhport, (uint8_t) p_request->wValue); - return true; // skip the rest - break; - - case TUSB_REQ_GET_CONFIGURATION: - data_buf = (uint8_t*) &_usbd_dev.config_num; - data_len = 1; - break; - - case TUSB_REQ_SET_CONFIGURATION: + //------------- Device Requests e.g in enumeration -------------// + case TUSB_REQ_RCPT_DEVICE: + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { - uint8_t const config = (uint8_t) p_request->wValue; - - dcd_set_config(rhport, config); - _usbd_dev.config_num = config; - - TU_ASSERT( TUSB_ERROR_NONE == process_set_config(rhport) ); - } - break; - - case TUSB_REQ_GET_DESCRIPTOR: - data_buf = (void*) get_descriptor(p_request, &data_len); - if ( data_buf == NULL || data_len == 0 ) return false; - break; - - case TUSB_REQ_SET_FEATURE: - if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) - { - // Host enable remote wake up before suspending especially HID device - _usbd_dev.remote_wakeup_en = true; - } - break; - - case TUSB_REQ_CLEAR_FEATURE: - if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) - { - // Host disable remote wake up after resuming - _usbd_dev.remote_wakeup_en = false; - } - break; - - default: + // Non standard request is not supported TU_BREAKPOINT(); - return false; - } + return false; + } + + void* data_buf = NULL; + uint16_t data_len = 0; + + switch ( p_request->bRequest ) + { + case TUSB_REQ_SET_ADDRESS: + // DCD must include zero-length status response since depending on mcu, + // status could be sent either before or after changing device address + dcd_set_address(rhport, (uint8_t) p_request->wValue); + return true; // skip the rest + break; + + case TUSB_REQ_GET_CONFIGURATION: + data_buf = (uint8_t*) &_usbd_dev.config_num; + data_len = 1; + break; + + case TUSB_REQ_SET_CONFIGURATION: + { + uint8_t const config = (uint8_t) p_request->wValue; + + dcd_set_config(rhport, config); + _usbd_dev.config_num = config; + + TU_ASSERT( process_set_config(rhport) ); + } + break; + + case TUSB_REQ_GET_DESCRIPTOR: + data_buf = (void*) get_descriptor(p_request, &data_len); + if ( data_buf == NULL || data_len == 0 ) return false; + break; + + case TUSB_REQ_SET_FEATURE: + if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) + { + // Host enable remote wake up before suspending especially HID device + _usbd_dev.remote_wakeup_en = true; + } + break; + + case TUSB_REQ_CLEAR_FEATURE: + if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) + { + // Host disable remote wake up after resuming + _usbd_dev.remote_wakeup_en = false; + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + + usbd_control_xfer(rhport, p_request, data_buf, data_len); + break; - usbd_control_xfer(rhport, p_request, data_buf, data_len); - } - else if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient ) - { //------------- Class/Interface Specific Request -------------// - uint8_t const itf = tu_u16_low(p_request->wIndex); - uint8_t const drvid = _usbd_dev.itf2drv[ itf ]; - - TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT); - - usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_request_complete ); - - // control endpoint will be stalled if driver return false - return usbd_class_drivers[drvid].control_request(rhport, p_request); - } - else if ( p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT && - p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) - { - //------------- Endpoint Request -------------// - switch ( p_request->bRequest ) + case TUSB_REQ_RCPT_INTERFACE: { - case TUSB_REQ_GET_STATUS: - { - uint16_t status = usbd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000; - usbd_control_xfer(rhport, p_request, &status, 2); - } - break; + uint8_t const itf = tu_u16_low(p_request->wIndex); + uint8_t const drvid = _usbd_dev.itf2drv[itf]; - case TUSB_REQ_CLEAR_FEATURE: - if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) - { - dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex)); - usbd_control_status(rhport, p_request); - } - break; + TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT); - case TUSB_REQ_SET_FEATURE: - if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) - { - usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex)); - usbd_control_status(rhport, p_request); - } - break; + usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_request_complete ); - default: - TU_BREAKPOINT(); - return false; + // stall control endpoint if driver return false + return usbd_class_drivers[drvid].control_request(rhport, p_request); } - } - else - { - //------------- Unsupported Request -------------// - TU_BREAKPOINT(); - return false; + break; + + //------------- Endpoint Request -------------// + case TUSB_REQ_RCPT_ENDPOINT: + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) + { + // Non standard request is not supported + TU_BREAKPOINT(); + return false; + } + + switch ( p_request->bRequest ) + { + case TUSB_REQ_GET_STATUS: + { + uint16_t status = usbd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000; + usbd_control_xfer(rhport, p_request, &status, 2); + } + break; + + case TUSB_REQ_CLEAR_FEATURE: + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) + { + dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex)); + usbd_control_status(rhport, p_request); + } + break; + + case TUSB_REQ_SET_FEATURE: + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) + { + usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex)); + usbd_control_status(rhport, p_request); + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + break; + + // Unknown recipient + default: TU_BREAKPOINT(); return false; } return true; @@ -488,7 +499,7 @@ static bool process_set_config(uint8_t rhport) // invoke callback if (tud_mount_cb) tud_mount_cb(); - return TUSB_ERROR_NONE; + return true; } // Helper marking endpoint of interface belongs to class driver From 28610198dfe70e98d3c2dcadb229f5ff12e2faf1 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 29 Mar 2019 17:42:10 +0700 Subject: [PATCH 07/22] clean up --- README.md | 6 +++--- examples/device/cdc_msc_hid/src/main.c | 19 +++++++++++++------ src/device/usbd.h | 11 ++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 635312eb..888e73f5 100644 --- a/README.md +++ b/README.md @@ -47,15 +47,15 @@ Currently the following OS are supported with tinyusb out of the box with a simp The stack supports the following MCUs - **Nordic:** nRF52840 -- **NXP:** LPC11Uxx, LPC13xx, LPC175x_6x, LPC177x_8x, LPC40xx, LPC43xx -- **MicroChip:** SAMD21, SAMD51 (device only) +- **NXP:** LPC11Uxx, LPC13xx, LPC175x_6x, LPC177x_8x, LPC18xx, LPC40xx, LPC43xx +- **MicroChip:** SAMD21, SAMD51 - **ST:** STM32F4 [Here is the list of supported Boards](docs/boards.md) ## Compiler & IDE -The stack is developed with GCC compiler, and should be compilable with others. However, it requires C99 to build with. Folder `examples` provide Makefile and Segger Embedded Studio build support. +The stack is developed with GCC compiler, and should be compilable with others. Folder `examples` provide Makefile and Segger Embedded Studio build support. ## Getting Started diff --git a/examples/device/cdc_msc_hid/src/main.c b/examples/device/cdc_msc_hid/src/main.c index 1416852f..53161fe8 100644 --- a/examples/device/cdc_msc_hid/src/main.c +++ b/examples/device/cdc_msc_hid/src/main.c @@ -34,6 +34,14 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ + +/* Blink pattern + * - 250 ms : device not mounted + * - 1000 ms : device mounted + * - 2000 ms : device is suspended + */ +static uint32_t blink_interval_ms = 250; + void led_blinking_task(void); extern void virtual_com_task(void); @@ -187,18 +195,19 @@ void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_t #endif //--------------------------------------------------------------------+ -// tinyusb callbacks +// Device callbacks //--------------------------------------------------------------------+ // Invoked when device is mounted void tud_mount_cb(void) { - + blink_interval_ms = 1000; } // Invoked when device is unmounted void tud_umount_cb(void) { + blink_interval_ms = 250; } //--------------------------------------------------------------------+ @@ -206,14 +215,12 @@ void tud_umount_cb(void) //--------------------------------------------------------------------+ void led_blinking_task(void) { - const uint32_t interval_ms = 1000; static uint32_t start_ms = 0; - static bool led_state = false; // Blink every 1000 ms - if ( board_millis() < start_ms + interval_ms) return; // not enough time - start_ms += interval_ms; + if ( board_millis() < start_ms + blink_interval_ms) return; // not enough time + start_ms += blink_interval_ms; board_led_control(led_state); led_state = 1 - led_state; // toggle diff --git a/src/device/usbd.h b/src/device/usbd.h index eb99337e..1a4a2183 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -34,16 +34,9 @@ extern "C" { #endif -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ #include "common/tusb_common.h" #include "device/dcd.h" -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - /// \brief Descriptor pointer collector to all the needed. typedef struct { void const * device; ///< pointer to device descriptor \ref tusb_desc_device_t @@ -64,7 +57,7 @@ typedef struct { extern tud_desc_set_t tud_desc_set; //--------------------------------------------------------------------+ -// APPLICATION API +// Application API //--------------------------------------------------------------------+ bool tud_mounted(void); void tud_task (void); @@ -72,7 +65,7 @@ void tud_task (void); bool tud_remote_wakeup(void); //--------------------------------------------------------------------+ -// APPLICATION CALLBACK (WEAK is optional) +// Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ // Callback invoked when device is mounted (configured) From 93a853cd5b5a7840536939d5a43c5ea3a0dcdfc3 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 30 Mar 2019 02:26:15 +0700 Subject: [PATCH 08/22] usbd add connected, suspended, remote_wakeup - remove use of osal_queue_reset --- examples/device/cdc_msc_hid/src/main.c | 14 ++++- src/device/dcd.h | 4 +- src/device/usbd.c | 85 ++++++++++++++++++-------- src/osal/osal.h | 1 - src/osal/osal_freertos.h | 5 -- src/osal/osal_mynewt.h | 5 -- src/osal/osal_none.h | 7 --- src/portable/nordic/nrf5x/dcd_nrf5x.c | 20 +++--- 8 files changed, 85 insertions(+), 56 deletions(-) diff --git a/examples/device/cdc_msc_hid/src/main.c b/examples/device/cdc_msc_hid/src/main.c index 53161fe8..1fa0fead 100644 --- a/examples/device/cdc_msc_hid/src/main.c +++ b/examples/device/cdc_msc_hid/src/main.c @@ -38,7 +38,7 @@ /* Blink pattern * - 250 ms : device not mounted * - 1000 ms : device mounted - * - 2000 ms : device is suspended + * - 2500 ms : device is suspended */ static uint32_t blink_interval_ms = 250; @@ -210,6 +210,18 @@ void tud_umount_cb(void) blink_interval_ms = 250; } +// Invoked when device is suspended +void tud_suspend_cb(bool remote_wakeup_en) +{ + (void) remote_wakeup_en; + blink_interval_ms = 2500; +} + +void tud_resume_cb(void) +{ + blink_interval_ms = 1000; +} + //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ diff --git a/src/device/dcd.h b/src/device/dcd.h index f47c3714..8dafef66 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -48,7 +48,7 @@ typedef enum DCD_EVENT_SETUP_RECEIVED, DCD_EVENT_XFER_COMPLETE, - USBD_EVT_FUNC_CALL + USBD_EVENT_FUNC_CALL } dcd_eventid_t; typedef struct ATTR_ALIGNED(4) @@ -67,7 +67,7 @@ typedef struct ATTR_ALIGNED(4) uint32_t len; }xfer_complete; - // USBD_EVT_FUNC_CALL + // USBD_EVENT_FUNC_CALL struct { void (*func) (void*); void* param; diff --git a/src/device/usbd.c b/src/device/usbd.c index 7ca81e8d..4089cf72 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -40,14 +40,20 @@ // Device Data //--------------------------------------------------------------------+ typedef struct { - volatile uint8_t config_num; // 0 is non-configured ~ disconnect - bool remote_wakeup_en; + volatile uint8_t config_num; - uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) - uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid ) + struct ATTR_PACKED + { + volatile uint8_t connected : 1; + volatile uint8_t suspended : 1; + uint8_t remote_wakeup_en : 1; + }; // uint8_t ep_busy_mask[2]; // bit mask for busy endpoint uint8_t ep_stall_mask[2]; // bit mask for stalled endpoint + + uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) + uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid ) }usbd_device_t; static usbd_device_t _usbd_dev = { 0 }; @@ -246,8 +252,27 @@ void tud_task (void) if ( !osal_queue_receive(_usbd_q, &event) ) return; + // Skip event if device is not connected except BUS_RESET & UNPLUGGED & FUNC_CALL + if ( !(_usbd_dev.connected || event.event_id == DCD_EVENT_UNPLUGGED || + event.event_id == DCD_EVENT_BUS_RESET || event.event_id == USBD_EVENT_FUNC_CALL) ) + { + return; + } + switch ( event.event_id ) { + case DCD_EVENT_BUS_RESET: + usbd_reset(event.rhport); + _usbd_dev.connected = 1; // connected after bus reset + break; + + case DCD_EVENT_UNPLUGGED: + usbd_reset(event.rhport); + + // invoke callback + if (tud_umount_cb) tud_umount_cb(); + break; + case DCD_EVENT_SETUP_RECEIVED: // Process control request if ( !process_control_request(event.rhport, &event.setup_received) ) @@ -278,19 +303,15 @@ void tud_task (void) } break; - case DCD_EVENT_BUS_RESET: - usbd_reset(event.rhport); - // TODO remove since if task is too slow, we could clear the event of the new attached - osal_queue_reset(_usbd_q); + // NOTE: When unplugging device, the D+/D- state are unstable and can accidentally meet the + // SUSPEND condition ( Idle for 3ms ). Most likely when this happen both suspend and resume + // are submitted by DCD before the actual UNPLUGGED + case DCD_EVENT_SUSPEND: + if (tud_suspend_cb) tud_suspend_cb( _usbd_dev.remote_wakeup_en ); break; - case DCD_EVENT_UNPLUGGED: - usbd_reset(event.rhport); - // TODO remove since if task is too slow, we could clear the event of the new attached - osal_queue_reset(_usbd_q); - - // invoke callback - if (tud_umount_cb) tud_umount_cb(); + case DCD_EVENT_RESUME: + if (tud_resume_cb) tud_resume_cb(); break; case DCD_EVENT_SOF: @@ -303,7 +324,7 @@ void tud_task (void) } break; - case USBD_EVT_FUNC_CALL: + case USBD_EVENT_FUNC_CALL: if ( event.func_call.func ) event.func_call.func(event.func_call.param); break; @@ -555,9 +576,8 @@ static void const* get_descriptor(tusb_control_request_t const * p_request, uint }else { // out of range - /* The 0xEE index string is a Microsoft USB extension. - * It can be used to tell Windows what driver it should use for the device !!! - */ + // The 0xEE index string is a Microsoft USB extension. + // It can be used to tell Windows what driver it should use for the device !!! return NULL; } break; @@ -587,7 +607,8 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) break; case DCD_EVENT_UNPLUGGED: - _usbd_dev.config_num = 0; // mark disconnected + _usbd_dev.connected = 0; + _usbd_dev.config_num = 0; osal_queue_send(_usbd_q, event, in_isr); break; @@ -595,9 +616,23 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) // nothing to do now break; + // NOTE: When unplugging device, the D+/D- state are unstable and can accidentally meet the + // SUSPEND condition ( Idle for 3ms ). Most likely when this happen both suspend and resume + // are submitted by DCD before the actual UNPLUGGED case DCD_EVENT_SUSPEND: + if (_usbd_dev.connected ) // skip event if disconnected + { + _usbd_dev.suspended = 1; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + case DCD_EVENT_RESUME: - osal_queue_send(_usbd_q, event, in_isr); + if (_usbd_dev.connected ) // skip event if disconnected + { + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + } break; case DCD_EVENT_SETUP_RECEIVED: @@ -606,14 +641,14 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) case DCD_EVENT_XFER_COMPLETE: // skip zero-length control status complete event, should dcd notifies us. - if ( 0 == tu_edpt_number(event->xfer_complete.ep_addr) && event->xfer_complete.len == 0) break; + if ( (0 == tu_edpt_number(event->xfer_complete.ep_addr)) && (event->xfer_complete.len == 0) ) break; osal_queue_send(_usbd_q, event, in_isr); TU_ASSERT(event->xfer_complete.result == XFER_RESULT_SUCCESS,); break; - // Not an DCD event, just a convenient way to defer ISR function should we need - case USBD_EVT_FUNC_CALL: + // Not an DCD event, just a convenient way to defer ISR function should we need to + case USBD_EVENT_FUNC_CALL: osal_queue_send(_usbd_q, event, in_isr); break; @@ -683,7 +718,7 @@ void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) dcd_event_t event = { .rhport = 0, - .event_id = USBD_EVT_FUNC_CALL, + .event_id = USBD_EVENT_FUNC_CALL, }; event.func_call.func = func; diff --git a/src/osal/osal.h b/src/osal/osal.h index 7ceb2212..d6c33de3 100644 --- a/src/osal/osal.h +++ b/src/osal/osal.h @@ -61,7 +61,6 @@ typedef void (*osal_task_func_t)( void * ); * osal_queue_t osal_queue_create(osal_queue_def_t* qdef) * osal_queue_receive (osal_queue_t const queue_hdl, void *p_data, uint32_t msec, uint32_t *p_error) * bool osal_queue_send(osal_queue_t const queue_hdl, void const * data, bool in_isr) - * osal_queue_reset() * * Semaphore * osal_semaphore_def_t, osal_semaphore_t diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h index 639501bb..973a1854 100644 --- a/src/osal/osal_freertos.h +++ b/src/osal/osal_freertos.h @@ -125,11 +125,6 @@ static inline bool osal_queue_send(osal_queue_t const queue_hdl, void const * da return in_isr ? xQueueSendToBackFromISR(queue_hdl, data, NULL) : xQueueSendToBack(queue_hdl, data, OSAL_TIMEOUT_WAIT_FOREVER); } -static inline void osal_queue_reset(osal_queue_t const queue_hdl) -{ - xQueueReset(queue_hdl); -} - #ifdef __cplusplus } #endif diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h index 9fa9f541..6f3d0532 100644 --- a/src/osal/osal_mynewt.h +++ b/src/osal/osal_mynewt.h @@ -161,11 +161,6 @@ static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, b return true; } -static inline void osal_queue_reset(osal_queue_t const queue_hdl) -{ - // TODO implement later -} - #ifdef __cplusplus } #endif diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 6144f3e5..d1d365bb 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -190,13 +190,6 @@ static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, b return success; } -static inline void osal_queue_reset(osal_queue_t const qhdl) -{ - // tusb_hal_int_disable_all(); - tu_fifo_clear(&qhdl->ff); - // tusb_hal_int_enable_all(); -} - #ifdef __cplusplus } #endif diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index edaef7cc..e7e9ae01 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -205,13 +205,14 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) { (void) rhport; (void) config_num; - // Nothing to do - // Clear current pending + // Enable usbevent for suspend and resume detection + // Since the bus signal D+/D- are stable from now on. + + // Clear current pending first NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE; NRF_USBD->EVENTS_USBEVENT = 0; - // Enable usb event for suspend and resume NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk; } @@ -377,19 +378,18 @@ void USBD_IRQHandler(void) if ( int_status & USBD_INTEN_USBEVENT_Msk ) { - uint32_t const evt_cause = NRF_USBD->EVENTCAUSE; + uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & (USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk); + NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt - if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk ) + if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk ) { dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } - - if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk ) + + if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk ) { dcd_event_bus_signal(0, DCD_EVENT_RESUME , true); } - - NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt } if ( int_status & EDPT_END_ALL_MASK ) @@ -397,7 +397,7 @@ void USBD_IRQHandler(void) // DMA complete move data from SRAM -> Endpoint edpt_dma_end(); } - + // Setup tokens are specific to the Control endpoint. if ( int_status & USBD_INTEN_EP0SETUP_Msk ) { From d9682f8240bed8603275ac02608916b7144fd6f5 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 30 Mar 2019 13:48:15 +0700 Subject: [PATCH 09/22] replaced config_num by configured --- src/device/dcd.h | 1 + src/device/usbd.c | 32 +++++++++++++++++++++----------- src/device/usbd_auto_desc.c | 2 +- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/device/dcd.h b/src/device/dcd.h index 8dafef66..63f923fa 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -48,6 +48,7 @@ typedef enum DCD_EVENT_SETUP_RECEIVED, DCD_EVENT_XFER_COMPLETE, + // Not an DCD event, just a convenient way to defer ISR function USBD_EVENT_FUNC_CALL } dcd_eventid_t; diff --git a/src/device/usbd.c b/src/device/usbd.c index 4089cf72..c2b463e7 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -40,13 +40,14 @@ // Device Data //--------------------------------------------------------------------+ typedef struct { - volatile uint8_t config_num; - struct ATTR_PACKED { - volatile uint8_t connected : 1; - volatile uint8_t suspended : 1; - uint8_t remote_wakeup_en : 1; + volatile uint8_t connected : 1; + volatile uint8_t configured : 1; + volatile uint8_t suspended : 1; + + uint8_t remote_wakeup_en : 1; + uint8_t self_powered : 1; }; // uint8_t ep_busy_mask[2]; // bit mask for busy endpoint @@ -177,7 +178,7 @@ void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_reque //--------------------------------------------------------------------+ bool tud_mounted(void) { - return _usbd_dev.config_num > 0; + return _usbd_dev.configured; } bool tud_remote_wakeup(void) @@ -359,6 +360,9 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const void* data_buf = NULL; uint16_t data_len = 0; + uint8_t cfgnum_tmp; + (void) cfgnum_tmp; // only used for GET_CONFIGURATION + switch ( p_request->bRequest ) { case TUSB_REQ_SET_ADDRESS: @@ -369,16 +373,18 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; case TUSB_REQ_GET_CONFIGURATION: - data_buf = (uint8_t*) &_usbd_dev.config_num; + cfgnum_tmp = _usbd_dev.configured ? 1 : 0; + + data_buf = &cfgnum_tmp; data_len = 1; break; case TUSB_REQ_SET_CONFIGURATION: { - uint8_t const config = (uint8_t) p_request->wValue; + uint8_t const cfg_num = (uint8_t) p_request->wValue; - dcd_set_config(rhport, config); - _usbd_dev.config_num = config; + dcd_set_config(rhport, cfg_num); + _usbd_dev.configured = cfg_num ? 1 : 0; TU_ASSERT( process_set_config(rhport) ); } @@ -405,6 +411,10 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const } break; + case TUSB_REQ_GET_STATUS: + + break; + // Unknown/Unsupported request default: TU_BREAKPOINT(); return false; } @@ -608,7 +618,7 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) case DCD_EVENT_UNPLUGGED: _usbd_dev.connected = 0; - _usbd_dev.config_num = 0; + _usbd_dev.configured = 0; osal_queue_send(_usbd_q, event, in_isr); break; diff --git a/src/device/usbd_auto_desc.c b/src/device/usbd_auto_desc.c index c4213edb..8272ea5a 100644 --- a/src/device/usbd_auto_desc.c +++ b/src/device/usbd_auto_desc.c @@ -254,7 +254,7 @@ tusb_desc_device_t const _desc_auto_device = .iProduct = 0x02, .iSerialNumber = 0x03, - .bNumConfigurations = 0x01 // TODO multiple configurations + .bNumConfigurations = 0x01 }; From cabf6abb4f49648ad6eb1f9cb54bfad131f457b7 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 30 Mar 2019 14:34:38 +0700 Subject: [PATCH 10/22] added tud_set_self_powered(), fix #50 reponse to GET_STATUS request --- src/device/usbd.c | 110 ++++++++++++++++++++++++---------------------- src/device/usbd.h | 1 + 2 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index c2b463e7..f90c6b4d 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -181,6 +181,11 @@ bool tud_mounted(void) return _usbd_dev.configured; } +void tud_set_self_powered(bool self_powered) +{ + _usbd_dev.self_powered = self_powered; +} + bool tud_remote_wakeup(void) { // only wake up host if this feature is enabled @@ -194,6 +199,8 @@ bool tud_remote_wakeup(void) //--------------------------------------------------------------------+ bool usbd_init (void) { + tu_varclr(&_usbd_dev); + // Init device queue & task _usbd_q = osal_queue_create(&_usbd_qdef); TU_ASSERT(_usbd_q != NULL); @@ -210,7 +217,13 @@ bool usbd_init (void) static void usbd_reset(uint8_t rhport) { + // self_powered bit is set by application and unchanged + bool self_powered = _usbd_dev.self_powered; + tu_varclr(&_usbd_dev); + + _usbd_dev.self_powered = self_powered; + memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping @@ -304,9 +317,6 @@ void tud_task (void) } break; - // NOTE: When unplugging device, the D+/D- state are unstable and can accidentally meet the - // SUSPEND condition ( Idle for 3ms ). Most likely when this happen both suspend and resume - // are submitted by DCD before the actual UNPLUGGED case DCD_EVENT_SUSPEND: if (tud_suspend_cb) tud_suspend_cb( _usbd_dev.remote_wakeup_en ); break; @@ -357,26 +367,20 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const return false; } - void* data_buf = NULL; - uint16_t data_len = 0; - - uint8_t cfgnum_tmp; - (void) cfgnum_tmp; // only used for GET_CONFIGURATION - switch ( p_request->bRequest ) { case TUSB_REQ_SET_ADDRESS: - // DCD must include zero-length status response since depending on mcu, - // status could be sent either before or after changing device address + // Depending on mcu, status phase could be sent either before or after changing device address + // Therefore DCD must include zero-length status response dcd_set_address(rhport, (uint8_t) p_request->wValue); - return true; // skip the rest + return true; // skip status break; case TUSB_REQ_GET_CONFIGURATION: - cfgnum_tmp = _usbd_dev.configured ? 1 : 0; - - data_buf = &cfgnum_tmp; - data_len = 1; + { + uint8_t cfgnum = _usbd_dev.configured ? 1 : 0; + usbd_control_xfer(rhport, p_request, &cfgnum, 1); + } break; case TUSB_REQ_SET_CONFIGURATION: @@ -387,39 +391,51 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.configured = cfg_num ? 1 : 0; TU_ASSERT( process_set_config(rhport) ); + usbd_control_status(rhport, p_request); } break; case TUSB_REQ_GET_DESCRIPTOR: - data_buf = (void*) get_descriptor(p_request, &data_len); - if ( data_buf == NULL || data_len == 0 ) return false; + { + uint16_t len = 0; + void* buf = (void*) get_descriptor(p_request, &len); + if ( buf == NULL || len == 0 ) return false; + + usbd_control_xfer(rhport, p_request, buf, len); + } break; case TUSB_REQ_SET_FEATURE: - if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) - { - // Host enable remote wake up before suspending especially HID device - _usbd_dev.remote_wakeup_en = true; - } + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + // Host may enable remote wake up before suspending especially HID device + _usbd_dev.remote_wakeup_en = true; + usbd_control_status(rhport, p_request); break; case TUSB_REQ_CLEAR_FEATURE: - if ( TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue ) - { - // Host disable remote wake up after resuming - _usbd_dev.remote_wakeup_en = false; - } + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + // Host may disable remote wake up after resuming + _usbd_dev.remote_wakeup_en = false; + usbd_control_status(rhport, p_request); break; case TUSB_REQ_GET_STATUS: - + { + // Device status bit mask + // - Bit 0: Self Powered + // - Bit 1: Remote Wakeup enabled + uint16_t status = (_usbd_dev.self_powered ? 1 : 0) | (_usbd_dev.remote_wakeup_en ? 2 : 0); + usbd_control_xfer(rhport, p_request, &status, 2); + } break; // Unknown/Unsupported request default: TU_BREAKPOINT(); return false; } - - usbd_control_xfer(rhport, p_request, data_buf, data_len); break; //------------- Class/Interface Specific Request -------------// @@ -439,12 +455,8 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const //------------- Endpoint Request -------------// case TUSB_REQ_RCPT_ENDPOINT: - if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) - { - // Non standard request is not supported - TU_BREAKPOINT(); - return false; - } + // Non standard request is not supported + TU_VERIFY( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type ); switch ( p_request->bRequest ) { @@ -459,16 +471,16 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) { dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex)); - usbd_control_status(rhport, p_request); } + usbd_control_status(rhport, p_request); break; case TUSB_REQ_SET_FEATURE: if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) { usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex)); - usbd_control_status(rhport, p_request); } + usbd_control_status(rhport, p_request); break; // Unknown/Unsupported request @@ -626,23 +638,17 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) // nothing to do now break; - // NOTE: When unplugging device, the D+/D- state are unstable and can accidentally meet the - // SUSPEND condition ( Idle for 3ms ). Most likely when this happen both suspend and resume - // are submitted by DCD before the actual UNPLUGGED case DCD_EVENT_SUSPEND: - if (_usbd_dev.connected ) // skip event if disconnected - { - _usbd_dev.suspended = 1; - osal_queue_send(_usbd_q, event, in_isr); - } + // NOTE: When unplugging device, the D+/D- state are unstable and can accidentally meet the + // SUSPEND condition ( Idle for 3ms ). Most likely when this happen both suspend and resume + // are submitted by DCD before the actual UNPLUGGED + _usbd_dev.suspended = 1; + osal_queue_send(_usbd_q, event, in_isr); break; case DCD_EVENT_RESUME: - if (_usbd_dev.connected ) // skip event if disconnected - { - _usbd_dev.suspended = 0; - osal_queue_send(_usbd_q, event, in_isr); - } + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); break; case DCD_EVENT_SETUP_RECEIVED: diff --git a/src/device/usbd.h b/src/device/usbd.h index 1a4a2183..ebf16682 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -63,6 +63,7 @@ bool tud_mounted(void); void tud_task (void); bool tud_remote_wakeup(void); +void tud_set_self_powered(bool self_powered); //--------------------------------------------------------------------+ // Application Callbacks (WEAK is optional) From b28cc6ddb11ef233b6e6ee25b4a305b4b76cc03c Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 30 Mar 2019 14:47:11 +0700 Subject: [PATCH 11/22] added dcd_remote_wakeup() stub for all ports --- docs/porting.md | 3 + src/device/usbd.c | 2 +- src/device/usbd.h | 11 +++- src/portable/microchip/samd21/dcd_samd21.c | 34 ++++++++++- src/portable/microchip/samd51/dcd_samd51.c | 5 ++ src/portable/nordic/nrf5x/dcd_nrf5x.c | 5 ++ .../nxp/lpc11_13_15/dcd_lpc11_13_15.c | 59 ++++++++++--------- src/portable/nxp/lpc17_40/dcd_lpc17_40.c | 6 +- src/portable/nxp/lpc18_43/dcd_lpc18_43.c | 5 ++ src/portable/st/stm32f3/dcd_stm32f3.c | 8 +++ src/portable/st/stm32f4/dcd_stm32f4.c | 5 ++ 11 files changed, 109 insertions(+), 34 deletions(-) diff --git a/docs/porting.md b/docs/porting.md index 5f1df0d7..5a97b3fb 100644 --- a/docs/porting.md +++ b/docs/porting.md @@ -76,6 +76,9 @@ If your peripheral automatically changes address during enumeration (like the nr ##### dcd_set_config Called when the device received SET_CONFIG request, you can leave this empty if your peripheral does not require any specific action. +##### dcd_remote_wakeup +Called to remote wake up host when suspended (e.g hid keyboard) + #### Special events You must let TinyUSB know when certain events occur so that it can continue its work. There are a few methods you can call to queue events for TinyUSB to process. diff --git a/src/device/usbd.c b/src/device/usbd.c index f90c6b4d..dde98939 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -189,7 +189,7 @@ void tud_set_self_powered(bool self_powered) bool tud_remote_wakeup(void) { // only wake up host if this feature is enabled - if (_usbd_dev.remote_wakeup_en ) dcd_remote_wakeup(TUD_OPT_RHPORT); + if (_usbd_dev.suspended && _usbd_dev.remote_wakeup_en ) dcd_remote_wakeup(TUD_OPT_RHPORT); return _usbd_dev.remote_wakeup_en; } diff --git a/src/device/usbd.h b/src/device/usbd.h index ebf16682..27bfe305 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -59,12 +59,19 @@ extern tud_desc_set_t tud_desc_set; //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ -bool tud_mounted(void); + +// Task function should be called in main/rtos loop void tud_task (void); -bool tud_remote_wakeup(void); +// Check if device is connected and configured +bool tud_mounted(void); + +// Tell stack that device is self or bus powered (default = bus) void tud_set_self_powered(bool self_powered); +// Remote wake up host, only if suspended and enabled by host +bool tud_remote_wakeup(void); + //--------------------------------------------------------------------+ // Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ diff --git a/src/portable/microchip/samd21/dcd_samd21.c b/src/portable/microchip/samd21/dcd_samd21.c index a340c888..39d59486 100644 --- a/src/portable/microchip/samd21/dcd_samd21.c +++ b/src/portable/microchip/samd21/dcd_samd21.c @@ -110,6 +110,18 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) (void) rhport; (void) config_num; // Nothing to do + +#if 0 + // Enable suspend to detect disconnection + // TODO need to distinguish Suspend vs Disconnect + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; + USB->DEVICE.INTENSET.reg |= USB_DEVICE_INTENSET_SUSPEND; +#endif +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; } /*------------------------------------------------------------------*/ @@ -290,13 +302,14 @@ void maybe_transfer_complete(void) { } } -void USB_Handler(void) { - uint32_t int_status = USB->DEVICE.INTFLAG.reg; +void USB_Handler(void) +{ + uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg; /*------------- Interrupt Processing -------------*/ if ( int_status & USB_DEVICE_INTFLAG_EORST ) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_EORST; + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; bus_reset(); dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); } @@ -307,6 +320,21 @@ void USB_Handler(void) { dcd_event_bus_signal(0, DCD_EVENT_SOF, true); } +#if 0 + if ( int_status & USB_DEVICE_INTFLAG_SUSPEND ) + { + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND; + + // disable interrupt to prevent it continue to trigger + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_SUSPEND; + + // TODO need to distinguish Suspend vs Disconnect + // reset address to 0, force host to re-enumerate after resume + USB->DEVICE.DADD.reg = 0; + dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true); + } +#endif + // Setup packet received. maybe_handle_setup_packet(); diff --git a/src/portable/microchip/samd51/dcd_samd51.c b/src/portable/microchip/samd51/dcd_samd51.c index 13250c38..a1702b05 100644 --- a/src/portable/microchip/samd51/dcd_samd51.c +++ b/src/portable/microchip/samd51/dcd_samd51.c @@ -117,6 +117,11 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) // Nothing to do } +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index e7e9ae01..452f2529 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -216,6 +216,11 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk; } +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ diff --git a/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c b/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c index f01bed1c..fff29d5e 100644 --- a/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c +++ b/src/portable/nxp/lpc11_13_15/dcd_lpc11_13_15.c @@ -126,33 +126,6 @@ static inline uint8_t ep_addr2id(uint8_t endpoint_addr) //--------------------------------------------------------------------+ // CONTROLLER API //--------------------------------------------------------------------+ -void dcd_int_enable(uint8_t rhport) -{ - (void) rhport; - NVIC_EnableIRQ(USB0_IRQn); -} - -void dcd_int_disable(uint8_t rhport) -{ - (void) rhport; - NVIC_DisableIRQ(USB0_IRQn); -} - -void dcd_set_config(uint8_t rhport, uint8_t config_num) -{ - (void) rhport; - (void) config_num; -} - -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); - - LPC_USB->DEVCMDSTAT &= ~CMDSTAT_DEVICE_ADDR_MASK; - LPC_USB->DEVCMDSTAT |= dev_addr; -} - void dcd_init(uint8_t rhport) { (void) rhport; @@ -165,9 +138,41 @@ void dcd_init(uint8_t rhport) LPC_USB->DEVCMDSTAT |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK | CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK; + NVIC_ClearPendingIRQ(USB0_IRQn); +} + +void dcd_int_enable(uint8_t rhport) +{ + (void) rhport; NVIC_EnableIRQ(USB0_IRQn); } +void dcd_int_disable(uint8_t rhport) +{ + (void) rhport; + NVIC_DisableIRQ(USB0_IRQn); +} + +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); + + LPC_USB->DEVCMDSTAT &= ~CMDSTAT_DEVICE_ADDR_MASK; + LPC_USB->DEVCMDSTAT |= dev_addr; +} + +void dcd_set_config(uint8_t rhport, uint8_t config_num) +{ + (void) rhport; + (void) config_num; +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + //--------------------------------------------------------------------+ // DCD Endpoint Port //--------------------------------------------------------------------+ diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index 5da18d52..30252f56 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -185,7 +185,6 @@ void dcd_init(uint8_t rhport) // USB IRQ priority should be set by application previously NVIC_ClearPendingIRQ(USB_IRQn); - NVIC_EnableIRQ(USB_IRQn); } void dcd_int_enable(uint8_t rhport) @@ -215,6 +214,11 @@ void dcd_set_config(uint8_t rhport, uint8_t config_num) sie_write(SIE_CMDCODE_CONFIGURE_DEVICE, 1, 1); } +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + //--------------------------------------------------------------------+ // CONTROL HELPER //--------------------------------------------------------------------+ diff --git a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c index b272a143..5c2d27d9 100644 --- a/src/portable/nxp/lpc18_43/dcd_lpc18_43.c +++ b/src/portable/nxp/lpc18_43/dcd_lpc18_43.c @@ -161,6 +161,11 @@ void dcd_set_config(uint8_t rhport, uint8_t config_num) // nothing to do } +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + //--------------------------------------------------------------------+ // HELPER //--------------------------------------------------------------------+ diff --git a/src/portable/st/stm32f3/dcd_stm32f3.c b/src/portable/st/stm32f3/dcd_stm32f3.c index 41f82891..02303747 100644 --- a/src/portable/st/stm32f3/dcd_stm32f3.c +++ b/src/portable/st/stm32f3/dcd_stm32f3.c @@ -55,6 +55,14 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) void dcd_set_config (uint8_t rhport, uint8_t config_num) {} +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { return false; diff --git a/src/portable/st/stm32f4/dcd_stm32f4.c b/src/portable/st/stm32f4/dcd_stm32f4.c index f0d6e7d5..f7128344 100644 --- a/src/portable/st/stm32f4/dcd_stm32f4.c +++ b/src/portable/st/stm32f4/dcd_stm32f4.c @@ -194,6 +194,11 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) // Nothing to do } +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; +} + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ From ee6ed084f48933ec884ceb5cdce2b265df37d78a Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 30 Mar 2019 15:03:35 +0700 Subject: [PATCH 12/22] clean up text --- examples/device/cdc_msc_hid/src/main.c | 4 +++- src/device/usbd.h | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/device/cdc_msc_hid/src/main.c b/examples/device/cdc_msc_hid/src/main.c index 1fa0fead..a8ef0575 100644 --- a/examples/device/cdc_msc_hid/src/main.c +++ b/examples/device/cdc_msc_hid/src/main.c @@ -210,13 +210,15 @@ void tud_umount_cb(void) blink_interval_ms = 250; } -// Invoked when device is suspended +// Invoked when usb bus is suspended +// USB specs: device can only draw up to 2.5 mA from bus void tud_suspend_cb(bool remote_wakeup_en) { (void) remote_wakeup_en; blink_interval_ms = 2500; } +// Invoked when usb bus is resumed void tud_resume_cb(void) { blink_interval_ms = 1000; diff --git a/src/device/usbd.h b/src/device/usbd.h index 27bfe305..2365d645 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -76,16 +76,16 @@ bool tud_remote_wakeup(void); // Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ -// Callback invoked when device is mounted (configured) +// Invoked when device is mounted (configured) ATTR_WEAK void tud_mount_cb(void); -// Callback invoked when device is unmounted +// Invoked when device is unmounted ATTR_WEAK void tud_umount_cb(void); -// Callback invoked when device is suspended +// Invoked when usb bus is suspended, max bus current draw is 2.5 mA ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); -// Callback invoked when device is resumed +// Invoked when usb bus is resumed ATTR_WEAK void tud_resume_cb(void); #ifdef __cplusplus From f3a954e7deaa33db5fed8e807cd146e65aaeb104 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 30 Mar 2019 17:38:00 +0700 Subject: [PATCH 13/22] self powered and remote wakeup support are from configuration descriptor attribute --- src/common/tusb_types.h | 3 +-- src/device/usbd.c | 44 +++++++++++++++++-------------------- src/device/usbd.h | 3 --- src/device/usbd_auto_desc.c | 2 +- 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 5e4da898..3a4ddb4c 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -166,8 +166,7 @@ typedef enum enum { TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5), - TUSB_DESC_CONFIG_ATT_SELF_POWER = TU_BIT(6), - TUSB_DESC_CONFIG_ATT_BUS_POWER = TU_BIT(7) + TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6), }; #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) diff --git a/src/device/usbd.c b/src/device/usbd.c index dde98939..fb624952 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -42,12 +42,13 @@ typedef struct { struct ATTR_PACKED { - volatile uint8_t connected : 1; - volatile uint8_t configured : 1; - volatile uint8_t suspended : 1; + volatile uint8_t connected : 1; + volatile uint8_t configured : 1; + volatile uint8_t suspended : 1; - uint8_t remote_wakeup_en : 1; - uint8_t self_powered : 1; + uint8_t remote_wakeup_en : 1; // enable/disable by host + uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute + uint8_t self_powered : 1; // configuration descriptor's attribute }; // uint8_t ep_busy_mask[2]; // bit mask for busy endpoint @@ -181,17 +182,12 @@ bool tud_mounted(void) return _usbd_dev.configured; } -void tud_set_self_powered(bool self_powered) -{ - _usbd_dev.self_powered = self_powered; -} - bool tud_remote_wakeup(void) { - // only wake up host if this feature is enabled - if (_usbd_dev.suspended && _usbd_dev.remote_wakeup_en ) dcd_remote_wakeup(TUD_OPT_RHPORT); - - return _usbd_dev.remote_wakeup_en; + // only wake up host if this feature is supported and enabled and we are suspended + TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en ); + dcd_remote_wakeup(TUD_OPT_RHPORT); + return true; } //--------------------------------------------------------------------+ @@ -217,13 +213,8 @@ bool usbd_init (void) static void usbd_reset(uint8_t rhport) { - // self_powered bit is set by application and unchanged - bool self_powered = _usbd_dev.self_powered; - tu_varclr(&_usbd_dev); - _usbd_dev.self_powered = self_powered; - memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping @@ -499,13 +490,18 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // This function parse configuration descriptor & open drivers accordingly static bool process_set_config(uint8_t rhport) { - uint8_t const * desc_cfg = (uint8_t const *) usbd_desc_set->config; - TU_ASSERT(desc_cfg != NULL); + tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) usbd_desc_set->config; + TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION); - uint8_t const * p_desc = desc_cfg + sizeof(tusb_desc_configuration_t); - uint16_t const cfg_len = ((tusb_desc_configuration_t*)desc_cfg)->wTotalLength; + // Parse configuration descriptor + _usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1 : 0; + _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED) ? 1 : 0; - while( p_desc < desc_cfg + cfg_len ) + // Parse interface descriptor + uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t); + uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + desc_cfg->wTotalLength; + + while( p_desc < desc_end ) { // Each interface always starts with Interface or Association descriptor if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) diff --git a/src/device/usbd.h b/src/device/usbd.h index 2365d645..d9b9cb8a 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -66,9 +66,6 @@ void tud_task (void); // Check if device is connected and configured bool tud_mounted(void); -// Tell stack that device is self or bus powered (default = bus) -void tud_set_self_powered(bool self_powered); - // Remote wake up host, only if suspended and enabled by host bool tud_remote_wakeup(void); diff --git a/src/device/usbd_auto_desc.c b/src/device/usbd_auto_desc.c index 8272ea5a..e418cd23 100644 --- a/src/device/usbd_auto_desc.c +++ b/src/device/usbd_auto_desc.c @@ -342,7 +342,7 @@ desc_auto_cfg_t const _desc_auto_config_struct = .bConfigurationValue = 1, .iConfiguration = 0x00, - .bmAttributes = TUSB_DESC_CONFIG_ATT_BUS_POWER, + .bmAttributes = TU_BIT(7) | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, .bMaxPower = TUSB_DESC_CONFIG_POWER_MA(100) }, From eabfc53f38dc538b44615aed32db66484a3acca4 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 30 Mar 2019 23:01:23 +0700 Subject: [PATCH 14/22] added tud_suspended() and tud_ready() --- examples/device/cdc_msc_hid/src/main.c | 15 ++++++++++++--- hw/bsp/pca10056/board_pca10056.c | 8 ++++---- src/class/cdc/cdc_device.c | 2 +- src/device/usbd.c | 6 ++++++ src/device/usbd.h | 12 +++++++++++- src/portable/nordic/nrf5x/dcd_nrf5x.c | 5 +++++ 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/examples/device/cdc_msc_hid/src/main.c b/examples/device/cdc_msc_hid/src/main.c index a8ef0575..a203e567 100644 --- a/examples/device/cdc_msc_hid/src/main.c +++ b/examples/device/cdc_msc_hid/src/main.c @@ -135,9 +135,16 @@ void usb_hid_task(void) if ( board_millis() < start_ms + interval_ms) return; // not enough time start_ms += interval_ms; -#if 1 uint32_t const btn = board_buttons(); + if ( tud_suspended() && btn ) + { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + } + +#if 0 /*------------- Keyboard -------------*/ if ( tud_hid_keyboard_ready() ) { @@ -157,8 +164,9 @@ void usb_hid_task(void) tud_hid_keyboard_keycode(0, NULL); } } +#endif - +#if 0 /*------------- Mouse -------------*/ if ( tud_hid_mouse_ready() ) { @@ -211,7 +219,8 @@ void tud_umount_cb(void) } // Invoked when usb bus is suspended -// USB specs: device can only draw up to 2.5 mA from bus +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus void tud_suspend_cb(bool remote_wakeup_en) { (void) remote_wakeup_en; diff --git a/hw/bsp/pca10056/board_pca10056.c b/hw/bsp/pca10056/board_pca10056.c index 90f46635..49350884 100644 --- a/hw/bsp/pca10056/board_pca10056.c +++ b/hw/bsp/pca10056/board_pca10056.c @@ -44,7 +44,7 @@ uint8_t _button_pins[] = { 11, 12, 24, 25 }; -#define BOARD_BUTTON_COUNT sizeof(_button_pins) +#define BUTTON_COUNT sizeof(_button_pins) /*------------------------------------------------------------------*/ @@ -84,7 +84,7 @@ void board_init(void) board_led_control(false); // Button - for(uint8_t i=0; iDPDMVALUE = USBD_DPDMVALUE_STATE_Resume; + NRF_USBD->TASKS_DPDMDRIVE = 1; } //--------------------------------------------------------------------+ @@ -389,6 +392,8 @@ void USBD_IRQHandler(void) if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk ) { dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + + } if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk ) From 2cc4ab2aef3c057f959cfec8a28e64061e04336f Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 31 Mar 2019 23:57:38 +0700 Subject: [PATCH 15/22] nrf5x added LOWPOWER when suspend/resume --- src/portable/nordic/nrf5x/dcd_nrf5x.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 15a1963b..05f42e60 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -220,8 +220,15 @@ void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; + // Bring controller out of low power mode + NRF_USBD->LOWPOWER = 0; + + // Initiate RESUME signal NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume; NRF_USBD->TASKS_DPDMDRIVE = 1; + + // TODO There is no USBEVENT Resume interrupt + // We may manually raise DCD_EVENT_RESUME event here } //--------------------------------------------------------------------+ @@ -393,7 +400,10 @@ void USBD_IRQHandler(void) { dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + // Put controller into low power mode + NRF_USBD->LOWPOWER = 1; + // Leave HFXO disable to application, since it may be used by other } if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk ) From 8457d0d14cb79174d537c2cd210c0dea3c997358 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 1 Apr 2019 18:31:20 +0700 Subject: [PATCH 16/22] add board_button_read() --- .../cdc_msc_hid/ses/samd21/samd21.emProject | 5 +++ examples/device/cdc_msc_hid/src/main.c | 2 +- .../device/cdc_msc_hid_freertos/src/main.c | 2 +- hw/bsp/board.h | 37 ++++++++----------- hw/bsp/ea4088qs/board_ea4088qs.c | 2 +- hw/bsp/ea4357/board_ea4357.c | 2 +- .../lpcxpresso11u68/board_lpcxpresso11u68.c | 2 +- hw/bsp/lpcxpresso1347/board_lpcxpresso1347.c | 2 +- hw/bsp/lpcxpresso1769/board_lpcxpresso1769.c | 2 +- hw/bsp/mcb1800/board_mcb1800.c | 2 +- hw/bsp/metro_m0_express/board.mk | 3 +- .../metro_m0_express/board_metro_m0_express.c | 14 +++++-- hw/bsp/metro_m4_express/board.mk | 3 +- .../metro_m4_express/board_metro_m4_express.c | 12 +++++- hw/bsp/pca10056/board_pca10056.c | 22 +++-------- 15 files changed, 59 insertions(+), 53 deletions(-) diff --git a/examples/device/cdc_msc_hid/ses/samd21/samd21.emProject b/examples/device/cdc_msc_hid/ses/samd21/samd21.emProject index e6587300..30aad55c 100644 --- a/examples/device/cdc_msc_hid/ses/samd21/samd21.emProject +++ b/examples/device/cdc_msc_hid/ses/samd21/samd21.emProject @@ -67,6 +67,11 @@ + + + + + diff --git a/examples/device/cdc_msc_hid/src/main.c b/examples/device/cdc_msc_hid/src/main.c index a203e567..12e331af 100644 --- a/examples/device/cdc_msc_hid/src/main.c +++ b/examples/device/cdc_msc_hid/src/main.c @@ -135,7 +135,7 @@ void usb_hid_task(void) if ( board_millis() < start_ms + interval_ms) return; // not enough time start_ms += interval_ms; - uint32_t const btn = board_buttons(); + uint32_t const btn = board_button_read(); if ( tud_suspended() && btn ) { diff --git a/examples/device/cdc_msc_hid_freertos/src/main.c b/examples/device/cdc_msc_hid_freertos/src/main.c index 388bd9ad..e47937bd 100644 --- a/examples/device/cdc_msc_hid_freertos/src/main.c +++ b/examples/device/cdc_msc_hid_freertos/src/main.c @@ -158,7 +158,7 @@ void usb_hid_task(void* params) if ( board_millis() < start_ms + interval_ms) return; // not enough time start_ms += interval_ms; - uint32_t const btn = board_buttons(); + uint32_t const btn = board_button_read(); /*------------- Keyboard -------------*/ if ( tud_hid_keyboard_ready() ) diff --git a/hw/bsp/board.h b/hw/bsp/board.h index df9d5d11..7d12d68f 100644 --- a/hw/bsp/board.h +++ b/hw/bsp/board.h @@ -46,6 +46,7 @@ //--------------------------------------------------------------------+ // Board Porting API +// For simplicity, only one LED and one Button are used //--------------------------------------------------------------------+ // Initialize on-board peripherals : led, button, uart and USB @@ -54,9 +55,9 @@ void board_init(void); // Turn LED on or off void board_led_control(bool state); -// Get the current state of buttons on the board -// \return Bitmask where a '1' means active (pressed), a '0' means inactive. -uint32_t board_buttons(void); +// Get the current state of button +// a '1' means active (pressed), a '0' means inactive. +uint32_t board_button_read(void); // Get characters from UART int board_uart_read(uint8_t* buf, int len); @@ -65,28 +66,20 @@ int board_uart_read(uint8_t* buf, int len); int board_uart_write(void const * buf, int len); #if CFG_TUSB_OS == OPT_OS_NONE - -// Get current milliseconds, must be implemented in board.c when no OS is used -uint32_t board_millis(void); - + // Get current milliseconds, must be implemented when no RTOS is used + uint32_t board_millis(void); #elif CFG_TUSB_OS == OPT_OS_FREERTOS - -static inline uint32_t board_millis(void) -{ - return ( ( ((uint64_t) xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ ); -} - + static inline uint32_t board_millis(void) + { + return ( ( ((uint64_t) xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ ); + } #elif CFG_TUSB_OS == OPT_OS_MYNEWT - -static inline uint32_t board_millis(void) -{ - return os_time_ticks_to_ms32( os_time_get() ); -} - + static inline uint32_t board_millis(void) + { + return os_time_ticks_to_ms32( os_time_get() ); + } #elif - -#error "Need to implement board_millis() for this OS" - + #error "Need to implement board_millis() for this OS" #endif //--------------------------------------------------------------------+ diff --git a/hw/bsp/ea4088qs/board_ea4088qs.c b/hw/bsp/ea4088qs/board_ea4088qs.c index 4f4e19ee..2d5110d2 100644 --- a/hw/bsp/ea4088qs/board_ea4088qs.c +++ b/hw/bsp/ea4088qs/board_ea4088qs.c @@ -127,7 +127,7 @@ static bool button_read(uint8_t id) } #endif -uint32_t board_buttons(void) +uint32_t board_button_read(void) { uint32_t result = 0; diff --git a/hw/bsp/ea4357/board_ea4357.c b/hw/bsp/ea4357/board_ea4357.c index 6d7d936d..898ad38a 100644 --- a/hw/bsp/ea4357/board_ea4357.c +++ b/hw/bsp/ea4357/board_ea4357.c @@ -269,7 +269,7 @@ static bool button_read(uint8_t id) } #endif -uint32_t board_buttons(void) +uint32_t board_button_read(void) { uint32_t result = 0; diff --git a/hw/bsp/lpcxpresso11u68/board_lpcxpresso11u68.c b/hw/bsp/lpcxpresso11u68/board_lpcxpresso11u68.c index fa096683..e1f1fd36 100644 --- a/hw/bsp/lpcxpresso11u68/board_lpcxpresso11u68.c +++ b/hw/bsp/lpcxpresso11u68/board_lpcxpresso11u68.c @@ -121,7 +121,7 @@ void board_led_control(bool state) //--------------------------------------------------------------------+ // Buttons //--------------------------------------------------------------------+ -uint32_t board_buttons(void) +uint32_t board_button_read(void) { // for(uint8_t i=0; iLFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk); NRF_CLOCK->TASKS_LFCLKSTART = 1UL; - // LEDs + // LED nrf_gpio_cfg_output(LED_PIN); board_led_control(false); // Button - for(uint8_t i=0; i Date: Tue, 2 Apr 2019 01:20:34 +0700 Subject: [PATCH 17/22] nrf5x enable suspend after set address, instead of set config --- src/portable/nordic/nrf5x/dcd_nrf5x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 05f42e60..1f8e9442 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -199,15 +199,9 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) (void) rhport; (void) dev_addr; // Set Address is automatically update by hw controller, nothing to do -} - -void dcd_set_config (uint8_t rhport, uint8_t config_num) -{ - (void) rhport; - (void) config_num; // Enable usbevent for suspend and resume detection - // Since the bus signal D+/D- are stable from now on. + // Since the bus signal D+/D- are stable now. // Clear current pending first NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE; @@ -216,6 +210,12 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk; } +void dcd_set_config (uint8_t rhport, uint8_t config_num) +{ + (void) rhport; + (void) config_num; +} + void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; From e9851f50420ae500476faa54e8fa9eb0a2b8b4b0 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 2 Apr 2019 01:20:51 +0700 Subject: [PATCH 18/22] clean up --- hw/bsp/metro_m0_express/board_metro_m0_express.c | 2 +- hw/bsp/metro_m4_express/board_metro_m4_express.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/bsp/metro_m0_express/board_metro_m0_express.c b/hw/bsp/metro_m0_express/board_metro_m0_express.c index ee0edca7..8876b62b 100644 --- a/hw/bsp/metro_m0_express/board_metro_m0_express.c +++ b/hw/bsp/metro_m0_express/board_metro_m0_express.c @@ -39,7 +39,7 @@ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ #define LED_PIN 17 -#define BUTTON_PIN 14 +#define BUTTON_PIN 14 // pin D2 /* Referenced GCLKs, should be initialized firstly */ #define _GCLK_INIT_1ST (1 << 0 | 1 << 1) diff --git a/hw/bsp/metro_m4_express/board_metro_m4_express.c b/hw/bsp/metro_m4_express/board_metro_m4_express.c index b311aa57..aaaf7c48 100644 --- a/hw/bsp/metro_m4_express/board_metro_m4_express.c +++ b/hw/bsp/metro_m4_express/board_metro_m4_express.c @@ -36,7 +36,7 @@ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ #define LED_PIN 16 -#define BUTTON_PIN (32 + 17) +#define BUTTON_PIN (32 + 17) // pin D2 /* Referenced GCLKs, should be initialized firstly */ #define _GCLK_INIT_1ST 0xFFFFFFFF From 491b5936d5abba5030cceea35a4aa31c470e5782 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 2 Apr 2019 01:30:01 +0700 Subject: [PATCH 19/22] usbd better support suspend/resume --- src/device/usbd.c | 64 +++++++++++++++++++++------------------ src/device/usbd_control.c | 1 + 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 7b87d194..cdbd6db5 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -262,18 +262,10 @@ void tud_task (void) if ( !osal_queue_receive(_usbd_q, &event) ) return; - // Skip event if device is not connected except BUS_RESET & UNPLUGGED & FUNC_CALL - if ( !(_usbd_dev.connected || event.event_id == DCD_EVENT_UNPLUGGED || - event.event_id == DCD_EVENT_BUS_RESET || event.event_id == USBD_EVENT_FUNC_CALL) ) - { - return; - } - switch ( event.event_id ) { case DCD_EVENT_BUS_RESET: usbd_reset(event.rhport); - _usbd_dev.connected = 1; // connected after bus reset break; case DCD_EVENT_UNPLUGGED: @@ -284,6 +276,10 @@ void tud_task (void) break; case DCD_EVENT_SETUP_RECEIVED: + // Mark as connected after receiving 1st setup packet. + // But it is easier to set it every time instead of wasting time to check then set + _usbd_dev.connected = 1; + // Process control request if ( !process_control_request(event.rhport, &event.setup_received) ) { @@ -294,27 +290,29 @@ void tud_task (void) break; case DCD_EVENT_XFER_COMPLETE: - { - // Invoke the class callback associated with the endpoint address - uint8_t const ep_addr = event.xfer_complete.ep_addr; - - if ( 0 == tu_edpt_number(ep_addr) ) + // Only handle xfer callback in ready state + // if (_usbd_dev.connected && !_usbd_dev.suspended) { - // control transfer DATA stage callback - usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); - } - else - { - uint8_t const drv_id = _usbd_dev.ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)]; - TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,); + // Invoke the class callback associated with the endpoint address + uint8_t const ep_addr = event.xfer_complete.ep_addr; - usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + if ( 0 == tu_edpt_number(ep_addr) ) + { + // control transfer DATA stage callback + usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + } + else + { + uint8_t const drv_id = _usbd_dev.ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)]; + TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,); + + usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + } } - } break; case DCD_EVENT_SUSPEND: - if (tud_suspend_cb) tud_suspend_cb( _usbd_dev.remote_wakeup_en ); + if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); break; case DCD_EVENT_RESUME: @@ -641,16 +639,22 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) break; case DCD_EVENT_SUSPEND: - // NOTE: When unplugging device, the D+/D- state are unstable and can accidentally meet the - // SUSPEND condition ( Idle for 3ms ). Most likely when this happen both suspend and resume - // are submitted by DCD before the actual UNPLUGGED - _usbd_dev.suspended = 1; - osal_queue_send(_usbd_q, event, in_isr); + // NOTE: When plugging/unplugging device, the D+/D- state are unstable and can accidentally meet the + // SUSPEND condition ( Idle for 3ms ). Some MCUs such as samd don't distinguish suspend vs disconnect as well. + // We will skip handling SUSPEND/RESUME event if not currently connected + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 1; + osal_queue_send(_usbd_q, event, in_isr); + } break; case DCD_EVENT_RESUME: - _usbd_dev.suspended = 0; - osal_queue_send(_usbd_q, event, in_isr); + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + } break; case DCD_EVENT_SETUP_RECEIVED: diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 24234f4d..8460a11b 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -114,6 +114,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) { + TU_VERIFY(_control_state.buffer); memcpy(_control_state.buffer, _usbd_ctrl_buf, xferred_bytes); } From dd9c441a612651c980b6eec748383bf58dea3d52 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 2 Apr 2019 01:52:12 +0700 Subject: [PATCH 20/22] samd support suspend and resume. Though cannot distinguish between Suspend and Disconnect should work with #47 --- .../cdc_msc_hid/ses/samd51/samd51.emProject | 5 ++ src/portable/microchip/samd21/dcd_samd21.c | 81 +++++++++++-------- src/portable/microchip/samd51/dcd_samd51.c | 66 ++++++++++++--- 3 files changed, 104 insertions(+), 48 deletions(-) diff --git a/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject b/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject index 280afdcd..cc34dc63 100644 --- a/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject +++ b/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject @@ -71,6 +71,11 @@ + + + + + diff --git a/src/portable/microchip/samd21/dcd_samd21.c b/src/portable/microchip/samd21/dcd_samd21.c index 39d59486..8ecfd366 100644 --- a/src/portable/microchip/samd21/dcd_samd21.c +++ b/src/portable/microchip/samd21/dcd_samd21.c @@ -38,19 +38,20 @@ static ATTR_ALIGNED(4) UsbDeviceDescBank sram_registers[8][2]; static ATTR_ALIGNED(4) uint8_t _setup_packet[8]; // Setup the control endpoint 0. -static void bus_reset(void) { - // Max size of packets is 64 bytes. - UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; - bank_out->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; - bank_in->PCKSIZE.bit.SIZE = 0x3; +static void bus_reset(void) +{ + // Max size of packets is 64 bytes. + UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; + bank_out->PCKSIZE.bit.SIZE = 0x3; + UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; + bank_in->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; - ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); - ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; + UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; + ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); + ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; - // Prepare for setup packet - dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); + // Prepare for setup packet + dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); } @@ -79,6 +80,7 @@ void dcd_init (uint8_t rhport) USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY; while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {} + USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST; } @@ -103,6 +105,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {} USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN; + + // Enable SUSPEND interrupt since the bus signal D+/D- are stable now. + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND; } void dcd_set_config (uint8_t rhport, uint8_t config_num) @@ -111,17 +117,13 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) (void) config_num; // Nothing to do -#if 0 - // Enable suspend to detect disconnection - // TODO need to distinguish Suspend vs Disconnect - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; - USB->DEVICE.INTENSET.reg |= USB_DEVICE_INTENSET_SUSPEND; -#endif } void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; + + USB->DEVICE.CTRLB.bit.UPRSM = 1; } /*------------------------------------------------------------------*/ @@ -305,35 +307,44 @@ void maybe_transfer_complete(void) { void USB_Handler(void) { uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg; + USB->DEVICE.INTFLAG.reg = int_status; // clear interrupt /*------------- Interrupt Processing -------------*/ - if ( int_status & USB_DEVICE_INTFLAG_EORST ) - { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; - bus_reset(); - dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); - } - if ( int_status & USB_DEVICE_INTFLAG_SOF ) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; dcd_event_bus_signal(0, DCD_EVENT_SOF, true); } -#if 0 + // SAMD doesn't distinguish between Suspend and Disconnect state. + // Both condition will cause SUSPEND interrupt triggered. + // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only + // enabled when we received SET_ADDRESS request and cleared on Bus Reset if ( int_status & USB_DEVICE_INTFLAG_SUSPEND ) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND; + // Enable wakeup interrupt + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP; - // disable interrupt to prevent it continue to trigger - USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_SUSPEND; - - // TODO need to distinguish Suspend vs Disconnect - // reset address to 0, force host to re-enumerate after resume - USB->DEVICE.DADD.reg = 0; - dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true); + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + } + + // Wakeup interrupt is only enabled when we got suspended. + // Wakeup interrupt will disable itself + if ( int_status & USB_DEVICE_INTFLAG_WAKEUP ) + { + // disable wakeup interrupt itself + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP; + dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); + } + + if ( int_status & USB_DEVICE_INTFLAG_EORST ) + { + // Disable both suspend and wakeup interrupt + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND; + + bus_reset(); + dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); } -#endif // Setup packet received. maybe_handle_setup_packet(); diff --git a/src/portable/microchip/samd51/dcd_samd51.c b/src/portable/microchip/samd51/dcd_samd51.c index a1702b05..d2e7aaf7 100644 --- a/src/portable/microchip/samd51/dcd_samd51.c +++ b/src/portable/microchip/samd51/dcd_samd51.c @@ -38,19 +38,20 @@ static UsbDeviceDescBank sram_registers[8][2]; static ATTR_ALIGNED(4) uint8_t _setup_packet[8]; // Setup the control endpoint 0. -static void bus_reset(void) { - // Max size of packets is 64 bytes. - UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; - bank_out->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; - bank_in->PCKSIZE.bit.SIZE = 0x3; +static void bus_reset(void) +{ + // Max size of packets is 64 bytes. + UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; + bank_out->PCKSIZE.bit.SIZE = 0x3; + UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; + bank_in->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; - ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); - ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; + UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; + ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); + ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; - // Prepare for setup packet - dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); + // Prepare for setup packet + dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); } @@ -78,6 +79,8 @@ void dcd_init (uint8_t rhport) USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS; USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY; while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {} + + USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST; } @@ -108,6 +111,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {} USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN; + + // Enable SUSPEND interrupt since the bus signal D+/D- are stable now. + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND; } void dcd_set_config (uint8_t rhport, uint8_t config_num) @@ -120,6 +127,8 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; + + USB->DEVICE.CTRLB.bit.UPRSM = 1; } /*------------------------------------------------------------------*/ @@ -270,12 +279,42 @@ USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2, USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5, USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */ void USB_0_Handler(void) { - uint32_t int_status = USB->DEVICE.INTFLAG.reg; + uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg; /*------------- Interrupt Processing -------------*/ + // SAMD doesn't distinguish between Suspend and Disconnect state. + // Both condition will cause SUSPEND interrupt triggered. + // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only + // enabled when we received SET_ADDRESS request and cleared on Bus Reset + if ( int_status & USB_DEVICE_INTFLAG_SUSPEND ) + { + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND; + + // Enable wakeup interrupt + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP; + + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + } + + // Wakeup interrupt is only enabled when we got suspended. + // Wakeup interrupt will disable itself + if ( int_status & USB_DEVICE_INTFLAG_WAKEUP ) + { + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; + + // disable wakeup interrupt itself + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP; + dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); + } + if ( int_status & USB_DEVICE_INTFLAG_EORST ) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_EORST; + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; + + // Disable both suspend and wakeup interrupt + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND; + bus_reset(); dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); } @@ -283,6 +322,7 @@ void USB_0_Handler(void) { // Setup packet received. maybe_handle_setup_packet(); } + /* USB_SOF_HSOF */ void USB_1_Handler(void) { USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; From 4af16efea706655a814d55e02f8d0463f4d29cf3 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 2 Apr 2019 02:14:39 +0700 Subject: [PATCH 21/22] add tud_ready() to hid_ready() --- src/class/hid/hid_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 765ee042..5c81a126 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -107,7 +107,7 @@ static inline hidd_interface_t* get_interface_by_itfnum(uint8_t itf_num) //--------------------------------------------------------------------+ bool tud_hid_generic_ready(void) { - return (_hidd_itf[ITF_IDX_GENERIC].ep_in != 0) && !dcd_edpt_busy(TUD_OPT_RHPORT, _hidd_itf[ITF_IDX_GENERIC].ep_in); + return tud_ready() && (_hidd_itf[ITF_IDX_GENERIC].ep_in != 0) && !dcd_edpt_busy(TUD_OPT_RHPORT, _hidd_itf[ITF_IDX_GENERIC].ep_in); } bool tud_hid_generic_report(uint8_t report_id, void const* report, uint8_t len) From 2c1072c0aba48a2e6cbe93118c286b7999b0db43 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 2 Apr 2019 02:16:54 +0700 Subject: [PATCH 22/22] fix build error with stm32 --- hw/bsp/stm32f303disc/board_stm32f303disc.c | 6 ++++++ hw/bsp/stm32f407g_disc1/board_stm32f407g_disc1.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/hw/bsp/stm32f303disc/board_stm32f303disc.c b/hw/bsp/stm32f303disc/board_stm32f303disc.c index d2f6244f..e4afbf8c 100644 --- a/hw/bsp/stm32f303disc/board_stm32f303disc.c +++ b/hw/bsp/stm32f303disc/board_stm32f303disc.c @@ -97,6 +97,12 @@ void board_led_control(bool state) HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, state); } +uint32_t board_button_read(void) +{ + // TODO implement + return 0; +} + /*------------------------------------------------------------------*/ /* TUSB HAL MILLISECOND *------------------------------------------------------------------*/ diff --git a/hw/bsp/stm32f407g_disc1/board_stm32f407g_disc1.c b/hw/bsp/stm32f407g_disc1/board_stm32f407g_disc1.c index d7b4a4bd..2622dde1 100644 --- a/hw/bsp/stm32f407g_disc1/board_stm32f407g_disc1.c +++ b/hw/bsp/stm32f407g_disc1/board_stm32f407g_disc1.c @@ -91,6 +91,12 @@ void board_led_control(bool state) } } +uint32_t board_button_read(void) +{ + // TODO implement + return 0; +} + /*------------------------------------------------------------------*/ /* TUSB HAL MILLISECOND