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