STM32: прерывание UART запускается без установки каких-либо флагов

Я использую модуль UART4 STM32F105. Я использую прерывание RXNE («RX Buffer Not Empty») для захвата данных по мере их поступления. Он работает, как и ожидалось.

Когда прерывание RXNE включено, оно также включает прерывание переполнения (ORE). Это также работает, как и ожидалось.

Флаг состояния ORE отображается как USART_FLAG_ORE. Соответствующий флаг прерывания USART_IT_ORE. Если прерывание RXNE разрешено, то при установке бита флага это должно привести к установке бита IT. Скопировано из руководства пользователя :

руда

Я обрабатываю прерывание так:

void usartISR(void)
{
    // Did we receive data?
    if(USART_GetITStatus(UART4, USART_IT_RXNE) == SET)
    {
        // Add it to the active buffer
    }

    // Did the receiver overrun?
    else if(USART_GetITStatus(UART4, USART_IT_ORE) == SET)
    {
        // Clean up and clear the Overrun condition
    }

    // No other triggers have been enabled
    else
    {
        ErrorHandler(ERR_BAD_INTERRUPT);
    }
}

Проблема возникает, если флаг ORE уже установлен, когда я разрешаю прерывание:

{
    // The USART_FLAG_ORE bit is already set

    // The following command causes an immediate vector to the ISR:
    USART_IT_Config(UART4, USART_IT_RXNE, ENABLE);
}

Векторы кода в ISR, но USART_IT_OREфлаг, похоже, не установлен. ISR весело переходит в конец и вызывает обработчик ошибок. Если я загляну в регистры USART_CR, ни одно из других событий прерывания не будет разрешено. Если я обойду обработчик ошибок, код будет повторно обращаться к ISR, даже если флаги IT не установлены.

Почему ISR запускается без USART_IT_OREустановки флага? Я упускаю что-то очевидное?

Возможно ли, что вы читаете регистр данных (возможно, в первом блоке IF) до того, как ISR попадет в обработчик OVE? Так как это может очистить флаг...
@TisteAndii Спасибо за мысль! Предполагается, что этот флаг сбрасывается чтением в SR, за которым следует чтение в DR. Мой код не касается DR до тех пор, пока он не войдет в блоки IF. В качестве теста я посмотрел на SR в самом верху своего ISR. Был USART_FLAG_OREустановлен, подразумевая, что USART_IT_OREдолжен был быть установлен, но USART_GetITStatus()функция все равно вернула отрицательный результат...
@TisteAndii И, в качестве еще одного теста, я несколько раз читал SR. Бит USART_FLAG_OREне был очищен ни одним из чтений.
Какую версию STDPeriph вы используете? Может быть, вы могли бы попробовать USART_IT_ORE_RXвместо USART_IT_OREin GetITStatus(). Последнее кажется устаревшим определением в одной библиотеке, которую я нашел
@TisteAndii USART_IT_OREиспользуется в моей версии SPL (v3.5.0). Я поискал в библиотеке USART_IT_ORE_RXи ничего не нашел. Я нашел обходной путь и разместил его в ответ. Не могли бы вы посмотреть на него и посмотреть, говорит ли он вам что-нибудь? Еще раз спасибо.

Ответы (2)

Изучив определения в источнике stm32f10x_usart.hи Get_ITStatus()в источнике, становится очевидным, что фактических «флагов прерывания» UART не существует. В регистре состояния есть только флаги состояния. Как вы знаете, когда происходит событие, устанавливается соответствующий бит флага, независимо от того, разрешены прерывания или нет. Если соответствующее прерывание разрешено , то MCU переходит к соответствующему ISR, где событие может быть обработано.

прерывания UART

На изображении выше показано, что если прерывание RXNE включено и установлен флаг ORE, прерывание срабатывает, как и должно быть. В своем коде вы пытались получить статус «флага прерывания» с помощью Get_ITStatus(). Однако единственное, что Get_ITStatus()нужно сделать, это: проверить, установлен ли соответствующий флаг состояния SET &&, если соответствующее прерывание разрешено.

Теперь мы знаем, что первое условие истинно, так как вы сами УСТАНАВЛИВАЕТЕ флаг и убедились, что он действительно установлен. Второе условие также должно быть истинным — если проверяемое прерывание было RXNEIE (поскольку вы включили его). Но фактически проверяемый бит разрешения прерывания, когда USART_IT_OREон передается в Get_ITStatus(), EIEравен (разрешение прерывания при ошибке). Поэтому, поскольку вы не включили это прерывание, Get_ITStatus()всегда будет возвращаться RESET (0) для ошибки переполнения.

Get_ITStatus()хотя и не совсем неправильно. На приведенной выше диаграмме показано, что при установке ORE, EIE и DMAR будет генерироваться прерывание. Согласно мануалу по указанной вами ссылке:

ЭИЭ определяет

Этот фрагмент предоставляет дополнительное подтверждение. Таким образом, кажется, что авторы библиотеки закодировали только эту вторую возможность (хотя и неправильно, поскольку DMAR не проверяется). Ваш обходной путь проверяет флаг состояния напрямую, что нормально, если вы не устанавливаете EIE с RXNEIE, поскольку вы не знаете, какой источник сгенерировал ошибку переполнения.

Я нашел обходной путь. Это не дает прямого ответа на вопрос, но, надеюсь, это поможет, пока кто-то не даст лучший ответ :)

Получается, что хотя бит USART_IT_OREне устанавливается, USART_FLAG_OREбит устанавливается . Если я изменю ISR для проверки бита флага (используя USART_GetFlagStatus(USART_FLAG_ORE)) вместо бита IT ( USART_GetITStatus(USART_IT_ORE)), тогда ISR будет работать нормально.

Интересно, что оба USART_FLAG_OREи USART_IT_OREочищаются с одинаковой последовательностью событий. Они очищаются вместе. Так что мне больше не пришлось менять код...

Я прошел через это Get_ITStatus()и думаю, что знаю, почему так происходит. Вы должны будете проверить все же. Ввод ответа...
Я не уверен, но вы можете случайно очистить ORE этим методом. ВСЕГДА выполняйте процедуру очистки флага непосредственно перед включением какого-либо конкретного прерывания. Вы никогда не знаете, в каком состоянии он может находиться по какой-либо причине, и в конечном итоге получите ложное прерывание, как только это разрешение будет установлено!