|
lbxxx原创 3 [ g( O: ~& ]/ p# B , J6 y' |3 u1 f0 w. z; | / \" c. M }+ [, B 基于STM32的USB程序开发笔记(一) - R, E& i+ ^0 }- X V/ u5 {' X5 P 5 i5 E: _) U/ t# @ 第一篇:需要准备的一些资料 1:STM32的参考手册,这对于设备底层USB的硬件配置以及事件驱动机制的了解尤为重要,你需要了解各个寄存器的功能以及如何操作,比如CNTR、ISTR、EPnR、DADDR等等,如果你想学习USB,这个手册是必须的。 2:USB2.0 协议,这个资料同样必不可少,如果因为英语阅读能力而苦苦寻找中文版的USB2.0协议,建议不要这么做,现在网络中的所谓的中文版的USB2.0协议不是官方撰写的,大多数是一些热心朋友自己翻译的,却不是很全面,如果你在为寻找这类的资料而无所获时,建议认真塌实的看看官方英文版的USB2.0协议,官方协议阐述的十分详细,650多页,一字一句的了解全部协议不太可行,可针对性的重点理解,比如对第9章USB Device Framework的详细理解对于你的USB Device固件开发不可缺少(这里就是STM32)。 3:ST提供的USB固件库,这个类库较为散乱,但不可不参考 k6 v8 L( a, E 以下是最近这段时间的成果,包含固件、驱动以及应用程序,固件部分有些功能是不被支持的,如SR_SetDescriptor()、 SR_SynchFrame()等等,在此说明战士不支持非故意如此,而是还没时间仔细深入编写完善,因为这些目前不被支持的部分目前不被使用到。 * b5 T: H% ?% C% D/ t6 P 后序将接着对各个部分进行一些说明,希望朋友们多多支持,同时欢迎朋友们讨论。 2 m/ S1 a8 t* P2 B: T 如果你使用的是万利的STM3210B-LK1开发板,则可以烧写hex文件后进行测试。 下载该文件请参阅: http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=1808061&bbs_page_no=1&bbs_id=3020 2 s! v) |2 H! B2 t) f0 x0 A1 M# G 6 X- V- ~! V6 _) |& Y5 \$ e 第2篇:STM32 USB固件函数的驱动原理 7 j, ]; d9 }9 _: _) @ 首先需要了解一个概念: 9 S! O( }. X( \" a USB 设备(DEVICE)从来只是被动触发,USB主机(HOST)掌握主动权,发送什么数据,什么时候发送,是给设备数据还是从设备请求数据,都是由USB 主机完成的,USB设备只是配合主机完成设备的枚举、数据方向和大小。根据数据特性再决定该不该回复该如何回复、该不该接收该如何接收这些动作。 了解这些,再仔细查看STM32的参考手册USB部分以及STM32的中断向量表,从中可以找到两个中断: 4 ?; q) C+ ?( q1 ?0 v- }$ x /******************************************************************************* * Function Name : USB_HP_CAN_TX_IRQHandler ) N2 p$ n [ }. h- D2 Z, ^1 w$ W8 u * Description : This function handles USB High Priority or CAN TX interrupts l; ~% ]' t$ u6 C: r * requests. , U5 o+ G8 u p- G* N * Input : None 3 J J, A B0 i% y) _( \1 l* w- R4 S * Output : None * Return : None *******************************************************************************/ void USB_HP_CAN_TX_IRQHandler(void) { USB_HPI(); } 4 x; t! o1 C% v" v S /******************************************************************************* * Function Name : USB_LP_CAN_RX0_IRQHandler g, g% ^7 E8 C * Description : This function handles USB Low Priority or CAN RX0 interrupts * requests. 8 U' |+ l. q$ m3 R$ K0 s+ S * Input : None & n2 e( K6 q+ z$ c9 ^6 Y * Output : None ; p$ f" E, a) k0 O5 }3 o& F; R * Return : None + L% m$ X+ x5 v- M# ] *******************************************************************************/ " x& s e6 {) _9 d: a' T void USB_LP_CAN_RX0_IRQHandler(void) 4 t" L+ v6 P' x& `: T# Q; J5 I8 Z { " ~/ |3 W, R% A! y2 t USB_LPI(); } $ X6 ?" |- ?9 X; S2 N 即 USB的高、低优先权中断处理函数,这也是整个STM32 USB的事件驱动源,USB_HPI()与USB_LPI()既而转向usb_core(.c,.h)进行相关处理。中断传输(interrupt)、控制传输(control)、大流量传输(bulk)由USB_LPI()响应,大流量传输(bulk)同样可能响应USB_HPI(),同步传输 (isochronous)只响应USB_HPI()。 $ I1 y( |+ I* u: w$ h5 q+ R 这样响应USB的所有请求只需要关注usb_core.c文件中的 USB_LPI()与USB_HPI()函数。由于本人也是对USB刚刚有所了解,因而在本例笔记中USB_HPI()函数未做任何处理,在此开源希望大家能完善与纠正错误并能共享喜悦。以下是USB_LPI()函数: 0 J. l( E. |9 e1 r u4 o0 s5 r7 u! E, J // ***************************************************************************** 3 s* _: {+ b# |2 z' x // Function Name : USB_LPI. / E! K& [7 K# \7 U- F# s // Description : Low Priority Interrupt's service routine. 4 p) y" A% x, j/ D // Input : // Output : 3 n1 m) G- k0 M& {/ |5 w' g2 V! } // Return : // ***************************************************************************** void USB_LPI(void) ) E+ m x0 K1 t W { unsigned short wValISTR = GetISTR(); #if(CNTR_MASK & ISTR_RESET) // Reset if(wValISTR & ISTR_RESET & vwInterruptMask) 4 M3 h% b9 g6 P: H; }2 z! { { SetISTR(CLR_RESET); INT_ISTR_RESET(); 6 l" P" y% V4 \' g8 B9 g } % s3 m$ Z1 R3 z #endif 0 {/ P o* A2 S #if(CNTR_MASK & ISTR_DOVR) // DMA Over/Underrun ; }+ @' j8 k! Y) }0 D if(wValISTR & ISTR_DOVR & vwInterruptMask) k/ k3 Y9 C5 H8 F/ `. K& K, c' @ { SetISTR(CLR_DOVR); INT_ISTR_DOVR(); } 6 |' y# M% k* r4 x* n #endif $ _" B } Z1 { | #if(CNTR_MASK & ISTR_ERR) // Error if(wValISTR & ISTR_ERR & vwInterruptMask) ; F& a; F6 ]3 T) b- r3 K4 [6 ^ { SetISTR(CLR_ERR); INT_ISTR_ERROR(); } % M7 f& u7 l0 L: P7 R- E #endif 0 e* O& @& i$ I# l( y #if(CNTR_MASK & ISTR_WKUP) // Wakeup if(wValISTR & ISTR_WKUP & vwInterruptMask) { ' m. c: _# [) g% f& H SetISTR(CLR_WKUP); INT_ISTR_WAKEUP(); } #endif * L- c7 e* t- ^% p% L #if(CNTR_MASK & ISTR_SUSP) // Suspend 7 v9 m5 D6 ], K) l, H1 W* z* z if(wValISTR & ISTR_SUSP & vwInterruptMask) { ! Y, T' {+ u0 f: X INT_ISTR_SUSPEND(); SetISTR(CLR_SUSP); // must be done after setting of CNTR_FSUSP } + Q' z8 f% c: J8 m! }/ A #endif " W3 @& I/ s% m5 u #if(CNTR_MASK & ISTR_SOF) // Start Of Frame if(wValISTR & ISTR_SOF & vwInterruptMask) { - l7 u+ [ q; w7 O' P! Y& ] SetISTR(CLR_SOF); INT_ISTR_SOF(); 1 X) h. k8 @2 u! Q& j9 o% P. L } 6 c2 E) h/ x, x #endif + b! n) `1 A! C0 A0 |" T& }# u5 e #if(CNTR_MASK & ISTR_ESOF) // Expected Start Of Frame / Q& c9 t- b6 B if(wValISTR & ISTR_ESOF & vwInterruptMask) 7 b5 T4 ^8 V' z { SetISTR(CLR_ESOF); INT_ISTR_ESOF(); } #endif 0 r. ^# R& v( c' r+ |! } $ W0 d; w8 Y3 d+ J9 P- e #if(CNTR_MASK & ISTR_CTR) // Correct Transfer & \4 n- s5 s) K% K. n2 f( O if(wValISTR & ISTR_CTR & vwInterruptMask) { 0 n" p( Q* j, [( Z. j2 f INT_ISTR_CTR(); } , A+ U( t- |. f5 m/ X- m C, M | #endif } ! O3 F) ]: g4 Z- V+ H 1 I+ i3 O0 `3 Y" d6 ` // ***************************************************************************** // Function Name : USB_HPI. // Description : High Priority Interrupt's service routine. // Input : // Output : - I6 Q3 D' u( F // Return : // ***************************************************************************** void USB_HPI(void) { , {6 V- `/ `* j& x* z( ]0 ~ } 1 v2 V/ j6 c5 _2 x# | 可以看出,在USB_LPI()函数中,根据STM32 USB的中断状态寄存器(ISTR)的标志位的状态以及定义的USB控制寄存器中断事件屏蔽码,响应各自的中断事件,比如 INT_ISTR_RESET()响应USB的复位中断,一般可在此函数内进行USB的寄存器的初始化;INT_ISTR_CTR()响应一次正确的数据传输中断,故名思意,在完成一次正确的数据传输操作后,就会响应此函数。 + e# v" k( ~+ w( X) e8 O% N$ x 具体含义请仔细查阅STM32参考手册,下篇将针对这些响应函数进行逐一的详细介绍。 |
|
| 谢谢分享 |
最全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设计与实现
微信公众号
手机版