5

我试图让 UART 传输在 stm32f405 上通过 DMA 工作。我的应用程序的这一部分旨在将文本字符串作为命令行界面发送出去。我有 UART 的 RX 部分与 DMA 一起工作(使用 1 字节循环 DMA 来处理任何进来的东西),但 TX 端被证明有点棘手。

我可以使用以下方法发送数据字符串:HAL_UART_Transmit_DMA(&handle, pData[], strlen(pData))只要函数的连续调用之间存在延迟。一旦我的程序决定一个接一个地发送两个字符串,新的数据指针就会被忽略。

通过使用while(HAL_UART_Transmit_DMA(...) != HAL_OK){},我可以让程序等待所需的时间并发送连续的字符串。

这工作了一段时间(几十次传输),然后由于 HAL_NOT_OK 而卡住。

作为参考,我的 DMA 设置是:DMA2 stream 7, channel 4, mem to periph, periph inc disabled, mem inc enabled, mem and periph align byte, normal mode (not circular), low priority, fifo disabled.

UART 设置为9600 baud, 8 bit word, 1 stop bit, no parity, no hw control, 16 oversampling.

我试图弄清楚使用 FIFO 是否会帮助我,尽管我不完全确定我是否理解它。如果我想发送一个字节的数据,我可以用 FIFO 来做吗?这里有 1 个字的最小限制吗?

我已经设置了一个tx complete callback我目前没有使用的。我确实想知道在此中断期间是否需要清除任何标志,但不确定..

任何帮助表示赞赏!

4

3 回答 3

3

我已经设置了一个我当前没有使用的 tx 完成回调。我确实想知道在此中断期间是否需要清除任何标志,但不确定。

您应该在再次使用之前等待tx complete回调HAL_UART_Transmit_DMA。就像是:

bool txDoneFlag = false;
HAL_UART_Transmit_DMA(...)
while(!txDoneFlag);
txDoneFlag = false;
...
...


void HAL_UART_TxCpltCallback(){
    txDoneFlag = true;
}
于 2015-08-18T17:12:39.140 回答
1

HammerFet,我相信您将需要使用循环模式(例如DMA_Mode_Circular)。试试看。

此外,请查看STM32F4 应用笔记中非常简短的第 1.1.8 节,其中说明如下:

正常模式:一旦 DMA_SxNDTR 寄存器达到零,则流被禁用(然后 DMA_SxCR 寄存器中的 EN 位等于 0)。

如下所示的 DMA 配置设置示例:

volatile char Buffer[] = "first uart test with stm32f4\r\n";

void DMA_Configuration(void)
{

  DMA_InitTypeDef  DMA_InitStructure;

  DMA_DeInit(DMA1_Stream2);

  DMA_InitStructure.DMA_Channel = DMA_Channel_4;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Receive
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer;
  DMA_InitStructure.DMA_BufferSize = (uint16_t)sizeof(Buffer);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

  DMA_Init(DMA1_Stream2, &DMA_InitStructure);

  /* Enable the USART Rx DMA request */
  USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);

  /* Enable DMA Stream Half Transfer and Transfer Complete interrupt */
  DMA_ITConfig(DMA1_Stream2, DMA_IT_TC | DMA_IT_HT , ENABLE);

  /* Enable the DMA RX Stream */
  DMA_Cmd(DMA1_Stream2, ENABLE);

}
于 2015-02-13T13:19:52.380 回答
1

如果您以高波特率 (>1MBaud) 进行传输,则用于传输的 FIFO 很有用。发生的情况是处理器无法足够快地为 UART 提供数据,然后可能会发生与缓冲区下溢相关的错误。您还可以更改为 UART 提供数据的 DMA 通道的优先级。

循环模式对 TX 没多大用处,因为它会无休止地重新传输缓冲区中的数据,除非您及时更新它。虽然我发现循环缓冲区对于接收数据非常有用。

我也遇到过问题,如果传输的字节数很小(<10Bytes),DMA 传输会在一段时间后失败。使用 IT 功能没有问题。我一直找不到原因。因此,对于 < 10 字节的消息,我使用 IT 传输功能,对于 >= 10 字节的消息,我使用 DMA 传输功能。

于 2015-11-30T12:50:15.473 回答