7

Using STM32F4 USB Mass Storage Controller example in Device Mode, how do you detect connections and disconnections with a host controller?

I tried polling the VBUS pin state yet it could be high from a wall adapter or high without any communication with the host.

Is there a register to check? I noticed DSTS (status I guess?) in the USB library structs but couldn't find its documentation nor any useful comments in the code.

JYelton
  • 32,302
  • 33
  • 134
  • 249
David
  • 165
  • 1
  • 1
  • 6

9 Answers9

5

You could detect the connection and disconnection from this file:

usbd_core.c

and the API for it is this

USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef  *pdev)
USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef  *pdev)

I am not sure about USB Mass Storage Class but in the CDC class, the 2 APIs above detect the USB connection and disconnection, maybe this helps

Things to note:

  • Connection > when the physical USB cable is plugged into the USB port
  • Disconnection > when the physical USB cable is unplugged from the USB port

I used STMCubeMX to generate the USB CDC class.

Tim
  • 899
  • 2
  • 12
  • 18
  • `usbd_core.c` has `USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev) { return USBD_OK; }` ...How does this work? – cp.engr Dec 02 '16 at 21:36
  • OP is asking *how to detect* the connection, not what to do after it's detected. – cp.engr Dec 02 '16 at 21:37
  • This seems the right answer, but AFAICS that code is only active if USB is OTG. – Ezequiel Garcia Sep 06 '17 at 15:14
  • But these callbacks are already implemented in **usbd_core.c** and you can't add user code there. So how can the event be handled by the user? – Alaa M. Oct 04 '18 at 06:52
  • I mean if you're using CubeMx it will overwrite your code every time you hit the generate button. – Alaa M. Oct 04 '18 at 07:27
  • To solve the problem I mentioned, you can edit the file `C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeMX\db\templates\usbdconf_f7_c.ftl` (depending on your board name), and just delete the implementation of the callbacks in this file. Now you can add your own implementation in your files and CubeMx will not overwrite your code. – Alaa M. Oct 04 '18 at 07:38
2

For the people who want to use the "User Code" parts made by CubeMX, This callback is called when USB is plugged into system.

void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)

And this one is called when USB is unplugged from the system.

void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)

Both functions are inside usbd_conf.c

Work
  • 73
  • 5
1
void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
{
  /* Inform USB library that core enters in suspend Mode. */
  USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData);
......

in usbd_conf.c

Function calls on usb cable disconnecting

(tested on Mass Storage device, CubeMX)

Иван
  • 11
  • 1
1

The best way that fits in with ST's software stack is to implement these functions:

void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd);
void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd);

These are declared with weak linkage in the HAL stack so your implementations will override the HAL do-nothing stubs.

However, if you're using Cube then you'll find these already implemented in usbd_conf.c and for reasons unknown there are no /* USER CODE BEGIN */ sections in these functions so cube will overwrite your code next time you save it. Until ST fixes this you either have to not use Cube (I use it to bootstrap a project then stop using it and take over control) or you can modify the Cube template for this file.

In the [CUBE-INSTALL-DIR]/db/templates directory locate the usbdconf_XX.ftl file for your MCU. e.g. for the f4 it will be usbdconf_f4_c.ftl. Now edit that file to include unique USER CODE BEGIN and USER CODE END comment blocks. Next time you generate source code you'll have a section where you can place your code.

Andy Brown
  • 141
  • 5
1

In my project, I am using the callbacks that are initialized / registered in the following structure:

typedef struct _USBD_CDC_Itf
{
  int8_t (* Init)(void);   // <- triggered on connection
  int8_t (* DeInit)(void); // <- triggered on disconnection

  int8_t (* Control)(uint8_t cmd, uint8_t *pbuf, uint16_t length);
  int8_t (* Receive)(uint8_t *Buf, uint32_t *Len);
  int8_t (* TransmitCplt)(uint8_t *Buf, uint32_t *Len, uint8_t epnum);
} USBD_CDC_ItfTypeDef;
nix
  • 11
  • 2
1

Per the chip reference manual, you can use the BSVLD (B-session valid) bit in the Global OTG Control and Status Register. I first tried the other solutions here, but the generated code doesn't allow you to register PCD callbacks before USBD_Start() is called. This means that you can't detect if USB is connected on startup. I only need to check once on startup, so this simpler bit test is easier.

The F4xx reference manual states the following (34.16.2 OTG_FS global registers):

Bit 19 BSVLD: B-session valid  
      Indicates the device mode transceiver status.  
      0: B-session is not valid.  
      1: B-session is valid.  
      In OTG mode, you can use this bit to determine if the device is
      connected or disconnected. 
      Note: Only accessible in device mode

Code:

#include "main.h"
...
// Defined in usbd_conf.c:
extern PCD_HandleTypeDef hpcd_USB_OTG_FS;
...
bool usbIsConnected = (bool)(hpcd_USB_OTG_FS.Instance->GOTGCTL & USB_OTG_GOTGCTL_BSESVLD);
Velvel
  • 3,591
  • 3
  • 12
  • 30
Harvey
  • 111
  • 2
0

I am using STM32F767ZI and was facing same issue of not detecting USB as Virtual com port so I added Minimum Heap stack 2000 and Maximum heap size from 4000 and boom!! It started working.

0

Yes it's strange that there isn't a simple check function or couple of callbacks for this. What I did (using an STM32G0B1) was add a function to usb_device.c to read the dev_state of the USB peripheral. In usb_device.c there is already the handle hUsbDeviceFS and there are blocks where user code can be added, so our code won't be removed next time we edit the .ioc file.

In usb_device.h add a prototype:

/*
 * -- Insert functions declaration here --
 */
/* USER CODE BEGIN FD */
USB_CABLE_e usb_device_check_plug_state(void);
/* USER CODE END FD */

And we'll need an enum for state tracking, I put this in the variables section of the same header file:

/*
 * -- Insert your variables declaration here --
 */
/* USER CODE BEGIN VARIABLES */
 typedef enum
 {
   USB_CABLE_UNPLUGGED = 0U,
   USB_CABLE_PLUGGED,
 } USB_CABLE_e;
/* USER CODE END VARIABLES */

Then add something like this to usb_device.c:

/*
 * -- Insert your variables declaration here --
 */
/* USER CODE BEGIN 0 */
static USB_CABLE_e lastState = USB_CABLE_UNPLUGGED;
/* USER CODE END 0 */

/*
 * -- Insert your external function declaration here --
 */
/* USER CODE BEGIN 1 */
USB_CABLE_e usb_device_check_plug_state(void)
{
   uint8_t stateNow = hUsbDeviceFS.dev_state;

   if((stateNow == USBD_STATE_CONFIGURED) && (lastState == USB_CABLE_UNPLUGGED))
   {
      lastState = USB_CABLE_PLUGGED;
   }
   else if((stateNow == USBD_STATE_SUSPENDED) && (lastState == USB_CABLE_PLUGGED))
   {
      lastState = USB_CABLE_UNPLUGGED;
   }

   return lastState;
}
/* USER CODE END 1 */

Then you can use this function in your main loop and do what you want with the returned state. I have a global to track the USB port state:

 usbPortState = usb_device_check_plug_state();

 if(usbPortState == USB_CABLE_PLUGGED)
 {
    HAL_GPIO_WritePin(DEBUG_LED2_GPIO_Port, DEBUG_LED2_Pin, GPIO_PIN_SET);
 }
 else
 {
    HAL_GPIO_WritePin(DEBUG_LED2_GPIO_Port, DEBUG_LED2_Pin, GPIO_PIN_RESET);
 }

Unfortunately it requires polling but using the current state / last state logic we can detect when the cable has just been unplugged or plugged in.

This works because when there is a connection/disconnection event interrupt, a chain of calls happens ending at USBD_LL_Suspend() and USBD_LL_Resume() which set the dev_state appropriately.

If there are any suggestions for improvement I am all ears! This is just what I've found to work.

-2

The answer is very simple. Just like you tried VBUS, try DSTS, and see what happens! Good luck.

Guill
  • 2,430
  • 10
  • 6
  • 4
    This is scarcely an answer. The question states that DSTS is not clearly documented. Do you have any insight to add? Or are you suggesting just logging the value to see what happens to happen, without bothering to understand what it represents? – Chris Stratton Oct 21 '14 at 18:36
  • Presumably @Guill is talking about this: "Bit0 SUSPSTS:Suspendstatus In device mode, this bit is set as long as a Suspend condition is detected on the USB. The core enters the Suspended state when there is no activity on the USB data lines for a period of 3 ms. The core comes out of the suspend: – When there is an activity on the USB data lines" – Daniel Apr 04 '16 at 03:54
  • Agreed, though, as a pro struggling with this awful USB core and associated documentation, this is unnecessarily teasing. – Daniel Apr 04 '16 at 03:55