cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UART_DMA_Receive problem

Arman Ilmak
Senior

Hi guys.

I have a problem with this hal function.The problem is that every time I use this function the first byte received is not what I transfer to it.For example when I send AT (ESP8266 AT command) to the module it must return AT OK,but every time(except the first time)the first byte is not A!

https://imghostr.com/KHNQXNw1P

10 REPLIES 10
Arman Ilmak
Senior
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
  
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
 
  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
	ESP_Enable;
	ESP_Set;
	delay_ms(5000);
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_TC);
	
 
 
	
 	
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	sprintf(data_tx,"AT\r\n");
	HAL_UART_Receive_DMA(&huart1,data_rx,10);
	HAL_UART_Transmit_DMA(&huart1,data_tx,4);
	delay_ms(5000);
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Bob S
Principal

Why are you explicitly enabling UART_IT_RXNE and UART_IT_TC? If you are using HAL_UART_***_DMA() calls, they will handle enabling and disabling whatever interrupts they need. Since you are enabling interrupts, have you added code to the interrupt handlers? Do you have any code in the UART transmit complete and receive complete callback functions? What exactly are you seeing in the "data_rx" buffer? And finally, how do you get 10 characters from "AT OK"? Its been a loooooong time since I've done modem work, but even it that is really "AT\r\nOK\r\n", that is only 8 bytes.

One is normally expected to parse/synchronize the stream, you can't just request "10" characters and hope. Good chance you won't be getting exactly 10 characters in response to any given request, nor that the first byte will be what you want.

You might want to get the mechanics down using interrupts, collecting and processing one byte at a time.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Arman Ilmak
Senior

"Why are you explicitly enabling UART_IT_RXNE and UART_IT_TC? "

I removed this.

After ESP_Set when i use uart_receive dma the uart receive 'r',the esp sends it.I checked and the other devices dont send this and everything is ok.I think its a bug in my esp module.

Arman Ilmak
Senior

Whats the problem?After each time I call uart receive dma an extra byte is received from the ESP8266!!!

Bob S
Principal

Don't be so quick to presume a bug in a mass-produced device to which your untested software is trying to communicate.

I suspect this problem goes back to my original post and @Community member​ 's post. The code you posted originally will NEVER work unless the device you are talking to always responds with exactly 10 bytes whenever you send "AT\r\n". And even if you know for sure the number of bytes the device was SUPPOSED to reply with, relying on a fixed size response is asking for trouble if there is every an error on the serial lines. For example, if the HAL code detects a framing error, noise error, etc. on the receiver, it will abort the DMA receive (well, this is an option in CobeMX to have it so this, and I don't recall if that is the default behavior). And any noise glitch of unexpected/extra character will throw off your synchronization.

In your code as posted, I suspect this is what is happening:

  • First time through the loop you probably see "AT OK\r\n" or whatever the response is, but HAL_UART_Receive_DMA() is still active because it hasn't received 10 characters yet
  • Second time through the loop, your call to HAL_UART_Receive_DMA() will fail and return HAL_BUSY (which you don't check for) because is it still waiting for the rest of the 10 characters from the first call.
  • ALso on the second time through the loop, HAL_UART_Transmit_DMA() will send the AT command again, causing the receive (from the 1st time through the loop) to receive some number of bytes (appended to the original "AT OK\r\n" from the first time) then terminate because it has now received 10 characters.
  • 3rd time through the loop, HAL_UART_Receive_DMA() probably succeeds in starting to receive. They may likely be one char still in the UART RX buffer from the previous data. Then you will see the response from the 3rd "AT" command
  • etc.

As quick bandaid patch to your current code, check the return values from HAL_UART_Receive_DMA() and HAL_UART_Transmit_DMA(). And make the size of your receive the EXACT number of bytes that the device responds with.

But this is only a kludge . The real answer is to stop trying to do fixed-count receive. Either use circular DMA mode with a larger buffer, or interrupt mode (NOT!!! the HAL_UART_Receive_IT, but your own interrupt code) to process bytes as they are received so you can re-synchronize to the incoming data as needed. Personally I prefer the circular DMA. Using HAL_UART_Receive_DMA() works for getting this running, but you need your own "read from the buffer" pointer and figure out how many bytes are available in the DMA buffer. This has been discussed several times in this forum. A search for UART DMA hopefully should find it (I have mixed luck with this forum's search function).

I checked the response size of each command and there was no problem with that.Each time the uart receive dma is called the buffer will completely get full.

Watch the code below:

In this code after cube initialization I enabled the esp and after 5 seconds(to make sure that nothing remained,because esp sends data after a hardware reset) I just put a receive function and did nothing else in the program.But there is a 'r' received!

This 'r' is the first character each time the hardware reset is done. When I put the ESP enable before MX_USART1_UART_Init(); this extra character wont be received.

int main(void)
{
 
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  MX_NVIC_Init();
	ESP_Set;
	ESP_Enable;
	delay_ms(5000);
	HAL_UART_Receive_DMA(&huart1,data_rx,9);
  while (1)
  {
 
  }
}

Arman Ilmak
Senior

https://imghostr.com/tGHM6F4NZ

This is what is received.

S.Ma
Principal

There are many AT command examples out there, including cellular modems which are also "AT command" such as X-CUBE-CELLULAR.

Missing the first byte smells like activation sequence (including initial GPIO state and level) is wrong. Fully agree with Clive, when data goes through wire(s) rugged SW will tacle it.