Un par de definiciones primero:
En el manual de programación de Cortex-M, una Excepción es cualquier cosa que interrumpa el flujo normal del programa e invoca un controlador desde la tabla vectorial, y Interrupts es un subconjunto de excepciones, provenientes de los periféricos fuera del núcleo ARM. Debido a que SysTick se implementa en el núcleo de Cortex-M, se considera una excepción, pero no una interrupción.
Las excepciones tienen un Número de excepción , comenzando desde 0. Las interrupciones tienen un Número de IRQ , comenzando desde 0. Debido a que todas las interrupciones son excepciones, todas obtienen un Número de excepción, que es 16 más alto que el número de IRQ. Las excepciones que no son interrupciones (incluido SysTick) tienen números de excepción en el rango de 0 a 15, más pequeños que los números de excepción de las interrupciones. Algo confuso, las excepciones que no son interrupciones también tienen números de IRQ, que por extensión caen en el rango de -16 a -1. SysTick tiene el número de excepción 15 y el número de IRQ -1.
Estoy usando un MCU STM32F303 y he notado que el SysTick puede configurarse para causar una excepción, que parece mencionarse con bastante frecuencia en varias Guías del usuario. De esta manera, tendrá un nivel de prioridad más alto que las interrupciones regulares.
Todas las excepciones, excepto Restablecer, NMI y Hardfault tienen prioridades configurables . Simplemente se configura de manera diferente para las interrupciones y otras excepciones. Vea la implementación de CMSIS como un claro ejemplo:
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)(IRQn) < 0)
{
SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
else
{
NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
}
Puedes llamar a NVIC_SetPriority
o manipular SCB->SHP
directamente para darle a SysTick una prioridad más baja que cualquier otra interrupción.
SysTick tiene de hecho un nivel de prioridad predeterminado que es más alto que cualquier interrupción, pero eso es solo porque al restablecer, todas las prioridades se establecen en 0, y en caso de un empate , el número IRQ más bajo gana, en este caso, SysTick con -1.
Por otro lado, parece ser posible configurar Systick como una interrupción en NVIC también. Tiene su propio número de solicitud de interrupción y parece que se puede establecer en estado pendiente. Debido a que las interrupciones de NVIC tienen niveles de prioridad programables, también podríamos configurarlo de esta manera.
Solo las interrupciones se pueden configurar a través de los registros NVIC, y SysTick no es una interrupción. Los registros NVIC no tienen lugar para números IRQ negativos, en máscaras de bits o en cualquier otro lugar.
SysTick puede establecerse en un estado pendiente, pero eso se hace a través de SCB->ICSR
, no en NVIC.
Tenga en cuenta que NVIC_SetPriority()
y NVIC_GetPriority()
son las únicas funciones NVIC_ en CMSIS que tratan los números IRQ negativos correctamente. Otras funciones como NVIC_SetPendingIRQ()
o NVIC_EnableIRQ()
solo aceptan números IRQ negativos felizmente, hacen un poco de mezcla aleatoria en ellos que resulta en un GRAN desplazamiento de los registros NVIC, y garabatea alguna dirección de memoria lejana, posiblemente causando un fallo de disco , u otro comportamiento extraño. Las funciones HAL_NVIC_ realizan algunas comprobaciones de límites cuando habilitas USE_FULL_ASSERT
en tus encabezados, pero de lo contrario, dejan que los parámetros no válidos ingresen a las funciones NVIC de CMSIS.
EDIT
Hay un buen truco para encontrar todos los lugares donde se llama a una función con un parámetro negativo. Ponga esto en un encabezado común:
#define NVIC_EnableIRQ(x) ((void)sizeof(char[x]))
Es un error en tiempo de compilación siempre que esta construcción se invoca con un número negativo. Repita esto para cada función de NVIC excepto NVIC_SetPriority()
y NVIC_GetPriority()
.