cancel
Showing results for 
Search instead for 
Did you mean: 

can't use HAL_UARTEx_ReceiveToIdle_DMA() with IDLE event

simon_EQUIUM
Associate III

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 ?


1 ACCEPTED SOLUTION

Accepted Solutions

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.

View solution in original post

18 REPLIES 18
TDK
Guru

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)
If you feel a post has answered your question, please click "Accept as Solution".

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.

 

Karl Yamashita
Principal

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

 

Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

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.

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.

If you feel a post has answered your question, please click "Accept as Solution".

Dear @TDK ,

The HAL_UARTEx_RxEventCallback is never called.
But I have something news !!
If I use the register number "3" for the modbus, the function HAL_UARTEx_RxEventCallback  is called. If I try with "4", it doesn't work.

I think the DMA is not working with my application.

simon_EQUIUM_1-1739546518245.png

 

 

I think the DMA is not working with my application.

This means the application isn't working as expected. Nothing wrong with the DMA at this point.

Unlike a CAN controller that can filter on specific ID's, the UART/DMA just receives bytes as is.

Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

Yes @Karl Yamashita , Totally agree with you. But I can't explain the reason why the register has an impact on the callback :(

@Karl Yamashita  If I have a problem with in the trame, does the function is called ? For example, the CRC is not complet.