星標公眾號,讓嵌入式知識 “投喂” 不停歇!
在嵌入式領域,USB接口因其高速度和普遍性成為首選通信方式之一。然而,USB協議的復雜性讓許多開發者望而卻步。傳統的USB協議棧往往存在以下問題:體積龐大、移植困難、內存不安全(動態分配)以及線程安全性差。
TinyUSB的出現徹底改變了這一現狀。這個由Ha Thach發起的開源項目,以其簡潔的設計、卓越的跨平臺支持和嚴謹的內存管理,成為了嵌入式USB開發的理想選擇。

https://github.com/hathach/tinyusb
TinyUSB是一個開源的跨平臺USB Host/Device協議棧,專為嵌入式系統設計。它支持多種MCU架構,包括STM32、nRF52、ESP32-S2等主流芯片。項目采用MIT許可證,核心代碼位于src目錄下,確保了商業使用的友好性。
讓我印象深刻的是,TinyUSB在保持功能豐富的同時,堅決不使用動態內存分配,所有資源在編譯時確定,這對于資源受限的嵌入式環境至關重要。
TinyUSB最精妙的設計之一是其事件處理機制。它采用完全線程安全的設計,將所有中斷事件推入中央隊列,然后在非ISR任務函數中處理。這種設計避免了在中斷上下文中執行復雜邏輯,提高了系統穩定性。
以下是TinyUSB的事件處理流程:

這種設計的關鍵優勢在于:
在代碼層面,這一機制通過tud_task()函數實現:

這里使用的_osal_queue_receive是OS抽象層的一部分,TinyUSB通過這種設計實現了對多種RTOS和無OS環境的支持。
TinyUSB的硬件抽象層是其可移植性的關鍵。它定義了一組簡潔的接口,將核心棧與硬件特定代碼分離。當我研究其HAL設計時,發現它沒有試圖抽象所有可能的硬件特性,而是聚焦于USB控制器的共同核心功能。

這種面向接口的設計使得移植新平臺變得直接。只需實現這一組標準函數,就能讓TinyUSB運行在新的硬件上。
在分析TinyUSB源碼時,我發現了端點描述符管理的一個精巧設計。在USB主機開發中,端點描述符包含了端點通信的關鍵參數(如端點地址、屬性、最大包大小等)。
TinyUSB采用分層架構,當上層調用usbh_edpt_control_open()時,硬件控制器驅動(HCD)層會獨立維護端點狀態,而不是直接引用上層傳入的描述符指針。這種設計避免了臨時結構體在棧上被破壞的風險,體現了TinyUSB對穩定性的高度重視。
最近,我將TinyUSB移植到一款MM32F5370微控制器上。雖然該芯片的SDK中沒有提供TinyUSB支持,但借助MM32F5270的參考實現,我成功完成了移植。
移植過程的關鍵步驟:
一個常見的陷阱是內存對齊問題。特別是在Cortex-M0/M0+等不支持非對齊訪問的平臺上,需要特別注意數據結構的設計。TinyUSB通過TU_ATTR_ALIGNED宏來處理這一問題:

在使用TinyUSB的CDC(通信設備類)進行高速數據傳輸時,我遇到了數據丟失問題。通過分析發現,這是因為在連續發送數據時沒有正確檢查可用空間。
正確的數據發送模式應該是:

對于更高性能的需求,可以實現tud_cdc_tx_complete_cb回調函數,采用中斷驅動的方式發送數據,減少輪詢開銷。
TinyUSB不僅僅是一個USB協議棧,更是嵌入式軟件設計的典范。通過研究它的源代碼,我學到了:
無論是用于實際項目還是學習目的,TinyUSB都是一個值得投入時間的優秀開源項目。
猜你喜歡:
適用于嵌入式的輕量級環緩沖區管理庫!
Git 交互式變基修改commit描述
單例模式:嵌入式全局狀態一致性的守護者
嵌入式領域:Linux 與 RTOS 的巔峰對決!
嵌入式軟件進階指南,一起來進階!
在公眾號聊天界面回復1024,獲取嵌入式資源