Skip to main content
Explorer
March 16, 2021
Solved

VBUS sensing doesn't work because internal pull-up is activated during USB init rather than when connected - STM32F072

  • March 16, 2021
  • 2 replies
  • 1886 views

Hi all, I just thought I'd add to the list of questions about USB! :grinning_face_with_sweat:

I read AN4879 and it says "when the host presence is detected by the device, the device connects its pull up resistor". This is very clear - first detect the host, second activate the pull-up. What actually happens in the Cube generated code though is that the USB device is initialised at boot and the embedded pull-up is immediately activated, whether a cable is attached or not.

This is triggered by a chain of function calls:

MX_USB_DEVICE_Init() -> USBD_Start() -> USBD_LL_Start() -> HAL_PCD_Start() -> USB_DevConnect() -> USBx->BCDR |= (uint16_t)USB_BCDR_DPPU;

This code is Cube generated so if I remove the call to USB_Start() it will just get added back in next time I make a change.

Should I call USBD_Stop() straight after the USBD_Start() or is there a different way to go about this? Then use my vbus detect pin to call USBD_Start() when the cable is plugged in. 

A second and perhaps bigger issue this is causing is that, because I'm using a TVS device for protection, when the D+ pull-up is active it causes 2.56V to appear on the vbus pin (3.26V from the D+ line then 0.7V dropped across the TVS diode) this goes through a potential divider (R1=62k,R2=100k) and results in 1.57V on my vbus detect pin therefore I can detect the connected event but never detect a disconnect event as once the pull-up is active the vbus pins will never go below 1.57V and VIL is 1.36V.

I could swap the resistors so I get 1V when unplugged and 2V when plugged.

Has anyone else run into these issues? Is there a different way to detect connect/disconnect events? Do you just let the embedded pull-up go high upon USB init or do you override the default behaviour?

    This topic has been closed for replies.
    Best answer by MattKefford

    I've tested using the LL functions and it works fine so I think I'd recommend those as they don't interfere with the USB class.

    In MX_USB_DEVICE_Init() :-

     /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */

     // Begin in an off state and detect when cable is plugged in

     //USBD_Stop(&hUsbDeviceFS);

     USBD_LL_Stop(&hUsbDeviceFS);

     /* USER CODE END USB_DEVICE_Init_PostTreatment */

    2 replies

    Explorer
    March 17, 2021

    So just to follow up on this, answering my own questions but hopefully helping others out in a similar position...

    I now have USB host detection and the embedded pull-up working as it should =)

    It seems fine to just stop the USB immediately after starting it. Strange thing to have to do but it works.

    I did swap the resistors to give a ratio of 0.4 which results in 2V when the cable is plugged in and 1V when the cable is unplugged. 1V is low enough to be a logic low so then the embedded pull-up can be disabled and the voltage drops to 0V. I'm not using the Vbus as this is a self-powered board so I only need it as a signal.

    I could use an interrupt but I just added code to my main loop to check this pin, do some basic de-bouncing and a basic state machine to start/stop the USB only when needed.

    static USB_PU_e usbPullupState = USB_PU_OFF;
     
     GPIO_PinState usbDetect = HAL_GPIO_ReadPin(USB_DET_GPIO_Port, USB_DET_Pin);
     
     // If USB is off and needs to be on - turn it on
     if((usbDetect == GPIO_PIN_SET) && (usbPullupState == USB_PU_OFF))
     {
     HAL_Delay(1); // Basic debounce
     
     if(GPIO_PIN_SET == HAL_GPIO_ReadPin(USB_DET_GPIO_Port, USB_DET_Pin))
     {
     //USBD_Start(&hUsbDeviceFS);
     USBD_LL_Start(&hUsbDeviceFS);
     usbPullupState = USB_PU_ON;
     }
     }
     // If USB is on and needs to be off - turn it off
     else if((usbDetect == GPIO_PIN_RESET) && (usbPullupState == USB_PU_ON))
     {
     HAL_Delay(1); // Basic debounce
     
     if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(USB_DET_GPIO_Port, USB_DET_Pin))
     {
     //USBD_Stop(&hUsbDeviceFS); // This will deinit the USB class
     USBD_LL_Stop(&hUsbDeviceFS);
     usbPullupState = USB_PU_OFF;
     }
     }

    So far everything seems fine. When the USB is stopped and my code calls CDC_Transmit_FS() it just fails the TxState check and returns early so no messages are getting buffered or left pending.

    The thing I'm not sure about now is should I be using USBD_Start() and USBD_Stop() or USBD_LL_Start() and USBD_LL_Stop() ?

    USBD_Stop() stops the driver but also de-inits the class and USBD_Start() starts the driver but doesn't init the class so I'm not even sure how it is working currently as the class should become de-initialised.

    MattKeffordAuthorAnswer
    Explorer
    March 17, 2021

    I've tested using the LL functions and it works fine so I think I'd recommend those as they don't interfere with the USB class.

    In MX_USB_DEVICE_Init() :-

     /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */

     // Begin in an off state and detect when cable is plugged in

     //USBD_Stop(&hUsbDeviceFS);

     USBD_LL_Stop(&hUsbDeviceFS);

     /* USER CODE END USB_DEVICE_Init_PostTreatment */