STM32. What should be done in firmware for VBUS detection through a GPIO pin?
I've got a is self-powered USB device, which means that I have to do VBUS detection. The device is built around STM32G474. Unlike some other STM32s, the STM32G4 don't have a dedicated pin for VBUS detection, so I have to do it through a GPIO pin and firmware. VBUS is connected to the GPIO pin PA10 through a 2x 100kΩ divider. What should be done in firmware for VBUS detection through a GPIO pin?
I checked the code examples for STM32G4s, but I couldn’t find examples for USB. If somebody could point me to a code example, that would be great.
I’ve read this knowledgebase article on VBUS detection which is a collection of excerpts from AN4879 (and I’ve read the app note too).
Any 5V tolerant pin with external interrupt functionality... [from knowledgebase article]
Does the VBUS detection have to be done in an interrupt? Or can it be done in the main loop? If it can be done in the main loop, then are there timing constraints?
However, the disadvantage of this solution is that the software handling of VBUS presence event needs to be implemented by the user. This is not managed within our STM32 USB library for the time being. [from the same knowledgebase article]
I have to pick up where that knowledgebase article left off. What should the firmware do when it detects that VBUS (re)appeared? What should the firmware do when VBUS has disappeared?
2 answers
What should the firmware do when it detects that VBUS (re)appeared? What should the firmware do when VBUS has disappeared?
I'm not familiar with the STM32 USB library, and have only dealt with this on PICs using my own USB library. I'll therefore answer the generic case.
The most important thing for the USB library to know is when a logical USB connection is opened and closed. Particularly when a new connection is opened, it needs to start with empty buffers.
Depending on how the hardware works, there may not be a need to know when a connection is closed. Something might be waiting for new packets that never come without any harm caused. In some cases there may be efficiency advantages to knowning there is no connection. For example, my USB library discards data the app tries to send when it knows there is no logical connection.
In this context, detecting Vbus is not strictly necessary. If the USB is not physically connected, the firmware should already know there is no logical connection.
Detecting lack of physical connection might be a convenient shortcut to absolutely knowing there is no logical connection, but ultimately it is the logical connection that you need to know is open or not. You already have to deal with that when the host does enumeration and establishes a logical connection.
Depending on how the hardware works, it may be necessary or desirable to reset it when a new physical connection is detected. Note that detecting Vbus is not the only way to do that. Another scheme is detecting no sync packets for some minimum time. They are sent every 1 ms when the USB connection is intact. If you don't see a sync packet for 100 ms, for example, something is definitely very wrong with the connection, whether power voltage is present or not.
0 comment threads
I've found a solution, and tested it. What @Olin wrote earlier holds. This is to post my code for STM32.
Does the VBUS detection have to be done in an interrupt?
I've asked the ST's technical support, and they replied that it should be done in the interrupt. Here's my ISR code.
/**
* @brief EXTI line detection callback
* @param GPIO_Pin: Specifies the pins connected EXTI line
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == VBUS_DETECT_Pin)
{
if (HAL_GPIO_ReadPin(VBUS_DETECT_GPIO_Port, VBUS_DETECT_Pin) == GPIO_PIN_SET)
{
MX_USB_Device_Init(); // reinitialize USB
}
else
{
USB_Device_DeInit(); // deinitialize USB
}
}
}
The USB_Device_DeInit()
function is in the usb_device.c
.
/* USER CODE BEGIN 1 */
void USB_Device_DeInit(void)
{
if (USBD_Stop(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
if (USBD_DeInit(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
}
/* USER CODE END 1 */
MX_USB_Device_Init()
remained unchanged just like CubeMX generated it.
I ran these snippets by the ST's support, and got a "looks good to me" verdict.
0 comment threads