STM32:未对齐的循环DMA UART缓冲区

STM32:未对齐的循环DMA UART缓冲区,stm32,uart,dma,cortex-m,hal,Stm32,Uart,Dma,Cortex M,Hal,对于我的STM32L053微控制器应用程序,我需要一个稳定的UART RX缓冲区,用于github的DMA实现,它基于ST HAL: 如果RX输入数据根据相应的缓冲区大小对齐,则此实现工作相当稳定。例如,如果缓冲区大小为24字节,并且所有传入数据请求的大小都是该缓冲区长度的倍数,例如,每个请求8字节,则缓冲区溢出可以正常工作,不会出现问题 我的应用程序使用不同的消息长度,因此我发现此实现存在未对齐缓冲区溢出的弱点。例如,如果缓冲区长度设置为23字节,则前两个8字节消息都正确传递,但下一个8字节消

对于我的STM32L053微控制器应用程序,我需要一个稳定的UART RX缓冲区,用于github的DMA实现,它基于ST HAL:

如果RX输入数据根据相应的缓冲区大小对齐,则此实现工作相当稳定。例如,如果缓冲区大小为24字节,并且所有传入数据请求的大小都是该缓冲区长度的倍数,例如,每个请求8字节,则缓冲区溢出可以正常工作,不会出现问题

我的应用程序使用不同的消息长度,因此我发现此实现存在未对齐缓冲区溢出的弱点。例如,如果缓冲区长度设置为23字节,则前两个8字节消息都正确传递,但下一个8字节消息没有正确传输

为此,我扩展了
HAL\u UART\u RxCpltCallback
例程,通过使用
CNDTR
DMA寄存器并记住变量
DMA\u UART\u rx.prevCNDTR
中的最后一个值来处理未对齐的缓冲区溢出:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
{
  uint16_t i, pos, start, length;
  uint32_t currCNDTR = huart.hdmarx->Instance->CNDTR;

  /* Ignore IDLE Timeout when the received characters exactly filled up the DMA buffer and DMA Rx Complete IT is generated, but there is no new character during timeout */
  if((dma_uart_rx.flag && currCNDTR == DMA_BUF_SIZE) || error_flag)
  {
    error_flag = RESET;
    dma_uart_rx.flag = 0;
    return;
  }

  /* Determine start position in DMA buffer based on previous CNDTR value */
  start = (dma_uart_rx.prevCNDTR < DMA_BUF_SIZE) ? (DMA_BUF_SIZE - dma_uart_rx.prevCNDTR) : 0;

  if (dma_uart_rx.flag)    /* Timeout event */
  {
    /* Determine new data length based on previous DMA_CNDTR value:
     *  If previous CNDTR is less than DMA buffer size: there is old data in DMA buffer (from previous timeout) that has to be ignored.
     *  If CNDTR == DMA buffer size: entire buffer content is new and has to be processed.
    */
    length = (dma_uart_rx.prevCNDTR < DMA_BUF_SIZE) ? (dma_uart_rx.prevCNDTR - currCNDTR) : (DMA_BUF_SIZE - currCNDTR);
    dma_uart_rx.prevCNDTR = currCNDTR;
    dma_uart_rx.flag = 0;
  }
  else                /* DMA Rx Complete event */
  {
    // My buffer overrun handling
    if (currCNDTR > dma_uart_rx.prevCNDTR) 
    {
      length = dma_uart_rx.prevCNDTR + DMA_BUF_SIZE - currCNDTR;

      // 1st rx data part
      for (i=0, pos=DMA_BUF_SIZE - dma_uart_rx.prevCNDTR; pos < DMA_BUF_SIZE; ++i,++pos)
      {
        data[i] = dma_rx_buf[pos];
      }

      // 2nd rx data part
      for (pos=0; pos < DMA_BUF_SIZE - currCNDTR; ++i,++pos)
      {
        data[i] = dma_rx_buf[pos];
      }

      receivedBytes = length;
      dma_uart_rx.prevCNDTR = currCNDTR;
      return;
    }

    length = DMA_BUF_SIZE - start;
    dma_uart_rx.prevCNDTR = DMA_BUF_SIZE;
  }

  /* Copy and Process new data */
  for (i=0,pos=start; i<length; ++i,++pos)
  {
    data[i] = dma_rx_buf[pos];
  }

  receivedBytes = length;
}
void HAL\u UART\u RxCpltCallback(UART\u HandleTypeDef*uartHandle)
{
uint16_t i,位置,起点,长度;
uint32\u t currccndtr=huart.hdmarx->Instance->CNDTR;
/*当接收到的字符完全填满DMA缓冲区并生成DMA接收完成时,忽略空闲超时,但超时期间没有新字符*/
if((dma_uart_rx.flag&&currCNDTR==dma_BUF_SIZE)| error_flag)
{
错误标志=重置;
dma_uart_rx.flag=0;
返回;
}
/*根据先前的CNDTR值确定DMA缓冲区中的起始位置*/
开始=(dma_uart_rx.prevCNDTRdma\U uart\U rx.prevCNDTR)
{
长度=dma_uart_rx.prevCNDTR+dma_BUF_SIZE-currccndtr;
//第一接收数据部分
对于(i=0,pos=DMA_BUF_SIZE-DMA_uart_rx.prevCNDTR;pos对于(i=0,pos=start;i对齐没有任何共同之处。您需要处理两个事件-DMA传输结束-当CNDR达到零并且从USART空闲时发生,以发现USART传输结束。NTDR将低于在后台发生的传输,并且触发brea,这是非常合理的kpoint需要一些时间。

对齐没有什么共同之处。您需要处理两个事件-DMA传输结束-当CNDR达到零并且从USART空闲时发生,以发现USART传输结束。NTDR将低于在后台和触发器中发生的传输,这是非常合乎逻辑的调用断点需要一些时间。

因为ARM处理器的整个Mx系列(也称为Thumb)在AMBA总线DMA pcore上至少有4条地址线被跳过,所以所有DMA相关的缓冲区都必须与32字节对齐

gcc编译器示例:

uint8_t dumpBuffer[2][DUMP_LIMIT] __attribute__ ((aligned(32)));

另外,在处理DMA时,请始终记住至少有两个缓冲区-一个由DMA使用,另一个由应用程序使用。

,因为整个Mx系列(又名Thumb)在AMBA总线DMA pcore上至少有4条地址线的ARM处理器中,所有DMA相关的缓冲区都必须与32字节对齐

gcc编译器示例:

uint8_t dumpBuffer[2][DUMP_LIMIT] __attribute__ ((aligned(32)));

另外,在处理DMA时,请始终记住至少有两个缓冲区-一个由DMA使用,另一个由应用程序使用。

如果没有调试/断点,也会出现问题。请您解释一下,为什么此实现可以在缓冲区大小为24和读取请求为8字节的情况下正常工作(我进行了几个小时的测试运行,没有出现任何问题),但如果我将缓冲区大小减少到23字节,并且仍然请求8字节,则每个缓冲区溢出都会导致传入数据损坏(接下来的2个请求会按照估计再次工作,直到下一个损坏的缓冲区溢出,依此类推……)?如果不存在调试/断点,也会出现问题。请您解释一下,为什么此实现在缓冲区大小为24且读取请求为8字节的情况下工作而没有问题(我进行了几个小时的测试,没有任何问题)但是,如果我将缓冲区大小减少到23字节,并且仍然请求8字节,那么每个缓冲区溢出都会导致传入数据损坏(接下来的2个请求会按照估计再次工作,直到下一个损坏的缓冲区溢出,依此类推?