最近在使用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的情况下,也可以当做全速接口使用(这是在调试的时候,因为硬件已经连接成这样了,没办法最后百度才知道可以这样使用的,而我最终的使用方式也是用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盘进行读写了。