STM32F303: проблема с многократным срабатыванием прерывания USART после столкновения шины RS485

У меня проблема с поведением USART, и мне интересно, может ли кто-нибудь из вас помочь! Я использую STM32F303 с тремя используемыми USART, из которых USART1 настроен как асинхронный порт RS485 с автоматически управляемой линией DE. Контакты TX, RX и DE микроконтроллера подключены к приемопередатчику TI SN65HVD1792 RS485, который предоставляет пользователю четыре линии (TX+, TX-, RX+, RX-) для связи.

Я использую управляемую прерываниями связь USART, которая в большинстве случаев работает абсолютно нормально. Однако у меня возникла проблема с обработкой состояния ошибки, при котором канал RS485 настроен как двухпроводный (TX+/RX+ и TX-/RX-, соединенные вместе, для формирования пары +ve/-ve, используемой для обоих передача и прием), и более чем одно устройство на шине пытается передать одновременно. Когда это происходит, STM32 перестает отвечать на все последовательные соединения до тех пор, пока не будет отключено питание.

Присмотревшись немного ближе к происходящему, я вижу, что USART1_IRQHandler в stm32f3xx_it.c вызывается многократно - снова и снова, пока я не выключу и снова выключу плату. Это вызывает HAL_UART_IRQHandler(&huart1) в stm32f3xx_hal_uart.c, функция которого заключается в проверке того, какое прерывание произошло (ошибка четности, ошибка кадра, шумовая ошибка, переполнение, пробуждение от остановки, регистр rx не пуст, tx ready, tx complete), разобраться с этим соответствующим образом, а затем очистить состояние прерывания. Однако ни одно из этих определенных прерываний не распознается как инициированное - выполнение просто проходит все операторы "если", функция завершается, а затем снова запускается - бесконечно.

Я не могу найти какой-либо способ распознать, что это произошло, так как это не вызывает ни одного из обнаруженных состояний ошибки. Я знаю, что при хорошем проектировании системы следует избегать столкновения шины RS485, но мы не можем исключить вероятность того, что это произойдет, когда система находится на установке клиента - и она должна быть в состоянии распознать ошибка, проигнорируйте "конфликтующее" сообщение и продолжайте - необходимость включения / выключения питания недопустима.

У кого-нибудь есть идеи относительно того, как распознать это условие / не дать системе войти в цикл прерывания?

заранее спасибо

Процедура прерывания выглядит следующим образом (версия файла HAL 1.2.0, дата 13 ноября 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 ответ

Решение

Первое, что я хотел бы сделать, это отключить все прерывания, которые вы явно не используете. По крайней мере, это должно помочь определить виновника. Сделай это с макросом __HAL_UART_DISABLE_IT() передавая прерывание, которое вы хотите отключить.

Если это не сработает, попробуйте подтвердить TXE прерывание отключается UART_Transmit_IT() функция вызывается IRQ. Быстрый способ выяснить, если это проблема, может быть вручную отключить прерывание (пока ваша проблема возникает) и посмотреть, перестает ли срабатывать IRQ. В противном случае, вы можете попробовать взломать UART_Transmit_IT() функционировать и видеть, если __HAL_UART_DISABLE_IT(huart, UART_IT_TXE); линия исполняется. Если TXE Прерывание не отключается должным образом после завершения, оно будет продолжать срабатывать, вызывая что-то похожее на то, что вы видите.

Другие вопросы по тегам