首頁>技術>

1. 概述

我們已經對USB硬體和資料的四種傳輸型別有了一個基本的瞭解。

控制傳輸(Control Transfers)

批次傳輸(Bulk Data Transfers)

中斷傳輸(Interrupt Data Transfers)

同步傳輸(Isochronous Data Transfers):

下面我們透過一個例子看一下USB的具體工作過程。在此我們用一個比較實用的例子,就是把我們的板子用USB連線至PC,然後在PC端出現一個模擬串列埠,透過串列埠助手開啟這個串列埠,然後實現資料的雙向傳輸。最後我們聊一下很多工程師都會忽視的USB認證問題。

2. 例程

我們開啟ST的Cube庫中的CDC例程:

STM32Cube_FW_F1_V1.8.0\Projects\STM3210C_EVAL\Applications\USB_Device\CDC_Standalone\MDK-ARM\Project.uvprojx

這個例程使用的硬體是STM3210C-EVAL,原理圖可以在stmcu.org.cn找到。如果我們使用的是其它板子,就需要在這個工程基礎上做一些改動。比如現在我們使用STM32F105RBT6,8M晶振,串列埠用PTA2,PTA3,那麼我們的要做如下修改:

首先,修改使用的MCU:

然後修改時鐘初始化部分。下圖為STM32F105時鐘模組示意圖。USB工作需要48MHz的時鐘。

(STM32F105xx Datasheet)

如果板子的晶振是8M,那麼引數需要做如下配置:

(OSC IN = 8M)

PREDIV1SRC = 0b0, HSE oscillator clock selected as PREDIV1 clock entry

PREDIV1 = 0b0, PREDIV1 input clock not divided

PLLSRC = 0b1, Clock from PREDIV1 selected as PLL input clock

PLLMUL = 0b0111, PLL input clock x 9

(PLLCLK = 72M)

SW = 0b10, PLL selected as system clock

PLLVCO = 2*PLLCLK = 144M

USBPRE = 0, PLL clock is divided by 1.5 (or PLLVCO/3)

USB Clock = = PLLCLK/1.5 = 72M/1.5 = 48M

例程中的對應程式碼修改:

最後修改使用的串列埠引腳:

stm32f1xx_hal_msp.c

//AFIOCOMx_REMAP(0); // Remap USART2 to PTD5/6

usbd_cdc_interface.h

/* Definition for USARTx Pins */

//#define USARTx_TX_PIN GPIO_PIN_5

//#define USARTx_TX_GPIO_PORT GPIOD

//#define USARTx_RX_PIN GPIO_PIN_6

//#define USARTx_RX_GPIO_PORT GPIOD

#define USARTx_TX_PIN GPIO_PIN_2

#define USARTx_TX_GPIO_PORT GPIOA

#define USARTx_RX_PIN GPIO_PIN_3

#define USARTx_RX_GPIO_PORT GPIOA

終於可以編譯運行了,用USB線把板子連到PC的USB口,記得把板子的PTA2和PTA3引腳短接起來。在裝置管理器我們看到多出來一個串列埠,看它的屬性會看到它的VID,PID跟我們程式中設定的一致。

用串列埠助手開啟此串列埠,傳送字串,會看到返回同樣的字串。

下面我們來看一下具體的工作過程。

3. USB列舉(Enumeration)

當我們給裝置上電,程式控制晶片內整合的上拉電阻連線至USBDP時,USB主機(PC端)會檢測到這一變化並向裝置供電。此時裝置處於Powered狀態。

主機等待100ms裝置穩定後復位並使能此埠,此時裝置可以從Vbus獲取不超過 100mA 的電流,其預設地址是0,處於Default狀態。

主機透過0地址向該裝置傳送Get_Descriptor標準請求,獲取裝置的描述符。主機再次復位該PORT,併發送標準請求Set_Address給裝置分配一個地址,之後的通訊都是用此地址,裝置進入Address狀態。

主機透過新地址向裝置再次傳送Get_Descriptor標準請求,獲取裝置描述符。傳送Get_Configuration請求,獲取配置描述符。一個裝置可以有多個配置,主機選擇合適配置,透過 Set_Configuration請求對裝置而進行配置,裝置進入Configured狀態。

USB的列舉過程是標準的,所以庫裡也有對應的標準處理程式碼。我們可以不用關心。好了,現在可以開始資料的雙向傳輸了。

4. 資料傳輸

我們已經瞭解所有USB傳輸都是由USB主機(Host)發起的,作為USB裝置只能是被動的等待。當Host下發請求時會在裝置中產生各種中斷,裝置完成各種中斷的處理就行了。其中需要特別關注的有兩個:

OEPINT(Output Endpoint Int),表明主機下發了資料。

IEPINT(Output Endpoint Int)。表明主機請求裝置上傳資料。

那麼使用者在程式碼裡如何收發USB資料的呢?

我們在usbd_cdc_interface.c裡關注下面這些就夠了:

uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; //USB下發資料緩衝區

uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; //需要發給USB上位機的資料緩衝區

static int8_t CDC_Itf_Receive(uint8_t * Buf, uint32_t * Len);

那麼如果有資料需要發給上位機呢?我們可以用下面這個函式:

USBD_CDC_TransmitPacket(&USBD_Device);

注意此資料是先放入IN端點,然後等待IEPINT中斷髮生時才被取走傳送。

5. 一個重要又容易被忽視的問題

至此好像萬事大吉了。

等等,如果產品這樣發出去,你可能給公司惹麻煩了!

還有一個很重要的問題我們千萬不要忽視,就是VID和PID,即廠商識別符(Vendor ID)和產品識別符(Product ID)。我們例程中使用的是VID 0x0483, PID 0x5740。這個VID是專門分配給ST的,雖然我們用這個號程式也能執行,但是不符合規範的。我們的可以在 usb.org/developers 網站查到當前為所有USB廠商分配的VID。如果我們要開發USB裝置,還要向USB組織申請自己的VID,之後還要做微軟徽標認證,就可以暢行無阻了。

參考資料:

UM1734 STM32Cube USB device library

USB Specification 2.0

Universal Serial Bus Class Definitions for Communications Devices 1.2

STM32F105xx Datasheet

STM32F105xx RM

21
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Java專案權威Top200排名-結果出乎你意料