Zynq 私有定时器 中断

2019-04-14 18:13发布

    本片文章将在ZYNQ的纯PS里实现私有定时器中断。每隔一秒中断一次,在中断函数里计数加1,通过串口打印输出。

    中断对于保证任务的实时性非常必要,在ZYNQ里集成了中断控制器GIC(Generic Interrupt Controller).GIC可以接受I/O外设中断IOP和PL中断,将这些中断发给CPU。  

中断体系结构框图图下: 
wps949F.tmp
14.1.1软件中断(SGI)
SGI通过写ICDSGIR寄存器产生SGI.
14.1.2共享中断SPI
通过PS和PL内各种I/O和存储器控制器产生。
14.1.3私有中断(PPI)
包含:全局定时器,私有看门狗定时器,私有定时器以及来自PL的FIQ/IRQ。本文主要介绍PPI,其它的请参考官方手册ug585_Zynq_7000_TRM.pdf。  
ZYNQ每个CPU链接5个私有外设中断,所有中断的触发类型都是固定不变的。并且来自PL的快速中断信号FIQ和中断信号IRQ反向,然后送到中断控制器因此尽管在ICDICFR1寄存器内反应的他们是低电平触发,但是PS-PL接口中为高电平触发。如图所示:  
wps94A0.tmp
14.1.4私有定时器
zynq中每个ARM core都有自己的私有定时器,私有定时器的工作频率为CPU的一半,比如Miz702的ARM工作频率为666MHZ,则私有定时器的频率为333MHz.  
私有定时器的特性如下: 
(1)32位计数器,达到零时产生一个中断  
(2)8位预分频计数器,可以更好的控制中断周期  
(3)可配置一次性或者自动重加载模式  
(4)定时器时间可以通过下式计算:  
定时时间 = [(预分频器的值 + 1) (加载值 + 1)]/定时器频率

14.2 搭建硬件工程

Step1:新建一个名为为Miz702_sys的工程wps94A1.tmpStep2:选择RTL Project 勾选Do not specify source at this timewps94B2.tmpStep3:由于Miz702兼容zedboard 因此选择zedboard开发包wps94B3.tmpStep4:单击Finishwps94B4.tmp

14.3使用IP Integrator创建硬件系统

Step1:单击Create Block DesignStep2:输入systemwps94B5.tmpStep3:单击下图中wps94C5.tmp添加IP按钮wps94C6.tmpStep4:搜素单词z选择ZYNQ7 Processing System,然后双击wps94C7.tmpStep5:添加进来了ZYNQ CPU IP,然后单击Run Block Automationwps94C8.tmpStep6:直接单击OKwps94D9.tmpStep7:在你点击了OK后,你会发现DDR以及FICED_IO自劢的延伸出来。wps94DA.tmpStep8:连线的作用就是把PS的时钟可以接入PL部分,当然这里我们暂时用不到PL部分的资源。在Block文件中,我们进行连线,将鼠标放在引脚处,鼠标变成铅笔后迚行拖拽,连线如下图所示:wps94DB.tmpStep9: 右击 system.bd, 单击Generate Output Productswps94DC.tmpStep10:支部操作会产生执行、仿真、综合的文件wps94EC.tmpStep11:右击system.bd 选择 Create HDL Wrapper 这步的作用是产生顶层的HDL文件wps94ED.tmpStep12:选择Leave Let Vivado manager wrapper and auto-update 然后单击OKStep13:执行->产生bit文件wps94EE.tmp

14.4导出SOC硬件到SDK

Step1:File->Export->Export Hardwarewps94EF.tmpStep2:勾选Include bitstream 直接单击OKwps9500.tmpStep3:File->Launch SDK加载到SDKwps9501.tmpStep4:单击OKwps9502.tmp

14.5 建立软件工程

建立一个TIMER_INTC空的工程,并且添加main.c 添加如下代码#include #include "xadcps.h" #include "xil_types.h" #include "Xscugic.h" #include "Xil_exception.h" #include "xscutimer.h" //timer info #define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR //#define TIMER_LOAD_VALUE 0x0FFFFFFF #define TIMER_LOAD_VALUE 0x13D92D3F //static XAdcPs XADCMonInst; //XADC static XScuGic Intc; //GIC static XScuTimer Timer;//timer static void SetupInterruptSystem(XScuGic *GicInstancePtr, XScuTimer *TimerInstancePtr, u16 TimerIntrId); static void TimerIntrHandler(void *CallBackRef); int main() { XScuTimer_Config *TMRConfigPtr; //timer config printf("------------START------------- "); // init_platform(); //私有定时器初始化 TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID); XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr); XScuTimer_SelfTest(&Timer); //加载计数周期,私有定时器的时钟为CPU的一般,为333MHZ,如果计数1S,加载值为1sx(333x1000x1000)(1/s)-1=0x13D92D3F XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE); //自动装载 XScuTimer_EnableAutoReload(&Timer); //启动定时器 XScuTimer_Start(&Timer); //set up the interrupts SetupInterruptSystem(&Intc,&Timer,TIMER_IRPT_INTR); while(1){ } return 0; } void SetupInterruptSystem(XScuGic *GicInstancePtr, XScuTimer *TimerInstancePtr, u16 TimerIntrId) { XScuGic_Config *IntcConfig; //GIC config Xil_ExceptionInit(); //initialise the GIC IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); //connect to the hardware Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, GicInstancePtr); //set up the timer interrupt XScuGic_Connect(GicInstancePtr, TimerIntrId, (Xil_ExceptionHandler)TimerIntrHandler, (void *)TimerInstancePtr); //enable the interrupt for the Timer at GIC XScuGic_Enable(GicInstancePtr, TimerIntrId); //enable interrupt on the timer XScuTimer_EnableInterrupt(TimerInstancePtr); // Enable interrupts in the Processor. Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); } static void TimerIntrHandler(void *CallBackRef) { static int sec = 0; //计数 XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef; XScuTimer_ClearInterruptStatus(TimerInstancePtr); sec++; printf(" %d Second ",sec); //每秒打印输出一次 }

14.6测试结果

可以看到串口终端每秒输出一次,并且值加1递增。

14.7本章小结

中断对于实时系统是非常重要的,可以说是是实时性的保障吧。本章简要介绍了ZYNQ的中断原理和中断类型,详细介绍了私有定时器,建立了完整的工程进行测试。