ZYNQ基础----双核硬中断(PL to PS)

PL端中断

  在上一篇博客中介绍了软中断,软中断可以用于ZYNQ的两个CPU之间进行中断,以此来进行两个CPU之间的通信,在ZYNQ的架构中,PL端也能够向PS端提供中断,PL端向PS端的中断一共有16个。
在这里插入图片描述

  可以看到PL端的中断,通过SPI连接到GIC上,在双核模式下使用PL端的中断时,需要对中断进行绑定。

搭建硬件系统

  为了快速上手,在搭建硬件系统时,设计一个定时器模块,该模块完成的功能就是每隔1s和2s向ZYNQ核提供一个PL端的中断。
  timer模块是产生PL端中断的模块,该模块是自行使用Vivado封装的一个模块,对应代码如下:
在这里插入图片描述

module timer(
	input	wire 			clk 		,
	input	wire 			rst_n		,
	output	wire 			pl_intr_0	,
	output	wire			pl_intr_1	
	);

//==========================================
//parameter define
//==========================================
parameter	ONE_SEC = 50000000;
parameter 	TWO_SEC	= ONE_SEC << 1;
parameter	ONE_US  = 500;

//==========================================
//internal signals
//==========================================
reg 	[31:0]		cnt_1s		;
wire 				add_cnt_1s	;
wire 				end_cnt_1s	;

reg 	[31:0]		cnt_2s		;
wire 				add_cnt_2s	;
wire 				end_cnt_2s	;

reg 				pl_intr_1_r	;
reg					pl_intr_0_r ;


assign pl_intr_0 = pl_intr_0_r;
assign pl_intr_1 = pl_intr_1_r;

//----------------cnt_1s------------------
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		cnt_1s <= 'd0;
	end
	else if (add_cnt_1s) begin
		if(end_cnt_1s)
			cnt_1s <= 'd0;
		else
			cnt_1s <= cnt_1s + 1'b1;
	end
	else begin
		cnt_1s <= 'd0;
	end
end

assign add_cnt_1s = 1;
assign end_cnt_1s = add_cnt_1s && cnt_1s == (ONE_SEC - 1);

//----------------cnt_2s------------------
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		cnt_2s <= 'd0;
	end
	else if (add_cnt_2s) begin
		if(end_cnt_2s)
			cnt_2s <= 'd0;
		else
			cnt_2s <= cnt_2s + 1'b1;
	end
	else begin
		cnt_2s <= 'd0;
	end
end

assign add_cnt_2s = 1;
assign end_cnt_2s = add_cnt_2s && cnt_2s == (TWO_SEC - 1);

//----------------pl_intr_0_r------------------
always @(posedge clk or negedge rst_n) begin
	if (rst_n==1'b0) begin
		pl_intr_0_r <= 1'b0;
	end
	else if (cnt_1s == (ONE_SEC - ONE_US - 1)) begin
		pl_intr_0_r <= 1'b1;
	end
	else if (end_cnt_1s) begin
		pl_intr_0_r <= 1'b0;
	end
end

//----------------pl_intr_1_r------------------
always @(posedge clk or negedge rst_n) begin
	if (rst_n==1'b0) begin
		pl_intr_1_r <= 1'b0;
	end
	else if (cnt_2s == (TWO_SEC - ONE_US - 1)) begin
		pl_intr_1_r <= 1'b1;
	end
	else if (end_cnt_2s) begin
		pl_intr_1_r <= 1'b0;
	end
end

endmodule

硬中断初始化流程

步骤函数
初始化异常处理系统Xil_ExceptionInit();
初始化中断控制器XScuGic_LookupConfig()
XScuGic_CfgInitialize()
注册异常回调函数Xil_ExceptionRegisterHandler()
将中断控制器与对应的中断ID相连接XScuGic_Connect()
设置中断类型和优先级XScuGic_SetPriTrigTypeByDistAddr()
硬中断映射到对应的CPUXScuGic_InterruptMaptoCpu()
使能中断控制器XScuGic_Enable()
使能异常处理系统Xil_ExceptionEnable()

程序设计

  程序设计十分简单,只需要在CPU0和CPU1接收到来自PL端的对应的中断时,就让其打印一下信息就行了。

CPU0应用程序

  在设置硬中断时,需要设置中断的类型和优先级,使用到的函数是XScuGic_SetPriTrigTypeByDistAddr(DIST_BASE_ADDR, CPU0_HW_INT_ID, 0x20, 0x03);
其中第一个参数是,中断设置的基地址,ZYNQ的中断设置都有一个基地址,对各个中断号的中断的响应,可以通过中断号来进行偏移,除此之外还需要设置中断的优先级,中断的优先级是以8为递增的,也就是中断的优先级有0x00,0x08,0x10,0x18等等,优先级最低的是0xF8;中断的类型根据中断的类型不同可以设置为不同类型的中断,其中私有中断(PPI)默认为上升沿触发,软中断(SFI),共享中断(SPI)可以设置为电平中断和边沿中断。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xscugic.h"
#include "sleep.h"

// OCM
#define OCM3_ADDR 		0xFFFF0000

#define GIC_DEV_ID		XPAR_PS7_SCUGIC_0_DEVICE_ID
#define DIST_BASE_ADDR	XPAR_PS7_SCUGIC_0_DIST_BASEADDR
//software interrupt ID is 0x00~0x0F
#define CPU0_SW_INT_ID	0x0D	//CPU0的软中断ID,用于中断CPU0
#define CPU1_SW_INT_ID	0x0E	//CPU1的软中断ID,用于中断CPU1
//PL 到 arm的中断
#define CPU0_HW_INT_ID	61		//CPU0的硬中断,1S计数器中断
#define CPU1_HW_INT_ID	62		//CPU1的硬中断,2S计数器中断

static XScuGic			gicInst;
static XScuGic_Config	* gicCfg_Ptr;

void hwIntrHandler(void * CallBackRef)
{
	printf("CPU0 is interrupted by HW\n");
}


int initGic()
{
	int status;
	//1. 初始化异常处理系统
	Xil_ExceptionInit();
	//2. 初始化中断控制器
	gicCfg_Ptr = XScuGic_LookupConfig(GIC_DEV_ID);
	status = XScuGic_CfgInitialize(&gicInst, gicCfg_Ptr, gicCfg_Ptr->CpuBaseAddress);
	if(status != XST_SUCCESS)
	{
		printf("initialize GIC failed\n");
		return XST_FAILURE;
	}
	//3. 注册异常回调函数
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &gicInst);
	//4. 连接GIC对应的硬中断ID
	status = XScuGic_Connect(&gicInst, CPU0_HW_INT_ID, (Xil_InterruptHandler)hwIntrHandler, &gicInst);
	if(status != XST_SUCCESS)
	{
		printf("Connect GIC failed\n");
		return XST_FAILURE;
	}
	XScuGic_SetPriTrigTypeByDistAddr(DIST_BASE_ADDR, CPU0_HW_INT_ID, 0x20, 0x03);
	//6. 将硬中断绑定到CPU0
	XScuGic_InterruptMaptoCpu(&gicInst, 0x00, CPU0_HW_INT_ID);
	//7. 使能硬中断
	XScuGic_Enable(&gicInst, CPU0_HW_INT_ID);
	//8. 使能异常处理系统
	Xil_ExceptionEnable();
	return status;
}

int main()
{
	//初始化中断控制器
	int status;
	status = initGic();
	if(status != XST_SUCCESS)
	{
		printf("initialize GIC failed\n");
		return XST_FAILURE;
	}

    while(1)
    {

    }
    return 0;
}

CPU1应用程序

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xscugic.h"
#include "sleep.h"

// on chip memory3 address
#define OCM3_ADDR 	0xFFFF0000

#define GIC_DEV_ID		XPAR_PS7_SCUGIC_0_DEVICE_ID
#define DIST_BASE_ADDR	XPAR_PS7_SCUGIC_0_DIST_BASEADDR
//software interrupt ID is 0x00~0x0F
#define CPU0_SW_INT_ID	0x0D	//CPU0的软中断ID,用于中断CPU0
#define CPU1_SW_INT_ID	0x0E	//CPU1的软中断ID,用于中断CPU1

#define CPU0_HW_INT_ID	61		//CPU0的硬中断,1S计数器中断
#define CPU1_HW_INT_ID	62		//CPU1的硬中断,2S计数器中断

static XScuGic			gicInst;
static XScuGic_Config	* gicCfg_Ptr;

void hwIntrHandler(void * CallBackRef)
{
	usleep(1000);
	printf("CPU1 is interrupted by HW\n");
}

int initGic()
{
	int status;
	//1. 初始化异常处理系统
	Xil_ExceptionInit();
	//2. 初始化中断控制器
	gicCfg_Ptr = XScuGic_LookupConfig(GIC_DEV_ID);
	status = XScuGic_CfgInitialize(&gicInst, gicCfg_Ptr, gicCfg_Ptr->CpuBaseAddress);
	if(status != XST_SUCCESS)
	{
		printf("initialize GIC failed\n");
		return XST_FAILURE;
	}
	//3. 注册异常回调函数,中断类型的异常
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &gicInst);
	//4. 连接GIC对应的硬中断ID
	status = XScuGic_Connect(&gicInst, CPU1_HW_INT_ID, (Xil_InterruptHandler)hwIntrHandler, &gicInst);
	if(status != XST_SUCCESS)
	{
		printf("Connect GIC failed\n");
		return XST_FAILURE;
	}
	//5. 设置硬中断优先级和中断类型
	XScuGic_SetPriTrigTypeByDistAddr(DIST_BASE_ADDR, CPU1_HW_INT_ID, 0x20, 0x03);
	//6. 将硬中断绑定到CPU0(双使用双核时,需要对硬中断进行一次映射)
	XScuGic_InterruptMaptoCpu(&gicInst, 0x01, CPU1_HW_INT_ID);
	//7. 使能硬中断
	XScuGic_Enable(&gicInst, CPU1_HW_INT_ID);
	//8. 使能异常处理系统
	Xil_ExceptionEnable();
	return status;
}

int main()
{
	//初始化中断控制器
	int status;
	status = initGic();
	if(status != XST_SUCCESS)
	{
		printf("initialize GIC failed\n");
		return XST_FAILURE;
	}
    while(1)
    {

	}
    return 0;
}

测试结果

从打印结果来看,PL端给到CPU0的中断是每隔1s产生一次中断,PL端给到CPU1的中断是每隔2S产生一次中断。所有可以看到,CPU0的每打印两次,CPU1打印一次。
在这里插入图片描述

  • 10
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: UG585-Zynq-7000-TRM是一份关于Xilinx Zynq-7000 SoC处理器的技术参考手册。Zynq-7000 SoC处理器是一款配备ARM Cortex-A9双核处理器和Xilinx可编程逻辑部分(PL)的可扩展平台,旨在为嵌入式系统开发者提供卓越的灵活性和可编程性。 TRM代表Technical Reference Manual(技术参考手册),其中包含了该处理器的体系结构和功能特性的详细描述,包括处理器内部的各种模块、外设、总线结构等等。该手册的主要目的是为开发者提供全面的指导和支持,从而加速其系统设计和开发应用,减少错误和风险。 UG585-Zynq-7000-TRM手册的内容包括Zynq-7000的基本特征、处理器件和软件架构、可编程逻辑PLPS之间的通信、外设接口和寄存器映射、中断控制等内容。开发者可以根据手册中的详细说明,了解Zynq-7000的构成和功能,从而基于此设计和实现自己的应用。 总之,UG585-Zynq-7000-TRM手册是一份非常重要的技术参考资料,为开发者提供全面的指导和支持,促进了Zynq-7000处理器的应用和拓展,也为未来的嵌入式系统设计提供了参考和借鉴。 ### 回答2: UG585是Xilinx公司发布的Zynq-7000系列技术手册,全称为“Zynq-7000 All Programmable SoC Technical Reference Manual”。Zynq-7000系列是Xilinx公司推出的一款功能强大的FPGA芯片,集成了双核ARM Cortex-A9处理器和可编程逻辑资源,支持高性能中间件、操作系统和外围设备的支持。该手册详细介绍了Zynq-7000系列SoC的架构、功能、性能、测试和验证、软件和件开发等方面的知识。他对于学习、使用和开发Zynq-7000 SoC具有非常重要的意义,使得开发人员能够深入了解这个芯片的细节,掌握它的特性和功能,以便更加高效地使用它进行开发。如果你想要学习和使用Zynq-7000 SoC,UG585是一个非常重要的参考文献,值得认真阅读和研究。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值