一、說明
在調試 STM32 USB device MSC 功能時,使用官方提供的庫和示例項目,電腦可以正確識別設備,也可以正常操作。但是將 USB 部分的代碼移植到自己的工程後,發現電腦無法正確識別設備,有時會在右下角顯示無法識別設備。
二、解決方法
在main.c中添加 hal_delay() 函數的實現方式。
在默認的模板工程裏,一般使用如下的方式實現延遲函數。
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
__weak void HAL_Delay(__IO uint32_t Delay)
{
uint32_t tickstart = 0U;
tickstart = HAL_GetTick();
while((HAL_GetTick() - tickstart) < Delay)
{
}
}
而在 USB 項目中,需要使用如下的方式實現延時函數。
void HAL_Delay(__IO uint32_t Delay)
{
while(Delay)
{
if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)
{
Delay--;
}
}
}
這兩種方式都可以實現基本的延時功能,都是使用的 SysTick 定時器來實現,也都是使用 while()
來進行條件判斷,條件不滿足,即計時到了指定的延時後退出 while()
。區別在於,第一種方式,進行條件判斷的變量 uwTick
在 SysTick 的中斷函數中進行加一操作,即如下代碼:
__weak void HAL_IncTick(void)
{
uwTick++;
}
void SysTick_Handler(void)
{
HAL_IncTick();
}
而第二種方式,進行 while()
條件判斷的變量 Delay
是不依賴於 SysTick 中斷函數進行改變的,而是直接在這個函數中進行判斷,等待寄存器數值改變,延時 1ms 後,對 Delay
進行減一操作。
默認的實現方式依賴於 SysTick
中斷函數void SysTick_Handler(void)
,而在使用 USB 功能時,USB的操作本身就是需要在中斷函數 void OTG_FS_IRQHandler(void)
中進行的。可能由於對不同中斷函數的處理,導致了時間上的錯誤,從而電腦無法正確進行枚舉操作。
USB 部分是在 usbd_conf.c
文件中的 void USBD_LL_Delay(uint32_t Delay)
函數中進行延時函數的調用的,如下所示:
void USBD_LL_Delay(uint32_t Delay)
{
HAL_Delay(Delay);
}
而且在底層的 USB 庫中,也有直接調用到hal_delay
的,如下:
2018.1.3修改
後來發現好像不是這個問題,不這樣修改也可以連接。講道理 SysTick 的中斷優先等級比 USB 的高,因此應該是不會受影響的。可是當時對比了兩個工程的代碼,好像也就這點區別。不過在官方庫中,都是使用第二種方式的。