按照alinx的学习教程,学习了hello world,接着就是学习RTC中断了。
教程中介绍了MPSOC的各种中断基本概念,我就挑着总结了:
RTC介绍
Zynq Ultrascale+ MPSOC的RTC可以由VCC-PSBATT供电,只需要一个纽扣电池,板子断电后,它还可以继续计时。

中断介绍
Zynq Ultrascale+ MPSOC含有APU和RPU,也是就A53和R5。各自有个中断控制器,A53对应的是GICv2、R5对应的是GICv1。

RPU的中断控制器

图中可以看到有三种中断源:
PPI:私有外设中断,只能对固定的core有效;
SPI:共享外设中断,可不是flash那个spi哈,我第一眼看到就整混了;
SGI:软件中断,用于软件主动产生中断;
然后就是介绍一堆寄存器,具体去参考ug1085吧。
APU的中断控制器

GICv2将中断分成了两个组,group0和group1,其中:
group0是安全中断,由nFIQ驱动;
group1是非安全中断,由nIRQ驱动;
中断号分配如下:

然后就是描述什么中断优先级、分组什么的,好特么烧脑,先不管了。直接跟着后面学,用到再说。
Vitis工程搭建
吸取之前的教训,我们基于之前的vivado工程生成的xsa文件,重新建一个vitis工程文件夹,Launch Vitis IDE后,我们这次不建APP工程,先只建立一个hardware平台:

选择vivado工程导出的xsa文件,然后建立好后就只有platform工程:

然后直接找RTC的例子工程:


选择其中的周期中断例子,点击OK就导入了:

哎哟,不错哦,直接就有现成的工程:

然后直接build这个例子工程。
下载调试
接上下载器和串口线,直接右键Run As试试,发现成功运行起来了:

这就完了?感觉没学会啊,不行,我得看看example代码。
运行完程序回头学习
首先看main函数里面,直接调用了RtcPsuPeriodicAlarmIntrExample,传递了中断控制器实体、RTC实体、RTC设备ID、RTC中断ID参数;
跟踪RTC_ALARM_INT_IRQ_ID可以查到,这玩意儿在xparameters_ps.h中定义的,值是:26+32
为毛是这个值呢?我从ug1085找到RTC的框图:

发现Alarm中断号确实就是58,哎,不管了,xilinx把这些编号都写在了xparameters_ps.h文件中,以后找define名字就行,别纠结具体编号了。
然后进入example函数中,发现有以下步骤:
Config = XRtcPsu_LookupConfig(DeviceId);
Status = XRtcPsu_CfgInitialize(RtcInstPtr, Config, Config->BaseAddr);
这两步就是去初始化RTC,设置基地址什么的。
然后还做了一个自测试:
Status = XRtcPsu_SelfTest(RtcInstPtr);
大概就是去读写了一些RTC的一个寄存器,看OK不OK。
然后就是打印了:
xil_printf("\n\rDay Convention : 0-Fri, 1-Sat, 2-Sun, 3-Mon, 4-Tue, 5-Wed, 6-Thur\n\r");
xil_printf("Current RTC time is..\n\r");
CurrentTime = XRtcPsu_GetCurrentTime(RtcInstPtr);
XRtcPsu_SecToDateTime(CurrentTime,&dt0);
xil_printf("YEAR:MM:DD HR:MM:SS \t %04d:%02d:%02d %02d:%02d:%02d\t Day = %d\n\r",dt0.Year,dt0.Month,dt0.Day,dt0.Hour,dt0.Min,dt0.Sec,dt0.WeekDay);
去RTC取CurrentTime,然后赋值到dt0,再打印出来;
对应这段打印:

接着就是去设置中断系统,再设置RTC的中断回调函数:
Status = SetupInterruptSystem(IntcInstPtr, RtcInstPtr, RtcIntrId);
XRtcPsu_SetHandler(RtcInstPtr, (XRtcPsu_Handler)Handler, RtcInstPtr);
然后就是去获取时间、设置alarm值、等待计数到10超时;
本来到这里基本就学习完毕了;
但是我发现了xilinx的一个bug,我从打印看,每次2s左右打印两行;
这不科学啊,不是应该1s打印一次,10s超时吗?
经过排查,发现应该是进中断后,未清除中断,导致重复进入中断了,修改代码后,发现打印正常了:

void Handler(void *CallBackRef, u32 Event)
{
XRtcPsu *RtcInstPtr = (XRtcPsu *)CallBackRef;
/* Alarm event */
if (Event == XRTCPSU_EVENT_ALARM_GEN) {
PeriodicAlarms++;
xil_printf("%dSec Periodic Alarm generated.\n\r",PeriodicAlarms);
}
XRtcPsu_SetInterruptMask(RtcInstPtr, XRTC_INT_EN_ALRM_MASK );
}

看来xilinx也特么的不严谨 !!!
342



被折叠的 条评论
为什么被折叠?



