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 ?


18 REPLIES 18

@simon_EQUIUM wrote:

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


Once the parser finds the Line Feed (0x0A), it will queue the packet. You'll have to parse the packet and make sure it's valid. If the packet doesn't have a CRC, then it's a bad packet. So it's up to you on how you want to report the error to the end user.

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.

After your reply I have checked something, and I thing I have something interesting.
When I use Putty and I send only 1 bytes the IDLE work every time.
If I send 2 bytes, the IDLE is never called and its never re-works.
I have to reboot the micro to re-send 1 bytes.
Do you have any idea ?

Show what code you have now.

 

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.

Here the code attached. it is a .C file and the IOC project.

I have tried something, if I use Realterm and I send some ASCII byte, it works like a charm.

 

simon_EQUIUM_0-1739798830233.png

BUT If I use KScada Modbus Doctor V2.10 the IDLE doesn't work.

simon_EQUIUM_1-1739798971648.png

 

I am wondering if the frame is ok on modbus doctor. But my other question is, if I have a problem with an RS485 frame, how can I prevent my software from being bricked?

 

 

Use a USB<>Serial adapter and monitor the Rx input of the STM32. Then you can see what the Modbus Doctor does differently than the RealTerm.

A better serial program to use would be Docklight https://docklight.de/

 

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.

Here some frames KO (modbus) :

simon_EQUIUM_3-1739877311373.png

simon_EQUIUM_4-1739877417223.png

 

 

Here some frames OK (UART ASCII) :

simon_EQUIUM_1-1739877019879.png

simon_EQUIUM_2-1739877085653.png

 

 

Karl Yamashita
Principal

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

 

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.

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.