IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> ZYNQ AMP模式下CPU1响应外部中断 -> 正文阅读

[C++知识库]ZYNQ AMP模式下CPU1响应外部中断

首先,中断相关的讲解和底层原理,详见另外一篇博客

ZYNQ PL触发PS中断函数_wangjie36的博客-CSDN博客_pl到ps中断

硬件平台:

一,问题描述和原因分析

问题描述:在单独的CPU0或者CPU1中接收中断,中断服务程序响应正常;但使用AMP模式,CPU0能接收中断触发,能够正常响应外设中断;若用以同样的初始化方式在CPU1中触发,CPU1是收不到外部中断触发的。

?原因分析:当使用openAMP双核模式的时候,编译器选项中添加的是“-DUSE_AMP=1”这个参数,那么在源码中的预编译指令是用“USE_AMP”定义的,主要影响到CPU1对缓存的操作。CPU1对全局时钟的操作。当定义了USE_AMP等于1时,编译的时候都是直接返回,不对CPU1外部中断进行配置。“-DUSE_AMP=1”编译选项将影响到工程代码里的USE_AMP预编译指令,使得Cache操作函数、全局时钟以及中断控制器SCUGIC的初始化函数不被编译进CPU1的应用程序中,避免可能会出现的CPU0和CPU1Cache一致性维护异常和中断异常等问题。

二,解决CPU1响应中断的办法

1,CPU1无法响应中断,需要将指定的中断号map到对应的CPU,使用关键函数才能使中断生效:XScuGic_InterruptMaptoCpu(intc,SOFT_INTR_ID_TO_CPU1,UART_INT_IRQ_ID);

XScuGic_InterruptMaptoCpu函数的底层操作

void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
{
	u32 RegValue, Offset;
	RegValue = XScuGic_DistReadReg(InstancePtr,
			XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
 
	Offset = (Int_Id & 0x3U);
	Cpu_Id = (0x1U << Cpu_Id);//根据寄存器说明设置触发的CPU号
 
	RegValue = (RegValue & (~(0xFFU << (Offset*8U))) );
	RegValue |= ((Cpu_Id) << (Offset*8U));
 
	XScuGic_DistWriteReg(InstancePtr,
	  XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), RegValue);
//XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id)是通过中断号计算操作哪个ICDIPTR寄存器的
//公式宏定义
}

2,设置触发方式的时候,参数用寄存器地址触发,用XScGic_SetPrioityTriggerTypeByDistAddr函数能从cpu1触发。中断名称XScGic_SetPrioityTriggerType函数,有时候触发不到CPU1。

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

3,具体代码

(1),CPU0

#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)
    {
       sleep(1);
    }
    return 0;
}

(2),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)
    {
       sleep(1);
	}
    return 0;
}

三,解决固化时候的CPU1中断不响应

问题描述:按照第二步解决后,仿真器仿真时所有程序在线运行一切正常,CPU1能正常响应外部接收中断。但是,在制BOOT.BIN文件固化进去以后,在FSBL文件当中添加CPU1启动函数,此时发现固化的程序无法正常运行,使用打断点的方式发现CPU1的外部中断又不能触发了。

解决办法:在startcpu1之间加入?cpu0_intr_init(&IntrruptController);函数

#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0
#define CPU1STARTMEM 0x20000000
void StartCpu1(void)
{
    printf("Write the address of the application for CPU1 to 0xFFFFFFF0\r\n");
    Xil_Out32(CPU1STARTADR, CPU1STARTMEM);
    dmb();
    printf("Execute the SEV instruction to cause CPU1 to wake up\r\n");
    sev();
}
int main()
{
     Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
     cpu0_intr_init(&IntrruptController);
     StartCpu1();
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-04 15:19:49  更:2022-03-04 15:19:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:49:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码