Estoy usando una placa Discovery STM32F4 con la biblioteca de periféricos estándar (SPL) de ST. Tengo una situación con un búfer circular: la interrupción del temporizador sondea botones y llena un búfer circular cada milisegundo si se presiona un botón, con un índice de ese botón. El bucle principal luego lo saca del búfer circular y ejecuta el comando apropiado. Ambas acciones requieren varios pasos (comprobar y cambiar los índices a un búfer circular, ...).
Cuando esto sucede en el bucle principal, la interrupción del temporizador debe desactivarse durante ese breve tiempo (para que los índices no se arruinen), pero no quiero desactivar todas las interrupciones solo por eso. Además, es preferible que aún se atienda una interrupción si ocurrió mientras estaba deshabilitada.
Traté de hacer esto deshabilitando la interrupción del temporizador para ese temporizador específico (TIM6 en mi caso) en el NVIC (pero lo dejé habilitado en el propio temporizador). Pero luego descubrí que no hay forma de verificar si las interrupciones se deshabilitaron en primer lugar, antes de deshabilitarlas (no puedo habilitar las interrupciones nuevamente si no se habilitaron antes, ya que puede estropear las cosas).
Entonces mis preguntas son:
¿Cómo verifico si una interrupción periférica específica está habilitada en el NVIC? (Solo hay funciones EnableIRQ
y DisableIRQ
.)
Intenté verificar el valor en
NVIC->ICER[((uint32_t)(IRQn) >> 5)];
y
NVIC->ISER[(uint32_t)((int32_t)IRQn) >> 5];
pero salen 0 aunque la interrupción esté habilitada.
¿Se seguirá sirviendo la interrupción (si ocurrió cuando estaba deshabilitada solo en el lado de NVIC) cuando se habilite nuevamente?
Respuesta rápida:
Yo usaría el siguiente (feo) código:
if (NVIC->ISER[(uint32_t)((int32_t)IRQn) >> 5] &
(uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F))
{
// It's enabled!
}
Explicación:
Los NVIC_ISERx
registros son de doble propósito. Si escribe a 1
en un bit específico, habilitará la interrupción. Si lee un bit específico, le dirá si la interrupción está habilitada:
Está utilizando SPL y, por lo tanto, está manejando la asignación de fuentes de interrupción a registros ISER y ubicaciones de bits.
En el core_cm4.h
archivo, versión 3.00, esta es la NVIC_EnableIRQ()
función:
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
/* NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); enable interrupt */
NVIC->ISER[(uint32_t)((int32_t)IRQn) >> 5] = (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); /* enable interrupt */
}
Es interesante que comentaron la primera línea (que era idéntica a la misma función en core_cm3.h
) y la dejaron ahí; Supongo que fue una corrección de errores y se olvidaron de eliminar el código incorrecto. Me perdí por todos los encasillamientos, pero espero que sean necesarios.
Mi respuesta anterior sigue el modelo de esta NVIC_EnableIRQ()
función.
En cuanto al comportamiento del sistema, lo siguiente se toma del documento PM0056 de ST (que es para M3, no para M4, pero el comportamiento es similar):
Si se habilita una interrupción pendiente, el NVIC activa la interrupción en función de su prioridad. Si una interrupción no está habilitada, afirmar su señal de interrupción cambia el estado de interrupción a pendiente, pero el NVIC nunca activa la interrupción, independientemente de su prioridad.
Si se establece el indicador "pendiente", la interrupción se atenderá tan pronto como vuelva a habilitar la interrupción.
brahans