STM32固件库分享,超全系列整理
小马哥STM32F103开源小四轴RoboFly全部资料大放送
【管管推荐】STM32经验分享篇
【MCU实战经验】+STM32F107的USB使用
基于STM32F103两轮平衡小车设计(开源)
STM32F107VCT6官方原理图和PCB
【福利】用STM32库的朋友有福了:STM32F10x_StdPeriph_Lib_V3.5.0chm...
基于STM32F10xx存储器和系统架构经验分享
基于STM32F1的CAN通信之BH1750
基于STM32F1的CAN通信之OLED
我这个是有复位信号输出线nRESET的,不过IDE要懂得向DAP发出复位命令。( m. H/ ~: [+ X
软件复位是另外一种情况,需要向目标IC发送复位“密码”,Cortex的IC有这样的密码。 这就不需要连接nRESET线了。
nRESET是受使用CMSIS-DAP的IDE的逻辑控制的, 不能随便修改。% j& q3 K! r n0 z
你要的功能应该不是一定需要走nRESET这条线, 随便找一条空闲的GPIO,模拟一下DTR/RTS,很容易的吧。, k7 c+ M3 J- `% i
你用的功能好像只是用USB转串口,那么就应该使用USB-VCP的程序来改。
或者买一个有DTR/RTS线的USB转UART的小板, 便宜得很, 5~10元一个。
% X2 g$ e: N5 h8 h# l* L$ O; A. c
/**& [+ n; d% f# G; v
******************************************************************************
* @file usb_endp.c
* @author MCD Application Team' N) ^3 b+ X: J }9 l# E/ I
* @version V4.1.0
* @date 26-May-2017! h6 y+ N( u; ]
* @brief Endpoint routines/ a7 a% V( O6 m" h8 i; s
******************************************************************************
* @attention6 `1 W5 B+ j, p/ p( ^; y
** \7 j) l' c" z
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>& M+ o1 [* d7 m. p' Z- E
*
* Redistribution and use in source and binary forms, with or without modification,: I' Y6 {, B; u# `
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,. U: w4 O! [$ @& a" Y
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation7 O3 h# Y2 Z. N
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.. i& p# u+ i& i4 ^: B2 j: \
*$ {& h5 {4 p0 `1 ^" q
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"& T& m. I% N2 s. U* l6 ]! h6 h5 @
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE' q" X! o& b) S
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR1 m: l$ D% o- D3 o( @% j
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,( A0 ?& F8 e5 x o1 p0 f0 v6 s9 d# n
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************% }4 {( V ^ y1 B2 r8 W% V
*/- G7 ^7 p' R7 {* T7 e8 ?
/* Includes ------------------------------------------------------------------*// M) @( n7 }* [
#include "hw_config.h"3 m; x9 V) [2 H x
#include "usb_lib.h"
#include "usb_istr.h"' X. a" `# o! Y. b" M' \
#include "stepper.h"0 r b' j' B% |8 T
#include "string.h"
. n' q7 w- F8 r, T' h
#include "DAP_config.h"& b3 x" e( f% {' d2 m5 a
#include "DAP.h"
$ w9 i9 b E5 c/ L+ m1 w
: Q" r3 p; d7 O
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/) C! \$ S. T; t% m
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static volatile uint16_t USB_RequestIndexI; // Request Index In% b/ z- u- g: R2 c: W0 x
static volatile uint16_t USB_RequestIndexO; // Request Index Out
static volatile uint16_t USB_RequestCountI; // Request Count In
static volatile uint16_t USB_RequestCountO; // Request Count Out
static volatile uint8_t USB_RequestIdle; // Request Idle Flag' W( Y5 A, O& ]
( B& `% N- |5 g* A0 [
static volatile uint16_t USB_ResponseIndexI; // Response Index In
static volatile uint16_t USB_ResponseIndexO; // Response Index Out
static volatile uint16_t USB_ResponseCountI; // Response Count In0 ?1 s4 P A2 W( c: }1 z T
static volatile uint16_t USB_ResponseCountO; // Response Count Out
static volatile uint8_t USB_ResponseIdle; // Response Idle Flag
static volatile uint32_t USB_EventFlags;
static uint8_t USB_Request [DAP_PACKET_COUNT][DAP_PACKET_SIZE] __attribute__((section(".bss.USB_IO"))); // Request Buffer
static uint8_t USB_Response[DAP_PACKET_COUNT][DAP_PACKET_SIZE] __attribute__((section(".bss.USB_IO"))); // Response Buffer
static uint16_t USB_RespSize[DAP_PACKET_COUNT];
' }7 r# m6 G4 x+ }
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : EP1_OUT_Callback.
* Description : EP1 OUT Callback Routine.
* Input : None.
* Output : None.9 l, U9 a1 u" z8 D K
* Return : None.% w. x2 h: M3 q, h) o
*******************************************************************************/
void EP1_OUT_Callback(void)
{
uint16_t n;( F3 ^- n6 \& F9 ]6 {# Z. L
n = GetEPRxCount(ENDP1);( U: ~% r0 C5 s+ q3 k/ g. d; s. g. j$ e
PMAToUserBufferCopy(USB_Request[USB_RequestIndexI], ENDP1_RXADDR, n);
if(n !=0){
if (USB_Request[USB_RequestIndexI][0] == ID_DAP_TransferAbort) {
DAP_TransferAbort = 1U;+ e' ]) A. h% t, t% _0 C
} else {
USB_RequestIndexI++; J2 w: A$ S1 g: r; H
if (USB_RequestIndexI == DAP_PACKET_COUNT) {
USB_RequestIndexI = 0U;
}8 Z8 l6 x6 l- v" M
USB_RequestCountI++;
USB_EventFlags = 0x01;. I% v) p/ N0 h+ M! i/ O
}
}
// Start reception of next request packet
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
SetEPRxStatus(ENDP1, EP_RX_VALID);
} else {* B% _" W, b2 _; J4 y
USB_RequestIdle = 1U;/ c% n4 Q6 B e9 K# y* ]5 c3 M
} 9 n% X/ Z5 w1 U& H, y6 O/ R4 S m
}
% x+ K) \+ h+ X: p. [/ ^
/*******************************************************************************
* Function Name : EP2_OUT_Callback.( s" k' {9 e2 [( W
* Description : EP2 OUT Callback Routine.
* Input : None.
* Output : None.
* Return : None.7 c. V) s9 Q3 \ H& a# l8 }
*******************************************************************************/, O& j9 o1 U( Z1 X5 }
static volatile uint32_t TX_n;
static uint8_t *pbuf;+ j9 G6 ?/ v6 G& r0 }* L
void EP2_IN_Callback(void)
{/ ?, @+ p4 D: h8 [
uint32_t a;
if(TX_n>0){
pbuf+=64;
if(TX_n>64){
a=64;1 \( L- }/ \( {% w$ O
TX_n-=64;
}else{
a=TX_n;6 y9 e5 g( x5 F
TX_n=0;
}, _4 q, m. s, R2 j. J
UserToPMABufferCopy(pbuf,ENDP2_TXADDR,a);; x6 T+ e [' b1 Q' c
SetEPTxCount(ENDP2,a);
SetEPTxValid(ENDP2);
}else{
#if (SWO_STREAM != 0)1 h, X3 Q0 p& |$ P# g* A# |6 ]
SWO_TransferComplete();; V8 m$ [' P7 F( ~) a
#endif
}
}+ D! B! f6 I9 C. l
1 o N1 @1 ]% L- R
/*******************************************************************************
* Function Name : EP1_IN_Callback." h8 @% ^2 ^0 a7 t1 d7 O
* Description : EP1 IN Callback Routine., x9 f8 {% U5 ~/ f8 O
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/1 R* b, [$ K* C4 O: ]
void EP1_IN_Callback(void)
{% B7 [, B* ~+ J, u, B% Z
if (USB_ResponseCountI != USB_ResponseCountO) {9 d# D) ^% ?/ C4 R. j5 K/ i
// Load data from response buffer to be sent back8 |( x* ^% I' h$ |0 ?6 w( f) _$ W; S
UserToPMABufferCopy(USB_Response[USB_ResponseIndexO],ENDP1_TXADDR,USB_RespSize[USB_ResponseIndexO]);# R( W, J% }/ [8 m
SetEPTxCount(ENDP1,USB_RespSize[USB_ResponseIndexO]);
SetEPTxValid(ENDP1);
USB_ResponseIndexO++;( l& a4 F# E2 n2 R- I
if (USB_ResponseIndexO == DAP_PACKET_COUNT) {
USB_ResponseIndexO = 0U;
}$ ]4 G# a5 d: o! x' e* d6 A+ X
USB_ResponseCountO++;8 b! H) b3 f! ~- E, T* m% w7 e
} else {6 A! n7 d9 s- X% B6 f
USB_ResponseIdle = 1U;
} ; s6 K7 A* g4 K8 e
}
// Called during USBD_Initialize to initialize the USB HID class instance.
void DAP_FIFO_Init(void)! K$ H! |) D D
{
// Initialize variables
USB_RequestIndexI = 0U;+ {+ y, ? X* X8 x$ p# c# `( @
USB_RequestIndexO = 0U;2 l8 ~+ m3 F& V( j
USB_RequestCountI = 0U;: Z7 @4 q( r" h, C
USB_RequestCountO = 0U;
USB_ResponseIndexI = 0U;
USB_ResponseIndexO = 0U;
USB_ResponseCountI = 0U;
USB_ResponseCountO = 0U;$ P: B2 Y! Z8 ^" s3 Y- Z% {6 g
USB_ResponseIdle = 1U;6 {' f7 _+ m- b' H
USB_EventFlags = 0U;; r8 {4 ?- A# ~) H7 h4 ?
}
0 v! S0 g5 M2 s4 M! J, [/ y: x1 _
uint8_t DAP_Thread (void) {
uint32_t flags;
uint32_t n;+ A; y Q. ]3 e4 v2 m8 z% Z
//for (;;) {
// osThreadFlagsWait(0x81U, osFlagsWaitAny, osWaitForever);5 N8 h: ]7 N" q: Y
if((USB_EventFlags & 0x81) == 0)
{: T; w- K$ F' w7 n2 i1 u2 @
return 0;
}3 `( x/ H. A2 J' C8 n
USB_EventFlags &= (~0X81);* m& b& i! w& \' l4 y4 E
, V L! Y8 q2 n3 s/ r7 l
8 U% h/ M: ~, r7 p- u& \
// Process pending requests
while (USB_RequestCountI != USB_RequestCountO) {
//if (USB_RequestCountI != USB_RequestCountO) {
// Handle Queue Commands/ D# ]' Z4 S' F5 E
n = USB_RequestIndexO;* B E1 t* ?; m8 N. a3 _% L' C
while (USB_Request[n][0] == ID_DAP_QueueCommands) {. t; D- g1 v( b& G8 P! x
//if (USB_Request[n][0] == ID_DAP_QueueCommands) {
USB_Request[n][0] = ID_DAP_ExecuteCommands;
n++;
if (n == DAP_PACKET_COUNT) {
n = 0U;' ]1 u( G# i5 W7 ]1 R
}
if (n == USB_RequestIndexI) {
flags = USB_EventFlags;
if (flags & 0x80U) { g! x- {3 F* R! h( N( V! }
break;
}
}9 t. s6 d; k: v1 ]: |
}
3 w8 J* h( f3 J' Y1 R/ B5 y6 {, ]
// Execute DAP Command (process request and prepare response)! d$ J6 K. z: O3 ~4 i/ G
USB_RespSize[USB_ResponseIndexI] =" v: M1 B0 j U1 K/ e: S
(uint16_t)DAP_ExecuteCommand(USB_Request[USB_RequestIndexO], USB_Response[USB_ResponseIndexI]);
* i6 n& i, ^& b+ u- r; `
// Update Request Index and Count
USB_RequestIndexO++;* ?: s. t/ H+ \$ Y/ j6 j
if (USB_RequestIndexO == DAP_PACKET_COUNT) {0 O" i2 D, ^) G0 }. P
USB_RequestIndexO = 0U;! J4 d/ y* l( r% S
}& X8 a4 O- |; B3 W/ t% P
USB_RequestCountO++;
if (USB_RequestIdle) {) Z' w0 h# J. V- F
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {' Q1 u9 {& Z8 g. _2 A$ @
USB_RequestIdle = 0U;
SetEPRxStatus(ENDP1, EP_RX_VALID);
}
}
// Update Response Index and Count0 A! B+ h1 P! `! Y3 z
USB_ResponseIndexI++;: K0 t8 w/ ?$ `4 p% x, i" x
if (USB_ResponseIndexI == DAP_PACKET_COUNT) {
USB_ResponseIndexI = 0U;
}% N3 c1 \1 s. J. o1 Y
USB_ResponseCountI++;
3 Q0 E7 E" y9 g1 l+ W
if (USB_ResponseIdle) {( x- c0 K) W2 [% J
if (USB_ResponseCountI != USB_ResponseCountO) {8 e# }( `$ P7 f2 t
// Load data from response buffer to be sent back
n = USB_ResponseIndexO++;
if (USB_ResponseIndexO == DAP_PACKET_COUNT) {
USB_ResponseIndexO = 0U;
}" [" q4 P: U: d! k
USB_ResponseCountO++;7 B$ D% U5 {+ u* H" S
USB_ResponseIdle = 0U;
//USBD_EndpointWrite(0U, USB_ENDPOINT_IN(1U), USB_Response[n], USB_RespSize[n]);9 J7 l6 n/ y7 [5 y* x( o" k" F1 E6 r
UserToPMABufferCopy(USB_Response[n],ENDP1_TXADDR,USB_RespSize[n]);) u; M- V4 \* }+ o, @
SetEPTxCount(ENDP1,USB_RespSize[n]);
SetEPTxValid(ENDP1);4 R3 S6 v0 w: Z4 Q8 G& i
}
}4 N% A/ d2 d7 L+ z% `9 C% o- q( c5 U
}
return 0;
}: p% C3 Q! W( e
// SWO Data Queue Transfer9 b4 n _' R3 I1 p: O
// buf: pointer to buffer with data
// num: number of bytes to transfer
void SWO_QueueTransfer (uint8_t *buf, uint32_t num) {1 i; u: u. x8 t& U8 p
//USBD_EndpointWrite(0U, USB_ENDPOINT_IN(2U), buf, num);/ Z/ v# u0 j6 K' Q0 s8 T9 T v
uint32_t a;
if(num>64)3 c( |1 W' k% ~
{
a=64;
TX_n=num-64;
pbuf=buf;" Z8 K! M w" n) |* N4 O2 A
) a' D% m* C9 F t( D3 j
}else {- V8 p! a n4 c0 }. I S- `
a=num;
TX_n=0;3 ?/ D7 Y( h+ t9 g& H' o* i/ r' Y7 B
}
UserToPMABufferCopy(buf,ENDP2_TXADDR,a);4 B3 d- ~# _1 Z+ \, |: G
SetEPTxCount(ENDP2,a);
SetEPTxValid(ENDP2);1 w! K' Y- f/ a2 Z
}
- s( B# P& w* i8 r$ p0 }2 @" j
// SWO Data Abort Transfer
void SWO_AbortTransfer (void) {' E9 X4 y: K' e/ R
//USBD_EndpointAbort(0U, USB_ENDPOINT_IN(2U));
//SetEPTxStatus(ENDP2, EP_TX_NAK);0 a+ L5 l+ x4 T- S6 |+ F
SetEPTxStatus(ENDP2, EP_TX_DIS);
SetEPTxCount(ENDP2,0);
//TX_n=0;: q, k) v3 s$ r% r2 I1 a/ y, Z1 J4 T
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/- Z4 t( {) C% i' E3 M
移植大概是这样的,利用STM32_USB-FS-Device_Lib_V4.1.0里面的例程Custom_HID修改为自定义USB设备,3个批量端点,OUT,IN,IN,由于批量端点不像HID哪样要使用报告描述符号,但要让WIN识别出驱动,添加了WINUSB相关的描述符号,在端点回调里实现DAP的FIFO处理,然后把DAP_Thread里面的线程调度修改为标志通过,放MAIN主循环里调用,测试SWD下载程序,调试都完全没问题,时钟设置为10M时感觉速度还是可以的,这能体现批量端点的好处. T2 P! v6 G8 ~7 L' b5 {; N
DWT部分即TIMESTAMP的时间参考,由于没使用Keil的核心库,得自己对相应的寄存器进行开启,而且3.5库的core_cm3.h里面没声明这个寄存器,只得自己定义一下了$ r5 P; F) K5 X p9 [
__STATIC_INLINE uint32_t TIMESTAMP_GET (void) {
return (DWT->CYCCNT);
}
! M* m; v4 D$ u9 B# v: h
void DWT_Init(void)
{2 P% d5 v5 |8 {# x( o& Y
/* 使能DWT外设 */9 O, ]4 V) Z1 D9 A. _
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; . }' e; _, O' U. I; k
( ?; ?( g( K( Z5 o D! [$ R
/* DWT CYCCNT寄存器计数清0 */% E" j1 K5 L, V
DWT->CYCCNT = (uint32_t)0u;& H% [3 h& P' f/ y! m: ?; x
" w2 \5 W( |, w$ M: S: l; Q: d6 o
/* 使能Cortex-M DWT CYCCNT寄存器 */. }& G5 d6 i2 }1 `
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
0 |8 g" t) a" N- r5 a4 A
然后加入了SWO,SWO有个SWO_STREAM传输方式,在不使用这种方式时,开启了SWO调试后单步调试时能正常打印信息了,但是当点全速运行后感觉像卡住了一样,要等非常长的时间才会在断点处停下,如果程序没有下过断点,点全速后就会出现Keil卡死,也不知道什么原因,看程序代码像是在调用SWO_Data时被阻塞住了一样,而且在等待的时间里操作Keil像是也没法动一样了,非常慢一卡一卡的,进入了断点停下后就没这现象了,此时单步也是正常的,也就是说全速下,SWO有问题了,但在没开启SWO时调试和响应速度哪叫一个爽的啊,SWO部分的串口是直接搬了DAP例子工程里的串口驱动代码进去实现的,不知道是不是这个原因导致SWO被阻塞,或者自己另外写串口驱动提供给SWO,另外串口波特率最高只能2MHZ,超过这频率,SWO打印信息打印不出来的,串口波特率就是在Trace设置页面里看到的SWO 频率$ R6 Y3 l% e. U3 @1 @
& l. f3 D! s" w( r' X5 z5 k
然后改为使用SWO_STREAM传输方式,这种方式是单独使用另一个IN端点进行传输,即DAP的命令调用SWO_Data时只取走了SWO的状态,没取走SWO读到的数据信息,数据信息通过SWO_Thread通过另一个IN端点发送出去,SWO_Thread也是把线程调度修改为标志式让行的方式,对于50毫秒超时处理部分没弄,就这样放到MAIN里的主循环轮询调用,换了这种方式后,SWO单步调试,全速下也能打印信息了,而且全速下不会是卡住了,响应速度就与没开SWO时一样的效果,即没了被阻塞的感觉了,非常爽快,所下的断点,按一个F5马上能停止,非常快的响应速度,但有时候Keil底部状态条会提示Trace:dataOVERFLOW,查了一下这提示说是SWO端口读取太多的数据,导致被截断,具体也弄不明白哪里问题,另外手上使用的自制JLINK V9,开启SWO时,SWO时钟是6.XMHZ时钟频率的,而且连接上芯片后,打印信息啥的都正常的,而且不会有报错等待问题,在想这会不会JLINK的SWO接口是使用SPI做的,毕竟串口这个时钟频率能正常工作吗?DAP里的SWO能否改为SPI接收,因为不使用SWO_STREAM传输时会被阻塞住,很大原因是串口时钟频率太慢了,这估计得研究一个SWO的接收协议才行,个人来说SWO方式还是比较实用的,有人会说会占用一根IO,但要说使用串口进行调试不也是占了一个串口,但又会有人说JLINK的RTT不香么?
声明这个变量static volatile uint32_t SWO_EventFlags=0;
在SWO里每一处调用osThreadFlagsSet的地方都改为如:
//osThreadFlagsSet(SWO_ThreadId, 1U);
SWO_EventFlags = 1U;
9 K4 }* R$ \$ h' M9 @: ?& d6 F0 A
// SWO Thread
/*__NO_RETURN void*/uint8_t SWO_Thread (void ) {
//uint32_t timeout;3 a4 c4 Y+ r j u( j: L* A R
uint32_t flags;% u% C* V4 y% R9 t* \( ^3 L
uint32_t count;( j! s6 `% S0 s( O
uint32_t index;
uint32_t i, n;
//(void) argument;
" f# J# y* H0 `6 ^3 B
//timeout = osWaitForever;: s X4 K/ O- j( k7 t/ l; u. o
//for (;;) {4 V# C0 m w* {( C- J
//flags = osThreadFlagsWait(1U, osFlagsWaitAny, timeout);& T6 _5 i* [0 T, R: w/ K2 b
if((SWO_EventFlags & 0x01)==0)return 0;
flags = SWO_EventFlags;% P, u+ H. I9 [& V9 U, M9 c
SWO_EventFlags = 0U;
if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) {
//timeout = SWO_STREAM_TIMEOUT; 这里是对于进入了SWO_CAPTURE_ACTIVE状态时就把线程超时设置为50毫秒,大概意思应该是osThreadFlagsWait到达这个超时时间后,不管标志是否切换为1U,都放行SWO_Thread调用一次,timeout = osWaitForever时相当于无限长的超时等待1U标志,对RTX不熟悉,不知道是不是这样子
;
} else {
//timeout = osWaitForever;
flags = osFlagsErrorTimeout;
} \7 f. c- P) b) H, @* i
if (TransferBusy == 0U) {
count = GetTraceCount();
if (count != 0U) {
index = TraceIndexO & (SWO_BUFFER_SIZE - 1U);
n = SWO_BUFFER_SIZE - index;
if (count > n) {$ @; S/ r" G: E& m
count = n;
}
if(count>USB_BLOCK_SIZE)5 L, A9 u4 T; ]! f" h# N2 ~
count=USB_BLOCK_SIZE;
if (flags != osFlagsErrorTimeout) {
i = index & (USB_BLOCK_SIZE - 1U);$ C! F& E3 [, B
if (i == 0U) {" ~0 Z+ y: l; k- k
count &= ~(USB_BLOCK_SIZE - 1U);
} else {
n = USB_BLOCK_SIZE - i;
if (count >= n) {
count = n;
} else {6 Y' v/ |. ~2 F" F& z
count = 0U;
}
}* V, {. b& G0 B3 w$ v
}! k7 |! [& B8 s; P7 ]% a
if (count != 0U) {
TransferSize = count;
TransferBusy = 1U; N8 }/ g. V, Q; q3 S" {
SWO_QueueTransfer(&TraceBuf[index], count);
}
}
}6 s: }2 h5 Z* N
//}
return 0;& S& D) H, W; S: F H
}
利用DWT增加超时等待,先声明变量timeout也在外面声明#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.8 ~ j8 F( X( M& z3 J; k) }: r
#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2).7 q+ l& R# D3 A0 [$ Z+ ^* O5 G6 V
static volatile uint32_t SWO_EventFlags=0;
static volatile uint32_t timeout=osWaitForever;
static volatile uint32_t timeWait;
函数改为这样' i' o* S) t" W/ H6 j
/*__NO_RETURN void*/uint8_t SWO_Thread (void ) {$ g& u7 y5 q3 @+ w
//uint32_t timeout;
uint32_t flags;
uint32_t count;( l* T0 }6 l2 J8 Y1 C- T. h* G# t
uint32_t index;8 U: I# h' a' G- u9 s8 d0 Y; n
uint32_t i, n;! ^) V2 [+ t, E1 _# V
//(void) argument;
* F" ?5 s. m6 V, L# H; s Z7 O D
//timeout = osWaitForever;
//for (;;) {% ?! o3 i) J. ~' {. m; X3 [; ?! M
//flags = osThreadFlagsWait(1U, osFlagsWaitAny, timeout);
if((SWO_EventFlags & 0x01)==0)
{
if((timeWait-=DWT->CYCCNT)/72000 < timeout) //少于timeout时间值直接返回,DWT->CYCCNT由于这计数值是按72M时钟计数的,所以72000就为1毫秒,0.001*72000000=72000,由于是与DAP处理是顺序执行,这个时间无法准确在50毫秒,但总来说与跑RTX系统 的超时等待差不多原理了
return 0;
* N8 ]! V- V0 r
}: {2 T8 U/ ]7 ~' B2 a! J; J
flags = SWO_EventFlags;3 l c; i" O3 A
SWO_EventFlags = 0U;
if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) {
timeout = SWO_STREAM_TIMEOUT;$ |1 @2 @1 ?2 |; A2 k
timeWait=DWT->CYCCNT;
} else {9 @' n7 q4 y4 N7 Z& X7 D$ s4 a
timeout = osWaitForever;
flags = osFlagsErrorTimeout;; X R. a1 T! e' S
}9 m$ i' W* v4 ~2 _2 I- `& [/ X
if (TransferBusy == 0U) {& O |" h4 ? r, k W
count = GetTraceCount();
if (count != 0U) {+ r3 C& K0 y1 `
index = TraceIndexO & (SWO_BUFFER_SIZE - 1U);4 Q4 _) U( ?' I' p. k
n = SWO_BUFFER_SIZE - index;
if (count > n) {; F0 S* R, q2 ^" g7 ]7 E
count = n;
( j* S9 V. Q8 H; p1 o( _4 H. _; K" T7 c
}
if(count>USB_BLOCK_SIZE)
count=USB_BLOCK_SIZE;( o1 o% |9 K/ V
if (flags != osFlagsErrorTimeout) {, F [3 k; t' Q- ^) `0 W) Z* }& `
i = index & (USB_BLOCK_SIZE - 1U);
if (i == 0U) {
count &= ~(USB_BLOCK_SIZE - 1U);
} else {
n = USB_BLOCK_SIZE - i;! U) J/ n3 ~1 C7 p
if (count >= n) {
count = n;
} else {
count = 0U;% x2 A# M) G& u0 ]7 M1 ?4 G4 F
}/ O u! d v0 n9 M8 B$ M' q
}6 U5 b7 K& y/ G+ E1 d% k- L# A
}
if (count != 0U) {
TransferSize = count;4 Q: g; a' e8 f0 |
TransferBusy = 1U;$ o* i8 s7 O# g' e( {% N( f- w0 v
SWO_QueueTransfer(&TraceBuf[index], count);( ~+ T8 F- N$ y, p* _& A/ F
}4 y% m- z3 t) J& ]
}
}1 }6 K& Q( w4 _" O3 ?$ V8 `
//}
return 0;
}这样修改后也不知道能否解决Trace:dataOVERFLOW,也是刚想到的,试了才能知道了,另外还要说明一下,USB_BLOCK_SIZE是声明为512字节的,即SWO_QueueTransfer(&TraceBuf[index], count);时,如果count超过64字节后就得要分包发送了,这个USB库发送部分得自己分包发送,上面的SWO_QueueTransfer发送代码和端点回调处EP2_IN_Callback已经加入发分发送了% G- I1 M1 w; C7 o
CDC部分暂时还没加入,SWD现在是非常稳定的,而且速度感觉也是不差,就是SWO的问题不知道如何弄,另外看到其它人弄DAP,把SWD读写部分改为SPI,看了一些SWD读写协议,它好像有一个8位一组和32位一组的部分,如果换为SPI是不是就可以更快的速度读写了,另外DAP与USB之间的FIFO部分它有一个队列等待,看意思就是当有标志着队列的包时,就等待接收更多的包缓存后再执行处理,对于批量端点,连续的传输大量数据确实是批量端点的长处,因为批量数据时,端点接收完一包后不会NAK,端点会接着接收下一包,少了一些中间商的处理,也尝试过这个队列等待修改为不等待,即接收一个包,执行一次DAP处理,它同样是能正常运行的,对于批量传输来来说,感觉应该队列等待会提高USB传输的速度,比如下载程序时,Keil 一次性下发多个命令包,比如达到1K或者2K字节或者更多,DAP先全部利用批量端点的优势一次性接收下来缓存,然后DAP才执行一个个命令包的响应处理,对于读写部分构成字节为一组的就使用SPI读写数据,零散的位部分像ACK,SWD复位等待部分用IO模拟来处理,SWO部分感觉如果能修改为SPI接收估计时钟频率可以更高,这样响应速度更快,另外STM32_USB-FS-Device_Lib_V4.1.0固件库的USB端点没有FIFO,不像OTG USB FS 库哪样端点都带有FIFO,但是提供双缓存端点,准备把端点修改为双缓存的,这样当连续多包传输时,端点就不会NAK,少了这个等待时间,能增加端点的传输速率
" \' a ^; F! K( v- ]( o% Q) u
int main(void)
{/ e0 Q4 y% s+ F9 U# N0 w E0 |
DWT_Init();
DAP_Setup();
USB_Interrupts_Config();
Set_USBClock();
USB_Init();$ G4 b% ?4 d, @2 p! }4 r0 t. D
//TIM3_Init(35999,0);) G1 b u1 [3 P @% n7 w
//TIM_Cmd(TIM3,ENABLE);
. i( t4 g# O3 n, {0 o' _/ m& x, J7 p
while (1)
{. q1 N6 v+ q0 v8 I' }" r
DAP_Thread();
#if (SWO_STREAM != 0)5 M+ ]3 l+ O1 N+ k7 t- V/ v" v: [
SWO_Thread();
#endif2 Z, ]$ d& I0 i( P' W
}
}
对于DAP_config.h的IO配置我是这样弄的% P ]2 w; a! D4 u
///@}( u8 Z8 s7 j% F. X
// Debug Port I/O Pins, U% N' r( Y: M% j+ N/ a
3 V. z+ V7 V: I, U+ T
// SWCLK/TCK Pin GPIOA[6]' j3 g- A" H; B& H) [
#define SWCLK_TCK_OUT *( uint32_t*)0x42210198) z8 L* A1 T8 X! I, v$ V7 P
#define SWCLK_TCK_IN *( uint32_t*)0x42210118
// SWDIO/TMS Pin GPIOA[7]
#define SWDIO_TMS_OUT *( uint32_t*)0x4221019C3 g$ H4 a2 a$ F' ]- T! U; R( U
#define SWDIO_TMS_IN *( uint32_t*)0x4221011C
// SWDIO Output Enable Pin GPIOA[7]6 U8 l' J4 q& {, m4 W C+ b
#define SWDIO_Output() {*(uint32_t*)0x4221021C = 1; \) N" e9 F7 D3 e2 W
*(uint32_t*)0x42210070 = 1; \1 w/ b5 e. s9 B3 H8 j9 c4 O9 `# W# p
*(uint32_t*)0x42210074 = 1; \
*(uint32_t*)0x42210078 = 0; \
*(uint32_t*)0x4221007C = 0;}; _- c$ k$ c8 T5 _
#define SWDIO_Input() {*(uint32_t*)0x4221021C = 1; \
*(uint32_t*)0x42210070 = 0; \
*(uint32_t*)0x42210074 = 0; \
*(uint32_t*)0x42210078 = 0; \
*(uint32_t*)0x4221007C = 1; }3 D! e3 a" O) s
. z' s8 ~, N: ]5 k4 l, W) T" y- F! g
// TDI Pin GPIOA[8] D9 N3 H* z' \+ u5 T _6 ~. ~. L: @
#define TDI_OUT *(volatile uint32_t*)0x422101A0' s! J" m" \$ _. p+ g2 h" I9 l
#define TDI_IN *(volatile uint32_t*)0x42210120
// TDO Pin GPIOA[10]- w4 N3 R2 |" x$ f5 X# b0 Z/ L6 T
#define TDO_OUT *(volatile uint32_t*)0x422101A8
#define TDO_IN *(volatile uint32_t*)0x422101286 k+ H! N4 b$ x4 P# R
// nTRST Pin GPIOB[3]& S; Z5 V. `/ L# h
#define nTRST_OUT *(volatile uint32_t*)0x4221818C/ Y. K( }7 H7 }$ S+ _
#define nTRST_IN *(volatile uint32_t*)0x4221010C: Z- X' f1 d8 [( ~1 M+ V. N
// nRESET Pin GPIOB[4]2 c9 d5 M. x& S0 P3 @
#define nRESET_OUT *(volatile uint32_t*)0x422181907 t4 C6 h* b0 Y& p; ^; v D
#define nRESET_IN *(volatile uint32_t*)0x42218110
// nRESET Output Enable Pin GPIOB[4]) s/ z" h, ]5 V9 N: f1 i8 h
#define nRESET_Output() {*(uint32_t*)0x42218210 = 1; \
*(uint32_t*)0x42218040 = 1; \- G- Y% X; q1 \
*(uint32_t*)0x42218044 = 1; \
*(uint32_t*)0x42218048 = 0; \% t4 ^2 z8 S3 Y9 v
*(uint32_t*)0x4221804C = 0; } 2 D: {1 p" A! {) y1 G8 K9 X
#define nRESET_Intput() {*(uint32_t*)0x42218210 = 1; \
*(uint32_t*)0x42218040 = 0; \
*(uint32_t*)0x42218044 = 0; \3 d: y0 ]3 _2 d
*(uint32_t*)0x42218048 = 0;\
*(uint32_t*)0x4221804C = 1; }
, P9 q' m9 m' H5 W
// Debug Unit LEDs; Z+ m; @3 X7 T' L9 y" _3 r+ D* i
5 @/ u- w5 x4 w) @5 ^
// Connected LED GPIOC[13]
#define LED_OUT *(volatile uint32_t*)0x422201B4
#define LED_IN *(volatile uint32_t*)0x42220134
! V8 m5 @& }, Q& U6 J( t
#define LED_Intput() {*(uint32_t*)0x42220234 = 1; \
*(uint32_t*)0x422200D0 = 0; \) k+ Z) a) B1 A+ q/ h9 N6 f
*(uint32_t*)0x422200D4 = 0; \
*(uint32_t*)0x422200D8 = 0; \' v# R- @+ _6 w! i; C/ s `
*(uint32_t*)0x422200DC = 1; }
// Target Running LED Not available
( v8 q! j. k- w% `
// SWCLK/TCK I/O pin -------------------------------------. f) M/ Z1 L) y# c7 \' Y; z
/** SWCLK/TCK I/O pin: Get Input.' L; U( O# r5 y1 V
\return Current status of the SWCLK/TCK DAP hardware I/O pin.0 p! i! [3 }7 B) |9 o
*/
__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) {/ }* L6 E9 a- |
return (SWCLK_TCK_IN); ~! z" n$ l+ b+ J. l' R
}* b: L! H) W( x* R
- J$ `/ M) x) d( ]
/** SWCLK/TCK I/O pin: Set Output to High.
Set the SWCLK/TCK DAP hardware I/O pin to high level.2 j. N6 p. m; X: G L1 L9 j% z
*/0 D2 H0 [# A1 B2 D0 x+ n8 P
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET (void) {
SWCLK_TCK_OUT = 1;
}& M. K! `: f$ \* v9 H
/ @. h4 j) \" p2 j. M
/** SWCLK/TCK I/O pin: Set Output to Low.
Set the SWCLK/TCK DAP hardware I/O pin to low level.$ r/ e" y9 }2 N' T7 D7 }
*/, G" v/ i. W8 ^! h' N5 K! x
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR (void) {/ M( j3 y9 d" X% P1 F* C
SWCLK_TCK_OUT = 0;
}
// SWDIO/TMS Pin I/O --------------------------------------, ]2 B; Z, s$ a
8 u2 D2 n5 o* C" Z
/** SWDIO/TMS I/O pin: Get Input.
\return Current status of the SWDIO/TMS DAP hardware I/O pin.0 r. ~1 T, K/ F% R, R5 C
*/
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN (void) {
return (SWDIO_TMS_IN);
}
/** SWDIO/TMS I/O pin: Set Output to High.& n2 l. M4 n/ Z1 l0 g
Set the SWDIO/TMS DAP hardware I/O pin to high level., N( v: l* u+ w1 L9 f7 m
*/
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET (void) {: \ g- h1 `! ^9 x
SWDIO_TMS_OUT = 1;4 O9 S2 {- W3 r$ o6 f
}; k b4 [0 Q- V) J& Y( J2 ]# G
) L6 d+ ~0 a: E
/** SWDIO/TMS I/O pin: Set Output to Low.
Set the SWDIO/TMS DAP hardware I/O pin to low level.- H) s' N% ?$ f+ V2 |
*/1 ?, @' ]/ g8 [, J) b5 n
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR (void) {
SWDIO_TMS_OUT = 0;+ ? p8 J1 D2 ^. |8 s. V$ e9 i
}9 O; r) B \9 v* @* Q
/** SWDIO I/O pin: Get Input (used in SWD mode only).
\return Current status of the SWDIO DAP hardware I/O pin." g# U; {1 i, t
*/( S( A! ?2 `# Y0 v0 w2 \( w7 L! z
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN (void) {
return (SWDIO_TMS_IN);
}
( M8 y( |, e8 o$ J1 c6 g2 a
/** SWDIO I/O pin: Set Output (used in SWD mode only).; U& s9 [; R+ x4 v& `5 W
\param bit Output value for the SWDIO DAP hardware I/O pin.
*/
__STATIC_FORCEINLINE void PIN_SWDIO_OUT (uint32_t bit) {
SWDIO_TMS_OUT = bit;
}
/ Z( S& J2 O' d' j6 X
/** SWDIO I/O pin: Switch to Output mode (used in SWD mode only).
Configure the SWDIO DAP hardware I/O pin to output mode. This function is- P* _; ^) `# p+ i( e8 e- R, a+ {
called prior \ref PIN_SWDIO_OUT function calls.
*/% n- M8 \9 j2 Z% C+ ]* I& ]
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE (void) {
SWDIO_Output();
}
5 v- u2 ~' x5 V" z( k. J
/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only).
Configure the SWDIO DAP hardware I/O pin to input mode. This function is a8 P0 O% P& I. E- l, B6 ]& E
called prior \ref PIN_SWDIO_IN function calls.
*/
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE (void) {" h2 F0 n. }- Y
SWDIO_Input();& d/ m( {$ D5 r' q. E# b
}, U) ?5 C8 u' A. Y
( B5 @% M# [2 N3 ^+ c1 n
楼上有的说弄无线,其实无线也就是PC<->USB<->无线模块A<->无线模块B-DAP,数据传输的速率主要是无线模块之间的速率限制了,也是非常简单的
即单片机先做好USB接口部分,OUT端点收到的数据发送到无线模块A,无线模块B接收到数据后,推给DAP处理,DAP响应的数据再让无线模块B发送回无线模块A,再通过USB发送回PC,也就是说USB与DAP之间也就多了两个无线模块作为数据的交换,要是会写USB驱动,写个虚拟WINUSB设备的驱动,让Keil的DAP驱动能识别到这个虚拟USB设备,通过ESP32利用WIFI通信应该比使用这种无线模块更快,而且ESP32主频更高,即使IO模拟 SWD接口,都会更快,会写USB驱动的大佬可以尝试一下