|
接着上篇,详细情况可以查看usb_core(.c/.h),STM32 USB中断事件为以下几种: / |: ~5 R/ t* Q! \9 a T" G9 f# q void ISTR_CTR(void); void ISTR_SOF(void); void ISTR_ESOF(void); ' h2 S4 _2 ^9 X) s3 E9 {6 ~ void ISTR_DOVR(void); void ISTR_ERROR(void); void ISTR_RESET(void); void ISTR_WAKEUP(void); void ISTR_SUSPEND(void); * K- x+ i* p# P, _( P( n$ N / P U2 d8 w# b6 {5 J. q 这些处理函数使能由定义CNTR_MASK决定: 6 [/ ?+ X2 p3 c% ^. n$ ~9 \. G // CNTR mask control ) ~( f+ F9 b$ e; M8 `* L #define CNTR_MASK CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM | \ ' K+ t9 z, a2 a9 y CNTR_SOFM | CNTR_ESOFM | CNTR_RESETM | CNTR_DOVRM \ 其中着重说明的是ISTR_RESET()和ISTR_CTR()函数,ISTR_RESET()主要处理USB复位后进行一些初始化任务,ISTR_CTR()则是处理数据正确传输后控制,比如说响应主机。 1 X" V1 \& B- p) t1 s ' p, N; D$ b' x" m) }! Y/ E // ***************************************************************************** : }7 n9 v* }5 u# W' D // Function Name : INT_ISTR_RESET // Description : ISTR Reset Interrupt service routines. $ i" o; m1 }$ ^ // Input : / L0 j( w" _# Y0 x // Output : // Return : // ***************************************************************************** 9 R! k; W; d) I3 n7 i; i void INT_ISTR_RESET(void) { # n4 y% P, W/ N // Set the buffer table address ; \; f+ L8 P e( P& B SetBTABLE(BASEADDR_BTABLE); % ^/ s4 X& \) c4 A1 O // Set the endpoint type: ENDP0 ' H' @. W. A& [+ T" ?0 R( n SetEPR_Type(ENDP0, EP_CONTROL); / m: G0 b- V r( ~5 C4 f. F Clr_StateOut(ENDP0); 4 y. E& [# X6 b% A" {# M9 c // Set the endpoint data buffer address: ENDP0 RX SetBuffDescTable_RXCount(ENDP0, ENDP0_PACKETSIZE); % @% }1 E9 n! T: V* O SetBuffDescTable_RXAddr(ENDP0, ENDP0_RXADDR); " H! A v! t- k/ F8 J // Set the endpoint data buffer address: ENDP0 TX SetBuffDescTable_TXCount(ENDP0, 0); SetBuffDescTable_TXAddr(ENDP0, ENDP0_TXADDR); // Initialize the RX/TX status: ENDP0 * `5 E8 [4 u. _7 q( m SetEPR_RXStatus(ENDP0, EP_RX_VALID); - Q0 N4 z$ u7 h' C6 p SetEPR_TXStatus(ENDP0, EP_TX_NAK); 5 y7 r/ A+ C0 b( |6 Q1 R . ]% V) _ F+ T; [& w2 m% w' I // Set the endpoint address: ENDP0 $ g1 p7 K; n+ ] SetEPR_Address(ENDP0, ENDP0); 0 V: r3 }* m9 @, S // --------------------------------------------------------------------- // TODO: Add you code here ' c; y! o2 T. H8 |2 ~9 i1 c& @ // --------------------------------------------------------------------- // Set the endpoint type: ENDP1 8 k) F" n4 |+ i3 Z9 | SetEPR_Type(ENDP1, EP_INTERRUPT); ( {( h. `2 Y* ^4 a Clr_StateOut(ENDP1); % t( U; a3 T, o+ C o7 \7 T // Set the endpoint data buffer address: ENDP1 RX SetBuffDescTable_RXCount(ENDP1, ENDP1_PACKETSIZE); ; i& G& h# S% ~& g( h SetBuffDescTable_RXAddr(ENDP1, ENDP1_RXADDR); # r# c( e- @3 A' s( v // Set the endpoint data buffer address: ENDP1 TX SetBuffDescTable_TXCount(ENDP1, 0); SetBuffDescTable_TXAddr(ENDP1, ENDP1_TXADDR); // Initialize the RX/TX status: ENDP1 SetEPR_RXStatus(ENDP1, EP_RX_VALID); SetEPR_TXStatus(ENDP1, EP_TX_DIS); // Set the endpoint address: ENDP1 , p6 J& w R- ~! A; Q" l! ]2 s SetEPR_Address(ENDP1, ENDP1); 3 z, C6 L8 \: f) k. ^ SetEPR_Type(ENDP2, EP_INTERRUPT); ( Z; s" g8 S8 T$ N7 \- T3 H Clr_StateOut(ENDP2); : X' Z+ U; L: \ // Set the endpoint data buffer address: ENDP2 RX 0 _" ]5 {6 ]0 D s SetBuffDescTable_RXCount(ENDP2, ENDP2_PACKETSIZE); SetBuffDescTable_RXAddr(ENDP2, ENDP2_RXADDR); 5 V) d/ P) l# x! y; G( p5 v) J // Set the endpoint data buffer address: ENDP2 TX SetBuffDescTable_TXCount(ENDP2, 0); SetBuffDescTable_TXAddr(ENDP2, ENDP2_TXADDR); # T7 d+ R6 r7 O1 N5 X: F- F // Initialize the RX/TX status: ENDP2 0 i$ w+ l4 @* n1 |/ v) T& b. A( d SetEPR_RXStatus(ENDP2, EP_RX_DIS); 7 T8 I' i& `) x- f SetEPR_TXStatus(ENDP2, EP_TX_VALID); ( q! x2 X9 t2 r+ l: R 3 P% W7 [. Z( k9 ]- V! |8 T // Set the endpoint address: ENDP2 SetEPR_Address(ENDP2, ENDP2); 8 @- j @7 E! c: c% ] - ?( N% a$ Y/ F/ ~8 C9 } // --------------------------------------------------------------------- // End of you code - e7 d' e1 C8 j: F. e7 {+ N1 z // --------------------------------------------------------------------- ; i5 b1 A4 n- m. g$ U9 s1 \% L SetDADDR(0x0080 | vsDeviceInfo.bDeviceAddress); vsDeviceInfo.eDeviceState = DS_DEFAULT; vsDeviceInfo.bCurrentFeature = 0x00; vsDeviceInfo.bCurrentConfiguration = 0x00; vsDeviceInfo.bCurrentInterface = 0x00; + N6 C* U: l( U( u* a vsDeviceInfo.bCurrentAlternateSetting = 0x00; vsDeviceInfo.uStatusInfo.w = 0x0000; + a% C+ X2 P1 N. J) F+ l } & w1 F! x- Y$ c: i: x6 M0 r 在这个ISTR_CTR()函数中,定义了EP0、1、2的传输方式以及各自的缓冲描述符,其中EP0是默认端口,负责完成USB设备的枚举,一般情况是不需要更改的。其他端点配置则需根据实际应用而决定,如何设置请仔细理解STM32的参考手册。 c" s6 s$ {7 z3 d+ W- _, E 值得说明的是STM32的端点RX/TX缓冲描述表是定义在PMA中的,他是基于分组缓冲区描述报表寄存器(BTABLE)而定位的,各端点RX/TX缓冲描述表说明是数据存储地址以及大小,这个概念需要了解,ST提供的固件很含糊,为此,我在usb_regs.h文件中进行了重新定义,如下: # ]5 G4 m+ K* T9 F& B; L6 ~4 U4 u) u // USB_IP Packet Memory Area base address #define PMAAddr (0x40006000L) [9 b; ^$ X4 f+ |2 S' | // Buffer Table address register : W$ s- }2 A6 d- F1 ^4 l1 a! [5 P #define BTABLE ((volatile unsigned *)(RegBase + 0x50)) // ***************************************************************************** // Packet memory area: Total 512Bytes 8 q2 l- J' r5 U. s7 B" S6 i7 S // ***************************************************************************** #define BASEADDR_BTABLE 0x0000 // ***************************************************************************** // PMAAddr + BASEADDR_BTABLE + 0x00000000 : EP0_TX_ADDR " _$ Z4 L# L" V0 L5 v) u* x8 L // PMAAddr + BASEADDR_BTABLE + 0x00000002 : EP0_TX_COUNT // PMAAddr + BASEADDR_BTABLE + 0x00000004 : EP0_RX_ADDR // PMAAddr + BASEADDR_BTABLE + 0x00000006 : EP0_RX_COUNT // + ^. `$ }! A9 k) |2 F5 z# t. f // PMAAddr + BASEADDR_BTABLE + 0x00000008 : EP1_TX_ADDR & n, _5 G9 y& }" T1 ]4 r, N // PMAAddr + BASEADDR_BTABLE + 0x0000000A : EP1_TX_COUNT * g. |" r1 q3 B! a // PMAAddr + BASEADDR_BTABLE + 0x0000000C : EP1_RX_ADDR // PMAAddr + BASEADDR_BTABLE + 0x0000000E : EP1_RX_COUNT // 6 g7 q& }6 X! B, U // PMAAddr + BASEADDR_BTABLE + 0x00000010 : EP2_TX_ADDR - h I* L7 L- T9 f) C5 F6 { // PMAAddr + BASEADDR_BTABLE + 0x00000012 : EP2_TX_COUNT // PMAAddr + BASEADDR_BTABLE + 0x00000014 : EP2_RX_ADDR % v5 c% v8 \ J; z9 N // PMAAddr + BASEADDR_BTABLE + 0x00000016 : EP2_RX_COUNT : U7 x2 C) _" _( K // // PMAAddr + BASEADDR_BTABLE + 0x00000018 : EP3_TX_ADDR % ^, n ?: C1 I // PMAAddr + BASEADDR_BTABLE + 0x0000001A : EP3_TX_COUNT // PMAAddr + BASEADDR_BTABLE + 0x0000001C : EP3_RX_ADDR // PMAAddr + BASEADDR_BTABLE + 0x0000001E : EP3_RX_COUNT // ; ?) l7 J5 |. i3 E- {) _6 f8 T$ B+ Z6 l // PMAAddr + BASEADDR_BTABLE + 0x00000020 : EP4_TX_ADDR // PMAAddr + BASEADDR_BTABLE + 0x00000022 : EP4_TX_COUNT // PMAAddr + BASEADDR_BTABLE + 0x00000024 : EP4_RX_ADDR 6 e- m) c+ T( T. e5 P) Q5 g+ r // PMAAddr + BASEADDR_BTABLE + 0x00000026 : EP4_RX_COUNT // 2 J3 L" r! n" ]) f7 H6 ^6 d // PMAAddr + BASEADDR_BTABLE + 0x00000028 : EP5_TX_ADDR 7 R+ j2 i" g7 W3 G // PMAAddr + BASEADDR_BTABLE + 0x0000002A : EP5_TX_COUNT $ ~, h7 f$ g$ J // PMAAddr + BASEADDR_BTABLE + 0x0000002C : EP5_RX_ADDR // PMAAddr + BASEADDR_BTABLE + 0x0000002E : EP5_RX_COUNT ) U1 I5 ~, i" S+ M // $ D% Z' Z: `( }5 o. z) h // PMAAddr + BASEADDR_BTABLE + 0x00000030 : EP6_TX_ADDR 5 h* g/ d" V9 T1 H+ ]5 D' U // PMAAddr + BASEADDR_BTABLE + 0x00000032 : EP6_TX_COUNT // PMAAddr + BASEADDR_BTABLE + 0x00000034 : EP6_RX_ADDR 4 E W( E& H5 K' g2 l9 z$ r: r // PMAAddr + BASEADDR_BTABLE + 0x00000036 : EP6_RX_COUNT // , R4 ?9 T5 E! h- s) n# w& L- s // PMAAddr + BASEADDR_BTABLE + 0x00000038 : EP7_TX_ADDR // PMAAddr + BASEADDR_BTABLE + 0x0000003A : EP7_TX_COUNT // PMAAddr + BASEADDR_BTABLE + 0x0000003C : EP7_RX_ADDR // PMAAddr + BASEADDR_BTABLE + 0x0000003E : EP7_RX_COUNT // ***************************************************************************** / C+ N$ a- l5 ~ D // // PMAAddr + BASEADDR_BTABLE + (0x00000040 - 0x000001FF) : assigned to data buffer & y; ]/ v' [4 G% Q, d8 B# s6 f5 [ // 3 m( @& y) l. p. F // ***************************************************************************** - c" t2 @1 z) n$ A #define BASEADDR_DATA (BASEADDR_BTABLE + 0x00000040) 3 j4 ?" f. [& ]8 I // ENP0 2 k: k$ X1 E7 Z) c# g( p$ b #define ENDP0_PACKETSIZE 0x40 #define ENDP0_RXADDR BASEADDR_DATA #define ENDP0_TXADDR (ENDP0_RXADDR + ENDP0_PACKETSIZE) 6 I+ x2 @8 ]% d% }' Z // ENP1 #define ENDP1_PACKETSIZE 0x40 3 B* [. L# n& i5 W #define ENDP1_RXADDR (ENDP0_TXADDR + ENDP0_PACKETSIZE) 5 J2 n; c0 f1 j9 j* i. W: f2 x #define ENDP1_TXADDR (ENDP1_RXADDR + ENDP1_PACKETSIZE) - e- H' Q) Z' d# }0 \8 R1 l& E // ENP2 1 W$ ?- Y+ B: W+ h, G" J% p q #define ENDP2_PACKETSIZE 0x40 3 d) k% r* n* u! k #define ENDP2_RXADDR (ENDP1_TXADDR + ENDP1_PACKETSIZE) 4 ]3 c( Q- j a) g" U #define ENDP2_TXADDR (ENDP2_RXADDR + ENDP2_PACKETSIZE) // ENP3 #define ENDP3_PACKETSIZE 0x40 #define ENDP3_RXADDR (ENDP2_TXADDR + ENDP2_PACKETSIZE) #define ENDP3_TXADDR (ENDP3_RXADDR + ENDP3_PACKETSIZE) ! @3 ?/ v+ H% v; [) |: ` // ENP4 #define ENDP4_PACKETSIZE 0x40 * o" q" f, S2 _ #define ENDP4_RXADDR (ENDP3_TXADDR + ENDP3_PACKETSIZE) #define ENDP4_TXADDR (ENDP4_RXADDR + ENDP4_PACKETSIZE) 8 ^3 L$ t$ l6 J" @ - d c- j9 W: ?; F$ O5 G; p // ENP5 4 T( W9 y7 a5 b G% t #define ENDP5_PACKETSIZE 0x40 #define ENDP5_RXADDR (ENDP4_TXADDR + ENDP4_PACKETSIZE) #define ENDP5_TXADDR (ENDP5_RXADDR + ENDP5_PACKETSIZE) % ^! H. q3 f k; {0 L$ S 2 A! N' b. {# J5 h- L" }3 m& E // ENP6 #define ENDP6_PACKETSIZE 0x40 #define ENDP6_RXADDR (ENDP5_TXADDR + ENDP5_PACKETSIZE) $ M7 O) F( e* d' V #define ENDP6_TXADDR (ENDP6_RXADDR + ENDP6_PACKETSIZE) ) K P) y& ^5 B: d: T // ENP7 #define ENDP7_PACKETSIZE 0x40 #define ENDP7_RXADDR (ENDP6_TXADDR + ENDP6_PACKETSIZE) #define ENDP7_TXADDR (ENDP7_RXADDR + ENDP7_PACKETSIZE) 1 f: o: t# [, X+ y. E, w/ C 0 x) q+ J5 y: Q5 O* t* o 这样,一般只要在PMA的大小区域内(512Bytes),修改端点EPnR的数据包大小就可以了,当然,实际情况可以根据需要进行更改。 0 |6 L% N, e6 ` + Y( t/ V/ H* m/ j 9 D+ k3 s4 n3 x. L# T" M$ C // ***************************************************************************** 9 P* K+ @6 L. [( u // Function Name : INT_ISTR_CTR * r# _8 Y8 Y. g- P: ^- p& U // Description : ISTR Correct Transfer Interrupt service routine. // Input : // Output : $ ^0 G$ t! y6 ~ // Return : // ***************************************************************************** * H% a/ _/ {% r void INT_ISTR_CTR(void) 4 i% {5 m( r+ {; ~. Y { 7 C/ [1 y" m7 b e8 t' s unsigned short wEPIndex; + j! K1 z* A* Q$ X5 ]0 D6 l unsigned short wValISTR; unsigned short wValENDP; * V5 b; I! N# G' L while( ((wValISTR=GetISTR()) & ISTR_CTR) != 0 ) { // Get the index number of the endpoints ; q! l# O [6 {: K S2 }" _7 g wEPIndex = wValISTR & ISTR_EP_ID; , ]& k6 J, T* [9 d7 T3 u3 M9 a if(wEPIndex == 0) { + J, g6 |4 D# ` L% j0 ~& X6 o // Set endpoint0 RX/TX status: NAK (Negative-Acknowlegment) " E+ l& @& m) }- A8 ^6 G- {8 V! W SetEPR_RXStatus(ENDP0, EP_RX_NAK); SetEPR_TXStatus(ENDP0, EP_TX_NAK); - R, @. P/ [* w // Transfer direction if((wValISTR & ISTR_DIR) == 0) ( Z0 i, M! K+ J! Y0 w% A9 P: \ { // DIR=0: IN * K, s+ z& t: X1 R2 j // DIR=0 implies that EP_CTR_TX always 1 ClrEPR_CTR_TX(ENDP0); CTR_IN0(); 3 ^/ X2 v" a/ b# s( f7 n return; } else { // DIR=1: SETUP or OUT // DIR=1 implies that CTR_TX or CTR_RX always 1 5 O$ I* m% n+ K( ? wValENDP = GetEPR(ENDP0); ' O/ c5 B! @* ]6 Q& U' z$ U if((wValENDP & EP_CTR_TX) != 0) k9 L" `" l' _: Q1 t. K { + R9 I9 t# ?6 S1 n! T8 N ClrEPR_CTR_TX(ENDP0); CTR_IN0(); return; + w' g' P3 ~ S& v/ _ I } $ M# h/ C2 o3 @: e2 b, d- E else if((wValENDP & EP_SETUP) != 0) 7 G6 h6 B5 a' |+ ?7 F { ClrEPR_CTR_RX(ENDP0); ( _" Z g) M/ g CTR_SETUP0(); return; ( v) I4 ]9 a- M& e M, W6 t } else if((wValENDP & EP_CTR_RX) != 0) { ClrEPR_CTR_RX(ENDP0); ! ]- L) ^. ~% }0 I2 x: c CTR_OUT0(); return; ' w+ v; A- S$ O. G, j5 @ } 0 }- ~% H2 f/ C8 Z9 ~! q3 I } . V$ { g6 l5 u! m6 G3 z; Q0 q } // Other endpoints else { wValENDP = GetEPR(wEPIndex); , v3 n5 f1 Y0 B6 ~% D SetEPR_RXStatus(wEPIndex, EP_RX_NAK); 5 \! D1 V( F4 N% R K5 H SetEPR_TXStatus(wEPIndex, EP_TX_NAK); if((wValENDP & EP_CTR_TX) != 0) 5 Q( Z0 z" [2 F' s i% v( W { ClrEPR_CTR_TX(wEPIndex); switch(wEPIndex) ; N J1 h* F5 V8 A" b { # o$ x" i4 T6 [) P" H9 J0 s case ENDP1: CTR_IN1(); break; 3 c9 H1 _/ J) A; s; T3 a case ENDP2: CTR_IN2(); break; case ENDP3: CTR_IN3(); break; & c, v: r3 d4 x" P' q: ?/ O% z3 j case ENDP4: CTR_IN4(); break; case ENDP5: CTR_IN5(); break; case ENDP6: CTR_IN6(); break; case ENDP7: CTR_IN7(); break; ' f; M8 k8 f- L# I- C& s9 ~ default: break; } # }* x' o- q5 e1 J1 F* _ } , E$ ~6 `( N* q \9 }& u ) p4 F, Q8 ~. k8 B- J if((wValENDP & EP_CTR_RX) != 0) { ClrEPR_CTR_RX(wEPIndex); switch(wEPIndex) M2 s" c, Q% o$ K3 R. x' W# O/ W { 8 k( x e7 F. p case ENDP1: CTR_OUT1(); break; case ENDP2: CTR_OUT2(); break; 5 K9 z* Y" I: f1 m. N case ENDP3: CTR_OUT3(); break; case ENDP4: CTR_OUT4(); break; case ENDP5: CTR_OUT5(); break; ' @ l3 J! E2 j- ^ case ENDP6: CTR_OUT6(); break; case ENDP7: CTR_OUT7(); break; default: break; } } } 3 f. Z6 F) N% V7 u) ~ } } INT_ISTR_CTR()函数将各自响应事件提取出来,默认端点EP0也是最为复杂的,这个需要查看STM32的参考手册以及USB协议才能更好了解为何如此。到这里STM32 USB里数据传输事件就指向了各个对应的端点。下篇着重说明USB设备的枚举。 |
最全USB HID开发资料,悉心整理一个月,亲自测试
【源码】STLINK-V3MINI 高速USB仿真器,成功改刷【高速CMSIS-DAP】
STM32 USB CDC 虚拟多串口
实战经验 | 选择USBX模块生成USB CDC ACM无PD的项目
STM32 USB HID键盘例程
刘氓兔的杂谈【001】-片上USB 高速PHY
【经验分享】在进行 USB CDC 类开发时,无法发送 64整数倍的数据
在线直播|无需编写任何代码即可在STM32上实现USB-C Power Delivery
圈圈发布USB图书第二版有感,以及分享一些我学习USB过程...
USB Audio设计与实现
微信公众号
手机版
回复:基于STM32的USB程序开发笔记(三) ——STM32 USB固件函数的一些介绍