ZYNQ ARM软中断具体实现步骤

本文只记录如何实现两个核之间简单的软中断,之后如果更深入在做详细更新

目录

1、创建FSBL

2、创建第一个核  APP_CORE0

3、创建第二个核  APP_CORE2


1、创建FSBL

        首先需要创建一个FSBL(First Stage Boot Loader 负责PS的初始化核PL的加载)用于加载核0和核1,修改main.c,在main函数前加入下面的代码,参考ug585-Zynq-7000-TRM

#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0
#define CPU1STARTMEM 0x2000000
void StartCpu1(void)
{
    #if 1
    fsbl_printf(DEBUG_GENERAL,"FSBL: Write the address of the application for CPU 1 to 0xFFFFFFF0\n\r");
    Xil_Out32(CPU1STARTADR, CPU1STARTMEM);
    dmb(); //waits until write has finished
    fsbl_printf(DEBUG_GENERAL,"FSBL: Execute the SEV instruction to cause CPU 1 to wake up and jump to the application\n\r");
    sev();
    #endif
}

 在mian.c中load boot image之后执行StartCpu1()函数;

2、创建第一个核  APP_CORE0

        注意processor选择后缀为0的核,之后选择helloworld模板

        修改core0的代码空间,在Iscript.Id中,点source到修改界面

        将helloworld.c改为main.c,在main.c中有一个宏定义变量COMM_VAL,程序通过此变量访问OCM(on chip memory)完成共享内存的访问,下图是具体的地址范围,下方使用的OCM3

         将main.c中的代码替换以下代码,其中 GIC_ID 是中断id在xparameters.h中可以找到,CPU0_SW_INTR 和 CPU1_SW_INTR 是核0的软中断id,具体id是可选的在下方图片中,Xil_SetTlbAttributes函数小弟还不是很明白,求大佬解答后面两个参数是什么意思

#include <stdio.h>
//#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xscugic.h"
// will data point share ram ocm3
#define COMM_VAL (*(volatile unsigned long*)(0xFFFF0000))
#define GIC_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define CPU0_SW_INTR 0x0d
#define CPU1_SW_INTR 0x0e

static XScuGic ScuGic;
static XScuGic_Config *ScuGicCfgPtr;

int InitSWIntr();
void cup0intrHandler(void *CallBackRef);

int main()
{
	COMM_VAL = 0;
    // cup0 -> cache -> ram <- cup1
	// disable onchip memory cache
	Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
	int status;
	status = InitSWIntr();
	if(status != XST_SUCCESS){
		return status;
	}
	while(1){
		printf("Hello world cpu0!\n\r");
		XScuGic_SoftwareIntr(&ScuGic,CPU1_SW_INTR,XSCUGIC_SPI_CPU1_MASK);
		COMM_VAL = 1;
		while(COMM_VAL == 1){

		}
	}
    return 0;
}

        之后就是中断的配置,在connect连接的时候因为软中断是直接到控制器的,不像gpio需要先到共享中断在调用自己写的函数,所有在connect直接写自己的中断触发函数就可以了

int InitSWIntr(){
	int status;
    // 初始化异常
	Xil_ExceptionInit();
    // 寻找中断
	ScuGicCfgPtr = XScuGic_LookupConfig(GIC_ID);
    // 初始化中断
	status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
	if(status != XST_SUCCESS){
		return status;
	}
    // 注册异常处理然后回调到cpu
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
    // 连接软中断并注册软中断函数
	status = XScuGic_Connect(&ScuGic,CPU0_SW_INTR,(Xil_InterruptHandler)cup0intrHandler,&ScuGic);
    // 使能中断控制器
	XScuGic_Enable(&ScuGic,CPU0_SW_INTR);
	if(status != XST_SUCCESS){
		return status;
	}
    // 使能异常
	Xil_ExceptionEnable();
	return XST_SUCCESS;
}

3、创建第二个核  APP_CORE2

        第二个核和一个核操作基本一样只需修改少许就可以让程序跑起来了,在创建的时候选择核1

        首先需要修改的是地址空间

然后将mian.c替换为下方代码,其实修改的不多,自己看吧,之后就可以debug了

include <stdio.h>
//#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xscugic.h"
// will data point share ram ocm3
#define COMM_VAL (*(volatile unsigned long*)(0xFFFF0000))
#define GIC_ID XPAR_PS7_SCUGIC_0_DEVICE_ID
#define CPU0_SW_INTR 0x0d
#define CPU1_SW_INTR 0x0e

static XScuGic ScuGic;
static XScuGic_Config *ScuGicCfgPtr;

int InitSWIntr();
void cup1intrHandler(void *CallBackRef);

int main()
{
	COMM_VAL = 0;
    // cup0 -> cache -> ram <- cup1
	// disable onchip memory cache
	Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
	int status;
	status = InitSWIntr();
	if(status != XST_SUCCESS){
		return status;
	}
	while(1){
		printf("Hello world cpu1!\n\r");
		XScuGic_SoftwareIntr(&ScuGic,CPU0_SW_INTR,XSCUGIC_SPI_CPU0_MASK);
		COMM_VAL = 0;
		while(COMM_VAL == 0){

		}
	}
    return 0;
}

int InitSWIntr(){
	int status;
	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,CPU1_SW_INTR,(Xil_InterruptHandler)cup1intrHandler,&ScuGic);
	XScuGic_Enable(&ScuGic,CPU1_SW_INTR);
	if(status != XST_SUCCESS){
		return status;
	}
	Xil_ExceptionEnable();
	return XST_SUCCESS;
}

void cup1intrHandler(void *CallBackRef){
	printf("cpu0 interrupt cpu1!!\n\r");
}

 

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Zynq ARM是一款基于Xilinx Zynq系统芯片的ARM处理器。要控制LED,首先需要连接LED到Zynq ARM芯片上的GPIO(通用输入输出)引脚。然后,通过对GPIO寄存器进行编程,可以控制GPIO引脚的电平状态,从而控制LED的亮灭。 对于Zynq ARM芯片上的GPIO控制,可以使用Linux操作系统和相应的GPIO驱动程序来实现。在Linux中,GPIO控制的接口通常被映射到/dev/gpio目录下的文件,我们可以通过读写这些文件来控制GPIO引脚。 首先,需要确定LED连接到Zynq ARM芯片的哪个GPIO引脚上。然后,在Linux中使用命令行或者编写程序来设置该GPIO引脚为输出模式。 例如,如果LED连接到Zynq ARM芯片的GPIO0引脚上,可以使用以下命令在命令行中设置该引脚为输出模式: echo out > /sys/class/gpio/gpio0/direction 然后,可以使用以下命令将GPIO0引脚的电平设置为高或低,从而控制LED的亮灭: echo 1 > /sys/class/gpio/gpio0/value # 设置引脚电平为高,LED亮起 echo 0 > /sys/class/gpio/gpio0/value # 设置引脚电平为低,LED熄灭 如果希望通过编写程序来控制LED,可以使用C语言或Python等语言,通过打开/dev/gpio目录下相应的文件,然后读写文件来控制GPIO引脚电平。 总结起来,要实现Zynq ARM控制LED,需要确定LED连接的GPIO引脚,然后通过GPIO控制接口,设置引脚为输出模式,并通过读写相关文件或者编写程序,控制GPIO引脚电平,从而控制LED的亮灭。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值