Zynq-7000 系列 SoC (System on Chip) 的定时器系统是由几个不同的定时器模块组成的,这些定时器可以满足广泛的嵌入式应用需求。主要包括:

  1. 全局定时器 (Global Timer)
    特点:全局定时器是一个 64 位的计时器,存在于 Cortex-A9 处理器内核中,提供一个全局的时间基准。
    用途:主要用于需要高精度的计时和同步任务,比如操作系统的时钟中断。
    时钟源:由 ARM CPU 提供的时钟信号 (CPU_3x2x 时钟),可以独立配置。
    中断支持:全局定时器可以配置中断,当计数器达到指定值时触发中断。
  2. 私有定时器 (Private Timer)
    特点:每个 Cortex-A9 核心都有一个私有定时器,32 位,主要用于内核级的定时任务。
    用途:在多核环境中,可为每个核单独提供定时服务,常用于操作系统的任务切换。
    时钟源:通常以 CPU 时钟的 2 倍频率运行。
    中断支持:可以配置自动重载模式,当计数值达到零时产生中断。
  3. 看门狗定时器 (Watchdog Timer)
    特点:用于监视系统状态,以确保系统在发生故障时自动恢复。32 位的看门狗定时器可以在一定时间内检测系统是否发生故障。
    用途:主要用于嵌入式系统的容错设计,当系统出现错误或死机时,自动复位 SoC。
    时钟源:也运行在 CPU 的 2 倍频率。
    中断支持:当计数器倒计到零时,可以触发中断或者复位系统。
  4. 可编程逻辑定时器 (Programmable Logic Timers)
    特点:Zynq-7000 的 FPGA 部分允许用户实现自定义的定时器模块,根据具体应用设计复杂的计时逻辑。
    用途:在需要高灵活性的场景下,可以使用可编程逻辑 (PL) 部分创建精确的定时模块,特别适用于复杂的控制和同步任务。
    中断支持:通过 AXI 总线与处理系统 (PS) 通信,可以通过中断或轮询方式处理定时器事件。
  5. Triple Timer Counter (TTC)
    特点:TTC 是一个 3 组定时器模块,每组有 3 个定时器,16 位计数,每个定时器都可单独配置。
    用途:适用于生成 PWM 信号、频率计数等应用,常用于定时精确事件。
    时钟源:TTC 的时钟源可以来自处理器系统 (PS) 的时钟或外部时钟。
    中断支持:每个定时器可以配置中断,当计数到达设定值时触发中断。
  6. 应用中的使用策略
    对于需要高精度、长时间计数的任务,推荐使用全局定时器或私有定时器。
    在关键任务或实时控制场景中,可以结合看门狗定时器用于系统恢复和监控。
    在 FPGA 设计中灵活使用 PL 中的定时器逻辑,适合实现复杂的定时和信号控制需求。

这是GPT对zynq7000定时器资源的描述

本次使用的是私有定时器中断,
根据描述,私有定时器的始终时钟频率为CPU时钟频率的一半

在xparamerter中查看CPU频率为650MHZ
image

同时需要定时器设ID,中断处理器ID, 定时器中断ID

  1. 中断处理器ID
    image
  2. 定时器ID
    image
  3. 定时器中断ID
    image

为了我们方便查看,直接重新进行宏定义

#define TimerDeviceId	XPAR_XSCUTIMER_0_DEVICE_ID
#define IntDeviceId		XPAR_SCUGIC_0_DEVICE_ID
#define TimerIntId		XPS_SCU_TMR_INT_ID

私有定时器的始终时钟频率为CPU时钟频率的一半,对我们需要的中断频率进行宏定义

#define TIMER_FREQ		5		// hz
#define SYS_CPU_CLK 	XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ
#define TIMER_VALUE		SYS_CPU_CLK/2/TIMER_FREQ

同时需要对定时器,中断处理器进行实例化

// instance timer and interrupt
XScuGic 	IntInst;
XScuTimer 	TimerInst;

定义初始化函数以及中断处理函数

// interrupt callback
static void IntHandle();
// setup timer and  interrupt
static void Init(XScuGic* IntInstance, XScuTimer* TimerInstance, u16 IntDeviceID, u16 TimerDeviceID, u16 IntID);

在初始化函数中进行

  1. 定时器初始化
/** Timer init  **/
	XScuTimer_Config * TimerConfPtr;
	TimerConfPtr = XScuTimer_LookupConfig(TimerDeviceID);
	XScuTimer_CfgInitialize(TimerInstance, TimerConfPtr, TimerConfPtr->BaseAddr);
  1. 中断处理器初始化
	/** Interrupt init **/
	XScuGic_Config * IntConfPtr;
	IntConfPtr = XScuGic_LookupConfig(IntDeviceID);
	XScuGic_CfgInitialize(IntInstance, IntConfPtr, IntConfPtr->CpuBaseAddress);
  1. 全局中断注册,以及中断回调函数绑定
	/** timer and interrupt config **/
	// register global Interrupt
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntInstance);
	// attach callback function to interrupt
	XScuGic_Connect(IntInstance, IntID, (Xil_ExceptionHandler)IntHandle, (void *)TimerInstance);
  1. 启用中断
	// config timer auto reload
	XScuTimer_EnableAutoReload(TimerInstance);
	// enbale timer interrupt
	XScuTimer_EnableInterrupt(TimerInstance);
	// enable interrupt source
	XScuGic_Enable(IntInstance, IntID);
	// enable global interrupt
	Xil_ExceptionEnable();

同时简单设计一个中断处理函数

static void IntHandle()
{
	flag = 1;
	cnt += 1;
	XScuTimer_ClearInterruptStatus(&TimerInst);
}

最后在主函数中调用初始化函数,对计数器计数值进行配置,并开启定时器

Init(&IntInst, &TimerInst, IntDeviceId, IntDeviceId, TimerIntId);
	XScuTimer_LoadTimer(&TimerInst, TIMER_VALUE);
	XScuTimer_Start(&TimerInst);
	while(1)
	{
		if(flag)
			printf("cnt is %d  \r\n", cnt);
		flag = 0;
	}

Code Here: https://github.com/tiruoQing/fpgas/blob/main/Timer_Interrupt/main.c

posted on 2024-10-29 14:46  天若手提滑铲  阅读(38)  评论(0编辑  收藏  举报