前言
本期讲的是一个状态机以及中断相结合的应用,展示的试验功能较为简单,主要是实现PL与PS部分的状态交互。
1.状态机部分
首先是状态机实现的功能。初始处于idle状态(led_idle亮起)收到开始指令(start)后切换到状态a,并向ps端发出一条指令,使ps端产生中断并执行相应命令(这里是输出一句话)。ps端完成任务后,返回一条指令done,状态机收到done指令后切换到状态b,并点亮led灯。保持b状态直到检测到按下按键(key),熄灭led并切回idle状态。
状态机代码
module blog(
input clk,
input rst_n,
input key,
input start,
input done,
output reg print,
output reg led_done,
output reg led_idle
);
parameter idle=0,a=1,b=2;
reg [1:0] state,nstate;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
state<=idle;
else
state<=nstate;
end
always @(*)begin
case(state)
idle:begin
if(start)
nstate=a;
else
nstate=state;
end
a:begin
if(done)
nstate=b;
else
nstate=state;
end
b:begin
if(key)
nstate=idle;
else
nstate=state;
end
default:;
endcase
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
print<=1'b0;
led_done<=1'b0;
led_idle<=1'b0;
end
else if(state==idle)begin
print<=1'b0;
led_done<=1'b0;
led_idle<=1'b1;
end
else if(state==a)begin
print<=1'b1;
led_done<=1'b0;
led_idle<=1'b0;
end
else if(state==b)begin
print<=1'b0;
led_done<=1'b1;
led_idle<=1'b0;
end
else begin
print<=1'b0;
led_done<=1'b0;
led_idle<=1'b0;
end
end
endmodule
block design设计
bd内添加zynq后如图添加中断及emio接口
在bd内右击空白处可以将编写的状态机设计文件作为模块添加进来
如图进行连线
约束文件
set_property IOSTANDARD LVCMOS33 [get_ports key]
set_property IOSTANDARD LVCMOS33 [get_ports start]
set_property IOSTANDARD LVCMOS33 [get_ports led_done]
set_property IOSTANDARD LVCMOS33 [get_ports led_idle]
set_property PACKAGE_PIN N15 [get_ports key]
set_property PACKAGE_PIN R18 [get_ports start]
set_property PACKAGE_PIN T22 [get_ports led_done]
set_property PACKAGE_PIN T21 [get_ports led_idle]
2.vitis部分
代码
#include "stdio.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xil_printf.h"
#define GPIOPS_ID XPAR_XGPIOPS_0_DEVICE_ID //PS端 GPIO器件 ID
#define SCUGIC_ID XPAR_SCUGIC_0_DEVICE_ID //中断控制器 ID
#define intr_id 61 //中断号
#define print_done 54 //将print_done信号连接到EMIO0
XGpioPs gpiops_inst; //PS端 GPIO 驱动实例
XGpioPs_Config *gpiops_cfg_ptr; //PS端 GPIO 配置信息
XScuGic scugic_inst; //中断控制器 驱动实例
XScuGic_Config * scugic_cfg_ptr; //中断控制器 配置信息
void print_handler(void *CallbackRef); //中断服务函数
int main()
{
//根据器件ID查找配置信息
gpiops_cfg_ptr = XGpioPs_LookupConfig(GPIOPS_ID);
scugic_cfg_ptr = XScuGic_LookupConfig(SCUGIC_ID);
//初始化器件驱动
XGpioPs_CfgInitialize(&gpiops_inst, gpiops_cfg_ptr, gpiops_cfg_ptr->BaseAddr);
XScuGic_CfgInitialize(&scugic_inst, scugic_cfg_ptr, scugic_cfg_ptr->CpuBaseAddress);
//设置print_done为输出
XGpioPs_SetDirectionPin(&gpiops_inst, print_done, 1);
//使能输出
XGpioPs_SetOutputEnablePin(&gpiops_inst, print_done, 1);
//设置中断优先级和触发类型(高电平触发)
XScuGic_SetPriorityTriggerType(&scugic_inst, intr_id, 0xA0, 0x1);
//关联中断ID和中断处理函数
XScuGic_Connect(&scugic_inst, intr_id, print_handler,(void *) intr_id);
//使能AXI GPIO中断
XScuGic_Enable(&scugic_inst, intr_id);
//设置并打开中断异常处理功能
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler, &scugic_inst);
Xil_ExceptionEnable();
return 0;
}
//中断服务(处理)函数
void print_handler(void *CallbackRef)
{
printf("print done!\n");
XGpioPs_WritePin(&gpiops_inst, print_done,1);//中断完成后,将print_done信号拉高,使状态机切换状态
}
上板验证
烧录好程序后,LD1会亮起,表示此刻处于idle状态
按下BTNR按键后(对应状态机内start命令),ps端会产生一个中断并在右下角terminal内输出一句话“print done!”,然后LD0亮起,表示此刻切换到了状态b,按下BTNL按键后(对应key命令),LD0熄灭,LD1亮起,即又切换回到IDLE状态