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
Прерывание не отключается должным образом после завершения, оно будет продолжать срабатывать, вызывая что-то похожее на то, что вы видите.