diff --git a/flight/pios/stm32f4xx/libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c b/flight/pios/stm32f4xx/libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c index d6e52c604..b572b9550 100644 --- a/flight/pios/stm32f4xx/libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c +++ b/flight/pios/stm32f4xx/libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c @@ -681,7 +681,7 @@ static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum) } // --- start fix uint32_t fifoemptymsk; - if (len < ep->maxpacket) + if (len < ep->maxpacket || ep->xfer_count==0) { // FIFO empty fifoemptymsk = 0x1 << epnum; diff --git a/flight/pios/stm32f4xx/pios_usb.c b/flight/pios/stm32f4xx/pios_usb.c index 686120069..158fd8128 100644 --- a/flight/pios/stm32f4xx/pios_usb.c +++ b/flight/pios/stm32f4xx/pios_usb.c @@ -38,7 +38,7 @@ #include /* Rx/Tx status */ -static uint8_t transfer_possible = 0; +static volatile uint8_t transfer_possible = 0; #ifdef PIOS_INCLUDE_FREERTOS static void(*disconnection_cb_list[3]) (void); @@ -148,6 +148,9 @@ out_fail: */ int32_t PIOS_USB_ChangeConnectionState(bool connected) { +#ifdef PIOS_INCLUDE_FREERTOS + static volatile uint8_t lastStatus = 2; // 2 is "no last status" +#endif // In all cases: re-initialise USB HID driver if (connected) { transfer_possible = 1; @@ -168,6 +171,12 @@ int32_t PIOS_USB_ChangeConnectionState(bool connected) #ifdef PIOS_INCLUDE_FREERTOS raiseConnectionStateCallback(connected); + if (lastStatus != transfer_possible) { + if (lastStatus == 1) { + raiseDisconnectionCallbacks(); + } + lastStatus = transfer_possible; + } #endif return 0; @@ -187,28 +196,19 @@ bool PIOS_USB_CheckAvailable(__attribute__((unused)) uint32_t id) return false; } - usb_found = ((usb_dev->cfg->vsense.gpio->IDR & usb_dev->cfg->vsense.init.GPIO_Pin) != 0) ^ usb_dev->cfg->vsense_active_low; -// Please note that checks of transfer_possible and the reconnection handling is -// suppressed for non freertos mode (aka bootloader) as this is causing problems detecting connection and -// broken communications. -#ifdef PIOS_INCLUDE_FREERTOS - static bool lastStatus = false; - bool status = usb_found != 0 && transfer_possible ? 1 : 0; - bool reconnect = false; - if (xSemaphoreTakeFromISR(usb_dev->statusCheckSemaphore, NULL) == pdTRUE) { - reconnect = (lastStatus && !status); - lastStatus = status; - xSemaphoreGiveFromISR(usb_dev->statusCheckSemaphore, NULL); - } - if (reconnect) { - raiseDisconnectionCallbacks(); - } - return status; + return transfer_possible; +} -#else - return usb_found; +/** + * This function returns wether a USB cable (5V pin) has been detected + * \return true: cable connected + * \return false: cable not detected (no cable or cable with no power) + */ +bool PIOS_USB_CableConnected(__attribute__((unused)) uint8_t id) +{ + struct pios_usb_dev *usb_dev = (struct pios_usb_dev *)pios_usb_id; -#endif + return ((usb_dev->cfg->vsense.gpio->IDR & usb_dev->cfg->vsense.init.GPIO_Pin) != 0) ^ usb_dev->cfg->vsense_active_low; } /* diff --git a/flight/pios/stm32f4xx/pios_usb_cdc.c b/flight/pios/stm32f4xx/pios_usb_cdc.c index 803d653c6..e8e847065 100644 --- a/flight/pios/stm32f4xx/pios_usb_cdc.c +++ b/flight/pios/stm32f4xx/pios_usb_cdc.c @@ -191,7 +191,7 @@ int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cf pios_usb_cdc_id = (uint32_t)usb_cdc_dev; - /* Tx is not active yet */ + /* Tx and Rx are not active yet */ usb_cdc_dev->tx_active = false; /* Clear stats */ @@ -607,6 +607,11 @@ static void PIOS_USB_CDC_DATA_IF_Init(uint32_t usb_cdc_id) PIOS_USB_CDC_DATA_EP_OUT_Callback, (uint32_t)usb_cdc_dev); usb_cdc_dev->usb_data_if_enabled = true; + usb_cdc_dev->tx_active = false; + /* Activate rx prophylactically */ + PIOS_USBHOOK_EndpointRx(usb_cdc_dev->cfg->data_rx_ep, + usb_cdc_dev->rx_packet_buffer, + sizeof(usb_cdc_dev->rx_packet_buffer)); } static void PIOS_USB_CDC_DATA_IF_DeInit(uint32_t usb_cdc_id) diff --git a/flight/pios/stm32f4xx/pios_usbhook.c b/flight/pios/stm32f4xx/pios_usbhook.c index 0d58a5e10..d587905db 100644 --- a/flight/pios/stm32f4xx/pios_usbhook.c +++ b/flight/pios/stm32f4xx/pios_usbhook.c @@ -280,7 +280,9 @@ static USBD_DEVICE device_callbacks = { static void PIOS_USBHOOK_USR_Init(void) { PIOS_USB_ChangeConnectionState(false); - reconnect(); + // reconnect dev logically on init (previously a call to reconnect()) + DCD_DevDisconnect(&pios_usb_otg_core_handle); + DCD_DevConnect(&pios_usb_otg_core_handle); } static void PIOS_USBHOOK_USR_DeviceReset(__attribute__((unused)) uint8_t speed) @@ -491,9 +493,24 @@ static USBD_Class_cb_TypeDef class_callbacks = { static void reconnect(void) { - /* Force a physical disconnect/reconnect */ - DCD_DevDisconnect(&pios_usb_otg_core_handle); - DCD_DevConnect(&pios_usb_otg_core_handle); + static volatile bool in_reconnect = false; + + /* Force a complete device reset. This can trigger a call to reconnect() so prevent recursion */ + if (!in_reconnect) { + in_reconnect = true; // save since volatile and STM32F4 is single core + // disable USB device + DCD_DevDisconnect(&pios_usb_otg_core_handle); + USBD_DeInit(&pios_usb_otg_core_handle); + USB_OTG_StopDevice(&pios_usb_otg_core_handle); + // enable USB device + USBD_Init(&pios_usb_otg_core_handle, + USB_OTG_FS_CORE_ID, + &device_callbacks, + &class_callbacks, + &user_callbacks); + + in_reconnect = false; + } } #endif /* PIOS_INCLUDE_USB */ diff --git a/flight/targets/boards/discoveryf4bare/bootloader/main.c b/flight/targets/boards/discoveryf4bare/bootloader/main.c index aa5c7999a..c85ef675e 100644 --- a/flight/targets/boards/discoveryf4bare/bootloader/main.c +++ b/flight/targets/boards/discoveryf4bare/bootloader/main.c @@ -82,7 +82,7 @@ int main() // is 2.7 volts check_bor(); - USB_connected = PIOS_USB_CheckAvailable(0); + USB_connected = PIOS_USB_CableConnected(0); if (PIOS_IAP_CheckRequest() == true) { PIOS_DELAY_WaitmS(1000); diff --git a/flight/targets/boards/osd/bootloader/main.c b/flight/targets/boards/osd/bootloader/main.c index c333ab9af..36252cc83 100644 --- a/flight/targets/boards/osd/bootloader/main.c +++ b/flight/targets/boards/osd/bootloader/main.c @@ -76,7 +76,7 @@ int main() PIOS_Board_Init(); PIOS_IAP_Init(); - USB_connected = PIOS_USB_CheckAvailable(0); + USB_connected = PIOS_USB_CableConnected(0); if (PIOS_IAP_CheckRequest() == true) { PIOS_DELAY_WaitmS(1000); diff --git a/flight/targets/boards/revolution/bootloader/main.c b/flight/targets/boards/revolution/bootloader/main.c index aa5c7999a..c85ef675e 100644 --- a/flight/targets/boards/revolution/bootloader/main.c +++ b/flight/targets/boards/revolution/bootloader/main.c @@ -82,7 +82,7 @@ int main() // is 2.7 volts check_bor(); - USB_connected = PIOS_USB_CheckAvailable(0); + USB_connected = PIOS_USB_CableConnected(0); if (PIOS_IAP_CheckRequest() == true) { PIOS_DELAY_WaitmS(1000); diff --git a/flight/targets/boards/revonano/bootloader/main.c b/flight/targets/boards/revonano/bootloader/main.c index aa5c7999a..c85ef675e 100644 --- a/flight/targets/boards/revonano/bootloader/main.c +++ b/flight/targets/boards/revonano/bootloader/main.c @@ -82,7 +82,7 @@ int main() // is 2.7 volts check_bor(); - USB_connected = PIOS_USB_CheckAvailable(0); + USB_connected = PIOS_USB_CableConnected(0); if (PIOS_IAP_CheckRequest() == true) { PIOS_DELAY_WaitmS(1000); diff --git a/flight/targets/boards/revoproto/bootloader/main.c b/flight/targets/boards/revoproto/bootloader/main.c index aa5c7999a..c85ef675e 100644 --- a/flight/targets/boards/revoproto/bootloader/main.c +++ b/flight/targets/boards/revoproto/bootloader/main.c @@ -82,7 +82,7 @@ int main() // is 2.7 volts check_bor(); - USB_connected = PIOS_USB_CheckAvailable(0); + USB_connected = PIOS_USB_CableConnected(0); if (PIOS_IAP_CheckRequest() == true) { PIOS_DELAY_WaitmS(1000); diff --git a/flight/targets/boards/sparky2/bootloader/main.c b/flight/targets/boards/sparky2/bootloader/main.c index 02d53d948..6ed56133f 100644 --- a/flight/targets/boards/sparky2/bootloader/main.c +++ b/flight/targets/boards/sparky2/bootloader/main.c @@ -83,7 +83,7 @@ int main() // is 2.7 volts check_bor(); - USB_connected = PIOS_USB_CheckAvailable(0); + USB_connected = PIOS_USB_CableConnected(0); if (PIOS_IAP_CheckRequest() == true) { PIOS_DELAY_WaitmS(1000);