|
问题描述: 我有一个需求,AD采得一定数目的数据之后,由串口DMA发出,由于AD使用双缓冲,所以每次开始DMA的时候都需要重新设置开始的内存地址以及传输的数目(这些都是理所当然的),但是在开始调试的时候,遇到了一些问题,问题如下:当第一次DMA传输完毕,关闭DMA以设置内存地址等,再开启DMA,发现不启动了。 开始是参考了《STM32中文参考手册REV10》,里面的发送步骤如下: - 1. 在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE事件后,数据将被传送到这个地址。0 H3 ~3 Y; N& `1 m
- 2. 在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从此存储器区读出数据并传送到USART_DR寄存器。
6 }1 B0 T }2 A - 3. 在DMA控制寄存器中配置要传输的总的字节数。4 S6 A. ` O+ j& w2 z5 V- N
- 4. 在DMA寄存器上配置通道优先级。
m. r, O; B: v! N4 D - 5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断。5 u Y1 m, P4 @$ l; o+ a [0 S5 K
- 6. 在DMA寄存器上激活该通道。
复制代码
. C8 M( m! q" |1 N6 a, K5 I* ^检查代码,发现没问题,但是问题还是解决不了,就找了英文的参考手册(REV14),发现上面的步骤有了些修改: - 1. Write the USART_DR register address in the DMA control register to configure it as the
9 n! ~, y$ M1 t3 b0 e" a - destination of the transfer. The data will be moved to this address from memory after+ C4 }1 s% z D$ u1 T! R7 B+ \" p
- each TXE event.% z8 Z5 ^* N3 _' E7 R5 d
- 2. Write the memory address in the DMA control register to configure it as the source of* g4 B/ y, S1 s0 f
- the transfer. The data will be loaded into the USART_DR register from this memory6 ?$ [- i0 T# o2 A' y1 C' t9 X- y# r! w
- area after each TXE event.5 w5 ~, e& l) K, B% L
- 3. Configure the total number of bytes to be transferred to the DMA control register.
. ~* S. g$ T7 i% T W, L - 4. Configure the channel priority in the DMA register7 x+ N5 p0 P0 l( J( p ]
- 5. Configure DMA interrupt generation after half/ full transfer as required by the
, Q1 f* a7 O ^" W. {' `0 h - application.
) v5 C% ]: g8 W5 t - 6. Clear the TC bit in the SR register by writing 0 to it.
: |, D; u. I; G7 O. [+ H - 7. Activate the channel in the DMA register.
* P$ }0 t* Z- J/ U1 X* [& V& U - When the number of data transfers programmed
复制代码 # ?; z; i, c2 a9 f
多了一步,即第6步,清除SR寄存器的TC标志位。照做,ok了。
3 f7 ~6 _, l) v) N, ~0 o% D重启DMA传输成功的条件:后来,又做了其他一些测试,发现即使不清除TC标志位,只要把对应DMA通道的TCIF标志(传输完成标志,DMA_ISR寄存器里面)清除,同样也可以正常重启传输。所以,要重启传输,保证在重新ENABLE DMA之前,满足以下两个条件之一即可: - DMA_ISR 对应的TCIF标志清除
- USART_SR 的TC标志位清除% |9 f% |7 h0 M2 N% s
一个诡异的问题:发现即使上面提到的两个条件都不满足,但是下面的代码依然可以正常传输:1 o/ p" U# J* {: N2 S" R# ^
- //ENBALE 之前USART1的TC,DMA1 对应USART TX的DMA通道TC标志都已经置位,没有清除
0 @5 s/ N- N% j; d/ R( b - DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);; f s; l6 b; t, u
- while((USART1->SR & USART_FLAG_TC) == 0x00);
复制代码
% w4 y% ]# J4 o' D这样也可以。但是只要换成: - DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);) ^* M/ Y! N, K$ ]
-
. |& `- c y0 a3 p. t" S0 T - /* Wait until USARTy TX DMA1 Channel Transfer Complete */4 a. a' p3 o8 R* W1 F
- while (DMA_GetFlagStatus(USART1_Tx_DMA_FLAG ) == RESET) {: H7 V1 X- i) Y t
- }
复制代码
& @5 u5 V D$ Y6 W8 E$ |* [5 Y就不行了。比较奇怪。
3 }2 `0 Z( C+ v( |: r结论:不管那些诡异的问题了,以后重启DMA之前,清除串口的TC或者DMA的TC。不过根据使用的感觉,清除DMA的TC简单些。
2 _8 s! u d' L |