diff --git a/hw/bsp/da14695_dk_usb/da14695_dk_usb.c b/hw/bsp/da14695_dk_usb/da14695_dk_usb.c index e7c7ae364..bdb30e0e5 100644 --- a/hw/bsp/da14695_dk_usb/da14695_dk_usb.c +++ b/hw/bsp/da14695_dk_usb/da14695_dk_usb.c @@ -53,6 +53,9 @@ void UnhandledIRQ(void) while(1); } +// DA146xx driver function that must be called whenever VBUS changes. +extern void tusb_vbus_changed(bool present); + void board_init(void) { // LED @@ -70,7 +73,10 @@ void board_init(void) // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); - NVIC_SetPriority(USB_IRQn, 2); +#if TUSB_OPT_DEVICE_ENABLED + // This board is USB powered there is no need to monitor + // VBUS line. Notify driver that VBUS is present. + tusb_vbus_changed(true); /* Setup USB IRQ */ NVIC_SetPriority(USB_IRQn, 2); @@ -81,6 +87,7 @@ void board_init(void) mcu_gpio_set_pin_function(14, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); +#endif } //--------------------------------------------------------------------+ diff --git a/hw/bsp/da1469x_dk_pro/da1469x-dk-pro.c b/hw/bsp/da1469x_dk_pro/da1469x-dk-pro.c index 85fa17152..2b6931e4e 100644 --- a/hw/bsp/da1469x_dk_pro/da1469x-dk-pro.c +++ b/hw/bsp/da1469x_dk_pro/da1469x-dk-pro.c @@ -36,6 +36,21 @@ void USB_IRQHandler(void) tud_int_handler(0); } +#if TUSB_OPT_DEVICE_ENABLED +// DA146xx driver function that must be called whenever VBUS changes +extern void tusb_vbus_changed(bool present); + +// VBUS change interrupt handler +void VBUS_IRQHandler(void) +{ + bool present = (CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0; + // Clear VBUS interrupt + CRG_TOP->VBUS_IRQ_CLEAR_REG = 1; + + tusb_vbus_changed(present); +} +#endif + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ @@ -70,7 +85,15 @@ void board_init(void) // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); - NVIC_SetPriority(USB_IRQn, 2); +#if TUSB_OPT_DEVICE_ENABLED + // Setup interrupt for both connect and disconnect + CRG_TOP->VBUS_IRQ_MASK_REG = CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_FALL_Msk | + CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_RISE_Msk; + NVIC_SetPriority(VBUS_IRQn, 2); + // Trigger interrupt at the start to inform driver about VBUS state at start + // otherwise it could go unnoticed. + NVIC_SetPendingIRQ(VBUS_IRQn); + NVIC_EnableIRQ(VBUS_IRQn); /* Setup USB IRQ */ NVIC_SetPriority(USB_IRQn, 2); @@ -81,6 +104,7 @@ void board_init(void) mcu_gpio_set_pin_function(14, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); +#endif } //--------------------------------------------------------------------+ diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 7b0d8f86c..112cdb502 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -217,6 +217,7 @@ typedef struct { static struct { bool vbus_present; + bool init_called; bool in_reset; xfer_ctl_t xfer_status[EP_MAX][2]; // Endpoints that use DMA, one for each direction @@ -224,6 +225,7 @@ static struct } _dcd = { .vbus_present = false, + .init_called = false, .xfer_status = { { { .regs = EP_REGS(USB_EPC0_REG) }, { .regs = EP_REGS(USB_EPC0_REG) } }, @@ -735,19 +737,13 @@ static void handle_ep0_nak(void) *------------------------------------------------------------------*/ void dcd_init(uint8_t rhport) { - USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk; - USB->USB_NFSR_REG = 0; - USB->USB_FAR_REG = 0x80; - USB->USB_NFSR_REG = NFSR_NODE_RESET; - USB->USB_TXMSK_REG = 0; - USB->USB_RXMSK_REG = 0; + (void) rhport; - USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk | - USB_USB_MAMSK_REG_USB_M_ALT_Msk | - USB_USB_MAMSK_REG_USB_M_WARN_Msk; - USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk; - - dcd_connect(rhport); + _dcd.init_called = true; + if (_dcd.vbus_present) + { + dcd_connect(rhport); + } } void dcd_int_enable(uint8_t rhport) @@ -783,10 +779,25 @@ void dcd_connect(uint8_t rhport) { (void)rhport; - REG_SET_BIT(USB_MCTRL_REG, USB_NAT); + if (GET_BIT(USB->USB_MCTRL_REG, USB_USB_MCTRL_REG_USB_NAT) == 0) + { + USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk; + USB->USB_NFSR_REG = 0; + USB->USB_FAR_REG = 0x80; + USB->USB_NFSR_REG = NFSR_NODE_RESET; + USB->USB_TXMSK_REG = 0; + USB->USB_RXMSK_REG = 0; - // Select chosen DMA to be triggered by USB. - DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX; + USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk | + USB_USB_MAMSK_REG_USB_M_ALT_Msk | + USB_USB_MAMSK_REG_USB_M_WARN_Msk; + USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk; + + REG_SET_BIT(USB_MCTRL_REG, USB_NAT); + + // Select chosen DMA to be triggered by USB. + DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX; + } } void dcd_disconnect(uint8_t rhport) @@ -796,6 +807,30 @@ void dcd_disconnect(uint8_t rhport) REG_CLR_BIT(USB_MCTRL_REG, USB_NAT); } +TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void) +{ + return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0; +} + +void tusb_vbus_changed(bool present) +{ + if (present && !_dcd.vbus_present) + { + _dcd.vbus_present = true; + // If power event happened before USB started, delay dcd_connect + // until dcd_init is called. + if (_dcd.init_called) + { + dcd_connect(0); + } + } + else if (!present && _dcd.vbus_present) + { + _dcd.vbus_present = false; + USB->USB_MCTRL_REG = 0; + dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr()); + } +} /*------------------------------------------------------------------*/ /* DCD Endpoint port