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发出复位命令。
软件复位是另外一种情况,需要向目标IC发送复位“密码”,Cortex的IC有这样的密码。 这就不需要连接nRESET线了。
nRESET是受使用CMSIS-DAP的IDE的逻辑控制的, 不能随便修改。' y C. {/ m$ C4 m# M8 r/ R5 d
你要的功能应该不是一定需要走nRESET这条线, 随便找一条空闲的GPIO,模拟一下DTR/RTS,很容易的吧。8 |' J2 Z6 y3 p$ h$ a& T/ z
你用的功能好像只是用USB转串口,那么就应该使用USB-VCP的程序来改。 6 ]7 k& @& i7 s) i6 B% ~7 D4 G
或者买一个有DTR/RTS线的USB转UART的小板, 便宜得很, 5~10元一个。
/**
******************************************************************************: ^' H. E8 O H
* @file usb_endp.c
* @author MCD Application Team
* @version V4.1.0, \" [) `! H1 }5 _# X! {. m1 l
* @date 26-May-2017. F/ @7 ?4 e# t, h
* @brief Endpoint routines
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>6 B* j& Q# A# J1 |$ s$ ]8 m) d
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:6 Q; G( `! f# ?1 q4 A' F
* 1. Redistributions of source code must retain the above copyright notice,$ \4 B$ Y7 P; [
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,/ W$ j: t6 K8 W# n( u# r
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.3 n2 X- Z, j" m6 a
* 3. Neither the name of STMicroelectronics nor the names of its contributors7 |* S I+ W1 u$ l3 S& e
* may be used to endorse or promote products derived from this software
* without specific prior written permission.% O# m9 d$ K E
*: B* u3 H8 D, X* ~
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"$ }% m0 V: P+ ?# r# L; Y7 W" Y
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE( _) [4 h J6 U. b/ w8 v
* 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" Z9 u7 o" c: z/ T
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.* U4 s/ A6 ~7 N
*
******************************************************************************
*/
! g* p$ R. S4 ^
/* Includes ------------------------------------------------------------------*/# s( j7 x5 [0 H' T2 Y3 y9 v2 i
#include "hw_config.h"
#include "usb_lib.h"; O* F* D3 `0 n: n) W; Z0 a
#include "usb_istr.h"
#include "stepper.h"
#include "string.h"# h; W, K" f1 b8 I/ k' s. ]
#include "DAP_config.h"
#include "DAP.h"' B% Q8 v5 b; a
1 E- p4 b* a9 j6 O4 z+ t6 E
/* Private typedef -----------------------------------------------------------*/1 P4 K- u5 p. H' W6 |
/* Private define ------------------------------------------------------------*/$ x* y C( z' J, N9 y6 O; d
/* Private macro -------------------------------------------------------------*/1 Y: I. |# t, c/ N- s" C
/* Private variables ---------------------------------------------------------*/
static volatile uint16_t USB_RequestIndexI; // Request Index In
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/ ?; i/ r/ c7 y2 ~. l) @ J
static volatile uint8_t USB_RequestIdle; // Request Idle Flag) ?% D! l/ T M6 f6 j
1 V) y5 u6 i9 J9 K) V' {) J0 p" i* s c
static volatile uint16_t USB_ResponseIndexI; // Response Index In8 M2 E( [* o6 \( J
static volatile uint16_t USB_ResponseIndexO; // Response Index Out. {( Y0 {$ J; P, M
static volatile uint16_t USB_ResponseCountI; // Response Count In! `* d$ S" H( o; ?$ W
static volatile uint16_t USB_ResponseCountO; // Response Count Out' Z. w7 Q- k8 W8 ]' Z9 [- V
static volatile uint8_t USB_ResponseIdle; // Response Idle Flag
static volatile uint32_t USB_EventFlags;. ?& f+ e. s! s7 p/ f
static uint8_t USB_Request [DAP_PACKET_COUNT][DAP_PACKET_SIZE] __attribute__((section(".bss.USB_IO"))); // Request Buffer! y1 @1 _6 q1 i/ }5 a
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];4 G; r! b3 C* R1 C, a, k0 e
9 M. P' Z+ u6 B7 s8 H! U
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/4 V" c' ~5 V1 r
/*******************************************************************************
* Function Name : EP1_OUT_Callback.
* Description : EP1 OUT Callback Routine.* H: q B# g9 ^3 T5 l; m* N* Y$ t
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************// q( n' {6 O8 {; c5 k
void EP1_OUT_Callback(void)
{+ a( N9 I U: f# o
uint16_t n;
n = GetEPRxCount(ENDP1);
PMAToUserBufferCopy(USB_Request[USB_RequestIndexI], ENDP1_RXADDR, n);& C/ W# d% E$ Q
if(n !=0){# N+ b' k2 F( u: S( c* f
if (USB_Request[USB_RequestIndexI][0] == ID_DAP_TransferAbort) {
DAP_TransferAbort = 1U;; z2 z4 U$ A8 }, ]' \2 @$ a
} else {
USB_RequestIndexI++;
if (USB_RequestIndexI == DAP_PACKET_COUNT) {
USB_RequestIndexI = 0U;) o$ l& {4 Z/ h- Z% e
}
USB_RequestCountI++;3 d, @1 n( j% o/ B9 x
USB_EventFlags = 0x01;
}1 l1 B6 Y9 q7 I c& i. h" |- M
}
// Start reception of next request packet
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
SetEPRxStatus(ENDP1, EP_RX_VALID);% A1 |6 p# s2 S. {( @- f% z" Z
} else {$ e. P2 \+ k1 W6 l
USB_RequestIdle = 1U;( v. ^+ C) k P# M. L
}
}
/*******************************************************************************
* Function Name : EP2_OUT_Callback.
* Description : EP2 OUT Callback Routine.4 o" q( p# h( P2 T; C" h& |
* Input : None.7 V5 r. j4 \- b, l9 y$ s9 h
* Output : None.
* Return : None.
*******************************************************************************// ?- D" c8 W6 e/ W2 L- G9 ]
static volatile uint32_t TX_n;; V/ z% Q( b6 C: E# w
static uint8_t *pbuf;/ E- E# E- O# D0 `$ C
void EP2_IN_Callback(void)
{3 P- L7 ]: ]. f$ l1 m
uint32_t a;
if(TX_n>0){
pbuf+=64;, R/ h7 i4 }: T, X) h4 o+ X1 O
if(TX_n>64){
a=64;0 T6 v% b' H2 f1 H) r, d l2 \
TX_n-=64;
6 W# O5 o( i+ o, u. g# f3 w% A
}else{1 A8 B( {3 |0 E! _* Y/ l* I& z
a=TX_n;
TX_n=0;
}
2 t. a+ l$ \' u2 `
UserToPMABufferCopy(pbuf,ENDP2_TXADDR,a);4 y1 ^. ~: y! |7 O
SetEPTxCount(ENDP2,a);* x' H; w. n2 |( r( k
' P' s2 Y+ u3 i7 W% A Y8 S7 b
SetEPTxValid(ENDP2); n3 X: I3 C1 t6 O. H) C) b6 A5 W
}else{
#if (SWO_STREAM != 0): v+ t7 E' q+ A. k; P- f' ?6 {
SWO_TransferComplete();
#endif
}
}
C R7 M, _ h8 ^7 F( V# K
/*******************************************************************************3 p) \$ G3 E4 R I, \, X6 E
* Function Name : EP1_IN_Callback.- }) z$ V; {4 `, o
* Description : EP1 IN Callback Routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void EP1_IN_Callback(void)
{3 `) H5 p) s8 A
if (USB_ResponseCountI != USB_ResponseCountO) {3 c2 \, {4 v5 P5 }, @1 K% N8 X+ U
// Load data from response buffer to be sent back8 a& p" g( H+ E
UserToPMABufferCopy(USB_Response[USB_ResponseIndexO],ENDP1_TXADDR,USB_RespSize[USB_ResponseIndexO]);
SetEPTxCount(ENDP1,USB_RespSize[USB_ResponseIndexO]);
SetEPTxValid(ENDP1); h7 b; w! _- U% |# g
USB_ResponseIndexO++;
if (USB_ResponseIndexO == DAP_PACKET_COUNT) {" ~" a2 R* k7 z o5 F9 Y+ _3 `* n6 h
USB_ResponseIndexO = 0U;; ~* ^. N6 D% U
}) Z5 C# N3 i8 B0 p
USB_ResponseCountO++;4 Z' [- x2 ~ N/ s! W
} else {
USB_ResponseIdle = 1U;% y2 |: a* I$ h7 F3 k
}
}7 a9 G5 E/ T, q$ R
: l! v2 I2 R2 f4 A9 T- u
// Called during USBD_Initialize to initialize the USB HID class instance.5 g$ N8 T1 J {0 y
void DAP_FIFO_Init(void)9 |0 ?% O' E; y1 v& c& }8 L* n
{
// Initialize variables
USB_RequestIndexI = 0U;
USB_RequestIndexO = 0U;
USB_RequestCountI = 0U;# o( }% T) b# M* U R
USB_RequestCountO = 0U;6 w6 L/ u1 V! P& ^; M# P( f% R
USB_ResponseIndexI = 0U;- F0 L, l- a8 J1 @' D, o
USB_ResponseIndexO = 0U;
USB_ResponseCountI = 0U;' p& n, V2 p. z( b2 ]$ g3 U% A
USB_ResponseCountO = 0U;
USB_ResponseIdle = 1U;
USB_EventFlags = 0U;
}% k, V+ }/ r: p( m- {6 n
uint8_t DAP_Thread (void) {6 z8 |8 t* {, v& s( `7 u/ V$ f& k" ?4 Y
uint32_t flags;
uint32_t n;) f# l1 m0 u" l
% t3 e4 a0 W" D& _
//for (;;) {9 s# Q: l" E1 g7 R5 \* x
// osThreadFlagsWait(0x81U, osFlagsWaitAny, osWaitForever);( A3 z' \( z9 o. ` ~3 C
if((USB_EventFlags & 0x81) == 0)3 b3 H" [) J3 W1 ]$ G0 y
{
return 0;
}
USB_EventFlags &= (~0X81);
: f5 C, t, X' M& p( x j. Y
3 \# o+ s7 K+ ^# z: g
// Process pending requests
while (USB_RequestCountI != USB_RequestCountO) {
//if (USB_RequestCountI != USB_RequestCountO) {
// Handle Queue Commands
n = USB_RequestIndexO;
while (USB_Request[n][0] == ID_DAP_QueueCommands) {
//if (USB_Request[n][0] == ID_DAP_QueueCommands) {
USB_Request[n][0] = ID_DAP_ExecuteCommands;# K( G! f' B/ ~9 l
n++;5 R t: J) c |0 e. X: q
if (n == DAP_PACKET_COUNT) {+ ?+ g" E0 S) t
n = 0U;1 g! v% k n- A
}9 F E% W/ {- F/ U& W* f7 H
if (n == USB_RequestIndexI) {/ ~: T; D7 U0 N7 h' o+ M, M
flags = USB_EventFlags; Q& L% m) s. i- ^% N2 L2 h& n6 t
if (flags & 0x80U) {5 ]6 @7 |) h: S @9 H
break;" N) |# J8 d, x$ `% C
}2 h4 w& q2 U8 x% N
}
}) y% _2 ~( [; G V; \
// Execute DAP Command (process request and prepare response)
USB_RespSize[USB_ResponseIndexI] =
(uint16_t)DAP_ExecuteCommand(USB_Request[USB_RequestIndexO], USB_Response[USB_ResponseIndexI]);* C% e; n! F' t/ d( a
( j7 n# ?3 C: H! r. a( |
// Update Request Index and Count
USB_RequestIndexO++;
if (USB_RequestIndexO == DAP_PACKET_COUNT) {
USB_RequestIndexO = 0U;
}9 G# T2 G9 r- s6 t+ v
USB_RequestCountO++;9 e6 p1 a* C$ Z/ _
m+ g7 X6 u7 N7 M: p# d! E5 h
if (USB_RequestIdle) {
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
USB_RequestIdle = 0U;- @- ]5 y, l8 B! W
SetEPRxStatus(ENDP1, EP_RX_VALID);, l7 {- p( a5 }2 Q& r. i
}
}
// Update Response Index and Count
USB_ResponseIndexI++;8 D2 ~ C* A4 A/ o7 G9 H6 |" R6 A
if (USB_ResponseIndexI == DAP_PACKET_COUNT) {
USB_ResponseIndexI = 0U;
}
USB_ResponseCountI++;
, F! L5 }' i, ?8 A6 i) O) F
if (USB_ResponseIdle) {
if (USB_ResponseCountI != USB_ResponseCountO) {5 j$ v5 C& t. v: z1 F
// Load data from response buffer to be sent back
n = USB_ResponseIndexO++;
if (USB_ResponseIndexO == DAP_PACKET_COUNT) { }! l( n, |- Z1 ^- b
USB_ResponseIndexO = 0U;! r. e' m, m/ ?+ P' A- i" S6 e+ B
}
USB_ResponseCountO++;" B! h( l9 s9 t' e- D# z- |
USB_ResponseIdle = 0U;
//USBD_EndpointWrite(0U, USB_ENDPOINT_IN(1U), USB_Response[n], USB_RespSize[n]);
UserToPMABufferCopy(USB_Response[n],ENDP1_TXADDR,USB_RespSize[n]);
SetEPTxCount(ENDP1,USB_RespSize[n]);9 S( e3 S g* B, m
SetEPTxValid(ENDP1);0 q+ T9 {* k8 ]) T- P
}
}, i( N. W- u& q5 s: ^; h: ]
}
return 0;
}7 x3 l0 f& T9 d$ O3 w' G. t* f
// SWO Data Queue Transfer
// buf: pointer to buffer with data
// num: number of bytes to transfer
void SWO_QueueTransfer (uint8_t *buf, uint32_t num) {
//USBD_EndpointWrite(0U, USB_ENDPOINT_IN(2U), buf, num);
uint32_t a;5 E1 X" {* Y5 ?# I
6 c6 }4 p! |1 f0 _# f
if(num>64)
{+ E! |' m* S& A: O, ~( A. A* p
a=64;
TX_n=num-64;
pbuf=buf;, h9 O" s0 V" J. L* j
+ z& ?+ o3 i! O( n# w* i! @
}else {& s4 e& X, N9 E
a=num;
TX_n=0;+ ]5 Q- k) B3 V* x: X
}
UserToPMABufferCopy(buf,ENDP2_TXADDR,a);. G" Z: w' N/ G% n+ a
SetEPTxCount(ENDP2,a);
SetEPTxValid(ENDP2);
}
, B) i2 M3 V9 T/ g7 q+ E3 C
// SWO Data Abort Transfer
void SWO_AbortTransfer (void) {
//USBD_EndpointAbort(0U, USB_ENDPOINT_IN(2U));8 [, B; G5 R2 [/ d
//SetEPTxStatus(ENDP2, EP_TX_NAK);
SetEPTxStatus(ENDP2, EP_TX_DIS);
SetEPTxCount(ENDP2,0);1 n2 U% y7 ]1 _
//TX_n=0;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/& N# n* ~/ l, a8 g' d6 e
) P% }: S8 G% E0 M2 n( V% ^1 i$ i
移植大概是这样的,利用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时感觉速度还是可以的,这能体现批量端点的好处: X( W; h; w4 Y+ H" p/ a7 C
DWT部分即TIMESTAMP的时间参考,由于没使用Keil的核心库,得自己对相应的寄存器进行开启,而且3.5库的core_cm3.h里面没声明这个寄存器,只得自己定义一下了7 u4 G' K# W) E3 b3 X+ l
__STATIC_INLINE uint32_t TIMESTAMP_GET (void) {
return (DWT->CYCCNT);
}, `7 N J" {9 V9 x. x
void DWT_Init(void)
{5 ?0 r6 @5 Z' O) K& q5 A) {
/* 使能DWT外设 */; A1 z; H) U4 N
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 6 S% Y! K9 `3 |0 o! L
3 u, R# [1 P+ Y* V- c
/* DWT CYCCNT寄存器计数清0 */; K& A) V7 \0 f: p+ b, E F$ R2 T1 t
DWT->CYCCNT = (uint32_t)0u;
5 V3 J8 }0 p9 I2 p" J0 T
/* 使能Cortex-M DWT CYCCNT寄存器 */
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;" D0 v8 Q6 D' A( L9 X+ v+ r
}
然后加入了SWO,SWO有个SWO_STREAM传输方式,在不使用这种方式时,开启了SWO调试后单步调试时能正常打印信息了,但是当点全速运行后感觉像卡住了一样,要等非常长的时间才会在断点处停下,如果程序没有下过断点,点全速后就会出现Keil卡死,也不知道什么原因,看程序代码像是在调用SWO_Data时被阻塞住了一样,而且在等待的时间里操作Keil像是也没法动一样了,非常慢一卡一卡的,进入了断点停下后就没这现象了,此时单步也是正常的,也就是说全速下,SWO有问题了,但在没开启SWO时调试和响应速度哪叫一个爽的啊,SWO部分的串口是直接搬了DAP例子工程里的串口驱动代码进去实现的,不知道是不是这个原因导致SWO被阻塞,或者自己另外写串口驱动提供给SWO,另外串口波特率最高只能2MHZ,超过这频率,SWO打印信息打印不出来的,串口波特率就是在Trace设置页面里看到的SWO 频率
( K3 P! m: M! Z& T4 j
然后改为使用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;) F4 o3 J( S) @: X( B: C* c! O3 H
在SWO里每一处调用osThreadFlagsSet的地方都改为如:
//osThreadFlagsSet(SWO_ThreadId, 1U);
SWO_EventFlags = 1U;
7 i8 T! B& b& H8 N/ d
// SWO Thread
/*__NO_RETURN void*/uint8_t SWO_Thread (void ) {
//uint32_t timeout;. K2 J: |; q4 F' A9 z, P6 ~
uint32_t flags;
uint32_t count;
uint32_t index;# m, Y$ W. u6 O
uint32_t i, n;# B- q' I6 q! k: U! E/ g
//(void) argument;
//timeout = osWaitForever;+ u4 F" S; s7 G5 O* ~/ V
) ]/ z3 B! c- Q$ J) I6 i
//for (;;) {
//flags = osThreadFlagsWait(1U, osFlagsWaitAny, timeout);2 U7 Y2 {. j* |9 ~7 H# M
if((SWO_EventFlags & 0x01)==0)return 0;7 y9 u9 U# v; C2 j$ D- t7 s
flags = SWO_EventFlags;- A: U3 y& R9 j. L
SWO_EventFlags = 0U;
if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) {* O) {% n: H- F5 n
//timeout = SWO_STREAM_TIMEOUT; 这里是对于进入了SWO_CAPTURE_ACTIVE状态时就把线程超时设置为50毫秒,大概意思应该是osThreadFlagsWait到达这个超时时间后,不管标志是否切换为1U,都放行SWO_Thread调用一次,timeout = osWaitForever时相当于无限长的超时等待1U标志,对RTX不熟悉,不知道是不是这样子
;
} else {! }- o6 G; d; y4 l; t! c2 L
//timeout = osWaitForever;
flags = osFlagsErrorTimeout;
}
if (TransferBusy == 0U) {
count = GetTraceCount();1 A; X# C w2 e5 {3 h
if (count != 0U) {; P9 Q- P! K* E3 |; J0 T
index = TraceIndexO & (SWO_BUFFER_SIZE - 1U);
n = SWO_BUFFER_SIZE - index;+ I4 L# }' ?4 D2 M
if (count > n) {# D( m2 a8 d2 l/ K" s" Z
count = n;7 j* @( |7 v6 U$ a' b% ?* `
6 Q1 Y: o& A( Q/ D( Z5 b. h" g( i5 I2 b* a
}
if(count>USB_BLOCK_SIZE)
count=USB_BLOCK_SIZE;
if (flags != osFlagsErrorTimeout) {
i = index & (USB_BLOCK_SIZE - 1U);
if (i == 0U) {
count &= ~(USB_BLOCK_SIZE - 1U);
} else {
n = USB_BLOCK_SIZE - i;! z6 c7 p$ ]( h. s, d
if (count >= n) {8 N p/ ]7 I/ A# p: ], X$ x$ H
count = n;) u2 ?3 ^) x" k; W; Y
} else {* g4 E6 Q9 n; V: L3 p6 C
count = 0U;
}( |1 z+ H5 p; `5 J; [$ Z
}
}4 S+ Z* ^1 A9 z8 c" Z
if (count != 0U) {& x G4 Y/ j1 ~$ p
TransferSize = count;
TransferBusy = 1U;' a( M6 V: y! N3 l! h9 _, @
SWO_QueueTransfer(&TraceBuf[index], count);9 O0 ~$ ~2 T5 v
}
}% B6 Q5 X) z8 ?. o0 ^& g0 H
}9 W, e7 T% Q" h' l3 q0 I m
//}; L0 F, E/ d+ X, i
return 0;
}
利用DWT增加超时等待,先声明变量timeout也在外面声明#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2).0 ~: i2 I9 ?/ d- Z: k0 F+ b
static volatile uint32_t SWO_EventFlags=0;
static volatile uint32_t timeout=osWaitForever;
static volatile uint32_t timeWait;( U; F, m2 E$ z5 ^1 D1 T8 K
函数改为这样/ B5 C% c+ P$ W# I3 j# d
/*__NO_RETURN void*/uint8_t SWO_Thread (void ) {/ t$ ]! p; ~- v6 a5 ]
//uint32_t timeout;
uint32_t flags;
uint32_t count;1 D" H6 P, M- T( S
uint32_t index;
uint32_t i, n;
//(void) argument;8 y0 g3 `8 a# N! P
//timeout = osWaitForever;
//for (;;) {( s+ }, i) @5 e) _6 m; h1 C
//flags = osThreadFlagsWait(1U, osFlagsWaitAny, timeout);6 r4 E; b# r2 C6 `7 T8 G2 @
if((SWO_EventFlags & 0x01)==0)2 M% N& c3 k* M* h% v6 g
{# ^3 f* Z& ]9 f9 j( y0 T [; c6 i* l! O
if((timeWait-=DWT->CYCCNT)/72000 < timeout) //少于timeout时间值直接返回,DWT->CYCCNT由于这计数值是按72M时钟计数的,所以72000就为1毫秒,0.001*72000000=72000,由于是与DAP处理是顺序执行,这个时间无法准确在50毫秒,但总来说与跑RTX系统 的超时等待差不多原理了) J. O8 f0 K, G( ^- Q, m. t
return 0;. q8 w: ?1 `) y) n" e e! [4 s' e) z
}: Q/ n* X' W3 x% o) v: l& d! i" h
: Z/ l+ |6 f! A1 V: W& Q
flags = SWO_EventFlags;
SWO_EventFlags = 0U;
if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) {
timeout = SWO_STREAM_TIMEOUT;* A: R& d. T6 q1 S' y) J
timeWait=DWT->CYCCNT;
} else {; H+ V4 ?5 p# s9 y3 ]1 W* n
timeout = osWaitForever;. ]4 Y4 @$ P/ z+ Z8 U. y. O
flags = osFlagsErrorTimeout;
}4 F' \+ g X+ V* A- Z
if (TransferBusy == 0U) {" x9 I$ f. q2 q( J; Q7 t8 \
count = GetTraceCount();
if (count != 0U) {
index = TraceIndexO & (SWO_BUFFER_SIZE - 1U);
n = SWO_BUFFER_SIZE - index;: c$ g4 o& f6 C% V7 |3 M+ `
if (count > n) {8 `: a1 y$ q4 \
count = n;
1 O! L) U. y4 G6 ] t" t
}" m0 m7 c# t7 o+ S1 I; N1 D
if(count>USB_BLOCK_SIZE)
count=USB_BLOCK_SIZE;! Q! |& M% X0 v+ w: G6 O) u
if (flags != osFlagsErrorTimeout) {6 O2 G* K" }9 K+ @+ C W. s' \/ X
i = index & (USB_BLOCK_SIZE - 1U);/ D4 T+ e! H5 w, x& g) [! \- {
if (i == 0U) {. e, \; x3 H: C6 G' e
count &= ~(USB_BLOCK_SIZE - 1U);
} else {
n = USB_BLOCK_SIZE - i;
if (count >= n) {
count = n; C3 l+ c" m0 }
} else {
count = 0U;& w5 `; ]4 I# j x3 t4 p
}1 [7 i4 b% X b# w* G' Q3 `1 }3 n
}
}% Z1 m7 t; N& ?( H* [/ f- f
if (count != 0U) {
TransferSize = count;
TransferBusy = 1U;
SWO_QueueTransfer(&TraceBuf[index], count);! @* j6 q) E+ F! H, G( h. M7 ^6 B3 ?
}# I+ i" ?* M6 d2 Z* w
}: y6 V$ h, Z$ r8 `/ [
}. N! ^4 E" O7 F, m
//}8 ^8 j2 R* t2 A* N) d( \
return 0;
}这样修改后也不知道能否解决Trace:dataOVERFLOW,也是刚想到的,试了才能知道了,另外还要说明一下,USB_BLOCK_SIZE是声明为512字节的,即SWO_QueueTransfer(&TraceBuf[index], count);时,如果count超过64字节后就得要分包发送了,这个USB库发送部分得自己分包发送,上面的SWO_QueueTransfer发送代码和端点回调处EP2_IN_Callback已经加入发分发送了
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,少了这个等待时间,能增加端点的传输速率
% L8 x7 }4 w( l
int main(void)! y! w; }9 g: D
{
DWT_Init();
DAP_Setup();3 k: w- P% Z( s e4 Q" P+ x! a
USB_Interrupts_Config();
Set_USBClock();* I9 W+ W: d: Z
USB_Init();
//TIM3_Init(35999,0);
//TIM_Cmd(TIM3,ENABLE);, I$ `) i! n. j/ ]6 @5 Y( V5 O
+ p5 [2 G {2 W1 y- p0 w# ^
while (1)
{1 s! v& R7 q8 g$ q9 C) k
DAP_Thread();
#if (SWO_STREAM != 0): I3 [4 e! M5 w% N" ~1 M
SWO_Thread();0 P! p% m; \5 f' ?! _# e3 P: }
#endif6 m% _! x+ m6 x8 F, u
}8 H% @9 ~3 }+ o# T2 p# R
}: c1 H6 P3 I b3 T/ `3 ^
对于DAP_config.h的IO配置我是这样弄的
///@}% f% s6 N6 i0 f' N
// Debug Port I/O Pins
// SWCLK/TCK Pin GPIOA[6]. D: _" u% ]3 j _
#define SWCLK_TCK_OUT *( uint32_t*)0x42210198
#define SWCLK_TCK_IN *( uint32_t*)0x42210118
// SWDIO/TMS Pin GPIOA[7]7 Z' E% f1 Z7 G0 Q5 H( Z
#define SWDIO_TMS_OUT *( uint32_t*)0x4221019C! d" W! l, W* i1 ^
#define SWDIO_TMS_IN *( uint32_t*)0x4221011C- G( ?! _4 h) k2 y j- Q
// SWDIO Output Enable Pin GPIOA[7]
#define SWDIO_Output() {*(uint32_t*)0x4221021C = 1; \. B$ S" W, c: |( \) S
*(uint32_t*)0x42210070 = 1; \. b* `. v0 k3 f3 Z
*(uint32_t*)0x42210074 = 1; \
*(uint32_t*)0x42210078 = 0; \
*(uint32_t*)0x4221007C = 0;}
#define SWDIO_Input() {*(uint32_t*)0x4221021C = 1; \
*(uint32_t*)0x42210070 = 0; \
*(uint32_t*)0x42210074 = 0; \+ }# E8 [6 _8 E* w( ]
*(uint32_t*)0x42210078 = 0; \) Q4 u0 e: u' |9 A7 V
*(uint32_t*)0x4221007C = 1; }
, U6 Z3 a0 D& r
// TDI Pin GPIOA[8]- |; o3 N) ]. Q' T/ C e
#define TDI_OUT *(volatile uint32_t*)0x422101A0
#define TDI_IN *(volatile uint32_t*)0x42210120
/ {1 m0 r H6 T. x2 Z N' I
// TDO Pin GPIOA[10]
#define TDO_OUT *(volatile uint32_t*)0x422101A8
#define TDO_IN *(volatile uint32_t*)0x42210128
# E& t; f p2 x
// nTRST Pin GPIOB[3]! e j* ] P0 Z7 b1 u
#define nTRST_OUT *(volatile uint32_t*)0x4221818C
#define nTRST_IN *(volatile uint32_t*)0x4221010C) w Y+ r* F' E9 p
// nRESET Pin GPIOB[4]
#define nRESET_OUT *(volatile uint32_t*)0x42218190
#define nRESET_IN *(volatile uint32_t*)0x42218110/ ]2 ?6 _4 Y) C
+ [7 [& K J& b$ E
// nRESET Output Enable Pin GPIOB[4]* f% ?( Z3 d" ^6 @
#define nRESET_Output() {*(uint32_t*)0x42218210 = 1; \ k+ y- O* R/ v! B, w
*(uint32_t*)0x42218040 = 1; \
*(uint32_t*)0x42218044 = 1; \
*(uint32_t*)0x42218048 = 0; \: h9 [7 ~/ M9 M/ S% [' x' n
*(uint32_t*)0x4221804C = 0; }
#define nRESET_Intput() {*(uint32_t*)0x42218210 = 1; \
*(uint32_t*)0x42218040 = 0; \2 H0 e) t8 C# |4 x
*(uint32_t*)0x42218044 = 0; \
*(uint32_t*)0x42218048 = 0;\ D1 o, O& T! D+ r& s/ C7 w3 n' I% d/ P
*(uint32_t*)0x4221804C = 1; }! n/ j& h7 |% {+ @4 x
// Debug Unit LEDs
// Connected LED GPIOC[13]
#define LED_OUT *(volatile uint32_t*)0x422201B4# h0 R; O- w! z% R
#define LED_IN *(volatile uint32_t*)0x42220134# x4 D( ]# p }: y/ F0 E; y, O; Z
#define LED_Intput() {*(uint32_t*)0x42220234 = 1; \: x% @! Z+ d* z: s1 Z3 \
*(uint32_t*)0x422200D0 = 0; \
*(uint32_t*)0x422200D4 = 0; \
*(uint32_t*)0x422200D8 = 0; \
*(uint32_t*)0x422200DC = 1; }" c! q- m9 c1 P! {" ]: l
// Target Running LED Not available! H- c7 b+ H* a! C) M
// SWCLK/TCK I/O pin -------------------------------------
/** SWCLK/TCK I/O pin: Get Input.' M* s+ B7 V% i8 c8 v6 g
\return Current status of the SWCLK/TCK DAP hardware I/O pin.
*/6 I4 C. x q ]; [ o
__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN (void) {' d- Y! P- S9 q9 k. y; A
return (SWCLK_TCK_IN);$ \" J" \% ~6 x* x1 {9 W
}
- q# h2 J. u+ w! x( j
/** SWCLK/TCK I/O pin: Set Output to High.: F3 N" F. {+ r7 ^# M
Set the SWCLK/TCK DAP hardware I/O pin to high level.
*/5 B: q2 G3 r% d" p. h' P$ }: L3 b
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET (void) {, d4 g) v* _. I4 U! b
SWCLK_TCK_OUT = 1;9 G+ v5 | u; v0 I; z( n5 q: ~# |2 s
}
" D+ ?3 w# M% _' T" i$ ?
/** SWCLK/TCK I/O pin: Set Output to Low.& F7 p* U; P% u/ \7 Z
Set the SWCLK/TCK DAP hardware I/O pin to low level.
*/
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR (void) {
SWCLK_TCK_OUT = 0;/ N) [, ?* M+ o1 m. p2 Q
}
! U7 T$ a- @* u2 j
// SWDIO/TMS Pin I/O --------------------------------------
: ~( a0 U8 I" [4 T5 c+ q
/** SWDIO/TMS I/O pin: Get Input.
\return Current status of the SWDIO/TMS DAP hardware I/O pin.. S5 Y, q5 {7 K, s
*/
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN (void) {
return (SWDIO_TMS_IN);
}! r8 m1 f/ a$ C; r# p% T
1 Z2 P$ Q5 [& s+ K% p q
/** SWDIO/TMS I/O pin: Set Output to High.$ i' N0 n; n: C6 \1 E0 g/ Y& f
Set the SWDIO/TMS DAP hardware I/O pin to high level.$ ]0 z& D8 W8 J" o; Z5 V! D
*/
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET (void) {8 I, }9 C3 \( B! n6 a
SWDIO_TMS_OUT = 1;- v! @6 w2 k; H8 P3 a# l7 i
}5 ]. Y( c9 X4 K6 C% ]$ a, J
2 M7 Y q3 m, ?2 F
/** SWDIO/TMS I/O pin: Set Output to Low.% U: P# R0 i+ x' k1 v* K! z
Set the SWDIO/TMS DAP hardware I/O pin to low level.
*/7 `, H T9 A$ N
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR (void) {
SWDIO_TMS_OUT = 0;9 I6 u( G( g3 C- M
}
/** SWDIO I/O pin: Get Input (used in SWD mode only).) t% r7 |$ [" T) F, i1 J6 h
\return Current status of the SWDIO DAP hardware I/O pin.
*/
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN (void) {4 o' n7 L ]& d: h8 d9 m
return (SWDIO_TMS_IN);' s% {& X% {; w. t$ ], f3 _
}
0 ]$ L. H. F4 z4 D" m% \( o" M7 g
/** SWDIO I/O pin: Set Output (used in SWD mode only).
\param bit Output value for the SWDIO DAP hardware I/O pin.' p( I8 E! X1 O/ p7 }0 P6 T- e& T- P
*/4 e A) D* A. S' P# q$ u
__STATIC_FORCEINLINE void PIN_SWDIO_OUT (uint32_t bit) {. Y' \5 q/ F) i4 j; y) G# R: c0 O! v
SWDIO_TMS_OUT = bit;
}" U7 ]+ O& U: O/ g
/** SWDIO I/O pin: Switch to Output mode (used in SWD mode only).8 u/ z( V$ R+ b
Configure the SWDIO DAP hardware I/O pin to output mode. This function is
called prior \ref PIN_SWDIO_OUT function calls.
*/
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE (void) {5 _8 w3 W% K. G9 C
SWDIO_Output();
}1 h7 M0 e7 b' j1 a! }
/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only).' X$ g5 B! \9 M {' p' f
Configure the SWDIO DAP hardware I/O pin to input mode. This function is
called prior \ref PIN_SWDIO_IN function calls.
*/
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE (void) {$ V9 O& O4 n! F: X/ J
SWDIO_Input();
}
楼上有的说弄无线,其实无线也就是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驱动的大佬可以尝试一下- T! |2 R+ P% Q" b! ?
有人将这个工程移植到stm32f4上吗,我在网上找了一个f4的dap工程,但是编译下载后无法使用。