Zynq 私有定时器 中断
2019-04-14 18:13发布
生成海报
本片文章将在ZYNQ的纯PS里实现私有定时器中断。每隔一秒中断一次,在中断函数里计数加1,通过串口打印输出。 中断对于保证任务的实时性非常必要,在ZYNQ里集成了中断控制器GIC(Generic Interrupt Controller).GIC可以接受I/O外设中断IOP和PL中断,将这些中断发给CPU。
中断体系结构框图图下:
SGI通过写ICDSGIR寄存器产生SGI.通过PS和PL内各种I/O和存储器控制器产生。包含:全局定时器,私有看门狗定时器,私有定时器以及来自PL的FIQ/IRQ。本文主要介绍PPI,其它的请参考官方手册ug585_Zynq_7000_TRM.pdf。
ZYNQ每个CPU链接5个私有外设中断,所有中断的触发类型都是固定不变的。并且来自PL的快速中断信号FIQ和中断信号IRQ反向,然后送到中断控制器因此尽管在ICDICFR1寄存器内反应的他们是低电平触发,但是PS-PL接口中为高电平触发。如图所示:
zynq中每个ARM core都有自己的私有定时器,私有定时器的工作频率为CPU的一半,比如Miz702的ARM工作频率为666MHZ,则私有定时器的频率为333MHz.
私有定时器的特性如下:
(1)32位计数器,达到零时产生一个中断
(2)8位预分频计数器,可以更好的控制中断周期
(3)可配置一次性或者自动重加载模式
(4)定时器时间可以通过下式计算:
定时时间 = [(预分频器的值 + 1) (加载值 + 1)]/定时器频率Step1:新建一个名为为Miz702_sys的工程Step2:选择RTL Project 勾选Do not specify source at this timeStep3:由于Miz702兼容zedboard 因此选择zedboard开发包Step4:单击FinishStep1:单击Create Block DesignStep2:输入systemStep3:单击下图中添加IP按钮Step4:搜素单词z选择ZYNQ7 Processing System,然后双击Step5:添加进来了ZYNQ CPU IP,然后单击Run Block AutomationStep6:直接单击OKStep7:在你点击了OK后,你会发现DDR以及FICED_IO自劢的延伸出来。Step8:连线的作用就是把PS的时钟可以接入PL部分,当然这里我们暂时用不到PL部分的资源。在Block文件中,我们进行连线,将鼠标放在引脚处,鼠标变成铅笔后迚行拖拽,连线如下图所示:Step9: 右击 system.bd, 单击Generate Output ProductsStep10:支部操作会产生执行、仿真、综合的文件Step11:右击system.bd 选择 Create HDL Wrapper 这步的作用是产生顶层的HDL文件Step12:选择Leave Let Vivado manager wrapper and auto-update 然后单击OKStep13:执行->产生bit文件Step1:File->Export->Export HardwareStep2:勾选Include bitstream 直接单击OKStep3:File->Launch SDK加载到SDKStep4:单击OK建立一个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); //每秒打印输出一次
}
可以看到串口终端每秒输出一次,并且值加1递增。中断对于实时系统是非常重要的,可以说是是实时性的保障吧。本章简要介绍了ZYNQ的中断原理和中断类型,详细介绍了私有定时器,建立了完整的工程进行测试。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮