cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to receive USART data using DMA normal mode in while loop more than one cycle

DevBee
Associate II

Hello,

Am using STM32F4 DISC board, with FreeRTOS with CMSIS v1, on CubeIDE with HAL generation.

To receive data from USART, below code has been used:

while(1)

{

.....

            ret = HAL_UART_Receive_IT(&huart6, rx_data, SIZE_RX_BYTES);

            if(ret != HAL_OK) {}

......

         ret = HAL_UART_Transmit_IT(&huart6, temp_data, SIZE_TX_BYTES);

         if(ret != HAL_OK) {}

......

}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

.......

 }

DMA is set to normal mode in CubeMxIDE, FIFO enabled, data width of both buses as byte, burst as single.

So, it is observed that unless USART global interrupt is enabled, DMA receive / tx doesn't behave cyclic, but happens only once.

What is the relation between USART global interrupt and DMA receive enable/interrupt? Will clearing TC flag in FCR register of DMA solve my problem?

17 REPLIES 17
Bob S
Principal

Your code doesn't use DMA. It uses interrupts (one interrupt per character). If you want to use DMA, the call HAL_UART_Receive_DMA() and HAL_UART_Transmit_DMA().

DevBee
Associate II

Am really sorry, that was a mistake, I used the DMA api itself, but mentioned USART api while framing the question.

The code is like this:

while(1)

{

.....

            ret = HAL_UART_Receive_DMA(&huart6, rx_data, SIZE_RX_BYTES);

            if(ret != HAL_OK) {}

......

         ret = HAL_UART_Transmit_DMA(&huart6, temp_data, SIZE_TX_BYTES);

         if(ret != HAL_OK) {}

......

}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

.......

 }

Bob S
Principal

When using DMA, the HAL library still uses the UART interrupt to determine when the transmit has actually completed. The flow goes something like this: DMA starts, then DMA Complete interrupt (all data written to UART FIFO) enables the UART "transmit complete" interrupt to know when the last byte has actually been sent. The UART interrupt is what ultimately calls HAL_UART_RxCpltCallback().

DevBee
Associate II

Does it mean I should keep USART global interrupt enabled, if I want to use USART with DMA in normal mode, to place DMA Receive in while loop?

Am I missing something here..?.

Bob S
Principal

If you are using the HAL layer, then yes, your code should never explicitly enable/disable the global UARTx interrupt. HAL_UART_MspInit() sets the interrupt priority and enables the global UARTx interrupt. The rest of the HAL UART functions expect the interrupt to always be enabled, as they only enable UART-specific interrupts (like "transmit complete" or the various error interrupts) in the UART control registers.

Be ware that the HAL DMA implementation will terminate DMA receive on any UART error (framing, parity, noise, etc.). There is a way you can override this in the CubeMX settings, but "terminate DMA on error" is enabled by default. At least with whatever old version of CubeMX I am using (looks like ver 4.24 - I only used it to start my projects a year or so ago). In the "Configuration" tab, clock on the UARTx then look for "DMA on RX Error" (which is REALLY "DMA terminate on RX error").

DevBee
Associate II

But the global UART enable in MspInit will happen only if I select/tick USART global interrupt in CubeMXIDE; Isn't it?

Or

Did you mean to say if I just enable DMA in CubeMX, then USART global interrupt will be enabled through code (even though on cubeMX it shows as not selected) in HAL generated code even if global USART interrupt is not selected in cubeMx?

Bob S
Principal

Probably, but I don't know for sure. The newer versions of CubeMX, including the version that is part of CubeMXIDE (which I have never used) may have changed this. All I know is that in my older version of CubeMX, by default, the USARTx global interrupt is enabled (in the configuration tab, click on UARTx, then "NVIC Settings"). Or maybe I explicitly enabled it long ago and just don't remember. I suggest enabling the global USART interrupt in CubeMX, then your code should leave it the heck alone and let the HAL code manipulate it as (or if) needed.

DevBee
Associate II

I have observed with selecting the USART global interrupt option and generating the code. Also generating the code without selectig the option.

Below lines make difference in generated code: (They are generated only if I select global interrupt in CubeMX)

   HAL_NVIC_SetPriority(USART6_IRQn, 5, 0);

   HAL_NVIC_EnableIRQ(USART6_IRQn);

DevBee
Associate II

I dont think it is so, I have seen code with same setup with respect to USART/DMA with one having global USART interrupt enabled and the other having global interrupt not enabled and the latter is working fine when DMA receive called in while loop ie (Normal, FIFO enabled, data width byte wide, single burst at both peripheral and memory side, pointer inc selected only for memory).

I compared file stm32f4xx_hal_msp.c too, but see no difference.

Even in any tutorial online/document it clearly shows DMA setup where global USART interrupt not enabled for USART with DMA. Eg: https://www.youtube.com/watch?v=urHGtvLYctk

I believe there is some missing piece of information here.