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

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

[复制链接]
乡村布拉德 发布时间:2008-12-23 13:47
SETUP事件正确接收后,根据该事件提供的请求类型进行对主机的响应。SETUP数据结构的wLength字段说明的是请求返回或者提供的数据长度。
' {* @5 x# j6 r如果判断出的请求信息错误或者说不被支持,STM32 USB设备需要中断此次请求: $ A& K1 K+ X) N) z! I/ t
    SetEPR_RXStatus(ENDP0, EP_RX_VALID); " q! a% _2 r" i
    SetEPR_TXStatus(ENDP0, EP_TX_STALL); 4 J5 c& w% j! l/ g8 i
. V# q. w. y( o, X; @" A& S( C! Y
正确获取到请求信息后,如果wLength为0,设备需要发送一个0长度数据包以响应主机: 6 d2 m) r' J$ B, ~# Y+ q
// *****************************************************************************
4 h0 n7 w! X/ C7 X" W; ?// Function Name  : SETUP0_Trans0Data ) k9 @' T$ |' s! b7 z! a
// Description    :
2 ?# T9 D" {* S' j1 W// Input          : + V( U) g; o3 U) G* C8 k4 d) X
// Output         : 1 D8 G! q, E$ ^3 ^
// Return         : * t" P2 n0 K' m, {* V  a
// *****************************************************************************
6 z+ A* f0 I3 B( _' a( o3 fRESULT SETUP0_Trans0Data(void) 4 p$ ]2 _: v1 `3 A
{
- `; T$ Z0 ^. d. \2 Y! j  // Send 0-length data frame as ACK to host
/ G3 q6 X$ ]! c8 q  SetBuffDescTable_TXCount(ENDP0, 0);
0 x9 z& w- l% X' o& r0 }" j  SetEPR_RXStatus(ENDP0, EP_RX_NAK);
7 Q- I' s/ |  X, @  SetEPR_TXStatus(ENDP0, EP_TX_VALID);
7 y3 B4 H9 z. R
/ S* v) a( n2 W0 A  return RESULT_SUCCESS;
: @: c6 u7 l( p9 I}
9 L- m/ I2 I2 N- A" y如果wLength不为0,设备则需要根据请求的数据长度发送数据包以响应主机:
: O2 C- X9 b) F- Y// *****************************************************************************   C5 r, e3 _+ `- r
// Function Name  : SETUP0_TransData
0 F8 f) T) N8 ]9 L( u% t% h// Description    :
7 }, s! k2 ~% [/ L* X# k: F) N// Input          :
$ S$ q% t3 i+ O/ P% k// Output         : + c2 V# t8 d  f8 b+ o6 M
// Return         : % e4 u; U7 E/ B; p8 i0 b
// *****************************************************************************
7 g5 V. l. s! T5 XRESULT SETUP0_TransData(void)
3 \, n9 _( q8 s0 [8 E3 E3 y( Z{
/ b- G/ U" b; V1 m4 _8 t  O  unsigned short wLength = vsDeviceInfo.TransInfo.wLength; 2 A$ y0 H3 v! M5 m  g- `) o
  unsigned short wOffset = vsDeviceInfo.TransInfo.wOffset; & H3 o5 [& C1 x. {% ^* B
  unsigned short wMaxSize = vsDeviceInfo.TransInfo.wPacketSize; - Z& M' h6 d. j3 W; U4 {1 V
3 N# ]( x' H' f( r) h  C. z
  if(wLength)
* x5 A) [' X. G4 \* q) W  {
( z2 h4 g' ~( x    if(wLength > wMaxSize) 5 Q2 u2 R  D/ t* b  l2 C1 G7 S1 z
    { , A& I. E# o  O
      wLength = wMaxSize;      2 M  I" {- `. h& b
    } & f1 m! r/ k" E4 S
 
3 Y# K: h+ u9 H% c/ Z2 l0 G    // Copy the transfer buffer to the endpoint0's buffer
' O" {3 D8 u- k* [    BufferCopy_UserToPMA( vsDeviceInfo.TransInfo.pBuffer+wOffset,   // transfer buffer
- q# L; w+ Y4 @# w- K2 ~& B                          GetBuffDescTable_TXAddr(ENDP0),           // endpoint 0 TX address
, T4 ]0 \7 z1 X4 N+ k. E                          wLength);
$ T0 S2 a0 z$ f2 s0 M' s
. q" p+ ^5 ]& m1 U9 Q) y; T    SetBuffDescTable_TXCount(ENDP0, wLength);
5 A$ v5 F& q& s& n# m    SetEPR_RXStatus(ENDP0, EP_RX_NAK); * Y' K% U- i2 P; }  u' s
    SetEPR_TXStatus(ENDP0, EP_TX_VALID); ' t+ H0 u/ a* {6 N- R+ T1 C
  & c: b( L: b4 z5 I* G7 q) t$ q
    // Update the data lengths
9 j8 H' \, ~8 g. ?5 b% u: p    vsDeviceInfo.TransInfo.wLength -= wLength; . _; Q% U! i( K  X6 p! Z5 A: Q
    vsDeviceInfo.TransInfo.wOffset += wLength;
6 V, y7 m! w) K0 b4 X$ u5 p    + |) a3 b: N$ Z- @' A
    return RESULT_LASTDATA;        
# c: H2 Y. I. E. ?( W  } # s  R. C$ g/ g4 e# S

$ ]5 e1 `% p, s* J! D  return RESULT_SUCCESS;
" P" N* B2 p  ~1 {}
. i  g, h+ M) s8 ?如果发送的数据长度大于端点设置的最大数据包长度,数据将分割为若干次发送,记录发送数据的状态包含在结构体TRANSFER_INFO中:
- P% u2 Z. }: n// ***************************************************************************** 4 ^0 b2 {- \% s* E7 O$ r
// TRANSFER_INFO / n* o: b3 |9 m2 H$ I! m- w( r' s
// *****************************************************************************
9 F; N$ `; A+ n, p. S+ Z/ Utypedef struct _TRANSFER_INFO
" B* S# U8 V; _! A2 h" I{
% ^" s2 x/ k/ @, @6 s* h# g  unsigned short wLength;                 // total lengths data will be transmit
( p: w8 n5 y: L9 [; h! @6 `  unsigned short wOffset;                 // number of data be transmited
# _* |% m* Q+ \8 k8 P8 P8 T9 f8 G$ a5 \  unsigned short wPacketSize;             // endpoints packet max size
+ ~# s0 t7 E5 }1 F; k4 c" I! v  unsigned char* pBuffer;                 // address of data buffer ( q3 f9 T5 c. o* t
} 4 }6 A/ m: }/ e: W$ l
TRANSFER_INFO,
6 y, D5 e& D/ ^: o*PTRANSFER_INFO; 2 H( z6 J; K, i2 R
TRANSFER_INFO.wLength记录发送的数据长度,如果非0,表示有数据需要被发送。
/ f3 ^* t5 }3 \* l. V8 Y, rTRANSFER_INFO.wOffset记录已发送的数据长度,用以确定数据缓冲TRANSFER_INFO.pBuffer的偏移量。
. F$ `) }' {  D# n; E( g& v. I, }+ K* c
需要了解的一点:USB主机向USB设备正确发送一请求后(这部分的处理由硬件完成),USB主机将间隔若干次的向USB设备索取响应数据,STM32 USB TX状态为NAK说明不响应USB主机,USB主机在超时后退出此次请求;TX状态为STLL说明中断此次请求,USB主机将无条件退出请求;TX状态为 VALID说明设备已准备好数据发送,USB主机将从USB设备读取数据。
+ b  v' ^$ i* y8 p" v! C( p" o以非0长度数据请求的GET_DESCRIPTOR请求为例的响应过程: 5 m, f' |& r* |6 Q- O1 T4 k
CTR_SETUP0()->SETUP0_Data()->SR_GetDescriptor()->SETUP0_TransData() . c  Q* {' v$ c, _

; P" B0 f" z( M$ N6 B8 hRESULT SR_GetDescriptor(void)
6 A) J) \. N  k6 D  c8 G: _{
/ S; t' h5 B# ?8 N  // RequestType: device->host, standard request and device recipient 7 v' Z8 t2 \4 x" t0 _; b
  if(vsDeviceInfo.SetupData.bmRequestType == RT_D2H_STANDARD_DEVICE) 4 e& N* T: n0 E8 v1 N& _. R
  { ( |2 t1 n- Y: T& N+ Z
    // SetupData.wValue.b.MSB: descriptor type
. S/ p) ^: b+ m9 x$ r    // SetupData.wValue.b.LSB: descriptor index
% h. L( I. S% g  a    switch(vsDeviceInfo.SetupData.wValue.b.MSB) 5 s0 I7 w6 F( y4 o7 M$ a
    {
7 A! \0 D9 r$ `' I7 I1 t2 c( q7 z    case DESCRIPTOR_DEVICE:               return SR_GetDescriptor_Device();
& b, l, h1 F" }/ }- {    case DESCRIPTOR_CONFIG:               return SR_GetDescriptor_Config(); 4 L+ G/ M( F/ h9 K+ ^2 k2 S
    case DESCRIPTOR_STRING:               return SR_GetDescriptor_String(); $ T& H# k9 Q; r% |7 G
" Y* H7 v. \) b; C/ \) b0 I
    default:  return RESULT_UNSUPPORT; 3 `, o+ Z0 {  ~% I
    } " N+ ]$ o( G4 G8 i' }' f
  } 2 c9 _% ]" |( j

3 a) n7 R- v# X& l  return RESULT_UNSUPPORT; ( v( V1 C3 x8 Z- j7 }
}
" V  ^: T" _5 s/ f: J! aGET_DESCRIPTOR请求属于USB协议中的标准请求(standard request)并且数据方向为设备至主机(device->host),分设备描述符、配置描述符、字符串描述符三种。已设备描述符为例:
* v! \) W  D* R( aRESULT SR_GetDescriptor_Device(void)
) c+ u; Y9 x6 k5 z{
0 ^7 k8 y* g7 r& t: \# L! X  // Assigned the device descriptor to the transfer " e& v- h" P0 {6 q( c0 t" X
  vsDeviceInfo.TransInfo.wOffset = 0;
5 l+ W7 Q4 u4 ^1 U2 r# P, J0 b0 P% B  vsDeviceInfo.TransInfo.wPacketSize = ENDP0_PACKETSIZE;
0 X; g5 O* i' S' x/ P$ C4 B  vsDeviceInfo.TransInfo.pBuffer = DescBuffer_Device.pBuff; " _( h! F- u( V
  vsDeviceInfo.TransInfo.wLength = DescBuffer_Device.wLen; 8 v8 ?1 w" W; @" n) J3 E; F
  vsDeviceInfo.eControlState = CS_GET_DESCRIPTOR;
0 m4 u1 e2 W- k! [2 a$ B; X2 b/ T
+ u+ t' [% w' M3 V# Q2 a- _  if(vsDeviceInfo.TransInfo.wLength > vsDeviceInfo.SetupData.wLength.w) 9 X$ O: s, D8 S% x  ~7 ^
  { / s" o9 Q4 Z. `# M( H0 l0 \
    vsDeviceInfo.TransInfo.wLength = vsDeviceInfo.SetupData.wLength.w; $ n$ w7 n, t+ c7 M4 e
  }
. i$ A/ ^4 T, W6 [# C9 b9 T+ r5 i* L( }7 }& g& n
  return SETUP0_TransData();
, T% u+ A. [! c- m; `3 _- p}
  L5 H8 ?' p% P. d7 K: Z' _5 E这里说明了发送数据的长度、缓冲、偏移、端点包大小以及当前的控制状态,并说明了如果发送的数据长度超出请求的数据长度,则将舍弃超出的部分。数据配置好后,调用SETUP0_TransData()进行数据发送。 ! H) m! M( W! d& u0 x! d$ G
在USB主机查询到USB设备准备就绪后,将读取出这些数据,完成后,USB设备将产生IN事件,此时将响应CTR_IN0()函数: 1 ]( f" ]8 |  s! n/ U2 Z# ]
// ***************************************************************************** + K% j* C0 {( J) J5 i  \+ ?$ o
// Function Name  : CTR_IN   b9 G7 ^2 r/ x" ]; l
// Description    : + c* p* Q2 U3 ^9 y& w
// Input          : / [0 ~( ]! a2 V! h
// Output         : ' ~/ |: b" O' M) g! J1 Q
// Return         : - T/ P- ]- _+ E
// *****************************************************************************
! k0 _1 M# n  q0 C# ~9 Nvoid CTR_IN0(void) , G  {. I) H8 Z3 h
{
: p! Q2 W  i6 }+ p5 x8 S+ z( N  switch(vsDeviceInfo.eControlState)
5 d" y  n0 H6 J2 \2 Y  { 4 K3 Y* n  A7 Z) f; W+ h- h
  case CS_GET_DESCRIPTOR:
1 \& j1 g( E0 f3 M    if(SETUP0_TransData() == RESULT_SUCCESS)
$ x1 ~5 e) N6 i4 E' W  u% u' c    {
# d/ ]8 \5 q' D0 Q: s; t      SetEPR_TXStatus(ENDP0, EP_TX_NAK);
5 @! h( U+ h1 {      SetEPR_RXStatus(ENDP0, EP_RX_VALID);
9 z5 R) u- E% U" k+ x    }   
; f2 Y/ u/ d0 l1 ?! [    break;
3 P2 ?. ~  t1 e0 Q     
+ A2 G  a3 f( T" i6 e" F* Y! Q  case CS_SET_ADDRESS: 5 Y+ y' d6 c* `1 G: q# n
    SetEPR_TXStatus(ENDP0, EP_TX_NAK);
* u) t+ j5 Y6 [4 {    SetEPR_RXStatus(ENDP0, EP_RX_VALID); # S  X' V9 ~  K; S7 M( x
) I; g# j* [* L' @. x# `  T
    SetDADDR(0x0080 | vsDeviceInfo.bDeviceAddress);
4 k6 Z2 D( T8 Q$ [% z$ i2 f* A    vsDeviceInfo.eDeviceState = DS_ADDRESSED;    : Z) {; J5 ?- B- p  C
    break; 2 _6 V2 h; p0 N! P

7 v9 `- j: j* W6 L# ?  case CS_SET_CONFIGURATION:
$ y1 B1 @* b' O% y+ ?    SetEPR_TXStatus(ENDP0, EP_TX_NAK); - ~8 R( q- n/ c$ G
    SetEPR_RXStatus(ENDP0, EP_RX_VALID);
5 c6 `# ^2 z7 K# G
- F1 W* \' Z9 I& M2 n    vsDeviceInfo.eDeviceState = DS_CONFIGURED; 2 L6 Y) A+ D+ s* U. x8 ^; D! q
    break; 9 l- v% f, N1 [/ q+ @; T5 J
 
- k/ @* f  }1 C4 U# g; n9 ]* @; i  default:
5 ]: C0 b/ @1 }    break; 5 C7 B9 U% {, s& X" Q0 H% X5 H/ C4 o
  }
( V4 M$ {  ^; m" \* C} 9 i5 u: h9 t6 q: s
再这如果响应GET_DESCRIPTOR请求发送的数据如果全部发送完毕,SETUP0_TransData()返回RESULT_SUCCESS,并设置TX状态为NAK;否则返回RESULT_LASTDATA,将继续发送剩余的数据直到数据全部被发送。至此,整个的GET_DESCRIPTOR请求过程完成。 2 x; h8 j- ~! @7 l  @8 z$ V/ [
0长度的数据请求在发送0长度数据响应后,因为不存在可能还未传送的数据,因而IN事件后直接结束此次请求。 ( L" ^9 Q8 h; u! R8 N: g# \
在数据方向为USB主机->USB设备时,如果正确接收到数据,将响应CTR_OUT0()函数,处理过程类同CTR_IN0()函数。 ! p( Q* `1 r% u; {5 B
在USB设备的枚举过程中,USB的一些描述符数据结构需要了解,具体在USB协议中有详细的说明,在usb_desc(.c/.h)文件中,定义了这些结构,这些结构是特定的:
4 Z0 b" }& ]& J$ r
1 B" z8 d8 U+ E: [设备描述符:长度、格式固定,其中VENDOR_ID与PRODUCT_ID决定上位机驱动的识别。设备分属类别决定了设备的性质,如果为自定义USB设备,设备分属类别值为0,同时上位机驱动必须配合编写;如果为标准USB设备,则必须使用这些标准设备的驱动、数据结构等等,条件是你必须了解这些标准设备的一些信息,好处是省去一些麻烦的驱动编写。 , o1 H) h- R" k. d" B# M
const unsigned char cbDescriptor_Device[DESC_SIZE_DEVICE] = 9 m* n1 c: I5 @* i/ U
{ ! |; |& ^: p$ j/ w) I' D
  DESC_SIZE_DEVICE,     // bLength: 18
& j- j; Q1 q4 J1 P  DESCRIPTOR_DEVICE,    // descriptor type 9 R& R! @: k. I/ Z8 u
. }+ J+ c- @6 H3 _
  0x00,            // bcdUSB LSB: USB release number -> USB2.0 4 T  M) T' p" L5 Y" L8 Z9 \
  0x02,       // bcdUSB MSB: USB release number -> USB2.0 - K4 e% }  c0 }% b/ l9 U

: j0 l# t$ c/ M! X  0x00,         // bDeviceClass:    Class information in the interface descriptors
, S8 c  q) u9 V& z& V  0x00,       // bDeviceSubClass:
. U' j8 {: p, L3 t# a  0x00,       // bDeviceProtocol: ' c9 ^0 s, C7 l' w
  0x40,       // bMaxPacketSize0:  LowS(8), FullS(8,16,32,64), HighS(64) 6 M: Q* N, I  j

# u% x9 g9 L  \- I  LOWORD(VENDOR_ID),       // idVendor LSB:
7 Q/ [6 C3 \) L3 f9 T  HIWORD(VENDOR_ID),       // idVendor MSB:
1 T% e) E% z% B( I) R
2 U' E8 A3 G' F  LOWORD(PRODUCT_ID),      // idProduct LSB:
# |; S5 O3 ]8 p3 P) X( r+ W  L  HIWORD(PRODUCT_ID),      // idProduct MSB: : }; B2 R4 ]" p9 N! R  c2 _" b

  x+ j$ ^4 U/ O3 J' G  LOWORD(DEVICE_VERSION),  // bcdDevice LSB:
8 S/ S, h! \) p+ R. X  HIWORD(DEVICE_VERSION),  // bcdDevice MSB:
) E, y; c0 }1 p& k1 v: W3 K! A+ M) [3 s# L
  0x01,       // iManufacturer: Index of string descriptor describing manufacturer % r- A+ v( Q* u6 T* y
  0x02,       // iProduct: Index of string descriptor describing product ( N6 ^+ t, {" y9 X' ~7 y
  0x03,       // iSerialNumber: Index of string descriptor describing the device serial number ; r1 {0 h, }6 _. E. u) C

( v2 h/ k, ^- b; Y: o# H9 A" I  0x01        // bNumConfigurations: number of configurations
, @9 d1 p4 Y$ S$ U4 R( L2 j}; ) u: b0 F8 R4 k7 ?1 k

; \) e( R* s# ^配置描述符:前9个字节格式固定,后面紧跟的各种描述结构跟实际配置有关,每增加一种描述结构,该描述结构的第一字节说明了结构的长度,第二直接说明了结构的类型。在配置描述符中一般包含配置描述、接口描述、端点描述,如果需要同样可增加自定义的描述。使用标准USB设备类别时,配置描述符的结构也必须满足此类标准设备的数据结构。 " k, C$ T6 F. [1 U8 E4 X
const unsigned char cbDescriptor_Config[DESC_SIZE_CONFIG] =
( a% ~1 _6 `: s# R9 U9 P  b{
7 V1 V( z4 B% c  // Descriptor of configuration
* ^$ h# N  S, R) d* m3 F8 n  0x09,                   // lengths    % N( F7 L$ k2 O; P7 f
  DESCRIPTOR_CONFIG,      // descriptor type 8 H" N- N# o2 e) O. o) Y

3 ]0 O0 M- Q8 e* W, j$ D  DESC_SIZE_CONFIG,       // Total configuration descriptor lengths LSB
; D' p  E" s+ Z, E  \: H  0x00,                   // Total configuration descriptor lengths MSB
4 v- G; A( k. ]/ M, p$ O& L% v+ \5 p
  0x01,       // bNumInterfaces: Total number of interfaces
1 w" l5 r# W6 E4 p% b& \  0x01,       // bConfigurationValue: Configuration value " v5 H3 ?  N$ ?; Q
  0x00,       // iConfiguration: Index of string descriptor describing the configuration
. ~) k5 B" [, n) j7 u 
% H) O  m  U3 D0 T! l( {* J" [4 i3 N  0xA0,       // bmAttributes: bus powered   _1 X8 V( ]- \0 {( s; c5 g
                        // bit 4...0 : Reserved, set to 0 ! z% u% e0 X0 U% L# K8 C9 q
                        // bit 5     : Remote wakeup (1:yes) 3 o5 ?9 e1 M% x/ N; @! b' M, m" t
                        // bit 6     : Self power (1:yes) : z( {" Y3 c% L- b
                        // bit 7     : Reserved, set to 1 1 m$ z0 N  M9 B) ~
( q8 Y1 |- _6 p
  0x32,       // bMaxPower: this current is used for detecting Vbus = 100mA ( `& \, ?9 i! e+ S  }1 R1 ^) F
( Z- g' Q5 ^" w  E, f+ B  _

2 w* T$ G! y& t  // Descriptor of interface
& S8 S* j3 z# m1 q# G  0x09, ) j- _' u: Y: D' T
  DESCRIPTOR_INTERFACE,
) w/ l& ^' t: B- R: f4 B% G+ F0 W1 O' W7 u
  0x00,       // bInterfaceNumber: Number of Interface % E* \* V& H& o% J0 r) ^
  0x00,       // bAlternateSetting: Alternate setting
, {, [! [5 L  Q7 Z2 m
( D% |# O/ c& X  0x02,       // bNumEndpoints: Number of endpoints except EP0 ; ?! H, ]( g: y2 Y
  0x00,       // bInterfaceClass: % f+ p7 g! c  c
  0x00,       // bInterfaceSubClass:
3 ]7 d  a5 ~5 ^% Q5 L! g" a4 T  0x00,       // nInterfaceProtocol:
' F" h- i' u& h$ e1 [
" s+ W: m; l6 @8 J- E, N5 L  0x00,       // iInterface: Index of string descriptor describing the interface 2 }1 n' I/ H; d5 f6 _! m" [  U3 M

, }' c" Z# L% }/ K+ I) A1 L) P& {
  // Descriptor of endpoint1 OUT ! v3 |! O+ U6 y% R
  0x07, $ D, j5 h1 N! {) p( u
  DESCRIPTOR_ENDPOINT,
: R1 q% i/ s; a9 X6 x% b' T4 f( x5 f3 b" @3 M0 D0 e
  0x01,       // bEndpointAddress
4 K; P! |, X  J1 t8 W              // bit 3...0 : the endpoint number
& z- \* \; H5 c! a" |* E* Y! `              // bit 6...4 : reserved
. ^$ l  `( W% S3 T% K5 m! L2 n) Q              // bit 7     : 0(OUT), 1(IN)
0 p$ u9 C$ H2 s6 t. u
% e( A4 Z' a  e4 `  0x03,       // bmAttributes
% m2 q" Q- y  X) q/ e: n8 _              // bit 1...0 : Transfer type / g; E) g. s0 {; R" y& \
              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT)
0 V+ y- A" y, A) z9 h! Y8 B              // bit 3...2 : Synchronization type
) U% q. \5 ?8 Y8 m( {( R  l/ Z  U              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous)   \. M- [& K- M  s; ^( s5 d
              // bit 5...4 : Endpoint Usage type $ b. U) L. }5 c# I, A
              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved)
, {5 ^1 {7 m6 f  @              // bit 7...6 : Reserved, must be zero   ?  z- V& W- r$ ?) c

- b0 c; e" {) C2 K# L  0x40,       // packet size LSB * n- K* x1 H( z; e
  0x00,       // packet size MSB
% j+ a) G: v9 X4 C
5 [7 s( k% F  f7 n; k  0x20,        // polling interval time: 32ms
% z+ u; O& J; @; N5 e6 [
8 W2 q; E9 Y* X& @. S$ `  // Descriptor of endpoint2 IN * J3 r* l, q5 v  d+ Z) P2 `
  0x07, % i/ w. {7 E% h1 O
  DESCRIPTOR_ENDPOINT, * S0 M( c8 p# S- z8 y0 z) |6 A  k

' l5 w. Z. ]  e8 S6 I; d/ A1 u  0x82,       // bEndpointAddress
: E, {+ o+ [% O" s! D$ h) |% {              // bit 3...0 : the endpoint number # n5 ]1 }) e; u/ z6 n
              // bit 6...4 : reserved
( }4 b$ D' T3 |              // bit 7     : 0(OUT), 1(IN) ' U! h0 w6 H3 X" R
7 `; c, C+ r! ~. s/ C/ j
  0x03,       // bmAttributes
# ]. N; Q* ?5 z              // bit 1...0 : Transfer type : y, ~, _* ?# B: k) \& A
              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT)
- V, J1 ?$ d; s- s8 p! _: k              // bit 3...2 : Synchronization type
3 h# q( Q- @5 E# Y              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous)   J: ]9 X* y& Y2 ]3 {/ K" v
              // bit 5...4 : Endpoint Usage type
8 D, k9 n6 T; r; }0 f              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved)
4 }; z8 i1 h  {/ R* F$ J% A              // bit 7...6 : Reserved, must be zero
7 f: t, H: U$ ]+ n1 r5 D! g" `7 o+ D; L' ^" A
  0x40,       // packet size LSB 2 y4 s6 p: D5 c9 z: I, h  m
  0x00,       // packet size MSB
9 c3 p! G- D) P) Z8 m+ J! c7 \! R5 n
  0x20        // polling interval time: 32ms
' X: H$ D* U$ v0 l7 n* z}; 7 e6 Q) U$ Y) \4 t+ F* c
3 a' _( f' ^0 v
字符串描述符:定义了与设备有关的一些信息,常见的为以下四种,如果有需要,同样可以定义自己的字符串描述符。 1 L0 g- G6 s" }6 J( U
const unsigned char cbDescriptor_StringLangID[DESC_SIZE_STRING_LANGID] =
. R  {2 E) E! v0 p* z) G  c& I. T" V0 y{
6 X9 v1 _3 }3 x; K4 T0 ]  DESC_SIZE_STRING_LANGID,  // bLength 3 g2 x8 Y0 L3 y$ ^& t5 `; D
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
0 C( I# h. M9 P6 H8 Y; B    4 k/ D) t+ K, [3 h9 U
  0x09,                                  // LangID LSB: ) x( U" V, Z- F9 I
  0x04                                  // LangID MSB: 0x0409(U.S. English)
- T8 `: j, n& M! W" f}; 6 C+ A! e. w4 I# h$ J% }0 M
5 P1 i+ r, i: L* [& k3 X$ K
const unsigned char cbDescriptor_StringVendor[DESC_SIZE_STRING_VENDOR] = 1 E0 e( k# I7 C% z( R6 q% W
{
) u& B. ]. z5 c7 F  DESC_SIZE_STRING_VENDOR,  // bLength & X% ]; k8 P$ w  E9 k1 V, L
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
" p# c' d, S3 g; C  ~
$ f3 y* u4 f) M  // String: "LaBiXiaoXiaoXin"
, }' ]+ Q( [. \& I  L0 v  'L',0, 'a',0, 'B',0, 'i',0, 'X',0, 'i',0, 'a',0, 'o',0, 3 I0 W$ J; V& l0 N" l* E
   'X',0, 'i',0, 'a',0, 'o',0, 'X',0, 'i',0, 'n',0 $ `; u/ C; w0 {  B3 e* N
}; " @& j) U. p/ g+ v4 Z

' P" I5 S" W$ E4 s) xconst unsigned char cbDescriptor_StringProduct[DESC_SIZE_STRING_PRODUCT] =
+ c: a" X' i2 ~' g5 A5 }{
3 t( e! W5 \4 ?3 Q1 M6 @  DESC_SIZE_STRING_PRODUCT, // bLength
, A0 R. M0 S8 k( |5 G8 L6 Y  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor 7 L% U3 C: E2 R' p: y  X
# Y9 r% D7 n) ^$ c" e9 v+ _2 g
    // String: "STM32 ezUSB-CORE V1.01" # M9 j5 }8 R! t5 T
  'S',0, 'T',0, 'M',0, '3',0, '2',0, ' ',0, 'e',0, 'z',0, 'U',0, 'S',0, 'B',0,
  _1 P7 i* |$ ?0 a- g  '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0, 'V',0, '1',0, '.',0, '0',0, '1',0
- K9 R  a1 X5 C" k# p' L+ l4 N};
! w! k# o: x! D( a0 H2 R1 H8 a! V& s# H1 S) S* k4 {/ v
const unsigned char cbDescriptor_StringSerial[DESC_SIZE_STRING_SERIAL] =
9 [: b+ r9 P+ ?{ ( K0 e- u2 r5 X# p" s+ C
  DESC_SIZE_STRING_SERIAL,  // bLength
6 W$ w& A, x( N7 r) Q' P  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
1 Y  d! V! ?( o( Q9 C2 Y
$ N. t1 h5 K" T! D& V! |0 M  y7 }    // String: "ezUSB-CORE Demo 2008/11/18"
+ m+ a# j& w! g# L  'e',0, 'z',0, 'U',0, 'S',0, 'B',0, '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0,   i* C, Y& h* S; J
  '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  x4 _4 L6 A! i- s0 k, m7 \
}; . M# C# p. \/ A2 s
0 P, i( u- O/ y5 |
了解这些描述符的用法以及作用,最好的方法的是编写自定义的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 手机版