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