2025-01-19 04:37 AM
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, &HID_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 am programming this in vscode with platformio rather than the IDE but I don't think that would cause any issues.
Does anyone know what could be wrong?