title: STM32: unaligned circular DMA UART buffer
body: <p>for my STM32L053 microcontroller application I need a stable UART RX buffer and used for that the DMA implementation from github, which is based on the ST HAL: <a href="https://github.com/akospasztor/stm32-dma-uart" rel="nofollow noreferrer">https://github.com/akospasztor/stm32-dma-uart</a>.</p>
  
  <p>This implementation works quite stable if the RX input data is aligned according to the corresponding buffer size. For example if the buffer size is 24 bytes and all incoming data requests have a multiple size of this buffer length is, let`s say for example 8 bytes per requests, a buffer overrun works fine without problems.</p>
  
  <p>My application uses different message lengths, so I discovered that this implementation has a weakness for unaligned buffer overrun. For example if the buffer length is set to 23 bytes the first both 8 byte messages are passed correctly, but the next 8 bytes message are not correctly transmitted.</p>
  
  <p>For this I extended the <code>HAL_UART_RxCpltCallback</code> routine for handling an unaligned buffer overrun by using the <code>CNDTR</code> DMA register and remembering it´s last value in the variable <code>dma_uart_rx.prevCNDTR</code>:</p>
  
  <pre><code>void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
  {
    uint16_t i, pos, start, length;
    uint32_t currCNDTR = huart.hdmarx-&gt;Instance-&gt;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 &amp;&amp; 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 &lt; 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 &lt; 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 &gt; 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 &lt; DMA_BUF_SIZE; ++i,++pos)
        {
          data[i] = dma_rx_buf[pos];
        }
  
        // 2nd rx data part
        for (pos=0; pos &lt; 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&lt;length; ++i,++pos)
    {
      data[i] = dma_rx_buf[pos];
    }
  
    receivedBytes = length;
  }
  </code></pre>
  
  <p>Until this point everything works seamless, but then I figured out a strange behavior of the <code>CNDTR</code> register on a buffer overrun:
  If I halt on a breakpoint after assigning the <code>CNDTR</code> register value to the variable <code>currCNDTR</code> and then compare the current register value of the <code>CNDTR</code> register with the mentioned variable in the debugger, the variable is always 1 byte higher than the register value of <code>CNDTR</code>, although there are no other assignments of the variable?!</p>
  
  <p><a href="https://i.stack.imgur.com/M5sQY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/M5sQY.png" alt="enter image description here"></a></p>
  
  <p>Can someone please help me figuring out, what I am doing wrong here?</p>