STM32: la interrupción de UART se activa sin que se establezcan indicadores

Estoy usando el módulo UART4 de un STM32F105. Estoy usando la interrupción RXNE ("RX Buffer Not Empty") para capturar datos a medida que ingresan. Funciona como se esperaba.

Cuando la interrupción RXNE está habilitada, también habilita la interrupción Overrun (ORE). Esto también parece funcionar como se esperaba.

El indicador de estado de ORE se asigna como USART_FLAG_ORE. El indicador de interrupción correspondiente es USART_IT_ORE. Si la interrupción RXNE está habilitada, cuando se establece el bit de bandera, debería hacer que también se establezca el bit de TI. Copiado del manual de usuario :

mineral

Estoy manejando la interrupción así:

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);
    }
}

El problema ocurre si el indicador ORE ya está configurado cuando habilito la interrupción:

{
    // 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);
}

Los vectores de código a la ISR, pero la USART_IT_OREbandera no parece establecerse. El ISR salta alegremente hasta el final y llama al controlador de errores. Si observo los registros USART_CR, ninguno de los otros eventos de interrupción está habilitado. Si omito el controlador de errores, el código se dirige repetidamente al ISR aunque no se establezcan indicadores de TI.

¿Por qué se activa el ISR sin que USART_IT_OREse establezca la bandera? ¿Me estoy perdiendo algo obvio?

¿Es posible que esté leyendo el registro de datos (tal vez en el primer bloque IF) antes de que el ISR llegue al controlador OVE? Ya que esto podría despejar la bandera...
@TisteAndii ¡Gracias por el pensamiento! Se supone que ese indicador se borra con una lectura en SR seguida de una lectura en DR. Mi código no toca el DR hasta que ingresa a los bloques IF. Como prueba, miré el SR en la parte superior de mi ISR. Se USART_FLAG_OREconfiguró, lo que implica que USART_IT_OREdebería haberse configurado, pero la USART_GetITStatus()función aún devolvió un negativo...
@TisteAndii Y, como otra prueba, leí la SR varias veces. El USART_FLAG_OREbit no fue borrado por ninguna de las lecturas.
¿Qué versión de STDPeriph estás usando? Tal vez podrías probar USART_IT_ORE_RXen lugar de USART_IT_OREen GetITStatus(). Este último parece ser una definición heredada en una biblioteca que encontré
@TisteAndii USART_IT_OREes el que se usa en mi versión del SPL (v3.5.0). Hice una búsqueda en la biblioteca USART_IT_ORE_RXy encontré cero resultados. Encontré una solución y la publiqué como una respuesta. ¿Lo mirarías y verías si te dice algo? Gracias de nuevo.

Respuestas (2)

Habiendo revisado las definiciones en stm32f10x_usart.hy Get_ITStatus()en la fuente, es evidente que no hay 'indicadores de interrupción' UART reales. Solo hay banderas de estado en el registro de estado. Como sabe, cuando ocurre un evento, se establece el bit de bandera correspondiente, ya sea que las interrupciones estén habilitadas o no. Si la interrupción asociada está habilitada, la MCU salta al ISR relevante, donde se puede manejar el evento.

Interrupciones UART

La imagen de arriba muestra que si la interrupción RXNE está habilitada y el indicador ORE está establecido, se activa una interrupción, como debería ser. En su código, intentó obtener el estado de la 'bandera de interrupción' con Get_ITStatus(). Sin embargo, lo único que Get_ITStatus()hace es: verificar si el indicador de estado asociado está SET && si la interrupción asociada está habilitada.

Ahora, sabemos que la primera condición es verdadera, ya que usted mismo CONFIGURÓ la bandera y verificó que efectivamente está configurada. La segunda condición también debería ser cierta, si la interrupción que se está comprobando fuera RXNEIE (ya que la habilitó). Pero el bit de habilitación de interrupción real que se verifica, cuando USART_IT_OREse pasa a Get_ITStatus(), es EIE(Error Interrupt Enable). Entonces, dado que no habilitó esta interrupción, Get_ITStatus()siempre devolverá RESET (0) para un error de desbordamiento.

Get_ITStatus()aunque no es completamente incorrecto. El diagrama anterior muestra que cuando se configuran ORE, EIE y DMAR, se generará una interrupción. De acuerdo con el manual en el enlace que proporcionó:

definiciones de EIE

Este fragmento proporciona una confirmación adicional. Entonces parece que los autores de la biblioteca solo codificaron esta segunda posibilidad (aunque no correctamente ya que DMAR no está verificado). Su solución alternativa verifica el indicador de estado directamente, lo cual está bien siempre que no configure EIE con RXNEIE, ya que no sabría qué fuente generó el error de desbordamiento.

He encontrado una solución. Esto no responde directamente a la pregunta, pero con suerte ayudará hasta que alguien dé una mejor respuesta :)

Resulta que aunque el USART_IT_OREno se establece, el USART_FLAG_OREbit sí lo hace . Si modifico el ISR para verificar el bit de bandera (usando USART_GetFlagStatus(USART_FLAG_ORE)) en lugar del bit de TI ( USART_GetITStatus(USART_IT_ORE)), entonces el ISR se comporta bien.

Curiosamente, ambos USART_FLAG_OREy USART_IT_OREse borran con la misma secuencia de eventos. Se aclaran juntos. Así que no tuve que cambiar nada más de mi código...

He pasado Get_ITStatus()y creo que sé por qué sucede de esa manera. Eso sí, tendrás que verificar. Escribiendo una respuesta...
No estoy seguro, pero es posible que esté limpiando ORE accidentalmente con este método. SIEMPRE realice el procedimiento de borrado de bandera justo antes de habilitar cualquier interrupción específica. ¡Nunca se sabe en qué estado podría estar por cualquier motivo, y termina con una interrupción espuria tan pronto como se activa esa habilitación!