zynq中拥有两个Cortex-A9的cpu,每个cpu有32bit的定时器和32bit的看门狗定时器。这些定时器都是由CPU频率的1/2驱动的。(CPU时钟频率若为666.666MHz,则寄存器为 333.333MHz(是不是看的眼熟=。=))。两个三重时钟计数器通常是CPU频率1/4或1/6,并且可用于信号的脉冲宽度的计数。
结构:(可看到控制中断控制器)
一、CPU定时器和看门狗定时器所带资源和支持
1、特点
(1)都有一个32位的计时器,当计时器减为0时,会产生一个终端
(2)8位的预调压器,控制中断中期
(3)两种迷失:单次检测、自动重新加载
(4)初始值可配置
2、全局时钟
全局定时器是一个64位自动递增计数器。全局定时器将内存映射在与私人定时器相同的地址空间中。全局定时器仅在重置时访问。两个Cortex-A9处理器都可以访问全局定时器。每个Cortex-A9处理器都各自有一个64位的比较器,用于在全局计时器达到比较器值时断言一个私有中断。
3、系统时钟看门狗
除了两个CPU的私有看门狗定时器,还有一个24位的系统看门狗SWDT,在发生灾难性的系统故障时发出信号(比如PS中的PLL工作失常)。SWDT可以工作在设备外部或PL提供的时钟下,并向它们输出一个复位信号。(SWDT可以工作在CPU频率的1/4或1/6)。
4、三重定时器(TTC)
每个TTC都有三个独立的定时器/计数器。TTC只能工作在CPU频率的1/4或1/6(CPU_1x),Zynq使用该定时器计算来自MIO管脚或PL的信号脉冲宽度。
二、程序(搭个最简单的最小系统定时控制OLED)
(另一个博主:几种定时器中,私有定时器是最常用的,使用双核时可能会用到全局定时器。私有定时器是CPU五种PPI中断源的一种,固定为上升沿敏感。)
#include <stdio.h>
#include "xparameters.h"
#include "xil_printf.h"
#include "xstatus.h"
#include "xscutimer.h"
#include "xscugic.h"
XScuTimer TimerInstance; /* Cortex A9 Scu Private Timer Instance */
XScuGic IntcInstance; /* Interrupt Controller Instance */
#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 0x3F940AA
//如果要设置200ms中断,由于333.33MHz,所以周期大约3ns
//20_000_000ns/3 = 66666600 =》3F9 40AA
//定时器初始化
int timer_init(XScuTimer * TimerInstancePtr,u16 TimerDeviceId)
{
int Status;
XScuTimer_Config *ConfigPtr;
//初始化私有定时器
ConfigPtr = XScuTimer_LookupConfig(TimerDeviceId);
/*
* This is where the virtual address would be used, this example
* uses physical address.
*/
Status = XScuTimer_CfgInitialize(TimerInstancePtr, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
//设备自检
Status = XScuTimer_SelfTest(TimerInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
//使能自动装载(确保不是只执行一次)
XScuTimer_EnableAutoReload(TimerInstancePtr);
//配置计数器初始值
XScuTimer_LoadTimer(TimerInstancePtr, TIMER_LOAD_VALUE);
//启动定时器
XScuTimer_Start(TimerInstancePtr);
return Status;
}
//定时器中断处理函数
static void Timer_Intr_Handler(void *CallBackRef)
{
XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
static int sec = 0; //计数
//清除中断
if (XScuTimer_IsExpired(TimerInstancePtr)) {
XScuTimer_ClearInterruptStatus(TimerInstancePtr);
//开始你的表演写你要的功能
sec++;
printf(" %d Second\n\r",sec); //每秒打印输出一次
}
}
//定时器中断初始化
int time_intr_init(XScuGic *IntcInstancePtr,XScuTimer *TimerInstancePtr,u16 TimerIntrId)
{
int Status;
XScuGic_Config *IntcConfig;
//初始化中断控制器
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig)
{
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
//中断异常处理
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
IntcInstancePtr);
Xil_ExceptionEnable();
//设置定时器的中断处理函数
Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId,
(Xil_ExceptionHandler)Timer_Intr_Handler,
(void *)TimerInstancePtr);
if (Status != XST_SUCCESS) {
return Status;
}
//使能中断控制器
XScuGic_Enable(IntcInstancePtr, TimerIntrId);
//使能定时器的中断
XScuTimer_EnableInterrupt(TimerInstancePtr);
return Status;
}
int main(void)
{
timer_init(&TimerInstance, TIMER_DEVICE_ID);
time_intr_init(&IntcInstance, &TimerInstance, TIMER_IRPT_INTR);
while(1){};
return XST_SUCCESS;
}
(程序嘛可以根据自己的需求改下跑自己想要的效果,顺便挖个坑,函数解析我会继续补齐,未完)