ZYNQ有两个CPU?(三)——SGI异步通信

ZYNQ有两个CPU三)——SGI异步通信

这篇文章的SGI测试方案是这样的:由CPU0绑定软件中断0的中断服务函数让CPU1来触发该中断,CPU0的main函数中会一直等待软件中断0被触发,触发后CPU0将触发软件中断1;而软件中断1的中断服务函数由CPU1绑定,CPU1在触发软件中断0后会一直等待自己的软件中断1被触发才会再次触发软件中断0。两个CPU在各自的main函数里采用乒乓的方式相互触发对方的软件中断并在串口输出调试信息。

在UG585第七章中断章节的阅读中,自然想到符合我要求的中断源就是SGI(软件生成中断),ZYNQ中的三大类中断SGI、SPI、PPI请查阅UG585。而SGI的中断 一共16个占据了ZYNQ本身96个中断 的0~15,中断产生的方式是往ICDSGIR(软件中断触发寄存器)写中断 和触发目标CPU来产生。可以中断自己,或其他CPU。ICDSGIR寄存器在UG585的附录B寄存器详情中有详细说明,而SGI测试程序的编写过程中会在第七章和附录B中来回查找相关信息。其中需要注意ICDSGIR寄存器的地址(绝对地址)软件名称(GIC_SFI_TRIG)。

根据我查询到的信息应该不需要重新建立Vivado下的HW_Platform,所以就在SDK中开始写代码了。按照流程实例化中断控制器了,写到Connect中断服务函数时就有点犯难了,因为最后一个参数是回调函数的设备实例,而SGI本身不是设备产生的中断,思索很久以后猜测是0,但是为了证实自己的想法在 上做了查询。明确讲到SGI应用的有三篇:

米联科技的SGI应用实例

S03_CH13_ZYNQ A9 TCP UART双核AMP例程

另外就是Xilinx官 上搜出来的大神写的《亚当.泰勒玩转Microzed》系列中有SGI的应用及对应的中文翻译博客,人家写了188篇啊!顿时有了高山仰止的膜拜感,赶紧查查搜藏一下:

Search – Community Forums

结果前面的搜索结果让我有点失望,米联的博客只是列出了工程项目的基本结构和步骤。我感兴趣的SGI如何设置和触发的并没有详细写出只交代了用哪几个自定义函数来实现这个功能。而大神的博客变成了《九阴真经》残本,关于AMP的三篇博客偏偏SGI的没有了,你们合伙坑我是不是/p>

回过头只能利用现有的资料进行探索了。首先根据UG585 查询到的根据关键字查到了和SGI相关的寄存器在xparameters.h中的定义,比如GIC定义的信息如下:

对应的API函数也查询了一下System.mss中的documentation

得到的结果我感兴趣的函数有几个:

读完这几个函数自己心里大概知道应该怎么做了:

1.初始化GIC中断控制器;

2.绑定中断服务函数;

3设置中断优先级和触发方式;(这条在我最初的设想中是不存在的)

4.绑定触发中断的CPU

5.允许中断

6.触发软件中断;(我在这里犯了第二个错误)

由于程序比较简单,三下五除二整吧整吧就开始debug了,结果不对,没有任何一个中断产生。这下有点懵逼了。逼得我回过头仔细看了第七章,发现了第一个错误,也就是我的第三步设置中断的触发方式,因为在UG585上是这么说的,所有的SGI均为边沿触发:

所以我加上了第三步设置中断优先级和触发方式的函数,但还是没有效果。这个坑有点深啊!

没办法继续找错误。看了一下第四步的函数操作的寄存器ICDIPTR[0:3],ICDIPTR寄存器一共有24个,每个寄存器管理4个中断一共96个中断用24个寄存器管理,用来标定每一个中断源用来中断哪个CPU。我用到的软件中断0和1,所以看了ICDIPTR[0]:

XScuGic_InterruptMaptoCpu函数的底层操作是这样的:


RegValue = (RegValue & (~(0xFFU << (Offset8U))) );
RegValue |= ((Cpu_Id) << (Offset8U));

//XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id)是通过中断 计算操作哪个ICDIPTR寄存器的
//公式宏定义
}

检查之后我确定在这里没有犯错误但效果依然是没有触发中断,而看完这个函数以后我觉得完全可以甩开BSP的API函数自己操作这些寄存器,简单粗暴原始的操作才是王道,因此我也就没检查第五和第六步了。直接写了自己的软件中断触发函数,根据是UG585上ICDSGIR寄存器的说明:

翻译一下:

第26到第31位保留也就是没用。

第16到23位共8位为目标CPU列表,对应的每一位代表一个CPU因此对应位设置为1则中断会触发对应的CPU(目标列表过滤设置必须设置为00才能让本列表有效)。

第15位安全设置默认为0。

第4到第14位必须设置为0。

第0到第3位是中断ID正好对应0~15的软件中断 。

根据这个说明我自己写了个暴力触发软件中断的函数:

* Assert the arguments
*/
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Xil_AssertNonvoid(Int_Id <= 15U) ;
Xil_AssertNonvoid(Cpu_Id <= 255U) ;

* The Int_Id is used to create the appropriate mask for the
* desired interrupt. Int_Id currently limited to 0 – 15
* Use the target list for the Cpu ID.
*/
Mask = ((Cpu_Id << 16U) | Int_Id) &//天杀的问题就出在这里
(XSCUGIC_SFI_TRIG_CPU_MASK | XSCUGIC_SFI_TRIG_INTID_MASK);

* Write to the Software interrupt trigger register. Use the appropriate
* CPU Int_Id.
*/
XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SFI_TRIG_OFFSET, Mask);

}

SDK的文档里并没有说明Cpu_Id的参数格式是怎么样的,而看了这里才知道我按照自己的理解填0或者1作为CPU的编 肯定不能得到正确的结果了。根据这个函数的操作,ICDSGIR寄存器的目标列表过滤被设置为00,需要从目标CPU列表中选择,而函数直接把我填入的Cpu_Id左移16位到第16到23位上,也就是说SDK希望我直接填入8位的目标CPU列表而不是从0开始编 的Cpu_Id,但在文档中根本没有说明,让我在坑里头转悠了好久。下面把我测试项目的所有代码贴出来:

CPU0的主函数ZYNQ_AMP_CPU0_SGI.c

}

void SGI0_INTR_ID_ISR (void)
{
xil_printf(“CPU0: The software interrupt0 has been triggerednr);
SGI_trigered=1;
}

CPU1的主函数ZYNQ_AMP_CPU1_SGI.c

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年6月1日
下一篇 2021年6月1日

相关推荐