|
问题描述: 我有一个需求,AD采得一定数目的数据之后,由串口DMA发出,由于AD使用双缓冲,所以每次开始DMA的时候都需要重新设置开始的内存地址以及传输的数目(这些都是理所当然的),但是在开始调试的时候,遇到了一些问题,问题如下:当第一次DMA传输完毕,关闭DMA以设置内存地址等,再开启DMA,发现不启动了。 开始是参考了《STM32中文参考手册REV10》,里面的发送步骤如下: - 1. 在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE事件后,数据将被传送到这个地址。5 c x( \- o& z4 X2 Y
- 2. 在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从此存储器区读出数据并传送到USART_DR寄存器。
. r P: N9 f) u& X, _; D l8 n - 3. 在DMA控制寄存器中配置要传输的总的字节数。
7 @5 S9 `; A* n/ K9 o- Y& l$ t1 J - 4. 在DMA寄存器上配置通道优先级。) t4 C% P* R7 h. r% h/ F
- 5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断。0 r6 g% a S4 E1 O/ {: s3 D
- 6. 在DMA寄存器上激活该通道。
复制代码
# Z0 Z! B7 { V y& h$ e2 @检查代码,发现没问题,但是问题还是解决不了,就找了英文的参考手册(REV14),发现上面的步骤有了些修改: - 1. Write the USART_DR register address in the DMA control register to configure it as the- }7 w. W3 I7 |" E; S
- destination of the transfer. The data will be moved to this address from memory after
/ N* V. G% c2 N1 U - each TXE event.% b I& r' X3 B' C2 \% S/ l
- 2. Write the memory address in the DMA control register to configure it as the source of
k2 \+ Y5 s2 c% W+ I" M - the transfer. The data will be loaded into the USART_DR register from this memory
f- a2 R7 @/ O$ w U5 q8 F - area after each TXE event.
s. t5 n! u' \# } - 3. Configure the total number of bytes to be transferred to the DMA control register.6 E+ O; t2 S7 p
- 4. Configure the channel priority in the DMA register
2 G6 c V% c3 W0 F! e - 5. Configure DMA interrupt generation after half/ full transfer as required by the
" T' Z: c3 g, A( I+ m; }4 T2 Y - application.
5 ^# h6 [2 V* M6 i3 V - 6. Clear the TC bit in the SR register by writing 0 to it.1 e* F$ C" r8 M
- 7. Activate the channel in the DMA register.
: t& L$ `6 Y/ O$ ], b% K - When the number of data transfers programmed
复制代码
! N6 \) l( Y# Z2 w- A) _+ Q, z多了一步,即第6步,清除SR寄存器的TC标志位。照做,ok了。
$ X7 n( ]) n- T- `重启DMA传输成功的条件:后来,又做了其他一些测试,发现即使不清除TC标志位,只要把对应DMA通道的TCIF标志(传输完成标志,DMA_ISR寄存器里面)清除,同样也可以正常重启传输。所以,要重启传输,保证在重新ENABLE DMA之前,满足以下两个条件之一即可: - DMA_ISR 对应的TCIF标志清除
- USART_SR 的TC标志位清除
" O7 W6 Z9 ]) I 一个诡异的问题:发现即使上面提到的两个条件都不满足,但是下面的代码依然可以正常传输:
4 @# l4 T, {+ J$ i+ D - //ENBALE 之前USART1的TC,DMA1 对应USART TX的DMA通道TC标志都已经置位,没有清除
" k" [: s! f) l+ e5 I4 `' n - DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);3 @5 R# S/ B1 U g! c6 z4 |* H; q0 {
- while((USART1->SR & USART_FLAG_TC) == 0x00);
复制代码
( z+ {( i# s$ s% T9 _. F' F' F2 p这样也可以。但是只要换成: - DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);
2 E# O/ E9 H' ?4 k1 f - : D3 A6 r4 a( y0 P
- /* Wait until USARTy TX DMA1 Channel Transfer Complete */
$ F9 ?* g: L/ n1 s$ x6 W% c) x - while (DMA_GetFlagStatus(USART1_Tx_DMA_FLAG ) == RESET) {/ H9 w2 |5 F4 N* D- `
- }
复制代码
" v. Q5 s6 E: O0 U) p( c就不行了。比较奇怪。 ( B& Z, v8 x; ~# K& w
结论:不管那些诡异的问题了,以后重启DMA之前,清除串口的TC或者DMA的TC。不过根据使用的感觉,清除DMA的TC简单些。 4 K: M( @/ O8 r; I5 v2 y* l% W# @0 z
|