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