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

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

[复制链接]
乡村布拉德 发布时间:2008-12-23 13:47
SETUP事件正确接收后,根据该事件提供的请求类型进行对主机的响应。SETUP数据结构的wLength字段说明的是请求返回或者提供的数据长度。 8 ?6 H' J7 w+ r0 r* n3 ^5 R
如果判断出的请求信息错误或者说不被支持,STM32 USB设备需要中断此次请求:   Y! K, v9 a$ x1 z
    SetEPR_RXStatus(ENDP0, EP_RX_VALID);
0 |7 m/ s! T5 v% g+ f( L    SetEPR_TXStatus(ENDP0, EP_TX_STALL);
4 r7 h) R) g' \% u; q5 G, r% S8 i7 ~+ E
正确获取到请求信息后,如果wLength为0,设备需要发送一个0长度数据包以响应主机: * X3 o7 ^6 I! q5 F8 q: G
// *****************************************************************************   P8 q& Z3 d. [" Z# e9 z- T
// Function Name  : SETUP0_Trans0Data ! P3 W' t0 \; J3 y( G: }
// Description    :
  n. p2 A1 _/ ~9 m  H* h// Input          :   Q0 F+ T; Z& W4 V
// Output         :
! J8 \0 P1 r3 n1 `! d9 w// Return         : 4 y: a" t1 I9 w* R
// ***************************************************************************** ( n4 z6 a1 r; D$ u4 E( d
RESULT SETUP0_Trans0Data(void)
+ }. ^6 p" g7 Q. C5 s{ $ x; a( R: S! q; V8 _% c+ S% d
  // Send 0-length data frame as ACK to host 8 b* l3 m; P# H, S1 t& _; R$ _- g
  SetBuffDescTable_TXCount(ENDP0, 0);
- D  B. W. h2 X: y/ ?! ^# \# E  i  SetEPR_RXStatus(ENDP0, EP_RX_NAK); 8 V1 a6 q8 Q6 T  [: ]6 g9 w
  SetEPR_TXStatus(ENDP0, EP_TX_VALID); 9 A& Y, Y7 C/ C$ z! X" }

  u$ |! n/ f2 A4 r" Y+ k% S  return RESULT_SUCCESS; : Q5 I" M1 G: w& @; G# \+ j4 _
} " d7 f) Q: a$ |
如果wLength不为0,设备则需要根据请求的数据长度发送数据包以响应主机: 9 [( o1 I4 C* i. ~# R
// *****************************************************************************
( U* [5 d2 |5 P2 u  H7 K+ q- W% p// Function Name  : SETUP0_TransData
8 O# ^: o, {, a// Description    :
6 h  i/ R! y% A# k7 A$ B$ a// Input          :
/ o; L0 u8 }+ c/ ?// Output         :
, e0 k! t" O. J// Return         :
- e/ ^  Y, N, @* a) i0 @5 c// *****************************************************************************
4 W+ I' U% F7 V+ _RESULT SETUP0_TransData(void)
+ T" ]1 g- j  A  D1 I, D{ 0 M. u& A7 W, F  V) \
  unsigned short wLength = vsDeviceInfo.TransInfo.wLength;
" E: c9 i9 k8 k( w  unsigned short wOffset = vsDeviceInfo.TransInfo.wOffset;
$ u4 U( p! s/ v! ^3 L) Z# _0 i  unsigned short wMaxSize = vsDeviceInfo.TransInfo.wPacketSize;
0 i. d) T1 e+ B. W( O" P' s' {# J: S, F$ [7 }
  if(wLength) 6 a' d2 P' M3 n5 C0 m
  {
$ E  u2 z- X. N+ O4 _# N0 O1 k9 r    if(wLength > wMaxSize) + b& f4 F! R( ^! z; ?" C
    { 4 I, l7 ]+ A; H9 I4 v  s2 u3 X
      wLength = wMaxSize;      ! z, q" ^+ I: Y
    }
, w; v2 q4 c3 u6 A 
7 X4 f, f8 n+ B$ s+ C" H- L- C5 y' v    // Copy the transfer buffer to the endpoint0's buffer
; W2 \, y% ~* d7 }3 a    BufferCopy_UserToPMA( vsDeviceInfo.TransInfo.pBuffer+wOffset,   // transfer buffer # p5 m" t7 Y9 I& b; Z1 b' W
                          GetBuffDescTable_TXAddr(ENDP0),           // endpoint 0 TX address
' T4 {3 J- i) Z  \# l3 E5 z: G5 f                          wLength); 7 V7 J" k, i! v/ `& E/ t; J
: @! l; y- n- B2 k
    SetBuffDescTable_TXCount(ENDP0, wLength); + L: ^$ q* C4 V# ?# O( h, t
    SetEPR_RXStatus(ENDP0, EP_RX_NAK);
, R* L9 p: H, F2 i) {+ D' r* H, w4 o    SetEPR_TXStatus(ENDP0, EP_TX_VALID);
& f- B. a& H, L 
! |% N$ l2 r+ h    // Update the data lengths
) k* f3 I8 z7 j5 C' K) \    vsDeviceInfo.TransInfo.wLength -= wLength;
) ^& f( |5 s/ W. D: {+ |    vsDeviceInfo.TransInfo.wOffset += wLength; ( U% o6 J7 t6 y4 T. ~
   
+ I1 z  C$ l. t: W# A. V    return RESULT_LASTDATA;        
$ }" y( M1 w/ r% w' r9 J  }
9 U' y0 S4 F. @  J( ]
# b3 [% V% J! @# a% ?  m  return RESULT_SUCCESS; 4 W8 z  F9 j. l) c6 o
} ! H! w0 e6 Z! h4 f6 A* B
如果发送的数据长度大于端点设置的最大数据包长度,数据将分割为若干次发送,记录发送数据的状态包含在结构体TRANSFER_INFO中: 3 F- u! L- G1 L8 j( z
// ***************************************************************************** 9 B, r# U. i6 k' D& Z" K6 ~+ c0 W- ~
// TRANSFER_INFO
. U' a1 c' ?6 R$ z0 a8 D/ R// ***************************************************************************** 1 `' G1 \' P1 y% ]
typedef struct _TRANSFER_INFO 6 e) G5 O0 Z% o3 i3 n% X
{ 8 s2 k+ l9 d1 R
  unsigned short wLength;                 // total lengths data will be transmit
5 `# d; ]1 r# |. @* C8 f) O3 [  unsigned short wOffset;                 // number of data be transmited
" Z( S2 W7 w. I) ]0 `+ i  unsigned short wPacketSize;             // endpoints packet max size
) B' y* ~& k' G+ c  O2 p; a% S  unsigned char* pBuffer;                 // address of data buffer . M' l+ q& }: k: w; R3 V
}
) `7 D4 z, `( \) _. e) M3 d2 cTRANSFER_INFO, . y: k! A+ d  J
*PTRANSFER_INFO; 0 z3 X& G; J& s# A. @' m1 l, x8 t& z
TRANSFER_INFO.wLength记录发送的数据长度,如果非0,表示有数据需要被发送。
0 y. n1 b1 O! @' ]# V# O' n4 Q) p2 _2 TTRANSFER_INFO.wOffset记录已发送的数据长度,用以确定数据缓冲TRANSFER_INFO.pBuffer的偏移量。 $ f* B4 o# I  d) e  L$ U7 T( @

. @5 p" n& Q8 Q" Y' S. r- Y- \需要了解的一点:USB主机向USB设备正确发送一请求后(这部分的处理由硬件完成),USB主机将间隔若干次的向USB设备索取响应数据,STM32 USB TX状态为NAK说明不响应USB主机,USB主机在超时后退出此次请求;TX状态为STLL说明中断此次请求,USB主机将无条件退出请求;TX状态为 VALID说明设备已准备好数据发送,USB主机将从USB设备读取数据。 7 j1 h: y7 [7 E" i3 ^
以非0长度数据请求的GET_DESCRIPTOR请求为例的响应过程: 2 D6 V4 s3 s& @& M. ^+ K0 Z
CTR_SETUP0()->SETUP0_Data()->SR_GetDescriptor()->SETUP0_TransData()
8 {( |9 M) B' [
9 G. O$ Y# T, O3 k1 U! @RESULT SR_GetDescriptor(void)
: W' W" s4 F: C/ C{ + j/ Y$ f2 [5 x" K
  // RequestType: device->host, standard request and device recipient & d/ x+ A" o5 Y7 C' |! h' Z7 e
  if(vsDeviceInfo.SetupData.bmRequestType == RT_D2H_STANDARD_DEVICE)
. N3 W+ q* x- R% I  { ! ?- A6 X  D9 P0 O$ P
    // SetupData.wValue.b.MSB: descriptor type - {" m+ |7 q% m6 a1 h, w; c* v
    // SetupData.wValue.b.LSB: descriptor index
1 F) A; K5 b8 E    switch(vsDeviceInfo.SetupData.wValue.b.MSB)
& R2 F% p+ E+ P    { 8 V4 o" v! ?. V3 k4 F
    case DESCRIPTOR_DEVICE:               return SR_GetDescriptor_Device(); 3 w& i: ~5 g% J- ?% l0 C  O4 P, s
    case DESCRIPTOR_CONFIG:               return SR_GetDescriptor_Config(); % k6 m3 p% Z3 l! V% t# s( V- T
    case DESCRIPTOR_STRING:               return SR_GetDescriptor_String();
4 a: R# [; o( o7 V0 _8 D; p: A6 `' C* o, t
    default:  return RESULT_UNSUPPORT; 0 \" d% {  |7 Y
    }
$ v. i' K, l9 H" w) I9 B  } 4 a0 q) ]( c, R0 i' |) q! G
# Y% h3 d5 ~: b( ?
  return RESULT_UNSUPPORT;
8 q! i) k) o* c  v2 \}
! Z) l1 I3 @6 w; _6 dGET_DESCRIPTOR请求属于USB协议中的标准请求(standard request)并且数据方向为设备至主机(device->host),分设备描述符、配置描述符、字符串描述符三种。已设备描述符为例:
; j; u" N) L& p% g. }RESULT SR_GetDescriptor_Device(void) 3 h7 j5 M3 d0 L2 {/ b' o' `
{ , B3 E8 z/ J& g# p9 m% m0 V" }' [
  // Assigned the device descriptor to the transfer
" s) E1 k/ c; |  f. F. v  vsDeviceInfo.TransInfo.wOffset = 0; $ C* T2 Q0 Z% Z1 S) t8 N4 L
  vsDeviceInfo.TransInfo.wPacketSize = ENDP0_PACKETSIZE; 3 F/ o$ H4 n" I/ G1 X9 ~& r
  vsDeviceInfo.TransInfo.pBuffer = DescBuffer_Device.pBuff;
0 E6 g4 {1 a* F/ f' J  vsDeviceInfo.TransInfo.wLength = DescBuffer_Device.wLen; - q3 a% q2 A5 W/ k8 }7 s
  vsDeviceInfo.eControlState = CS_GET_DESCRIPTOR;
3 `5 V( `1 R( v$ W1 l% u
+ F$ `* s8 F6 J  if(vsDeviceInfo.TransInfo.wLength > vsDeviceInfo.SetupData.wLength.w) 6 ]5 m/ ]* T- S1 i1 L$ R
  { 4 l; N* z; f: W- b6 e' I
    vsDeviceInfo.TransInfo.wLength = vsDeviceInfo.SetupData.wLength.w;
9 F8 D  K5 b# U& l5 r) J4 j  } % C& B, T3 B! x: d

  k, A* ^4 d9 j$ U1 R3 o' L5 w% }  return SETUP0_TransData(); ; H3 M! X+ \  `4 F7 Z3 c. D
}
0 `6 D1 m' {9 H$ Z这里说明了发送数据的长度、缓冲、偏移、端点包大小以及当前的控制状态,并说明了如果发送的数据长度超出请求的数据长度,则将舍弃超出的部分。数据配置好后,调用SETUP0_TransData()进行数据发送。 $ q. E; r: O9 g5 a& W( O
在USB主机查询到USB设备准备就绪后,将读取出这些数据,完成后,USB设备将产生IN事件,此时将响应CTR_IN0()函数:
0 N: a; j; P/ J8 ~// *****************************************************************************
$ X6 g& g/ l4 \0 w' K( @// Function Name  : CTR_IN
' B  Q; z0 s$ x// Description    :
; y' V) @/ l9 G$ [  V// Input          :
. A8 _9 ~6 o1 o# q  ]. _  R. q( G, \// Output         : 9 _- y. ]' e7 [+ U" G
// Return         :
8 W# x7 @- C: ]2 `6 [// *****************************************************************************   `" I) d8 F+ A# K; U  [! T
void CTR_IN0(void) " |9 h, I1 c- h. p: ~0 S* ]
{ 8 R/ A; O* j$ @" L4 m+ t& B) R
  switch(vsDeviceInfo.eControlState) % k0 I& m# c- @- @$ ~
  {
. C0 D4 i9 L* b9 P' J* D. X* h, ?& E  case CS_GET_DESCRIPTOR: 8 i, L) T5 U. {2 A" h
    if(SETUP0_TransData() == RESULT_SUCCESS)
6 _5 U4 n0 q1 a$ F' H    {   b0 _' H4 k6 U6 R: M4 D8 f
      SetEPR_TXStatus(ENDP0, EP_TX_NAK); 2 u& c6 Q5 K# h- ]/ F8 K
      SetEPR_RXStatus(ENDP0, EP_RX_VALID); ; N% t/ i& _* i+ |; R
    }   
" }( b, G& T" {) ~1 a    break;
% C, l* p- H+ I     
; ~8 u/ L$ \( R4 }9 {, B  case CS_SET_ADDRESS: ; n& j1 }8 G2 P: g' Y* z8 o# ~
    SetEPR_TXStatus(ENDP0, EP_TX_NAK);
2 ]  l% M* B; c6 D- m- Z% f5 s    SetEPR_RXStatus(ENDP0, EP_RX_VALID); ! x; _7 m) |7 G/ N$ L5 c2 d
' p1 j+ _2 b* K- e- \
    SetDADDR(0x0080 | vsDeviceInfo.bDeviceAddress);
9 ~9 T4 U6 i# D9 n+ A    vsDeviceInfo.eDeviceState = DS_ADDRESSED;    9 J4 c" {: V) l3 B% r
    break;
" M+ R- E( \3 s  d: ~- m4 v3 c4 a
  case CS_SET_CONFIGURATION: 0 x  Z: K  c2 k5 J' u0 P$ R
    SetEPR_TXStatus(ENDP0, EP_TX_NAK); 6 z6 U9 g6 l% r9 J8 t
    SetEPR_RXStatus(ENDP0, EP_RX_VALID);
0 C! c2 ^% @# {' x( V/ J0 m
4 Y1 y9 r8 _) f    vsDeviceInfo.eDeviceState = DS_CONFIGURED;
# R' y* r4 G0 h9 k- o; Q    break;
: k$ i6 U8 a( H; W  2 N+ W5 _3 {7 c# L
  default:
3 J+ S8 L1 E" x+ g0 z    break; , L0 v. z; g* C$ q
  } % [1 G; j: [7 v3 n6 n, Q
} , r5 D. o1 c, l# x! v
再这如果响应GET_DESCRIPTOR请求发送的数据如果全部发送完毕,SETUP0_TransData()返回RESULT_SUCCESS,并设置TX状态为NAK;否则返回RESULT_LASTDATA,将继续发送剩余的数据直到数据全部被发送。至此,整个的GET_DESCRIPTOR请求过程完成。 ' _) i( s$ O  t/ L' m' s
0长度的数据请求在发送0长度数据响应后,因为不存在可能还未传送的数据,因而IN事件后直接结束此次请求。   M7 q$ V1 n0 q: c" U! p5 }
在数据方向为USB主机->USB设备时,如果正确接收到数据,将响应CTR_OUT0()函数,处理过程类同CTR_IN0()函数。
& [3 P6 K6 \# @% B8 n" G在USB设备的枚举过程中,USB的一些描述符数据结构需要了解,具体在USB协议中有详细的说明,在usb_desc(.c/.h)文件中,定义了这些结构,这些结构是特定的:
3 j: g" E% P' j) x# K7 W0 R1 T: N8 {
* t; w# }: @9 k) w( P设备描述符:长度、格式固定,其中VENDOR_ID与PRODUCT_ID决定上位机驱动的识别。设备分属类别决定了设备的性质,如果为自定义USB设备,设备分属类别值为0,同时上位机驱动必须配合编写;如果为标准USB设备,则必须使用这些标准设备的驱动、数据结构等等,条件是你必须了解这些标准设备的一些信息,好处是省去一些麻烦的驱动编写。
& D+ x, L. J* Q' u( gconst unsigned char cbDescriptor_Device[DESC_SIZE_DEVICE] =   W3 `: ]( p7 F  R. J# n
{
9 F8 Y- w( M# r7 t$ x/ S2 J) _0 P  DESC_SIZE_DEVICE,     // bLength: 18
' q, ~- @8 s, ]. H7 z* G2 B* a: i! d  DESCRIPTOR_DEVICE,    // descriptor type ; ]% D6 `& J3 c8 Q( G
' O) M+ E* O' o, G8 a
  0x00,            // bcdUSB LSB: USB release number -> USB2.0
# Z# A1 o8 {4 M/ C# H( k  0x02,       // bcdUSB MSB: USB release number -> USB2.0   ]) g# L3 g- |1 }' b! D  x
) I9 Q+ S: G% B( U, l' C4 N0 g- Y
  0x00,         // bDeviceClass:    Class information in the interface descriptors ) ~# m2 q8 e$ n/ C9 Z0 W6 F
  0x00,       // bDeviceSubClass: 0 }" f- r6 i7 C3 j
  0x00,       // bDeviceProtocol: 1 b. B0 U  j! P5 G
  0x40,       // bMaxPacketSize0:  LowS(8), FullS(8,16,32,64), HighS(64) ) K" @& a- D6 N2 |6 \
" x' J( F: A% f: g# [% q
  LOWORD(VENDOR_ID),       // idVendor LSB:
: K( b1 o7 P9 w+ o( V. v5 h+ p  HIWORD(VENDOR_ID),       // idVendor MSB:
" ?$ H  q4 ?7 B9 T0 ]5 F8 ~/ ^# h+ v6 I! c: T
  LOWORD(PRODUCT_ID),      // idProduct LSB:
0 v! R& z* x% b, `3 _' n2 z  HIWORD(PRODUCT_ID),      // idProduct MSB:
. Q% W5 J: E# b: p
1 `# U) M5 l7 b. a$ P( q  LOWORD(DEVICE_VERSION),  // bcdDevice LSB:
0 T4 A1 v, @- w( V% l  HIWORD(DEVICE_VERSION),  // bcdDevice MSB:
7 c1 V' N+ D: @+ Z9 Q, Z# |4 U4 f% v% U- R, x4 T. f
  0x01,       // iManufacturer: Index of string descriptor describing manufacturer
3 t0 ]+ c' H. T& r- H$ J  0x02,       // iProduct: Index of string descriptor describing product
7 D4 Y  _! o3 @5 O. k6 K- K: o  0x03,       // iSerialNumber: Index of string descriptor describing the device serial number 4 u& x8 F4 H% W) ~, D

2 T. O- p6 L4 [$ M/ g  0x01        // bNumConfigurations: number of configurations
0 w! {( s9 \2 o' n) i. O' V8 b5 H}; + Q) G: G( F$ Q( n: s
8 y  |* |$ L* l/ E
配置描述符:前9个字节格式固定,后面紧跟的各种描述结构跟实际配置有关,每增加一种描述结构,该描述结构的第一字节说明了结构的长度,第二直接说明了结构的类型。在配置描述符中一般包含配置描述、接口描述、端点描述,如果需要同样可增加自定义的描述。使用标准USB设备类别时,配置描述符的结构也必须满足此类标准设备的数据结构。
2 t5 }  O+ A; s  Lconst unsigned char cbDescriptor_Config[DESC_SIZE_CONFIG] = 0 S. v  B8 [- ^7 r6 F. l
{ , y2 ^: e; \0 T
  // Descriptor of configuration
0 c: k& j! K* L% S  0x09,                   // lengths    # V3 o0 i4 d4 G+ g" y
  DESCRIPTOR_CONFIG,      // descriptor type 3 j  A  d. x& G( U; _

! G6 X2 v, Z) d; Q& _. K- @- B  DESC_SIZE_CONFIG,       // Total configuration descriptor lengths LSB - d$ p; n; n) o, s1 p
  0x00,                   // Total configuration descriptor lengths MSB ! U( z0 H, p: `1 d  S9 M6 t
5 @5 t, y0 a3 E1 r# S3 `3 k/ W
  0x01,       // bNumInterfaces: Total number of interfaces
- L  T/ V8 G3 z4 `* E) K( v) `  0x01,       // bConfigurationValue: Configuration value
# E  A; P2 ^1 a. {9 c& {  0x00,       // iConfiguration: Index of string descriptor describing the configuration   P7 Y0 f  o" [5 ^6 b$ Q
 
' y( ?' _2 o5 }2 {  0xA0,       // bmAttributes: bus powered
  ]0 F( m, l# o, i3 J3 |: x                        // bit 4...0 : Reserved, set to 0 0 g; U& A. |9 l* o  s
                        // bit 5     : Remote wakeup (1:yes) ) G1 v4 `* E3 D9 Z9 s# s. S
                        // bit 6     : Self power (1:yes) " ^0 `5 M' x" y+ z$ X6 I, `+ ?
                        // bit 7     : Reserved, set to 1
" K" v2 b; G5 b6 |7 ^" p4 ?8 w
' O. O) i- P2 {5 j9 X  0x32,       // bMaxPower: this current is used for detecting Vbus = 100mA 6 T* X1 C+ b1 I# c
) W% \* Z; k6 Y' b& }
8 l( r  H. Q/ |9 ^
  // Descriptor of interface
  D% m* D+ S8 x2 @6 w  0x09,
, Q+ U) X, U9 V* V. U7 h  DESCRIPTOR_INTERFACE,
& ~3 j4 y0 o% U
1 d9 Y- {: v4 w8 Z  0x00,       // bInterfaceNumber: Number of Interface
1 i6 O1 t+ J( E; I8 }) U& b( {  0x00,       // bAlternateSetting: Alternate setting
! C5 z* e. F" T" c2 a! L8 ~
( R( q+ D# O1 ^/ i) n3 K1 E  0x02,       // bNumEndpoints: Number of endpoints except EP0
" E5 S* X4 j, K& y4 _  0x00,       // bInterfaceClass: # l3 x% z! b' C% s9 R
  0x00,       // bInterfaceSubClass:
( g, ]- G! }# r$ s  0x00,       // nInterfaceProtocol: 8 v/ S# y3 |' f) V6 N% N

% X( q, ~0 @8 q/ _# l4 S  0x00,       // iInterface: Index of string descriptor describing the interface 2 d' B7 T5 ]) l! Z3 \  `! V- z* z

+ A. f  }" p0 K2 R' U- Y$ f4 _+ ]$ o* W9 Q) j- f
  // Descriptor of endpoint1 OUT 9 |# G  ?; s2 \0 H# q5 j+ l
  0x07, $ a5 i' ?. R9 Q) e. S8 ~% ~! A% Q
  DESCRIPTOR_ENDPOINT, - l; F7 x, ?9 ^' I: h8 ^+ b, S) w
! R/ L; Q7 b! A) @7 |
  0x01,       // bEndpointAddress
( @* m( Y" `# l& g0 @5 L              // bit 3...0 : the endpoint number
) }' N/ R9 \. u- r  X              // bit 6...4 : reserved 1 M! `& J9 z" \9 S" d
              // bit 7     : 0(OUT), 1(IN) ' V# f2 R' V( T9 X

& z. C" r* p; _+ T( p' K5 t& m" F+ p  0x03,       // bmAttributes 5 x3 X% {7 C+ ?' H
              // bit 1...0 : Transfer type & N; Y' }. f  |4 w! ?7 @9 v3 o
              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT)
% F4 ~  |# U) j! m; ^1 Y              // bit 3...2 : Synchronization type
3 X. i. c4 y6 D# _* A              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous)
) S2 i) ^2 s- A9 `, Y0 e              // bit 5...4 : Endpoint Usage type ; N! o% [. z# f/ n% B
              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved) $ [$ X" k5 p6 Q, K$ Z) u
              // bit 7...6 : Reserved, must be zero 2 U; N+ \7 E+ q& [& O. t

' Y' c% z3 g+ ?% G. M- s* y7 q* i  0x40,       // packet size LSB
  i/ [& O, C7 e, J5 C  0x00,       // packet size MSB ( S" E* V" y$ c, X+ g9 O$ I

- A5 z5 N+ k& E* E  0x20,        // polling interval time: 32ms - k( n4 j7 S7 e2 v/ e0 G
; g/ K4 G' h+ F2 u: k9 Y1 n
  // Descriptor of endpoint2 IN
# ]# T$ \3 `3 s2 P# M3 A3 l  0x07,
+ y4 E7 B- v# s0 U/ X8 p) t  DESCRIPTOR_ENDPOINT, # _3 }* Y. |  O

* q5 T$ ?! |" W* P  0x82,       // bEndpointAddress & a$ Q* O5 x9 z. A
              // bit 3...0 : the endpoint number
$ R' S. P6 q* v  l6 c. ^+ _              // bit 6...4 : reserved # S; P& q. J& b6 Y; V! a: [# R
              // bit 7     : 0(OUT), 1(IN) 6 r' U3 b& @0 Q! S( Q
3 P/ u4 _$ b0 D3 e
  0x03,       // bmAttributes : Z. n6 c( v7 i/ ~, J
              // bit 1...0 : Transfer type
# u$ K) N, d* G: K* u3 D% c: q3 I              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT) . L/ M) ^4 |1 Z8 z( C( R
              // bit 3...2 : Synchronization type
7 T/ u* F& f3 _" E8 m              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous) 6 |. I4 L8 p: g4 `
              // bit 5...4 : Endpoint Usage type ! g0 v9 R) O" O' R$ K- O/ z0 ^
              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved) ! b: K( O( o, [5 W: n
              // bit 7...6 : Reserved, must be zero / H5 J4 P' N& T6 \) I
% m/ a  F* C0 r
  0x40,       // packet size LSB
% v# H) u& j' Q; l8 a2 _; H  0x00,       // packet size MSB
! A0 p* }- z: p3 C0 f, u$ b, d) ~; M9 `' Y( j: b6 B6 [
  0x20        // polling interval time: 32ms 5 b" s% F$ U: }/ m
}; % V4 m+ L1 r  u' x
4 v7 o* L8 j( H# E; t
字符串描述符:定义了与设备有关的一些信息,常见的为以下四种,如果有需要,同样可以定义自己的字符串描述符。 - ~1 Q# v: ^! [( _9 J0 K
const unsigned char cbDescriptor_StringLangID[DESC_SIZE_STRING_LANGID] = - c$ F% O9 c) l3 x- _5 L/ _
{
- y) M' }8 T' H  DESC_SIZE_STRING_LANGID,  // bLength
) l  h5 l( E, d) R. i  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
% F/ X; Z9 c! V9 m    2 v: M4 X4 w. v0 Q! S
  0x09,                                  // LangID LSB: * |% }: ]9 {+ q0 T# O* N
  0x04                                  // LangID MSB: 0x0409(U.S. English) ! {7 _  d7 z0 B7 G; {
};
; x; Y2 E# }7 q1 T8 _  a3 p
- Q) x' L( ?, u3 B! ^+ Rconst unsigned char cbDescriptor_StringVendor[DESC_SIZE_STRING_VENDOR] = / i0 K6 x2 o! M5 E& r
{
' w3 `6 i, j2 {: g2 g  DESC_SIZE_STRING_VENDOR,  // bLength
0 C! B9 y4 [8 T4 T  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor   q+ ?" N, d: @7 t/ f: g2 P
3 b. t+ _0 k2 \5 V! I
  // String: "LaBiXiaoXiaoXin" + I) y# B$ E( X# \! t5 T
  'L',0, 'a',0, 'B',0, 'i',0, 'X',0, 'i',0, 'a',0, 'o',0,
& ?& k$ i. J+ @8 |9 M   'X',0, 'i',0, 'a',0, 'o',0, 'X',0, 'i',0, 'n',0 4 T% `( y0 I  K( I  A$ j
}; $ b. n/ s& m- l9 {- F( z

( g! [# X; @  N3 ]- oconst unsigned char cbDescriptor_StringProduct[DESC_SIZE_STRING_PRODUCT] = 4 o* A: R# H. D% `! I) x
{ 2 f& `% h. g2 r7 G% e3 n* W
  DESC_SIZE_STRING_PRODUCT, // bLength
' N/ l6 H1 p* U; [  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
2 x6 c. ?; \9 D6 e7 C* S# ?3 H2 p' W0 y% L: K0 H8 i  a6 ~
    // String: "STM32 ezUSB-CORE V1.01"
2 z/ G* P. Z# @2 v  'S',0, 'T',0, 'M',0, '3',0, '2',0, ' ',0, 'e',0, 'z',0, 'U',0, 'S',0, 'B',0,
1 u. q5 ~( O8 z6 N  '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0, 'V',0, '1',0, '.',0, '0',0, '1',0 7 d' ^3 I- o& k) ^
};
5 Q) V) _4 S1 h' E& m  R
+ ~  I% A3 ?% M, N! ]. Rconst unsigned char cbDescriptor_StringSerial[DESC_SIZE_STRING_SERIAL] = 5 g6 u0 d' K2 Z/ |& K8 @6 ?7 N
{ ) @1 r$ J5 O+ `. p
  DESC_SIZE_STRING_SERIAL,  // bLength   l! C& ?3 `* R0 V
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor 7 i# k: |* d8 F& f' b% \

8 _3 [; j# `$ S    // String: "ezUSB-CORE Demo 2008/11/18"
% i" a/ v- B2 b  a  'e',0, 'z',0, 'U',0, 'S',0, 'B',0, '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0, ! X7 N, A& n/ N
  '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
; R  F+ T7 v2 i};
+ o( ~' Z$ Q; a, U. p) N  v5 E
4 o( a" z5 t6 u$ H: ?7 b. L) v了解这些描述符的用法以及作用,最好的方法的是编写自定义的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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版