最近在使用STM32F207的芯片調試USB讀寫U盤的功能,花費了好多天,總算是調試通過了。現在回頭去看,還是走了很多的彎路的,下面將正確的思路總結如下,對自己是個經驗的記錄,當然也希望對后面要用到的朋友有所幫助。
硬件環境:STM32F207的芯片,這款芯片USB接口有FS和HS之分,由於之前對這兩個接口的區別不是很了解,所以畫原理圖的時候,就將USB的接口連接在了HS的接口上(PB14,PB15), 另外對於USB接口只連接了DP和DM,並沒有連接VBUS信號。外部晶振使用的是8M的晶振。 USB部分的電路,如下圖所示

說明: OTG_FS為 full speed 全速接口, OTG_HS為 high speed 高速接口,對於全速接口就是我們一般使用最多的USB接口形式了,而高速的USB接口,一般需要配合USB的外部PHY聯合使用,但是在不使用外部PHY的情況下,也可以當做全速接口使用(這是在調試的時候,因為硬件已經連接成這樣了,沒辦法最后百度才知道可以這樣使用的,而我最終的使用方式也是用HS的接口,當FS使用)。
軟件環境: 調試USB讀寫U盤的功能是基於ST官方論壇上下下來的例程,在此基礎上做修改。
1.首先需要解決的就是,如何在HS的USB接口上使用USB FS,代碼需要做這樣幾處修改。
(1)時鍾配置部分,一定要配置正確,時鍾是一切系統工作的基礎(從ST官網論壇上下載下來的STM32F2的例程有的是12M晶振的,有的是8M晶振的,盡量選擇和自己的晶振一致的例程,避免不必要的錯誤)。
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 240;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 5;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3);
}
(2)接下來就是USBH_LL_Init()函數的修改了,這里一定要使用HS的配置。也就是需要對USE_USB_HS進行宏定義
USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost)
{
/* Set the LL Driver parameters */
// hhcd.Instance = USB_OTG_FS;
hhcd.Instance = USB_OTG_HS;
hhcd.Init.Host_channels = 11;
hhcd.Init.dma_enable = 0;
hhcd.Init.low_power_enable = 0;
hhcd.Init.phy_itface = HCD_PHY_EMBEDDED; // 需要特別注意這幾個標紅的地方,這些地方是需要進行修改的
hhcd.Init.Sof_enable = 0;
hhcd.Init.speed = HCD_SPEED_FULL;
hhcd.Init.vbus_sensing_enable = 0;
/* Link the driver to the stack */
hhcd.pData = phost;
phost->pData = &hhcd;
/* Initialize the LL Driver */
HAL_HCD_Init(&hhcd);
USBH_LL_SetTimer(phost, HAL_HCD_GetCurrentFrame(&hhcd));
return USBH_OK;
}
(3)最后就是對硬件管腳的配置了
void HAL_HCD_MspInit(HCD_HandleTypeDef *hhcd)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* Configure USB FS GPIOs */
__HAL_RCC_GPIOB_CLK_ENABLE();
/* Enable USB FS Clocks */
__HAL_RCC_USB_OTG_HS_CLK_ENABLE();
/*USB DM and DP */
GPIO_InitStruct.Pin = (GPIO_PIN_14 | GPIO_PIN_15); //因為這里沒有使用VBUS信號,所以只有DP和DM信號的定義
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; //這里一定要選復用,就是靠這個將HS應用於FS的
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Set USBFS Interrupt priority */
HAL_NVIC_SetPriority(OTG_HS_IRQn, 6, 0);
/* Enable USBFS Interrupt */
HAL_NVIC_EnableIRQ(OTG_HS_IRQn);
}
(4)還有一個需要注意的地方,就是中斷處理函數,用的也是HS的,不能使用FS
void OTG_HS_IRQHandler(void)
{
HAL_HCD_IRQHandler(&hhcd);
}
其他地方就不用再修改了,依照例程原有的方式就好了,到此就可以正常的對U盤進行讀寫了。
特別說明:對於要使用STM32的DFU功能升級程序的功能時,不要照上面描述的使用,因為STM32的DFU功能默認是在USB FS的管腳上配置的,如下圖描述所示

