cancel
Showing results for 
Search instead for 
Did you mean: 

can't use HAL_UARTEx_ReceiveToIdle_DMA() with IDLE event

simon_EQUIUM
Associate II

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 ?


3 REPLIES 3
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.