cancel
Showing results for 
Search instead for 
Did you mean: 

USART TX problem in blocking and non-blocking mode in one main program

Katarzyna Bartnik
Associate II
Posted on February 28, 2017 at 22:28

Hello! I have a problem with using usart transmit function twice in main program on STM32F4/

STM32

F0. First transmition should be with DMA and after it data should be send in blocking mode without using DMA. Problem is that I have to use the same usart module for each of transmitions and there is a conflict because using DMA requires USART global interrupts to be enabled and transmition in blocking mode doesn't work properly when the interrupts are enabled. I would be very grateful if you coud give me some information or any suggestions what I couls do to resolve my problem.

#stm32f4-usart #stm32f4-discovery #stm32f4 #stm32f0-discovery #stm32f4-dma-usart #stm32f0-usart
11 REPLIES 11
Posted on March 01, 2017 at 23:47

I don't quite understand your description. Please try to restate it.

Why do you think DMA requires USART interrupts to be enabled?

JW

kardwor1
Associate II
Posted on March 02, 2017 at 00:20

Can you post your USART configuration?

Do you use circular buffer in DMA configuration?

Posted on March 02, 2017 at 09:26

The problem is that when I don't enable usart global interrupts, the transmit  DMA function doesn't work, I mean there is no transmited data.

Only if I enable it, I can transmit data to my PC. Another problem is that if I enable the interrupts  

HAL_UART_Transmit function leaves out some of data to send which it has already received, beacause the performing time is much longer (about 1ms).

I would like to make such a program:

HAL_UART_Receive(&huart1,UART1TX_Buffer,16,10);

HAL_UART_Transmit_DMA(&huart3,UART3TX_Buffer,16);

.

.

.

HAL_UART_Transmit(&huart3,UART3TX_Buffer,16,10);

 In this configuration the performing time seems to be much longer then 1ms (I can see it on a scope in MATLAB. 

I don't have any idea why it happens like that.

Posted on March 02, 2017 at 09:30

For 

HAL_UART_Transmit_DMA I use normal DMA mode.

My USART configuration:

static void MX_USART1_UART_Init(void)

{

huart1.Instance = USART1;

huart1.Init.BaudRate = 512000;

huart1.Init.WordLength = UART_WORDLENGTH_8B;

huart1.Init.StopBits = UART_STOPBITS_1;

huart1.Init.Parity = UART_PARITY_NONE;

huart1.Init.Mode = UART_MODE_TX_RX;

huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

huart1.Init.OverSampling = UART_OVERSAMPLING_16;

huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;

huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT;

huart1.AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE;

if (HAL_UART_Init(&huart1) != HAL_OK)

{

Error_Handler();

}

}

and DMA for USART TX configuration:

hdma_usart1_tx.Instance = DMA1_Channel2;

hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;

hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;

hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;

hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

hdma_usart1_tx.Init.Mode = DMA_NORMAL;

hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;

if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)

{

Error_Handler();

}

__HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);

Guenael Cadier
ST Employee
Posted on March 03, 2017 at 18:40

Hi all,

I could try to explain requirement for having USARTx interrupt to be enabled at NVIC level in case of TX DMA (normal mode), (for example by calling : HAL_NVIC_EnableIRQ(USARTx_IRQn); )

From DMA point of view, a transmit DMA sequence is considered as completed once last data is pushed in TDR. Then, DMA notifies USART of this transfer completion. Prior calling user DMA transfer complete callback (HAL_UART_TxCpltCallback), HAL usart code needs to ensure that in addition to have been loaded into TDR, data has also been transmitted. TC interrupt is used for that, instead of having a blocking wait on TC flag to be set.

This does not mean that user code has to enable some interrupts in USART registers to be able to use HAL DMA Transmit services, it is all handled within HAL code.

Now, regarding your use case, nothing prevents in my opinion, to perform USART transmit in blocking mode, after having used the DMA. it should be able to work. Just need to ensure that DMA transmit is complete (HAL_UART_TxCpltCallback has been called), prior calling HAL_UART_Transmit(&huart3,UART3TX_Buffer,16,10);

It is sure that use of HAL_UART_Transmit() might require more time than using HAL_UART_Transmit_DMA(), but there should be no problem of loss data or similar issues.

Hope this helps.

Regards

Guenael

Posted on March 06, 2017 at 12:46

Thank you for your answer but what if when I don't enable usart interrupts and it is the only one modification and DMA transmition doesn't work?

Moreover if I wait for TC flag in DMA ISR register it takes much more time to send data in DMA mode because it wait long time for this flag.

Have you any ideas why it happens?

Posted on March 06, 2017 at 12:58

Writing that DMA mode doesn't work, I mean that if I make suche a program, for example:

uint8_t tx_buff[]={0,1,2,3,4,5,6,7,8,9};

uint8_t rx_buff[10];

while(1){

   HAL_UART_Receive_DMA(&huart1,rx_buff,10);

   HAL_UART_Transmit_DMA(&huart1,tx_buff,10);

}

and don't enable global usart interrupts it sends me only one frame and nothing else.

Posted on March 06, 2017 at 13:54

Hi

Bartnik.Katarzyna

‌,

This is corresponding to what I tried to explain in my previous posts : Transmission in DMA mode on USARTx, requires USARTx IRQ to be enabled. Tranmission process will enable TC interrupt when last data has been loaded in TDR by DMA, and then, on TC interrupt, transmission will be considered as complete.

If USART IRQ is not enabled, no interrupt will occur, and the, DMA process will remain in Busy state, i.e. not able to start a new process.

HAL_UART_Transmit_DMA (and HAL_UART_Receive_DMA) proces are not blocking : this means that when function code is executed (when you exit function code), transfer is programmed, maybe started, but not executed yet.

In above code section you wrote, if USARTx IRQ is not enabled :

  • 2nd and subsequent calls to HAL_UART_Transmit_DMA() will not return HAL_OK, as transmission process is still waiting for completion (waiting for TC interrupt).
  • all this is implemented in HAL service, so you don't need to wait for TC flag in your own code, when using DMA UART Tx service.

What you need is :

  • enable USARTx IRQ
  • wait for Tx complete callback (HAL_UART_TxCpltCallback) to be called). USART Tx state is then back to READY, meaning that USART is able to handle another transmit. HAL_UART_TxCpltCallback() is a weak function defined in HAL, you could define your own. Prior this moment, USART is busy and could not handle other transmit requests.

For more details, you could have a look to code examples provided in STM32Cube firmware packages. (for example, for F0 serie, please look into Firmware\Projects\STM32F072B-Discovery\Examples\UART\UART_TwoBoards_ComDMA projects, for having an example of code using USART/UART DMA services). Example highlights the fact that DMA transmit process is conly considered as completed in main(), when a global variable is set. setting of this variable is done in HAL_UART_TxCpltCallback() Tx complete callback.

This example should be available for other targets/series.

Hope this helps.

Regards

Guenael

Posted on March 07, 2017 at 10:09

Hi,

Sorry I didn't understand at the first time. I tried to use callback but it turned out that that 

HAL_UART_TxCpltCallback() is not called in dma normal mode. There is only USART_DMATransmitCplt() called and there is cleared this bit:

CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);

So in this case I tried to use such a loop after dma transmit function:

while ((huart1.Instance->CR3 & USART_CR3_DMAT)!=0);

Now, my program looks like that (in TIM_IRQhandler):

/sin wave calculating/

/some memcpy functions/

HAL_UART_Transmit_DMA(&huart1,UART1TX_Buffer,16);

while ((huart1.Instance->CR3 & USART_CR3_DMAT)!=0);

UART2Rx_Receive(UART3_RX_temp_buffer, 8);

/some memcpy functions/

HAL_UART_Transmit_DMA(&huart1,UART1TX_Buffer,16);

while ((huart1.Instance->CR3 & USART_CR3_DMAT)!=0);

As a result, I get such figures in MATLAB host:

0690X00000606SHQAY.png

These are sin waves get from another stm. Something like that happens only if I use blocking mode with usart global interrupts (which are not necessary for blocking mode but I need them for DMA and if I have each of modes used in one main program I have to enable the interrupts) or if I wait for clearing one of flags behind the information about transmit complete.