你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的USB程序开发笔记(五) ——USB设备的枚举(下)

[复制链接]
乡村布拉德 发布时间:2008-12-23 13:47
SETUP事件正确接收后,根据该事件提供的请求类型进行对主机的响应。SETUP数据结构的wLength字段说明的是请求返回或者提供的数据长度。 ) w& b" @. E9 T: n" b
如果判断出的请求信息错误或者说不被支持,STM32 USB设备需要中断此次请求: 7 z! [! ]  ]* \( A1 j4 B) ?  c
    SetEPR_RXStatus(ENDP0, EP_RX_VALID); " p0 i: s/ h& T9 u3 o
    SetEPR_TXStatus(ENDP0, EP_TX_STALL); 6 q3 n" H* ]2 b4 V: {* ?

0 p4 D; D8 Q5 B正确获取到请求信息后,如果wLength为0,设备需要发送一个0长度数据包以响应主机: $ C8 |$ r1 T4 t* f
// *****************************************************************************
% G' g/ b, r+ ?% m  T// Function Name  : SETUP0_Trans0Data + l  V2 J6 b; N& t. c
// Description    :
' U1 g) }: I, X) {; \" _6 w: C. C// Input          : ' U( b0 Q2 l2 V/ ?6 H4 c' l/ s
// Output         : 0 f0 A# I- U- ~; ]3 d. m( R
// Return         :
# `, C' @8 m9 M: u. y1 q9 c// ***************************************************************************** ! k9 E: j+ b2 p+ }: t
RESULT SETUP0_Trans0Data(void)
6 `  ]0 k0 n% |& \{
$ G) i2 o! |# k; ?  // Send 0-length data frame as ACK to host
6 K7 r% r  s4 X4 J$ b, K( x  SetBuffDescTable_TXCount(ENDP0, 0);
* W: v: a3 M; z' B. b. w6 k  SetEPR_RXStatus(ENDP0, EP_RX_NAK);
" x3 ~3 b1 ~6 _' k( |& o  SetEPR_TXStatus(ENDP0, EP_TX_VALID); 9 Z! o0 R4 C3 q7 e" }( a% j, a

/ D4 t' Z: w) z  return RESULT_SUCCESS;
! k& ^1 n- p. q! e' ~} " k1 d7 |. F8 t* k3 Z4 Z
如果wLength不为0,设备则需要根据请求的数据长度发送数据包以响应主机:
9 H: {8 E/ N0 D" y+ M// *****************************************************************************
3 M9 i& E  g5 }6 G0 n7 Z* t# u0 I// Function Name  : SETUP0_TransData
% p5 H. d5 ^0 p( x+ }0 ?// Description    :
2 r- P* r; \: K( ~. a% a5 o. G// Input          : 1 w) J  q8 w. O0 ?5 H  Q9 Z( G; C
// Output         : ' ?5 H) b6 v& _! a
// Return         : & k3 X7 d/ O& A4 l1 B! V
// ***************************************************************************** , y+ P3 W4 w5 _& k  i
RESULT SETUP0_TransData(void) / L, s8 n9 O1 Q; x4 W+ T4 G) V* }
{ * T! o4 y6 g( W  Z
  unsigned short wLength = vsDeviceInfo.TransInfo.wLength;
. V: G& [; |% V0 k7 N, t  unsigned short wOffset = vsDeviceInfo.TransInfo.wOffset; 6 L/ S% F% h" x% s8 j  K2 G
  unsigned short wMaxSize = vsDeviceInfo.TransInfo.wPacketSize;
6 U' V% [- R+ i  [. N' y! u
" {5 k, t- Z. @4 n" _4 O  if(wLength) / @) q: ?+ U, i9 D; X( u
  { 3 d  Z; J  b5 w
    if(wLength > wMaxSize) 1 F7 J+ `0 t$ X* D7 ]
    {
# R7 F7 N9 Y' f9 K  y' _      wLength = wMaxSize;      ( o( M. R5 `0 ]- N5 i  r
    } 3 S  s- q3 F0 J& F7 s) t
 
9 U0 E7 ~8 c0 U# c& t+ q8 Q    // Copy the transfer buffer to the endpoint0's buffer
8 N7 E! |- j3 x0 u; _    BufferCopy_UserToPMA( vsDeviceInfo.TransInfo.pBuffer+wOffset,   // transfer buffer & v8 W- Z8 c. i8 V
                          GetBuffDescTable_TXAddr(ENDP0),           // endpoint 0 TX address . W: Q$ o" N7 w0 Y7 J
                          wLength);
6 x& S, a0 Q7 t9 x$ q
; G4 l; ?" n/ s: l) q    SetBuffDescTable_TXCount(ENDP0, wLength); 0 I( |% S9 l' z+ |
    SetEPR_RXStatus(ENDP0, EP_RX_NAK); 2 h/ E: `9 Q: M' s. _
    SetEPR_TXStatus(ENDP0, EP_TX_VALID);
3 @$ m  A- ^- W4 w# n% t# \ 
7 {! x: [4 K; \. F! y7 o1 Q! w" }    // Update the data lengths
% Y! P5 t0 l0 J- ]( a    vsDeviceInfo.TransInfo.wLength -= wLength; " ^' }  d8 M8 Z6 _# y6 p6 t4 s2 X
    vsDeviceInfo.TransInfo.wOffset += wLength; 8 J  H+ d8 D9 `; b; x* d' n7 O
   
0 F8 e7 T5 B. c' D7 S    return RESULT_LASTDATA;         # z7 w7 B" u( R- R- w3 L' c
  } 1 e8 I4 _/ i* T7 [) R8 L+ _( d. M/ P" Z
- j2 ?, z4 U% Q: L3 {3 t( ]
  return RESULT_SUCCESS; . y$ [/ @. {0 @+ E) P* c0 C( {4 k& S
}
% }1 \, B3 d* O! {$ E如果发送的数据长度大于端点设置的最大数据包长度,数据将分割为若干次发送,记录发送数据的状态包含在结构体TRANSFER_INFO中:
2 }7 `  ~& k( ~" W( e/ H6 {// ***************************************************************************** 1 J+ ~) ^/ O* A6 P# t# H. j; m
// TRANSFER_INFO & n# a! M1 q, F# P" W/ _
// *****************************************************************************
* ?. ^% V; I7 |9 Z) I. Qtypedef struct _TRANSFER_INFO 9 K% h: R; d5 ~0 y
{ : h7 n+ a1 O9 k. T6 L/ u
  unsigned short wLength;                 // total lengths data will be transmit
9 X2 c+ R9 ~1 I, ]2 ], H" B# T  unsigned short wOffset;                 // number of data be transmited
) Q+ e) {- Z' e% s! m2 M  unsigned short wPacketSize;             // endpoints packet max size 0 _. H8 e7 n! Q
  unsigned char* pBuffer;                 // address of data buffer 8 q3 u' `+ g/ H( K# G( X
} % C* G& o. M, O/ T. }2 d3 X: u
TRANSFER_INFO,
& d1 }0 ~$ j0 Q*PTRANSFER_INFO;
2 }. s; R# f5 N( m5 L" \" CTRANSFER_INFO.wLength记录发送的数据长度,如果非0,表示有数据需要被发送。 7 h4 Q" c1 X. G% N& u, B, M
TRANSFER_INFO.wOffset记录已发送的数据长度,用以确定数据缓冲TRANSFER_INFO.pBuffer的偏移量。
, A# b. w* |) w! ]" ]4 {9 C4 A  ]8 T" u
需要了解的一点:USB主机向USB设备正确发送一请求后(这部分的处理由硬件完成),USB主机将间隔若干次的向USB设备索取响应数据,STM32 USB TX状态为NAK说明不响应USB主机,USB主机在超时后退出此次请求;TX状态为STLL说明中断此次请求,USB主机将无条件退出请求;TX状态为 VALID说明设备已准备好数据发送,USB主机将从USB设备读取数据。
6 [' y7 L$ P# d( j* D' l以非0长度数据请求的GET_DESCRIPTOR请求为例的响应过程:
# m& Z) f2 F8 tCTR_SETUP0()->SETUP0_Data()->SR_GetDescriptor()->SETUP0_TransData()
( Q  N9 |# p5 l9 P! x& r
7 t1 ?$ W4 U/ f9 Q% D) S$ s6 IRESULT SR_GetDescriptor(void)
, j5 A, k' N: `9 `7 h$ B4 B6 Z1 Y{
1 Q% R+ y; e4 J& ^" o: R" |  // RequestType: device->host, standard request and device recipient
9 p; n  }+ R; l! Z  d* ]  if(vsDeviceInfo.SetupData.bmRequestType == RT_D2H_STANDARD_DEVICE)
7 B# }7 q* O- d2 x& g: O: _3 e- b) A  { . A, n: w7 l& F9 ]* }7 z% Y, j3 v
    // SetupData.wValue.b.MSB: descriptor type 4 n5 F- \4 }0 Z9 j* a
    // SetupData.wValue.b.LSB: descriptor index
" N3 f8 o- D/ g$ O* H" Y# e    switch(vsDeviceInfo.SetupData.wValue.b.MSB)
% H2 j  U8 @6 t' O' A/ C    {
3 B3 z  |; x0 P' B4 G5 B8 W0 u    case DESCRIPTOR_DEVICE:               return SR_GetDescriptor_Device();
; K1 [! k9 |1 ^( Y% i6 k; H4 C    case DESCRIPTOR_CONFIG:               return SR_GetDescriptor_Config();
' M, C0 i9 _' z" {) A5 ^    case DESCRIPTOR_STRING:               return SR_GetDescriptor_String();
# g# ^& j0 ^6 V& R5 I( q, v- J& h, M; x- j6 H- \6 r: k6 R6 r
    default:  return RESULT_UNSUPPORT;
+ x  q$ p- M( z0 b# ?& R" }    } 5 L1 T: t) h) i# p" L9 {0 W
  }
; i/ T) S) e, O! H. c) W8 l) O) A$ _# s
  return RESULT_UNSUPPORT; 2 Z8 S3 h6 _0 N! L& m* @
}
: P/ u: B/ t  ?1 pGET_DESCRIPTOR请求属于USB协议中的标准请求(standard request)并且数据方向为设备至主机(device->host),分设备描述符、配置描述符、字符串描述符三种。已设备描述符为例: ' C* e/ h+ q6 p9 r- \' X
RESULT SR_GetDescriptor_Device(void) ! U' L; }4 n# v4 F
{
, g+ r) i( j4 u  v$ ?  // Assigned the device descriptor to the transfer 2 c/ ^) h  b5 l' Z5 v# O
  vsDeviceInfo.TransInfo.wOffset = 0; 8 _' I; T8 w% j1 a  ?
  vsDeviceInfo.TransInfo.wPacketSize = ENDP0_PACKETSIZE; 3 R1 U- I( v3 v: Y- b3 B# X5 t7 X
  vsDeviceInfo.TransInfo.pBuffer = DescBuffer_Device.pBuff; & {9 J1 T9 A7 y2 m# n+ l8 h1 @
  vsDeviceInfo.TransInfo.wLength = DescBuffer_Device.wLen;
$ J" r3 T0 r7 b/ Z& n' ]  vsDeviceInfo.eControlState = CS_GET_DESCRIPTOR;
, l) L  _8 v3 t0 L) y( z( x8 U' t4 c9 X
  if(vsDeviceInfo.TransInfo.wLength > vsDeviceInfo.SetupData.wLength.w) 9 X1 x1 y7 _, K4 u6 q# N6 Z
  { " O7 w6 {1 b8 L$ ^& }' l
    vsDeviceInfo.TransInfo.wLength = vsDeviceInfo.SetupData.wLength.w;
  e8 U( j0 g. l: M  } & Q" W- h- n6 `2 O6 T7 h" x

, e, X2 t; C; B( R9 U0 Q" A* f  return SETUP0_TransData();
: u# R5 G2 x; G* s# }} # p% H3 k2 l; d7 O! c( r/ j- F
这里说明了发送数据的长度、缓冲、偏移、端点包大小以及当前的控制状态,并说明了如果发送的数据长度超出请求的数据长度,则将舍弃超出的部分。数据配置好后,调用SETUP0_TransData()进行数据发送。 $ R( F% r3 ?- f% P# y
在USB主机查询到USB设备准备就绪后,将读取出这些数据,完成后,USB设备将产生IN事件,此时将响应CTR_IN0()函数:
& A5 E- P- t2 I& g/ n// *****************************************************************************
+ E) q$ Q- y$ f6 j# c  t; @  |- |2 }! K// Function Name  : CTR_IN , A# R; k; ]/ w+ N0 v) i
// Description    : % W* U& W$ L. Z- f) b. g
// Input          : " D& I( y' p6 W4 R6 s2 }6 l
// Output         : 8 K2 q3 H3 L% `) R3 D! ^3 i0 x& [' U% w
// Return         : 7 F/ b" x& G1 I; D- w
// *****************************************************************************
" w' o" }+ X# L! H2 cvoid CTR_IN0(void)
" C0 p. d! P, |" o1 {0 F# Y{
; z, H0 J$ f! T  V" f8 R, S  switch(vsDeviceInfo.eControlState) , m7 @/ a" h$ z) P6 v# i* J0 Y' S
  {
' n  K8 T3 L1 y4 l' L  case CS_GET_DESCRIPTOR:
! Y2 O0 C8 F* _    if(SETUP0_TransData() == RESULT_SUCCESS)
1 t2 f1 t  B9 g: D    { 1 [7 x$ i2 c1 u8 D/ J9 @, p% C
      SetEPR_TXStatus(ENDP0, EP_TX_NAK); 6 s# m2 l  z1 U" v$ v7 \5 n
      SetEPR_RXStatus(ENDP0, EP_RX_VALID); 8 Q0 `7 Z8 M9 t. _) z
    }   
. ^7 Z, w! v! D% L8 `    break; 5 x4 O7 v: W& u# ~
     
/ Y+ V- D* Y$ k  case CS_SET_ADDRESS: $ v% g3 j7 d6 r) I9 R
    SetEPR_TXStatus(ENDP0, EP_TX_NAK);
) F2 j3 ^. t2 n    SetEPR_RXStatus(ENDP0, EP_RX_VALID);
3 y1 E" |+ |5 Y3 K1 }# I/ r
' ], X' L, g/ r9 n1 j    SetDADDR(0x0080 | vsDeviceInfo.bDeviceAddress); " o; e$ d" u8 `" j6 ^+ t
    vsDeviceInfo.eDeviceState = DS_ADDRESSED;    + d* ~' p% U. V; Q$ S# B
    break;
# T+ Z8 j8 @/ e5 r  B8 B( W1 b5 L
) U5 M5 V0 k- W; o  case CS_SET_CONFIGURATION: * d7 j: m! x  y& ~& q+ U  c' d+ }  b
    SetEPR_TXStatus(ENDP0, EP_TX_NAK);
4 v+ `! ?# V" Z" _    SetEPR_RXStatus(ENDP0, EP_RX_VALID); 4 V3 V5 y( D8 d' Y$ q
% d( m8 B; k* m2 K; I' J
    vsDeviceInfo.eDeviceState = DS_CONFIGURED;
5 ^$ o% y4 b5 B# T( q; _    break;
5 F( n  E) C& M 
* l0 Q( |; {4 Z0 L/ a  default: 1 R8 o: |, {$ ^0 ?( B
    break;
+ A: n/ C" h$ y0 ]+ L) j$ q: {7 c2 A  } , ~8 g6 L' {! y, a6 \
}
% Q7 g& Y+ k, s再这如果响应GET_DESCRIPTOR请求发送的数据如果全部发送完毕,SETUP0_TransData()返回RESULT_SUCCESS,并设置TX状态为NAK;否则返回RESULT_LASTDATA,将继续发送剩余的数据直到数据全部被发送。至此,整个的GET_DESCRIPTOR请求过程完成。 : F2 L0 _; F/ w, Q- o" x+ y
0长度的数据请求在发送0长度数据响应后,因为不存在可能还未传送的数据,因而IN事件后直接结束此次请求。 % W7 \8 X! U  s
在数据方向为USB主机->USB设备时,如果正确接收到数据,将响应CTR_OUT0()函数,处理过程类同CTR_IN0()函数。
0 t- p# K" ~' L$ k  d* |在USB设备的枚举过程中,USB的一些描述符数据结构需要了解,具体在USB协议中有详细的说明,在usb_desc(.c/.h)文件中,定义了这些结构,这些结构是特定的:
, E( t3 l7 v' V: |( Y+ m+ [
, ~& N) r  o( f* q; f设备描述符:长度、格式固定,其中VENDOR_ID与PRODUCT_ID决定上位机驱动的识别。设备分属类别决定了设备的性质,如果为自定义USB设备,设备分属类别值为0,同时上位机驱动必须配合编写;如果为标准USB设备,则必须使用这些标准设备的驱动、数据结构等等,条件是你必须了解这些标准设备的一些信息,好处是省去一些麻烦的驱动编写。
2 {, y* r. }' p5 ?5 A4 s8 Rconst unsigned char cbDescriptor_Device[DESC_SIZE_DEVICE] =
/ n, v& s- o. r2 H4 R, B{ $ e# i7 Q  _  t# U% m% }
  DESC_SIZE_DEVICE,     // bLength: 18
( X# B' \+ m! [2 D  DESCRIPTOR_DEVICE,    // descriptor type $ \! D+ S- d  b* P9 e

8 l2 V* ^, r/ d( R! |  0x00,            // bcdUSB LSB: USB release number -> USB2.0
# w  j) \: A: b, I2 h  0x02,       // bcdUSB MSB: USB release number -> USB2.0
% h' `3 p" |1 F; V) {/ u  L
. ]8 v2 f/ }4 m/ r' X/ G  0x00,         // bDeviceClass:    Class information in the interface descriptors
6 V8 y4 U9 f7 n& ~- W  0x00,       // bDeviceSubClass:
$ J1 Z4 K; I. H* l; C6 W$ w& p  0x00,       // bDeviceProtocol:
& w& v! o1 m8 U: [) c& z3 ]  0x40,       // bMaxPacketSize0:  LowS(8), FullS(8,16,32,64), HighS(64) - o* }# P2 X8 l/ ]2 U; w
1 Z$ X. a9 \- d- v2 D; K6 I
  LOWORD(VENDOR_ID),       // idVendor LSB:   Z* q# `5 p# ~2 j
  HIWORD(VENDOR_ID),       // idVendor MSB:
8 s' T4 L; X8 M- @
6 i6 p9 y8 X3 e& W  LOWORD(PRODUCT_ID),      // idProduct LSB: 1 w' o: M8 R9 `: Y% b- L3 Q
  HIWORD(PRODUCT_ID),      // idProduct MSB: & |% p  _7 t0 P5 \4 Q0 O9 R7 @

- o! |( l# ~/ y9 Y; K/ H  LOWORD(DEVICE_VERSION),  // bcdDevice LSB:
  R/ j. \+ g$ j+ ]: Y  HIWORD(DEVICE_VERSION),  // bcdDevice MSB: & ?) K% e  S% Q6 J  ^

  D: h! D  y( n- D6 l0 z  0x01,       // iManufacturer: Index of string descriptor describing manufacturer
9 i: q  ?2 x7 S7 T+ M3 }# B  0x02,       // iProduct: Index of string descriptor describing product 9 A& D: h4 @$ b5 n- u/ g
  0x03,       // iSerialNumber: Index of string descriptor describing the device serial number 6 ^; z1 r+ J) h6 b. s( D( o7 w$ ^

. o! s; i( _( I$ B1 m  0x01        // bNumConfigurations: number of configurations $ E: @  q, {. x; Z( f: j: L
}; # O+ m/ Y6 g. M  \. m) X1 [- W
) L+ L8 D. y' S
配置描述符:前9个字节格式固定,后面紧跟的各种描述结构跟实际配置有关,每增加一种描述结构,该描述结构的第一字节说明了结构的长度,第二直接说明了结构的类型。在配置描述符中一般包含配置描述、接口描述、端点描述,如果需要同样可增加自定义的描述。使用标准USB设备类别时,配置描述符的结构也必须满足此类标准设备的数据结构。   Y& Q! N' c+ U. F% |9 T( h
const unsigned char cbDescriptor_Config[DESC_SIZE_CONFIG] =
; ]6 ?7 Y, A% Y! C( {$ k0 g! J{ 2 ?* p2 j7 R; k+ @
  // Descriptor of configuration , J) s7 c9 ?5 P5 O
  0x09,                   // lengths   
. V5 Q! A1 D# h  DESCRIPTOR_CONFIG,      // descriptor type 8 z5 B; l) n( z. A  ]' D
) _  T: b: v" o8 f+ F
  DESC_SIZE_CONFIG,       // Total configuration descriptor lengths LSB
  v( F7 ~7 s+ ]+ Y, b( f8 ^  0x00,                   // Total configuration descriptor lengths MSB ; a& G/ p- n  B3 A# U% R" m6 Z2 E  S/ p; G
! _8 Y" V, O4 H) ?" Q
  0x01,       // bNumInterfaces: Total number of interfaces 4 z' Z9 t& ~( Q: z, |
  0x01,       // bConfigurationValue: Configuration value 6 r, v& w# k; S7 u- e5 D4 H. t
  0x00,       // iConfiguration: Index of string descriptor describing the configuration ( K, G1 a( ?9 X4 I  ~) U# n- ^
 
7 k" u$ F$ b. X  0xA0,       // bmAttributes: bus powered
8 ~0 N, G5 Y! h9 v$ h1 f                        // bit 4...0 : Reserved, set to 0 ! h$ q* P) X/ P3 p$ X9 _
                        // bit 5     : Remote wakeup (1:yes) : h8 W. \3 ?* d# v) \3 D0 z
                        // bit 6     : Self power (1:yes) 7 H+ q2 H: E$ i; A
                        // bit 7     : Reserved, set to 1
' ?$ X  o1 X3 ?
5 ^. P6 ?8 ]: k4 ~5 \$ E3 x4 n  0x32,       // bMaxPower: this current is used for detecting Vbus = 100mA
; ?3 I$ x1 t  i
4 w# B. j" E/ ]. e- M6 J' L/ F5 K3 n
  // Descriptor of interface
& i( b0 v8 Z, c  0x09,
0 j0 y; J8 Z8 K% w. l3 H1 K) N8 U, K: L  DESCRIPTOR_INTERFACE,
: E- q1 _. r2 g* J
/ i% a1 ]8 P$ |; Y$ j9 A  0x00,       // bInterfaceNumber: Number of Interface ' e7 N# E0 \2 A; K2 r9 F" P9 [9 o
  0x00,       // bAlternateSetting: Alternate setting $ U. N4 J# T% b4 L/ Q- e
7 l, I" X( ]( Z& j
  0x02,       // bNumEndpoints: Number of endpoints except EP0
+ R- y5 J( J. E0 v- L7 G% |" A; v  0x00,       // bInterfaceClass: " @% p/ T/ `; U0 I
  0x00,       // bInterfaceSubClass: 6 Z5 Z  k8 h; q
  0x00,       // nInterfaceProtocol: & P) t- k8 d8 z$ g. D" T

. m$ v( I1 `3 |! ]8 V  0x00,       // iInterface: Index of string descriptor describing the interface
% e* T* M: K: l% ], j! \% y6 p3 P9 Q# ~( t1 {

" }# P  r/ f, E, Y9 g; @& J& f  // Descriptor of endpoint1 OUT 3 M7 g4 z- v7 Q1 ]
  0x07,
9 x0 F! r4 ?! F  DESCRIPTOR_ENDPOINT, 9 j; |  r9 U" r
4 T7 c& h  Z- Z: q; e: ~6 U( z
  0x01,       // bEndpointAddress + V0 e* f. z, v" K# c' D
              // bit 3...0 : the endpoint number
! X6 g1 z$ Q2 R' `! }              // bit 6...4 : reserved
; y7 H& _$ f% J, p. |              // bit 7     : 0(OUT), 1(IN)
# [0 [4 w2 Q8 q3 R% g( [/ r
, ~/ ]8 T8 j6 c5 F$ L; }$ x8 P0 U  0x03,       // bmAttributes
2 X$ T5 T" C2 y- z              // bit 1...0 : Transfer type
  k% s- B7 i7 k( K1 b: y              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT)
1 e9 R* O$ r- _              // bit 3...2 : Synchronization type
% V6 M' F+ U9 N              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous)
! d5 r+ a! L: P: E" I              // bit 5...4 : Endpoint Usage type 0 S1 K; f3 P) B8 `7 R1 |
              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved)
1 e' H! ]8 f. R# l- l4 W              // bit 7...6 : Reserved, must be zero ! T: j4 q& K9 ]
4 w) U& P1 k8 |: c% E, d8 e
  0x40,       // packet size LSB 9 a$ _" j: e! ^7 P& r4 `
  0x00,       // packet size MSB
* W, ^$ W+ P) G2 a' L6 x  N0 w5 W" p# w" N
  0x20,        // polling interval time: 32ms
) }' P9 v$ _& n8 P- y& Y/ R
9 I% {' {0 ?# S) Y) o  ]  // Descriptor of endpoint2 IN . T3 Z: j/ S/ _
  0x07, : L. W. F/ s0 r, L6 Z  a' V2 u
  DESCRIPTOR_ENDPOINT,
8 Z) \, [( h6 @
7 b' R. ]3 T& t; I  0x82,       // bEndpointAddress
+ i3 k4 x7 i; |% ]% K              // bit 3...0 : the endpoint number
3 Z. a% R) _" S, L1 |: P4 j! d( D              // bit 6...4 : reserved 7 D( Y4 N# @0 ]& C9 G% s( m) h
              // bit 7     : 0(OUT), 1(IN) % U8 Y( Y' N, I: }8 Z- \

3 Q4 y  z7 I4 ^  0x03,       // bmAttributes
* U* {* [# |) R  P              // bit 1...0 : Transfer type 5 k& |9 ~9 w, L' g9 J* O% i
              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT)
! Q6 G2 T* u& c6 U& F+ B& L; R              // bit 3...2 : Synchronization type 0 [, z/ m! I9 m7 N
              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous) : P1 d$ D5 h6 h: y/ {% U
              // bit 5...4 : Endpoint Usage type
2 F  ^) a6 d4 R+ Q8 N- |6 z' x              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved) + C2 y- P8 i& n/ ^; }2 X
              // bit 7...6 : Reserved, must be zero
+ h% B- u/ w8 [5 Q* W5 f. M7 B
% J4 L: h. b3 n' a& L' ^# l, S0 ?  0x40,       // packet size LSB ' N2 r, K! ~( ^
  0x00,       // packet size MSB ' c* S4 o7 P5 K. y  x. J

0 c5 s8 [6 p# V4 |9 h  0x20        // polling interval time: 32ms
. e, M) d" w+ R8 \* G% p& p( h$ A4 K7 k}; 1 }  B3 C; x( h# C) J7 l

8 w6 \+ T% S. P/ z  t字符串描述符:定义了与设备有关的一些信息,常见的为以下四种,如果有需要,同样可以定义自己的字符串描述符。
# E- L7 ^7 \0 z; lconst unsigned char cbDescriptor_StringLangID[DESC_SIZE_STRING_LANGID] = 2 Z+ z, B4 i& x1 Z
{
4 ]& a. M& d% b6 L) a7 j  DESC_SIZE_STRING_LANGID,  // bLength $ o2 Z1 q3 t! e7 @! G  ^- v6 Y8 u# F
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor - y7 P; K8 y; F0 S4 A3 ?! ~; w0 @
   
5 J3 ]& A6 i: V4 n# u  X. K2 J; m% A  0x09,                                  // LangID LSB:
! X# i! d; U4 j' w  0x04                                  // LangID MSB: 0x0409(U.S. English) - C% K+ c; Q% r
}; & m" H* ~+ s: `9 V! X

2 [( s, n; M: J+ n' g7 {const unsigned char cbDescriptor_StringVendor[DESC_SIZE_STRING_VENDOR] = ! G( X& O4 I1 x5 W# a
{
3 o$ Q) a1 M8 y  DESC_SIZE_STRING_VENDOR,  // bLength   R' W0 |+ Q9 s; r
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
- f6 o5 o. q6 `! Y. s
% I+ o; L. e& ?* K- P0 e% a, n  // String: "LaBiXiaoXiaoXin" - m# {+ _9 p. S, w& L0 g
  'L',0, 'a',0, 'B',0, 'i',0, 'X',0, 'i',0, 'a',0, 'o',0, - x+ `& N9 w" D& k9 z$ Q
   'X',0, 'i',0, 'a',0, 'o',0, 'X',0, 'i',0, 'n',0
" i5 H3 s8 _% k: V+ P8 W6 ^& r}; + V, c' |1 ~: n- J

( F- ]  C) n. @  H" w* G* Kconst unsigned char cbDescriptor_StringProduct[DESC_SIZE_STRING_PRODUCT] =
, q/ z9 t: U* V# K6 |{
6 |' v  Y8 O' C* u+ {9 U  DESC_SIZE_STRING_PRODUCT, // bLength   A' c6 C3 H( F* k# r
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor 4 o) S- l" X# p4 U; [+ T  R# C
. S5 D4 v% A. t2 O( v
    // String: "STM32 ezUSB-CORE V1.01"
# C2 v+ n, W: U9 \6 B7 m  'S',0, 'T',0, 'M',0, '3',0, '2',0, ' ',0, 'e',0, 'z',0, 'U',0, 'S',0, 'B',0,
* L+ O( Z3 N. J5 e  '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0, 'V',0, '1',0, '.',0, '0',0, '1',0
- U8 y& L, N8 l" I$ t( v+ w( Z}; 1 \( E+ r8 u9 e0 o
* l9 B( [" ~! K1 T# k0 T
const unsigned char cbDescriptor_StringSerial[DESC_SIZE_STRING_SERIAL] = ; }" K4 j3 |3 b/ o! C/ q2 M. o, }
{ ( d( o) l+ G5 k9 C& c9 I' [6 V  @
  DESC_SIZE_STRING_SERIAL,  // bLength # q; A3 H7 |2 o' }! C# w
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor 4 u) J# P- y: [9 e( W3 R

! O* x/ j9 A0 \    // String: "ezUSB-CORE Demo 2008/11/18"
$ i' `/ e# I) B! z9 ]: }: A  'e',0, 'z',0, 'U',0, 'S',0, 'B',0, '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0, / {- g/ @- H3 s; o( L% ?
  'D',0, 'e',0, 'm',0, 'o',0, ' ',0, '2',0, '0',0, '0',0, '8',0, '/',0, '1',0, '1',0, '/',0, '1',0, '8',0 ( Y& Z/ X4 i( X) C$ n, u
};
) p3 P0 T% Q$ V3 z% p; I  V4 Y
' l1 o9 k( f2 Y) O6 K了解这些描述符的用法以及作用,最好的方法的是编写自定义的USB上位机驱动以及应用程序,这样你可以深刻了解USB设备与主机间的数据交换方式以及实现手段,下篇将开始介绍USB上位机驱动以及应用程序的编写以及开发环境的建立,STM32 USB设备的固件程序如有什么疑问,请朋友们多花几分种时间留言、讨论,共同学习与进步。
收藏 评论3 发布时间:2008-12-23 13:47

举报

3个回答
圣手008 回答时间:2012-10-30 20:21:23

回复:基于STM32的USB程序开发笔记(五) ——USB设备的枚举(下)

找不到设备啊
lin1620c 回答时间:2012-11-12 23:51:57

RE:基于STM32的USB程序开发笔记(五) ——USB设备的枚举(下)

谢谢!!!!!非常谢谢
123-370895 回答时间:2013-12-18 11:34:50

RE:基于STM32的USB程序开发笔记(五) ——USB设备的枚举(下)

强烈支持

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版