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

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

[复制链接]
乡村布拉德 发布时间:2008-12-23 13:47
SETUP事件正确接收后,根据该事件提供的请求类型进行对主机的响应。SETUP数据结构的wLength字段说明的是请求返回或者提供的数据长度。
& {6 F5 ]% u4 p6 D如果判断出的请求信息错误或者说不被支持,STM32 USB设备需要中断此次请求: ' _' h  a* f* Z- ^* l. Z% d
    SetEPR_RXStatus(ENDP0, EP_RX_VALID);
8 F1 A* k3 b6 P+ X    SetEPR_TXStatus(ENDP0, EP_TX_STALL);
. [1 l* {# l/ m2 }& c! c; D  i( S5 A& F
正确获取到请求信息后,如果wLength为0,设备需要发送一个0长度数据包以响应主机:
# {' n3 F- u8 S9 c: O7 C// ***************************************************************************** , e8 {8 J9 C- `8 n" s; p5 m* F
// Function Name  : SETUP0_Trans0Data
6 w# }% m! k* a/ \1 Z2 t// Description    : & F& K! n% U' X( m- _
// Input          : $ p/ B9 w, j! F" L5 }
// Output         : 4 D. ]' ~; ~$ ?  A/ `) u
// Return         :
; e6 M, |# ?0 u7 ]7 A$ F// ***************************************************************************** . [, b6 W' \) o9 F* v
RESULT SETUP0_Trans0Data(void)
8 o- I& F3 V7 `1 X& _{ ) i- e+ f& z9 B
  // Send 0-length data frame as ACK to host 3 R8 j8 O& j6 T/ ~: j
  SetBuffDescTable_TXCount(ENDP0, 0);   C) G' W) j: L( O
  SetEPR_RXStatus(ENDP0, EP_RX_NAK);
% M7 M, m; Q; g& L3 [% K, C7 [  SetEPR_TXStatus(ENDP0, EP_TX_VALID); 7 [1 I/ ~, G" j" D

. V1 l' d( c4 [9 V. m% e  return RESULT_SUCCESS; + S2 g* D' l& h8 {0 K3 w
} ) Q0 s! x4 P0 I5 L: R9 b4 M
如果wLength不为0,设备则需要根据请求的数据长度发送数据包以响应主机:
& v) K( a, k" N  m// ***************************************************************************** " I2 M; U2 M! K. F
// Function Name  : SETUP0_TransData
( h2 ]* ^( _. p( W1 `, Q// Description    : & j* M6 w  B9 [& f6 d1 |; a5 m
// Input          :
0 ]# w9 Y  v# v5 p. r// Output         :
; A( s) W9 w. ?+ m! l// Return         :
  C/ X1 {3 N7 X$ b// ***************************************************************************** 4 I1 z* N( N5 Y/ F& e
RESULT SETUP0_TransData(void)
& W, `) w$ Y8 @2 ~" E7 H3 n{ $ z+ ]( X; e* ]
  unsigned short wLength = vsDeviceInfo.TransInfo.wLength; " m; P4 ^3 m7 r! U
  unsigned short wOffset = vsDeviceInfo.TransInfo.wOffset; 7 n" v) _+ G8 B; h2 ]! I3 L
  unsigned short wMaxSize = vsDeviceInfo.TransInfo.wPacketSize;
% i2 u( b# D. z! i# k  N
. b* v5 R" K, H' k# [- u! Z  if(wLength) 2 S% \4 R0 I8 T/ f3 T8 A
  {
+ X; K6 W+ Q* O8 a4 Y" d7 _    if(wLength > wMaxSize)
. }+ j' m9 o- `    { 0 ~  x, F* ?/ c6 \8 K  I& e& |
      wLength = wMaxSize;      ( [7 e! M; @& I+ y2 x1 Y
    } ) }1 b; U* m  D$ a& X# N0 R, q
  ) x2 J- Q! V& ?( K9 y/ z
    // Copy the transfer buffer to the endpoint0's buffer : C1 }3 C4 G/ x% _1 ~, A* Z" p/ T
    BufferCopy_UserToPMA( vsDeviceInfo.TransInfo.pBuffer+wOffset,   // transfer buffer ! @1 ^1 e2 G+ m9 }. J
                          GetBuffDescTable_TXAddr(ENDP0),           // endpoint 0 TX address
/ w# i" J0 Q( N0 u1 M. R+ W  g                          wLength);
5 `) g" O8 U/ `( X( ?
2 u- j8 y0 w) F+ T7 Q    SetBuffDescTable_TXCount(ENDP0, wLength);
+ H# c  Y% O, |6 p    SetEPR_RXStatus(ENDP0, EP_RX_NAK); % C1 U$ T% Z3 L1 Y* M7 i8 X7 A) ~
    SetEPR_TXStatus(ENDP0, EP_TX_VALID); ( _. G# Q0 m" o) }* P
  & @5 E: H+ g. V7 X# k" v
    // Update the data lengths
1 V( O8 ]& k9 u8 ]( A8 t    vsDeviceInfo.TransInfo.wLength -= wLength;
; n$ L1 N- X6 Y9 y# n    vsDeviceInfo.TransInfo.wOffset += wLength; # C) B2 E! @* L8 q
    0 ^8 ]% r4 j! c
    return RESULT_LASTDATA;        
. b8 O$ X  o0 A  ^  } 6 R- |# e/ d' ?2 C6 ]6 f
* J% Y. M1 P4 e8 }4 M6 C# }( f
  return RESULT_SUCCESS; # S# T" {( Y" G0 c" [7 a7 j
} 0 {( \* u2 V/ \  ^0 i* l% o# Z2 y
如果发送的数据长度大于端点设置的最大数据包长度,数据将分割为若干次发送,记录发送数据的状态包含在结构体TRANSFER_INFO中: 3 z6 z, I" _/ X0 h
// ***************************************************************************** ! p- }  n0 i; M" ?5 z; u' c) Q
// TRANSFER_INFO
' w2 w8 F" @! h' O  {// ***************************************************************************** 9 e* n' \/ W2 q$ d3 X" ~* x9 X0 l
typedef struct _TRANSFER_INFO . `! H7 f9 n, q7 I. P  k
{ 5 C# v$ Y( p0 V: R% f$ @$ {
  unsigned short wLength;                 // total lengths data will be transmit 8 ~) q+ K$ U) F
  unsigned short wOffset;                 // number of data be transmited 7 |* [: f" j! M& V% X8 o
  unsigned short wPacketSize;             // endpoints packet max size
1 [- M' p8 P/ P, X. \& Y; [  ]  unsigned char* pBuffer;                 // address of data buffer
5 S1 U, k+ [- W6 g} ( A" v% n9 T4 U8 }% f' L: l
TRANSFER_INFO, 4 z$ n6 O# _# p1 V* g$ J4 M# R
*PTRANSFER_INFO;
: N- e7 P8 ?! h8 NTRANSFER_INFO.wLength记录发送的数据长度,如果非0,表示有数据需要被发送。
( m. {! j* m, ]TRANSFER_INFO.wOffset记录已发送的数据长度,用以确定数据缓冲TRANSFER_INFO.pBuffer的偏移量。 0 j8 ]' q/ }  Y2 Q4 d% H1 K
' N  M5 x4 o- ^9 t
需要了解的一点:USB主机向USB设备正确发送一请求后(这部分的处理由硬件完成),USB主机将间隔若干次的向USB设备索取响应数据,STM32 USB TX状态为NAK说明不响应USB主机,USB主机在超时后退出此次请求;TX状态为STLL说明中断此次请求,USB主机将无条件退出请求;TX状态为 VALID说明设备已准备好数据发送,USB主机将从USB设备读取数据。 # E5 N# V) ]6 S) D  g6 \9 [9 g) Y
以非0长度数据请求的GET_DESCRIPTOR请求为例的响应过程: 1 E3 t- y# w7 W. e- v5 Q) j7 {
CTR_SETUP0()->SETUP0_Data()->SR_GetDescriptor()->SETUP0_TransData()
; N- D7 m, ]1 I! w* ^5 U$ z, s4 ?* s1 @* ~# k+ B
RESULT SR_GetDescriptor(void)
7 G, s: M: j2 Q6 |2 {9 a9 j{ 4 d# p3 I; r# X' J( L: H
  // RequestType: device->host, standard request and device recipient : h- n1 ]/ r" y( e) C+ Y8 V
  if(vsDeviceInfo.SetupData.bmRequestType == RT_D2H_STANDARD_DEVICE)
+ \' r, _' {) X: I7 L& h  { . U/ K  S- w- _5 {
    // SetupData.wValue.b.MSB: descriptor type - L- X/ L7 b9 u# L
    // SetupData.wValue.b.LSB: descriptor index 7 X# e4 o6 S) ?3 Q0 p
    switch(vsDeviceInfo.SetupData.wValue.b.MSB) % d/ n, F0 n: o% @5 J* ?
    {
2 ~9 b' @, l7 l    case DESCRIPTOR_DEVICE:               return SR_GetDescriptor_Device();
) I: d2 q& @: [9 n( p% O    case DESCRIPTOR_CONFIG:               return SR_GetDescriptor_Config(); : J2 N" I6 P" K! {
    case DESCRIPTOR_STRING:               return SR_GetDescriptor_String(); 8 ]- e; Q; z; [7 A

" `/ v- G5 _% l4 \% t( L) h7 Z    default:  return RESULT_UNSUPPORT; / r5 N  S* H4 v! [1 q
    } & O$ O/ j9 J% W
  } 2 G1 I. A) ^3 U) D* N
$ v( y6 \- p# F" w4 h3 J
  return RESULT_UNSUPPORT; " n7 T* z9 v7 G9 y4 E
} . a; K: P8 c  W( M/ o
GET_DESCRIPTOR请求属于USB协议中的标准请求(standard request)并且数据方向为设备至主机(device->host),分设备描述符、配置描述符、字符串描述符三种。已设备描述符为例: / I8 g3 ~. \3 I! n6 }( Q$ V* W
RESULT SR_GetDescriptor_Device(void) . k8 Q0 d6 U, J: y
{ $ q) E4 {! Z: ~) h, W
  // Assigned the device descriptor to the transfer 2 j- o9 V) t- T$ k+ ?  ^
  vsDeviceInfo.TransInfo.wOffset = 0;
( w; X) h- x' J; y) w: {$ X0 m  vsDeviceInfo.TransInfo.wPacketSize = ENDP0_PACKETSIZE;
* u" r! x8 V! J. u5 H' x3 j  vsDeviceInfo.TransInfo.pBuffer = DescBuffer_Device.pBuff;   e4 `* V& A6 W6 d& y2 {$ ]# ?7 r
  vsDeviceInfo.TransInfo.wLength = DescBuffer_Device.wLen; 9 m: F: @; P3 x3 E( l( x0 e
  vsDeviceInfo.eControlState = CS_GET_DESCRIPTOR;
9 N# `3 D  E, y6 ?7 [' d
) ?4 c% U$ W# F  if(vsDeviceInfo.TransInfo.wLength > vsDeviceInfo.SetupData.wLength.w)
/ E2 P. E' Q) Y0 w  {
# q1 u6 L. w9 J# b) k1 l$ k    vsDeviceInfo.TransInfo.wLength = vsDeviceInfo.SetupData.wLength.w;
( _; e& j1 R4 [& P  } & B, g( w7 V6 G
9 A9 p6 W) r3 Z4 V
  return SETUP0_TransData(); 0 V& d& b4 s* |5 t/ `9 |* G: |" D
}
( N0 i7 ]# J6 z- J# }这里说明了发送数据的长度、缓冲、偏移、端点包大小以及当前的控制状态,并说明了如果发送的数据长度超出请求的数据长度,则将舍弃超出的部分。数据配置好后,调用SETUP0_TransData()进行数据发送。 ) u' z' I( `0 v" a( n
在USB主机查询到USB设备准备就绪后,将读取出这些数据,完成后,USB设备将产生IN事件,此时将响应CTR_IN0()函数:
( |' |4 b" V7 y5 _( C9 K5 F9 F// *****************************************************************************
0 z  f0 D* e; o& W$ j/ ^- @// Function Name  : CTR_IN
0 H' g! Y& C9 D# _  {' G// Description    : ( _! t- _; `& P- k8 y& n
// Input          :
* m' z* ~6 ~) s4 N+ f8 y// Output         : / V% l) c( R5 ?- J% _, i1 t
// Return         : ' n( O7 K8 \7 k4 z+ }! r4 D9 M2 k
// ***************************************************************************** & C) G( ~1 H5 i, {5 C  Y" J- Q
void CTR_IN0(void)
" e7 b( @0 v+ b* r" Q: q{ $ a& A5 n  {. s/ ~( m; u5 y2 D
  switch(vsDeviceInfo.eControlState) - {1 }: o/ i& Z) R
  { / E7 u3 t. r4 s& z
  case CS_GET_DESCRIPTOR: 9 w6 g2 g* q  c- N( q$ V1 B( `
    if(SETUP0_TransData() == RESULT_SUCCESS) 2 D, w& v  k, D
    { : |" n/ b9 C, }
      SetEPR_TXStatus(ENDP0, EP_TX_NAK);
  F5 o5 u  V7 z7 s. o      SetEPR_RXStatus(ENDP0, EP_RX_VALID);
; Z7 J6 `. D( k, D- x: A    }   
2 D" l* a+ T( {! [    break; 3 ?7 ]  y% z: S5 `1 K
      9 R  ~0 T$ ]* r' `6 s
  case CS_SET_ADDRESS: ) q1 E1 V8 h5 K& _- d3 W2 M
    SetEPR_TXStatus(ENDP0, EP_TX_NAK); - _9 Y* h. F. P5 F3 f
    SetEPR_RXStatus(ENDP0, EP_RX_VALID); 3 M: H9 K$ C* _8 _9 v6 d: J2 U
3 D- p: T8 a' z2 b
    SetDADDR(0x0080 | vsDeviceInfo.bDeviceAddress);
& S2 g9 A5 k# J, q- r$ i: F* i    vsDeviceInfo.eDeviceState = DS_ADDRESSED;    6 f6 c2 K) t5 `' [3 c- ]
    break; 8 N. l( g, p- G' y0 l4 D, Y
. n: c' x( E2 W4 `2 ?# m! W9 N2 `
  case CS_SET_CONFIGURATION: , g/ C0 N# Y7 [, F$ H2 R' {; U
    SetEPR_TXStatus(ENDP0, EP_TX_NAK); 7 b2 g5 h4 }) x2 P2 ?
    SetEPR_RXStatus(ENDP0, EP_RX_VALID);
% x9 D" M, s! h. `
# M$ {; b& ]7 s* ^0 q( x% c- x    vsDeviceInfo.eDeviceState = DS_CONFIGURED;
6 x+ A. v1 ^3 V    break;
) q# [! {% B) N2 [/ W2 y  & H, X% k' T# s/ ~- }. N- g# ^
  default: . K# g( n6 p6 X: j- V
    break; 8 [; R/ P8 E$ S2 H8 _( N
  }
; j% M/ ^/ f0 f} 0 m) I) C' o4 |' S/ _/ c
再这如果响应GET_DESCRIPTOR请求发送的数据如果全部发送完毕,SETUP0_TransData()返回RESULT_SUCCESS,并设置TX状态为NAK;否则返回RESULT_LASTDATA,将继续发送剩余的数据直到数据全部被发送。至此,整个的GET_DESCRIPTOR请求过程完成。
& A2 E' i' n  H! v5 Q5 k' R2 m0长度的数据请求在发送0长度数据响应后,因为不存在可能还未传送的数据,因而IN事件后直接结束此次请求。
! R8 A2 h* y3 n( F% R  d+ t5 V在数据方向为USB主机->USB设备时,如果正确接收到数据,将响应CTR_OUT0()函数,处理过程类同CTR_IN0()函数。
7 C5 {7 n+ Z0 i' ~6 N4 A( ]在USB设备的枚举过程中,USB的一些描述符数据结构需要了解,具体在USB协议中有详细的说明,在usb_desc(.c/.h)文件中,定义了这些结构,这些结构是特定的: 8 p( A8 E# A; m; I- m4 ~! ~
! ^' X' H8 F2 Q) o. K1 K( |" _4 j
设备描述符:长度、格式固定,其中VENDOR_ID与PRODUCT_ID决定上位机驱动的识别。设备分属类别决定了设备的性质,如果为自定义USB设备,设备分属类别值为0,同时上位机驱动必须配合编写;如果为标准USB设备,则必须使用这些标准设备的驱动、数据结构等等,条件是你必须了解这些标准设备的一些信息,好处是省去一些麻烦的驱动编写。 $ k6 b" U& d+ t- v. K" K) B
const unsigned char cbDescriptor_Device[DESC_SIZE_DEVICE] = & N5 ?3 \" U2 T5 o. ~& L6 v: [4 T9 B/ p
{ # z. b  t; E' E( ^4 m+ v+ t( F9 u
  DESC_SIZE_DEVICE,     // bLength: 18 $ j  }& N- n$ t( _/ Z: |5 g$ ^
  DESCRIPTOR_DEVICE,    // descriptor type
" C/ G; m! A  |! X2 l) ?/ O+ G4 Z0 b/ d% N0 C4 d) _$ P! A
  0x00,            // bcdUSB LSB: USB release number -> USB2.0 : R9 u0 P6 {5 N9 @& j
  0x02,       // bcdUSB MSB: USB release number -> USB2.0
  z( U' J$ K& ^5 J( d6 S: p
. |) m9 T* A9 B4 h) s7 a  0x00,         // bDeviceClass:    Class information in the interface descriptors . J1 E' i3 `9 \7 F. ^2 P5 }
  0x00,       // bDeviceSubClass:   E) j, M1 @& M1 P8 |- O
  0x00,       // bDeviceProtocol: & v+ v, u( T- a6 q$ p
  0x40,       // bMaxPacketSize0:  LowS(8), FullS(8,16,32,64), HighS(64) + L( L# D* r# R* b3 F  F# F

) v' E% ~* C& p' b6 d$ F: O  LOWORD(VENDOR_ID),       // idVendor LSB: 3 o4 e9 A5 n8 A
  HIWORD(VENDOR_ID),       // idVendor MSB:
  N& {8 F4 \2 O8 j& F. s7 P; x2 C9 H, S3 [% Y$ v  ?& A6 L
  LOWORD(PRODUCT_ID),      // idProduct LSB: ! R6 F+ H+ A7 U( `
  HIWORD(PRODUCT_ID),      // idProduct MSB:
( n( }& C8 M! `( E" ]# q( r0 z
9 Y% }7 J+ ~# K' b* F6 N$ t. _7 n  LOWORD(DEVICE_VERSION),  // bcdDevice LSB:
" @/ |( g5 Q, v# x% ~  HIWORD(DEVICE_VERSION),  // bcdDevice MSB: 8 j  \# P! S& ^5 G, J
+ A. a# A9 @: q; B7 W' R5 d
  0x01,       // iManufacturer: Index of string descriptor describing manufacturer
' j& p4 I+ q: V/ u  0x02,       // iProduct: Index of string descriptor describing product
% i/ o0 j1 Y3 Y: [# A! f) H) Y  0x03,       // iSerialNumber: Index of string descriptor describing the device serial number
0 q: i' `4 Z1 m! d8 W& T
9 b3 [6 D# }. K% R# E2 k  0x01        // bNumConfigurations: number of configurations ' Y+ b2 t& ~8 q, q+ f
};
0 ?+ V. G; R* x; P1 D4 t* c- R4 S9 u5 j
配置描述符:前9个字节格式固定,后面紧跟的各种描述结构跟实际配置有关,每增加一种描述结构,该描述结构的第一字节说明了结构的长度,第二直接说明了结构的类型。在配置描述符中一般包含配置描述、接口描述、端点描述,如果需要同样可增加自定义的描述。使用标准USB设备类别时,配置描述符的结构也必须满足此类标准设备的数据结构。
* c# B# O+ [& V$ c& T5 q3 R' iconst unsigned char cbDescriptor_Config[DESC_SIZE_CONFIG] = / k/ D/ n' r: l5 W2 d" O
{
! p* x, M3 p4 E3 E( `) R  // Descriptor of configuration 6 o( p. c0 \' K' o3 ]
  0x09,                   // lengths   
" C* i3 _6 e# P8 m  ?  DESCRIPTOR_CONFIG,      // descriptor type
- o9 X$ A5 y2 I2 _% q
6 n" h: ~9 b9 v# j  DESC_SIZE_CONFIG,       // Total configuration descriptor lengths LSB ) }- Z9 }" d6 x7 d# f% q6 x9 J
  0x00,                   // Total configuration descriptor lengths MSB
- U  @3 Q6 _. C) J$ t( L
6 h! R1 n0 f( ]7 Z& N$ A6 }3 @  0x01,       // bNumInterfaces: Total number of interfaces # K, z5 q& A) v- @7 a) i
  0x01,       // bConfigurationValue: Configuration value
/ p9 Y7 F5 M+ e  0x00,       // iConfiguration: Index of string descriptor describing the configuration 6 V* K5 n5 X  ]. \' o
 
: W7 |2 O1 \! G" @2 ?% w" K" s1 T  0xA0,       // bmAttributes: bus powered
* R) ?" W; D: ~- r                        // bit 4...0 : Reserved, set to 0 4 `: ]1 U. ]* m+ ~6 ^
                        // bit 5     : Remote wakeup (1:yes) ( |' H2 }: r4 {6 C+ q3 T' v+ [0 v
                        // bit 6     : Self power (1:yes) * e( Q! x2 s  s. P
                        // bit 7     : Reserved, set to 1 6 \8 W) d& s7 [9 X
8 c1 v3 i% N" }; X) g' G0 k
  0x32,       // bMaxPower: this current is used for detecting Vbus = 100mA . R5 L8 ?, K, J$ L- L

5 J; b1 Z! Q6 e9 i/ O4 }# e7 M9 T0 w( O+ [- b/ y7 |1 T0 Z8 m# @5 j
  // Descriptor of interface
* K1 f4 W% ~% R2 M! h  0x09, $ v( q& j6 a( r0 ?9 _1 W/ F
  DESCRIPTOR_INTERFACE,
% }- ^# o# ]% S: a6 D6 u) e; L  [  Z- q2 q; N6 ?
  0x00,       // bInterfaceNumber: Number of Interface ) B7 o# x3 o* S- N1 ]
  0x00,       // bAlternateSetting: Alternate setting + U! K  S. I& o2 d0 I

, W+ j8 }9 p  y- p! m# E4 A- z  0x02,       // bNumEndpoints: Number of endpoints except EP0 ; _% Z, H; g* r- y# A
  0x00,       // bInterfaceClass: % k5 [& a5 O% z5 ]
  0x00,       // bInterfaceSubClass: " ?5 P8 i0 y+ Z- [, V' y! X) I' ]
  0x00,       // nInterfaceProtocol: 0 g# K; s8 `8 i# q& f

3 j: d  s; |! c5 v  `  0x00,       // iInterface: Index of string descriptor describing the interface , P- x  v3 e+ M$ q7 h4 }; g

3 m# S4 [7 o0 N6 S, {) j# c: o+ O+ G
  // Descriptor of endpoint1 OUT
* O" }0 O9 G6 T9 F0 r* x8 }% ]; `" _  0x07, / y! F) p: P7 z; n3 j
  DESCRIPTOR_ENDPOINT,
, z$ h5 d7 l3 y
* K( A4 `8 _. w; T- ]3 W$ u3 d  0x01,       // bEndpointAddress + b( c" f" i. I
              // bit 3...0 : the endpoint number
5 c$ i) f3 K, q# X" c              // bit 6...4 : reserved
5 t8 i4 y7 Z0 s. c, f3 X2 v              // bit 7     : 0(OUT), 1(IN)
; b2 W/ P- }# f9 ~8 e2 F
- N6 a; L$ v1 G4 u; P! m$ w  0x03,       // bmAttributes
  f2 v+ u' E0 `" R              // bit 1...0 : Transfer type 0 E3 m( F  b" m9 r
              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT)
: k5 h( t5 D3 Q% |% n2 G: Y' v              // bit 3...2 : Synchronization type
0 X! K" T, N* t' n2 _              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous)
* y, c  Y5 Y1 g7 [2 T              // bit 5...4 : Endpoint Usage type
9 Z7 l4 a% k3 Q% g              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved) 0 \& y; o) V, c; i6 v
              // bit 7...6 : Reserved, must be zero
2 v% `3 E+ s5 E7 H: ~/ m) `8 x6 {  d/ J; w
  0x40,       // packet size LSB
* d4 p# b( H7 b! N* `  0x00,       // packet size MSB
* g/ A, v/ F1 ~8 g7 S# R/ a3 g. U2 _. C6 x1 U7 |" s7 Q6 M$ g1 V: q3 X
  0x20,        // polling interval time: 32ms
, N% [* }; J- _  w( D' e, r
! {/ P, \, J* c, k  // Descriptor of endpoint2 IN
  k& m9 _" x& o1 G0 t$ e  0x07, ; n$ X9 k* h7 G) P# y! Z
  DESCRIPTOR_ENDPOINT, & t1 m3 u4 a7 k

6 J  t" B! W9 b  0x82,       // bEndpointAddress
& N2 J2 j, u# C              // bit 3...0 : the endpoint number
. n( D9 h0 @% n2 s9 J* r              // bit 6...4 : reserved
) _; J7 L' Z+ m1 m              // bit 7     : 0(OUT), 1(IN) 4 [4 I( Y, H) K. N. P9 j

) m( c1 b5 t' z8 D; v# I/ a  0x03,       // bmAttributes
/ X  V8 I* G: y              // bit 1...0 : Transfer type
( h$ _# [; O% X7 W# l$ y              //                00(CONTROL), 01(ISOCHRONOUS), 10(BULK), 11(INTERRUPT)
1 Y- W4 f  Z7 ?) W+ y- J) X4 q9 E              // bit 3...2 : Synchronization type ) l$ P1 X. P) u: w. R4 |4 {
              //                00(No Synch), 01(Asynchronous), 10(Adaptive), 11(Synchronous)
0 _' y" x# Z$ R1 e$ @; @, r$ B# u" C              // bit 5...4 : Endpoint Usage type
+ z6 v( @& b5 [5 b: i              //                00(data), 01(Feedback), 10(Implicit feedback data endpoint), 11(Reserved)
* K. ~; H0 V( m              // bit 7...6 : Reserved, must be zero % ?( N( i. e/ y: p# L5 S

, F# P) w& o9 t, H' P* X: A1 h  0x40,       // packet size LSB + n( ~! R  L- B6 Q2 U7 F* ?
  0x00,       // packet size MSB & z2 L& e3 e; x0 N

2 z4 j  E- K; r  X  O  0x20        // polling interval time: 32ms / ^% o) w3 Z4 H
}; 1 k; c1 Y& E# E' c) F% b! V

  j+ N( g5 R4 b" S字符串描述符:定义了与设备有关的一些信息,常见的为以下四种,如果有需要,同样可以定义自己的字符串描述符。 0 c8 Y; @; Z9 T5 ^
const unsigned char cbDescriptor_StringLangID[DESC_SIZE_STRING_LANGID] = ; {, Z. e9 E! `/ e2 d% h' I( u9 A
{
4 I0 [/ U/ ]- r  n) q  DESC_SIZE_STRING_LANGID,  // bLength
' y- d+ d  Q& ~  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor * d1 D# l1 R6 U( f" D* W
   
% x8 v7 s+ A" i+ ~) t6 R5 d- h( g  0x09,                                  // LangID LSB:
- _  y' C0 I: x  0x04                                  // LangID MSB: 0x0409(U.S. English)
  U( u+ x5 h$ W}; + d* V% W+ w, v9 Z9 V& y! r+ k: k$ X

; E& x* R+ Z& s2 N2 E8 oconst unsigned char cbDescriptor_StringVendor[DESC_SIZE_STRING_VENDOR] =
& z- s0 }8 z2 w' U2 v9 u8 K; t{ % O& h5 y! G( R7 k% v
  DESC_SIZE_STRING_VENDOR,  // bLength " S0 q! u& t# N8 j  Q7 }5 p+ q
  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
/ `& I2 n0 `& n7 V/ U1 o2 M" J4 l  C8 \$ C$ ^4 w- r
  // String: "LaBiXiaoXiaoXin"
3 H7 Z1 v* Q& _) Y8 e- H, ]  'L',0, 'a',0, 'B',0, 'i',0, 'X',0, 'i',0, 'a',0, 'o',0,
% [6 ^) T, x9 O9 v   'X',0, 'i',0, 'a',0, 'o',0, 'X',0, 'i',0, 'n',0
) `' K8 F" d: D/ o9 y};
" h. H1 l( z: ~+ j# A/ C0 \( ?5 b1 _1 n( u8 x* K# _) [5 @
const unsigned char cbDescriptor_StringProduct[DESC_SIZE_STRING_PRODUCT] =
( L2 u, }. ?5 M: A{ : |' p. w( `  T- S0 S
  DESC_SIZE_STRING_PRODUCT, // bLength
# C5 X9 s7 n, K) a1 \1 O$ _3 j: h  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor
  y  d/ p  o1 a1 J
3 f4 x% Z) o) W6 |    // String: "STM32 ezUSB-CORE V1.01"
% K8 r( \; p- o8 p  'S',0, 'T',0, 'M',0, '3',0, '2',0, ' ',0, 'e',0, 'z',0, 'U',0, 'S',0, 'B',0,
9 ^* [1 B, {8 T2 Z- X  '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0, 'V',0, '1',0, '.',0, '0',0, '1',0 9 U% x' A# m& D5 G
};
5 x1 e- \# ?( l8 H. R* @- G& V
" x9 p3 J+ n: f+ A+ Rconst unsigned char cbDescriptor_StringSerial[DESC_SIZE_STRING_SERIAL] = 6 v/ w; n) u8 y" j1 g1 v
{ : \# w; q+ N1 q
  DESC_SIZE_STRING_SERIAL,  // bLength
( y! X8 t9 P, y- \  W  DESCRIPTOR_STRING,        // bDescriptorType = String Descriptor ( Z* L5 l1 P7 L
( M+ V) \1 ^. C) a. W, ~
    // String: "ezUSB-CORE Demo 2008/11/18" # p9 l- W+ k0 r* q
  'e',0, 'z',0, 'U',0, 'S',0, 'B',0, '-',0, 'C',0, 'O',0, 'R',0, 'E',0, ' ',0,
% R, f2 |/ Q3 P) g4 C5 ?9 q  '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 9 j  `" ?, k# p, N4 @/ n6 m
};
8 ^) l( I% k. s& H+ G# [) r( G) u( C6 w$ D0 v4 p8 a
了解这些描述符的用法以及作用,最好的方法的是编写自定义的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 手机版