Skip to main content
Visitor II
February 13, 2025
Solved

can't use HAL_UARTEx_ReceiveToIdle_DMA() with IDLE event

  • February 13, 2025
  • 3 replies
  • 2305 views

Hello,
I am trying to use the HAL_UARTEx_ReceiveToIdle_DMA function() but the IDLE function don't work.

I call the function here :

 

 

/* Extern variables */
extern UART_HandleTypeDef huart4;
extern osEventFlagsId_t comEventHandle;
extern osMessageQueueId_t sensorQueueHandle;
extern osEventFlagsId_t regEventHandle;
extern DMA_HandleTypeDef hdma_uart4_rx;

static void modbus_receive_DMA(void) {
 buf_rec = 0; // reset the counter of received bytes in the buffer

 /* Reset pin for receiving data */
 HAL_GPIO_WritePin(RS485_SIEMENS_RE_GPIO_Port, RS485_SIEMENS_RE_Pin, GPIO_PIN_RESET);

 if (HAL_UARTEx_ReceiveToIdle_DMA(&huart4, nmbs.msg.buf, sizeof(nmbs.msg.buf)) != HAL_OK) {
 log_debug("HAL_UARTEx_ReceiveToIdle_DMA error");
 }

}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
 if (huart == &huart4) {
 modbus_receive_DMA();
 }
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
 if (huart == &huart4) {
 switch (HAL_UARTEx_GetRxEventType(huart)) {
 case HAL_UART_RXEVENT_IDLE: // when Idle event occurred prior reception has
 // been completed (nb of received data is lower
 // than expected one).
 packet_sended = 0; // clear flag of transmit
 buf_rec = Size; // set size of received data

 nmbs_error res_poll = nmbs_server_poll(&nmbs);
 if (NMBS_ERROR_NONE != res_poll) {
 // This will probably never happen, since we don't return < 0 in our
 // platform funcs
 }

 // If there was no packet transmission, then we immediately switch to
 // receive mode. Otherwise, this function will trigger an interrupt at the
 // end of DMA packet transmission
 if (!packet_sended)
 modbus_receive_DMA();

 break;
 }
 }
}

 



simon_EQUIUM_0-1739461351484.pngsimon_EQUIUM_1-1739461381278.pngsimon_EQUIUM_2-1739461390277.png

simon_EQUIUM_3-1739461400991.png

 

I have tryed to replace sizeof(nmbs.msg.buf) by 1 or 2 or 3 and it works but not in IDLE mode. So the function HAL_UARTEx_RxEventCallback works but not in the right way. I have seen on the forum lot of topics with the same problem but I am not able to fix it with my micro..

Do you have any idea ?


    This topic has been closed for replies.
    Best answer by simon_12542

    Thank you Karl,
    The DMA doesn't work since the new STM32G473. I have tried with your example but it is not working with the G473 and the NULL byte. I have gave up, and change to normal UART IT. Thank you for your help.

    3 replies

    Super User
    February 13, 2025

    Probably you are not handling the half-complete interrupt.

    What is sizeof(nmbs.msg.buf)?

    How many bytes are you expecting at the IDLE event?

    How many bytes does it say are received?

    /**
     * @brief Provide Rx Event type that has lead to RxEvent callback execution.
     * @note When HAL_UARTEx_ReceiveToIdle_IT() or HAL_UARTEx_ReceiveToIdle_DMA() API are called, progress
     * of reception process is provided to application through calls of Rx Event callback (either default one
     * HAL_UARTEx_RxEventCallback() or user registered one). As several types of events could occur (IDLE event,
     * Half Transfer, or Transfer Complete), this function allows to retrieve the Rx Event type that has lead
     * to Rx Event callback execution.
     * @note This function is expected to be called within the user implementation of Rx Event Callback,
     * in order to provide the accurate value :
     * In Interrupt Mode :
     * - HAL_UART_RXEVENT_TC : when Reception has been completed (expected nb of data has been received)
     * - HAL_UART_RXEVENT_IDLE : when Idle event occurred prior reception has been completed (nb of
     * received data is lower than expected one)
     * In DMA Mode :
     * - HAL_UART_RXEVENT_TC : when Reception has been completed (expected nb of data has been received)
     * - HAL_UART_RXEVENT_HT : when half of expected nb of data has been received
     * - HAL_UART_RXEVENT_IDLE : when Idle event occurred prior reception has been completed (nb of
     * received data is lower than expected one).
     * In DMA mode, RxEvent callback could be called several times;
     * When DMA is configured in Normal Mode, HT event does not stop Reception process;
     * When DMA is configured in Circular Mode, HT, TC or IDLE events don't stop Reception process;
     * @PAram huart UART handle.
     * @retval Rx Event Type (return vale will be a value of @ref UART_RxEvent_Type_Values)
     */
    HAL_UART_RxEventTypeTypeDef HAL_UARTEx_GetRxEventType(const UART_HandleTypeDef *huart)
    Visitor II
    February 13, 2025

    Hello TDK,

    I have tried to disabled the IT at the half-complete :

     

     if (HAL_UARTEx_ReceiveToIdle_DMA(&huart4, nmbs.msg.buf, sizeof(nmbs.msg.buf)) != HAL_OK) {
     log_debug("HAL_UARTEx_ReceiveToIdle_DMA error");
     }
    __HAL_DMA_DISABLE_IT(&hdma_uart4_rx, DMA_IT_HT);

     

      but nothing changed
    the size of sizeof(nmbs.msg.buf) is 260. I just tested it now with a lenght of 20. Nothing changed.. :

     

    typedef struct nmbs_t {
     struct {
     uint8_t buf[260];
     uint16_t buf_idx;
    
     uint8_t unit_id;
     uint8_t fc;
     uint16_t transaction_id;
     bool broadcast;
     bool ignored;
     } msg;
    
     nmbs_callbacks callbacks;
    
     int32_t byte_timeout_ms;
     int32_t read_timeout_ms;
    
     nmbs_platform_conf platform;
    
     uint8_t address_rtu;
     uint8_t dest_address_rtu;
     uint16_t current_tid;
    } nmbs_t;

     

    I am expecting (for my current test) 8bytes.

    How many bytes does it say are received? I don't know how to check that.

     

    Graduate II
    February 13, 2025

    Size is not technically the amount of bytes received, but actually a pointer to where the DMA saved the last byte in the buffer. Size is not zero based, so it starts at 1 and goes up to <size of your buffer>

     

    See this project. This uses a pointer to keep track of the DMA data that is being received.

    https://github.com/karlyamashita/Nucleo-G071RB_UART_DMA_Idle_Circular/wiki

     

    Visitor II
    February 14, 2025

    Thanks @Karl Yamashita ,

    I have tried with 1, and I could go to the function but not in idle mode.
    I have tried with 8, same.. But with 16, it is not working.

    In the example you gave me, I don't see my mistake..

    I don't know if it is important but the interrupt of the function UART4_IRQHandler(void) works only ones. After one interrupt, I don't have any other interrupt.

    Super User
    February 14, 2025

    Does HAL_UARTEx_RxEventCallback get called ever? If so, what is the value of Size when it is called?

    If not, what flags are causing UART4_IRQHandler to be called? The UART4->SR register should show these immediately after the interrupt is called.

    Graduate II
    February 18, 2025

    I have tryed to replace sizeof(nmbs.msg.buf) by 1 or 2 or 3 and it works but not in IDLE mode.


    It may have something to do with the amount of bytes you are trying to receive versus the actual amount being received.

    Take a look at this project as it might help you set the amount of bytes you want the DMA ro receive in idle mode. https://github.com/karlyamashita/Nucleo-G431RB_Three_UART/wiki

     

    simon_12542AuthorAnswer
    Visitor II
    February 24, 2025

    Thank you Karl,
    The DMA doesn't work since the new STM32G473. I have tried with your example but it is not working with the G473 and the NULL byte. I have gave up, and change to normal UART IT. Thank you for your help.