EXCEPCIONES E INTERRUPCIONES EN EL ARM CORTEX-M4
#include "TM4C123.h" // Device header
#define NVIC_EN0_R (*((volatile unsigned long *)0xE000E100)) // IRQ 0 to 31 Set Enable Register
#define NVIC_PRI0_R (*((volatile unsigned long *)0xE000E400)) // IRQ 0 to 31 Priority Register
// begins the definition of the registers of Port A to be used as a GPIO
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define GPIO_PORTA_PCTL_R (*((volatile unsigned long *)0x4000452C))
#define GPIO_PORTA_AMSEL_R (*((volatile unsigned long *)0x40004528))
#define GPIO_PORTA_DIR_R (*((volatile unsigned long *)0x40004400))
#define GPIO_PORTA_AFSEL_R (*((volatile unsigned long *)0x40004420))
#define GPIO_PORTA_DEN_R (*((volatile unsigned long *)0x4000451C))
#define GPIO_PORTA_DATA_R (*((volatile unsigned long *)0x400043FC))
// ends the definition of the registers of Port A
//PLL Registers
#define SYSCTL_RIS_R (*((volatile unsigned long *)0x400FE050))
#define SYSCTL_RCC_R (*((volatile unsigned long *)0x400FE060))
#define SYSCTL_RCC2_R (*((volatile unsigned long *)0x400FE070))
void GPIOA_Handler(void){
GPIOA->ICR |= 0x20; // clear the corresponding interrupt
GPIOF->DATA ^= 0x04;
}
void Trigger_PA5(void){
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000001; //1) activate clock for Port A
delay = SYSCTL_RCGC2_R; //allow time for clock to start
GPIO_PORTA_AMSEL_R &= ~0x20; // 3) disable analog on PA5
GPIO_PORTA_PCTL_R &= ~0x00F00000; // 4) PCTL GPIO on PA5
GPIO_PORTA_DIR_R &= ~0x20; // 5) direction PA5 input
GPIO_PORTA_AFSEL_R &= ~0x20; // 6) PA5 regular port function
GPIO_PORTA_DEN_R |= 0x20; // 7) enable PA5 digital port
}
void Trigger_Interrupt_Init()
{
GPIOA->IS &= ~0x20; // The pin PA5 is set as edge sensitive
GPIOA->IBE &= ~0x20; // interrup event is controlled by GPIOIEV register
GPIOA->IEV |= 0x20; // Rising edge or low level in PF4 triggers and interrupt
GPIOA->ICR |= 0x20; // Corresponding interrupt is cleared
GPIOA->IM |= 0x20; // Interrupt from the pin is sent to the interrupt controller
NVIC_PRI0_R = (NVIC_PRI0_R&0xFF00FFFF)|0x00000000; //
NVIC_EN0_R |= 0x00000001; // (h) enable interrupt 0 in NVIC
//NVIC->IP[7] = 0x03 << 21; /* set interrupt priority to 3 */
//NVIC->ISER[0] |= 0x01; /* enable IRQ0 */
__enable_irq(); // Interrupt enable using startup.s functions
}
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source 10001111
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL, DIV400
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock, 400/(4+1) = 80MHz
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
void PortF_config(){
SYSCTL->RCGC2|=(0x1<<5);// The clock of PORTF
GPIOF->DEN |= 0xFF; //PORTF is Digital enable now
GPIOF->DIR|=(0x1<<2)|(0x1<<3)|(0x1<<1);//LEDs are outputs
}
int main()
{
PLL_Init();
Trigger_PA5();
Trigger_Interrupt_Init();
PortF_config();
while(1){
}
} // end of main
#define NVIC_EN0_R (*((volatile unsigned long *)0xE000E100)) // IRQ 0 to 31 Set Enable Register
#define NVIC_PRI0_R (*((volatile unsigned long *)0xE000E400)) // IRQ 0 to 31 Priority Register
// begins the definition of the registers of Port A to be used as a GPIO
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define GPIO_PORTA_PCTL_R (*((volatile unsigned long *)0x4000452C))
#define GPIO_PORTA_AMSEL_R (*((volatile unsigned long *)0x40004528))
#define GPIO_PORTA_DIR_R (*((volatile unsigned long *)0x40004400))
#define GPIO_PORTA_AFSEL_R (*((volatile unsigned long *)0x40004420))
#define GPIO_PORTA_DEN_R (*((volatile unsigned long *)0x4000451C))
#define GPIO_PORTA_DATA_R (*((volatile unsigned long *)0x400043FC))
// ends the definition of the registers of Port A
//PLL Registers
#define SYSCTL_RIS_R (*((volatile unsigned long *)0x400FE050))
#define SYSCTL_RCC_R (*((volatile unsigned long *)0x400FE060))
#define SYSCTL_RCC2_R (*((volatile unsigned long *)0x400FE070))
void GPIOA_Handler(void){
GPIOA->ICR |= 0x20; // clear the corresponding interrupt
GPIOF->DATA ^= 0x04;
}
void Trigger_PA5(void){
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000001; //1) activate clock for Port A
delay = SYSCTL_RCGC2_R; //allow time for clock to start
GPIO_PORTA_AMSEL_R &= ~0x20; // 3) disable analog on PA5
GPIO_PORTA_PCTL_R &= ~0x00F00000; // 4) PCTL GPIO on PA5
GPIO_PORTA_DIR_R &= ~0x20; // 5) direction PA5 input
GPIO_PORTA_AFSEL_R &= ~0x20; // 6) PA5 regular port function
GPIO_PORTA_DEN_R |= 0x20; // 7) enable PA5 digital port
}
void Trigger_Interrupt_Init()
{
GPIOA->IS &= ~0x20; // The pin PA5 is set as edge sensitive
GPIOA->IBE &= ~0x20; // interrup event is controlled by GPIOIEV register
GPIOA->IEV |= 0x20; // Rising edge or low level in PF4 triggers and interrupt
GPIOA->ICR |= 0x20; // Corresponding interrupt is cleared
GPIOA->IM |= 0x20; // Interrupt from the pin is sent to the interrupt controller
NVIC_PRI0_R = (NVIC_PRI0_R&0xFF00FFFF)|0x00000000; //
NVIC_EN0_R |= 0x00000001; // (h) enable interrupt 0 in NVIC
//NVIC->IP[7] = 0x03 << 21; /* set interrupt priority to 3 */
//NVIC->ISER[0] |= 0x01; /* enable IRQ0 */
__enable_irq(); // Interrupt enable using startup.s functions
}
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source 10001111
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL, DIV400
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock, 400/(4+1) = 80MHz
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
void PortF_config(){
SYSCTL->RCGC2|=(0x1<<5);// The clock of PORTF
GPIOF->DEN |= 0xFF; //PORTF is Digital enable now
GPIOF->DIR|=(0x1<<2)|(0x1<<3)|(0x1<<1);//LEDs are outputs
}
int main()
{
PLL_Init();
Trigger_PA5();
Trigger_Interrupt_Init();
PortF_config();
while(1){
}
} // end of main
De hecho, no hay una diferencia significativa entre una excepción y una interrupción en el Sistema ARM Cortex-M4. Regularmente el procesador ARM genera una excepción y tiene un nivel de prioridad más alto en comparación con otras interrupciones. Una excepción a menudo se genera por un evento, como el evento de falla del sistema u otra operación incorrecta del sistema. Una interrupción generalmente es creada por un periférico interno o externo con menor nivel de prioridad.
Además de configurar e inicializar cada pin GPIO, también es necesario configurar los niveles de prioridad y habilitar las interrupciones relacionadas para los puertos GPIO seleccionados.
Esto se maneja usando algunos registros de control de interrupción de NVIC Entre ellos, dos grupos de registro son muy útiles y son:
Interrupt Priority-Level Registers (0xE000E4000xE000E4EF)
Interrupt Set Enable Registers (0xE000E1000xE000E11C)
Estos dos grupos de registros se utilizan para establecer los niveles de prioridad para todos los periféricos y habilitar periféricos seleccionados
Esto se maneja usando algunos registros de control de interrupción de NVIC Entre ellos, dos grupos de registro son muy útiles y son:
Interrupt Priority-Level Registers (0xE000E4000xE000E4EF)
Interrupt Set Enable Registers (0xE000E1000xE000E11C)
Estos dos grupos de registros se utilizan para establecer los niveles de prioridad para todos los periféricos y habilitar periféricos seleccionados
Configurción de los Registros de Prioridad
En la siguiente figura observaras una formula 4n+1 etc. Esto es para cofigurar cada interrupcion de las N que estan disponibles. Por ejemplo si quisiera configurar la interrupcion 31 se requiere configurar el registro PRI7 pues si n=7 entonces tenemos 4*7+3= 31.
Nota: Recuerde que en este ejemplo estamos trabajando la interrupcion externa que corresponde a la interrupcion numero 0. Por lo tanto tenemos que configurar el registro PRI0.
Nota: Recuerde que en este ejemplo estamos trabajando la interrupcion externa que corresponde a la interrupcion numero 0. Por lo tanto tenemos que configurar el registro PRI0.
Entonces si queremos configurar la interrupción 0 que corresponde al Puerto A. Tenemos que escribir un vaor en binario de 0 a 7 en los bits 7-5 del registro PRI0 como esta en nuestro ejemplo.