[X]关闭

【ZYNQ-7000开发之十三】中断:私有定时器中断

文档创建者:RZJM
浏览次数:9320
最后更新:2017-11-20
本帖最后由 RZJM 于 2016-3-6 13:56 编辑

上篇文章实现了了PS接受来自PL的中断,本片文章将在ZYNQ的纯PS里实现私有定时器中断。每个一秒中断一次,在中断函数里计数加1,通过串口打印输出。

本文所使用的开发板是Miz702(兼容zedboard)
PC 开发环境版本:Vivado 2015.2 Xilinx SDK 2015.2

中断原理

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


中断体系结构框图图下:

软件中断(SGI)

SGI通过写ICDSGIR寄存器产生SGI.


共享中断SPI

通过PS和PL内各种I/O和存储器控制器产生。


私有中断(PPI)

包含:全局定时器,私有看门狗定时器,私有定时器以及来自PL的FIQ/IRQ。本文主要介绍PPI,其它的请参考官方手册ug585_Zynq_7000_TRM.pdf。
ZYNQ每个CPU链接5个私有外设中断,所有中断的触发类型都是固定不变的。并且来自PL的快速中断信号FIQ和中断信号IRQ反向,然后送到中断控制器因此尽管在ICDICFR1寄存器内反应的他们是低电平触发,但是PS-PL接口中为高电平触发。如图所示:


私有定时器

zynq中每个ARM core都有自己的私有定时器,私有定时器的工作频率为CPU的一半,比如Miz702或者zedboard的ARM工作频率为666MHZ,则私有定时器的频率为333MHz.
私有定时器的特性如下:
(1)32为计数器,达到零时产生一个中断
(2)8位预分频计数器,可以更好的控制中断周期
(3)可配置一次性或者自动重加载模式
(4)定时器时间可以通过下式计算:
定时时间 = [(预分频器的值 + 1) (加载值 + 1)]/定时器频率


搭建硬件系统工程:配置ZYNQ PS
把ZYNQ配置为只保留UART1,然后点击OK如图所示


点击Run Connection Automation,取消掉Apply Board Preset,如图


最终的框图很简洁,如图:



建立软件工程

建立一个Hello World工程
把Helloworld.c的代码修改如下:

  1. #include <stdio.h>
  2. #include "platform.h"
  3. #include "xadcps.h"
  4. #include "xil_types.h"
  5. #include "Xscugic.h"
  6. #include "Xil_exception.h"
  7. #include "xscutimer.h"
  8. //timer info
  9. #define TIMER_DEVICE_ID                XPAR_XSCUTIMER_0_DEVICE_ID
  10. #define INTC_DEVICE_ID                XPAR_SCUGIC_SINGLE_DEVICE_ID
  11. #define TIMER_IRPT_INTR                XPAR_SCUTIMER_INTR
  12. //#define TIMER_LOAD_VALUE        0x0FFFFFFF
  13. #define TIMER_LOAD_VALUE        0x13D92D3F
  14. static XAdcPs  XADCMonInst; //XADC
  15. static XScuGic Intc; //GIC
  16. static XScuTimer Timer;//timer
  17. static void SetupInterruptSystem(XScuGic *GicInstancePtr,
  18.                 XScuTimer *TimerInstancePtr, u16 TimerIntrId);
  19. static void TimerIntrHandler(void *CallBackRef);
  20. int main()
  21. {
  22.          XScuTimer_Config *TMRConfigPtr;     //timer config
  23.          printf("------------START-------------\n");
  24.          init_platform();
  25.      //
  26.      //私有定时器初始化
  27.      TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
  28.      XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);
  29.      XScuTimer_SelfTest(&Timer);
  30.           //加载计数周期,私有定时器的时钟为CPU的一般,为333MHZ,如果计数1S,加载值为1sx(333x1000x1000)(1/s)-1=0x13D92D3F
  31.           XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);
  32.           //自动装载
  33.           XScuTimer_EnableAutoReload(&Timer);
  34.           //启动定时器
  35.           XScuTimer_Start(&Timer);
  36.      //set up the interrupts
  37.      SetupInterruptSystem(&Intc,&Timer,TIMER_IRPT_INTR);
  38.      while(1){
  39.      }
  40.      return 0;
  41. }
  42. void SetupInterruptSystem(XScuGic *GicInstancePtr,
  43.                 XScuTimer *TimerInstancePtr, u16 TimerIntrId)
  44. {
  45.                 XScuGic_Config *IntcConfig; //GIC config
  46.                 Xil_ExceptionInit();
  47.                 //initialise the GIC
  48.                 IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
  49.                 XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,
  50.                                                 IntcConfig->CpuBaseAddress);
  51.             //connect to the hardware
  52.                 Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
  53.                                         (Xil_ExceptionHandler)XScuGic_InterruptHandler,
  54.                                         GicInstancePtr);
  55.                 //set up the timer interrupt
  56.                 XScuGic_Connect(GicInstancePtr, TimerIntrId,
  57.                                                 (Xil_ExceptionHandler)TimerIntrHandler,
  58.                                                 (void *)TimerInstancePtr);
  59.                 //enable the interrupt for the Timer at GIC
  60.                 XScuGic_Enable(GicInstancePtr, TimerIntrId);
  61.                 //enable interrupt on the timer
  62.                 XScuTimer_EnableInterrupt(TimerInstancePtr);
  63.                 // Enable interrupts in the Processor.
  64.                 Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
  65.         }
  66. static void TimerIntrHandler(void *CallBackRef)
  67. {
  68.         static int sec = 0;   //计数
  69.         XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
  70.         XScuTimer_ClearInterruptStatus(TimerInstancePtr);
  71.         sec++;
  72.         printf(" %d Second\n\r",sec);  //每秒打印输出一次
  73. }
复制代码

上电测试

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


发表评论已发布 4

Li2015

发表于 2016-3-6 13:06:27 | 显示全部楼层

赞!不知道前辈能不能写出一个关于SPI的例程,最近想学一下这个,就是找不到例子。

uisrc

发表于 2016-3-6 13:35:37 | 显示全部楼层

越努力越幸运!加油!
回复

使用道具 举报

yukang1744

发表于 2016-3-6 14:48:18 | 显示全部楼层

非常好!一个定时器不够用,麻烦楼主再来一个全局定时器的例程。

lllll

发表于 2017-11-20 15:02:36 | 显示全部楼层

串口通信可不可以也来一个?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则