I’m trying to set up USB host on the STM32F411CEU6 (blackpill board). It’s been hard to find examples specifically for this chip so I have put together my current code based off of other F4 chip examples with some modifications for this specific chip, but I’m having an issue where the CPU will hang due to interrupts once it makes it to the enumeration phase (I’m pretty sure 100% of the CPU is being used by the interrupts).
When I connect a device, it succesfully detects the device and runs through the state machine up until the HOST_ENUMERATION
state, at which point it will just hang completely. Following the usb host function chain all the way, specifically once phost->Control.state
is set to CTRL_DATA_IN_WAIT
will it hang (in USBH_HandleControl
). I have stepped through the code using the debugger and I have found that it gets permanently stuck in the HAL_HCD_IRQHandler
function. It specifically always takes the Handle Host SOF Interrupt
and Handle Host channel Interrupt
branches. I’m fairly confident it’s taking up 100% of the CPU because, as a test, I put other code in the while
loop in main
and once it reaches the enumeration state the while loop never starts a new iteration it just constantly runs the interrupt handler instead.
This led me to find this post and a few others that are related but the solutions in them, including the one I linked, did not solve the issue.
Here are my HAL_HCD_MspInit
and USBH_LL_Init
functions from usbh_conf.c
. The rest of the functions required are just the same as they would be in any USB host example:
void HAL_HCD_MspInit(HCD_HandleTypeDef *hcdHandle) {
GPIO_InitTypeDef GPIO_InitStruct;
if (hcdHandle->Instance == USB_OTG_FS) {
/* Enable GPIO clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure USB DM and DP pins (PA11, PA12) */
GPIO_InitStruct.Pin = (DATAP | DATAM);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Enable USB OTG FS clock */
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();
/* Enable USB OTG FS interrupt */
HAL_NVIC_SetPriority(OTG_FS_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
}
}
USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost) {
if (phost->id == HOST_FS) {
/* Link the driver to the stack. */
hhcd_USB_OTG_FS.pData = phost;
phost->pData = &hhcd_USB_OTG_FS;
hhcd_USB_OTG_FS.Instance = USB_OTG_FS;
hhcd_USB_OTG_FS.Init.Host_channels = 1;
hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL;
hhcd_USB_OTG_FS.Init.dma_enable = DISABLE;
hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED;
hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
hhcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
hhcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
hhcd_USB_OTG_FS.Init.use_external_vbus = DISABLE;
if (HAL_HCD_Init(&hhcd_USB_OTG_FS) != HAL_OK) {
printf("HAL_HC_Init ERROR\n");
while (1) {
}
// Error_Handler();
}
USBH_LL_SetTimer(phost, HAL_HCD_GetCurrentFrame(&hhcd_USB_OTG_FS));
}
return USBH_OK;
}
I setup the USB host during startup like so:
void USB_HOST_Init(void) {
if (USBH_Init(&hUsbHostFS, USBH_UserProcess, HOST_FS) != USBH_OK) {
printf("USB_Init ERROR\n");
while (1) {
}
}
if (USBH_RegisterClass(&hUsbHostFS, &AUDIO_Class) != USBH_OK) {
printf("USBH_RegisterClass ERROR\n");
while (1) {
}
}
if (USBH_Start(&hUsbHostFS) != USBH_OK) {
printf("USBH_Start ERROR\n");
while (1) {
}
}
}
and then I just call USBH_Process
in the while
loop.
This is my system clock config function:
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
// RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // Enable PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // Use HSE as PLL source
RCC_OscInitStruct.PLL.PLLM = 25; // Divide HSE by 8 -> 1 MHz
RCC_OscInitStruct.PLL.PLLN = 336; // Multiply by 336 -> 336 MHz
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; // Divide by 4 -> 84 MHz (SYSCLK)
RCC_OscInitStruct.PLL.PLLQ = 7; // Divide by 7 -> 48 MHz (USB clock)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error_Handler();
}
}
I want to aim this at the audio class, specifically microphones, but I have also tried the HID class in case it was something to do with audio/my microphone in particular, but that doesn’t seem to be the case and it hangs no matter the device I connect.
I have already posted this on the ST forums about a week ago but I have recieved no response, so I want to try here. The stm32cube framework, the microcontroller itself and ARM on an MCU is pretty new to me, so even with debugging I just don’t know what I’m looking for. I’m not sure what the registers are supposed to be, what interrupts relate to the USB host, etc, otherwise I would try and debug further than I have already.
Does anyone know what could be wrong? I would massively appreciate any assistance!