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.

hit me up in https://www.linkedin.com/in/javiermu%C3%B1oz/
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 */
}

hit me up in https://www.linkedin.com/in/javiermu%C3%B1oz/

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;
}

 

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.
CAN Jammer an open source CAN bus hacking tool

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)

 

hit me up in https://www.linkedin.com/in/javiermu%C3%B1oz/