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