1
votes

I am having an issue with USART behaviour and am wondering if any of you can help! I am using an STM32F303 with three of its USARTs in use, of which USART1 is configured as an asynchronous RS485 port with its DE line controlled automatically. The TX, RX and DE pins from the microcontroller are connected to a TI SN65HVD1792 RS485 transceiver, which presents four lines (TX+, TX-, RX+, RX-) to the user for communication.

I am using interrupt-driven USART communication, which in most cases works absolutely fine. However, I am having an issue with handling the error condition in which the RS485 link is configured as two-wire (TX+/RX+ and TX-/RX- connected together, to form a +ve/-ve pair of wires used for both transmission and reception) and more than one device on the bus tries to transmit at the same time. When this happens, the STM32 stops responding to all serial communications until the power is cycled.

Looking a little bit closer at what is going on, I see that USART1_IRQHandler in stm32f3xx_it.c is being called repeatedly - over and over until I power-cycle the board. This calls HAL_UART_IRQHandler(&huart1) in stm32f3xx_hal_uart.c, the function of which is to check which interrupt has occurred (parity error, frame error, noise error, overrun, wakeup from stop, rx register not empty, tx ready, tx complete), deal with it appropriately, and then clear the interrupt state. However, none of these specific interrupts are recognised as having triggered - execution just passes by all the "if" statements, the function exits, and then runs again - endlessly.

I can't find any way of recognising that this has occurred, as it doesn't throw up any of the recognised error conditions. I'm aware that RS485 bus clash is something that should be avoided by good system design, but we can't rule out the possibility that it will happen when the system is in a customer installation - and it needs to be able to recognise the error, ignore the "clashed" message and continue - needing to power cycle it is unacceptable.

Does anyone have any ideas as to how to recognise this condition / stop the system from entering an interrupt loop?

Thanks in advance

The interrupt routine is as follows (HAL file version 1.2.0, date 13 Nov 15)

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  /* UART parity error interrupt occurred -------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_PE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_PEF);

    huart->ErrorCode |= HAL_UART_ERROR_PE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

  /* UART frame error interrupt occurred --------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_FE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_FEF);

    huart->ErrorCode |= HAL_UART_ERROR_FE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

  /* UART noise error interrupt occurred --------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_NE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_NEF);

    huart->ErrorCode |= HAL_UART_ERROR_NE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

  /* UART Over-Run interrupt occurred -----------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_ORE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_OREF);

    huart->ErrorCode |= HAL_UART_ERROR_ORE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

   /* Call UART Error Call back function if need be --------------------------*/
  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    HAL_UART_ErrorCallback(huart);
  }

  /* UART wakeup from Stop mode interrupt occurred -------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_WUF) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_WUF) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_WUF);
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    HAL_UARTEx_WakeupCallback(huart);
  }

  /* UART in mode Receiver ---------------------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE) != RESET))
  {
    UART_Receive_IT(huart);
    /* Clear RXNE interrupt flag */
    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
  }


  /* UART in mode Transmitter ------------------------------------------------*/
 if((__HAL_UART_GET_IT(huart, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE) != RESET))
  {
    UART_Transmit_IT(huart);
  }

  /* UART in mode Transmitter (transmission end) -----------------------------*/
 if((__HAL_UART_GET_IT(huart, UART_IT_TC) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC) != RESET))
  {
    UART_EndTransmit_IT(huart);
  }

}
1
Do you have access to a debugger? Could you break on each if statement and check which interrupt is triggering? My guess is that an interrupt is triggering and a flag is not being reset properly - my initial guess is the TXE flag/IT.mban
Hi mban - I've done that; every if statement evaluates to "false". So no interrupt flags are being reset, which may lead to the repeated entries into the interrupt handler - but no interrupts are recognised as having triggered, so I'm not sure why the interrupt handler is being entered - or how to stop this happening! ThanksJMessenger
Could you post the interrupt routine? If it's the same one I'm thinking of, there are two checks for each if statement - one for the IT and one for the Flag. It's possible the interrupt is triggering but the flag isn't reset, preventing it from entering the proper interrupt handling statement. This is actually likely an issue with the HAL libraries; they have quite a few nasty bugs.mban
Thanks mban - Have edited to include the interrupt routine. I also tried adding "__HAL_UART_CLEAR_IT(huart, 0x1FFFFF) to the end of the routine, to clear all interrupt flags - this didn't work.JMessenger
Post original irq handler from file stm32f3xx_it.c which call to HAL_UART_IRQHandler(UART_HandleTypeDef *huart).imbearr

1 Answers

0
votes

The first thing I would do is to disable all of the interrupts you aren't explicitly using. At the very least, this should help identify the culprit. Do this with the macro __HAL_UART_DISABLE_IT() by passing in the interrupt you want to disable.

If that doesn't work, try confirming the TXE interrupt is being disabled by the UART_Transmit_IT() function being called by the IRQ. A quick way to figure out if this is the issue might be manually disabling the interrupt (while your issue is occurring) and seeing if the IRQ stops triggering. Otherwise, you could try breaking in the UART_Transmit_IT() function and seeing if the __HAL_UART_DISABLE_IT(huart, UART_IT_TXE); line gets executed. If the TXE interrupt isn't being properly disabled when finished, it will continue to trigger - causing something similar to what you're seeing.