cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UARTEx_ReceiveToIdle_DMA().............. IDLE event?? what is that, whatever it is is not working for me.

Javier1
Principal

Hi everyone, im using an STM32WB and i just managed to get my own BLE<->UART bridge to "half work".

But my problem is about UART managing.

If i receive data with length of less than 247bytes(set by me) just stays in the rx bufer and no DMA transfer complete happens.

I set up the DMA to listen for the next incoming 247 bytes

HAL_UARTEx_ReceiveToIdle_DMA(&huart1, NotifyCharData, RxBuf_SIZE);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);//we dont want the half done transaction interrupt

Whenever the data arrives(stream of data uartRx) ,it gets written into a BLE characteristic, everything works like a charm, but if the last uart received message is less than 247length DMA rx doesnt trigger after an idle time.

No IDLE event occurs.

/**
  * @brief Receive an amount of data in DMA mode till either the expected number of data is received or an IDLE event occurs.
  * @note   Reception is initiated by this function call. Further progress of reception is achieved thanks
  *         to DMA services, transferring automatically received data elements in user reception buffer and
  *         calling registered callbacks at half/end of reception. UART IDLE events are also used to consider
  *         reception phase as ended. In all cases, callback execution will indicate number of received data elements.
  * @note   When the UART parity is enabled (PCE = 1), the received data contain
  *         the parity bit (MSB position).
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         the received data is handled as a set of uint16_t. In this case, Size must indicate the number
  *         of uint16_t available through pData.
  * @note   Dual core specific: there is no support for unaligned accesses on the Cortex-M0+ processor.
  *         When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         address of user data buffer for storing data to be received, should be aligned on a half word frontier (16 bits)
  *         (as received data will be handled by DMA from halfword frontier). Depending on compilation chain,
  *         use of specific alignment compilation directives or pragmas might be required to ensure proper alignment for pData.
  * @param huart UART handle.
  * @param pData Pointer to data buffer (uint8_t or uint16_t data elements).
  * @param Size  Amount of data elements (uint8_t or uint16_t) to be received.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

I dont even know what does an "IDLE event" mean, i tought DMA triggered after a short time of bus inactivity (as seen in this video ) but no.

we dont need to firmware by ourselves, lets talk
14 REPLIES 14

ding ding ding,

i was not using the uart in IT mode so i didint enabled the uart1 global interrupt at all.

Now it detects the IDLE state!

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
 
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
if(huart1.gState==1<<7){
//IDLE STATE
}
  /* USER CODE END USART1_IRQn 1 */
}

we dont need to firmware by ourselves, lets talk

I am trying to understand the example below.  Since HAL_UARTEx_RxEventCallback is called also on full complete, is it possible that Size < old_pos?  That is, is it possible that a single call to HAL_UARTEx_RxEventCallback will cover a buffer wrap around?

https://github.com/STMicroelectronics/STM32CubeWB/blob/11042898d71249ed9c698355fd7b7812b741a161/Proj... 

 

Edit: Anything wrong with this event handler?  We are using DMA to IDLE, circular rx buffer, and DMA is set to one byte at a time.

 

void Serial::uart_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
  // Map the HAL's hurart to our Serial wrapper class.
  Serial *serial = serial::get_serial_by_huart(huart);

  const uint16_t new_pos = Size;
  constexpr size_t kBufferSize = sizeof(serial->_rx_dma_buffer);

  // Assertion: Wrap around cannot happen within one invocation
  // since the handler is invoked also on full complete.
  if (new_pos < serial->_rx_last_pos) {
    Error_Handler();
  }

  // Assertion: New pos can be equal to the buffer size, e.g.
  // on a full complete event, but not above it.
  if (new_pos > kBufferSize) {
    Error_Handler();
  }

  // Copy the new bytes.
  BaseType_t task_woken = pdFALSE;
  const uint32_t len = new_pos - serial->_rx_last_pos;
  serial->rx_data_arrived_isr(&serial->_rx_dma_buffer[serial->_rx_last_pos], len,
                              &task_woken);

// Remember the new position, adjusting to for wrap around.
  serial->_rx_last_pos =
      new_pos >= kBufferSize ? (new_pos - kBufferSize) : new_pos;

  portYIELD_FROM_ISR(task_woken)
}

Hi
The IDLE interrupt is calling a standard callback

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
}


@Javier1 wrote:

Hi @TDK​ , yes, it is implemented

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
 //restarts the DMA listening of the UART rx (next 247 bytes)
	if(huart->Instance ==USART1){
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, NotifyCharData, RxBuf_SIZE);
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
	}
	return;
}

>>The TC IRQ won't fire unless you receive all characters.

What about that "idle event".

Isnt there a programmable timeout i can use for the TC interruption to trigger even if the buffer is not full?


 

If interrupts no longer work, then HAL_UARTEx_ReceiveToIdle_DMA returned HAL_BUSY. You don't check the HAL status. Rewrite you code to set an error flag that you can check in main loop.

 

 

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
 //restarts the DMA listening of the UART rx (next 247 bytes)
	if(huart->Instance ==USART1){
		if(HAL_UARTEx_ReceiveToIdle_DMA(&huart1, NotifyCharData, RxBuf_SIZE) != HAL_OK)
		{
			// set an error flag, poll for flag in main loop, and call HAL_UARTEx_ReceiveToIdle_DMA again.
			return;
		}
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
	}
	return;
}

 

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

So, one year later, i had a similar problem.
Imagine how happy i was to google about it and this thread pops up first.

Anyway, i am implementing HAL_UARTEx_ReceiveToIdle_DMA() again in a stm32g4.

The reason why this was not working for me this time is:
As i am using 

 

HAL_UARTEx_ReceiveToIdle_DMA()

 

to setup the Rx stream.

I was getting worried why my callback was never reached...


The reason being was using (incorrectly)

 

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

 

instead of (correct)

 

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

 

we dont need to firmware by ourselves, lets talk