ug585_ch8定时器阅读

zynq中拥有两个Cortex-A9的cpu,每个cpu有32bit的定时器和32bit的看门狗定时器。这些定时器都是由CPU频率的1/2驱动的。(CPU时钟频率若为666.666MHz,则寄存器为 333.333MHz(是不是看的眼熟=。=))。两个三重时钟计数器通常是CPU频率1/4或1/6,并且可用于信号的脉冲宽度的计数。
结构:(可看到控制中断控制器)
ug585_ch8定时器阅读
一、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;
}

(程序嘛可以根据自己的需求改下跑自己想要的效果,顺便挖个坑,函数解析我会继续补齐,未完)

上一篇:c# – 如何处理Windows窗体中文本框的完整更改?


下一篇:CH8 YARN节点标签