STM32F4 HAL DMA UART TX

5
我正在尝试在stm32f405上使用DMA实现UART传输。这部分应用程序旨在将文本字符串发送为命令行界面。我已经成功使用1字节循环DMA处理RX端的UART(处理任何进来的数据),但TX端证明有些棘手。
只要函数调用之间有延迟,我就能够使用HAL_UART_Transmit_DMA(&handle, pData[], strlen(pData))发送数据字符串。但是,一旦我的程序决定连续发送两个字符串,新的数据指针就会被忽略。
通过使用while(HAL_UART_Transmit_DMA(...) != HAL_OK){},我可以让程序等待所需时间并连续发送字符串。
这可以工作一段时间(几十次传输),然后由于HAL_NOT_OK而卡住。
参考资料,我的DMA设置为:DMA2 stream 7channel 4mem to periphperiph inc disabledmem inc enabledmem and periph align bytenormal mode (not circular)low priorityfifo disabled
UART设置为9600 baud8 bit word1 stop bitno parityno hw control16 oversampling
我正在尝试弄清楚使用FIFO是否会帮助我。如果我想发送单个字节的数据,我能用FIFO吗?这里有1个字最小限制吗?
我已经设置了一个tx complete callback,但目前没有使用。我想知道在此中断期间是否需要清除任何标志,但不确定。
感谢任何帮助!
3个回答

3

我设置了一个tx完成的回调函数,但目前没有使用。我想知道在这个中断期间是否需要清除任何标志。

在再次使用HAL_UART_Transmit_DMA之前,你应该等待tx complete回调函数,例如:

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


void HAL_UART_TxCpltCallback(){
    txDoneFlag = true;
}

2

如果你以高波特率(>1MBaud)进行传输,则使用FIFO发送有用。当处理器无法快速提供UART并且缓冲区发生下溢错误时,就会出现问题。您还可以更改馈送UART的DMA通道的优先级。

循环模式对于TX来说并不那么有用,因为除非您及时更新数据缓冲区,否则它将无限期地重复传输数据。尽管我认为循环缓冲区非常适用于接收数据。

我也遇到过这样的问题,当传输的字节数很少(<10Bytes)时,DMA传输在一段时间后会失败。使用IT功能可以无问题工作。我从未能找到原因。因此,对于消息<10字节,我使用IT传输函数,对于消息>=10字节,我使用DMA传输函数。


我在STM32H743上遇到了完全相同的问题。@Flip,你最终找到了这个失败的原因吗? - Shahar Hadas
@ShaharHadas 不,我的数据包最小为32字节,所以这不再是一个问题。我还没有再去研究它。 - Flip
1
无论如何,您在这里的小评论似乎已解决了我们的问题。我在STM的文档中找不到任何关于这个问题的资料。您能否从STM得到官方回复? 您知道更新的HAL版本是否仍然存在这个问题吗?(我正在使用一个非常旧的HAL项目,但当我们尝试升级时 - 问题消失了,但我不知道它是否与HAL版本有关还是更难以复制) - Shahar Hadas

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);

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接