整理:MilerShao 關鍵詞:STM32、USB、DEVICE、PACKET BUFFER 、PMA 、ENDPOINT、緩沖描述表、包緩沖、端點 STM32系列MCU大多具有USB外設,其中一部分具有USB FS模塊,作為DEVICE使用。另外一部分具備OTG模塊,可以實現HOST/DEVICE雙重角色的功能。這里聊聊關于STM32F1/F3/L1系列的USB FS 模塊中的包數據緩沖話題,即Packet Buffer Memory。STM32F1/F3/L1這三個系列的USB FS模塊基本具有相同的結構,這里不妨以STM32F1系列的非互聯型芯片的USB FS 模塊為例來介紹下Packet Buffer Memory Area,后面簡稱PMA.
這個PMA的作用就是USB設備模塊用來實現MCU與主機進行數據通信的一個專門的數據緩沖區,我們稱之為USB硬件緩沖區。說得具體點就是USB模塊把來自主機的數據接收進來后先放到PMA,然后再被拷貝到用戶數據緩存區;或者MCU要發送到主機的數據,先從用戶數據緩存區拷貝進PMA,再通過USB模塊負責發送給主機。 不少人在利用ST官方提供的參考工程庫文件來開發自己的USB應用時,圍繞PMA的配置和使用的地方有時會出錯卡殼,或者說即使做完了,即使關于PMA可能還有些疑惑。這里一起聊聊PMA話題。不妨先看看STM32F1系列的非互聯型芯片的USB FS 模塊功能結構圖。
上圖中的紅色方框部分就是Packet Buffer Memory,該系列芯片的的最大容量為512字節,在USB模塊內部按半字訪問,即256個半字。該存儲區域既可以被USB內核通過Packer buffer Interface【包緩沖接口】尋址訪問,亦可以被CPU通過APB1總線訪問,某時刻具體誰去訪問它由圖中的Arbiter【仲裁器】決定,APB1總線具有更高優先級。要注意的是,USB內核訪問該區域是16位數據寬度對齊,而APB1總線訪問它是以32位數據寬度對齊。另外,USB模塊中的端點相關寄存器的訪問跟PMA一樣,也可以分別被USB內核或APB1總線訪問,同樣存在兩種訪問對齊的問題。
好,繼續聊聊PMA的具體內部結構和用法。我們知道,【如果不知道就假設知道吧,其實無數的理論都是從假設或約定開始的:-)】每個雙向端點對應2個Packet Buffer,分別用作發送數據包的緩沖和接收數據包的緩沖【雙緩沖端點可視為兩個單向端點輪流跟HOST固定地做IN或OUT方向的單向通信,輪換使用2個同向緩沖區】。這些Packet buffer的大小和位置在PMA內可以配置,具體由緩沖描述表【buffer description table】來指定,該描述表也放在PMA里面。它的起始地址由USB_BTABLE寄存器指定。即整個PMA放置的內容就是緩沖描述表和該表所指定的各端點相應的接收或發送緩沖區。 現在問題來了,既然緩沖描述表負責指定使用到的各端點的包緩沖地址及大小,那緩沖描述表自身在PMA中所占存儲空間的大小怎么定的呢?
下面就是PMA的內容框架結構示意圖。PMA內存放著USB應用中用到的各端點包緩沖【PACKET BUFFER】和指定這些PACKET BUFFER的地址和大小的緩沖描述表【buffer description table】兩部分內容。  從上面PMA的內部框架圖可以比較直觀地看出緩沖描述表是由各端點兩個方向的緩沖區起始地址及相關數據長度之內容所占據,每個雙向端點占4個連續的半字,在PMA內部按照地址從低往高的順序依次存放各端點的發送緩沖區的地址、待發送數據的長度、接收緩沖區的地址、接收緩沖區的長度。這4個連續的半字組成緩沖描述表的一個表項[ENTRY]。各表項又按照端點序號依次從小往大的朝地址遞增方向連續存放。
前面說過緩沖描述表在PMA中的起始位置的偏移量由USB_BTABLE寄存器決定。如無特別需要,一般把它設置為零,即從PMA的硬件起始地址開始存放包緩沖描述表,確切地說,從PMA的起始地址開始沿著端點序號由小到大的順序依次存放或預留各端點表項,直到程序代碼中指定的最大端點號為止。每個表項占4個半字,即8個字節。 比方說,如果你用到端點0,1,3 共三個端點,那緩沖描述表里除了安排端點0,1,3的表項外,其中2號端點的表項空間【8個字節】依然會預留在表項1與表項3之間的存儲空間。也就是說這種情況下,緩沖描述表自身還是占4*8=32字節的空間,其中表項2的8字節空間可以說是浪費了【其實也可以用,只是使用起來不太方便】。
當然,我這里只是舉個例子。一般來講,比方中的端點安排完全可以調整為 0,1,2,那3號端點就用不著了。這樣的話緩沖描述表自身所占的PMA空間為 3*8=24 字節,節省出8個字節可以給后面的包收發緩沖區之用。 我們已經知道,PMA里面的各端點的包緩沖地址及大小是由緩沖描述表指定的,而緩沖描述表同時又跟這些包緩沖共同占據整個PMA。那么,如果緩沖描述表自身在什么位置、占多少空間不清的話,而去給端點指定緩沖地址及大小難免有點抓瞎的味道。有人在做STM32 USB DEVICE開發應用時,正是在對緩沖描述表本身位置及自身用到多少PMA存儲空間不清楚的情況下而去給用到的端點指派緩沖地址及大小,經常出現調試或通信異常。
經過上面的介紹,了解了緩沖描述表的結構和存儲模式后,對于不同端點需求的情況下,緩沖描述表自身占多少空間就不難算出了,知道了起始地址,結尾地址自然就知道了。下面一起來看看大家常見的一個STM32 USB DEVICE 應用實例。
顯然,這里用到了0,1,2三個端點。具體是0號雙向端點,1號IN端點,2號OUT端點。配置代碼里有5個數據,其中第一行的數據0x00告知緩沖描述表的起始位置位于PMA的起始位置,另外4個數據用來明確給出應用中用到的各端點數據緩沖區起始地址【或發或收】。順便提下,USB硬件不會把本端點的數據溢出到相鄰端點的緩沖區。從這幾句代碼可以看出使用到的各端點數據緩沖區的起始地址及大致范圍,但似乎并不能明確看出前面提到的緩沖描述表所占的地址空間及尾地址。尤其ENDP0_TXADDR的起始地址0X18怎么定出來的呢?是否還可以變動? 結合上面關于緩沖描述表的介紹,一起來分析下。這里用到3個端點,而且是三個編號連續的端點,對應3個表項,那么該緩沖描述表自身所占空間長度為 3*8=24,16進制是0x18; 因為BTABLE_ADDRESS=0,所以緩沖描述表在PMA里存放位置就是0x00-0x17這段存儲空間,從0x18開始以上的空間就可用作包緩沖區了。為了充分利用PMA空間,所以0號端點的發送緩沖區起始地址ENDP0_TXADDR就從0x18開始了。其它緩沖區的地址位置和大小也是在結合各自端點傳輸特性和相鄰包緩沖大小的基礎上擬定,避免相鄰緩沖區的交叉重疊。
那這個起始地址0X18是否可以變動呢?如果在端點安排不變的前提下,這個0X18是否可以變動,答案是肯定的。只要不放進緩沖描述表地址段里面就好,完全可以弄成0x20,0x28,0x48等不小于0x17的偶數,因為USB模塊對PMA存儲區的訪問是雙字節對齊。當然,如果你把0x18調整后,其它相鄰的包緩沖地址往往需要做相應的調整。
那假如在上面圖示的基礎上,因為項目功能需求調整,減少1個端點,比如把2號OUT端點取消,那上面的PMA地址配置需要怎樣調整呢?【其它相關問題這里就不延伸了】 如果取消OUT 2端點的話,上面有關PMA地址的配置基本可以不動,屏蔽掉關于OUT2端點接收緩沖地址定義的就行。當然,這里的端點數由之前的3個變少到2個,緩沖描述表自身的長度實際上變少為 2*8=16 字節了,也就是說從0x10開始以上的空間都可以用來做包緩沖區,如果包緩沖區繼續保持在0x18開始的地方也無妨。
假如就在上面圖示基礎上,因為功能的需求調整,增加1個單向端點,比如增加3號IN端點,那上面的PMA地址配置需要怎樣調整呢? 這里的端點數由之前的3個變成4個,緩沖描述表自身的長度就變多為 4*8=32字節了,即0x20以下的空間都給緩沖描述表占了,換句話說,只有從0x20開始以上的空間才能用作包緩沖區。那端點0發送緩沖地址【ENP0_TXADDR】如果還保持0x18的話肯定不行,這里不調整的話可能就亂大了。經常有人在以ST官方參考庫的基礎上增加端點后,只是添加新增端點的緩沖區地址和大小及相應描述配置等,卻沒有顧及到這個包緩沖的起始地址的問題而遇到調試障礙。具體到這里,ENP0_TXADDR緩沖區的地址不得小于0x20,其它緩沖地址往往需要適當調整移動。當然,如果覺得剩余PMA空間夠用的話,你也完全可以在既不影響其它端點緩沖大小又不影響自身緩沖需要的前提下,大刀闊斧的把ENP0_TXADDR緩沖起始地址換到一個全新的地址,不一定非得圍著0x18或0x20轉來轉去,比方換到0x138。 ......Have a rest..... 還是接著上面的實例繼續聊,看看根據上面的初始化配置,相關緩沖描述表的表項內容在PMA中是如何存放的。
顯然,整個緩沖描述表用到3個端點,共占空間 3*8=24個字節。 因為OUT 1端點和IN 2端點沒有用到,但他們在表項中的橢圓形圓圈圈出來的灰色部分空間還預留出來了,一共8個字節夾在中間基本算是浪費了。如果把端點 OUT 2 換到 OUT 1,那整個緩沖描述表只用到2個端點,所需空間就變為 16字節了。多余出來的8字節就可以方便的留給包緩沖用。另外,表格中的有些數據可能需要結合參考手冊的USB寄存器部分看看。那個XXXX/YYYY表示初始化時不定的,準備做數據傳輸時才確定。地址0x40006000是PMA的起始地址。 小結下,緩沖描述表的起始地址和所占空間都是可以明確指定和計算出來的,包緩沖地址的安排往往跟它有關聯。只有明確知道了緩沖描述表的起始地址和自身所需存儲空間長度后,才能放心地用剩余的PMA給用到的端點分別指定緩沖地址及大小。 緩沖描述表里的表項是根據端點號在PMA里按序填充的,合理安排端點可以減少緩沖描述表的PMA空間使用量,而留下更多空間給端點包緩沖區。 最后,注意每次傳輸實際收到的數據包長度不會超過各端點接收緩沖區容量的限制,長了會被截掉。 |