|
串口调试在项目中被使用越来越多,串口资源的紧缺也变的尤为突出。很多本本人群,更是深有体会,不准备一个USB转串口工具就没办法进行开发。本章节来简单概述STM32低端芯片上的USB虚拟串口的移植。在官方DEMO中已经提供了现成的程序,这里对修改方法做简单说明。
5 `3 h" {9 L5 O7 v; Y8 i" u- O; b7 ]3 V/ B/ t9 u
首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下: Projects\Virtual_COM_Port文件夹下,复制红线部分 图1 - P% ~* n! l! U9 g1 j
0 n0 T$ s' J- o" R3 h
图2
: N8 b) N" ~8 W( h7 ^) F: _7 J
' s' M& W5 H1 [& d我为了方便演示统放在usb/src文件夹下: 图3 ( o0 x4 d/ u' q* t# _
. H4 o+ ?2 u8 P- I5 E现在复制USB的库文件,这些文件不需要我们修改: 图4 ) |" K) o+ M* G2 A4 I# w
' w' x3 `2 x5 f6 L# p6 }- A- c上图中的文件统一放在usb/lib文件夹下: 图5
% T- s6 Y2 b: H" {- L: ?
* A. {% e# w, q. ]& L- U) `& A" P- d0 X8 h7 {% D% ^- g
好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:
: @+ Y( t1 Z# ^6 b7 x L
# M! Q/ P+ K! H6 E! v, B& n
图6 由上图可知,PC通过虚拟串口发送数据到STM32 usb口,STM32再通过usart1发送数据到PC串口。我们做项目时,只用USB虚拟串口即可。所以我们现在需要把串口发送部分删除。把USB做为一个COM口来使用。我们要如何使用这个USB口呢?demo中是把USB发送数据做了一个缓存,先把要发送的数据存入缓存中,然后由USB自动发送出去。而接收部分是直接通过串口透传。我们在应用时就需要用到两个FIFO,1是发送,这个和demo方式是样;2是接收,接收也做一个缓存,我们通过查询来判断是否收到新数据。这下大家应该明白为什么使用两个FIFO了。 我这里有写好的FIFO库函数可直接使用Queue.c文件。 现在开始修改: 1,stm32_it.c 更名为usb_it.c删除无用代码,只保留usb中断函数,和唤醒函数。代码如下: 代码1 - 1 /* Includes ------------------------------------------------------------------*/* Q; b6 e7 |3 `# q2 K+ R
- 2 #include "hw_config.h"6 Z# m! J/ p" I
- 3 #include "usb_lib.h"0 J0 t7 {- n- S! V4 p% V( }4 G8 L
- 4 #include "usb_istr.h"7 c& L8 {; t: T5 S! {
- 5 % ]8 H, c6 r; h i( |- Y" m
- 6
# n6 c+ O8 \1 m+ T3 B& ^2 ] - 7 /*******************************************************************************
) J! K V6 a( X- d# y - 8 * Function Name : USB_IRQHandler" b" c& s2 {: V5 A) d
- 9 * Description : This function handles USB Low Priority interrupts
2 t; `1 _* r& w# g( [! R! F. D - 10 * requests.
`# @ Q; V; O, V8 O - 11 * Input : None
" G0 [* D3 |2 \! ~ - 12 * Output : None1 ]7 _3 o9 t+ p/ R5 @2 m
- 13 * Return : None9 u C* g/ @/ g( r, N, x+ K$ z
- 14 *******************************************************************************/
6 }% K: H6 ]1 {, f! u - 15 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)|| defined (STM32F37X)3 D! g$ ^; Q3 _
- 16 void USB_LP_IRQHandler(void)
' C- R$ |6 t* |2 b, ]( { - 17 #else
7 O2 R0 h0 p+ d, d/ z - 18 void USB_LP_CAN1_RX0_IRQHandler(void)$ r) F5 b* h% b8 v0 K9 O3 Y7 h
- 19 #endif T! J4 a* Y y: d$ O* g" E
- 20 {, J( X: Z: Y8 a( w% c* |
- 21 USB_Istr();
4 f! b" m J6 Z - 22 }
/ D" V% p$ _6 T* b - 23
: _2 v3 j) B( u, d B2 @ - 24 /*******************************************************************************
; c* Q5 s* g8 i% H; Q0 N2 U" y: O - 25 * Function Name : USB_FS_WKUP_IRQHandler5 d9 X( W6 }1 d
- 26 * Description : This function handles USB WakeUp interrupt request.
; U" |( I% X9 D3 L! w* C - 27 * Input : None
" i+ |1 b; m# \2 N; Y - 28 * Output : None
- p: j+ ~6 C8 S5 y% k6 a$ l+ q7 p* T - 29 * Return : None6 _; L3 n5 b/ K
- 30 *******************************************************************************/
0 g7 P7 Z! r( o; } - 31 4 \- Z6 L, [2 d0 q5 F& U
- 32 #if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)
. u0 U2 ]- y; q: w - 33 void USB_FS_WKUP_IRQHandler(void)
8 x# L# G, U' D# Q7 v, P - 34 #else
I& x6 E0 q& K" K6 w - 35 void USBWakeUp_IRQHandler(void)
; U' j9 u, F) V0 I! E - 36 #endif, L% P# H+ K, ]( D5 B- p4 s
- 37 {. e0 x P2 @. d2 \
- 38 EXTI_ClearITPendingBit(EXTI_Line18);
9 p! a4 k# S4 O2 q- o - 39 }
复制代码 5 U0 B5 E u1 c% k7 k7 K! Q
2,修改代码hw_config.c删除无用代码,新建立2组,读FIFO和写FIFO的函数。后面会用到。 代码如下: 代码2 - 1 /* Includes ------------------------------------------------------------------*/
/ `( H, e: q8 @" K: ^0 e - 2
u Y3 l" U% q# s7 ^& ]; R- T - 3 #include "usb_lib.h"" u/ g6 P% t( z' }, e6 l
- 4 #include "usb_prop.h"
" q d( ?! a( M* d* C - 5 #include "usb_desc.h"! @% n: N" {& C. \% B6 i
- 6 #include "hw_config.h". _2 w$ e* H0 c4 G
- 7 #include "usb_pwr.h"
- O4 E# ~& m3 r5 r - 8 #include "Queue.h"2 i/ W9 l3 W: q& @
- 9 , Q6 @2 z% x" y& v( u
- 10 - {/ \' `* U+ Z
- 11 /* Private typedef -----------------------------------------------------------*/% I- f: w- ]5 K# j5 I* R5 O
- 12 /* Private define ------------------------------------------------------------*/
8 U8 D# k% l" H1 ?+ p - 13 /* Private macro -------------------------------------------------------------*/
- z" ?% p$ C% E3 e - 14 /* Private variables ---------------------------------------------------------*/
. u/ L4 f2 B: i3 H/ h8 v - 15 ErrorStatus HSEStartUpStatus;' K. p/ k- |5 F k p
- 16 USART_InitTypeDef USART_InitStructure;
9 A2 _, }& F3 T; p" V" C - 17 EXTI_InitTypeDef EXTI_InitStructure;
- m5 _. u/ b9 _; m: \ - 18 - C W* S% n& A+ O; a1 V! K
- 19 0 q: u, ^1 }6 i% `. b5 B4 D
- 20 #define USB_COM_RX_BUF_SIZE (1024 + 256)
' d# \, b$ @" ~: U: ^ - 21 #define USB_COM_TX_BUF_SIZE (1024 + 256)
! @( _, v+ C+ m+ D - 22 % X* [' g: v' c$ K" G
- 23 static QUEUE8_t m_QueueUsbComRx = {0};2 ^& l# W3 m7 W/ }- r9 t
- 24 static QUEUE8_t m_QueueUsbComTx = {0};
: }0 n3 V& V3 A* d9 s - 25 static uint8_t m_UsbComRxBuf[USB_COM_RX_BUF_SIZE] = {0};
# ~; L+ m: \- F; x" T, b- R! U) g - 26 static uint8_t m_UsbComTxBuf[USB_COM_TX_BUF_SIZE] = {0};
: u+ m' x/ c* x' A( x - 27 , |- N/ [/ e6 [* F3 Z* y" P- s
- 28 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);& U& n% U& h! P* b; h
- 29 /* Extern variables ----------------------------------------------------------*/8 W6 D" O! d5 c+ t7 h2 ~
- 30
: t9 A% E3 ]0 i - 31 extern LINE_CODING linecoding;& v/ l! q& z) k- I. h8 N. S
- 32 8 L. A( _/ O/ D# g- N- j% b4 }
- 33 /* Private function prototypes -----------------------------------------------*/
/ @4 A" R4 b% s+ M9 O+ J* o I# i - 34 /* Private functions ---------------------------------------------------------*/
" m5 {8 C: z) v& V - 35 /*******************************************************************************
: v; N4 z7 [: U+ V- y N - 36 * Function Name : Set_System
' `1 D# n4 e- H2 d! o7 w8 l& L6 s" J: z - 37 * Description : Configures Main system clocks & power- w/ L; y% M1 k1 y( A9 \& |$ v
- 38 * Input : None.* t3 P- u* \, f+ }- `4 H# U
- 39 * Return : None., |' j+ s( B, `5 J
- 40 *******************************************************************************/1 }8 ^& v1 k/ o# _: v
- 41 void Set_System(void). M/ c4 {4 \9 ?6 z. L+ x
- 42 {: u1 x! a" l! x, y5 k: z; t2 }. \
- 43 GPIO_InitTypeDef GPIO_InitStructure;
) b& N0 t% A! z, l1 T( D - 44 1 D3 E7 b# z( e; i/ k- ^
- 45 QUEUE_PacketCreate(&m_QueueUsbComRx, m_UsbComRxBuf, sizeof(m_UsbComRxBuf));
! L9 M4 c+ Z2 {5 `) ]+ S - 46 QUEUE_PacketCreate(&m_QueueUsbComTx, m_UsbComTxBuf, sizeof(m_UsbComTxBuf));
5 w! V7 O# m$ R5 B8 A. Q. z - 47
9 |' X' ?. Z! N! h; w. p4 h - 48 /* Enable USB_DISCONNECT GPIO clock */* g9 E) @! Z. T2 W4 e7 z8 c6 N
- 49 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);# D* N- b: V( K f0 g
- 50
# Z6 P J: N* [2 f) n, }/ t3 ~ - 51 /* Configure USB pull-up pin */
1 ?/ I1 M7 e+ n" S: I$ E - 52 GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
4 {: u' Y X3 o( t G( j - 53 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;9 ]. C1 D( |$ r+ S4 H$ W
- 54 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; o4 [- k# Z+ G/ v
- 55 GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);5 A- R; e& i7 O! j! @1 u
- 56
/ W$ H3 G. [, j( I* S7 V; a2 S# h - 57 /* Configure the EXTI line 18 connected internally to the USB IP */
) B) l; u+ A( A" _1 t( ^ - 58 EXTI_ClearITPendingBit(EXTI_Line18);. [" G% y; ^: F( h; {" a
- 59 EXTI_InitStructure.EXTI_Line = EXTI_Line18; ) y% P9 u& h6 y- q0 E3 E3 l
- 60 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;- c% n3 M) C6 `3 E/ p
- 61 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
* {( j1 F* ~ n! f6 f8 N/ i - 62 EXTI_Init(&EXTI_InitStructure);
% k4 [5 W" b9 |) F3 J - 63 ) D8 S7 u5 d/ K! Y8 \2 u
- 64 @: @. i+ c+ @: U) S6 @9 X
- 65 }
, w. C8 T/ {' q' T* V" R9 { - 66 # C2 j* N; ~( ^$ X& S% }1 e
- 67 /*******************************************************************************
, p& D7 c2 j3 A* t& O1 H4 W - 68 * Function Name : Set_USBClock
, E& Z t8 n( b! t, @" l. l+ a - 69 * Description : Configures USB Clock input (48MHz)8 W2 a O+ O% P' ^ h6 Y" ]
- 70 * Input : None.+ ^; l$ }$ f& |2 Z2 \9 O
- 71 * Return : None.
8 ~# X/ o9 k! S* D: o5 J a! i - 72 *******************************************************************************/
, k2 U5 g' t# b6 Y8 { - 73 void Set_USBClock(void). w' l0 I. s, k' r
- 74 {
+ a1 \ J- w/ Z% n* x) Z/ R% W/ m - 75 /* Select USBCLK source */% s" w0 j4 ~1 ~
- 76 RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
^( P) ]8 M; C a! r9 Z {1 s9 N - 77 : {0 o2 e* n" y7 y
- 78 /* Enable the USB clock */7 N5 ]( C' h% Y3 y
- 79 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
5 v8 c e' Z1 Q6 Y" |: y% T: [ - 80 }
: G4 r- }2 E/ h5 n* N" T1 a# K - 81 # I6 L0 e6 A# y: M
- 82 /*******************************************************************************0 Q7 ~% Z6 q& c- C& Z
- 83 * Function Name : Enter_LowPowerMode
3 C1 T" Q- R2 H5 x" r - 84 * Description : Power-off system clocks and power while entering suspend mode
; r) a7 ]; P% W2 q( s6 E {1 i - 85 * Input : None.& a: Y* Q/ f6 ?" Z
- 86 * Return : None.8 Q3 Z* v$ n/ |- H5 G+ }4 @* V: O# `0 q
- 87 *******************************************************************************/3 K) E5 {+ }) c2 J. k- {
- 88 void Enter_LowPowerMode(void)3 P& O9 J' h; q3 @
- 89 {
9 h2 P7 O. O C4 f( m - 90 /* Set the device state to suspend */" s3 D6 ?& l2 G" E7 K+ `
- 91 bDeviceState = SUSPENDED;
+ {: p: i9 R8 S - 92 }+ |) Y3 x9 y3 n# `) k0 l9 @. y/ \
- 93
* _ D# q6 `' n G$ S }) f - 94 /*******************************************************************************
- F& N5 H% N3 a1 C - 95 * Function Name : Leave_LowPowerMode
# C3 W9 c! e& j" G' [0 Z0 V - 96 * Description : Restores system clocks and power while exiting suspend mode( F1 ?- Y- q: O+ p
- 97 * Input : None.
9 \4 ]. H+ u" p) [1 z) c" Q P - 98 * Return : None.
7 ]. D8 M% b+ J1 j - 99 *******************************************************************************/; O/ `/ P {8 N# J; M, ?
- 100 void Leave_LowPowerMode(void)! L- X: b! C e- b2 Q% s8 w
- 101 {
j( o' m' ? k% m b! U5 i - 102 DEVICE_INFO *pInfo = &Device_Info;
, ?1 B* G D, W6 `1 i/ g* ^7 w - 103
7 p1 H5 M: S; c) ~$ U - 104 /* Set the device state to the correct state */( c5 A0 P* M s/ s2 S
- 105 if (pInfo->Current_Configuration != 0)! T, R8 `7 u6 p! A' Z
- 106 {4 i0 k. m. P L( R- V
- 107 /* Device configured */
$ P H% g7 m$ t$ Q - 108 bDeviceState = CONFIGURED;* Z1 A% x8 y [+ Y& W q
- 109 }% ]/ P$ k6 G. S$ P `6 F
- 110 else* q5 y- ^ ~3 z$ U4 O+ t
- 111 {
; W; b& j% c3 U: y6 ^ - 112 bDeviceState = ATTACHED;
/ U8 m& b) _+ { - 113 }( Z7 H# ?4 g7 r% K! Y
- 114 /*Enable SystemCoreClock*/
# M1 @. ]- r( K2 F - 115 // SystemInit();" Z5 O4 P8 I/ z) l3 m5 D
- 116 }
9 `$ }! [* v8 r3 [7 [$ y) W: S - 117 ! v$ @8 k! o7 F Y2 s' D. t0 R% R
- 118 /*******************************************************************************9 a- ]0 u0 R* G7 z
- 119 * Function Name : USB_Interrupts_Config
6 [: U# X% \$ U# l9 w) U1 U+ V - 120 * Description : Configures the USB interrupts) u( V" p3 r9 q2 f
- 121 * Input : None.. Z( I" m1 o/ c
- 122 * Return : None.4 u2 W3 F& L, s
- 123 *******************************************************************************/! T4 j8 T, ~" x- x
- 124 void USB_Interrupts_Config(void)
/ a: s9 H+ s# S4 l5 j/ i( f- d/ E - 125 {9 B. ~# X7 j$ w8 Q2 O' k8 u
- 126 NVIC_InitTypeDef NVIC_InitStructure; 9 k4 n( Y$ z, f7 {; F
- 127
/ c: @% N& I! P" A0 [ - 128 NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
5 F% a3 ]! E, L% y+ x - 129 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;! [2 n8 p' P; I3 G) o% Y
- 130 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
5 _2 V! ?4 Q9 W# f6 _ - 131 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
$ M1 Y* a5 s" I, z2 o - 132 NVIC_Init(&NVIC_InitStructure);) j' ^+ J7 O3 P
- 133
+ C/ R S* x, \1 e }: H; Y8 ]- a - 134 /* Enable the USB Wake-up interrupt */
1 ^1 L( G9 L* A% X0 ^" a - 135 NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
6 P! E$ O! e) G9 {; S i8 l - 136 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
! n2 N% ~* W* I* t# m2 m- j - 137 NVIC_Init(&NVIC_InitStructure);
4 c, s; s8 Y! X - 138 }
1 C. c* T0 m. G+ S( X7 p - 139 ! I1 J* `0 c: z1 @2 k7 x" G( f9 s) j
- 140 /*******************************************************************************
/ w; f7 o# x& ]& D3 z( c- r - 141 * Function Name : USB_Cable_Config9 l2 z0 i4 T$ M$ h$ c9 a
- 142 * Description : Software Connection/Disconnection of USB Cable3 r. i w+ t: {8 ]& h" e. E" B
- 143 * Input : None.
R0 X8 ~2 ? Y4 o- g$ C5 W( D: k+ c2 K4 j - 144 * Return : Status& u4 c I5 X% o8 U7 \7 S
- 145 *******************************************************************************/
8 X% E% X x3 U& j+ l - 146 void USB_Cable_Config (FunctionalState NewState)
: R% }# P$ E; H+ Y - 147 {
6 x8 ~3 f4 v, S2 h& l+ Q& P5 q3 o - 148 if (NewState == DISABLE)
8 H0 @3 n! _2 s - 149 {% i; j4 K2 L3 ~9 E3 W8 ~* w* }+ e
- 150 GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
% G8 T2 E# J6 a: b- I7 i, E) E - 151 }* {9 T" J* g1 J# T0 K7 V; n. }
- 152 else
) J* h: V P6 u2 a- \7 T W - 153 {
6 i! Z( R7 ~( I3 } - 154 GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);6 t% \: y! { Q
- 155 }
7 d# Z5 A3 |* t) o1 }& |: G0 p8 k - 156 }& D! C, ?/ Z( p& Q7 @
- 157 / j7 X) W9 N: @& M' s
- 158 /*******************************************************************************( b6 T) X. r3 P$ }" x& T9 Z
- 159 * Function Name : void USB_Config(void)
& o' H5 a' A2 h) r! R- n- x3 k - 160 * Description : USB系统初始化
6 W0 z% l5 u+ `# t, C G3 d - 161 * Input :
$ {% p. g( a/ K0 t) H - 162 * Output : 1 b, [- n/ q n- Y W
- 163 * Other :
" v2 z! B( k- o5 p& D - 164 * Date : 2014.11.28
$ H; m5 C: t2 r3 Y/ t3 v3 `2 i - 165 *******************************************************************************/3 Q3 ?$ t2 B& k! g! S9 H$ G
- 166 void USB_Config(void)+ D4 k) {9 P) a
- 167 {* R' i4 r3 B/ z% B+ c$ B
- 168 Set_System();2 G" J0 I8 w, Z k( Y5 m- |. v2 `5 G
- 169
0 y* X7 `- j" N" b' m - 170 Set_USBClock();" _% B4 q- U0 m2 t& L* \+ G ~
- 171
2 V. U3 d9 p9 a1 W, ~* S- I - 172 USB_Interrupts_Config();
3 I6 X- H+ F, e. d" I6 Q - 173 . o8 W* c+ d. m" @ Y; i, {
- 174 USB_Init();0 ]) v1 J ~ Y- l- ?% d
- 175 }+ z! T/ A. M$ w! L" T
- 176 9 S. e& U2 Z+ t# B
- 177 /*******************************************************************************: E! Z, B2 C9 H
- 178 * Function Name : uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)
8 b8 H/ e$ p2 | - 179 * Description : 从USB接收缓存中读数据. O) z: c& I, H) s/ e2 y9 ~
- 180 * Input : & ]8 h" v5 Q! N
- 181 * Output :
" S5 P5 E- \! S" \& k7 i - 182 * Other : ; v* R7 P# D+ h) S4 Q9 d' u: L. T& {
- 183 * Date : 2014.11.280 @' ^! k* C/ C/ [# [5 T9 R
- 184 *******************************************************************************/
4 ?; \7 D& u/ T4 {, O6 D4 P - 185 uint32_t USB_RxRead(uint8_t *buffter, uint32_t buffterSize)2 G7 G! }! R4 L( R% M! _8 s
- 186 {' S6 f; @% e3 h0 P! p
- 187 return QUEUE_PacketOut(&m_QueueUsbComRx, buffter, buffterSize);
: X! |# ]. p9 u - 188 }
3 m2 |8 V5 l( u! ^- N8 n - 189 /*******************************************************************************
/ v: z3 K! \# D3 K5 d8 i - 190 * Function Name : uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)$ T& T" X" [( q& n5 x
- 191 * Description : 写数据到USB接收缓存中9 I3 e: x1 w' h) `8 k7 ~% ?
- 192 * Input : 9 \: t1 Y1 q c, k$ R, Q w0 F' S- d7 l* H
- 193 * Output :
3 B4 Y8 W" x: B0 u - 194 * Other :
( d8 [5 e; d, H7 K N: | - 195 * Date : 2014.11.28$ t0 ?! q$ V$ A$ C
- 196 *******************************************************************************/* X0 s0 l* V5 G
- 197 uint32_t USB_RxWrite(uint8_t *buffter, uint32_t writeLen)
8 T1 e9 @9 Y0 N - 198 {
5 ^' `. O5 r/ {8 O0 P: |9 X1 b - 199 return QUEUE_PacketIn(&m_QueueUsbComRx, buffter, writeLen);2 `9 X$ J+ i% p, ]+ G3 \0 j
- 200 }2 P$ V. R' L o% w
- 201 /*******************************************************************************
2 b, T+ r# @ }6 u) z; _6 M+ a9 y. P1 c - 202 * Function Name : uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)
9 H/ E% C2 x: n: W4 A, [ - 203 * Description : 从USB发送缓存中读数据
* M3 ^3 L" [: T% i - 204 * Input :
- p4 Z- s6 S6 I( A, e/ Z% l - 205 * Output : 4 w8 o( O+ a& ^* A) c2 i" u$ C
- 206 * Other :
7 R0 |6 k& R4 w" r+ w( X0 M& O - 207 * Date : 2014.11.28
& B! ~4 p$ I. h1 c& l5 l. L - 208 *******************************************************************************/
4 ~5 p$ M; i( j; N3 y - 209 uint32_t USB_TxRead(uint8_t *buffter, uint32_t buffterSize)
4 f" M! Q* F. u- W' v8 c2 l' e& W- ^ - 210 {
+ M$ J3 K- a4 `+ w" _3 S6 k3 W - 211 return QUEUE_PacketOut(&m_QueueUsbComTx, buffter, buffterSize);;' s" F: i$ p: z5 [ M7 X
- 212 }
; G) Q* w, W! K& E- @ - 213 /*******************************************************************************( k/ {# g$ {5 c' a+ k4 y
- 214 * Function Name : uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen)
. m7 Y5 P) C, B! o0 f - 215 * Description : 写数据到USB发送缓存中! h _/ ~0 T/ f0 y# M
- 216 * Input : $ W5 O" L& X/ E6 [/ T$ _; i! C9 B
- 217 * Output :
5 e, S* O, i$ P" W( \- H. d+ ^ - 218 * Other : 0 E' m( T5 s) C7 k9 b9 Y" V7 z$ Z0 N
- 219 * Date : 2014.11.28 N8 q1 b2 d$ \# h! @$ a0 s- h
- 220 *******************************************************************************/+ s5 ]4 `$ k& ?7 y
- 221 uint32_t USB_TxWrite(uint8_t *buffter, uint32_t writeLen)
1 c9 J! J9 b) P+ f2 K - 222 {( u Z9 V# X- U1 u& ]
- 223 return QUEUE_PacketIn(&m_QueueUsbComTx, buffter, writeLen);
/ @ O% m; g \ - 224 }9 @: z4 F: d6 H6 _
- 225 ) M( q, ]. V& @5 j$ O
- 226
. M0 d. g8 J9 ?4 s r N4 @ - 227
$ R ?. V+ d) P7 B7 o - 228 /*******************************************************************************3 w6 B7 x$ x* b$ f5 g0 @* U
- 229 * Function Name : Get_SerialNum.
( E( b/ j& `1 u- f - 230 * Description : Create the serial number string descriptor.
3 g6 g0 y: S" K' T - 231 * Input : None.
# F1 R) g% P8 ` - 232 * Output : None.2 H* h6 [/ m- {6 l4 o
- 233 * Return : None.9 ?8 W `; h9 S8 \3 i8 m4 ^. l
- 234 *******************************************************************************/3 D, U6 ~% D: A0 H0 F
- 235 void Get_SerialNum(void)
6 d: L4 Z4 O6 S" g- G& m- x - 236 {
8 n+ v8 @# q# J$ f) Q8 x+ Y! |- I - 237 uint32_t Device_Serial0, Device_Serial1, Device_Serial2;
" `3 b! W# H% @ h0 } - 238 % m$ q. J8 z+ F
- 239 Device_Serial0 = *(uint32_t*)ID1;" d" z6 J, T5 `; \' _
- 240 Device_Serial1 = *(uint32_t*)ID2;
% H7 l2 [0 q/ |# I2 k - 241 Device_Serial2 = *(uint32_t*)ID3;
% v, ~! J. J) q- N- M u$ q2 Y - 242
: s" L" D# C7 G( Z H - 243 Device_Serial0 += Device_Serial2;$ Z6 V' p5 V H9 ~1 V0 T& r
- 244
2 l) E, w- V$ G! ?" q, i - 245 if (Device_Serial0 != 0)
) i9 |% w; W8 n& y9 ]4 N7 ~% p - 246 {6 U( M" e8 e* J# i/ }0 i
- 247 IntToUnicode (Device_Serial0, &Virtual_Com_Port_StringSerial[2] , 8);
9 j/ C$ J# k. A0 W+ K - 248 IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4);; z5 D" C4 ]+ M& F
- 249 }
5 p o6 b" m' O. Z! S - 250 }6 e/ u' J. j/ ]
- 251
2 V/ S" w+ ~" H6 T - 252 /*******************************************************************************- Q9 o* U# t {' v/ K
- 253 * Function Name : HexToChar.
$ {5 F# r+ u7 I1 D% c - 254 * Description : Convert Hex 32Bits value into char.
' J ?; E/ x% j( h5 [7 M* Y - 255 * Input : None./ h2 y7 z) [) ?3 `& U
- 256 * Output : None.) X f/ j) ?5 q: ?
- 257 * Return : None.
9 u1 q+ w3 b, x! ?# a - 258 *******************************************************************************/
. @3 F( T7 I9 Z: D( r; H9 P+ Y - 259 static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len)
1 C% S* ?/ U$ z6 W8 l) {' }; r - 260 {- T* P3 ~& Q6 J0 w9 t2 U' A4 g/ X
- 261 uint8_t idx = 0;
( |2 j% a. _ k$ F/ v- e# b6 Q - 262 " p8 X O; V* m4 b4 Z
- 263 for( idx = 0 ; idx < len ; idx ++)
h; }1 J9 a, `2 G0 W6 J3 | - 264 {
2 S7 S: {7 w. e% O2 ^ j4 y - 265 if( ((value >> 28)) < 0xA )
6 L$ |9 T6 p( \$ N - 266 {
: T4 T8 E4 |. N) P - 267 pbuf[ 2* idx] = (value >> 28) + '0';' d& [" J6 M `$ ]/ \3 W' S; M
- 268 }
1 h3 D& H! i! B, g- T* [, ^! @9 y - 269 else, w3 m- `* g. U2 R
- 270 {
u3 K5 O6 o( P2 O: M+ g8 b - 271 pbuf[2* idx] = (value >> 28) + 'A' - 10;
: X7 S& Z8 M" G7 m* m+ E& N - 272 }
$ R1 x! _" h& {8 A - 273
* O+ X# h4 R: p+ S9 J2 j' P - 274 value = value << 4;3 ?$ c! M; U- @. I% _
- 275
2 P' `* t" d; m/ ] - 276 pbuf[ 2* idx + 1] = 0;/ z( B$ |7 T( u& y2 k( ?! R
- 277 }* ]. q4 v d4 P" P
- 278 }
% O* ]- X! v7 {1 J) V f0 U - 279 . Y# B' z! z# G# L# `6 f; h
- 280 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码 U" ^' {* P6 E9 G. Z( D: y
5 Y! v/ o" ~5 G: b- m8 S0 d这里要讲一下为什么要屏蔽SystemInit(),因为demo只运行虚拟串口功能,在USB未插入的情况下,是进入低功耗状态,插入时从低功耗状态退出后会调用此函数。当然我们在项目中一般不会这样,系统是否运行和插USB接口没有联系。所以我在下文中把进入低功耗代码屏蔽了,自然也就不用唤醒代码了。 图7 5 o" ~6 o5 f3 I) w
% h( Q# l) B. }9 p1 K, b3 W6 U
关于USB口使能控制引脚,需要根据开发板的引脚定义来修改宏定义platform_config.h文件中,笔者使用的是神舟3号开发板,控制信号刚好和demo相反,所以修改hw_config.c代码如下: 代码3 - 1 /*******************************************************************************
7 b0 }, t# v {9 k0 k - 2 * Function Name : USB_Cable_Config
$ J& k i( U2 t4 j) u" ~$ J - 3 * Description : Software Connection/Disconnection of USB Cable2 r9 `3 u2 _- ?* S i5 L5 \
- 4 * Input : None.
* h5 V& H! D- G. n' _, a$ ]9 q - 5 * Return : Status
& G" U; j1 p2 }6 I% ?' V g* f - 6 *******************************************************************************/
1 V- S. z3 p3 }4 v. s( ]5 u, h - 7 void USB_Cable_Config (FunctionalState NewState)" r. |2 S3 J- X
- 8 {
& A# ?. `7 }4 p: s/ U! T - 9 if (NewState == DISABLE)
" H$ p8 s0 L! M8 g* D - 10 {( w+ c0 |- \* [/ L2 s; D( g
- 11 GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);, |% T7 w( Z, W+ z1 {# l
- 12 }) w; c. B- ]* {+ F% E
- 13 else
- i) n' ~) d0 ^1 d# z# M - 14 {5 }- C. c& X" Q. ?2 k( Z4 s
- 15 GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);2 @% u; S) `+ k1 s1 U7 V \
- 16 }0 R% E Y7 `: x' _$ D
- 17 }
复制代码
+ a( k, j- e% p; X7 X5 I3,现在修改USB 回调函数中的代码usb_endp.c文件。使用下文代码替换: 代码4 - 1 /* Includes ------------------------------------------------------------------*/, z4 r5 L4 ]- W# c! e& O- {
- 2 #include "usb_lib.h". ~0 E$ T4 s2 O$ X9 [. w v2 |
- 3 #include "usb_desc.h"
# h1 @, x. n" G* y& d- q - 4 #include "usb_mem.h"
# R0 n8 O- r& H% R" r/ X* @2 D! n! n3 E - 5 #include "hw_config.h"; M4 o5 Q0 M7 k$ E$ r! |
- 6 #include "usb_istr.h"3 o/ r* I! l: k
- 7 #include "usb_pwr.h"
, e0 _: l1 e: Z5 y - 8 1 o& ~( ^8 P" C# A. u
- 9 /* Private typedef -----------------------------------------------------------*/
w& g/ \! m3 J4 z: P - 10 /* Private define ------------------------------------------------------------*/
7 e* l' ^$ S! x/ i - 11 & b$ N1 z. J$ l4 ?& Q
- 12 /* Interval between sending IN packets in frame number (1 frame = 1ms) */
3 U9 a1 N' s7 K9 @ - 13 #define VCOMPORT_IN_FRAME_INTERVAL 5
6 G$ @8 m& U4 l) A3 \4 Q9 v; {0 g - 14 p0 y+ l6 t' x2 M9 P
- 15 /* Private macro -------------------------------------------------------------*/
8 x' Q& P% _6 J, b - 16 /* Private variables ---------------------------------------------------------*/( F. j; X6 k5 s# `
- 17 static uint8_t txBuffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};
0 ?% i" Q3 p, J" G - 18 static volatile uint8_t txFlg = 0;5 y: s; Y4 v6 O
- 19 static volatile uint32_t FrameCount = 0;. \' j3 n7 h9 ^* O5 q
- 20 & |7 U) `1 [! n: E6 N5 x
- 21
; ?: p. R8 L. L3 Y3 U+ R - 22 /* Private function prototypes -----------------------------------------------*/
( Y/ ~/ K4 ~4 ~/ i# h, g - 23 /* Private functions ---------------------------------------------------------*/( m$ _) M/ z$ B
- 24 1 @" T- f! B/ I0 Z/ X$ z; s
- 25 /*******************************************************************************
) ]- K% m* Q' Q; s& P! [/ j - 26 * Function Name : EP1_IN_Callback. w( g2 e$ |7 k$ S `& L9 G
- 27 * Description : D* w4 n4 o% O# E+ D9 t. ?
- 28 * Input : None. F4 s& x2 E; N% s9 {. c: L3 A
- 29 * Output : None.
: y6 I6 n) _% G! F: v - 30 * Return : None.0 d: T# W3 x5 G1 _
- 31 *******************************************************************************/
* i3 D1 H9 k0 {. ^" t& T - 32 void EP1_IN_Callback (void)
1 P% ?/ T5 ~4 K4 A9 ] - 33 {
6 X, w8 M! K1 J; ?9 r$ k1 o - 34 uint16_t len = 0;
# c$ h) C& r4 C - 35
8 P3 O' b" J5 |6 I2 k2 L { N1 k - 36 if (1 == txFlg)
% s! }4 H& ~5 l9 p T$ Z - 37 {6 t: c& S" ^& C; ^
- 38 len = USB_TxRead(txBuffter, sizeof(txBuffter));) h! m6 N& d& d+ r& {% X
- 39 # c8 b" f3 ^; H, p* W& O# \
- 40 if (len > 0)
7 I' G6 Y! z! P3 j X! x- s - 41 {! i6 B, O* j, i. Q% L
- 42 UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
5 n/ q7 ]: u i) O- ` - 43 SetEPTxCount(ENDP1, len);
% r3 M! c# A6 ]) R2 `5 | - 44 SetEPTxValid(ENDP1);
& R+ Y$ e7 A1 q - 45 FrameCount = 0;
) S5 x+ d) W3 M7 J7 [+ z% V - 46 }
H+ V/ q9 V, Z8 r - 47 else
1 @4 ?2 Z2 j- x4 A1 i - 48 {
5 v3 c1 f# q9 [& m& R! S& ~ - 49 txFlg = 0;. k0 _" A- p! x" e: ^
- 50 }
, ?% F* _9 \2 L - 51 }( n V6 [" U. Q" ?& Q+ |
- 52 }" z; J' J R( X3 c
- 53
7 U$ P7 k: U1 t) W8 S4 w0 { l* \ - 54 /*******************************************************************************
* _. S* _! v. n: e+ c - 55 * Function Name : EP3_OUT_Callback
1 Q3 F, X0 R, L3 B1 M$ Q. w - 56 * Description :
: K) n+ i, y( q9 k3 Y+ a+ Q# N& ^" u - 57 * Input : None.
5 @- |9 T# F) w& m W: x4 f" ` - 58 * Output : None.
# [( j* O! T& W- N* \ - 59 * Return : None.
; F. [# V% N- s. U7 Z - 60 *******************************************************************************/
6 g) d; N7 a& h - 61 void EP3_OUT_Callback(void)
0 j3 u; x7 |( e4 W& s8 \5 ?9 J6 I - 62 {
( [- _" c7 X% `" F - 63 static uint8_t buffter[VIRTUAL_COM_PORT_DATA_SIZE] = {0};4 [. o* c' e1 f P9 H% m( Q
- 64 9 ^8 ^9 F/ |5 j5 _$ \# p2 y
- 65 uint16_t USB_Rx_Cnt;# Z; ]5 [+ [4 P: C
- 66
+ t! D3 H3 I3 U% V - 67 /* Get the received data buffer and update the counter */
j; @7 d% E/ I! h9 e - 68 USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, buffter);! x1 b+ u1 U m7 g8 R2 X6 L/ w
- 69
2 M- C2 J; }/ L' ~ - 70 /* USB data will be immediately processed, this allow next USB traffic being * h( Z r! V/ k
- 71 NAKed till the end of the USART Xfer */
5 P6 U0 C/ u9 c) q& l( M* f - 72 USB_RxWrite(buffter, USB_Rx_Cnt);# L( w$ O; }3 q' J8 J/ B+ { y
- 73 3 s. f0 [4 J# n
- 74 /* Enable the receive of data on EP3 */
, E2 E# q8 e, } S- M7 f- j' a - 75 SetEPRxValid(ENDP3);
5 ]# I" _% W1 A+ B - 76 ) n. ]8 O$ @4 _5 u% v
- 77 }" T# ~# M, W/ ~; K0 i4 C
- 78
5 l; s$ H0 S7 G6 _5 _ - 79
, @# G% E3 ?& E5 i9 {6 e* g! K ] Z - 80 /*******************************************************************************
4 k4 D0 C# ^* R - 81 * Function Name : SOF_Callback / INTR_SOFINTR_Callback
6 Y6 F O( M& B M' a - 82 * Description :# Q0 A4 b$ |& X: p8 m4 r* i0 E' [6 |
- 83 * Input : None. i& f. ?% a3 Q V
- 84 * Output : None., N4 Z7 g; A! \) n
- 85 * Return : None.2 P& N6 O8 t1 T! r/ n
- 86 *******************************************************************************/
. O: d3 l) t" t1 e" q! Z- n! [ - 87 void SOF_Callback(void)
, o. }5 J u- T, y - 88 {
* k1 j. @+ m& D$ m( X' f: r2 C- | - 89 uint16_t len = 0;& i% l& } b# g5 ?8 {
- 90
) g; ] e! ^& z9 R' n- E9 M: K - 91 if(bDeviceState == CONFIGURED) ?# a d9 @9 S7 @0 t
- 92 {
0 r0 ?) C* e5 g4 P: q. W: M - 93 if (0 == txFlg)9 O) f) ?% G; O( t6 P0 ~
- 94 {
: Y5 B4 }, R; @. N { - 95 if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
, n6 ?! n8 p* A) b& I - 96 {3 P, S1 v7 `( } o/ E8 Z
- 97 /* Reset the frame counter */: l: j3 G0 s1 P7 Y
- 98 FrameCount = 0;% J& x8 @* N. r% Y' v8 O2 `
- 99 0 ]0 V, A8 @; J( X+ n$ E! n. ?# D; d
- 100 /* Check the data to be sent through IN pipe */9 ?- c" K" k! z5 K6 X
- 101 len = USB_TxRead(txBuffter, sizeof(txBuffter));
6 P( m; D- H D: }1 c - 102 3 [& J' I2 X% c8 m7 T! O$ w; O( I4 N+ x7 O
- 103 if (len > 0)8 _8 y" W/ z# t+ B" j
- 104 {
" [. y1 L3 r3 k z, ?. }3 n o0 H - 105 UserToPMABufferCopy(txBuffter, ENDP1_TXADDR, len);
: ]3 G1 y# S) X" \# Y7 W/ M - 106 SetEPTxCount(ENDP1, len);' r7 E# P9 ]' H5 X3 M; r4 {* N
- 107 SetEPTxValid(ENDP1);
3 y/ U9 |: |6 h, Y - 108
! Y/ \6 W+ Z1 y$ S4 R8 h - 109 txFlg = 1;+ [; q% N/ a |9 }
- 110 }
' z% m+ G W2 ^; F - 111 }6 v, z: U/ b' d8 q H
- 112 }4 g- r% W8 g2 x; f; m" E
- 113 }
! ^" z. V$ D' n: X - 114 }
3 e& k" r8 _/ }. S5 Z0 H9 _ - 115 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
& b! p. W l9 ]+ G* y3 Y) Q; N4 c5 H+ u0 d0 [/ ~; ?, _
这里讲下大概意思,函数EP3_OUT_Callback是在USB口收到数据后,将数据存入FIFO中。 函数SOF_Callback定时查询用户是否有要发送的数据,如果有则进行发送,在发送完成后会触发发送中断EP1_IN_Callback函数,如果发送完毕就不调用SetEPTxValid(ENDP1)函数,发送完成后就不会再触发EP1_IN_Callback函数。 4,修改usb_pwr.c在前文中说到:不让系统进入休眠状态,这里屏蔽185行 __WFI(); 5,修改usb_prop.c屏蔽COM初始化代码。137行USART_Config_Default(); 237行USART_Config(); 6,修改usb_desc.c 这里修改需要参考一些USB专业的书籍,推荐全圈圈的书,讲的通俗易懂。关于本程序的驱动,笔者在win7下测试可以自动安装,如果无法自动安装可使用文章开始的链接中的驱动程序。本文件如果修改需谨慎,其中pid,vid是制造商ID和产品编号,如果修改了那驱动也要对应修改,官方驱动就无法自动进行安装了。 到这里移植就差不多完成了,下面进行测试。由于USB虚拟串口不受波特率限制,所以笔者进行过50k/s的压力测试,运行半小时未丢1个字节。 移植好的工程STM32_UsbVirtualCom.rar也一起存放在上文章开始的链接中。
B. q7 w! Q0 o9 E |