Zynq-7000 系列 SoC (System on Chip) 的定时器系统是由几个不同的定时器模块组成的,这些定时器可以满足广泛的嵌入式应用需求。主要包括:
- 全局定时器 (Global Timer)
特点:全局定时器是一个 64 位的计时器,存在于 Cortex-A9 处理器内核中,提供一个全局的时间基准。
用途:主要用于需要高精度的计时和同步任务,比如操作系统的时钟中断。
时钟源:由 ARM CPU 提供的时钟信号 (CPU_3x2x 时钟),可以独立配置。
中断支持:全局定时器可以配置中断,当计数器达到指定值时触发中断。 - 私有定时器 (Private Timer)
特点:每个 Cortex-A9 核心都有一个私有定时器,32 位,主要用于内核级的定时任务。
用途:在多核环境中,可为每个核单独提供定时服务,常用于操作系统的任务切换。
时钟源:通常以 CPU 时钟的 2 倍频率运行。
中断支持:可以配置自动重载模式,当计数值达到零时产生中断。 - 看门狗定时器 (Watchdog Timer)
特点:用于监视系统状态,以确保系统在发生故障时自动恢复。32 位的看门狗定时器可以在一定时间内检测系统是否发生故障。
用途:主要用于嵌入式系统的容错设计,当系统出现错误或死机时,自动复位 SoC。
时钟源:也运行在 CPU 的 2 倍频率。
中断支持:当计数器倒计到零时,可以触发中断或者复位系统。 - 可编程逻辑定时器 (Programmable Logic Timers)
特点:Zynq-7000 的 FPGA 部分允许用户实现自定义的定时器模块,根据具体应用设计复杂的计时逻辑。
用途:在需要高灵活性的场景下,可以使用可编程逻辑 (PL) 部分创建精确的定时模块,特别适用于复杂的控制和同步任务。
中断支持:通过 AXI 总线与处理系统 (PS) 通信,可以通过中断或轮询方式处理定时器事件。 - Triple Timer Counter (TTC)
特点:TTC 是一个 3 组定时器模块,每组有 3 个定时器,16 位计数,每个定时器都可单独配置。
用途:适用于生成 PWM 信号、频率计数等应用,常用于定时精确事件。
时钟源:TTC 的时钟源可以来自处理器系统 (PS) 的时钟或外部时钟。
中断支持:每个定时器可以配置中断,当计数到达设定值时触发中断。 - 应用中的使用策略
对于需要高精度、长时间计数的任务,推荐使用全局定时器或私有定时器。
在关键任务或实时控制场景中,可以结合看门狗定时器用于系统恢复和监控。
在 FPGA 设计中灵活使用 PL 中的定时器逻辑,适合实现复杂的定时和信号控制需求。
这是GPT对zynq7000定时器资源的描述
本次使用的是私有定时器中断,
根据描述,私有定时器的始终时钟频率为CPU时钟频率的一半
在xparamerter中查看CPU频率为650MHZ
同时需要定时器设ID,中断处理器ID, 定时器中断ID
- 中断处理器ID
- 定时器ID
- 定时器中断ID
为了我们方便查看,直接重新进行宏定义
#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);
在初始化函数中进行
- 定时器初始化
/** Timer init **/
XScuTimer_Config * TimerConfPtr;
TimerConfPtr = XScuTimer_LookupConfig(TimerDeviceID);
XScuTimer_CfgInitialize(TimerInstance, TimerConfPtr, TimerConfPtr->BaseAddr);
- 中断处理器初始化
/** Interrupt init **/
XScuGic_Config * IntConfPtr;
IntConfPtr = XScuGic_LookupConfig(IntDeviceID);
XScuGic_CfgInitialize(IntInstance, IntConfPtr, IntConfPtr->CpuBaseAddress);
- 全局中断注册,以及中断回调函数绑定
/** 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);
- 启用中断
// 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