cancel
Showing results for 
Search instead for 
Did you mean: 

DMA reads data from DR register even with RXNE cleared. Why?

tecnico23
Associate II
Posted on November 20, 2012 at 17:15

Hi,

I have the following Usart interrupt request handler: (simplified version, but has all the necessary information)

void USART1_IRQHandler(void)

{

  if(USART_GetITStatus(COM1_PC, USART_IT_RXNE) != RESET)

  {

    data = (USART_ReceiveData(COM1_PC) & 0xfF);

    if (data == DATA_READ)

    {

    

       //Disable the Usart interrupt request because from this point,

       //I want to use the DMA to store the incoming data at a specified address!

       USART_ITConfig(COM1_PC, USART_IT_RXNE, DISABLE);

      

       //make sure that the DMA is not transferring any data before configuring it with new parameters

       while (DMA_GetCmdStatus(RS232_DMA_RX_STREAM) != DISABLE)

       {

       }

       //Configure the DMA to store usNumOfBytes bytes to memory, starting at address pStartAddress

       RS232_DMA_RX_STREAM->NDTR = usNumOfbytes;

       RS232_DMA_RX_STREAM->M0AR = (uint32_t)pStartAddress;

       //Clear some flags before enable the DMA

       DMA_ClearFlag(RS232_DMA_RX_STREAM, RS232_RX_DMA_FLAG_HTIF | RS232_RX_DMA_FLAG_TCIF);

       /* Enable DMA Stream Transfer Complete interrupt */

       DMA_ITConfig(RS232_DMA_RX_STREAM, DMA_IT_TC, ENABLE);

      //Only for debugging to make sure that it no data has been stored until now!

      RXcounter=DMA_GetCurrDataCounter(RS232_DMA_RX_STREAM);

      

      //make sure that the RXNE bit is cleared before activating the DMA

      while(USART_GetITStatus(COM1_PC, USART_IT_RXNE) != RESET);

      //Activate the DMA

      DMA_Cmd(RS232_DMA_RX_STREAM, ENABLE);

     //only for debugging, but at this point the DMA, has read the old data stored in the DR register, and RXcounter is equal to usNumOfbytes - 1!

     RXcounter=DMA_GetCurrDataCounter(RS232_DMA_RX_STREAM);

   }

  }

}

With this interrupt handler I want to implement the following:

Whenever it receives a DATA_READ command, it should:

-Disable the USART RX interrupt request;

-Configure the DMA to read data coming from a host PC via RS232 and store it at the specified address.

-Enable the DMA for that propose.

Surprisingly (for me), the DMA stores the old received data at the specified address, as soon as, it is enabled. Even with the RXNE bit cleared.

But, on page 786 of the reference manual RM0008 (Doc ID 13902 Rev 14), subtitle ''Reception using DMA'', it states that ''The data will be loaded from USART_DR to this memory area after each

RXNE event.''

So, I would like to know, what really forces the DMA to read data from the DR register to the specified memory!

It doesn't seems that it is the RXNE event, because this bit is cleared by reading data from the DR register, and I have forced to make sure that this bit was cleared before enabling the DMA.

Thank you all for any help,

Best regards,

A. Paiva

#usart #dma #rxne
12 REPLIES 12
tecnico23
Associate II
Posted on November 21, 2012 at 16:10

Thanks for your post.

As soon as, I enable the DMA, this occurs! Inspite of the last received data from the UART has already been read by the processor, it reads it again, and then wait for the new incoming data.

Best regards,

A.Paiva

tecnico23
Associate II
Posted on November 21, 2012 at 17:56

Ok,

It's working, but I really don't like my solution. I would like to find the source of the fault, instead of shut up the DMA!

I force the DMA to read the unwanted byte to a dummy address, and then I prepare the DMA to receive new data.

void USART1_IRQHandler(void)

{

  if(USART_GetITStatus(COM1_PC, USART_IT_RXNE) != RESET)

  {

    data = (USART_ReceiveData(COM1_PC) & 0xfF);

    if (data == DATA_READ)

    {

    

       //Disable the Usart interrupt request because from this point,

       //I want to use the DMA to store the incoming data at a specified address!

       USART_ITConfig(COM1_PC, USART_IT_RXNE, DISABLE);

      

       //make sure that the DMA is not transferring any data before configuring it with new parameters

       while (DMA_GetCmdStatus(RS232_DMA_RX_STREAM) != DISABLE)

       {

       }

/************************* NEW CODE START's HERE ************************************/

    //Force the DMA to read unwanted byte to a dummy address!

    RS232_DMA_RX_STREAM->NDTR = 1;

        RS232_DMA_RX_STREAM->M0AR = (uint32_t)dummyAddress;

        DMA_Cmd(RS232_DMA_RX_STREAM, ENABLE);

        DMA_ClearITPendingBit(RS232_DMA_RX_STREAM, RS232_DMA_RX_IT_TCIF);

/************************* NEW CODE STOP's HERE ************************************/

       //Configure the DMA to store usNumOfBytes bytes to memory, starting at address pStartAddress

       RS232_DMA_RX_STREAM->NDTR = usNumOfbytes;

       RS232_DMA_RX_STREAM->M0AR = (uint32_t)pStartAddress;

       //Clear some flags before enable the DMA

       DMA_ClearFlag(RS232_DMA_RX_STREAM, RS232_RX_DMA_FLAG_HTIF | RS232_RX_DMA_FLAG_TCIF);

       /* Enable DMA Stream Transfer Complete interrupt */

       DMA_ITConfig(RS232_DMA_RX_STREAM, DMA_IT_TC, ENABLE);

      //Only for debugging to make sure that it no data has been stored until now!

      RXcounter=DMA_GetCurrDataCounter(RS232_DMA_RX_STREAM);

      

      //make sure that the RXNE bit is cleared before activating the DMA

      while(USART_GetITStatus(COM1_PC, USART_IT_RXNE) != RESET);

      //Activate the DMA

      DMA_Cmd(RS232_DMA_RX_STREAM, ENABLE);

     //only for debugging, but at this point the DMA, has read the old data stored in the DR register, and RXcounter is equal to usNumOfbytes - 1!

     RXcounter=DMA_GetCurrDataCounter(RS232_DMA_RX_STREAM);

   }

  }

}

Even so, I would be grateful if someone could explain what forces the DMA read with the RXNE cleared.

Thanks,

Regards,

A. Paiva

Posted on November 21, 2012 at 19:36

> As soon as, I enable the DMA, this occurs!

Yes, but that does not answer my question.

I meant, does this happen when the DMA is enabled for the very first time after reset (i.e. the first time the interrupt routine is entered)?

JW

tecnico23
Associate II
Posted on November 21, 2012 at 22:34

Hi Jan,

I have not tested. As I had mencioned before, this is a simplified code of my interrupt routine.

Actualy, I don't receive only a byte, before configuring the DMA to receive data.

Tomorrow, I will try and post here if it also appears the first time the interrupt routine is called.

Regards,

A.Paiva

tecnico23
Associate II
Posted on November 22, 2012 at 09:40

Hi,

It occurs at the first time the interrupt routine is called too.

Best regards,

A.Paiva

Posted on November 22, 2012 at 12:07

Thanks.

Hummmm....

JW
Nickname12657_O
Associate III
Posted on November 26, 2012 at 17:35

Hi,

''... Inspite of the last received data from the UART has already been read by the processor, it reads it again, and then wait for the new incoming data.''

It seems this is due to the fact that sizeof(USART_DR) = 1 byte

Cheers,

STOne-32
Posted on November 26, 2012 at 17:53

How do you mean that?

In stm32f4xx.h,

typedef struct

{

  __IO uint16_t SR;         /*!< USART Status register,                   Address offset: 0x00 */

  uint16_t      RESERVED0;  /*!< Reserved, 0x02                                                */

  __IO uint16_t DR;         /*!< USART Data register,                     Address offset: 0x04 */

  uint16_t      RESERVED1;  /*!< Reserved, 0x06                                                */

  __IO uint16_t BRR;        /*!< USART Baud rate register,                Address offset: 0x08 */

  uint16_t      RESERVED2;  /*!< Reserved, 0x0A                                                */

  __IO uint16_t CR1;        /*!< USART Control register 1,                Address offset: 0x0C */

  uint16_t      RESERVED3;  /*!< Reserved, 0x0E                                                */

  __IO uint16_t CR2;        /*!< USART Control register 2,                Address offset: 0x10 */

  uint16_t      RESERVED4;  /*!< Reserved, 0x12                                                */

  __IO uint16_t CR3;        /*!< USART Control register 3,                Address offset: 0x14 */

  uint16_t      RESERVED5;  /*!< Reserved, 0x16                                                */

  __IO uint16_t GTPR;       /*!< USART Guard time and prescaler register, Address offset: 0x18 */

  uint16_t      RESERVED6;  /*!< Reserved, 0x1A                                                */

} USART_TypeDef;

For me it looks that DR is declared as 16-bit, ie. sizeof(DR) is 2. I of course don't see what did compiler A.Paiva used make out of it, but I somehow doubt it is anything else than a halfword access.

Could you please be more specific with your comment?

Thanks,

JW