DMA 原理从 0 到 1:为什么它能解放 CPU?一文讲透 DMA 的工作流程
【福利三:雨露均沾·逢7狂欢】之五:STM32系统时钟PLL故障排除1例
【福利三:雨露均沾·逢7狂欢】之三:AI帮我查BUG
福利三:雨露均沾·逢7狂欢】之二:STM32F407VG串口通信乱码故障的排除
基于STM32F103的I2C主从机通信
OpenBLT移植到STM32F103战舰开发板上适用于所有STM32F103系列的Bootloader
TFT LCD 与 FSMC 的硬件连接大容量 STM32F10xxx FSMC 接口
单片机:初学者该了解的STM32F103基础知识
2025软件工具兔哥知道
STM32之继电器模块
微信公众号
手机版
我这个是有复位信号输出线nRESET的,不过IDE要懂得向DAP发出复位命令。& H% Z) P# a, e- A( d* M
软件复位是另外一种情况,需要向目标IC发送复位“密码”,Cortex的IC有这样的密码。 这就不需要连接nRESET线了。
nRESET是受使用CMSIS-DAP的IDE的逻辑控制的, 不能随便修改。
你要的功能应该不是一定需要走nRESET这条线, 随便找一条空闲的GPIO,模拟一下DTR/RTS,很容易的吧。: k) N3 |; i1 \ f4 R- V
你用的功能好像只是用USB转串口,那么就应该使用USB-VCP的程序来改。
或者买一个有DTR/RTS线的USB转UART的小板, 便宜得很, 5~10元一个。1 c( B0 E: r% Q1 o
" h4 y) t7 E: F1 ^8 l5 S( q
& l8 F2 h# m% s' A
/**
******************************************************************************
* @file usb_endp.c4 p8 r1 k4 T/ A
* @author MCD Application Team
* @version V4.1.0
* @date 26-May-20177 }- o5 x8 \! g) \
* @brief Endpoint routines& e, e; e9 Z% S5 n7 b7 y9 S
******************************************************************************2 ]( E: v9 W( N9 h; d, m
* @attention4 }. o h3 H9 @! e( y9 V/ R7 q1 i7 T
*
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>/ G; ?- g+ K% v# m0 E5 V$ f
*" K& c" \2 r2 t# e: V1 q8 t3 `$ Q
* Redistribution and use in source and binary forms, with or without modification,# C7 m# S9 s/ G7 L" {; U
* are permitted provided that the following conditions are met:$ m6 F& w4 S# @* e0 G
* 1. Redistributions of source code must retain the above copyright notice,1 J9 o' n. C0 q2 p. }
* 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 documentation
* and/or other materials provided with the distribution.4 p, K. Z; w7 H" A8 v' Z* z M4 l
* 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.4 z5 E: v5 P( t4 J
*: H& y& b I7 a6 a) m
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"1 S$ F+ Q: ?, k: d
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* d4 k8 T# b' Y- d) @! |1 T4 d+ Q
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* 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.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/7 |; w" t: v: q# R$ }9 l9 c
#include "hw_config.h"
#include "usb_lib.h": Y7 e+ y7 D A+ S) f1 |; K
#include "usb_istr.h"
#include "stepper.h"$ a# ]9 ~% G: J' h& o, d [' X! N. E F
#include "string.h"
#include "DAP_config.h"8 r# |, x6 R4 M- k' ~' Q7 X5 |+ R
#include "DAP.h"
( t E# F; n! S2 P: `
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static volatile uint16_t USB_RequestIndexI; // Request Index In6 Q) R, d6 l( c I# |
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! i, O, i2 r( Y0 ]( ]4 _; d
static volatile uint16_t USB_ResponseIndexI; // Response Index In
static volatile uint16_t USB_ResponseIndexO; // Response Index Out& _1 o, r- }# R: Z |
static volatile uint16_t USB_ResponseCountI; // Response Count In
static volatile uint16_t USB_ResponseCountO; // Response Count Out
static volatile uint8_t USB_ResponseIdle; // Response Idle Flag
static volatile uint32_t USB_EventFlags;
7 {- s3 R) C* A0 L9 V. V. K
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, R& q4 I& T ?6 Q, h/ v
static uint16_t USB_RespSize[DAP_PACKET_COUNT];
/* Private function prototypes -----------------------------------------------*/- @# }. D; u+ {5 O4 N
/* Private functions ---------------------------------------------------------*/0 H: `& d5 g2 t& H% e( U
/*******************************************************************************
* Function Name : EP1_OUT_Callback.. f+ ]$ S: e5 j' q
* Description : EP1 OUT Callback Routine.1 [2 ^1 O# H8 _# m" X: G
* Input : None.' A' x+ T, U X5 `/ B% M8 A
* Output : None.
* Return : None.: n2 |! }. k' ]9 a% }* q% ^
*******************************************************************************/( R. \0 t5 ]' k/ `- {# {- i
void EP1_OUT_Callback(void); l3 o/ D u3 r( e
{
uint16_t n;( t( ~5 n' u8 ~4 M$ u2 W. j7 M
n = GetEPRxCount(ENDP1);
PMAToUserBufferCopy(USB_Request[USB_RequestIndexI], ENDP1_RXADDR, n);0 ~ q2 m1 c: a0 E# W
if(n !=0){0 n) j T0 }" u% X# p" M
if (USB_Request[USB_RequestIndexI][0] == ID_DAP_TransferAbort) {
DAP_TransferAbort = 1U;! Q% p4 i0 r" g- k g# J. j: ~( S
} else {$ ~( g( P+ W1 N9 `9 `
USB_RequestIndexI++;
if (USB_RequestIndexI == DAP_PACKET_COUNT) {6 G# c% W" B. J0 q/ f9 V4 A
USB_RequestIndexI = 0U;% H( I2 y- ?9 w/ m# t7 ~* D
}! \7 p. s# D0 r3 R8 U
USB_RequestCountI++;" D- W$ S6 t; M/ O: i
USB_EventFlags = 0x01;7 r6 F9 G2 b/ x# A
} K/ `2 B6 I5 \/ |$ } D! d
}
// Start reception of next request packet
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {# Y4 x% v2 Y* j( h- e! I9 _
SetEPRxStatus(ENDP1, EP_RX_VALID);
} else {
USB_RequestIdle = 1U;
}
}
/*******************************************************************************% R, a8 J7 v: j, X5 t2 O
* Function Name : EP2_OUT_Callback., |3 B# Z/ l6 u+ H
* Description : EP2 OUT Callback Routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static volatile uint32_t TX_n;5 ?5 t- E* S; `# o: w
static uint8_t *pbuf;' A, h( x" a" @( o% G' {+ T. `
void EP2_IN_Callback(void)
{
uint32_t a;
if(TX_n>0){
pbuf+=64;0 z( c* d8 s/ \. T7 b# ~9 Z
if(TX_n>64){! q% w6 M5 ]9 C8 ^" K9 K
a=64;
TX_n-=64;0 B+ k$ S8 n' |: G
}else{1 S+ B! Y+ R% m
a=TX_n;) W( l- K3 L% o% b- L- g5 s5 B
TX_n=0;- ~' N8 z5 h1 b8 ?
}1 R# t; J; Q2 @/ N! I4 [5 q7 r
0 _ p, s! ?% [/ I- z4 g; l
UserToPMABufferCopy(pbuf,ENDP2_TXADDR,a);
SetEPTxCount(ENDP2,a);
SetEPTxValid(ENDP2);( `# B* K4 ^& A( }4 |/ a
}else{ t# t; ?" x3 \! B" Z9 r
#if (SWO_STREAM != 0)* N( b. U2 n8 d( W
SWO_TransferComplete();
#endif
}; }& J# l+ C! D- O& ~+ ]" N
}
0 m( U% R, U( I$ Y4 L
/*******************************************************************************
* Function Name : EP1_IN_Callback./ h* n6 f; j v. d2 r8 e$ j
* Description : EP1 IN Callback Routine.
* Input : None.9 b2 Y" H3 t# ^2 Q
* Output : None.5 f+ D( |: G8 u Y, m, e9 ~ l
* Return : None.
*******************************************************************************/
void EP1_IN_Callback(void)
{" S( l" f0 ?7 b: A7 Y; {
if (USB_ResponseCountI != USB_ResponseCountO) {0 }* L& Y# s7 q, z& t
// Load data from response buffer to be sent back7 W4 R1 `" c7 ?( M; y3 M
UserToPMABufferCopy(USB_Response[USB_ResponseIndexO],ENDP1_TXADDR,USB_RespSize[USB_ResponseIndexO]);
SetEPTxCount(ENDP1,USB_RespSize[USB_ResponseIndexO]);
SetEPTxValid(ENDP1);
USB_ResponseIndexO++;
if (USB_ResponseIndexO == DAP_PACKET_COUNT) {* E& _! N' h& j3 K# h& [' \; R6 L
USB_ResponseIndexO = 0U;
}
USB_ResponseCountO++;
} else {
USB_ResponseIdle = 1U;
}
}. E: n4 d! h' P& M
. F' v8 ~1 o2 _- W
// Called during USBD_Initialize to initialize the USB HID class instance.
void DAP_FIFO_Init(void)
{2 U( t* Z# U# F- k$ k
// Initialize variables& N' O' g7 D3 P' P
USB_RequestIndexI = 0U;% ^' _# Z+ f' X0 ?# j( _
USB_RequestIndexO = 0U;
USB_RequestCountI = 0U; q8 G | j7 M) D+ S7 ?
USB_RequestCountO = 0U;
USB_ResponseIndexI = 0U;' M7 S. N+ V+ T2 u2 Y2 S7 \
USB_ResponseIndexO = 0U;( R* H7 L4 t" H3 v: n7 M; {
USB_ResponseCountI = 0U;
USB_ResponseCountO = 0U;4 I. _+ \, a: y5 F, H+ c
USB_ResponseIdle = 1U;; Z) o( N2 [$ U, ?; A5 e
USB_EventFlags = 0U;
}
uint8_t DAP_Thread (void) {
uint32_t flags;
uint32_t n;, T0 L4 x+ P5 q5 m R3 L& M
/ H8 z# r. o9 h8 E) {
//for (;;) {* P: A; [7 l7 E- K( e
// osThreadFlagsWait(0x81U, osFlagsWaitAny, osWaitForever);+ G1 w1 P; V5 T3 k
if((USB_EventFlags & 0x81) == 0)9 V3 w6 }# W. ^, ~% L9 h
{
return 0;
}
USB_EventFlags &= (~0X81);
; H' r# z1 P/ c C: }
// Process pending requests
while (USB_RequestCountI != USB_RequestCountO) {/ z% R! q' S* `& k5 j4 w
//if (USB_RequestCountI != USB_RequestCountO) {; _- R' g( _: X, N& ?( p
// Handle Queue Commands, B6 |/ }* S" e6 b q" Z
n = USB_RequestIndexO;9 ~ K0 ]* i1 ~& m2 a* U6 T
while (USB_Request[n][0] == ID_DAP_QueueCommands) {. C T* D0 W- E& o- v1 Q% `
//if (USB_Request[n][0] == ID_DAP_QueueCommands) {
USB_Request[n][0] = ID_DAP_ExecuteCommands;) H: R# N' S" K V
n++; e4 G6 C* r$ Q# [ u
if (n == DAP_PACKET_COUNT) {4 J' o1 A& ^6 L: h
n = 0U;
}/ d4 m0 h" H6 t* v2 M
if (n == USB_RequestIndexI) {
flags = USB_EventFlags;
if (flags & 0x80U) {5 g) M: @( g' y0 \0 q
break;
}! S+ u) J6 H- l. p% x9 Q! C c
}. u ]& M/ M7 L/ Q! B; ?8 x, {
}3 R* g' h% Q( w- p/ {8 g( I5 ~8 y
! S7 l: z6 Y0 O; r% f* b
// Execute DAP Command (process request and prepare response)
USB_RespSize[USB_ResponseIndexI] =
(uint16_t)DAP_ExecuteCommand(USB_Request[USB_RequestIndexO], USB_Response[USB_ResponseIndexI]);$ B4 Q( e) G, {6 \
// Update Request Index and Count9 \# M1 S A6 v
USB_RequestIndexO++; g* P! S- I7 J
if (USB_RequestIndexO == DAP_PACKET_COUNT) {
USB_RequestIndexO = 0U;$ L4 A' E9 Y6 t- M& t
}
USB_RequestCountO++;7 a8 X9 r. [2 B! n
. H! @/ t' S3 G+ I2 Y$ R2 I. T" S
if (USB_RequestIdle) {! w; k' v! j3 y: ^& [# J
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
USB_RequestIdle = 0U;. p+ Q7 h5 @& y
SetEPRxStatus(ENDP1, EP_RX_VALID);
}
}
3 |7 m/ n! P5 r) A- h3 M
// Update Response Index and Count
USB_ResponseIndexI++;, r: Z- |* k8 t, p5 m2 U
if (USB_ResponseIndexI == DAP_PACKET_COUNT) {( |6 z, x' }# v" g3 g. S
USB_ResponseIndexI = 0U;
}
USB_ResponseCountI++;
7 ^1 p4 `# C8 ^8 i( v% E
if (USB_ResponseIdle) {
if (USB_ResponseCountI != USB_ResponseCountO) {
// Load data from response buffer to be sent back3 |( p! ~5 z1 q# T# k9 I8 m
n = USB_ResponseIndexO++;. d$ L. E6 V, C
if (USB_ResponseIndexO == DAP_PACKET_COUNT) {
USB_ResponseIndexO = 0U;
}
USB_ResponseCountO++;6 i2 x( g \3 G- V& L3 I) G
USB_ResponseIdle = 0U;/ l) E9 C s. N! Q! i
//USBD_EndpointWrite(0U, USB_ENDPOINT_IN(1U), USB_Response[n], USB_RespSize[n]);# I/ k% d+ Y7 C% C# H; o) y( @0 o
UserToPMABufferCopy(USB_Response[n],ENDP1_TXADDR,USB_RespSize[n]);
SetEPTxCount(ENDP1,USB_RespSize[n]);
SetEPTxValid(ENDP1);# r9 c$ G0 N* l' ?+ v3 t
} C& S# D1 a. Q' @$ Y0 {3 ~
}; _' e) T; l/ ]
}
return 0;
}1 A/ P9 b( Q; M
// SWO Data Queue Transfer
// buf: pointer to buffer with data; P V4 z6 R) } Y# ~
// num: number of bytes to transfer9 @- [9 c/ F) A0 m8 t+ D7 m
void SWO_QueueTransfer (uint8_t *buf, uint32_t num) {
//USBD_EndpointWrite(0U, USB_ENDPOINT_IN(2U), buf, num);
uint32_t a;
if(num>64) _" m: h- b; p/ F
{
a=64;
TX_n=num-64;
pbuf=buf;+ I" m( X* e3 `: B2 W: F% J5 S
6 ?5 z5 j- a, ^9 ~4 ~
}else {" K* j; z. K7 [: e# J) @6 z
a=num;
TX_n=0;) H z' c+ h& q+ @* M7 T
}
UserToPMABufferCopy(buf,ENDP2_TXADDR,a);8 M' y, e. b$ P( i' Z
SetEPTxCount(ENDP2,a);
SetEPTxValid(ENDP2);
}7 u$ |! [; u7 N5 D" y
// SWO Data Abort Transfer4 B: L4 |7 k; B( N w( ^$ M0 C+ L
void SWO_AbortTransfer (void) {: G' \! C2 b: Q4 r8 l
//USBD_EndpointAbort(0U, USB_ENDPOINT_IN(2U));
//SetEPTxStatus(ENDP2, EP_TX_NAK);6 y/ c( z/ V% ^6 m6 f1 z0 ~) k
SetEPTxStatus(ENDP2, EP_TX_DIS);# L: n8 l9 L1 c5 f( ^: u( p" S
SetEPTxCount(ENDP2,0);
//TX_n=0;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
移植大概是这样的,利用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时感觉速度还是可以的,这能体现批量端点的好处
DWT部分即TIMESTAMP的时间参考,由于没使用Keil的核心库,得自己对相应的寄存器进行开启,而且3.5库的core_cm3.h里面没声明这个寄存器,只得自己定义一下了
__STATIC_INLINE uint32_t TIMESTAMP_GET (void) {; }) ^% z. W% n/ D; g
return (DWT->CYCCNT);6 T. e p3 s+ a1 h- H) V
}$ a( z1 ]6 I( R: X+ O
void DWT_Init(void), e& K( F2 I m. C7 D6 S% Y
{" `9 u- _* E( s
/* 使能DWT外设 */3 B2 m% p' I/ g1 `! d# A
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; ! M( o* |, F: O' F# w2 ?! y
/* DWT CYCCNT寄存器计数清0 */
DWT->CYCCNT = (uint32_t)0u;
/* 使能Cortex-M DWT CYCCNT寄存器 */7 o; U7 O$ ~) }* C& s
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}, P# x" h/ a/ M$ P; X+ _$ X2 i
, N& D% U9 V/ T! J, `$ {9 q& P
然后加入了SWO,SWO有个SWO_STREAM传输方式,在不使用这种方式时,开启了SWO调试后单步调试时能正常打印信息了,但是当点全速运行后感觉像卡住了一样,要等非常长的时间才会在断点处停下,如果程序没有下过断点,点全速后就会出现Keil卡死,也不知道什么原因,看程序代码像是在调用SWO_Data时被阻塞住了一样,而且在等待的时间里操作Keil像是也没法动一样了,非常慢一卡一卡的,进入了断点停下后就没这现象了,此时单步也是正常的,也就是说全速下,SWO有问题了,但在没开启SWO时调试和响应速度哪叫一个爽的啊,SWO部分的串口是直接搬了DAP例子工程里的串口驱动代码进去实现的,不知道是不是这个原因导致SWO被阻塞,或者自己另外写串口驱动提供给SWO,另外串口波特率最高只能2MHZ,超过这频率,SWO打印信息打印不出来的,串口波特率就是在Trace设置页面里看到的SWO 频率
- r# x* M2 W6 Z
然后改为使用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的地方都改为如:* d A8 w$ p$ b }$ J n
//osThreadFlagsSet(SWO_ThreadId, 1U);
SWO_EventFlags = 1U;5 Y4 o7 `* s- J% q
) z c& p5 g/ W7 O
: J; R, H5 \7 j: c0 E
// SWO Thread
/*__NO_RETURN void*/uint8_t SWO_Thread (void ) {
//uint32_t timeout;2 i$ X9 q" \3 h2 d3 v& j, I$ b4 f
uint32_t flags;6 t) ^& V! ~+ `# S' ^0 ^
uint32_t count;$ u" N- t* G7 D3 h/ z
uint32_t index;
uint32_t i, n;/ w/ S3 m I; X+ ^# Q2 ^0 D
//(void) argument;' |1 k# R# c9 c8 M- c
! u" K( C% Q/ l
//timeout = osWaitForever;( D$ m. W5 @% J
9 K" G4 S9 I5 s2 W
//for (;;) {6 S' @. D# ~0 v. F% J7 D9 o
//flags = osThreadFlagsWait(1U, osFlagsWaitAny, timeout);
if((SWO_EventFlags & 0x01)==0)return 0;
3 z* j8 c. s! v
flags = SWO_EventFlags;
SWO_EventFlags = 0U; # X: q; p; j5 r) y1 U# a% T
if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) {
//timeout = SWO_STREAM_TIMEOUT; 这里是对于进入了SWO_CAPTURE_ACTIVE状态时就把线程超时设置为50毫秒,大概意思应该是osThreadFlagsWait到达这个超时时间后,不管标志是否切换为1U,都放行SWO_Thread调用一次,timeout = osWaitForever时相当于无限长的超时等待1U标志,对RTX不熟悉,不知道是不是这样子2 e3 e* ?: v+ D2 C
;. ~ I; R$ @- q. c+ U, j2 P; x
} else {6 h0 r0 |& J! P7 C
//timeout = osWaitForever;) ]7 z; ]; D. c9 s
flags = osFlagsErrorTimeout;4 I; O5 A0 }2 p2 @4 k
}
if (TransferBusy == 0U) {3 I/ U& @# }! M3 @7 c$ G R6 W; ]( x
count = GetTraceCount();+ x0 S. ?( k& H; w% Y% r0 Y
if (count != 0U) {
index = TraceIndexO & (SWO_BUFFER_SIZE - 1U);
n = SWO_BUFFER_SIZE - index;! L" J x+ u6 J. ]' i6 e
if (count > n) {+ b, Y$ Z x `
count = n;/ W1 w' b5 s6 j' x3 l
}
if(count>USB_BLOCK_SIZE)
count=USB_BLOCK_SIZE;0 z8 @+ k2 d; h
if (flags != osFlagsErrorTimeout) {+ a3 C$ b h+ ^7 ]4 p
i = index & (USB_BLOCK_SIZE - 1U);: D4 ?7 v5 c+ L2 `1 e
if (i == 0U) {, t# v; P6 N: V- r
count &= ~(USB_BLOCK_SIZE - 1U);
} else {
n = USB_BLOCK_SIZE - i;2 j" p2 Z9 e9 p% \
if (count >= n) {# U5 I' m/ z) N6 {" }" Y8 W, _
count = n;
} else {4 D: \5 a5 v0 {* A q
count = 0U;; R+ |' b6 o( s/ i) h. J$ r4 u
}
}; l- Y8 p- P; ? g: `
}. y; A$ N% p0 ~2 F
if (count != 0U) {
TransferSize = count;
TransferBusy = 1U;
SWO_QueueTransfer(&TraceBuf[index], count);+ \# F/ x0 k# D* A& |) h- Q* _# y- N
}
}, V. e5 t& h: m4 i' e4 b3 y
}
//}/ S, i' D$ n( `# ]7 ?% ^
return 0;! M' O3 `# g( h5 o3 I
}: j. Y9 Q0 k& `: x
利用DWT增加超时等待,先声明变量timeout也在外面声明#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.5 W7 ^/ X1 a& s3 W: q
#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2).. a. w% Z5 j7 ^4 N) a0 e
static volatile uint32_t SWO_EventFlags=0;
static volatile uint32_t timeout=osWaitForever;6 D4 t& x5 R4 t: l, D
static volatile uint32_t timeWait;
函数改为这样: A4 O8 D7 @- [" X- A; a9 i# K$ i& t
/*__NO_RETURN void*/uint8_t SWO_Thread (void ) {4 ]- Z7 X1 `8 v8 z! _, n. e" z& T
//uint32_t timeout;
uint32_t flags;
uint32_t count;1 `3 V4 G7 H1 A5 J* q, q- x
uint32_t index;
uint32_t i, n;' v7 Y A$ ^) D3 Y
//(void) argument;
//timeout = osWaitForever;, ?, {: V& U- n# f) M4 j
; G# C0 S0 {2 F5 t9 r! P
//for (;;) {5 ?$ j: W6 F& j# ?9 ^0 E1 @
//flags = osThreadFlagsWait(1U, osFlagsWaitAny, timeout);# k% J" Z% k" O6 a4 V* O! r
if((SWO_EventFlags & 0x01)==0)) i5 o0 b8 e: z% k; A* o9 u
{0 L9 i J: y) @6 R( {6 X
if((timeWait-=DWT->CYCCNT)/72000 < timeout) //少于timeout时间值直接返回,DWT->CYCCNT由于这计数值是按72M时钟计数的,所以72000就为1毫秒,0.001*72000000=72000,由于是与DAP处理是顺序执行,这个时间无法准确在50毫秒,但总来说与跑RTX系统 的超时等待差不多原理了
return 0;
}, i6 T& Y: K' U; q0 g8 L
flags = SWO_EventFlags;2 s2 Z* \2 ]* q" ?
SWO_EventFlags = 0U;
if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) {, Z5 }; p0 k! c+ @
timeout = SWO_STREAM_TIMEOUT;( R! U3 i, i6 Y# m2 {# k
timeWait=DWT->CYCCNT;
} else {1 L$ A# s9 k9 z( b
timeout = osWaitForever;3 p/ `$ B. l# D2 e
flags = osFlagsErrorTimeout;
}& f% N6 J" ^$ H7 F6 M& j
if (TransferBusy == 0U) {6 v6 {% e4 c5 T! R# I
count = GetTraceCount();; S- j0 u- k& R* N7 t/ h- p
if (count != 0U) {1 D; i f( t% J
index = TraceIndexO & (SWO_BUFFER_SIZE - 1U);' E- {4 [8 P) m5 c% y8 |
n = SWO_BUFFER_SIZE - index;6 g. M3 X# z0 R* U7 g7 z9 z
if (count > n) {
count = n;9 F1 z8 `' c L& C2 ~' `
1 g0 s1 a7 A" `, O9 H$ A8 {
}% w, l8 X% K; u
if(count>USB_BLOCK_SIZE)
count=USB_BLOCK_SIZE;- H4 W& r% K+ f
if (flags != osFlagsErrorTimeout) {
i = index & (USB_BLOCK_SIZE - 1U);5 v/ `; `3 q* k3 e6 R; d5 X
if (i == 0U) {
count &= ~(USB_BLOCK_SIZE - 1U);8 t+ A' y3 `* ?) k
} else {0 q3 q2 B8 V) @8 B0 w2 f1 e
n = USB_BLOCK_SIZE - i;
if (count >= n) {5 {% Z& ?+ G4 e7 ` g, V' n
count = n;
} else {8 |7 I# b& U& z i
count = 0U;3 }7 Q$ p2 z: B" _" d
}, K% z- _! I7 r8 h0 v& a3 B
}
}
if (count != 0U) {
TransferSize = count;7 p1 ]1 z2 w+ z2 l( R
TransferBusy = 1U;, R2 t" ]; g- P
SWO_QueueTransfer(&TraceBuf[index], count);
}: U+ r4 P0 d' w3 f1 ^. R9 A
}
}
//}5 m, w, |# M$ j. n1 P. B4 t' N9 N/ b. f
return 0;0 x/ \0 Q& \0 J/ d
}这样修改后也不知道能否解决Trace:dataOVERFLOW,也是刚想到的,试了才能知道了,另外还要说明一下,USB_BLOCK_SIZE是声明为512字节的,即SWO_QueueTransfer(&TraceBuf[index], count);时,如果count超过64字节后就得要分包发送了,这个USB库发送部分得自己分包发送,上面的SWO_QueueTransfer发送代码和端点回调处EP2_IN_Callback已经加入发分发送了- N& m5 |) T/ w v& D7 W5 |
' `" L/ y+ b% V8 T
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,少了这个等待时间,能增加端点的传输速率! C' d% ]- D7 h; U" l; ^
: \. A/ y: A9 a& A& Y/ H
int main(void)
{! P% R# S6 [/ ]. e5 w2 M
DWT_Init();' c: C4 q D4 v4 l4 t
DAP_Setup();
USB_Interrupts_Config();
Set_USBClock();
USB_Init();6 d. [6 l3 c! g. h+ o$ \
//TIM3_Init(35999,0);
//TIM_Cmd(TIM3,ENABLE);
while (1)
{' J1 v8 R* v5 W8 y( D$ z' M& I
DAP_Thread();
#if (SWO_STREAM != 0)% [2 n1 F3 w; P; M2 F; _
SWO_Thread();
#endif
}
}
: D, h1 G/ j, r. M: O4 a" j
对于DAP_config.h的IO配置我是这样弄的% U- h7 V' i y" h( _ H N5 \& o7 I
///@}
// Debug Port I/O Pins+ E- e* R2 m3 |2 x
1 q; ^. r" M1 `5 @
// SWCLK/TCK Pin GPIOA[6]# [+ n4 X6 B4 d$ D
#define SWCLK_TCK_OUT *( uint32_t*)0x42210198
#define SWCLK_TCK_IN *( uint32_t*)0x42210118 i6 v1 H! Q3 h b( Z; [" f6 r
// SWDIO/TMS Pin GPIOA[7]; i* e( }9 r) `( i+ S
#define SWDIO_TMS_OUT *( uint32_t*)0x4221019C
#define SWDIO_TMS_IN *( uint32_t*)0x4221011C/ N; V' I/ w2 u+ H. }
// SWDIO Output Enable Pin GPIOA[7]
#define SWDIO_Output() {*(uint32_t*)0x4221021C = 1; \
*(uint32_t*)0x42210070 = 1; \1 R! c8 [9 o0 s+ R3 p& ` v
*(uint32_t*)0x42210074 = 1; \
*(uint32_t*)0x42210078 = 0; \
*(uint32_t*)0x4221007C = 0;}
" _0 P8 Z% `" P4 q
#define SWDIO_Input() {*(uint32_t*)0x4221021C = 1; \- S6 P$ R3 G: G- [3 h/ u
*(uint32_t*)0x42210070 = 0; \. V0 j: i9 T. P) @! \
*(uint32_t*)0x42210074 = 0; \
*(uint32_t*)0x42210078 = 0; \4 v3 \2 }3 x6 K" ?
*(uint32_t*)0x4221007C = 1; }
// TDI Pin GPIOA[8]
#define TDI_OUT *(volatile uint32_t*)0x422101A0
#define TDI_IN *(volatile uint32_t*)0x42210120" e" U D7 v2 d
" G( \) `1 E: w
// TDO Pin GPIOA[10]
#define TDO_OUT *(volatile uint32_t*)0x422101A8
#define TDO_IN *(volatile uint32_t*)0x422101280 J7 P# b: J% u- @- ^( v/ M K
// nTRST Pin GPIOB[3]2 P; N' j5 X, i: B/ r2 g( c) [
#define nTRST_OUT *(volatile uint32_t*)0x4221818C$ M# ]! r! m. B+ r, ~' l8 ]
#define nTRST_IN *(volatile uint32_t*)0x4221010C: H' T6 F* L( a: [
// nRESET Pin GPIOB[4]
#define nRESET_OUT *(volatile uint32_t*)0x42218190
#define nRESET_IN *(volatile uint32_t*)0x42218110
// nRESET Output Enable Pin GPIOB[4]
#define nRESET_Output() {*(uint32_t*)0x42218210 = 1; \1 N: z- b Q9 e5 [# Z( `" L4 Y
*(uint32_t*)0x42218040 = 1; \) K; M4 {9 O. m& G2 m1 {: D* r( X
*(uint32_t*)0x42218044 = 1; \
*(uint32_t*)0x42218048 = 0; \$ j& \! T( `. m6 u' ~" b0 ^
*(uint32_t*)0x4221804C = 0; }
#define nRESET_Intput() {*(uint32_t*)0x42218210 = 1; \! u- B. s/ K; F
*(uint32_t*)0x42218040 = 0; \
*(uint32_t*)0x42218044 = 0; \! V' d5 H/ \6 `. c4 I
*(uint32_t*)0x42218048 = 0;\/ |/ t- ~$ R; ?5 d2 c) C
*(uint32_t*)0x4221804C = 1; }$ q# J4 _8 s8 ~
// Debug Unit LEDs+ F# J; i1 J( ?( M& Y+ Z8 | l
// Connected LED GPIOC[13]' y/ V' D1 g4 N& r
#define LED_OUT *(volatile uint32_t*)0x422201B4
#define LED_IN *(volatile uint32_t*)0x422201346 |4 S$ |/ E5 D- L
#define LED_Intput() {*(uint32_t*)0x42220234 = 1; \
*(uint32_t*)0x422200D0 = 0; \
*(uint32_t*)0x422200D4 = 0; \) `3 t, ?0 @" x: v2 M+ q
*(uint32_t*)0x422200D8 = 0; \
*(uint32_t*)0x422200DC = 1; }' o& C7 b2 U+ X( F; q
// Target Running LED Not available
4 r* x9 L- _, W1 p
// SWCLK/TCK I/O pin -------------------------------------
1 y- \/ @( Z9 Q3 b
/** SWCLK/TCK I/O pin: Get Input.
\return Current status of the SWCLK/TCK DAP hardware I/O pin.( \$ i! s; |2 c5 M9 X4 M% o, A7 w
*/. z+ Y- i Q+ N8 n/ c
__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) {
return (SWCLK_TCK_IN);4 ]2 E7 L: ?; p2 f# d% O- q5 |
}
/** SWCLK/TCK I/O pin: Set Output to High.
Set the SWCLK/TCK DAP hardware I/O pin to high level.
*/
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET (void) {
SWCLK_TCK_OUT = 1;
}
/** SWCLK/TCK I/O pin: Set Output to Low.- d' D8 y3 B# V0 D+ n) [* n
Set the SWCLK/TCK DAP hardware I/O pin to low level.* E0 a O [; P8 z G( l
*/
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR (void) {. w) y& d4 }4 n
SWCLK_TCK_OUT = 0;
}
/ q8 L# o3 i7 Q$ A$ @5 @) j! d; R% j* k
// SWDIO/TMS Pin I/O --------------------------------------
/** SWDIO/TMS I/O pin: Get Input.
\return Current status of the SWDIO/TMS DAP hardware I/O pin.
*/. Y, D( b, P4 G1 _9 k# F: q: ]
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN (void) {
return (SWDIO_TMS_IN);
}
1 ] x8 {' E# t
/** SWDIO/TMS I/O pin: Set Output to High.3 \0 B+ _( a4 U) b5 @" t) d- ^
Set the SWDIO/TMS DAP hardware I/O pin to high level.) N) b' x6 K: v) h4 o* O$ Q
*/
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET (void) {2 }! e, ~$ @/ [4 W& b
SWDIO_TMS_OUT = 1;* M6 u6 u- }; ~( \
}
/** SWDIO/TMS I/O pin: Set Output to Low.
Set the SWDIO/TMS DAP hardware I/O pin to low level.
*/! V' y3 |9 Z4 Y' C i7 ^) H
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR (void) {, f& F2 k1 Q5 C3 A$ u7 s3 I( S+ @
SWDIO_TMS_OUT = 0;
}$ I. ]" d, ?. _) U( M9 a6 r5 {
) c2 g# }8 J0 J* b( a+ B
/** SWDIO I/O pin: Get Input (used in SWD mode only)." R c* O1 j6 S7 S! b
\return Current status of the SWDIO DAP hardware I/O pin.& w% z8 R# m1 E- c @% z
*/5 ?, }; ~9 I$ q' y! U2 K, @! J" _
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN (void) {
return (SWDIO_TMS_IN);8 ?& I% a/ K0 p# k
}
3 s& X- K5 s/ G9 `7 k
/** SWDIO I/O pin: Set Output (used in SWD mode only).% u; G; X: z; J( W1 \
\param bit Output value for the SWDIO DAP hardware I/O pin.
*/3 a2 R- |/ y% F7 P' d, |
__STATIC_FORCEINLINE void PIN_SWDIO_OUT (uint32_t bit) {2 t3 G9 ?) F+ D9 R
SWDIO_TMS_OUT = bit;0 u6 r9 e+ V. L J
}: a4 `6 g+ g2 s/ l' V; r
) \& G' \& D y! |6 p% i
/** 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
called prior \ref PIN_SWDIO_OUT function calls.
*/ G& F! B! X. o' r/ u( o) i' t
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE (void) {: Y% |9 @: G4 \ x2 |& v. p
SWDIO_Output();! Y( G" d7 Z& @
}/ u' j# j4 e/ V$ [/ v+ @
+ c* K/ B' A4 M6 V$ `. V8 y
/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only)." {0 i! M5 R/ x! B1 \
Configure the SWDIO DAP hardware I/O pin to input mode. This function is
called prior \ref PIN_SWDIO_IN function calls.6 c. m& b) D- F0 M+ G) z
*/
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE (void) {
SWDIO_Input();2 g2 E+ l6 G4 t4 P. f8 }" J8 C0 o/ F) P
}
楼上有的说弄无线,其实无线也就是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驱动的大佬可以尝试一下
有人将这个工程移植到stm32f4上吗,我在网上找了一个f4的dap工程,但是编译下载后无法使用。