软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! 8.1 概述本课将中断对于实时系统是非常重要。本课简要介绍了ZYNQ的中断原理和中断类型,详细介绍了私有定时器,在ZYNQ的纯PS里实现私有定时器中断。每隔一秒钟中断一次,在中断函数里计数加1,通过串口打印输出。 8.2 中断原理 中断对于保证任务的实时性非常必要,ZYNQ中集成了中断控制器GIC(Generic Interrupt Controller).GIC可以接受I/O外设中断IOP和PL中断,将这些中断发给CPU。 8.2.1 软件中断(SGI)SGI通过写ICDSGIR寄存器产生SGI. 8.2.2 共享中断SPI通过PS和PL内各种I/O和存储器控制器产生。 8.2.3 私有中断(PPI) 包含:全局定时器,私有看门狗定时器,私有定时器以及来自PL的FIQ/IRQ。本文主要介绍PPI,其它的请参考官方手册ug585_Zynq_7000_TRM.pdf。 8.2.4 私有定时器 ZYNQ每个ARM core都有自己的私有定时器,私有定时器的工作频率为CPU的一半。ARM工作频率为666MHZ,则私有定时器的频率为333MHz. 8.3 搭建FPGA BD工程Step1:新建一个名为为Miz_sys的工程。 Step2:创建一个BD文件,并命名为system,添加并且配置好ZYNQ IP。读者需要根据自己的硬件类型配置好输入时钟频率、内存型号、串口,连接时钟等。新手不清楚这些内容个,请参考“CH01 HelloWold/DDR/网口测试及固化”这一节课。 Step5:单击窗口上的运行按钮,运行程序。 8.6 实验结果系统运行结果如下图所示: 8.7 程序分析本节课封装了sys_intr中断函数,以及timer_intr中断函数,其中,sys_intr负责控制整个中断的启动,而timer_intr函数负责管理timer中断。 8.7.1 timer_intr.c
8.7.1.1 Timer_init 函数int Timer_init(XScuTimer *TimerPtr,u32 Load_Value,u32 DeviceId)函数负责初始化Timer 下面对Timer_init中的函数做一些介绍,同时也是对如何分析XILINX 库函数做一些介绍: 1、ScuTimer_LookupConfig函数分析: ScuTimer_LookupConfig(DeviceId)负责查看parameters.h里面是否有关于Timer的资源分配 ScuTimer_LookupConfig函数的定义如下 在parameters.h可以看到XscuTimer_ConfigTable的定义如下,包括了外设的ID号、基地址、DIST基地址,只要我们在FPGA硬件电路上添加了定时器,那这些参数就会自动被添加,定时器的参数也将会自动生成。 因此当调用ScuTimer_LookupConfig会对TMRConfigPtr初始化,TMRConfigPtr。 2、XScuTimer_CfgInitialize函数分析: XScuTimer_CfgInitialize(TimerPtr, TMRConfigPtr,TMRConfigPtr->BaseAddr);负责初始化Timer对象。 函数定义如下: Xil_AssertNonvoid(InstancePtr= !NULL)和Xil_AssertNonvoid(ConfigPtr= !NULL)用来检测传递进来的参数是否是空的,如果是,则不能正常跳转到下一个语句。 接下来的一句是检测定时器是否已经初始化,如果没有,就跳到if中的语句里面。否则,返回一个已经初始化了的标志。接下来我们看到if语句里面的程序。 程序把配置指针中的设备id拷贝进入了定时器的实例结构中的DeviceId。接着把程序的最后一个参数EffectiveAddress(这个就是定时器的基地址)也传递到了定时器的实例结构中的BaseAddr,紧接着把实例结构里的IsStarted标志置为0,再之后把实例结构中的IsReady标志置为XIL_COMPONENT_IS_READY。最后再给Status变量赋值为XST_SUCCUSS。可以看出来,定时器的一系列的初始化都是围绕着这个实例结构来的。那么,我们就来看看这个实例结构到底是什么?我们在主函数中找到这个实例结构。 static XScuTimer Timer;//timer 在这里,这个实例结构是指向一个结构体的,查看这个结构体的内容。 可以看到,这个结构体中又包含了一个结构体,我们再继续查看它包含的这个结构体。 3、XScuTimer_LoadTimer函数 XScuTimer_LoadTimer(TimerPtr, Load_Value);加载定时器的初值 本课程将程序的定时时间设置为了1秒。那么,系统是如何做到定时一秒的呢?定时器时间可以通过下式计算:定时时间 = 1/定时器频率*(预加载值+1),则可以推算出:预加载值=定时时间*定时器频率-1。定时时间是已知的,如果再知道定时器频率则可以计算出加载的值,查看xilinx的编程指导手册ug585-zynq-7000-TRM的定时器篇得知: 定时器频率为处理器频率的一半,比如Miz702的ARM工作频率为666MHZ,则私有定时器的频率为333MHz,则加载值为1*333_000_000*(1/s)-1=0x13D92D3F。 回到main函数的分析,当我们把鼠标停留在装载加载值函数XScuTimer_LoadTimer上时,SDK会显示关于这个函数的一些信息。 我们看到这个函数的原函数是向一个寄存器地址中写入了预加载值,我们计算一下这个寄存器地址。原函数的第一个参数我们刚才提到过,就是那个实例结构中的基地址,也就是定时器的基地址。我们在xparameters.h中找到它。 此时我们就可以计算了:F8F00600+00=F8F00600。在ug585中查找一下这个寄存器地址,看看这个寄存器是干什么用的。 4、XScuTimer_EnableAutoReload函数 XScuTimer_EnableAutoReload(TimerPtr);使能定时器的重载功能 这段程序与上一句差不多一致,我们通过分析寄存器,看看这段程序完成的功能。这段程序的寄存器地址为:F8F00600+08=F8F00608。这段程序写入的数据为:(F8F00600+08)|0x00000002=F8F0060A。查找ug585看看寄存器的功能。 这个寄存器是把中断的预加载值设置为了自动装载模式(也就是中断一次过后,系统又会自动的装入初值,不用人工载入初值),也就是图中用方框圈出的部分。 8.7.1.2 Timer_Setup_Intr_System函数void Timer_Setup_Intr_System(XScuGic *GicInstancePtr,XScuTimer *TimerInstancePtr, u16 TimerIntrId);负责初始化定时器中断,这个函数带了三个参数:第一个参数指向了中断控制器,第二个指向的是定时器,第三个是中断号。将鼠标放在中断号上面时,我们可以发现中断号为29。我们可以在ug585的中断部分查看一下中断号29是什么类型的中断。 可以看到这是定时器中断,上升沿触发的。这样定义是有一定依据的。这段程序与上一课PL_PS中断是差不多的,我们上一课对其进行过详细的分析,大家可参照上一课介绍的方法对其进行分析。 8.7.1.3 Timer_start函数void Timer_start(XScuTimer *TimerPtr) 用来启动定时器,在Timer_start中调用了XScuTimer_Start(TimerPtr) 可以看出来,这也是一个通过读写寄存器的方式来操作定时器的过程,我们依然是来分析一下寄存器。 之前的一些初始化程序就跳过不再讲解了,直接看到上图所示的程序,这个程序的分析与我们刚才讲的装载初值的方法是一样的,这里我们可以直接计算此程序读出的寄存器地址:F8F00600+08=F8F00608。 这一句的意思就是把刚才得到的寄存器的地址与0x00000001或操作。此时寄存器地址为:F8F00608 | 0x00000001U =F8F00609。 这里我们发现,上图中这个函数的源程序中,第一个参数即为我们第一次得到的寄存器地址,写入的数据为第二次得到的寄存器地址。也就是说向F8F00608这个寄存器里写入数据F8F00609。查看ug585,看看这么配置是什么意思。 此时就可以清晰的知晓,通过控制这个寄存器的最后一位,就可以控制定时器的工作与否,刚才我们写入的是F8F00609,将最后一位置1,也就是启动了定时器。 8.7.1.4 TimerIntrHandler函数定时器中断产生后,会调用void TimerIntrHandler(void *CallBackRef)函数。 8.7.2 sys_intr.c
8.7.2.1 Init_Intr_System函数int Init_Intr_System(XScuGic * IntcInstancePtr)负责初始化全局中断控制器 8.7.2.2 Setup_Intr_Exception函数void Setup_Intr_Exception(XScuGic * IntcInstancePtr)函数负责启动全局中断控制器 8.8.3 main.c
本课程对timer中断,以及系统中断控制器部分做了封装,方便后面在项目中管理调用,main函数演示了如何对系统中断控制器以及Timer定时器的初始化和使用。 |
扫描关注,了解最新资讯