Code examples for Project 4

Examples for configuring and using the GIC

1927

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;



}