Merge pull request #1094 from kasjer/kasjer/da146xx-vbus-handling

dcd_da146xx: Add VBUS handling
This commit is contained in:
Ha Thach 2021-09-18 23:12:40 +07:00 committed by GitHub
commit 3e569f8e79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 17 deletions

View File

@ -53,6 +53,9 @@ void UnhandledIRQ(void)
while(1); while(1);
} }
// DA146xx driver function that must be called whenever VBUS changes.
extern void tusb_vbus_changed(bool present);
void board_init(void) void board_init(void)
{ {
// LED // LED
@ -70,7 +73,10 @@ void board_init(void)
// 1ms tick timer // 1ms tick timer
SysTick_Config(SystemCoreClock / 1000); 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 */ /* Setup USB IRQ */
NVIC_SetPriority(USB_IRQn, 2); 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(14, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
#endif
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -36,6 +36,21 @@ void USB_IRQHandler(void)
tud_int_handler(0); 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 // MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -70,7 +85,15 @@ void board_init(void)
// 1ms tick timer // 1ms tick timer
SysTick_Config(SystemCoreClock / 1000); 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 */ /* Setup USB IRQ */
NVIC_SetPriority(USB_IRQn, 2); 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(14, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB); mcu_gpio_set_pin_function(15, MCU_GPIO_MODE_INPUT, MCU_GPIO_FUNC_USB);
#endif
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -217,6 +217,7 @@ typedef struct {
static struct static struct
{ {
bool vbus_present; bool vbus_present;
bool init_called;
bool in_reset; bool in_reset;
xfer_ctl_t xfer_status[EP_MAX][2]; xfer_ctl_t xfer_status[EP_MAX][2];
// Endpoints that use DMA, one for each direction // Endpoints that use DMA, one for each direction
@ -224,6 +225,7 @@ static struct
} _dcd = } _dcd =
{ {
.vbus_present = false, .vbus_present = false,
.init_called = false,
.xfer_status = .xfer_status =
{ {
{ { .regs = EP_REGS(USB_EPC0_REG) }, { .regs = EP_REGS(USB_EPC0_REG) } }, { { .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) void dcd_init(uint8_t rhport)
{ {
USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk; (void) rhport;
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;
USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk | _dcd.init_called = true;
USB_USB_MAMSK_REG_USB_M_ALT_Msk | if (_dcd.vbus_present)
USB_USB_MAMSK_REG_USB_M_WARN_Msk; {
USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk; dcd_connect(rhport);
}
dcd_connect(rhport);
} }
void dcd_int_enable(uint8_t rhport) void dcd_int_enable(uint8_t rhport)
@ -783,10 +779,25 @@ void dcd_connect(uint8_t rhport)
{ {
(void)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. USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX; 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) void dcd_disconnect(uint8_t rhport)
@ -796,6 +807,30 @@ void dcd_disconnect(uint8_t rhport)
REG_CLR_BIT(USB_MCTRL_REG, USB_NAT); 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 /* DCD Endpoint port