源:​​STM32的USART DMA传输​

 

问题描述:

     我有一个需求,AD采得一定数目的数据之后,由串口DMA发出,由于AD使用双缓冲,所以每次开始DMA的时候都需要重新设置开始的内存地址以及传输的数目(这些都是理所当然的),但是在开始调试的时候,遇到了一些问题,问题如下:当第一次DMA传输完毕,关闭DMA以设置内存地址等,再开启DMA,发现不启动了。

      开始是参考了《STM32中文参考手册REV10》,里面的发送步骤如下:



1. 在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE事件后,数据将被传送到这个地址。
2. 在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从此存储器区读出数据并传送到USART_DR寄存器。
3. 在DMA控制寄存器中配置要传输的总的字节数。
4. 在DMA寄存器上配置通道优先级。
5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断。
6. 在DMA寄存器上激活该通道。


检查代码,发现没问题,但是问题还是解决不了,就找了英文的参考手册(REV14),发现上面的步骤有了些修改:



1. Write the USART_DR register address in the DMA control register to configure it as the
destination of the transfer. The data will be moved to this address from memory after
each TXE event.
2. Write the memory address in the DMA control register to configure it as the source of
the transfer. The data will be loaded into the USART_DR register from this memory
area after each TXE event.
3. Configure the total number of bytes to be transferred to the DMA control register.
4. Configure the channel priority in the DMA register
5. Configure DMA interrupt generation after half/ full transfer as required by the
application.
6. Clear the TC bit in the SR register by writing 0 to it.
7. Activate the channel in the DMA register.
When the number of data transfers programmed


多了一步,即第6步,清除SR寄存器的TC标志位。照做,ok了。

 

重启DMA传输成功的条件:

后来,又做了其他一些测试,发现即使不清除TC标志位,只要把对应DMA通道的TCIF标志(传输完成标志,DMA_ISR寄存器里面)清除,同样也可以正常重启传输。所以,要重启传输,保证在重新ENABLE DMA之前,满足以下两个条件之一即可:

  • DMA_ISR 对应的TCIF标志清除
  • USART_SR 的TC标志位清除

一个诡异的问题:

发现即使上面提到的两个条件都不满足,但是下面的代码依然可以正常传输:

 



//ENBALE 之前USART1的TC,DMA1 对应USART TX的DMA通道TC标志都已经置位,没有清除
DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);
while((USART1->SR & USART_FLAG_TC) == 0x00);


 

这样也可以。但是只要换成:



DMA_Cmd(USART1_Tx_DMA_Channel, ENABLE);

/* Wait until USARTy TX DMA1 Channel Transfer Complete */
while (DMA_GetFlagStatus(USART1_Tx_DMA_FLAG ) == RESET) {
}


就不行了。比较奇怪。

 

结论:

不管那些诡异的问题了,以后重启DMA之前,清除串口的TC或者DMA的TC。不过根据使用的感觉,清除DMA的TC简单些。