2025-02-13 07:48 AM
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;
}
}
}
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 ?
Solved! Go to Solution.
2025-02-24 02:41 AM - edited 2025-02-24 02:43 AM
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.
2025-02-13 08:08 AM
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)
2025-02-13 08:15 AM - edited 2025-02-13 08:22 AM
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.
2025-02-13 09:22 AM
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
2025-02-14 01:23 AM
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.
2025-02-14 05:46 AM
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.
2025-02-14 07:24 AM
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.
2025-02-14 07:41 AM
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.
2025-02-14 08:04 AM
Yes @Karl Yamashita , Totally agree with you. But I can't explain the reason why the register has an impact on the callback :(
2025-02-14 09:59 AM
@Karl Yamashita If I have a problem with in the trame, does the function is called ? For example, the CRC is not complet.