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 готов, tx завершен), обработайте его соответствующим образом, а затем очистите состояние прерывания. Однако ни одно из этих конкретных прерываний не распознается как сработавшее — выполнение просто проходит мимо всех операторов «если», функция завершается, а затем снова запускается — бесконечно.

Я не могу найти никакого способа распознать, что это произошло, так как это не вызывает ни одного из распознанных условий ошибки. Я знаю, что конфликтов на шине 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);
  }

}

person JMessenger    schedule 26.04.2016    source источник
comment
У вас есть доступ к отладчику? Не могли бы вы остановиться на каждом операторе if и проверить, какое прерывание срабатывает? Я предполагаю, что срабатывает прерывание, и флаг не сбрасывается должным образом - мое первоначальное предположение - это флаг TXE/IT.   -  person mban    schedule 26.04.2016
comment
Hi mban - я сделал это; каждый оператор if оценивается как ложный. Таким образом, никакие флаги прерывания не сбрасываются, что может привести к повторным входам в обработчик прерываний, но никакие прерывания не распознаются как сработавшие, поэтому я не уверен, почему вводится обработчик прерываний - или как это остановить! Спасибо   -  person JMessenger    schedule 26.04.2016
comment
Не могли бы вы опубликовать процедуру прерывания? Если это тот же самый, о котором я думаю, для каждого оператора if есть две проверки — одна для IT и одна для флага. Возможно, прерывание срабатывает, но флаг не сбрасывается, что не позволяет ему ввести правильный оператор обработки прерывания. Скорее всего, это проблема с библиотеками HAL; у них довольно много неприятных ошибок.   -  person mban    schedule 27.04.2016
comment
Спасибо, mban - отредактировал, чтобы включить процедуру прерывания. Я также попытался добавить __HAL_UART_CLEAR_IT(huart, 0x1FFFFF) в конец подпрограммы, чтобы сбросить все флаги прерывания - это не сработало.   -  person JMessenger    schedule 27.04.2016
comment
Опубликуйте исходный обработчик прерывания из файла stm32f3xx_it.c, который вызывает HAL_UART_IRQHandler(UART_HandleTypeDef *huart).   -  person imbearr    schedule 27.04.2016
comment
imbearr — эта функция (USART1_IRQHandler) представляет собой всего лишь одну строку, вызов HAL_UART_IRQHandler(&huart1), как указано выше. Спасибо   -  person JMessenger    schedule 27.04.2016


Ответы (1)


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

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

person mban    schedule 27.04.2016