interrupts.h
#ifndef SRC_INTERRUPTS_H_
#define SRC_INTERRUPTS_H_
#include <stdint.h>
//definitions for GIC configuration regisjters
#define ICCPMR *((uint32_t *) 0xF8F00104) //Priority mask reg
#define ICCICR *((uint32_t *) 0xF8F00100) //CPU interface control reg
#define ICDDCR *((uint32_t *) 0xF8F01000) //Distributor Control reg
#define ICDISER(n) *(((uint32_t *) 0xF8F01100) + n ) //Int. set enable reg
#define ICDICER(n) *(((uint32_t *) 0xF8F01180) + n ) //Int. Clear Enable reg
#define ICDIPR(n) *(((uint32_t *) 0xF8F01400) + n ) //Int. Priority reg
#define ICDIPTR(n) *(((uint32_t *) 0xF8F01800) + n ) //Int. Processor Targets reg
#define ICDICFR(n) *(((uint32_t *) 0xF8F01C00) + n ) //Int. Configuration reg
#define ICCIAR *((uint32_t *) 0xF8F0010C)
#define ICCEOIR *((uint32_t *) 0xF8F00110)
void disable_arm_interrupts(void);
void enable_arm_interrupts(void);
void configure_GIC_interrupt52(void);
#endif /* SRC_INTERRUPTS_H_ */
interrupts.c
#include "interrupts.h"
//disables the GIC distributor
void disable_gic_dist() { (ICDDCR = 0); };
//enables the GIC distributor
void enable_gic_dist() { (ICDDCR = 1); };
//Drive IRQ from the GIC
void disable_IRQ_passthrough() { (ICCICR =0x3); };
//sets the priority mask to the passed value 'priority'
void set_gic_pmr(uint32_t priority) { ICCPMR = (priority & 0xFF); };
//disables interrupt ID 52
void disable_interrupt52(void)
{
ICDIPTR(13) &= ~0x3; //remove processors from interrupt
ICDICER(1) = 0x00100000; //disable interrupts from GPIO module
}
//enables interrupt 52
void enable_interrupt52()
{
ICDIPTR(13) |= 1; //set bit 1 of ICDIPTR13 (enable for cpu0)
ICDISER(1) = 0x00100000;
}
//sets the interrupt priority of 52 to ‘priority_val’
void set_interrupt52_priority(uint8_t priority_val)
{
ICDIPR(13) &= ~0xFF; //clear priority bits for interrupt 52
ICDIPR(13) |= (priority_val) & 0xF8; //set top 5 bits based on passed value
}
//sets interrupt sensitivity of interrupt52 to ‘sens’
void set_interrupt52_sensitivity(uint8_t sens)
{
ICDICFR(3) &= ~0x300;
ICDICFR(3) |= (sens&0x3)<<8;
}
void configure_GIC_interrupt52(void)
{
//disable and configure GIC
disable_gic_dist(); //disable GIC interrupt generation
disable_IRQ_passthrough(); //drive IRQ from GIC
set_gic_pmr(0xFF); //set priority mask
//disable and configure interrupt 52
disable_interrupt52();
set_interrupt52_priority(0xA0); //set 52’s priority to 160
set_interrupt52_sensitivity(1); //set to high level
enable_interrupt52(); //reenable interrupt52
enable_gic_dist(); //reenable distributor
}
void disable_arm_interrupts(void)
{
uint32_t cpsr_val =0;
asm("mrs %0, cpsr\n" : "=r" (cpsr_val) ); //get current cpsr
cpsr_val &= ~(0xFF); //clear lower 8 bits
cpsr_val |= 0xDF; //set all bits but the 'T' bit
asm("msr cpsr, %0\n" : : "r" (cpsr_val)); //writeback modified value
return;
}
void enable_arm_interrupts(void)
{
uint32_t cpsr_val =0;
asm("mrs %0, cpsr\n" : "=r" (cpsr_val) ); //get current cpsr value
cpsr_val &= ~(0xFF); //clear lower 8 bits
cpsr_val |= 0x5F; //set all bits but 'T' and 'I' bit
asm("msr cpsr, %0\n" : : "r" (cpsr_val)); //writeback modified value
return;
}
GPIO.h
#ifndef SRC_GPIO_H_
#define SRC_GPIO_H_
#include <stdint.h>
//GPIO Configuration registers
//output data register
#define GPIO_DATA(n) *(((uint32_t*) 0xE000A040)+n)
//input data register
#define GPIO_DATA_RO(n) *(((uint32_t*) 0xE000A060)+n)
//direction register
#define GPIO_DIRM(n) *(((uint32_t*) 0xE000A204) + 16*n)
//output enable register
#define GPIO_OEN(n) *(((uint32_t*) 0xE000A208) + 16*n)
//RGB LED channels are bits 16-18, in bank 0
#define RGB_MASK 0x70000
//interrupt mask readonly reg
#define GPIO_INT_MASK(n) *(((uint32_t *) 0xE000A20C) + 16*(n))
//interrupt enable
#define GPIO_INT_EN(n) *(((uint32_t *) 0xE000A210) + 16*(n))
//interrupt disable
#define GPIO_INT_DIS(n) *(((uint32_t *) 0xE000A214) + 16*(n))
//interrupt status register
#define GPIO_INT_STAT(n) *(((uint32_t *) 0xE000A218) + 16*(n))
//interrupt edge/level sensitivity register
#define GPIO_INT_TYPE(n) *(((uint32_t *) 0xE000A21C) + 16*(n))
//interrupt polarity register
#define GPIO_INT_POL(n) *(((uint32_t *) 0xE000A220) + 16*(n))
//interrupt any edge register
#define GPIO_INT_ANY(n) *(((uint32_t *) 0xE000A224) + 16*(n))
//btn4 is 18 in bank 1, btn5 is 19 in bank 1
//define bit masks for easy access in banks
#define BT4_MASK 0x40000
#define BT5_MASK 0x80000
//define the bank the buttons are in
#define BT4_BANK 1
#define BT5_BANK 1
void configure_button_interrupts();
uint32_t get_GPIO_int_status(int bank, uint32_t mask);
void clear_GPIO_int_status(int bank, uint32_t mask);
#endif /* SRC_GPIO_H_ */
GPIO.c
#include "GPIO.h"
void set_GPIO_output(int n, uint32_t mask)
{
GPIO_DIRM(n) |= mask;
}
//sets the channels in the mask, in bank n, as inputs
void set_GPIO_input(int n, uint32_t mask)
{
GPIO_DIRM(n) &= ~mask;
}
//gets the value of only the bits in the mask
int read_GPIO_input(int n, uint32_t mask)
{
return (GPIO_DATA_RO(n) & mask);
}
//disables interrupts for channels set in the mask, for the given bank
void disable_GPIO_interrupt(int bank, uint32_t mask)
{
GPIO_INT_DIS(bank) = mask;
}
//enables interrupts for channels set in the mask, for the given bank
void enable_GPIO_interrupt(int bank, uint32_t mask)
{
GPIO_INT_EN(bank) = mask;
}
//sets int sensitivity of the channels set in the mask to level-sensitive
void set_GPIO_int_level_sens(int bank, uint32_t mask)
{
GPIO_INT_TYPE(bank) &= ~mask;
}
//sets int sensitivity of the channels set in the mask to edge-sensitive
void set_GPIO_int_edge_sens(int bank, uint32_t mask)
{
GPIO_INT_TYPE(bank) |= mask;
}
//sets polarity of the channels set in the mask to high
void set_GPIO_int_pol_high(int bank, uint32_t mask)
{
GPIO_INT_POL(bank) |= mask;
}
//sets polarity of the channels set in the mask to high
void set_GPIO_int_pol_low(int bank, uint32_t mask)
{
GPIO_INT_POL(bank) &= ~mask;
}
//sets edges of the channels set in the mask to both (if edge sensitive)
void set_GPIO_int_any_edge(int bank, uint32_t mask)
{
GPIO_INT_ANY(bank) |= mask;
}
//sets edges of the channels set in the mask to only specified edge [from pol] (if edge sensitive)
void clear_GPIO_int_any_edge(int bank, uint32_t mask)
{
GPIO_INT_ANY(bank) &= ~mask;
}
//clears the fields in given bank's int flag reg, based on the mask
void clear_GPIO_int_status(int bank, uint32_t mask)
{
GPIO_INT_STAT(bank) = mask;
}
// returns the given bank's interrupt flags, masked by the 2nd parameter
uint32_t get_GPIO_int_status(int bank, uint32_t mask)
{
return GPIO_INT_STAT(bank) & mask;
}
//configures the GPIO module to generate interrupts for
void configure_button_interrupts()
{
//disable all GPIO interrupts
disable_GPIO_interrupt(BT4_BANK, BT4_MASK | BT5_MASK);
//set buttons 4 and 5 to edge sensitive
set_GPIO_int_edge_sens(BT4_BANK, BT4_MASK | BT5_MASK);
//set button 4 to rising edge interrupts
set_GPIO_int_pol_high(BT4_BANK, BT4_MASK);
//set button 5 to falling edge interrupts
set_GPIO_int_pol_low(BT5_BANK, BT5_MASK);
//set so only use the defined edge
clear_GPIO_int_any_edge(BT4_BANK, BT4_MASK | BT5_MASK);
//clear interrupt flags for button 4 and 5
clear_GPIO_int_status(BT4_BANK, BT4_MASK | BT5_MASK);
//enable interrupts for button 4 and 5
enable_GPIO_interrupt(BT4_BANK, BT4_MASK|BT5_MASK);
}
main.c
#include "interrupts.h"
#include "GPIO.h"
#include <xil_exception.h>
#define GTC_INT_ID 27
#define GPIO_INT_ID 52
//set both the LED DATA and enable regsisters to the same value
#define LED_CTL *((uint32_t *) 0x4BB00000)
#define LED_DATA *((uint32_t *) 0x4BB00004)
//prototype ;ISR
void ISR();
int main(void)
{
//test using leds
LED_CTL = 0xF;//enable LEDS
LED_DATA =8; //light one led to indicate this program
//sequence to configure interrupts
disable_arm_interrupts();
configure_GIC_interrupt52();
configure_button_interrupts();
//register the ISR: 'ISR'
Xil_ExceptionRegisterHandler(5, ISR, NULL);
//enable interrupts
enable_arm_interrupts();
for(;;); //wait here
}
//interrupt service routine
void ISR()
{
uint32_t id;
id = ICCIAR; //get the interrupt ID
//switch for different interrupt ds
switch(id)
{
case GTC_INT_ID: //Global Timer interrupt
//code for GTC Interrupt Service goes here
break;
case GPIO_INT_ID: //interrupt ID 52 (GPIO)
//code for GPIO Interrupt Service goes here
LED_DATA ^=1; //toggle this led every interrupt
clear_GPIO_int_status(BT4_BANK,0xFFFFFFFF);
break;
default:
//other interrupts
break;
}
ICCEOIR = id; //acknowledge end of interrupt by giving it the id
return;
}