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