Microblaze Xgpio interrupts
Leider sind die Beispiele betreffend Interrupts am Microblaze Softcore von Xilinx nicht gerade üppig gesät zumal wenn es um Xgpio geht. Dieses C Beispiel hilft hoffentlich ein wenig mit den Interrupts klar zu kommen. Laut der Xilinx Interrupt Dokumentation die schon ein paar Jahre auf dem Buckel hat (4 Jahre) gibt es 2 Level auf denen die Interrupts angelegt werden können. Der unterste Level (LowLevel) ist in den *_l.h header files festgelegt. Dieser Level ist auch halbwegs gut beschrieben (in diesem Dokument und im Anhang B der Embedded System Tools Reference Manual) nur über den höher abstrahierten Level gibt es von Xilinx ein einziges Anwendungsbeispiel (und falls doch so habe ich es nicht gefunden) zugegebener maßen ist die API Dokumentation sehr gut … aber ein greifbares Beispiel wäre schon sehr Praktisch gewesen.
Gut jetzt gibts ja eins … nämlich meins … ich hoffe es Hilft.
Ich habe das Projekt mit dem BSB (Base System Builder) erstellt und die Buttons und den Timer dort hinzugefühgt und als Interrupt Quellen angegeben. (das ist normal nicht Schwer)
Zum abgleichen gebe ich hier meine mit der EDK 10.1 erstellten MHS (Microprocessor Hardware Specification) MSS (Microprocessor Software Specification) files an.
MHS:
# #########################################################
# Created by Base System Builder Wizard for Xilinx EDK 10.1.03 Build EDK_K_SP3.6
# Wed Feb 24 10:37:29 2010
# Target Board: Avnet Avnet V5FXT Evaluation Board Rev B
# Family: virtex5
# Device: xc5vfx30t
# Package: ff665
# Speed Grade: -1
# Processor: microblaze_0
# System clock frequency: 125.00 MHz
# On Chip Memory : 16 KB
# ########################################################
PARAMETER VERSION = 2.1.0PORT fpga_0_RS232_USB_RX_pin = fpga_0_RS232_USB_RX, DIR = I
PORT fpga_0_RS232_USB_TX_pin = fpga_0_RS232_USB_TX, DIR = O
PORT fpga_0_RS232_USB_reset_dummy_pin = net_vcc, DIR = O
PORT fpga_0_LEDs_8Bit_GPIO_d_out_pin = fpga_0_LEDs_8Bit_GPIO_d_out, DIR = O, VEC = [0:7]
PORT fpga_0_Push_Buttons_3Bit_GPIO_in_pin = fpga_0_Push_Buttons_3Bit_GPIO_in, DIR = I, VEC = [0:2]
PORT sys_clk_pin = dcm_clk_s, DIR = I, SIGIS = CLK, CLK_FREQ = 100000000
PORT sys_rst_pin = sys_rst_s, DIR = I, RST_POLARITY = 1, SIGIS = RSTBEGIN microblaze
PARAMETER INSTANCE = microblaze_0
PARAMETER C_INTERCONNECT = 1
PARAMETER HW_VER = 7.10.d
PARAMETER C_DEBUG_ENABLED = 1
BUS_INTERFACE DLMB = dlmb
BUS_INTERFACE ILMB = ilmb
BUS_INTERFACE DPLB = mb_plb
BUS_INTERFACE IPLB = mb_plb
BUS_INTERFACE DEBUG = microblaze_0_dbg
PORT MB_RESET = mb_reset
PORT Interrupt = Interrupt
ENDBEGIN plb_v46
PARAMETER INSTANCE = mb_plb
PARAMETER HW_VER = 1.03.a
PORT PLB_Clk = sys_clk_s
PORT SYS_Rst = sys_bus_reset
ENDBEGIN lmb_v10
PARAMETER INSTANCE = ilmb
PARAMETER HW_VER = 1.00.a
PORT LMB_Clk = sys_clk_s
PORT SYS_Rst = sys_bus_reset
ENDBEGIN lmb_v10
PARAMETER INSTANCE = dlmb
PARAMETER HW_VER = 1.00.a
PORT LMB_Clk = sys_clk_s
PORT SYS_Rst = sys_bus_reset
ENDBEGIN lmb_bram_if_cntlr
PARAMETER INSTANCE = dlmb_cntlr
PARAMETER HW_VER = 2.10.a
PARAMETER C_BASEADDR = 0×00000000
PARAMETER C_HIGHADDR = 0x00003fff
BUS_INTERFACE SLMB = dlmb
BUS_INTERFACE BRAM_PORT = dlmb_port
ENDBEGIN lmb_bram_if_cntlr
PARAMETER INSTANCE = ilmb_cntlr
PARAMETER HW_VER = 2.10.a
PARAMETER C_BASEADDR = 0×00000000
PARAMETER C_HIGHADDR = 0x00003fff
BUS_INTERFACE SLMB = ilmb
BUS_INTERFACE BRAM_PORT = ilmb_port
ENDBEGIN bram_block
PARAMETER INSTANCE = lmb_bram
PARAMETER HW_VER = 1.00.a
BUS_INTERFACE PORTA = ilmb_port
BUS_INTERFACE PORTB = dlmb_port
ENDBEGIN xps_uartlite
PARAMETER INSTANCE = RS232_USB
PARAMETER HW_VER = 1.00.a
PARAMETER C_BAUDRATE = 9600
PARAMETER C_DATA_BITS = 8
PARAMETER C_ODD_PARITY = 0
PARAMETER C_USE_PARITY = 0
PARAMETER C_SPLB_CLK_FREQ_HZ = 125000000
PARAMETER C_BASEADDR = 0×84000000
PARAMETER C_HIGHADDR = 0x8400ffff
BUS_INTERFACE SPLB = mb_plb
PORT RX = fpga_0_RS232_USB_RX
PORT TX = fpga_0_RS232_USB_TX
ENDBEGIN xps_gpio
PARAMETER INSTANCE = LEDs_8Bit
PARAMETER HW_VER = 1.00.a
PARAMETER C_GPIO_WIDTH = 8
PARAMETER C_IS_DUAL = 0
PARAMETER C_IS_BIDIR = 0
PARAMETER C_ALL_INPUTS = 0
PARAMETER C_BASEADDR = 0×81400000
PARAMETER C_HIGHADDR = 0x8140ffff
BUS_INTERFACE SPLB = mb_plb
PORT GPIO_d_out = fpga_0_LEDs_8Bit_GPIO_d_out
ENDBEGIN xps_gpio
PARAMETER INSTANCE = Push_Buttons_3Bit
PARAMETER HW_VER = 1.00.a
PARAMETER C_INTERRUPT_PRESENT = 1
PARAMETER C_GPIO_WIDTH = 3
PARAMETER C_IS_DUAL = 0
PARAMETER C_IS_BIDIR = 0
PARAMETER C_ALL_INPUTS = 1
PARAMETER C_BASEADDR = 0×81420000
PARAMETER C_HIGHADDR = 0x8142ffff
BUS_INTERFACE SPLB = mb_plb
PORT GPIO_in = fpga_0_Push_Buttons_3Bit_GPIO_in
PORT IP2INTC_Irpt = Push_Buttons_3Bit_IP2INTC_Irpt
ENDBEGIN xps_timer
PARAMETER INSTANCE = xps_timer_1
PARAMETER HW_VER = 1.00.a
PARAMETER C_COUNT_WIDTH = 32
PARAMETER C_ONE_TIMER_ONLY = 1
PARAMETER C_BASEADDR = 0x83c00000
PARAMETER C_HIGHADDR = 0x83c0ffff
BUS_INTERFACE SPLB = mb_plb
PORT Interrupt = xps_timer_1_Interrupt
ENDBEGIN clock_generator
PARAMETER INSTANCE = clock_generator_0
PARAMETER HW_VER = 2.01.a
PARAMETER C_EXT_RESET_HIGH = 1
PARAMETER C_CLKIN_FREQ = 100000000
PARAMETER C_CLKOUT0_FREQ = 125000000
PARAMETER C_CLKOUT0_BUF = TRUE
PARAMETER C_CLKOUT0_PHASE = 0
PARAMETER C_CLKOUT0_GROUP = NONE
PORT CLKOUT0 = sys_clk_s
PORT CLKIN = dcm_clk_s
PORT LOCKED = Dcm_all_locked
PORT RST = net_gnd
ENDBEGIN mdm
PARAMETER INSTANCE = debug_module
PARAMETER HW_VER = 1.00.d
PARAMETER C_MB_DBG_PORTS = 1
PARAMETER C_USE_UART = 1
PARAMETER C_UART_WIDTH = 8
PARAMETER C_BASEADDR = 0×84400000
PARAMETER C_HIGHADDR = 0x8440ffff
BUS_INTERFACE SPLB = mb_plb
BUS_INTERFACE MBDEBUG_0 = microblaze_0_dbg
PORT Debug_SYS_Rst = Debug_SYS_Rst
ENDBEGIN proc_sys_reset
PARAMETER INSTANCE = proc_sys_reset_0
PARAMETER HW_VER = 2.00.a
PARAMETER C_EXT_RESET_HIGH = 1
PORT Slowest_sync_clk = sys_clk_s
PORT Dcm_locked = Dcm_all_locked
PORT Ext_Reset_In = sys_rst_s
PORT MB_Reset = mb_reset
PORT Bus_Struct_Reset = sys_bus_reset
PORT MB_Debug_Sys_Rst = Debug_SYS_Rst
PORT Peripheral_Reset = sys_periph_reset
ENDBEGIN xps_intc
PARAMETER INSTANCE = xps_intc_0
PARAMETER HW_VER = 1.00.a
PARAMETER C_BASEADDR = 0×81800000
PARAMETER C_HIGHADDR = 0x8180ffff
BUS_INTERFACE SPLB = mb_plb
PORT Irq = Interrupt
PORT Intr = Push_Buttons_3Bit_IP2INTC_Irpt & xps_timer_1_Interrupt
END
MSS:
PARAMETER VERSION = 2.2.0BEGIN OS
PARAMETER OS_NAME = standalone
PARAMETER OS_VER = 2.00.a
PARAMETER PROC_INSTANCE = microblaze_0
PARAMETER STDIN = RS232_USB
PARAMETER STDOUT = RS232_USB
ENDBEGIN PROCESSOR
PARAMETER DRIVER_NAME = cpu
PARAMETER DRIVER_VER = 1.11.b
PARAMETER HW_INSTANCE = microblaze_0
PARAMETER COMPILER = mb-gcc
PARAMETER ARCHIVER = mb-ar
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = bram
PARAMETER DRIVER_VER = 1.00.a
PARAMETER HW_INSTANCE = dlmb_cntlr
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = bram
PARAMETER DRIVER_VER = 1.00.a
PARAMETER HW_INSTANCE = ilmb_cntlr
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = generic
PARAMETER DRIVER_VER = 1.00.a
PARAMETER HW_INSTANCE = lmb_bram
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = uartlite
PARAMETER DRIVER_VER = 1.13.a
PARAMETER HW_INSTANCE = RS232_USB
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = gpio
PARAMETER DRIVER_VER = 2.12.a
PARAMETER HW_INSTANCE = LEDs_8Bit
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = gpio
PARAMETER DRIVER_VER = 2.12.a
PARAMETER HW_INSTANCE = Push_Buttons_3Bit
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = tmrctr
PARAMETER DRIVER_VER = 1.10.b
PARAMETER HW_INSTANCE = xps_timer_1
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = generic
PARAMETER DRIVER_VER = 1.00.a
PARAMETER HW_INSTANCE = clock_generator_0
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = uartlite
PARAMETER DRIVER_VER = 1.13.a
PARAMETER HW_INSTANCE = debug_module
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = generic
PARAMETER DRIVER_VER = 1.00.a
PARAMETER HW_INSTANCE = proc_sys_reset_0
ENDBEGIN DRIVER
PARAMETER DRIVER_NAME = intc
PARAMETER DRIVER_VER = 1.11.a
PARAMETER HW_INSTANCE = xps_intc_0
END
Das C Progamme zur verarbeitung der Interrupts:
#include <xtmrctr.h>
#include <xintc.h>
#include <xgpio.h>
#include <xparameters.h>XGpio gpio, buttons;
XIntc intc;
XTmrCtr timer;void buttons_int_handler(void * baseaddr_p) {
//xil_printf(“Button!\r\n\n”);
unsigned int csr;
/* Read Button CSR to see if it raised the interrupt */
csr = XTmrCtr_mGetControlStatusReg (XPAR_PUSH_BUTTONS_3BIT_BASEADDR, 0);
xil_printf(“csr=%d\r\n”,csr);switch(csr) {
case 0×01:
xil_printf(“SW4\r\n”);
break;case 0×02:
xil_printf(“SW3\r\n”);
break;case 0×04:
xil_printf(“SW2\r\n”);
break;default : {
}}
//Clear the interrupt both in the Gpio instance as well as the interrupt controlle
XGpio_InterruptClear(&buttons, 0×3);
XIntc_Acknowledge (&intc, XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR);
xil_printf(“Interrupt Cleared\r\n”);}
void timer_int_handler(void * baseaddr_p) {
unsigned int csr;
/* Read timer 0 CSR to see if it raised the interrupt */
csr = XTmrCtr_mGetControlStatusReg (XPAR_XPS_TIMER_1_BASEADDR, 0);
/* If the interrupt occurred, then increment a counter */
if (csr & XTC_CSR_INT_OCCURED_MASK)
{
count++;
}
print (“Timer Interrupt\r\n”);
xil_printf (“Count Sagt: %d Interrupts \r\n”,count);/* Clear the timer interrupt */
XTmrCtr_mSetControlStatusReg (XPAR_XPS_TIMER_1_BASEADDR, 0, csr); //Still Level 0 Macro
}int main()/*the one and only*/ {
microblaze_enable_interrupts();
xil_printf(“MB interrupts\t\t Enabled\r\n”);Xuint32 status;
//Interr Init
status=XIntc_Initialize (&intc, XPAR_XPS_INTC_0_DEVICE_ID);
if (status != XST_SUCCESS){
xil_printf(“init INTC_0\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“init INTC_0\t\t OK \r\n”);//Button Init Stuff
status=XGpio_Initialize (&buttons, XPAR_PUSH_BUTTONS_3BIT_DEVICE_ID);
if (status != XST_SUCCESS){
xil_printf(“init Buttons\t\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“init Buttons\t\t OK \r\n”);XGpio_SetDataDirection(&buttons, 1, 0xFFFFFFFF);
xil_printf(“Buttons Direction\t Set\r\n”);//Timer Init Stuff
status=XTmrCtr_Initialize (&timer, XPAR_XPS_TIMER_1_DEVICE_ID);
if (status != XST_SUCCESS){
xil_printf(“init Timer\t\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“init Timer\t\t OK \r\n”);//buttons
status=XIntc_Connect (&intc, XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR,
&buttons_int_handler, (void *)0);if (status != XST_SUCCESS){
xil_printf(“connect buttons\t\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“connect buttons\t\t OK \r\n”);//Timer Options
XTmrCtr_SetOptions(&timer, 0, //for timer #0 (there are 2 timers in the led_timer device, we’re only using one)
XTC_DOWN_COUNT_OPTION | // Count down to 0
XTC_INT_MODE_OPTION | // When it hits 0, cause an interrupt
XTC_AUTO_RELOAD_OPTION); // And reload the “reset” value and begin counting againxil_printf(“Timer Setting\t\t Set\r\n”);
//Timer
status=XIntc_Connect (&intc, XPAR_XPS_INTC_0_XPS_TIMER_1_INTERRUPT_INTR, &timer_int_handler, (void*)0);if (status != XST_SUCCESS){
xil_printf(“connect timer\t\t Error\r\n”);
return XST_FAILURE;
}
else xil_printf(“connect timer\t\t OK\r\n”);XIntc_Enable (&intc, XPAR_PUSH_BUTTONS_3BIT_DEVICE_ID);
xil_printf(“Button interrupt\t Enabled\r\n”);XIntc_Enable (&intc, XPAR_XPS_TIMER_1_DEVICE_ID);
xil_printf(“Timer interrupt\t\t Enabled\r\n”);//Enable Xgpio Interrupt Stuff ans so on …
//XGpio_InterruptClear(buttons, XGPIO_IR_CH1_MASK);
xil_printf(“Buttons Interrupt\t NOT Cleared YET\r\n”);XGpio_InterruptEnable (&buttons, XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR);
xil_printf(“XGpio interrupt\t\t Enabled\r\n”);
XGpio_InterruptGlobalEnable (&buttons);
xil_printf(“XGpio Global interrupt\t Enabled\r\n”);status=XIntc_Start (&intc ,XIN_REAL_MODE);
if (status != XST_SUCCESS){
xil_printf(“start xintc\t\t Error\r\n”);
return XST_FAILURE;
}
else xil_printf(“start xintc\t\t OK\r\n”);//Load Value 4 the Timer
XTmrCtr_SetResetValue(&timer, 0, 1000000000);
//Start the timer
XTmrCtr_Start (&timer,0);xil_printf(“<—Entering WHILE(1);—>\r\n”);
while(1);
}
Beim erstellen des Codes haben die Beispiele die auch beide schon ein wenig älter sein dürften (ca. 3 Jahre) hier und hier sehr geholfen.
Ich hoffe ihr könnt mit meinem Code fetzen etwas anfangen über Kommentare würde ich mich sehr freuen.
Die Ausgaben des Progammes erfolgen über stdout (je nach dem wie er konfiguriert ist über Usb (virtueller Com Port) oder direkt über RS232.
Für mein Beispiel ist das Hyperterminal (Windows Zubehör/ Kommunikation) auf 9600 Baud, 8 Datenbits, Ohne Parität, mit einem Stoppbit und ohne Flusssteuerung zu konfigurieren (BSB default iirr). Getestet habe ich es auf einem Avnet Virtex5 Board.
#include <xintc.h>
#include <xgpio.h>
#include <xparameters.h>
XGpio gpio, buttons;
XIntc intc;
XTmrCtr timer;
void buttons_int_handler(void * baseaddr_p) {
//xil_printf(“Button!\r\n\n”);
unsigned int csr;
/* Read Button CSR to see if it raised the interrupt */
csr = XTmrCtr_mGetControlStatusReg (XPAR_PUSH_BUTTONS_3BIT_BASEADDR, 0);
xil_printf(“csr=%d\r\n”,csr);
switch(csr) {
case 0×01:
xil_printf(“SW4\r\n”);
break;
case 0×02:
xil_printf(“SW3\r\n”);
break;
case 0×04:
xil_printf(“SW2\r\n”);
break;
default : {
}
}
//Clear the interrupt both in the Gpio instance as well as the interrupt controlle
XGpio_InterruptClear(&buttons, 0×3);
XIntc_Acknowledge (&intc, XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR);
xil_printf(“Interrupt Cleared\r\n”);
}
void timer_int_handler(void * baseaddr_p) {
unsigned int csr;
/* Read timer 0 CSR to see if it raised the interrupt */
csr = XTmrCtr_mGetControlStatusReg (XPAR_XPS_TIMER_1_BASEADDR, 0);
/* If the interrupt occurred, then increment a counter */
if (csr & XTC_CSR_INT_OCCURED_MASK)
{
count++;
}
print (“Timer Interrupt\r\n”);
xil_printf (“Count Sagt: %d Interrupts \r\n”,count);
/* Clear the timer interrupt */
XTmrCtr_mSetControlStatusReg (XPAR_XPS_TIMER_1_BASEADDR, 0, csr); //Still Level 0 Macro
}
int main()/*the one and only*/ {
microblaze_enable_interrupts();
xil_printf(“MB interrupts\t\t Enabled\r\n”);
Xuint32 status;
//Interr Init
status=XIntc_Initialize (&intc, XPAR_XPS_INTC_0_DEVICE_ID);
if (status != XST_SUCCESS){
xil_printf(“init INTC_0\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“init INTC_0\t\t OK \r\n”);
//Button Init Stuff
status=XGpio_Initialize (&buttons, XPAR_PUSH_BUTTONS_3BIT_DEVICE_ID);
if (status != XST_SUCCESS){
xil_printf(“init Buttons\t\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“init Buttons\t\t OK \r\n”);
XGpio_SetDataDirection(&buttons, 1, 0xFFFFFFFF);
xil_printf(“Buttons Direction\t Set\r\n”);
//Timer Init Stuff
status=XTmrCtr_Initialize (&timer, XPAR_XPS_TIMER_1_DEVICE_ID);
if (status != XST_SUCCESS){
xil_printf(“init Timer\t\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“init Timer\t\t OK \r\n”);
//buttons
status=XIntc_Connect (&intc, XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR,
&buttons_int_handler, (void *)0);
if (status != XST_SUCCESS){
xil_printf(“connect buttons\t\t Error \r\n”);
return XST_FAILURE;
}
else xil_printf(“connect buttons\t\t OK \r\n”);
//Timer Options
XTmrCtr_SetOptions(&timer, 0, //for timer #0 (there are 2 timers in the led_timer device, we’re only using one)
XTC_DOWN_COUNT_OPTION | // Count down to 0
XTC_INT_MODE_OPTION | // When it hits 0, cause an interrupt
XTC_AUTO_RELOAD_OPTION); // And reload the “reset” value and begin counting again
xil_printf(“Timer Setting\t\t Set\r\n”);
//Timer
status=XIntc_Connect (&intc, XPAR_XPS_INTC_0_XPS_TIMER_1_INTERRUPT_INTR, &timer_int_handler, (void*)0);
if (status != XST_SUCCESS){
xil_printf(“connect timer\t\t Error\r\n”);
return XST_FAILURE;
}
else xil_printf(“connect timer\t\t OK\r\n”);
XIntc_Enable (&intc, XPAR_PUSH_BUTTONS_3BIT_DEVICE_ID);
xil_printf(“Button interrupt\t Enabled\r\n”);
XIntc_Enable (&intc, XPAR_XPS_TIMER_1_DEVICE_ID);
xil_printf(“Timer interrupt\t\t Enabled\r\n”);
//Enable Xgpio Interrupt Stuff ans so on …
//XGpio_InterruptClear(buttons, XGPIO_IR_CH1_MASK);
xil_printf(“Buttons Interrupt\t NOT Cleared YET\r\n”);
XGpio_InterruptEnable (&buttons, XPAR_XPS_INTC_0_PUSH_BUTTONS_3BIT_IP2INTC_IRPT_INTR);
xil_printf(“XGpio interrupt\t\t Enabled\r\n”);
XGpio_InterruptGlobalEnable (&buttons);
xil_printf(“XGpio Global interrupt\t Enabled\r\n”);
status=XIntc_Start (&intc ,XIN_REAL_MODE);
if (status != XST_SUCCESS){
xil_printf(“start xintc\t\t Error\r\n”);
return XST_FAILURE;
}
else xil_printf(“start xintc\t\t OK\r\n”);
//Load Value 4 the Timer
XTmrCtr_SetResetValue(&timer, 0, 1000000000);
//Start the timer
XTmrCtr_Start (&timer,0);
xil_printf(“<—Entering WHILE(1);—>\r\n”);
while(1);
}