Está en la página 1de 28

1

MANEJO DE INTERRUPCIONES
Una interrupción es un evento asíncrono que
provoca detener la ejecución del código actual
en base a una prioridad (cuanto más importante
es la interrupción, mayor será su prioridad, lo
que hará que una interrupción de menor
prioridad se suspenda).

ISR (Rutina de servicio de interrupción


o Interrupt Service Routine)
Es la rutina que se ejecuta durante una
interrupción se denomina “
MANEJO DE INTERRUPCIONES
La interrupción es una fuente de
multiprogramación: el hardware es responsable
de guardar el contexto de ejecución actual (es
decir, los datos de la pila, el actual Contador
de Programa y entre otras cosas) antes de
cambiar al ISR. Esta funcionalidad
es explotada por los sistemas operativos en
tiempo real para introducir la noción de tareas.
Sin ayuda del hardware es imposible contar con
un verdadero sistema preventivo, que permita
conmutar varios contextos de ejecución sin
perder irreparablemente el flujo de ejecución
actual.
MANEJO DE INTERRUPCIONES
La arquitectura ARM distingue entre los dos
tipos:

• interrupciones de hardware
• interrupciones por el software (por
ejemplo, un acceso a una ubicación de
memoria no válida).

En la terminología ARM, una interrupción es


un tipo de excepción.
MANEJO DE INTERRUPCIONES

Los procesadores Cortex-M proporcionan una


unidad de HARDWARE dedicada a la
administración de interrupciones llamada:
NVIC (Nested Vectored Interrupt Controller).
MANEJO DE INTERRUPCIONES
NVIC (Administrador de vector de
interrupciones anidadas).
La imagen muestra la relación entre la unidad NVIC, el núcleo
del procesador y los periféricos. Distinguimos dos tipos de
periféricos:
• Los externos al núcleo Cortex-M, pero internos a la MCU
STM32 (por ejemplo, temporizadores, UARTS, etc.)
• los periféricos externos a la MCU.

La fuente de las interrupciones procedentes de la última clase


de periféricos son puertos GPIO, que pueden configurarse
como entrada o salida o para excitar un periférico externo
avanzado. Un controlador programable dedicado, llamado
“External Interrupt/Event Controller” (EXTI), es responsable
de la interconexión entre las señales de E/S externas y el
controlador NVIC, como veremos a continuación.
MANEJO DE INTERRUPCIONES
Interrupciones EXTERNAS
STM32 proporciona un número variable de fuentes de interrupción
externas conectadas al NVIC a través del controlador EXTI, que a su vez
es capaz de gestionar varias líneas EXTI. Los GPIO están conectados a las
líneas EXTI, y es posible habilitar interrupciones para cada GPIO la
mayoría de ellos comparten la misma línea de interrupción.

Px0 están conectados a EXTI0, todos los pines Px1, Px2, Px3 y Px4 están
conectados a EXTI1, EXTI2, EXTI3 y EXTI4 respectivamente, mientras que
los pines Px5, Px6, Px7, Px8, Px9 están asociados a la misma línea
EXTI9_5 de la misma manera los pines Px10, Px11, Px12, Px13, Px14,
Px15 están en la EXTI15_10
Esto significa que:
• Sólo un pin PxY puede ser fuente de interrupción. Por ejemplo, no podemos definir PA0 y PB0 como pines de
interrupción de entrada.
• Para las líneas EXTI que comparten el mismo IRQ dentro del controlador NVIC, tenemos que codificar el ISR
correspondiente para que debamos ser capaces de discriminar qué líneas generaron la interrupción. Por ejemplo, si
definimos PA10 y PA15, necesitamos leer los dos pines para identificar cual genero el evento de interrupción.
MANEJO DE INTERRUPCIONES
HABILITACION DE INTERRUPCIONES
Para habilitar y deshabilitar la interrupciones, la librería HAL
proporciona las siguientes funciones:

Void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);

Void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);

Donde IRQn_Type IRQn es el nombre de la interrupcion que se activara,


ese nombre se puede encontrar en una lista que contiene la tabla
vectorial en el archivo startup_stm32.s
MANEJO DE INTERRUPCIONES
Asignación de prioridades
La arquitectura ARM Cortex-M tiene la capacidad de priorizar interrupciones. La prioridad de interrupción permite
definir dos cosas:
• Los ISR que se ejecutarán primero en caso de interrupciones simultáneas;
• Aquellas rutinas que se pueden optar opcionalmente para iniciar la ejecución de un ISR con una prioridad más
alta.
El mecanismo de prioridad de interrupción en Cortex-M3 es más avanzado que el disponible en los
microcontroladores basados en Cortex-M0/0+. Los desarrolladores tienen un mayor grado de flexibilidad. En los
núcleos Cortex-M3/4/7, la prioridad de cada interrupción se define a través del registro IPR. Se trata de un registro
de 8 bits en la arquitectura de núcleo ARMv7-M que permite hasta 255 niveles de prioridad diferentes. Sin
embargo, en la práctica, los MCUs STM32 que implementan estos núcleos utilizan solamente los cuatro bits superiores
de este registro, viendo todos los otros bits igual a cero.
MANEJO DE INTERRUPCIONES
Asignación de prioridades
La imagen muestra claramente cómo se interpreta el
contenido de los DPI. Esto significa que tenemos 16
niveles de prioridad máxima del 0x00 al 0xF0.
Cuanto menor sea este número, mayor será la
prioridad. Si dos interrupciones disparan al mismo
tiempo, el que tenga la mayor prioridad será
atendido primero. Si el procesador ya está
atendiendo una interrupción y una prioridad más
alta interrumpe, entonces la ejecución de la actual
interrupción se suspende y el control pasa a la
interrupción de prioridad más alta. Cuando la
ejecución de la interrupción de alta prioridad se
completa, la ejecución vuelve a la interrupción
anterior, mientras no se produzca otra interrupción
con mayor prioridad.
MANEJO DE INTERRUPCIONES
Asignación de prioridades
La complicación surge del hecho de que el registro
IPR puede subdividirse lógicamente en dos partes:
una serie de bits que definen la prioridad de
prioridad y una serie de bits que definen la sub-
prioridad. El primer nivel de prioridad rige las
prioridades de prioridad entre ISRs. Si un ISR tiene
una prioridad más alta que otra, prevendrá la
ejecución del ISR de menor prioridad en caso de
que se active. La sub-prioridad determina qué ISR
se ejecutará primero, en caso de un ISR múltiple
pendiente.
MANEJO DE INTERRUPCIONES
Asignación de prioridades

La imagen muestra un ejemplo de interrupciones de diferentes prioridades. La letra A representa un IRQ con una
prioridad baja (0x20) que se dispara en el tiempo t0. El ISR inicia la ejecución de A-ISR, pero el B-IRQ que tiene
una prioridad más alta (0x10), se dispara en el instante t1. Entonces la ejecución de A-ISR se detiene y comienza
la ejecución de B-ISR. Después en un tiempo t3 se dispara C-IRQ (prioridad 0x00), la ejecución de B-ISR se
detiene y se inicia la ejecución de C-ISR. Cuando la ejecución de C-ISR termina, se reanuda la ejecución de B-ISR
hasta que termina. Finalmente se reanuda la ejecución de A-ISR hasta el final. A este proceso de control de
interrupciones se le llama: “anidado”. El mecanismo inducido por prioridades de interrupción conduce al nombre
del controlador NVIC o Controlador de Interrupción Vectorial Anidado.
MANEJO DE INTERRUPCIONES
MANEJO DE INTERRUPCIONES
MANEJO DE INTERRUPCIONES
MANEJO DE INTERRUPCIONES
Cuando se llama a la función ISR EXTIx_IRQHandler(), se transfiere el
control a la función HAL_GPIO_EXTI_IRQHandler().
Esta función realiza todas las actividades relacionadas con la interrupción y
llama a la rutina HAL_GPIO_EXTI_Callback(), pasando como parámetro
el GPIO que generó el IRQ.
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_4)
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11); //Toggle LED
else if(GPIO_Pin == GPIO_PIN_10)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, RESET);
}
MANEJO DE INTERRUPCIONES
En caso de tener varios pines de interrupción en una ISR
combinada, CubeMX genera el código para diferenciar entre los
pines.

void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
}
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}
CONFIGURACIÓN DE INTERRUPCIONES

Para comprender la configuración de este periférico,


desarrollaremos el siguiente programa:

EJEMPLO 1:
Escribir un programa en el cual un led se prenda o se apague
cada vez que se presione un pulsador configurado como fuente
de interrupción externa.
CONFIGURACIÓN DE INTERRUPCIONES
#include "main.h"
#include "stm32f1xx_hal.h"
EJEMPLO 1:
Configuración de los pines: Se usaran /* Private function prototypes--*/
los puertos C y B. El pin13 de puerto C void SystemClock_Config(void);
static void MX_GPIO_Init(void);
será configurado como entrada con
pull-up y habilitado como interrupción int main(void)
externa con detección de flanco de {
bajada. El pin 10 del puerto B será
configurado como salida para HAL_Init();
conectar el led. SystemClock_Config();
GPIO_Init();
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

while (1);

}
CONFIGURACIÓN DE INTERRUPCIONES
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EJEMPLO 1:
Configuración de los pines: Se usaran __HAL_RCC_GPIOC_CLK_ENABLE();
los puertos C y B. El pin13 de puerto C __HAL_RCC_GPIOB_CLK_ENABLE();
será configurado como entrada con
pull-up y habilitado como interrupción GPIO_InitStruct.Pin = GPIO_PIN_13;
externa con detección de flanco de GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
bajada. El pin 10 del puerto B será GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
configurado como salida para
conectar el led. GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);


}
NOTA:
La función HAL_Delay NO

CONFIGURACIÓN DE INTERRUPCIONES funciona dentro de las


subrutinas de interrupción. Se
debe usa otro método de
temporización, por ejemplo un
ciclo FOR son parámetros.
EJEMPLO 1: void EXTI15_10_IRQHandler(void)
Configuración de los pines: Se usaran {
los puertos C y B. El pin13 de puerto C for(int i=0;i<100000;i++);
será configurado como entrada con __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_13);
pull-up y habilitado como interrupción if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)==0)
externa con detección de flanco de {
bajada. El pin 10 del puerto B será HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_10);
configurado como salida para }
conectar el led. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
CONFIGURACIÓN DE INTERRUPCIONES

EJEMPLO 2:
Escribir un programa en el cual dos leds conectados a dos
pines intercambian el parpadeo. Si se presiona un pulsador
conectado a otro pin configurado como interrupción externa
el parpadeo aumentara de velocidad. Si se vuelve a
presionar el pulsador el parpadeo volverá a su velocidad
inicial.
CONFIGURACIÓN DE INTERRUPCIONES
Configuración de los pines: Se usara #include "main.h"
el puerto C y B. El pin13 de puerto C #include "stm32f1xx_hal.h"
como entrada con pull-up habilitado
configurado como interrupción externa int valor=0;
con detección de flanco de bajada, y void SystemClock_Config(void);
los pines 13 y 14 del puerto B como static void MX_GPIO_Init(void);
salidas para conectar los leds. void EXTI15_10_IRQHandler(void);
CONFIGURACIÓN DE INTERRUPCIONES
Configuración de los pines: Se usara
int main(void)
el puerto C y B. El pin13 de puerto C
{
como entrada con pull-up habilitado
HAL_Init();
configurado como interrupción externa
con detección de flanco de bajada, y
SystemClock_Config();
los pines 13 y 14 del puerto B como
salidas para conectar los leds.
GPIO_Init();

HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

while (1)
CONFIGURACIÓN DE INTERRUPCIONES
while (1)
{
if(valor==1) {
Configuración de los pines: Se usara HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
el puerto C y B. El pin13 de puerto C HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
como entrada con pull-up habilitado HAL_Delay(100);
configurado como interrupción externa HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
con detección de flanco de bajada, y HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);
los pines 13 y 14 del puerto B como HAL_Delay(100);
salidas para conectar los leds. }
else if (valor==0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_Delay(500);
}
}
CONFIGURACIÓN DE INTERRUPCIONES
static void GPIO_Init(void)
{
Configuración de los pines: Se usara GPIO_InitTypeDef GPIO_InitStruct;
el puerto C y B. El pin13 de puerto C
como entrada con pull-up habilitado __HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
configurado como interrupción externa
con detección de flanco de bajada, y HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
los pines 13 y 14 del puerto B como
salidas para conectar los leds. GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
CONFIGURACIÓN DE INTERRUPCIONES
void EXTI15_10_IRQHandler(void)
Configuración de los pines: Se usara
{
el puerto C y B. El pin13 de puerto C
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_13);
como entrada con pull-up habilitado
if(valor==0) {
configurado como interrupción externa
valor=1;
con detección de flanco de bajada, y
}
los pines 13 y 14 del puerto B como
else if (valor==1){
salidas para conectar los leds.
valor=0;
}
}
CONFIGURACIÓN DE INTERRUPCIONES
void EXTI15_10_IRQHandler(void)
{
Configuración de los pines: Se usara HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
el puerto C y B. El pin13 de puerto C }
como entrada con pull-up habilitado
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
configurado como interrupción externa
{
con detección de flanco de bajada, y
if(GPIO_Pin == GPIO_PIN_13)
los pines 13 y 14 del puerto B como
{
salidas para conectar los leds.
if(valor==0) {
valor=1;
}
else if (valor==1){
valor=0;
}
}
}

También podría gustarte