0,前言
使用定时器实现中断。这里通过PS端的EMIO进行使用计数器,然后再定时产生中断。本来听得很头疼,后来自己想了想,画了个图,再结合前面讲的,就觉得清楚了很多。这里分享下这张图。
1,代码分析
这里的FPGA代码很简单,C代码由于之前已经都学过了,这里只是将两个模块的函数简单修改即可。这里只贴代码。
在这之前先总结一个问题。就是我在使能EMIO的时候,只要了一个GPIO口。前面介绍过有0-53个MIO,因此EMIO是从54开始的。但是当我将55这个编号作为使能信号时,时钟信号却总是不能拉低。而将其值修改为54的时候,就可以很好地使能了。因此这里的EMIO使用是有他的顺序的。
其次就是在定义status的时候。发现有两个地址。因此返回值总是错误的。代码原本是我在main函数中定义了一个status,在初始化GPIO的时候又定义了一次。于是就出现了上述返回错误的问题。因此在代码中,我将其定义在函数之外,不在任何一个函数中定义这个变量,问题就被解决了。
代码分享
Verilog代码
module interrupt_10_50ms(
input sclk,
input rst,
output intr10ms,
output intr50ms
);
parameter INTR10MS_END = 24'd1999999;
parameter INTR50MS_END = 24'd9999999;
parameter PULER_W = 8'd199;
reg intr10ms_flag,intr50ms_flag;
reg [31:0] intr10ms_cnt;
reg [31:0] intr50ms_cnt;
assign intr10ms = intr10ms_flag;
assign intr50ms = intr50ms_flag;
always @ (posedge sclk)begin
if(rst == 1'b1) begin
intr10ms_cnt <= 'd0;
end
else if(intr10ms_cnt == INTR10MS_END)begin
intr10ms_cnt <= 'd0;
end
else begin
intr10ms_cnt <= intr10ms_cnt + 1'b1;
end
end
always @ (posedge sclk)begin
if(rst == 1'b1) begin
intr50ms_cnt <= 'd0;
end
else if(intr50ms_cnt == INTR50MS_END)begin
intr50ms_cnt <= 'd0;
end
else begin
intr50ms_cnt <= intr50ms_cnt + 1'b1;
end
end
always @ (posedge sclk)
begin
if(rst == 1'b1 )
intr10ms_flag <= 1'b0;
else
if(intr10ms_cnt == PULER_W)
intr10ms_flag <= 1'b0;
else
if(intr10ms_cnt == INTR10MS_END)
intr10ms_flag <= 1'b1;
else
intr10ms_flag <= intr10ms_flag;
end
always @ (posedge sclk)
begin
if(rst == 1'b1 )
intr50ms_flag <= 1'b0;
else
if(intr50ms_cnt == PULER_W)
intr50ms_flag <= 1'b0;
else
if(intr50ms_cnt == INTR50MS_END)
intr50ms_flag <= 1'b1;
else
intr50ms_flag <= intr50ms_flag;
end
endmodule
C代码。代码虽然有点长,但是原理很清楚。就是
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpiops.h" //import gpio
#include "xparameters.h"
#include "xscugic.h"
#define GPIO_DEV_ID XPAR_PS7_GPIO_0_DEVICE_ID //redefine device id
#define GIC_ID XPAR_PS7_SCUGIC_0_DEVICE_ID //redefine GIC id
#define F2P_INTR0_ID 61
#define GPIO0 54
XGpioPs GpioPs;//实例化一个对象,将对其进行配置
XGpioPs_Config *GpioPsCfgPtr;
static XScuGic ScuGic;
static XScuGic_Config * ScuGicCfgPtr;
int status;
void f2pIntr0Handler(void * callbackref);
int initGpio();
int initHwIntr();
int main()
{
initGpio();//initial GPIO
if(status != XST_SUCCESS){
return status ;
}
initHwIntr();
if(status != XST_SUCCESS){
return status ;
}
XGpioPs_WritePin(&GpioPs,GPIO0,(u32)0x01);
while(1){
}
}
//initial gpio
int initGpio(){
GpioPsCfgPtr = XGpioPs_LookupConfig(GPIO_DEV_ID);
status = XGpioPs_CfgInitialize(&GpioPs,GpioPsCfgPtr,GpioPsCfgPtr->BaseAddr);
if(status != XST_SUCCESS){
return status ;
}
XGpioPs_SetDirectionPin(&GpioPs,GPIO0,0x01);
XGpioPs_SetOutputEnablePin(&GpioPs,GPIO0,0x01);
return status;
}
//hw callback function id = 61
void f2pIntr0Handler(void * callbackref){
printf("interrupt id = 61 success!\n\r");
}
//initial gic & hardware intr
int initHwIntr(){
Xil_ExceptionInit();//打开系统异常
ScuGicCfgPtr = XScuGic_LookupConfig(GIC_ID);
status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
if(status != XST_SUCCESS){
return status ;
}
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
status = XScuGic_Connect(&ScuGic,F2P_INTR0_ID,(Xil_ExceptionHandler)f2pIntr0Handler,&ScuGic);
if(status != XST_SUCCESS){
return status ;
}
XScuGic_Enable(&ScuGic,F2P_INTR0_ID);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
打印的结果是正确的。有时候可能会遇见一些莫名其妙的问题。不要着急,关掉再打开试试有可能问题就解决了!!!