【解決方案】STM32F107VC單片機下運行STM32CubeMX生成的USB_OTG Mass Storage工程,無法識別USB設備的解決辦法

這是因爲:CubeMX生成的代碼裏面,沒有響應OTG_FS_IRQn中斷。

USB設備模式的電路如下。該電路適合所有的STM32型號。
紅框部分爲上拉電阻,STM32F1(如STM32F103和STM32F107)才需要這部分電路,而STM32F4就可以不要。這是因爲STM32F4的USB_OTG_GCCFG寄存器裏面有NOVBUSSENS這一位,可以打開內部的上拉電阻,而STM32F1卻沒有。
當PE1(可以選擇其他I/O口)爲低電平時使能上拉電阻,主機認爲USB設備已插入。當PE1爲高電平時,主機認爲USB設備已拔出。正常情況下應該使PE1輸出低電平。

STM32F107VC的時鐘配置如下。保證USB有48MHz的時鐘。

USB配置爲Device Only模式,只需要兩個引腳(PA11和PA12)就可以實現USB設備。

確保PE1配置爲輸出低電平。

生成工程後,打開stm32f1xx_it.c,可以發現裏面根本沒有USB OTG的中斷處理函數,儘管CubeMX裏面勾選了USB OTG中斷處理(灰色必選),然而這並不能改變USB OTG中斷處理函數沒有生成的事實。

於是添加如下代碼:

extern PCD_HandleTypeDef hpcd_USB_OTG_FS;

void OTG_FS_IRQHandler(void)
{
  HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
}

還要打開usbd_conf.c,找到HAL_PCD_MspInit函數,在裏面打開USB OTG的中斷。
(連打開USB中斷的代碼都沒有。。。)

/* USER CODE BEGIN USB_OTG_FS_MspInit 1 */
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
/* USER CODE END USB_OTG_FS_MspInit 1 */

燒寫後,再運行程序,問題就解決了。可以在電腦裏面看到U盤盤符了。

 

另外,如果發現USB設備能夠成功枚舉但無法啓動,則可能是malloc分配內存失敗導致的。
打開usbd_conf.h,檢查USBD_malloc和USBD_free的定義。如果是下面的定義,是不會出問題的。

/* Memory management macros */

/** Alias for memory allocation. */
#define USBD_malloc         (uint32_t *)USBD_static_malloc

/** Alias for memory release. */
#define USBD_free           USBD_static_free

如果定義的是malloc和free,那就很可能內存分配失敗,USBD_malloc返回了NULL導致USB 端點1沒有開啓。

/* Memory management macros */
#define USBD_malloc               malloc
#define USBD_free                 free

在Mass Storage的USBD_MSC_Init函數裏面會調用USBD_malloc函數分配8300字節的內存用於存儲USBD_MSC_BOT_HandleTypeDef結構體的內容。這遠遠超出了啓動文件(如startup_stm32f103xb.s)裏面定義的堆內存的大小Heap_Size。

pdev->pClassData = USBD_malloc(sizeof(USBD_MSC_BOT_HandleTypeDef));

Heap_Size默認爲0x200,加上8300(=0x206c)後是0x226c,可以把Heap_Size定義爲0x2400。

 

——————————————————————————————————————————————————————

這裏順便說一下,STM32F103裏面的從USB,收發數據靠的是讀寫512字節的PMA(Packet Memory Area),其地址爲0x40006000~0x400063fd。第0個字節是0x40006000,第1個字節是0x40006001;第2個字節是0x40006004,第3個字節是0x40006005;第4個字節是0x40006008,第5個字節是0x40006009……以此類推,直到第511個字節0x400063fd。

而STM32F107裏面的USB OTG,收發數據靠的是1.25KB的DFIFO。定義:

#define USB_OTG_FS_PERIPH_BASE               0x50000000UL
#define USB_OTG_FIFO_BASE                    0x00001000UL
#define USB_OTG_FS_DFIFO ((USB_OTG_DFIFOTypeDef *)(USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE))

typedef struct
{
  uint32_t DFIFO;
  uint32_t RESERVED[1023];
} USB_OTG_DFIFOTypeDef;

則接收數據始終是讀取USB_OTG_FS_DFIFO->DFIFO寄存器(相當於USB_OTG_FS_DFIFO[0].DFIFO),而發送數據是寫USB_OTG_FS_DFIFO[端點號].DFIFO寄存器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章