cancel
Showing results for 
Search instead for 
Did you mean: 

CubeF3 UART DMA HAL_UART_RxCpltCallback(...) only called once

sebastian23
Associate II
Posted on June 19, 2015 at 20:40

Hi,

i'm currently playing arround with the ESP8266 serial wifi module. I'm exchanging data with this module using an UART interface. I'm using an STM32F3 Discovery board.

Generally it's working, the module answer to my requests. The communication with module is controlled by sending AT commands to the module.

When I send an simple ''AT'' to the module it responds with a fixed length answer. I got no problem receiving data from the module for which i know the length of the response.

But there are some responses to an AT command (for example AT+CWLAP ''Show all available APs'') which doesn't have a defined response length.

For receiving these responses i wanted to use a ''single byte receive strategy'' in a state machine.

The state machine is working in the following way:

1) Send AT command to the ESP8266 Module

2) Receive one byte from the response

3) Wait for HAL_UART_RxCpltCallback

4) HAL_UART_RxCpltCallback sets a variable which is used by the state machine to determine that receiving of the single byte is completed. And sets a counter variable to 0. And sets the state machine to ''read next byte'' state.

5) In state reading next byte, increase an counter variable when receiving ready flag is not set. Also the receiving data pointer is increased that next receive command doesn't overwrite before received byte.

6) When the counter variable exceeds a limit (currently 5000000) the state machine goes to the receiving complete state.

I'm reading one byte using:

HAL_UART_Receive_DMA(pESP8266->pUartHandle, m_rxBuffer, 1);

My problem is that HAL_UART_RxCpltCallback is only called once (after receiving the first byte), after sending the next HAL_UART_Receive_DMA command, its never called again.

When i set a breakpoint in the ''receiving complete'' state HAL_UART_GetState() gives back HAL_UART_STATE_BUSY_RX. When i call HAL_UART_GetState() later again, it returns never another state.

Am i missing something?

Has anybody found a way to receive sequences with unknown length using STM32 Cube library?

Any hint is appreciated.

CubeMX tells me i'm using the latest version of the cube library.

Kind regards,

Sebastian

#cubef3-uart-dma-callback
10 REPLIES 10
sebastian23
Associate II
Posted on June 23, 2015 at 22:38

I gave it up to get it like working this.

I extended my receiving buffer to maximum length of the response which can occur. And created a timeout in the ''waiting for complete'' state. When this timeout happens the state transists to ''receive complete'' state. In this state i'm checking the response, and stop and resume the DMA reading use HAL_UART_DMAStop() and starting it again with HAL_UART_DMAResume(..).

If anyone stumbles about this thread and got an idea how to get this working with an one byte buffer, please reply here.

Regards,

Sebastian

krzysztof2399
Associate II
Posted on June 23, 2015 at 23:24

Hi,

There is an error in ''stm32f3xx_hal_uart.c'' file.

In callback function ''UART_DMAReceiveCplt'' line 1822, condition for Circular mode.

Working function should look like:

/**

  * @brief DMA UART receive process complete callback

  * @param hdma: DMA handle

  * @retval None

  */

static void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)  

{

  UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;

  if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0)

  {

  huart->RxXferCount = 0;

 

  /* Disable the DMA transfer for the receiver request by setting the DMAR bit

     in the UART CR3 register */

  huart->Instance->CR3 &= (uint32_t)~((uint32_t)USART_CR3_DMAR);

 

  /* Check if a transmit Process is ongoing or not */

  if(huart->State == HAL_UART_STATE_BUSY_TX_RX)

  {

    huart->State = HAL_UART_STATE_BUSY_TX;

  }

  else

  {

    huart->State = HAL_UART_STATE_READY;

  }

 

}

  HAL_UART_RxCpltCallback(huart);

}

Offcourse you have to set DMA channel in Circular mode.

I hope it will help.

Posted on June 24, 2015 at 19:07

I'm hard pressed to see the point of 1 byte DMA, the management overhead seem significantly higher than just processing bytes as they arrive via interrupt.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
krzysztof2399
Associate II
Posted on June 25, 2015 at 00:41

I have no other idea how to manage UART framed communication with various frame sizes, without possibility for loosing some bytes . Especially using HAL libraries .

If you have better solution, 

I would appreciate to see it.

(sorry for my English 🙂 )

Posted on June 25, 2015 at 03:16

The HAL just adds a thick layer of issues, I'm not using it.

You might have to modify the HAL code to get it to do what you want, especially if it doesn't fit into ST's paradigm for handling things.

A 1-byte DMA changes the dynamics slightly, but you're still juggling the same problem, if you can't handle the inbound stream efficiently you're going to still lose data.

An interrupt based USART solution using the SPL should be able to handle several hundred Kbps. Depending on what else you're doing you might get to 1Mbps.

Does the Wifi chip have flow control?

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
krzysztof2399
Associate II
Posted on June 25, 2015 at 15:58

You are right, but question was about HAL libraries, so using DMA with single byte transfer is workaround for HAL ''issue''.

Using normal UART interrupts you also need to generate interrupt for receiving each byte, so difference is not so big.

In other hand using DMA for sending UART data (especially big frames) is very useful and allows to spare processor time for frame transferring  , so it is ''clear'' solution to use DMA for sending and receiving packages.

I understand that using Standard or HAL libraries is not very optimal and can cause lot of problems, but it is much faster than write own libraries for every single microcontroller family. Normally I'm also using own code but sometimes vendor libraries are very useful.  

hbarta2
Associate III
Posted on June 25, 2015 at 23:03

Back in the day we used to choose 16550 UARTs because they could buffer incoming (and maybe outgoing?) characters in case the processor could not service arriving data  fast enough.

I studied the data sheet for these parts for something similar and did not find anything. I did see a mention of a FIFO with DMA and there is a check mark for configuring that in MX. I don't know if it would provide the same benefit but it seems worth exploring. (I'm lazy and think it would be easier than writing your own driver. 😉 )

Lars Beiderbecke
Senior III
Posted on May 26, 2018 at 15:04

Thank god for this post.

I spent an entire week trying to communicate with an ESP8266, but no matter how I programmed this, only the reply of the first command was ever received.

The reason for that was first that I used HAL_DMA_Abort() instead of HAL_UART_DMAStop(), and second that I issued a new DMA request instead of using HAL_UART_DMAResume().

I know this article is very old, but my solution is to Receive_DMA 100 bytes, and then search the buffer for 'OK', until a timeout hits.

Posted on May 26, 2018 at 15:05

Oh wow, deities are offensive here.