0
\$\begingroup\$
void USART2_IRQHandler(void)
 
{
 
 /* USER CODE BEGIN USART2_IRQn 0 */
 
  /* UART IDLE Interrupt */
 
    if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) == SET)  
 
    {
 
     __HAL_UART_CLEAR_IDLEFLAG(&huart2);
 print("time %d",timeCounter");
receivedDataFlag = 1;

 
}
 
}

When I use the this function check line idle states and decide the data received or not received. But this interrup trigger while transmitting. How can I seperate receive data line idle and receive idle ?

I want to trigger just receive data line idle, how can I do that ? What other register should I look at?

I get very interesting result,

Sender send every 100 ms data to my device;

If I use the only receive DMA functions; time return 10, 110, 220,330 (Idle states working)

But If I received than after transmit data with uart this times values return 10,13,15,... a mean transmit function cahnge the line idle state, how is the possible ? IS the UART_FLAG_IDLE related only rx?

EDIT: By the way I am using rs485 so when I start to transmitting, I set to tranceiver transmitter mode so Sender side receiver mode so my MCU does decide to IDLE this state ? is that possible? How can I protect this situation?

When I start the transmition mode after received data, then completed callback call, When I call the HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE); function IDLE interrupt trigger every 5 ms but data sending timeout 100 ms

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
 

  HAL_UART_DMAStop(&huart2);
  dmaTransmitCompletedFlag = 1;
  RS485_Set_Receive_Mode();
  HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE);
  waitForTransmittingData = 0;

}
\$\endgroup\$
4
  • \$\begingroup\$ Never do function calls from ISRs! You just pushed all registers used in ISR and now you do it again. The printf increases registers used and latency from function in ISR is wasteful. Set your flag. In your software, check flag, process it and print message. \$\endgroup\$ Commented Jun 18, 2021 at 17:18
  • \$\begingroup\$ @StainlessSteelRat Are you serious about what you said? Calling functions from ISR is fine. The STM32 HAL already does that. It's a STM32 so on ISR the registers are pushed to stack by hardware for ISR context anyway, there is no penalty any more than for a regular function call. Besides the STM32 could have like 1 megabyte of RAM, so it's not a problem, not even on a 8 kilobyte STM32. What's not right is to call a heavy function like printf in ISR, and most likely it is not re-entrant so those are the largest issues. \$\endgroup\$
    – Justme
    Commented Jun 18, 2021 at 17:28
  • \$\begingroup\$ Depends upon the function. Any printf is a pig and is part of OP's problem. \$\endgroup\$ Commented Jun 18, 2021 at 17:37
  • \$\begingroup\$ @StainlessSteelRat is correct that using prints in an interrupt is a problem since the stdio stream driver should be thread safe. Which it isn't by default for stm32. \$\endgroup\$
    – Jeroen3
    Commented Jun 21, 2021 at 6:05

3 Answers 3

2
\$\begingroup\$

That interrupt is used for both transmit and receive.

The IDLE is relevant only to reception, it means there is at least one full frame of idle detected.

Using print in an interrupt is unwise, espcially if the print uses the same UART for which the interrupt is.

\$\endgroup\$
6
  • \$\begingroup\$ print using usart1 but the this interrupt using usart2, is IDLE relevant only reception how this posible ? How is my timer very close? \$\endgroup\$
    – mathco
    Commented Jun 18, 2021 at 14:39
  • \$\begingroup\$ By the way I am using rs485 so when I start to transmitting, I set to tranceiver transmitter mode so Sender side receiver mode so my MCU does decide to IDLE this state ? is that possible? \$\endgroup\$
    – mathco
    Commented Jun 18, 2021 at 14:49
  • 1
    \$\begingroup\$ second the caution against print in an interrupt. In addition to the blocking nature of that function, there's a lot of overhead and RAM usage that further increases the execution time. Best practice is to keep your handlers very fast and simple, and to pass off more time intensive functionality by setting flags in the handler and clearing them in the main loop. If you handlers run too long, you'll get 'interrupt storms' which basically soft-brick your code. \$\endgroup\$
    – Ocanath
    Commented Jun 18, 2021 at 15:54
  • 1
    \$\begingroup\$ @mathco I don't understand why you ask how this is possible, because it is how it is designed. IDLE is relevant only to reception, it is set when after a frame reception if the reception of a new frame is not detected within a timeout period of one frame. If you want me to quote the manual for you, you must state which exact STM32 microcontroller model you are using. \$\endgroup\$
    – Justme
    Commented Jun 18, 2021 at 16:12
  • \$\begingroup\$ I added some detail in my question \$\endgroup\$
    – mathco
    Commented Jun 21, 2021 at 5:59
1
\$\begingroup\$

That IRQ is dedicated for USART2, but it gets called for every enabled interrupt associated with USART2. That means that the handler needs to check and handle every enabled interrupt signal. For STM32 USART, that includes signals fundamental to interrupt driven UART like TXNE and RXNE, as well as error signals, IDLE, etc.

The IDLE signal is for framing multi-byte receptions (a common issue for USART, especially in noisy environments). It gets asserted when the receive line has been asserted high (or 'idle') for some debounce time (determined by the baud rate/oversampling settings), after that line has been active (during reception of a group of one or more bytes). This is useful because you can use it to reset your receive buffer back to the '0' index, so that the next frame is lined up properly (even if too few or too many bytes were received in the current frame). Normally you have to implement this kind of logic with a dedicated timer peripheral, but STM32 conveniently packs it into their USART peripherals (although it's not supported by the native HAL driver).

If you really want only the idle signal to trigger an interrupt, you'll need to manually disable every other interrupt signal. If you want a useful interrupt-driven UART receiver, I don't suggest you do that.

\$\endgroup\$
0
\$\begingroup\$

From one of your previous questions I gave you some links, where this is implemented.

Source code

USART3_IRQHandler(void) {
    /* Check for IDLE line interrupt */
    if (LL_USART_IsEnabledIT_IDLE(USART3) && LL_USART_IsActiveFlag_IDLE(USART3)) {
        LL_USART_ClearFlag_IDLE(USART3);        /* Clear IDLE line flag */
        usart_rx_check();                       /* Check for data to process */
    }

    /* Implement other events when needed */
}
\$\endgroup\$
2
  • \$\begingroup\$ I looked all source code in this link before writting my code, but the IDLE interrupt trigger when the RS485 tranceiver start transmit mode, I dont know why ? \$\endgroup\$
    – mathco
    Commented Jun 21, 2021 at 5:34
  • \$\begingroup\$ After this function, IDLE interrupt trigger; void HAL_UART_TxCpltCallback(UART_HandleTypeDef huart) { HAL_UART_DMAStop(&huart2); dmaTransmitCompletedFlag = 1; RS485_Set_Receive_Mode(); HAL_UART_Receive_DMA(&huart2,(uint8_t)dma_rx_buf,DMA_BUF_SIZE); waitForTransmittingData = 0; } \$\endgroup\$
    – mathco
    Commented Jun 21, 2021 at 5:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.