STM32F0 DMA "input overflow"

Yuriy

I have a problem with STM32F0 DMA receiving data from UART. I use 2 DMA channels (for rx and tx) both in non-circular mode, rx channel has lower priority. Data from UART handles in Idle Line interrupt, where I read the number of DMA received bytes and process them. Everything works fine until the number of bytes in package is less than or equal to DMA buffer size. Otherwise DMA strangely turns off and following Idle Line interrupts give me the 1, 0, 0, ... number of DMA received bytes. Here is part of the code, where I check if the DMA buffers fills and try to reset DMA counter to buffer size:

#define S_M_INPUT_CMD_SIZE 20
static char s_m_uart_dma_in_buff[S_M_INPUT_CMD_SIZE + 1]; 

void USART1_IRQHandler(void)
{
   ITStatus reception_status = USART_GetITStatus(USART1, USART_IT_IDLE);
   if(reception_status != RESET)
   {
      int32_t bytes_number = S_M_INPUT_CMD_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);            
      if (DMA_GetFlagStatus(DMA1_FLAG_TC3) != RESET)
      {
         USART_ITConfig(UART_, USART_IT_IDLE, DISABLE);
         DMA_Cmd(DMA1_Channel3, DISABLE);
         while (DMA1_Channel3->CCR & DMA_CCR_EN);
         for (int i = 0; i < S_M_INPUT_CMD_SIZE; i++)
            s_m_uart_dma_in_buff[i] = '\0'; 
         DMA_SetCurrDataCounter(DMA1_Channel3, S_M_INPUT_CMD_SIZE); 
         DMA_Cmd(DMA1_Channel3, ENABLE); 
         DMA_ClearFlag(DMA1_FLAG_GL3);
      }
      USART_ClearITPendingBit(UART_, USART_IT_IDLE);
   } 
}

After the first "overflow" and DMA enabling comes "buffer size + 1" byte that was in rx register and later the number of received bytes is stable zero. What I'm doing wrong?

alexander

Here what happens if you trying to receive packet with size greater than S_M_INPUT_CMD_SIZE using your code:

  1. DMA complete reception of block S_M_INPUT_CMD_SIZE and disable (non-circular mode)
  2. USART1 receive one byte
  3. USART1 receive one more bytes from packet and drop them, because no one handle UART
  4. packet finished, you get IDLE interrupt and reinit DMA
  5. DMA read previously received byte
  6. No more packets - you get 0, 0, ... number of DMA received bytes

I have to say, this is really strange way to handle DMA transfers. DMA transfers usually must be handled in DMA interrupt handlers, not peripheral.

In order to handle long packets you have to implement DMA interrupt handler. So can reinit DMA reception earlier than IDLE interrupt. So DMA will be ready to receive more data from UART.

One more thing. In your code there is a race. between you read bytes_number and disable DMA one or more bytes could be transferred by DMA.

But more correct way to handle UART is to run DMA in circular mode and don't reinitialize it. Because every time you disable DMA you can miss some UART input.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

TOP Ranking

HotTag

Archive