Skip to main content
Javier1
Principal
January 13, 2022
Solved

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

  • January 13, 2022
  • 4 replies
  • 29780 views

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.

Best answer by Guenael Cadier

The code of HAL_UARTEx_ReceiveToIdle_DMA() will enable the IDLEIE bit, so enable the IDLE interrupt source inside the UART instance. Now in order to be genrated and processed the UART IRQ at NVIC side should also be enabled.

If you generate your code using STM32CubeMx tool, please make sure you do it in your UART configuration panel. (See below pic).

0693W00000HrgGPQAZ.jpgIf not, IRQ could be enabled in MSP_Init functions (as HAL_UART_MspInit) by below code :

 /* USART1 interrupt Init */
 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(USART1_IRQn);

Guenael

4 replies

TDK
Super User
January 13, 2022

Do you have HAL_UARTEx_RxEventCallback implemented?

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

"If you feel a post has answered your question, please click ""Accept as Solution""."
Javier1
Javier1Author
Principal
January 13, 2022

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?

hit me up in https://www.linkedin.com/in/javiermuñoz/
Karl Yamashita
Principal
October 16, 2023

@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 toolCANableV3 Open Source
Guenael Cadier
ST Employee
January 13, 2022

Hi @Javier Muñoz​ 

DMA Transfer complete is a DMA interrupt, whilst IDLE Line event will be indicated through the USART interrupt. Please make sure USART interrupt, is enabled and handled using HAL IRQ handler.

Regards

TDK
Super User
January 13, 2022

The HAL_UARTEx_RxEventCallback function gets called at every HT, TC, or IDLE event. You should do your character reception within there. Probably better to use the buffer in circular mode rather than restarting as the reception may still be going when that function is called.

See one possible implementation of HAL_UARTEx_RxEventCallback here:

https://github.com/STMicroelectronics/STM32CubeWB/blob/11042898d71249ed9c698355fd7b7812b741a161/Projects/P-NUCLEO-WB55.Nucleo/Examples/UART/UART_ReceptionToIdle_CircularDMA/Src/main.c#L389

Some explanation of how it all works is here:

https://github.com/STMicroelectronics/STM32CubeWB/blob/11042898d71249ed9c698355fd7b7812b741a161/Projects/P-NUCLEO-WB55.Nucleo/Examples/UART/UART_ReceptionToIdle_CircularDMA/readme.txt#L64

"If you feel a post has answered your question, please click ""Accept as Solution""."
Javier1
Javier1Author
Principal
January 14, 2022

@TDK​ 

Im working on implementing that circular buffer you suggested, ill post the result of that.

I still dont know what IDLE event is, (from the readme.txt you sent me)

- Idle Event on Rx line : Triggered when RX line has been in idle state (normally high state)
 for 1 frame time, after last received byte.

I dont think the STLINK's uart does that IDLE line thing when no activity happened.

hit me up in https://www.linkedin.com/in/javiermuñoz/
Guenael Cadier
ST Employee
January 14, 2022

HI @Javier Muñoz​ 

An Idle character is considered to be an entire frame of “1�?s (the number of “1�?s includes the number of stop bits). See below picture to be more clear.

After some activity on RX line, when an inactivity period lasting at least one character is detected (Idle state), the IDLE event is considered as occurring. If IDLEIE interrupt is enabled, then an interrupt is raised. This interrupt is used to inform application, in case HAL_UARTEx_ReceiveToIdle_DMA() has been called.

It corresponds to an inactivity period occuring after some reception.

Hope this helps.

Guenael

0693W00000Hrf2vQAB.jpg

Guenael Cadier
Guenael CadierBest answer
ST Employee
January 14, 2022

The code of HAL_UARTEx_ReceiveToIdle_DMA() will enable the IDLEIE bit, so enable the IDLE interrupt source inside the UART instance. Now in order to be genrated and processed the UART IRQ at NVIC side should also be enabled.

If you generate your code using STM32CubeMx tool, please make sure you do it in your UART configuration panel. (See below pic).

0693W00000HrgGPQAZ.jpgIf not, IRQ could be enabled in MSP_Init functions (as HAL_UART_MspInit) by below code :

 /* USART1 interrupt Init */
 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(USART1_IRQn);

Guenael

Javier1
Javier1Author
Principal
January 14, 2022

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ñoz/