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.

1 ACCEPTED SOLUTION

Accepted Solutions
Guenael Cadier
ST Employee

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

View solution in original post

14 REPLIES 14
TDK
Guru

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".

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?

Guenael Cadier
ST Employee

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
Guru

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".

@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.

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

Thanks @Guenael Cadier​ , so after sniffing the uart line i recognice IDLE times that should be detected by the ST32WB's uart

 0693W00000HrfCbQAJ.png 

>>If IDLEIE interrupt is enabled,

Ill look into this

I only found this enables: (stm32wbxx_hal_dma.h)

/** @defgroup DMA_interrupt_enable_definitions DMA interrupt enable definitions
  * @{
  */
#define DMA_IT_TC                       LL_DMA_CCR_TCIE                 /*!< Transfer complete interrupt */
#define DMA_IT_HT                       LL_DMA_CCR_HTIE                 /*!< Half Transfer interrupt     */
#define DMA_IT_TE                       LL_DMA_CCR_TEIE                 /*!< Transfer error interrupt    */
/**
  * @}
  */

 Found it: (stm32wbxx_hal_uart,h)

/** @defgroup UART_Interrupt_definition   UART Interrupts Definition
  *        Elements values convention: 000ZZZZZ0XXYYYYYb
  *           - YYYYY  : Interrupt source position in the XX register (5bits)
  *           - XX  : Interrupt source register (2bits)
  *                 - 01: CR1 register
  *                 - 10: CR2 register
  *                 - 11: CR3 register
  *           - ZZZZZ  : Flag position in the ISR register(5bits)
  *        Elements values convention: 000000000XXYYYYYb
  *           - YYYYY  : Interrupt source position in the XX register (5bits)
  *           - XX  : Interrupt source register (2bits)
  *                 - 01: CR1 register
  *                 - 10: CR2 register
  *                 - 11: CR3 register
  *        Elements values convention: 0000ZZZZ00000000b
  *           - ZZZZ  : Flag position in the ISR register(4bits)
  * @{
  */
#define UART_IT_PE                          0x0028U              /*!< UART parity error interruption                 */
#define UART_IT_TXE                         0x0727U              /*!< UART transmit data register empty interruption */
#define UART_IT_TXFNF                       0x0727U              /*!< UART TX FIFO not full interruption             */
#define UART_IT_TC                          0x0626U              /*!< UART transmission complete interruption        */
#define UART_IT_RXNE                        0x0525U              /*!< UART read data register not empty interruption */
#define UART_IT_RXFNE                       0x0525U              /*!< UART RXFIFO not empty interruption             */
#define UART_IT_IDLE                        0x0424U              /*!< UART idle interruption <------------------------------------                        */
#define UART_IT_LBD                         0x0846U              /*!< UART LIN break detection interruption          */
#define UART_IT_CTS                         0x096AU              /*!< UART CTS interruption                          */
#define UART_IT_CM                          0x112EU              /*!< UART character match interruption              */
#define UART_IT_WUF                         0x1476U              /*!< UART wake-up from stop mode interruption       */
#define UART_IT_RXFF                        0x183FU              /*!< UART RXFIFO full interruption                  */
#define UART_IT_TXFE                        0x173EU              /*!< UART TXFIFO empty interruption                 */
#define UART_IT_RXFT                        0x1A7CU              /*!< UART RXFIFO threshold reached interruption     */
#define UART_IT_TXFT                        0x1B77U              /*!< UART TXFIFO threshold reached interruption     */
#define UART_IT_RTO                         0x0B3AU              /*!< UART receiver timeout interruption             */
 
#define UART_IT_ERR                         0x0060U              /*!< UART error interruption                        */
 
#define UART_IT_ORE                         0x0300U              /*!< UART overrun error interruption                */
#define UART_IT_NE                          0x0200U              /*!< UART noise error interruption                  */
#define UART_IT_FE                          0x0100U              /*!< UART frame error interruption                  */
/**
  * @}
  */

im trying out __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); but no luck either....

    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);
                __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
    	}
    	return;
    }

Guenael Cadier
ST Employee

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