问题描述: 我有一个需求,AD采得一定数目的数据之后,由串口DMA发出,由于AD使用双缓冲,所以每次开始DMA的时候都需要重新设置开始的内存地址以及传输的数目(这些都是理所当然的),但是在开始调试的时候,遇到了一些问题,问题如下:当第一次DMA传输完毕,关闭DMA以设置内存地址等,再开启DMA,发现不启动了。 开始是参考了《STM32中文参考手册REV10》,里面的发送步骤如下: - 1. 在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE事件后,数据将被传送到这个地址。
/ e0 G+ H. f# M: k X0 R - 2. 在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从此存储器区读出数据并传送到USART_DR寄存器。
! D0 g0 z6 X* U# ?) q6 K - 3. 在DMA控制寄存器中配置要传输的总的字节数。
4 d. T+ s- b! Q0 @4 l# \0 \: ^ - 4. 在DMA寄存器上配置通道优先级。
8 T6 ]3 v. {2 p - 5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断。" g! P" s+ p" G c; J J
- 6. 在DMA寄存器上激活该通道。
复制代码
2 [1 O. p5 M' r! B/ k4 r; e7 p检查代码,发现没问题,但是问题还是解决不了,就找了英文的参考手册(REV14),发现上面的步骤有了些修改: - 1. Write the USART_DR register address in the DMA control register to configure it as the1 W% T0 t* [ |* o6 P# R; B
- destination of the transfer. The data will be moved to this address from memory after
/ |! M2 I- N* J( Q8 P% @ - each TXE event.
" y" Y, @! i& R' K {- k4 s - 2. Write the memory address in the DMA control register to configure it as the source of
0 H; W2 Q7 |0 q2 g' @3 h0 p( {5 z - the transfer. The data will be loaded into the USART_DR register from this memory
6 i) `- f9 V a/ Z* K - area after each TXE event.
M' }; `- X }) m - 3. Configure the total number of bytes to be transferred to the DMA control register.
! d7 j5 H L% H' C9 l# Z - 4. Configure the channel priority in the DMA register7 V8 x6 D0 D# `% g* G9 U8 B4 v( N
- 5. Configure DMA interrupt generation after half/ full transfer as required by the) K0 S5 j P. U) Y8 V# G
- application.$ H: }1 w' p* @& k2 I7 Z2 k
- 6. Clear the TC bit in the SR register by writing 0 to it./ ?9 q2 h: R& ?; G
- 7. Activate the channel in the DMA register.( T* {* ^3 g. V6 H3 w
- When the number of data transfers programmed
复制代码
# e% B" w( P; H6 h多了一步,即第6步,清除SR寄存器的TC标志位。照做,ok了。
& J3 U% p" w+ H# W" X, f. @重启DMA传输成功的条件:后来,又做了其他一些测试,发现即使不清除TC标志位,只要把对应DMA通道的TCIF标志(传输完成标志,DMA_ISR寄存器里面)清除,同样也可以正常重启传输。所以,要重启传输,保证在重新ENABLE DMA之前,满足以下两个条件之一即可: - DMA_ISR 对应的TCIF标志清除
- USART_SR 的TC标志位清除
[3 I. i7 b6 { 一个诡异的问题:发现即使上面提到的两个条件都不满足,但是下面的代码依然可以正常传输:
# g& ~5 n6 q J- L3 T - //ENBALE 之前USART1的TC,DMA1 对应USART TX的DMA通道TC标志都已经置位,没有清除+ }8 |1 s' L% a
- DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);1 c; w9 i% t2 U( w, X/ a
- while((USART1->SR & USART_FLAG_TC) == 0x00);
复制代码
x; b! s7 [+ H5 Z这样也可以。但是只要换成: - DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);
0 c9 d# s% Y3 J* M - " S% z1 Q3 F2 \: O
- /* Wait until USARTy TX DMA1 Channel Transfer Complete */
6 F! T6 {* B1 b/ J- l! m - while (DMA_GetFlagStatus(USART1_Tx_DMA_FLAG ) == RESET) {
( o9 ^, U6 g |8 X. d4 a - }
复制代码 ; L7 d- m9 Q# q. P" ?
就不行了。比较奇怪。 & ^7 w1 K9 ?4 y
结论:不管那些诡异的问题了,以后重启DMA之前,清除串口的TC或者DMA的TC。不过根据使用的感觉,清除DMA的TC简单些。
3 _- m* Z3 w" a# O, X% t5 X |