//=========================By xiaowei
/*
*/
//=========================
1、硬件介紹
1、SGM7227,USB高速切換開關,OE是芯片使能,低電平才能使總線導通;
S腳是切換控制;
USB協議
https://segmentfault.com/a/1190000015995506
2、軟件移植
移植文件分析
stm32自帶USB接口,OTG-FS(全速)和OTG-HS(高速),因為stm32f4只帶有高速PHY,想使用高速模式,就需要外擴高速PHY,在此為USB3300。
系統配置一個Device端口,一個Host端口;
Device端口連接主機,在此處為POS機,外接USB3300作為高速PHY;
Host端口連接打印進,使用了STM32內置的全速PHY;
移植時,我們重點要修改的就是 USB_APP 文件夾下面的代碼。其他代碼(USB_OTG 和USB_DEVICE 文件夾下的代碼)一般不用修改。
需要修改的文件:
usb_bsp.c 提供了幾個 USB 庫需要用到的底層初始化函數,包括: IO 設置、中斷設置、VBUS配置以及延時函數等,需要我們自己實現。 USB Device(Slave)和 USB Host 共用這個.c 文件。
usbd_desc.c 提供了 USB 設備類的描述符,直接決定了 USB 設備的類型、斷點、接口、字符串、制造商等重要信息。這個里面的內容,我們一般不用修改,直接用官方的即可。注意,這里: usbd_desc.c 里面的: usbd 即 device 類,同樣: usbh 即 host 類,所以通過文件名我們可以很容易區分該文件是用在 device 還是 host,而只有 usb 字樣的那就是 device 和 host 可以共用的。
usbd_usr.c 提供用戶應用層接口函數,即 USB 設備類的一些回調函數,當 USB 狀態機處理完不同事務的時候,會調用這些回調函數,我們通過這些回調函數,就可以知道 USB 當前狀態,比如:是否枚舉成功了?是否連接上了?是否斷開了?等,根據這些狀態,用戶應用程序可以執行不同操作,完成特定功能。
usbd_storage_msd.c 提供一些磁盤操作函數,包括支持的磁盤個數,以及每個磁盤的初始化和讀寫等函數。本章我們設置了 2 個磁盤: SD 卡和 SPI FLASH。
這些文件都是以回調函數的方式被內核調用,需要用戶編寫具體的應用程序;
使用時,需要定義 USB_OTG_CORE_HANDLE ,是一個全局結構體類型,用于存儲 USB 通信中 USB 內核需要使用的的各種變量、狀態和緩存等,任何 USB 通信(不論主機,還是從機),我們都必須定義這么一個結構體以實現 USB 通信。
USB 初始化非常簡單,只需要調用 USBD_Init 函數即可,本章的 USB 讀卡器屬于 USB 設備類,所以使用該函數。該函數初始化了USB 設備類處理的各種回調函數,以便 USB 驅動庫調用。執行完該函數以后, USB 就啟動了,所有 USB 事務,都是通過 USB 中斷觸發,并由 USB 驅動庫自動處理。
USB設備需要存儲介質,需要用戶定義存儲介質驅動。
USB驅動會自己調用處理函數進行處理,用戶需要改動的是底層的驅動,即磁盤的讀寫;具體在usbd_storage_msd.c里面,
磁盤回調函數結構體:
USBD_STORAGE_cb_TypeDef USBD_MICRO_SDIO_fops =
{
STORAGE_Init,
STORAGE_GetCapacity,
STORAGE_IsReady,
STORAGE_IsWriteProtected,
STORAGE_Read,
STORAGE_Write,
STORAGE_GetMaxLun,
(int8_t *)STORAGE_Inquirydata,
};
讀操作:
int8_t STORAGE_Read (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len)
{
buf=&U_DISK[blk_addr*512];
return 0;
}
USB啟動階段請求
這個博客分析的挺好:
https://www.cnblogs.com/Daniel-G/p/3993883.html
USB內核處理
USB_OTG_CORE_HANDLE 是全局變量,
用于存儲 USB 通信中 USB 內核需要使用的的各種變量、狀態和緩存等,任何 USB 通信(不論主機,還是從機),我們都必須定義這么一個結構體以實現 USB 通信,
typedef struct USB_OTG_handle
{
USB_OTG_CORE_CFGS cfg;
USB_OTG_CORE_REGS regs;
#ifdef USE_DEVICE_MODE
DCD_DEV dev;
#endif
#ifdef USE_HOST_MODE
HCD_DEV host;
#endifdda
#ifdef USE_OTG_MODE
OTG_DEV otg;
#endif
}
USB_OTG_CORE_HANDLE , *PUSB_OTG_CORE_HANDLE;
USB_OTG_CORE_HANDLE分析:
這是個全局結構體,內部存儲內核處理USB設備,主機的變量;
當USB作為Device設備時,USB_OTG_CORE_HANDLE定義為DCD_DEV ;
其參數如下:
typedef struct _DCD
{
uint8_t device_config;
uint8_t device_state;
uint8_t device_status;
uint8_t device_old_status;
uint8_t device_address;
uint8_t connection_status;
uint8_t test_mode;
uint32_t DevRemoteWakeup;
USB_OTG_EP in_ep [USB_OTG_MAX_TX_FIFOS];
USB_OTG_EP out_ep [USB_OTG_MAX_TX_FIFOS];
uint8_t setup_packet [8*3];
USBD_Class_cb_TypeDef *class_cb;
USBD_Usr_cb_TypeDef *usr_cb;
USBD_DEVICE *usr_device;
uint8_t *pConfig_descriptor;
}
DCD_DEV , *DCD_PDEV;
DCD_DEV 結構說明:
DCD_DEV結構包含用于實時保存與設備,控制傳輸狀態機以及端點信息和狀態相關的所有信息的所有變量和結構。
中斷處理
所有USB的事件都是通過中斷觸發,并由內核自動處理。
在此處USB_OTG_CORE_HANDLE USB_OTG_Core;用來作為主機結構;
__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_dev __ALIGN_END ;用來作為從機設備;
OTG概念
On-The-Go,即OTG技術就是實現在沒有Host的情況下,實現設備間的數據傳送。例如數碼相機直接連接到打印機上,通過OTG技術,連接兩臺設備間的USB口,將拍出的相片立即打印出來;也可以將數碼照相機中的數據,通過OTG發送到USB接口的移動硬盤上,野外操作就沒有必要攜帶價格昂貴的存儲卡,或者背一個便攜電腦。
3、USB作為Device設備
usbd_req和usbd_ioreq
文件描述:該文件處理USB事務的結果。
usb_dcd和usb_dcd_int
這兩個文件為USB庫提供設備接口層封裝;
其中usb_dcd文件包含以下函數:
DCD_EP_PrepareRx
DCD_EP_Tx
DCD_EP_Stall
DCD_EP_ClrStall
DCD_EP_Flush
USB OTG低電平驅動器的DCD層有一個必須通過USB中斷調用的功能(高速或全速):
DCD_Handle_ISR (USB_OTG_CORE_HANDLE *pdev)
usb_dcd_int文件說明:
上圖是USB設備庫構架;
如上圖所示,USB設備庫由兩個主要部分組成:庫核心和類驅動程序
庫核心包括三個主要部分:
USB device core
USB requests
USB I/O requests
USB設備庫處理流程圖
上圖的分析:
分為4個模塊,
上層應用;
設備庫和設備類
底層驅動
上層應用調用USBD_init()函數來調用USBD庫;同時應用層還為用戶提供了回調函數接口,在調用USBD庫時調用;
上層應用與設備類的交互是通過USBD_Class_cb來調用的,從上一張圖中可知,USB的設備類分為很多種,HID,audio,MSC等等;
上層應用與底層驅動的交互是通過幾個中斷函數聯系的;
MSC設備類驅動
MSC設備類包含文件:
usbd_msc_core ----- MSC類的核心處理文件
usbd_msc_bot -------bot協議封裝
usbd_msc_scsi----------SCSI指令封裝
MSC(Mass storage class)
USB大容量存儲類是圍繞僅批量傳輸(BOT)構建的。 它使用SCSI透明命令集。
SCSI指令集:
4、偽裝成打印機
usbd_desc.c 提供了 USB 設備類的描述符,直接決定了 USB 設備的類型、斷點、接口、字
符串、制造商等重要信息。
在這里,需要將單片機偽裝成打印機,因此需要封裝其USB信息。
需要講解一個概念:USB設備描述符;
USB設備描述符
說到USB設備,不得不提到各種描述符(descriptors), 一般來說,描述符有如下幾種:
1:設備描述符(Device Descriptors)
2:配置描述符(Configuration Descriptors)
2:接口描述符(Interface Descriptors)
3:端點描述符(Endpoint Descriptors)
他們之間的關系如下圖所示:
圖片說明:設備描述符定義了配置數多少,配置描述符又定義了端口多少,一層層向下定義。
USB描述符信息存儲在USB設備中,在枚舉過程中,USB主機會向USB設備發送GetDescriptor請求,
USB設備在收到這個請求之后,會將USB描述符信息返回給USB主機,USB主機分析返回來的數據,判斷出該設備是哪一種USB設備,建立相應的數據鏈接通道。
設備描述符包含信息:
描述符(Descriptor )是一個完整的數據結構, 存儲在USB 設備中, 用于描述一個USB 設備的所有屬性。USB主機通過一系列命令要求設備發送這些信息。
USB 設備的屬性包括很多內容, 為了便于管理, USB2.0協議將這些信息做了分類, 定義了多種描述符,包括標準和HID類的描述符,下面是標準描述符描述。
標準描述符
標準描述符 bDescriptorType字段
設備描述符(Device Descriptor) 0x01
配置描述符(Configuration Descriptor) 0x02
字符串描述符(String Descriptor,可選) 0x03
接口描述符(Interface Descriptor) 0x04
端點描述符(Endpoint Descriptor) 0x05
設備限定描述符(DEVICE_QUALIFIER) 0x06
其他速率配置描述符(OTHER_SPEED_CONFIGURATION) 0x07
接口功率描述符(INTERFACE_POWER) 0x08
描述符間的關系
一個設備有且只能有一個設備描述符,之后的描述符都允許有多個不同的描述符。
設備描述符(Device Descriptor)
每一個設備有且只有一個設備描述符
默認控制管道的數據包的長度( 端點0長度)是在設備描述符中定義, 而不像其他端點在端點描述符中定義。
14 個字段,18 Byte
偏移量 字段名稱 長度(Byte) 字段值 意義
0 bLength 1 0x12 設備描述符的字節數大小
1 bDescriptorType 1 0x01 設備描述符類型編號
2 bcdUSB 2 協議版本2.31其值就是0x0231 USB版本號
4 bDeviceClass 1 類 USB分配設備類代碼(1-FE)FF為廠商自定義
5 bDeviceSubClass 1 子類 USB分配子類代碼
6 bDeviceProtocol 2 協議 USB分配設備協議代碼
7 bMa xPack et Size0 1 控制傳輸端點0包大小 端點0最大包大小
8 idVendor 2 ID編號 廠商編號
10 idProduct 2 ID編號 產品編號
12 bcdDevice 2 BCD碼 設備出廠編號
14 iManufacturer 1 索引 描述廠商字符串索引
15 iProduct 1 索引 描述產品字符串的索引
16 iSerialNumber 1 索引 描述設備序列號字符串的索引
17 b NumConf igur at ions 1 配置描述符個數 可能配置數量
配置描述符(Configuration Descriptor)
8 個字段,9Byte
bmAttributes字段:D7保留值, 固定為1 ; D6表示供電方式, 1表示自供電, 0表示總線供電; D5,值為1 表示支持遠程喚醒, 值為0 則不支持;D4~D0沒有意義, 固定為0。
偏移量 字段名稱 長度(字節) 字段值 意義
0 bLength 1 0x09 配置描述符的字節數大小
1 bDescriptorType 1 0x02 配置描述符類型編號
2 wTotalLength 2 數字 這是一個以2 字節二進制數為內容的字段。該字段表示該配置所返回的所有描述符( 包括配置、接口和端點描述符) 的大小總和。
4 bNumInterfaces 1 接口描述符個數 此配置所支持的接口數量
5 bConfigurationValue 1 數字 Set_Configuration /Get_Configuration命令需要的參數值
6 iConfiguration 1 索引 描述該配置的字符串的索引值
7 bmAttributes 1 位圖 供電模式的選擇,第7位D7保留固定為1;D6值為1表示自供電,值為0表示總線供電; D5值為1表示支持遠程喚醒,值為0則不支持;D4~D0沒有意義固定為0
8 MaxPower 1 字段值*2(mA) 設備從總線提取的最大電流(<=500mA)
接口描述符(Interface Descriptor)
9 個字段,共9 字節
只能作為配置描述符的一部分返回,不能用GetDescriptor()或SetDescriptor()直接訪問。
偏移量 字段名稱 長度(字節) 字段值 意義
0 bLength 1 0x09 接口描述符的字節數大小
1 bDescriptorType 1 0x04 接口描述符類型編號
2 bInterfaceNumber 1 數字 該接口編號
3 bAlternateSetting 1 數字
4 bNumEndpoints 1 如果為0則說明只用了端點0 該接口使用的端點數 ,不包括端點0
5 bInterfaceClass 1 類 接口類型
6 bInterfaceSubClass 1 子類 接口子類類型
7 bInterfaceProtocol 1 協議 接口遵循的協議
8 iInterface 1 索引 描述該接口的字符串索引值
bInterfaceNumber:如果一個配置擁有N個接口, 那么這些接口都是互不相干的, 每一個接口都有惟一的編號, USB 就是通過此字段來識別不同的接口。默認值為0。
bAlternateSetting:USB設備配置與USB配置描述符是一一對應的, 即一個配置只能有一個配置描述符。雖然由bInterfaceNumber字段可知, 每一個接口都有一個惟一確定的接口編號, 但是一個接口卻可以由不只一個接口描述符來描述它。USB 允許多個接口描述符來描述同一個接口, 且這些描述符都可通過命令切換。此字段就是每一個這類描述符惟一的編號。USB可通過調用這個字段來切換描述同一個接口的不同描述符。控制傳輸中的Get_Inter face 命令可以用來得到目前正在使用的描述一個確定接口的接口描述符的編號, 即此字段。而Set_Inte rface 命令則以此字段值為參數, 用來使相應的接口描述符描述某個確定的接口
端點描述符(Endpoint Descriptor)
用于接口的每個端點都有自己的描述符。 此描述符包含信息
需要主機確定每個端點的帶寬要求。 端點描述符為始終由GetDescriptor(獲取配置描述符),作為配置信息的一部分返回。 端點描述符不能直接用GetDescriptor()或SetDescriptor()直接訪問。對于端點零,不存在端點描述符。
6 個字段共7 字節
描述接口所使用的非0 端點的屬性, 包括輸入/ 輸出方向、端點號和端點容量即包的大小等
偏移量 字段名稱 長度(字節) 字段值 意義
0 bLength 1 0x07 端點描述符的字節數大小
1 bDescriptorType 1 0x05 端點描述符類型編號
2 bEndpointAddress 1 端點 端點地址及輸入輸出屬性
3 bmAttributes 1 位圖 端點的傳輸類型屬性
4 wMaxPacketSize 2 數字 端點收、發的最大包的大小
6 bInterval 1 數字 主機查詢端點的時間間隔
偽裝成打印機的設備描述符
__ALIGN_BEGIN uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] __ALIGN_END =
{
0x12, /*bLength */
0x01, /*bDescriptorType*/
0x00, /*bcdUSB */ // usb 版本 2
0x02, //
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/ // 傳輸包大小 7
LOBYTE(USBD_VID), /*idVendor*/ // 廠商編碼 8
HIBYTE(USBD_VID), /*idVendor*/
LOBYTE(USBD_PID), /*idVendor*/ // 產品編碼 10
HIBYTE(USBD_PID), /*idVendor*/
0x00, /*bcdDevice rel. 2.00*/ // 設備出廠編號 12
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/ // 廠商字符串索引 14
上一篇:STM32F103系列USB的學習過程及使用心得(一)(概括篇)
下一篇:STM32f103USB移植之USB鼠標
推薦閱讀
史海拾趣