//================================================================================= //================================================================================= /*****************************************************************************/ /* Most of this code came from the design example generted automatically by XPS. In the corresponding project, I add pushbuttons with interrupt, LEDs and the uart light. A series of directories are added as the board support package, which contains, among others, an xgpio and intc directories. This code assumes that there is an interrupt controller in the hardware system and the GPIO device is connected to the interrupt controller. The buttons and LEDs are on 2 seperate channels of the GPIO so that interrupts are not caused when the LEDs are turned on and off. ******************************************************************************/ /***************************** Include Files *********************************/ #include "xparameters.h" #include "xgpio.h" #include "xil_exception.h" #include "xintc.h" #include "stdio.h" /************************** Constant Definitions *****************************/ /* The following constants map to the names of the hardware instances that were created in the EDK XPS system. They are only defined here such that a user can easily change all the needed device IDs in one place. */ #define GPIO_DEVICE_ID XPAR_PUSH_BUTTONS_3BIT_DEVICE_ID #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID #define INTC_GPIO_INTERRUPT_ID XPAR_INTC_0_GPIO_1_VEC_ID #define GPIO_CHANNEL1 1 /* The following constants define the positions of the buttons and LEDs each channel of the GPIO */ #define GPIO_ALL_LEDS 0xFFFF #define GPIO_ALL_BUTTONS 0xFFFF /* The following constants define the GPIO channel that is used for the buttons and the LEDs. They allow the channels to be reversed easily. */ #define BUTTON_CHANNEL 1 /* Channel 1 of the GPIO Device */ #define LED_CHANNEL 2 /* Channel 2 of the GPIO Device */ #define BUTTON_INTERRUPT XGPIO_IR_CH1_MASK /* Channel 1 Interrupt Mask */ /* The following constant determines which buttons must be pressed at the same time to cause interrupt processing to stop and start */ #define INTERRUPT_CONTROL_VALUE 0x7 /* The following constant is used to wait after an LED is turned on to make sure that it is visible to the human eye. This constant might need to be tuned for faster or slower processor speeds. */ #define LED_DELAY 1000000 #define INTR_DELAY 0x00FFFFFF /************************** Function Prototypes ******************************/ void GpioDriverHandler(void *CallBackRef); int GpioIntrExample(XIntc* IntcInstancePtr, XGpio* InstancePtr, u16 DeviceId, u16 IntrId, u16 IntrMask, u32 *DataRead); int GpioSetupIntrSystem(XIntc* IntcInstancePtr, XGpio* InstancePtr, u16 DeviceId, u16 IntrId, u16 IntrMask); void GpioDisableIntr(XIntc* IntcInstancePtr, XGpio* InstancePtr, u16 IntrId, u16 IntrMask); /************************** Variable Definitions *****************************/ /* The following are declared globally so they are zeroed and so they are easily accessible from a debugger */ XGpio Gpio; /* The Instance of the GPIO Driver */ XIntc Intc; /* The Instance of the Interrupt Controller Driver */ static u16 GlobalIntrMask; /* GPIO channel mask that is needed by * the Interrupt Handler */ static volatile u32 IntrFlag; /* Interrupt Handler Flag */ /****************************************************************************/ /* Main initializes the GPIO device, sets up the interrupts and provides a foreground loop such that interrupt can occur in the background. IntcInstancePtr is a reference to the Interrupt Controller driver Instance, GpioInstancePtr is a reference to the GPIO driver Instance, GPIO_DEVICE_ID is the XPAR__DEVICE_ID value from xparameters.h INTC_GPIO_INTERRUPT_ID is XPAR___IP2INTC_IRPT_INTR value from xparameters.h GPIO_CHANNEL1 is the GPIO channel mask, DataRead is the pointer where the data read from GPIO Input is returned. *****************************************************************************/ int main(void) { int Status; u32 DataRead; XIntc *IntcInstancePtr = &Intc; XGpio *GpioInstancePtr = &Gpio; u32 delay; IntrFlag = 0; print("Press button to Generate Interrupt\r\n"); /* Initialize the GPIO driver. Basically copies the BaseAddress, InterruptPresent and and IsDual fields from the XGpio_ConfigTable into the instance pointer, and sets the IsReady field to 'ready'. Note the instance typedef has no DeviceId field -- it is replaced with the 'IsReady' field. This function defined in microblaze_0/libsrc/gpio_v3_00_a/src/xgpio_sinit.c */ Status = XGpio_Initialize(GpioInstancePtr, GPIO_DEVICE_ID); if (Status != XST_SUCCESS) { print("Failed to initialize GPIO driver!\n"); return; } /* The following statements set up the GPIO for Interrupts. First set GlobalIntrMask to the GPIO channel mask so the ISR can access it globally. */ GlobalIntrMask = GPIO_CHANNEL1; /* Initialize the interrupt controller driver so that it's ready to use. Specify the Interrupt controller device ID that was generated in xparameters.h. This function defined in microblaze_0/libsrc/intc_v2_02_a/src/xintc.c */ Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); if (Status != XST_SUCCESS) { print("Failed to initialize Interrupt Controller driver!\n"); return; } /* Hook up the interrupt service routine. Pass the GpioInstancePtr as data to the ISR when called. Never returns anything but XST_SUCCESS! This function defined in microblaze_0/libsrc/intc_v2_02_a/src/xintc.c */ Status = XIntc_Connect(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID, (XInterruptHandler)GpioDriverHandler, GpioInstancePtr); /* Enable the GPIO channel interrupts so that push button can be detected and enable interrupts for the GPIO device. Defined in microblaze_0/libsrc/gpio_v3_00_a/src/xgpio_intr.c */ XGpio_InterruptEnable(GpioInstancePtr, GPIO_CHANNEL1); /* Enable the global interrupt signal for the GPIO channel. Also defined in microblaze_0/libsrc/gpio_v3_00_a/src/xgpio_intr.c */ XGpio_InterruptGlobalEnable(GpioInstancePtr); /* Enable this specific interrupt vector on the interrupt controller. Also defined in microblaze_0/libsrc/intc_v2_02_a/src/xintc.c */ XIntc_Enable(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID); /* Initialize the exception table and register the interrupt controller handler with the exception table. Defined in the xil functions (somewhere). */ Xil_ExceptionInit(); /* The XIntc_InterruptHandler function is defined in microblaze_0/libsrc/intc_v2_02_a/src/xintc_intr.c but simply calls XIntc_DeviceInterruptHandler which is defined in microblaze_0/libsrc/intc_v2_02_a/src/xintc_l.c This function services all interrupts, calling the handlers for those interrupts that are active and then acknowledging them. */ Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XIntc_InterruptHandler, IntcInstancePtr); /* Enable non-critical exceptions */ Xil_ExceptionEnable(); /* Start the interrupt controller such that interrupts are recognized and handled by the processor. Writes MER is '11' -- preventing software testing. Enables the connection between the interrupt controller and the processor. Defined in microblaze_0/libsrc/intc_v2_02_a/src/xintc.c */ Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); if (Status != XST_SUCCESS) { print("Failed to setup Interrupt Controller!\n"); return; } delay = 0; while (!IntrFlag && (delay < INTR_DELAY)) { delay++; } /* Disable the interrupt in the GPIO */ XGpio_InterruptDisable(GpioInstancePtr, GPIO_CHANNEL1); /* Disable in the GPIO interrupt in the controller (xintc.c) */ XIntc_Disable(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID); DataRead = IntrFlag; if ( Status == 0 ) { if (DataRead == 0) print("No button pressed. \r\n"); else print("Gpio Interrupt Test PASSED. \r\n"); } else { print("Gpio Interrupt Test FAILED.\r\n"); } } /******************************************************************************/ /* This is the interrupt handler routine for the GPIO for this example. @param CallbackRef is the Callback reference for the handler. @return None. ******************************************************************************/ void GpioDriverHandler(void *CallbackRef) { XGpio *GpioPtr = (XGpio *)CallbackRef; IntrFlag = 1; /* Clear the Interrupt */ XGpio_InterruptClear(GpioPtr, GlobalIntrMask); }